ETH Price: $1,975.43 (+0.08%)

Transaction Decoder

Block:
16849172 at Mar-17-2023 06:00:59 PM +UTC
Transaction Fee:
0.004424916767105884 ETH $8.74
Gas Used:
209,629 Gas / 21.108323596 Gwei

Emitted Events:

178 Proxy.0x3d0ce9bfc3ed7d6862dbb28b2dea94561fe714a1b4d019aa8af39730d1ad7c3d( 0x3d0ce9bfc3ed7d6862dbb28b2dea94561fe714a1b4d019aa8af39730d1ad7c3d, 0x00000000000000000000000000000000000001ad428e4906ae43d8f9852d0dd6, 000000000000000000000000000000000000000000000000000221b262dd8000 )
179 Kawakami.Approval( owner=0xaa547deaea05872b7deaf0fdedfa466fc535f112, approved=0x00000000...000000000, tokenId=25 )
180 Kawakami.Transfer( from=0xaa547deaea05872b7deaf0fdedfa466fc535f112, to=[Receiver] TransparentUpgradeableProxy, tokenId=25 )
181 Seaport.OrderFulfilled( orderHash=0127021C413D54EDA368A2B336DE6607BEF5AA0E7D865257E123CBF0298CC7AE, offerer=0xaa547deaea05872b7deaf0fdedfa466fc535f112, zone=0x004C0050...C00560C00, recipient=[Receiver] TransparentUpgradeableProxy, offer=, consideration= )
182 Kawakami.Approval( owner=[Receiver] TransparentUpgradeableProxy, approved=0x00000000...000000000, tokenId=25 )
183 Kawakami.Transfer( from=[Receiver] TransparentUpgradeableProxy, to=0x9a938064...6Af700E24, tokenId=25 )

Account State Difference:

  Address   Before After State Difference Code
0x00000000...9852d0dD6
(Seaport 1.4)
0x0000a26b...000fAa719
60.517155765861741225 Eth60.517755765861741225 Eth0.0006
0x0f88CAE6...38c9367B8
0xAa547DEa...fC535f112 0.073272787515778036 Eth0.192072787515778036 Eth0.1188
0xd0B84202...F65D8dFB3
(Kawakami: Marketing Fund)
0.014 Eth0.0146 Eth0.0006
(Flashbots: Builder)
1.260224823096257286 Eth1.260539266596257286 Eth0.0003144435
0xEF0B5669...57c31Bcc9
(MoonPay: Proxy Smart Contract)
48.700964360517003401 Eth48.580964360517003401 Eth0.12
0xf408Bee3...AC657006F
0.65803916774315579 Eth
Nonce: 62163
0.653614250976049906 Eth
Nonce: 62164
0.004424916767105884

Execution Trace

TransparentUpgradeableProxy.88a7765b( )
  • 0xf1f5932613ac2896edbd5543313de13ad8c29ef2.88a7765b( )
    • ETH 0.12 Seaport.fulfillAdvancedOrder( advancedOrder=[{name:parameters, type:tuple, order:1, indexed:false, value:[{name:offerer, type:address, order:1, indexed:false, value:0xAa547DEaeA05872b7deAf0FdEdfa466fC535f112, valueString:0xAa547DEaeA05872b7deAf0FdEdfa466fC535f112}, {name:zone, type:address, order:2, indexed:false, value:0x004C00500000aD104D7DBd00e3ae0A5C00560C00, valueString:0x004C00500000aD104D7DBd00e3ae0A5C00560C00}, {name:offer, type:tuple[], order:3, indexed:false}, {name:consideration, type:tuple[], order:4, indexed:false}, {name:orderType, type:uint8, order:5, indexed:false, value:0, valueString:0}, {name:startTime, type:uint256, order:6, indexed:false, value:1679072865, valueString:1679072865}, {name:endTime, type:uint256, order:7, indexed:false, value:1679677665, valueString:1679677665}, {name:zoneHash, type:bytes32, order:8, indexed:false, value:0000000000000000000000000000000000000000000000000000000000000000, valueString:0000000000000000000000000000000000000000000000000000000000000000}, {name:salt, type:uint256, order:9, indexed:false, value:24446860302761739304752683030156737591518664810215442929811153025651907195399, valueString:24446860302761739304752683030156737591518664810215442929811153025651907195399}, {name:conduitKey, type:bytes32, order:10, indexed:false, value:0000007B02230091A7ED01230072F7006A004D60A8D4E71D599B8104250F0000, valueString:0000007B02230091A7ED01230072F7006A004D60A8D4E71D599B8104250F0000}, {name:totalOriginalConsiderationItems, type:uint256, order:11, indexed:false, value:3, valueString:3}], valueString:[{name:offerer, type:address, order:1, indexed:false, value:0xAa547DEaeA05872b7deAf0FdEdfa466fC535f112, valueString:0xAa547DEaeA05872b7deAf0FdEdfa466fC535f112}, {name:zone, type:address, order:2, indexed:false, value:0x004C00500000aD104D7DBd00e3ae0A5C00560C00, valueString:0x004C00500000aD104D7DBd00e3ae0A5C00560C00}, {name:offer, type:tuple[], order:3, indexed:false}, {name:consideration, type:tuple[], order:4, indexed:false}, {name:orderType, type:uint8, order:5, indexed:false, value:0, valueString:0}, {name:startTime, type:uint256, order:6, indexed:false, value:1679072865, valueString:1679072865}, {name:endTime, type:uint256, order:7, indexed:false, value:1679677665, valueString:1679677665}, {name:zoneHash, type:bytes32, order:8, indexed:false, value:0000000000000000000000000000000000000000000000000000000000000000, valueString:0000000000000000000000000000000000000000000000000000000000000000}, {name:salt, type:uint256, order:9, indexed:false, value:24446860302761739304752683030156737591518664810215442929811153025651907195399, valueString:24446860302761739304752683030156737591518664810215442929811153025651907195399}, {name:conduitKey, type:bytes32, order:10, indexed:false, value:0000007B02230091A7ED01230072F7006A004D60A8D4E71D599B8104250F0000, valueString:0000007B02230091A7ED01230072F7006A004D60A8D4E71D599B8104250F0000}, {name:totalOriginalConsiderationItems, type:uint256, order:11, indexed:false, value:3, valueString:3}]}, {name:numerator, type:uint120, order:2, indexed:false, value:1, valueString:1}, {name:denominator, type:uint120, order:3, indexed:false, value:1, valueString:1}, {name:signature, type:bytes, order:4, indexed:false, value:0x7FD0592DF48D35C3F993A991FAD498C49A66E2CB87731B99C063801EA1692197CDF3B93507E7124DD3A0534B4A99AB2A8BD202D056A33F35AB8F2BCDF75D24A4, valueString:0x7FD0592DF48D35C3F993A991FAD498C49A66E2CB87731B99C063801EA1692197CDF3B93507E7124DD3A0534B4A99AB2A8BD202D056A33F35AB8F2BCDF75D24A4}, {name:extraData, type:bytes, order:5, indexed:false, value:0x, valueString:0x}], criteriaResolvers=, fulfillerConduitKey=0000007B02230091A7ED01230072F7006A004D60A8D4E71D599B8104250F0000, recipient=0xEF0B56692F78A44CF4034b07F80204757c31Bcc9 ) => ( fulfilled=True )
      • Null: 0x000...001.e617f1ba( )
      • ETH 0.1188 0xaa547deaea05872b7deaf0fdedfa466fc535f112.CALL( )
      • ETH 0.0006 PayableProxy.CALL( )
      • ETH 0.0006 Proxy.CALL( )
        • ETH 0.0006 GnosisSafe.DELEGATECALL( )
        • OpenSea: Conduit.4ce34aa2( )
          • Kawakami.transferFrom( from=0xAa547DEaeA05872b7deAf0FdEdfa466fC535f112, to=0xEF0B56692F78A44CF4034b07F80204757c31Bcc9, tokenId=25 )
          • Kawakami.safeTransferFrom( from=0xEF0B56692F78A44CF4034b07F80204757c31Bcc9, to=0x9a938064c4d370A03B5A5509156c3586Af700E24, tokenId=25 )
          • Kawakami.ownerOf( tokenId=25 ) => ( 0x9a938064c4d370A03B5A5509156c3586Af700E24 )
            File 1 of 6: TransparentUpgradeableProxy
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.0;
            import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
            import "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol";
            import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
            import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
            import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
            // Kept for backwards compatibility with older versions of Hardhat and Truffle plugins.
            contract AdminUpgradeabilityProxy is TransparentUpgradeableProxy {
                constructor(address logic, address admin, bytes memory data) payable TransparentUpgradeableProxy(logic, admin, data) {}
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.0;
            import "./IBeacon.sol";
            import "../Proxy.sol";
            import "../ERC1967/ERC1967Upgrade.sol";
            /**
             * @dev This contract implements a proxy that gets the implementation address for each call from a {UpgradeableBeacon}.
             *
             * The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't
             * conflict with the storage layout of the implementation behind the proxy.
             *
             * _Available since v3.4._
             */
            contract BeaconProxy is Proxy, ERC1967Upgrade {
                /**
                 * @dev Initializes the proxy with `beacon`.
                 *
                 * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This
                 * will typically be an encoded function call, and allows initializating the storage of the proxy like a Solidity
                 * constructor.
                 *
                 * Requirements:
                 *
                 * - `beacon` must be a contract with the interface {IBeacon}.
                 */
                constructor(address beacon, bytes memory data) payable {
                    assert(_BEACON_SLOT == bytes32(uint256(keccak256("eip1967.proxy.beacon")) - 1));
                    _upgradeBeaconToAndCall(beacon, data, false);
                }
                /**
                 * @dev Returns the current beacon address.
                 */
                function _beacon() internal view virtual returns (address) {
                    return _getBeacon();
                }
                /**
                 * @dev Returns the current implementation address of the associated beacon.
                 */
                function _implementation() internal view virtual override returns (address) {
                    return IBeacon(_getBeacon()).implementation();
                }
                /**
                 * @dev Changes the proxy to use a new beacon. Deprecated: see {_upgradeBeaconToAndCall}.
                 *
                 * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon.
                 *
                 * Requirements:
                 *
                 * - `beacon` must be a contract.
                 * - The implementation returned by `beacon` must be a contract.
                 */
                function _setBeacon(address beacon, bytes memory data) internal virtual {
                    _upgradeBeaconToAndCall(beacon, data, false);
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.0;
            import "./IBeacon.sol";
            import "../../access/Ownable.sol";
            import "../../utils/Address.sol";
            /**
             * @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their
             * implementation contract, which is where they will delegate all function calls.
             *
             * An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon.
             */
            contract UpgradeableBeacon is IBeacon, Ownable {
                address private _implementation;
                /**
                 * @dev Emitted when the implementation returned by the beacon is changed.
                 */
                event Upgraded(address indexed implementation);
                /**
                 * @dev Sets the address of the initial implementation, and the deployer account as the owner who can upgrade the
                 * beacon.
                 */
                constructor(address implementation_) {
                    _setImplementation(implementation_);
                }
                /**
                 * @dev Returns the current implementation address.
                 */
                function implementation() public view virtual override returns (address) {
                    return _implementation;
                }
                /**
                 * @dev Upgrades the beacon to a new implementation.
                 *
                 * Emits an {Upgraded} event.
                 *
                 * Requirements:
                 *
                 * - msg.sender must be the owner of the contract.
                 * - `newImplementation` must be a contract.
                 */
                function upgradeTo(address newImplementation) public virtual onlyOwner {
                    _setImplementation(newImplementation);
                    emit Upgraded(newImplementation);
                }
                /**
                 * @dev Sets the implementation contract address for this beacon
                 *
                 * Requirements:
                 *
                 * - `newImplementation` must be a contract.
                 */
                function _setImplementation(address newImplementation) private {
                    require(Address.isContract(newImplementation), "UpgradeableBeacon: implementation is not a contract");
                    _implementation = newImplementation;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.0;
            import "../Proxy.sol";
            import "./ERC1967Upgrade.sol";
            /**
             * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
             * implementation address that can be changed. This address is stored in storage in the location specified by
             * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
             * implementation behind the proxy.
             */
            contract ERC1967Proxy is Proxy, ERC1967Upgrade {
                /**
                 * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
                 *
                 * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
                 * function call, and allows initializating the storage of the proxy like a Solidity constructor.
                 */
                constructor(address _logic, bytes memory _data) payable {
                    assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1));
                    _upgradeToAndCall(_logic, _data, false);
                }
                /**
                 * @dev Returns the current implementation address.
                 */
                function _implementation() internal view virtual override returns (address impl) {
                    return ERC1967Upgrade._getImplementation();
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.0;
            import "../ERC1967/ERC1967Proxy.sol";
            /**
             * @dev This contract implements a proxy that is upgradeable by an admin.
             *
             * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
             * clashing], which can potentially be used in an attack, this contract uses the
             * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
             * things that go hand in hand:
             *
             * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
             * that call matches one of the admin functions exposed by the proxy itself.
             * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the
             * implementation. If the admin tries to call a function on the implementation it will fail with an error that says
             * "admin cannot fallback to proxy target".
             *
             * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing
             * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due
             * to sudden errors when trying to call a function from the proxy implementation.
             *
             * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,
             * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.
             */
            contract TransparentUpgradeableProxy is ERC1967Proxy {
                /**
                 * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and
                 * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.
                 */
                constructor(address _logic, address admin_, bytes memory _data) payable ERC1967Proxy(_logic, _data) {
                    assert(_ADMIN_SLOT == bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1));
                    _changeAdmin(admin_);
                }
                /**
                 * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.
                 */
                modifier ifAdmin() {
                    if (msg.sender == _getAdmin()) {
                        _;
                    } else {
                        _fallback();
                    }
                }
                /**
                 * @dev Returns the current admin.
                 *
                 * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.
                 *
                 * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                 * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                 * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
                 */
                function admin() external ifAdmin returns (address admin_) {
                    admin_ = _getAdmin();
                }
                /**
                 * @dev Returns the current implementation.
                 *
                 * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.
                 *
                 * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the
                 * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
                 * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
                 */
                function implementation() external ifAdmin returns (address implementation_) {
                    implementation_ = _implementation();
                }
                /**
                 * @dev Changes the admin of the proxy.
                 *
                 * Emits an {AdminChanged} event.
                 *
                 * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.
                 */
                function changeAdmin(address newAdmin) external virtual ifAdmin {
                    _changeAdmin(newAdmin);
                }
                /**
                 * @dev Upgrade the implementation of the proxy.
                 *
                 * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.
                 */
                function upgradeTo(address newImplementation) external ifAdmin {
                    _upgradeToAndCall(newImplementation, bytes(""), false);
                }
                /**
                 * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified
                 * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the
                 * proxied contract.
                 *
                 * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.
                 */
                function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {
                    _upgradeToAndCall(newImplementation, data, true);
                }
                /**
                 * @dev Returns the current admin.
                 */
                function _admin() internal view virtual returns (address) {
                    return _getAdmin();
                }
                /**
                 * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.
                 */
                function _beforeFallback() internal virtual override {
                    require(msg.sender != _getAdmin(), "TransparentUpgradeableProxy: admin cannot fallback to proxy target");
                    super._beforeFallback();
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.0;
            import "./TransparentUpgradeableProxy.sol";
            import "../../access/Ownable.sol";
            /**
             * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an
             * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}.
             */
            contract ProxyAdmin is Ownable {
                /**
                 * @dev Returns the current implementation of `proxy`.
                 *
                 * Requirements:
                 *
                 * - This contract must be the admin of `proxy`.
                 */
                function getProxyImplementation(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
                    // We need to manually run the static call since the getter cannot be flagged as view
                    // bytes4(keccak256("implementation()")) == 0x5c60da1b
                    (bool success, bytes memory returndata) = address(proxy).staticcall(hex"5c60da1b");
                    require(success);
                    return abi.decode(returndata, (address));
                }
                /**
                 * @dev Returns the current admin of `proxy`.
                 *
                 * Requirements:
                 *
                 * - This contract must be the admin of `proxy`.
                 */
                function getProxyAdmin(TransparentUpgradeableProxy proxy) public view virtual returns (address) {
                    // We need to manually run the static call since the getter cannot be flagged as view
                    // bytes4(keccak256("admin()")) == 0xf851a440
                    (bool success, bytes memory returndata) = address(proxy).staticcall(hex"f851a440");
                    require(success);
                    return abi.decode(returndata, (address));
                }
                /**
                 * @dev Changes the admin of `proxy` to `newAdmin`.
                 *
                 * Requirements:
                 *
                 * - This contract must be the current admin of `proxy`.
                 */
                function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner {
                    proxy.changeAdmin(newAdmin);
                }
                /**
                 * @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}.
                 *
                 * Requirements:
                 *
                 * - This contract must be the admin of `proxy`.
                 */
                function upgrade(TransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner {
                    proxy.upgradeTo(implementation);
                }
                /**
                 * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See
                 * {TransparentUpgradeableProxy-upgradeToAndCall}.
                 *
                 * Requirements:
                 *
                 * - This contract must be the admin of `proxy`.
                 */
                function upgradeAndCall(TransparentUpgradeableProxy proxy, address implementation, bytes memory data) public payable virtual onlyOwner {
                    proxy.upgradeToAndCall{value: msg.value}(implementation, data);
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.0;
            /**
             * @dev This is the interface that {BeaconProxy} expects of its beacon.
             */
            interface IBeacon {
                /**
                 * @dev Must return an address that can be used as a delegate call target.
                 *
                 * {BeaconProxy} will check that this address is a contract.
                 */
                function implementation() external view returns (address);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.0;
            /**
             * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
             * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
             * be specified by overriding the virtual {_implementation} function.
             *
             * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
             * different contract through the {_delegate} function.
             *
             * The success and return data of the delegated call will be returned back to the caller of the proxy.
             */
            abstract contract Proxy {
                /**
                 * @dev Delegates the current call to `implementation`.
                 *
                 * This function does not return to its internall call site, it will return directly to the external caller.
                 */
                function _delegate(address implementation) internal virtual {
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        // Copy msg.data. We take full control of memory in this inline assembly
                        // block because it will not return to Solidity code. We overwrite the
                        // Solidity scratch pad at memory position 0.
                        calldatacopy(0, 0, calldatasize())
                        // Call the implementation.
                        // out and outsize are 0 because we don't know the size yet.
                        let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
                        // Copy the returned data.
                        returndatacopy(0, 0, returndatasize())
                        switch result
                        // delegatecall returns 0 on error.
                        case 0 { revert(0, returndatasize()) }
                        default { return(0, returndatasize()) }
                    }
                }
                /**
                 * @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
                 * and {_fallback} should delegate.
                 */
                function _implementation() internal view virtual returns (address);
                /**
                 * @dev Delegates the current call to the address returned by `_implementation()`.
                 *
                 * This function does not return to its internall call site, it will return directly to the external caller.
                 */
                function _fallback() internal virtual {
                    _beforeFallback();
                    _delegate(_implementation());
                }
                /**
                 * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
                 * function in the contract matches the call data.
                 */
                fallback () external payable virtual {
                    _fallback();
                }
                /**
                 * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
                 * is empty.
                 */
                receive () external payable virtual {
                    _fallback();
                }
                /**
                 * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
                 * call, or as part of the Solidity `fallback` or `receive` functions.
                 *
                 * If overriden should call `super._beforeFallback()`.
                 */
                function _beforeFallback() internal virtual {
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.2;
            import "../beacon/IBeacon.sol";
            import "../../utils/Address.sol";
            import "../../utils/StorageSlot.sol";
            /**
             * @dev This abstract contract provides getters and event emitting update functions for
             * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
             *
             * _Available since v4.1._
             *
             * @custom:oz-upgrades-unsafe-allow delegatecall
             */
            abstract contract ERC1967Upgrade {
                // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
                bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
                /**
                 * @dev Storage slot with the address of the current implementation.
                 * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
                 * validated in the constructor.
                 */
                bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
                /**
                 * @dev Emitted when the implementation is upgraded.
                 */
                event Upgraded(address indexed implementation);
                /**
                 * @dev Returns the current implementation address.
                 */
                function _getImplementation() internal view returns (address) {
                    return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
                }
                /**
                 * @dev Stores a new address in the EIP1967 implementation slot.
                 */
                function _setImplementation(address newImplementation) private {
                    require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
                    StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
                }
                /**
                 * @dev Perform implementation upgrade
                 *
                 * Emits an {Upgraded} event.
                 */
                function _upgradeTo(address newImplementation) internal {
                    _setImplementation(newImplementation);
                    emit Upgraded(newImplementation);
                }
                /**
                 * @dev Perform implementation upgrade with additional setup call.
                 *
                 * Emits an {Upgraded} event.
                 */
                function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
                    _setImplementation(newImplementation);
                    emit Upgraded(newImplementation);
                    if (data.length > 0 || forceCall) {
                        Address.functionDelegateCall(newImplementation, data);
                    }
                }
                /**
                 * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
                 *
                 * Emits an {Upgraded} event.
                 */
                function _upgradeToAndCallSecure(address newImplementation, bytes memory data, bool forceCall) internal {
                    address oldImplementation = _getImplementation();
                    // Initial upgrade and setup call
                    _setImplementation(newImplementation);
                    if (data.length > 0 || forceCall) {
                        Address.functionDelegateCall(newImplementation, data);
                    }
                    // Perform rollback test if not already in progress
                    StorageSlot.BooleanSlot storage rollbackTesting = StorageSlot.getBooleanSlot(_ROLLBACK_SLOT);
                    if (!rollbackTesting.value) {
                        // Trigger rollback using upgradeTo from the new implementation
                        rollbackTesting.value = true;
                        Address.functionDelegateCall(
                            newImplementation,
                            abi.encodeWithSignature(
                                "upgradeTo(address)",
                                oldImplementation
                            )
                        );
                        rollbackTesting.value = false;
                        // Check rollback was effective
                        require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades");
                        // Finally reset to the new implementation and log the upgrade
                        _setImplementation(newImplementation);
                        emit Upgraded(newImplementation);
                    }
                }
                /**
                 * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
                 * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
                 *
                 * Emits a {BeaconUpgraded} event.
                 */
                function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
                    _setBeacon(newBeacon);
                    emit BeaconUpgraded(newBeacon);
                    if (data.length > 0 || forceCall) {
                        Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
                    }
                }
                /**
                 * @dev Storage slot with the admin of the contract.
                 * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
                 * validated in the constructor.
                 */
                bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
                /**
                 * @dev Emitted when the admin account has changed.
                 */
                event AdminChanged(address previousAdmin, address newAdmin);
                /**
                 * @dev Returns the current admin.
                 */
                function _getAdmin() internal view returns (address) {
                    return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
                }
                /**
                 * @dev Stores a new address in the EIP1967 admin slot.
                 */
                function _setAdmin(address newAdmin) private {
                    require(newAdmin != address(0), "ERC1967: new admin is the zero address");
                    StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
                }
                /**
                 * @dev Changes the admin of the proxy.
                 *
                 * Emits an {AdminChanged} event.
                 */
                function _changeAdmin(address newAdmin) internal {
                    emit AdminChanged(_getAdmin(), newAdmin);
                    _setAdmin(newAdmin);
                }
                /**
                 * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
                 * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
                 */
                bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
                /**
                 * @dev Emitted when the beacon is upgraded.
                 */
                event BeaconUpgraded(address indexed beacon);
                /**
                 * @dev Returns the current beacon.
                 */
                function _getBeacon() internal view returns (address) {
                    return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
                }
                /**
                 * @dev Stores a new beacon in the EIP1967 beacon slot.
                 */
                function _setBeacon(address newBeacon) private {
                    require(
                        Address.isContract(newBeacon),
                        "ERC1967: new beacon is not a contract"
                    );
                    require(
                        Address.isContract(IBeacon(newBeacon).implementation()),
                        "ERC1967: beacon implementation is not a contract"
                    );
                    StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.0;
            /**
             * @dev Collection of functions related to the address type
             */
            library Address {
                /**
                 * @dev Returns true if `account` is a contract.
                 *
                 * [IMPORTANT]
                 * ====
                 * It is unsafe to assume that an address for which this function returns
                 * false is an externally-owned account (EOA) and not a contract.
                 *
                 * Among others, `isContract` will return false for the following
                 * types of addresses:
                 *
                 *  - an externally-owned account
                 *  - a contract in construction
                 *  - an address where a contract will be created
                 *  - an address where a contract lived, but was destroyed
                 * ====
                 */
                function isContract(address account) internal view returns (bool) {
                    // This method relies on extcodesize, which returns 0 for contracts in
                    // construction, since the code is only stored at the end of the
                    // constructor execution.
                    uint256 size;
                    // solhint-disable-next-line no-inline-assembly
                    assembly { size := extcodesize(account) }
                    return size > 0;
                }
                /**
                 * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                 * `recipient`, forwarding all available gas and reverting on errors.
                 *
                 * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                 * of certain opcodes, possibly making contracts go over the 2300 gas limit
                 * imposed by `transfer`, making them unable to receive funds via
                 * `transfer`. {sendValue} removes this limitation.
                 *
                 * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                 *
                 * IMPORTANT: because control is transferred to `recipient`, care must be
                 * taken to not create reentrancy vulnerabilities. Consider using
                 * {ReentrancyGuard} or the
                 * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                 */
                function sendValue(address payable recipient, uint256 amount) internal {
                    require(address(this).balance >= amount, "Address: insufficient balance");
                    // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                    (bool success, ) = recipient.call{ value: amount }("");
                    require(success, "Address: unable to send value, recipient may have reverted");
                }
                /**
                 * @dev Performs a Solidity function call using a low level `call`. A
                 * plain`call` is an unsafe replacement for a function call: use this
                 * function instead.
                 *
                 * If `target` reverts with a revert reason, it is bubbled up by this
                 * function (like regular Solidity function calls).
                 *
                 * Returns the raw returned data. To convert to the expected return value,
                 * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                 *
                 * Requirements:
                 *
                 * - `target` must be a contract.
                 * - calling `target` with `data` must not revert.
                 *
                 * _Available since v3.1._
                 */
                function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                  return functionCall(target, data, "Address: low-level call failed");
                }
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                 * `errorMessage` as a fallback revert reason when `target` reverts.
                 *
                 * _Available since v3.1._
                 */
                function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                    return functionCallWithValue(target, data, 0, errorMessage);
                }
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                 * but also transferring `value` wei to `target`.
                 *
                 * Requirements:
                 *
                 * - the calling contract must have an ETH balance of at least `value`.
                 * - the called Solidity function must be `payable`.
                 *
                 * _Available since v3.1._
                 */
                function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                    return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                }
                /**
                 * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                 * with `errorMessage` as a fallback revert reason when `target` reverts.
                 *
                 * _Available since v3.1._
                 */
                function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
                    require(address(this).balance >= value, "Address: insufficient balance for call");
                    require(isContract(target), "Address: call to non-contract");
                    // solhint-disable-next-line avoid-low-level-calls
                    (bool success, bytes memory returndata) = target.call{ value: value }(data);
                    return _verifyCallResult(success, returndata, errorMessage);
                }
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                 * but performing a static call.
                 *
                 * _Available since v3.3._
                 */
                function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                    return functionStaticCall(target, data, "Address: low-level static call failed");
                }
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                 * but performing a static call.
                 *
                 * _Available since v3.3._
                 */
                function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
                    require(isContract(target), "Address: static call to non-contract");
                    // solhint-disable-next-line avoid-low-level-calls
                    (bool success, bytes memory returndata) = target.staticcall(data);
                    return _verifyCallResult(success, returndata, errorMessage);
                }
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                 * but performing a delegate call.
                 *
                 * _Available since v3.4._
                 */
                function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                    return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                }
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                 * but performing a delegate call.
                 *
                 * _Available since v3.4._
                 */
                function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                    require(isContract(target), "Address: delegate call to non-contract");
                    // solhint-disable-next-line avoid-low-level-calls
                    (bool success, bytes memory returndata) = target.delegatecall(data);
                    return _verifyCallResult(success, returndata, errorMessage);
                }
                function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                    if (success) {
                        return returndata;
                    } else {
                        // Look for revert reason and bubble it up if present
                        if (returndata.length > 0) {
                            // The easiest way to bubble the revert reason is using memory via assembly
                            // solhint-disable-next-line no-inline-assembly
                            assembly {
                                let returndata_size := mload(returndata)
                                revert(add(32, returndata), returndata_size)
                            }
                        } else {
                            revert(errorMessage);
                        }
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.0;
            /**
             * @dev Library for reading and writing primitive types to specific storage slots.
             *
             * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
             * This library helps with reading and writing to such slots without the need for inline assembly.
             *
             * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
             *
             * Example usage to set ERC1967 implementation slot:
             * ```
             * contract ERC1967 {
             *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
             *
             *     function _getImplementation() internal view returns (address) {
             *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
             *     }
             *
             *     function _setImplementation(address newImplementation) internal {
             *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
             *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
             *     }
             * }
             * ```
             *
             * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
             */
            library StorageSlot {
                struct AddressSlot {
                    address value;
                }
                struct BooleanSlot {
                    bool value;
                }
                struct Bytes32Slot {
                    bytes32 value;
                }
                struct Uint256Slot {
                    uint256 value;
                }
                /**
                 * @dev Returns an `AddressSlot` with member `value` located at `slot`.
                 */
                function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
                 */
                function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
                 */
                function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
                    assembly {
                        r.slot := slot
                    }
                }
                /**
                 * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
                 */
                function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
                    assembly {
                        r.slot := slot
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.0;
            import "../utils/Context.sol";
            /**
             * @dev Contract module which provides a basic access control mechanism, where
             * there is an account (an owner) that can be granted exclusive access to
             * specific functions.
             *
             * By default, the owner account will be the one that deploys the contract. This
             * can later be changed with {transferOwnership}.
             *
             * This module is used through inheritance. It will make available the modifier
             * `onlyOwner`, which can be applied to your functions to restrict their use to
             * the owner.
             */
            abstract contract Ownable is Context {
                address private _owner;
                event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
                /**
                 * @dev Initializes the contract setting the deployer as the initial owner.
                 */
                constructor () {
                    address msgSender = _msgSender();
                    _owner = msgSender;
                    emit OwnershipTransferred(address(0), msgSender);
                }
                /**
                 * @dev Returns the address of the current owner.
                 */
                function owner() public view virtual returns (address) {
                    return _owner;
                }
                /**
                 * @dev Throws if called by any account other than the owner.
                 */
                modifier onlyOwner() {
                    require(owner() == _msgSender(), "Ownable: caller is not the owner");
                    _;
                }
                /**
                 * @dev Leaves the contract without owner. It will not be possible to call
                 * `onlyOwner` functions anymore. Can only be called by the current owner.
                 *
                 * NOTE: Renouncing ownership will leave the contract without an owner,
                 * thereby removing any functionality that is only available to the owner.
                 */
                function renounceOwnership() public virtual onlyOwner {
                    emit OwnershipTransferred(_owner, address(0));
                    _owner = address(0);
                }
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`).
                 * Can only be called by the current owner.
                 */
                function transferOwnership(address newOwner) public virtual onlyOwner {
                    require(newOwner != address(0), "Ownable: new owner is the zero address");
                    emit OwnershipTransferred(_owner, newOwner);
                    _owner = newOwner;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.0;
            /*
             * @dev Provides information about the current execution context, including the
             * sender of the transaction and its data. While these are generally available
             * via msg.sender and msg.data, they should not be accessed in such a direct
             * manner, since when dealing with meta-transactions the account sending and
             * paying for execution may not be the actual sender (as far as an application
             * is concerned).
             *
             * This contract is only required for intermediate, library-like contracts.
             */
            abstract contract Context {
                function _msgSender() internal view virtual returns (address) {
                    return msg.sender;
                }
                function _msgData() internal view virtual returns (bytes calldata) {
                    this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                    return msg.data;
                }
            }
            

            File 2 of 6: Proxy
            pragma solidity ^0.5.3;
            
            /// @title Proxy - Generic proxy contract allows to execute all transactions applying the code of a master contract.
            /// @author Stefan George - <stefan@gnosis.io>
            /// @author Richard Meissner - <richard@gnosis.io>
            contract Proxy {
            
                // masterCopy 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 masterCopy;
            
                /// @dev Constructor function sets address of master copy contract.
                /// @param _masterCopy Master copy address.
                constructor(address _masterCopy)
                    public
                {
                    require(_masterCopy != address(0), "Invalid master copy address provided");
                    masterCopy = _masterCopy;
                }
            
                /// @dev Fallback function forwards all transactions and returns all received return data.
                function ()
                    external
                    payable
                {
                    // solium-disable-next-line security/no-inline-assembly
                    assembly {
                        let masterCopy := and(sload(0), 0xffffffffffffffffffffffffffffffffffffffff)
                        // 0xa619486e == keccak("masterCopy()"). The value is right padded to 32-bytes with 0s
                        if eq(calldataload(0), 0xa619486e00000000000000000000000000000000000000000000000000000000) {
                            mstore(0, masterCopy)
                            return(0, 0x20)
                        }
                        calldatacopy(0, 0, calldatasize())
                        let success := delegatecall(gas, masterCopy, 0, calldatasize(), 0, 0)
                        returndatacopy(0, 0, returndatasize())
                        if eq(success, 0) { revert(0, returndatasize()) }
                        return(0, returndatasize())
                    }
                }
            }

            File 3 of 6: Kawakami
            // File: @openzeppelin/contracts/utils/cryptography/MerkleProof.sol
            
            
            // OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/MerkleProof.sol)
            
            pragma solidity ^0.8.0;
            
            /**
             * @dev These functions deal with verification of Merkle Trees proofs.
             *
             * The proofs can be generated using the JavaScript library
             * https://github.com/miguelmota/merkletreejs[merkletreejs].
             * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled.
             *
             * See `test/utils/cryptography/MerkleProof.test.js` for some examples.
             */
            library MerkleProof {
                /**
                 * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
                 * defined by `root`. For this, a `proof` must be provided, containing
                 * sibling hashes on the branch from the leaf to the root of the tree. Each
                 * pair of leaves and each pair of pre-images are assumed to be sorted.
                 */
                function verify(
                    bytes32[] memory proof,
                    bytes32 root,
                    bytes32 leaf
                ) internal pure returns (bool) {
                    return processProof(proof, leaf) == root;
                }
            
                /**
                 * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up
                 * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
                 * hash matches the root of the tree. When processing the proof, the pairs
                 * of leafs & pre-images are assumed to be sorted.
                 *
                 * _Available since v4.4._
                 */
                function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
                    bytes32 computedHash = leaf;
                    for (uint256 i = 0; i < proof.length; i++) {
                        bytes32 proofElement = proof[i];
                        if (computedHash <= proofElement) {
                            // Hash(current computed hash + current element of the proof)
                            computedHash = _efficientHash(computedHash, proofElement);
                        } else {
                            // Hash(current element of the proof + current computed hash)
                            computedHash = _efficientHash(proofElement, computedHash);
                        }
                    }
                    return computedHash;
                }
            
                function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
                    assembly {
                        mstore(0x00, a)
                        mstore(0x20, b)
                        value := keccak256(0x00, 0x40)
                    }
                }
            }
            
            // File: @openzeppelin/contracts/security/ReentrancyGuard.sol
            
            
            // OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)
            
            pragma solidity ^0.8.0;
            
            /**
             * @dev Contract module that helps prevent reentrant calls to a function.
             *
             * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
             * available, which can be applied to functions to make sure there are no nested
             * (reentrant) calls to them.
             *
             * Note that because there is a single `nonReentrant` guard, functions marked as
             * `nonReentrant` may not call one another. This can be worked around by making
             * those functions `private`, and then adding `external` `nonReentrant` entry
             * points to them.
             *
             * TIP: If you would like to learn more about reentrancy and alternative ways
             * to protect against it, check out our blog post
             * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
             */
            abstract contract ReentrancyGuard {
                // Booleans are more expensive than uint256 or any type that takes up a full
                // word because each write operation emits an extra SLOAD to first read the
                // slot's contents, replace the bits taken up by the boolean, and then write
                // back. This is the compiler's defense against contract upgrades and
                // pointer aliasing, and it cannot be disabled.
            
                // The values being non-zero value makes deployment a bit more expensive,
                // but in exchange the refund on every call to nonReentrant will be lower in
                // amount. Since refunds are capped to a percentage of the total
                // transaction's gas, it is best to keep them low in cases like this one, to
                // increase the likelihood of the full refund coming into effect.
                uint256 private constant _NOT_ENTERED = 1;
                uint256 private constant _ENTERED = 2;
            
                uint256 private _status;
            
                constructor() {
                    _status = _NOT_ENTERED;
                }
            
                /**
                 * @dev Prevents a contract from calling itself, directly or indirectly.
                 * Calling a `nonReentrant` function from another `nonReentrant`
                 * function is not supported. It is possible to prevent this from happening
                 * by making the `nonReentrant` function external, and making it call a
                 * `private` function that does the actual work.
                 */
                modifier nonReentrant() {
                    // On the first call to nonReentrant, _notEntered will be true
                    require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
            
                    // Any calls to nonReentrant after this point will fail
                    _status = _ENTERED;
            
                    _;
            
                    // By storing the original value once again, a refund is triggered (see
                    // https://eips.ethereum.org/EIPS/eip-2200)
                    _status = _NOT_ENTERED;
                }
            }
            
            // File: @openzeppelin/contracts/utils/Strings.sol
            
            
            // OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)
            
            pragma solidity ^0.8.0;
            
            /**
             * @dev String operations.
             */
            library Strings {
                bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
            
                /**
                 * @dev Converts a `uint256` to its ASCII `string` decimal representation.
                 */
                function toString(uint256 value) internal pure returns (string memory) {
                    // Inspired by OraclizeAPI's implementation - MIT licence
                    // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
            
                    if (value == 0) {
                        return "0";
                    }
                    uint256 temp = value;
                    uint256 digits;
                    while (temp != 0) {
                        digits++;
                        temp /= 10;
                    }
                    bytes memory buffer = new bytes(digits);
                    while (value != 0) {
                        digits -= 1;
                        buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
                        value /= 10;
                    }
                    return string(buffer);
                }
            
                /**
                 * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
                 */
                function toHexString(uint256 value) internal pure returns (string memory) {
                    if (value == 0) {
                        return "0x00";
                    }
                    uint256 temp = value;
                    uint256 length = 0;
                    while (temp != 0) {
                        length++;
                        temp >>= 8;
                    }
                    return toHexString(value, length);
                }
            
                /**
                 * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
                 */
                function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
                    bytes memory buffer = new bytes(2 * length + 2);
                    buffer[0] = "0";
                    buffer[1] = "x";
                    for (uint256 i = 2 * length + 1; i > 1; --i) {
                        buffer[i] = _HEX_SYMBOLS[value & 0xf];
                        value >>= 4;
                    }
                    require(value == 0, "Strings: hex length insufficient");
                    return string(buffer);
                }
            }
            
            // File: @openzeppelin/contracts/utils/Context.sol
            
            
            // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
            
            pragma solidity ^0.8.0;
            
            /**
             * @dev Provides information about the current execution context, including the
             * sender of the transaction and its data. While these are generally available
             * via msg.sender and msg.data, they should not be accessed in such a direct
             * manner, since when dealing with meta-transactions the account sending and
             * paying for execution may not be the actual sender (as far as an application
             * is concerned).
             *
             * This contract is only required for intermediate, library-like contracts.
             */
            abstract contract Context {
                function _msgSender() internal view virtual returns (address) {
                    return msg.sender;
                }
            
                function _msgData() internal view virtual returns (bytes calldata) {
                    return msg.data;
                }
            }
            
            // File: @openzeppelin/contracts/access/Ownable.sol
            
            
            // OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)
            
            pragma solidity ^0.8.0;
            
            
            /**
             * @dev Contract module which provides a basic access control mechanism, where
             * there is an account (an owner) that can be granted exclusive access to
             * specific functions.
             *
             * By default, the owner account will be the one that deploys the contract. This
             * can later be changed with {transferOwnership}.
             *
             * This module is used through inheritance. It will make available the modifier
             * `onlyOwner`, which can be applied to your functions to restrict their use to
             * the owner.
             */
            abstract contract Ownable is Context {
                address private _owner;
            
                event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
            
                /**
                 * @dev Initializes the contract setting the deployer as the initial owner.
                 */
                constructor() {
                    _transferOwnership(_msgSender());
                }
            
                /**
                 * @dev Returns the address of the current owner.
                 */
                function owner() public view virtual returns (address) {
                    return _owner;
                }
            
                /**
                 * @dev Throws if called by any account other than the owner.
                 */
                modifier onlyOwner() {
                    require(owner() == _msgSender(), "Ownable: caller is not the owner");
                    _;
                }
            
                /**
                 * @dev Leaves the contract without owner. It will not be possible to call
                 * `onlyOwner` functions anymore. Can only be called by the current owner.
                 *
                 * NOTE: Renouncing ownership will leave the contract without an owner,
                 * thereby removing any functionality that is only available to the owner.
                 */
                function renounceOwnership() public virtual onlyOwner {
                    _transferOwnership(address(0));
                }
            
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`).
                 * Can only be called by the current owner.
                 */
                function transferOwnership(address newOwner) public virtual onlyOwner {
                    require(newOwner != address(0), "Ownable: new owner is the zero address");
                    _transferOwnership(newOwner);
                }
            
                /**
                 * @dev Transfers ownership of the contract to a new account (`newOwner`).
                 * Internal function without access restriction.
                 */
                function _transferOwnership(address newOwner) internal virtual {
                    address oldOwner = _owner;
                    _owner = newOwner;
                    emit OwnershipTransferred(oldOwner, newOwner);
                }
            }
            
            // File: @openzeppelin/contracts/utils/Address.sol
            
            
            // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)
            
            pragma solidity ^0.8.1;
            
            /**
             * @dev Collection of functions related to the address type
             */
            library Address {
                /**
                 * @dev Returns true if `account` is a contract.
                 *
                 * [IMPORTANT]
                 * ====
                 * It is unsafe to assume that an address for which this function returns
                 * false is an externally-owned account (EOA) and not a contract.
                 *
                 * Among others, `isContract` will return false for the following
                 * types of addresses:
                 *
                 *  - an externally-owned account
                 *  - a contract in construction
                 *  - an address where a contract will be created
                 *  - an address where a contract lived, but was destroyed
                 * ====
                 *
                 * [IMPORTANT]
                 * ====
                 * You shouldn't rely on `isContract` to protect against flash loan attacks!
                 *
                 * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
                 * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
                 * constructor.
                 * ====
                 */
                function isContract(address account) internal view returns (bool) {
                    // This method relies on extcodesize/address.code.length, which returns 0
                    // for contracts in construction, since the code is only stored at the end
                    // of the constructor execution.
            
                    return account.code.length > 0;
                }
            
                /**
                 * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                 * `recipient`, forwarding all available gas and reverting on errors.
                 *
                 * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                 * of certain opcodes, possibly making contracts go over the 2300 gas limit
                 * imposed by `transfer`, making them unable to receive funds via
                 * `transfer`. {sendValue} removes this limitation.
                 *
                 * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                 *
                 * IMPORTANT: because control is transferred to `recipient`, care must be
                 * taken to not create reentrancy vulnerabilities. Consider using
                 * {ReentrancyGuard} or the
                 * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                 */
                function sendValue(address payable recipient, uint256 amount) internal {
                    require(address(this).balance >= amount, "Address: insufficient balance");
            
                    (bool success, ) = recipient.call{value: amount}("");
                    require(success, "Address: unable to send value, recipient may have reverted");
                }
            
                /**
                 * @dev Performs a Solidity function call using a low level `call`. A
                 * plain `call` is an unsafe replacement for a function call: use this
                 * function instead.
                 *
                 * If `target` reverts with a revert reason, it is bubbled up by this
                 * function (like regular Solidity function calls).
                 *
                 * Returns the raw returned data. To convert to the expected return value,
                 * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                 *
                 * Requirements:
                 *
                 * - `target` must be a contract.
                 * - calling `target` with `data` must not revert.
                 *
                 * _Available since v3.1._
                 */
                function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                    return functionCall(target, data, "Address: low-level call failed");
                }
            
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                 * `errorMessage` as a fallback revert reason when `target` reverts.
                 *
                 * _Available since v3.1._
                 */
                function functionCall(
                    address target,
                    bytes memory data,
                    string memory errorMessage
                ) internal returns (bytes memory) {
                    return functionCallWithValue(target, data, 0, errorMessage);
                }
            
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                 * but also transferring `value` wei to `target`.
                 *
                 * Requirements:
                 *
                 * - the calling contract must have an ETH balance of at least `value`.
                 * - the called Solidity function must be `payable`.
                 *
                 * _Available since v3.1._
                 */
                function functionCallWithValue(
                    address target,
                    bytes memory data,
                    uint256 value
                ) internal returns (bytes memory) {
                    return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                }
            
                /**
                 * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                 * with `errorMessage` as a fallback revert reason when `target` reverts.
                 *
                 * _Available since v3.1._
                 */
                function functionCallWithValue(
                    address target,
                    bytes memory data,
                    uint256 value,
                    string memory errorMessage
                ) internal returns (bytes memory) {
                    require(address(this).balance >= value, "Address: insufficient balance for call");
                    require(isContract(target), "Address: call to non-contract");
            
                    (bool success, bytes memory returndata) = target.call{value: value}(data);
                    return verifyCallResult(success, returndata, errorMessage);
                }
            
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                 * but performing a static call.
                 *
                 * _Available since v3.3._
                 */
                function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                    return functionStaticCall(target, data, "Address: low-level static call failed");
                }
            
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                 * but performing a static call.
                 *
                 * _Available since v3.3._
                 */
                function functionStaticCall(
                    address target,
                    bytes memory data,
                    string memory errorMessage
                ) internal view returns (bytes memory) {
                    require(isContract(target), "Address: static call to non-contract");
            
                    (bool success, bytes memory returndata) = target.staticcall(data);
                    return verifyCallResult(success, returndata, errorMessage);
                }
            
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                 * but performing a delegate call.
                 *
                 * _Available since v3.4._
                 */
                function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                    return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                }
            
                /**
                 * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                 * but performing a delegate call.
                 *
                 * _Available since v3.4._
                 */
                function functionDelegateCall(
                    address target,
                    bytes memory data,
                    string memory errorMessage
                ) internal returns (bytes memory) {
                    require(isContract(target), "Address: delegate call to non-contract");
            
                    (bool success, bytes memory returndata) = target.delegatecall(data);
                    return verifyCallResult(success, returndata, errorMessage);
                }
            
                /**
                 * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
                 * revert reason using the provided one.
                 *
                 * _Available since v4.3._
                 */
                function verifyCallResult(
                    bool success,
                    bytes memory returndata,
                    string memory errorMessage
                ) internal pure returns (bytes memory) {
                    if (success) {
                        return returndata;
                    } else {
                        // Look for revert reason and bubble it up if present
                        if (returndata.length > 0) {
                            // The easiest way to bubble the revert reason is using memory via assembly
            
                            assembly {
                                let returndata_size := mload(returndata)
                                revert(add(32, returndata), returndata_size)
                            }
                        } else {
                            revert(errorMessage);
                        }
                    }
                }
            }
            
            // File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol
            
            
            // OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol)
            
            pragma solidity ^0.8.0;
            
            /**
             * @title ERC721 token receiver interface
             * @dev Interface for any contract that wants to support safeTransfers
             * from ERC721 asset contracts.
             */
            interface IERC721Receiver {
                /**
                 * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
                 * by `operator` from `from`, this function is called.
                 *
                 * It must return its Solidity selector to confirm the token transfer.
                 * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
                 *
                 * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
                 */
                function onERC721Received(
                    address operator,
                    address from,
                    uint256 tokenId,
                    bytes calldata data
                ) external returns (bytes4);
            }
            
            // File: @openzeppelin/contracts/utils/introspection/IERC165.sol
            
            
            // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
            
            pragma solidity ^0.8.0;
            
            /**
             * @dev Interface of the ERC165 standard, as defined in the
             * https://eips.ethereum.org/EIPS/eip-165[EIP].
             *
             * Implementers can declare support of contract interfaces, which can then be
             * queried by others ({ERC165Checker}).
             *
             * For an implementation, see {ERC165}.
             */
            interface IERC165 {
                /**
                 * @dev Returns true if this contract implements the interface defined by
                 * `interfaceId`. See the corresponding
                 * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
                 * to learn more about how these ids are created.
                 *
                 * This function call must use less than 30 000 gas.
                 */
                function supportsInterface(bytes4 interfaceId) external view returns (bool);
            }
            
            // File: @openzeppelin/contracts/utils/introspection/ERC165.sol
            
            
            // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
            
            pragma solidity ^0.8.0;
            
            
            /**
             * @dev Implementation of the {IERC165} interface.
             *
             * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
             * for the additional interface id that will be supported. For example:
             *
             * ```solidity
             * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
             *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
             * }
             * ```
             *
             * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
             */
            abstract contract ERC165 is IERC165 {
                /**
                 * @dev See {IERC165-supportsInterface}.
                 */
                function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                    return interfaceId == type(IERC165).interfaceId;
                }
            }
            
            // File: @openzeppelin/contracts/token/ERC721/IERC721.sol
            
            
            // OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)
            
            pragma solidity ^0.8.0;
            
            
            /**
             * @dev Required interface of an ERC721 compliant contract.
             */
            interface IERC721 is IERC165 {
                /**
                 * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
                 */
                event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
            
                /**
                 * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
                 */
                event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
            
                /**
                 * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
                 */
                event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
            
                /**
                 * @dev Returns the number of tokens in ``owner``'s account.
                 */
                function balanceOf(address owner) external view returns (uint256 balance);
            
                /**
                 * @dev Returns the owner of the `tokenId` token.
                 *
                 * Requirements:
                 *
                 * - `tokenId` must exist.
                 */
                function ownerOf(uint256 tokenId) external view returns (address owner);
            
                /**
                 * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
                 * are aware of the ERC721 protocol to prevent tokens from being forever locked.
                 *
                 * Requirements:
                 *
                 * - `from` cannot be the zero address.
                 * - `to` cannot be the zero address.
                 * - `tokenId` token must exist and be owned by `from`.
                 * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
                 * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
                 *
                 * Emits a {Transfer} event.
                 */
                function safeTransferFrom(
                    address from,
                    address to,
                    uint256 tokenId
                ) external;
            
                /**
                 * @dev Transfers `tokenId` token from `from` to `to`.
                 *
                 * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
                 *
                 * Requirements:
                 *
                 * - `from` cannot be the zero address.
                 * - `to` cannot be the zero address.
                 * - `tokenId` token must be owned by `from`.
                 * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
                 *
                 * Emits a {Transfer} event.
                 */
                function transferFrom(
                    address from,
                    address to,
                    uint256 tokenId
                ) external;
            
                /**
                 * @dev Gives permission to `to` to transfer `tokenId` token to another account.
                 * The approval is cleared when the token is transferred.
                 *
                 * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
                 *
                 * Requirements:
                 *
                 * - The caller must own the token or be an approved operator.
                 * - `tokenId` must exist.
                 *
                 * Emits an {Approval} event.
                 */
                function approve(address to, uint256 tokenId) external;
            
                /**
                 * @dev Returns the account approved for `tokenId` token.
                 *
                 * Requirements:
                 *
                 * - `tokenId` must exist.
                 */
                function getApproved(uint256 tokenId) external view returns (address operator);
            
                /**
                 * @dev Approve or remove `operator` as an operator for the caller.
                 * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
                 *
                 * Requirements:
                 *
                 * - The `operator` cannot be the caller.
                 *
                 * Emits an {ApprovalForAll} event.
                 */
                function setApprovalForAll(address operator, bool _approved) external;
            
                /**
                 * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
                 *
                 * See {setApprovalForAll}
                 */
                function isApprovedForAll(address owner, address operator) external view returns (bool);
            
                /**
                 * @dev Safely transfers `tokenId` token from `from` to `to`.
                 *
                 * Requirements:
                 *
                 * - `from` cannot be the zero address.
                 * - `to` cannot be the zero address.
                 * - `tokenId` token must exist and be owned by `from`.
                 * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
                 * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
                 *
                 * Emits a {Transfer} event.
                 */
                function safeTransferFrom(
                    address from,
                    address to,
                    uint256 tokenId,
                    bytes calldata data
                ) external;
            }
            
            // File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol
            
            
            // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol)
            
            pragma solidity ^0.8.0;
            
            
            /**
             * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
             * @dev See https://eips.ethereum.org/EIPS/eip-721
             */
            interface IERC721Enumerable is IERC721 {
                /**
                 * @dev Returns the total amount of tokens stored by the contract.
                 */
                function totalSupply() external view returns (uint256);
            
                /**
                 * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
                 * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
                 */
                function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
            
                /**
                 * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
                 * Use along with {totalSupply} to enumerate all tokens.
                 */
                function tokenByIndex(uint256 index) external view returns (uint256);
            }
            
            // File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol
            
            
            // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)
            
            pragma solidity ^0.8.0;
            
            
            /**
             * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
             * @dev See https://eips.ethereum.org/EIPS/eip-721
             */
            interface IERC721Metadata is IERC721 {
                /**
                 * @dev Returns the token collection name.
                 */
                function name() external view returns (string memory);
            
                /**
                 * @dev Returns the token collection symbol.
                 */
                function symbol() external view returns (string memory);
            
                /**
                 * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
                 */
                function tokenURI(uint256 tokenId) external view returns (string memory);
            }
            
            // File: contracts/nft.sol
            
            
            
            pragma solidity ^0.8.7;
            
            
            
            
            
            
            
            
            
            
            
            
            
            /**
             * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
             * the Metadata and Enumerable extension. Built to optimize for lower gas during batch mints.
             *
             * Assumes serials are sequentially minted starting at 0 (e.g. 0, 1, 2, 3..).
             *
             * Assumes the number of issuable tokens (collection size) is capped and fits in a uint128.
             *
             * Does not support burning tokens to address(0).
             */
            contract ERC721A is
                Context,
                ERC165,
                IERC721,
                IERC721Metadata,
                IERC721Enumerable
            {
                using Address for address;
                using Strings for uint256;
            
                struct TokenOwnership {
                    address addr;
                    uint64 startTimestamp;
                }
            
                struct AddressData {
                    uint128 balance;
                    uint128 numberMinted;
                }
            
                uint256 private currentIndex = 0;
            
                uint256 internal immutable collectionSize;
                uint256 internal immutable maxBatchSize;
            
                // Token name
                string private _name;
            
                // Token symbol
                string private _symbol;
            
                // Mapping from token ID to ownership details
                // An empty struct value does not necessarily mean the token is unowned. See ownershipOf implementation for details.
                mapping(uint256 => TokenOwnership) private _ownerships;
            
                // Mapping owner address to address data
                mapping(address => AddressData) private _addressData;
            
                // Mapping from token ID to approved address
                mapping(uint256 => address) private _tokenApprovals;
            
                // Mapping from owner to operator approvals
                mapping(address => mapping(address => bool)) private _operatorApprovals;
            
                //Mapping to check staking status
                mapping(uint256 => uint256) private stakingData;
            
                /**
                 * @dev
                 * `maxBatchSize` refers to how much a minter can mint at a time.
                 * `collectionSize_` refers to how many tokens are in the collection.
                 */
                constructor(
                    string memory name_,
                    string memory symbol_,
                    uint256 maxBatchSize_,
                    uint256 collectionSize_
                ) {
                    require(
                        collectionSize_ > 0,
                        "ERC721A: collection must have a nonzero supply"
                    );
                    require(maxBatchSize_ > 0, "ERC721A: max batch size must be nonzero");
                    _name = name_;
                    _symbol = symbol_;
                    maxBatchSize = maxBatchSize_;
                    collectionSize = collectionSize_;
                }
            
                /**
                 * @dev See {IERC721Enumerable-totalSupply}.
                 */
                function totalSupply() public view override returns (uint256) {
                    return currentIndex;
                }
            
                /**
                 * @dev See {IERC721Enumerable-tokenByIndex}.
                 */
                function tokenByIndex(uint256 index)
                    public
                    view
                    override
                    returns (uint256)
                {
                    require(index < totalSupply(), "ERC721A: global index out of bounds");
                    return index;
                }
            
                /**
                 * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
                 * This read function is O(collectionSize). If calling from a separate contract, be sure to test gas first.
                 * It may also degrade with extremely large collection sizes (e.g >> 10000), test for your use case.
                 */
                function tokenOfOwnerByIndex(address owner, uint256 index)
                    public
                    view
                    override
                    returns (uint256)
                {
                    require(index < balanceOf(owner), "ERC721A: owner index out of bounds");
                    uint256 numMintedSoFar = totalSupply();
                    uint256 tokenIdsIdx = 0;
                    address currOwnershipAddr = address(0);
                    for (uint256 i = 0; i < numMintedSoFar; i++) {
                        TokenOwnership memory ownership = _ownerships[i];
                        if (ownership.addr != address(0)) {
                            currOwnershipAddr = ownership.addr;
                        }
                        if (currOwnershipAddr == owner) {
                            if (tokenIdsIdx == index) {
                                return i;
                            }
                            tokenIdsIdx++;
                        }
                    }
                    revert("ERC721A: unable to get token of owner by index");
                }
            
                /**
                 * @dev See {IERC165-supportsInterface}.
                 */
                function supportsInterface(bytes4 interfaceId)
                    public
                    view
                    virtual
                    override(ERC165, IERC165)
                    returns (bool)
                {
                    return
                        interfaceId == type(IERC721).interfaceId ||
                        interfaceId == type(IERC721Metadata).interfaceId ||
                        interfaceId == type(IERC721Enumerable).interfaceId ||
                        super.supportsInterface(interfaceId);
                }
            
                /**
                 * @dev See {IERC721-balanceOf}.
                 */
                function balanceOf(address owner) public view override returns (uint256) {
                    require(
                        owner != address(0),
                        "ERC721A: balance query for the zero address"
                    );
                    return uint256(_addressData[owner].balance);
                }
            
                function _numberMinted(address owner) internal view returns (uint256) {
                    require(
                        owner != address(0),
                        "ERC721A: number minted query for the zero address"
                    );
                    return uint256(_addressData[owner].numberMinted);
                }
            
                function ownershipOf(uint256 tokenId)
                    internal
                    view
                    returns (TokenOwnership memory)
                {
                    require(_exists(tokenId), "ERC721A: owner query for nonexistent token");
            
                    uint256 lowestTokenToCheck;
                    if (tokenId >= maxBatchSize) {
                        lowestTokenToCheck = tokenId - maxBatchSize + 1;
                    }
            
                    for (uint256 curr = tokenId; curr >= lowestTokenToCheck; curr--) {
                        TokenOwnership memory ownership = _ownerships[curr];
                        if (ownership.addr != address(0)) {
                            return ownership;
                        }
                    }
            
                    revert("ERC721A: unable to determine the owner of token");
                }
            
                /**
                 * @dev See {IERC721-ownerOf}.
                 */
                function ownerOf(uint256 tokenId) public view override returns (address) {
                    return ownershipOf(tokenId).addr;
                }
            
                /**
                 * @dev See {IERC721Metadata-name}.
                 */
                function name() public view virtual override returns (string memory) {
                    return _name;
                }
            
                /**
                 * @dev See {IERC721Metadata-symbol}.
                 */
                function symbol() public view virtual override returns (string memory) {
                    return _symbol;
                }
            
                /**
                 * @dev See {IERC721Metadata-tokenURI}.
                 */
                function tokenURI(uint256 tokenId)
                    public
                    view
                    virtual
                    override
                    returns (string memory)
                {
                    require(
                        _exists(tokenId),
                        "ERC721Metadata: URI query for nonexistent token"
                    );
            
                    string memory baseURI = _baseURI();
                    return
                        bytes(baseURI).length > 0
                            ? string(abi.encodePacked(baseURI, tokenId.toString()))
                            : "";
                }
            
                /**
                 * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
                 * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
                 * by default, can be overriden in child contracts.
                 */
                function _baseURI() internal view virtual returns (string memory) {
                    return "";
                }
            
                /**
                 * @dev See {IERC721-approve}.
                 */
                function approve(address to, uint256 tokenId) public override {
                    address owner = ERC721A.ownerOf(tokenId);
                    require(to != owner, "ERC721A: approval to current owner");
            
                    require(
                        _msgSender() == owner || isApprovedForAll(owner, _msgSender()),
                        "ERC721A: approve caller is not owner nor approved for all"
                    );
            
                    _approve(to, tokenId, owner);
                }
            
                /**
                 * @dev See {IERC721-getApproved}.
                 */
                function getApproved(uint256 tokenId)
                    public
                    view
                    override
                    returns (address)
                {
                    require(
                        _exists(tokenId),
                        "ERC721A: approved query for nonexistent token"
                    );
            
                    return _tokenApprovals[tokenId];
                }
            
                /**
                 * @dev See {IERC721-setApprovalForAll}.
                 */
                function setApprovalForAll(address operator, bool approved)
                    public
                    override
                {
                    require(operator != _msgSender(), "ERC721A: approve to caller");
            
                    _operatorApprovals[_msgSender()][operator] = approved;
                    emit ApprovalForAll(_msgSender(), operator, approved);
                }
            
                /**
                 * @dev See {IERC721-isApprovedForAll}.
                 */
                function isApprovedForAll(address owner, address operator)
                    public
                    view
                    virtual
                    override
                    returns (bool)
                {
                    return _operatorApprovals[owner][operator];
                }
            
                /**
                 * @dev See {IERC721-transferFrom}.
                 */
                function transferFrom(
                    address from,
                    address to,
                    uint256 tokenId
                ) public override {
                    _transfer(from, to, tokenId);
                }
            
                /**
                 * @dev See {IERC721-safeTransferFrom}.
                 */
                function safeTransferFrom(
                    address from,
                    address to,
                    uint256 tokenId
                ) public override {
                    safeTransferFrom(from, to, tokenId, "");
                }
            
                /**
                 * @dev See {IERC721-safeTransferFrom}.
                 */
                function safeTransferFrom(
                    address from,
                    address to,
                    uint256 tokenId,
                    bytes memory _data
                ) public override {
                    _transfer(from, to, tokenId);
                    require(
                        _checkOnERC721Received(from, to, tokenId, _data),
                        "ERC721A: transfer to non ERC721Receiver implementer"
                    );
                }
            
                /**
                 * @dev Returns whether `tokenId` exists.
                 *
                 * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
                 *
                 * Tokens start existing when they are minted (`_mint`),
                 */
                function _exists(uint256 tokenId) internal view returns (bool) {
                    return tokenId < currentIndex;
                }
            
                function _safeMint(address to, uint256 quantity) internal {
                    _safeMint(to, quantity, "");
                }
            
                event stakingEnabled(address _owner, uint256[] _tokenID);
                event unstaked(address _owner, uint256[] _tokenID);
                event claimed(address _owner, uint256[] _tokenID);
            
                // Start staking
                function enableMultiStaking(uint256[] calldata tokenIds)
                    external
                    returns (bool)
                {
                    uint256 tokenId = 0;
                    for (uint256 i = 0; i < tokenIds.length; i++) {
                        tokenId = tokenIds[i];
                        require(msg.sender == ownerOf(tokenId), "Not the owner of nft");
                        require(stakingData[tokenId] == 0, "Staking Already Enabled");
                        stakingData[tokenId] = block.timestamp;
                    }
                    emit stakingEnabled(ownershipOf(tokenId).addr, tokenIds);
                    return true;
                }
            
                //Function to claim and optional unstake multiple nfts
                function multiUpdateStaking(uint256[] calldata tokenIds, bool unStake)
                    external
                    returns (uint256[] memory stakedTime)
                {
                    uint256[] memory stakedTimes = new uint256[](tokenIds.length);
                    for (uint256 i = 0; i < tokenIds.length; i++) {
                        uint256 tokenId = tokenIds[i];
                        bool isApprovedOrOwner = (_msgSender() ==
                            ownershipOf(tokenId).addr ||
                            getApproved(tokenId) == _msgSender() ||
                            isApprovedForAll(ownershipOf(tokenId).addr, _msgSender()));
                        require(isApprovedOrOwner, "Sender is not owner or approved");
                        uint256 stakingStartTime = stakingData[tokenId];
                        require(stakingStartTime > 0, "NFT not staked"); // Make Sure call is only for staked NFTs
                        stakedTimes[i] = block.timestamp - stakingStartTime; //  Storing Time NFT was staked for
                        if (unStake) {
                            stakingData[tokenId] = 0;
                        } else {
                            stakingData[tokenId] = block.timestamp; // Setting Current time as staking start time
                        }
                    }
                    if (unStake) {
                        emit unstaked(_msgSender(), tokenIds);
                    } else {
                        emit claimed(_msgSender(), tokenIds);
                    }
                    return stakedTimes;
                }
            
                // Unstake the NFT
                //   function disableStaking(uint256 tokenId) external returns(bool){
            
                //     bool isApprovedOrOwner = (_msgSender() == ownershipOf(tokenId).addr ||
                //       getApproved(tokenId) == _msgSender() ||
                //       isApprovedForAll(ownershipOf(tokenId).addr, _msgSender()));
                //     uint256 stakingStartTime = stakingData[tokenId];
                //     require(stakingStartTime != 0, "NFT not staked");
                //     // require(stakingStartTime < block.timestamp, "Staking not started");
                //     require(isApprovedOrOwner, "Sender is not owner or approved");
                //     // uint256 stakedTime = block.timestamp - stakingStartTime;
                //     stakingData[tokenId] = 0;
                //     emit unstaked(ownershipOf(tokenId).addr,tokenId);
                //     return true;
                //   }
            
                function getStakingTime(uint256 tokenId) external view returns (uint256) {
                    uint256 stakingStartTime = stakingData[tokenId];
                    return stakingStartTime;
                }
            
                /**
                 * @dev Mints `quantity` tokens and transfers them to `to`.
                 *
                 * Requirements:
                 *
                 * - there must be `quantity` tokens remaining unminted in the total collection.
                 * - `to` cannot be the zero address.
                 * - `quantity` cannot be larger than the max batch size.
                 *
                 * Emits a {Transfer} event.
                 */
                function _safeMint(
                    address to,
                    uint256 quantity,
                    bytes memory _data
                ) internal {
                    uint256 startTokenId = currentIndex;
                    require(to != address(0), "ERC721A: mint to the zero address");
                    // We know if the first token in the batch doesn't exist, the other ones don't as well, because of serial ordering.
                    require(!_exists(startTokenId), "ERC721A: token already minted");
                    require(quantity <= maxBatchSize, "ERC721A: quantity to mint too high");
            
                    _beforeTokenTransfers(address(0), to, startTokenId, quantity);
            
                    AddressData memory addressData = _addressData[to];
                    _addressData[to] = AddressData(
                        addressData.balance + uint64(quantity),
                        addressData.numberMinted + uint64(quantity)
                    );
                    _ownerships[startTokenId] = TokenOwnership(to, uint64(block.timestamp));
            
                    uint256 updatedIndex = startTokenId;
            
                    for (uint256 i = 0; i < quantity; i++) {
                        emit Transfer(address(0), to, updatedIndex);
                        require(
                            _checkOnERC721Received(address(0), to, updatedIndex, _data),
                            "ERC721A: transfer to non ERC721Receiver implementer"
                        );
                        updatedIndex++;
                    }
            
                    currentIndex = updatedIndex;
                    _afterTokenTransfers(address(0), to, startTokenId, quantity);
                }
            
                function resetMintCountForWhiteList(address _addr) internal {
                    _addressData[_addr].numberMinted = 0;
                }
            
                /**
                 * @dev Transfers `tokenId` from `from` to `to`.
                 *
                 * Requirements:
                 *
                 * - `to` cannot be the zero address.
                 * - `tokenId` token must be owned by `from`.
                 *
                 * Emits a {Transfer} event.
                 */
                function _transfer(
                    address from,
                    address to,
                    uint256 tokenId
                ) private {
                    require(
                        stakingData[tokenId] == 0,
                        "Staking enabled, Disable staking to transfer"
                    );
                    TokenOwnership memory prevOwnership = ownershipOf(tokenId);
            
                    bool isApprovedOrOwner = (_msgSender() == prevOwnership.addr ||
                        getApproved(tokenId) == _msgSender() ||
                        isApprovedForAll(prevOwnership.addr, _msgSender()));
            
                    require(
                        isApprovedOrOwner,
                        "ERC721A: transfer caller is not owner nor approved"
                    );
            
                    require(
                        prevOwnership.addr == from,
                        "ERC721A: transfer from incorrect owner"
                    );
                    require(to != address(0), "ERC721A: transfer to the zero address");
            
                    _beforeTokenTransfers(from, to, tokenId, 1);
            
                    // Clear approvals from the previous owner
                    _approve(address(0), tokenId, prevOwnership.addr);
            
                    _addressData[from].balance -= 1;
                    _addressData[to].balance += 1;
                    _ownerships[tokenId] = TokenOwnership(to, uint64(block.timestamp));
            
                    // If the ownership slot of tokenId+1 is not explicitly set, that means the transfer initiator owns it.
                    // Set the slot of tokenId+1 explicitly in storage to maintain correctness for ownerOf(tokenId+1) calls.
                    uint256 nextTokenId = tokenId + 1;
                    if (_ownerships[nextTokenId].addr == address(0)) {
                        if (_exists(nextTokenId)) {
                            _ownerships[nextTokenId] = TokenOwnership(
                                prevOwnership.addr,
                                prevOwnership.startTimestamp
                            );
                        }
                    }
            
                    emit Transfer(from, to, tokenId);
                    _afterTokenTransfers(from, to, tokenId, 1);
                }
            
                /**
                 * @dev Approve `to` to operate on `tokenId`
                 *
                 * Emits a {Approval} event.
                 */
                function _approve(
                    address to,
                    uint256 tokenId,
                    address owner
                ) private {
                    _tokenApprovals[tokenId] = to;
                    emit Approval(owner, to, tokenId);
                }
            
                uint256 public nextOwnerToExplicitlySet = 0;
            
                /**
                 * @dev Explicitly set `owners` to eliminate loops in future calls of ownerOf().
                 */
                function _setOwnersExplicit(uint256 quantity) internal {
                    uint256 oldNextOwnerToSet = nextOwnerToExplicitlySet;
                    require(quantity > 0, "quantity must be nonzero");
                    uint256 endIndex = oldNextOwnerToSet + quantity - 1;
                    if (endIndex > collectionSize - 1) {
                        endIndex = collectionSize - 1;
                    }
                    // We know if the last one in the group exists, all in the group exist, due to serial ordering.
                    require(_exists(endIndex), "not enough minted yet for this cleanup");
                    for (uint256 i = oldNextOwnerToSet; i <= endIndex; i++) {
                        if (_ownerships[i].addr == address(0)) {
                            TokenOwnership memory ownership = ownershipOf(i);
                            _ownerships[i] = TokenOwnership(
                                ownership.addr,
                                ownership.startTimestamp
                            );
                        }
                    }
                    nextOwnerToExplicitlySet = endIndex + 1;
                }
            
                /**
                 * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
                 * The call is not executed if the target address is not a contract.
                 *
                 * @param from address representing the previous owner of the given token ID
                 * @param to target address that will receive the tokens
                 * @param tokenId uint256 ID of the token to be transferred
                 * @param _data bytes optional data to send along with the call
                 * @return bool whether the call correctly returned the expected magic value
                 */
                function _checkOnERC721Received(
                    address from,
                    address to,
                    uint256 tokenId,
                    bytes memory _data
                ) private returns (bool) {
                    if (to.isContract()) {
                        try
                            IERC721Receiver(to).onERC721Received(
                                _msgSender(),
                                from,
                                tokenId,
                                _data
                            )
                        returns (bytes4 retval) {
                            return retval == IERC721Receiver(to).onERC721Received.selector;
                        } catch (bytes memory reason) {
                            if (reason.length == 0) {
                                revert(
                                    "ERC721A: transfer to non ERC721Receiver implementer"
                                );
                            } else {
                                assembly {
                                    revert(add(32, reason), mload(reason))
                                }
                            }
                        }
                    } else {
                        return true;
                    }
                }
            
                /**
                 * @dev Hook that is called before a set of serially-ordered token ids are about to be transferred. This includes minting.
                 *
                 * startTokenId - the first token id to be transferred
                 * quantity - the amount to be transferred
                 *
                 * Calling conditions:
                 *
                 * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
                 * transferred to `to`.
                 * - When `from` is zero, `tokenId` will be minted for `to`.
                 */
                function _beforeTokenTransfers(
                    address from,
                    address to,
                    uint256 startTokenId,
                    uint256 quantity
                ) internal virtual {}
            
                /**
                 * @dev Hook that is called after a set of serially-ordered token ids have been transferred. This includes
                 * minting.
                 *
                 * startTokenId - the first token id to be transferred
                 * quantity - the amount to be transferred
                 *
                 * Calling conditions:
                 *
                 * - when `from` and `to` are both non-zero.
                 * - `from` and `to` are never both zero.
                 */
                function _afterTokenTransfers(
                    address from,
                    address to,
                    uint256 startTokenId,
                    uint256 quantity
                ) internal virtual {}
            }
            
            pragma solidity ^0.8.0;
            
            //Pubic Mint: price, max supply
            //Private Mint: max amount for team
            //Whitelist Mint: merkle tree
            
            contract Kawakami is Ownable, ERC721A, ReentrancyGuard {
                uint256 public immutable maxPerAddressDuringMint;
                uint256 public immutable amountForDevs;
                uint256 public immutable whitelistMaxPerAddress;
            
                //Root for merkel tree whitelisting
                bytes32 private root;
            
                struct SaleConfig {
                    uint32 publicSaleStartTime;
                    uint64 whitelistPrice;
                    uint64 publicPrice;
                }
            
                SaleConfig private saleConfig;
            
                mapping(address => uint256) private whitelistMintCount;
            
                constructor(
                    uint256 maxBatchSize_,
                    uint256 collectionSize_,
                    uint256 amountForDevs_,
                    uint256 whitelistSize_
                ) ERC721A("Kawakami", "Kawakami", maxBatchSize_, collectionSize_) {
                    maxPerAddressDuringMint = maxBatchSize_;
                    amountForDevs = amountForDevs_;
                    whitelistMaxPerAddress = whitelistSize_;
                }
            
                //test public mint
                function publicMint(uint256 quantity) external payable {
                    uint256 publicPrice = uint256(saleConfig.publicPrice);
                    uint256 publicSaleStartTime = uint256(saleConfig.publicSaleStartTime);
                    require(
                        totalSupply() + quantity <= collectionSize,
                        "reached max supply"
                    ); //Can't mint more than collectionSize
                    require(
                        isPublicSaleOn(publicPrice, publicSaleStartTime),
                        "Public sale has not begun yet"
                    );
                    require(
                        numberMinted(msg.sender) + quantity <= maxPerAddressDuringMint,
                        "can not mint this many"
                    );
                    require(msg.value == publicPrice * quantity, "Check Ether amount sent");
            
                    _safeMint(msg.sender, quantity);
                }
            
                //whitelistMint
                function whitelistMint(bytes32[] calldata _proof, uint256 quantity)
                    external
                    payable
                {
                    uint256 price = uint256(saleConfig.whitelistPrice);
                    require(price != 0, "Whitelist sale has not begun yet");
                    require(
                        block.timestamp < saleConfig.publicSaleStartTime,
                        "Public Mint started, Whitelisted Mint Closed"
                    );
                    require(msg.value == (price * quantity), "Incorrect eth amount");
                    bytes32 leaf = keccak256(abi.encodePacked(msg.sender));
                    require(MerkleProof.verify(_proof, root, leaf), "Incorrect proof");
                    require(
                        whitelistMintCount[msg.sender] + quantity <= whitelistMaxPerAddress,
                        "Whitelist Limit Exceeded"
                    );
            
                    whitelistMintCount[msg.sender] =
                        whitelistMintCount[msg.sender] +
                        quantity;
                    _safeMint(msg.sender, quantity);
                    resetMintCountForWhiteList(msg.sender);
                }
            
                function checkValidity(bytes32[] calldata _merkleProof)
                    public
                    view
                    returns (bool)
                {
                    bytes32 leaf = keccak256(abi.encodePacked(msg.sender));
                    require(
                        MerkleProof.verify(_merkleProof, root, leaf),
                        "Incorrect proof"
                    );
                    return true; // Or you can mint tokens here
                }
            
                function setRoot(bytes32 _root) external onlyOwner {
                    root = _root;
                }
            
                function refundIfOver(uint256 price) private {
                    require(msg.value >= price, "Need to send more ETH.");
                    if (msg.value > price) {
                        payable(msg.sender).transfer(msg.value - price);
                    }
                }
            
                function isPublicSaleOn(uint256 publicPriceWei, uint256 publicSaleStartTime)
                    public
                    view
                    returns (bool)
                {
                    return publicPriceWei != 0 && block.timestamp >= publicSaleStartTime;
                }
            
                function getWhiteistMintCount(address _address) public view returns(uint256){
                    return whitelistMintCount[_address];
                } 
            
                function getSaleConfig() public view returns(SaleConfig memory){
                    return saleConfig;
                }
            
                function setPublicMintInfo(
                    uint64 whitelistPriceWei,
                    uint64 publicPriceWei,
                    uint32 publicSaleStartTime
                ) external onlyOwner {
                    saleConfig = SaleConfig(
                        publicSaleStartTime,
                        whitelistPriceWei,
                        publicPriceWei
                    );
                }
            
                // For marketing etc.
                function devMint(uint256 quantity) external onlyOwner {
                    require(
                        totalSupply() + quantity <= amountForDevs,
                        "too many already minted before dev mint"
                    );
                    require(
                        quantity % maxBatchSize == 0,
                        "can only mint a multiple of the maxBatchSize"
                    );
                    uint256 numChunks = quantity / maxBatchSize;
                    for (uint256 i = 0; i < numChunks; i++) {
                        _safeMint(msg.sender, maxBatchSize);
                    }
                }
            
                // // metadata URI
                string private _baseTokenURI;
            
                function _baseURI() internal view virtual override returns (string memory) {
                    return _baseTokenURI;
                }
            
                function setBaseURI(string calldata baseURI) external onlyOwner {
                    _baseTokenURI = baseURI;
                }
            
                function withdrawMoney() external onlyOwner nonReentrant {
                    (bool success, ) = msg.sender.call{value: address(this).balance}("");
                    require(success, "Transfer failed.");
                }
            
                function setOwnersExplicit(uint256 quantity)
                    external
                    onlyOwner
                    nonReentrant
                {
                    _setOwnersExplicit(quantity);
                }
            
                function numberMinted(address owner) public view returns (uint256) {
                    return _numberMinted(owner);
                }
            
                function getOwnershipData(uint256 tokenId)
                    external
                    view
                    returns (TokenOwnership memory)
                {
                    return ownershipOf(tokenId);
                }
            
                function renounceOwnership() public virtual override onlyOwner {
                    require(false, "Can't renounceOwnership");
                }
            }

            File 4 of 6: Seaport
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.17;
            import { Consideration } from "./lib/Consideration.sol";
            /**
             * @title Seaport
             * @custom:version 1.4
             * @author 0age (0age.eth)
             * @custom:coauthor d1ll0n (d1ll0n.eth)
             * @custom:coauthor transmissions11 (t11s.eth)
             * @custom:coauthor James Wenzel (emo.eth)
             * @custom:contributor Kartik (slokh.eth)
             * @custom:contributor LeFevre (lefevre.eth)
             * @custom:contributor Joseph Schiarizzi (CupOJoseph.eth)
             * @custom:contributor Aspyn Palatnick (stuckinaboot.eth)
             * @custom:contributor Stephan Min (stephanm.eth)
             * @custom:contributor Ryan Ghods (ralxz.eth)
             * @custom:contributor Daniel Viau (snotrocket.eth)
             * @custom:contributor hack3r-0m (hack3r-0m.eth)
             * @custom:contributor Diego Estevez (antidiego.eth)
             * @custom:contributor Chomtana (chomtana.eth)
             * @custom:contributor Saw-mon and Natalie (sawmonandnatalie.eth)
             * @custom:contributor 0xBeans (0xBeans.eth)
             * @custom:contributor 0x4non (punkdev.eth)
             * @custom:contributor Laurence E. Day (norsefire.eth)
             * @custom:contributor vectorized.eth (vectorized.eth)
             * @custom:contributor karmacoma (karmacoma.eth)
             * @custom:contributor horsefacts (horsefacts.eth)
             * @custom:contributor UncarvedBlock (uncarvedblock.eth)
             * @custom:contributor Zoraiz Mahmood (zorz.eth)
             * @custom:contributor William Poulin (wpoulin.eth)
             * @custom:contributor Rajiv Patel-O'Connor (rajivpoc.eth)
             * @custom:contributor tserg (tserg.eth)
             * @custom:contributor cygaar (cygaar.eth)
             * @custom:contributor Meta0xNull (meta0xnull.eth)
             * @custom:contributor gpersoon (gpersoon.eth)
             * @custom:contributor Matt Solomon (msolomon.eth)
             * @custom:contributor Weikang Song (weikangs.eth)
             * @custom:contributor zer0dot (zer0dot.eth)
             * @custom:contributor Mudit Gupta (mudit.eth)
             * @custom:contributor leonardoalt (leoalt.eth)
             * @custom:contributor cmichel (cmichel.eth)
             * @custom:contributor PraneshASP (pranesh.eth)
             * @custom:contributor JasperAlexander (jasperalexander.eth)
             * @custom:contributor Ellahi (ellahi.eth)
             * @custom:contributor zaz (1zaz1.eth)
             * @custom:contributor berndartmueller (berndartmueller.eth)
             * @custom:contributor dmfxyz (dmfxyz.eth)
             * @custom:contributor daltoncoder (dontkillrobots.eth)
             * @custom:contributor 0xf4ce (0xf4ce.eth)
             * @custom:contributor phaze (phaze.eth)
             * @custom:contributor hrkrshnn (hrkrshnn.eth)
             * @custom:contributor axic (axic.eth)
             * @custom:contributor leastwood (leastwood.eth)
             * @custom:contributor 0xsanson (sanson.eth)
             * @custom:contributor blockdev (blockd3v.eth)
             * @custom:contributor fiveoutofnine (fiveoutofnine.eth)
             * @custom:contributor shuklaayush (shuklaayush.eth)
             * @custom:contributor dravee (dravee.eth)
             * @custom:contributor 0xPatissier
             * @custom:contributor pcaversaccio
             * @custom:contributor David Eiber
             * @custom:contributor csanuragjain
             * @custom:contributor sach1r0
             * @custom:contributor twojoy0
             * @custom:contributor ori_dabush
             * @custom:contributor Daniel Gelfand
             * @custom:contributor okkothejawa
             * @custom:contributor FlameHorizon
             * @custom:contributor vdrg
             * @custom:contributor dmitriia
             * @custom:contributor bokeh-eth
             * @custom:contributor asutorufos
             * @custom:contributor rfart(rfa)
             * @custom:contributor Riley Holterhus
             * @custom:contributor big-tech-sux
             * @notice Seaport is a generalized native token/ERC20/ERC721/ERC1155
             *         marketplace with lightweight methods for common routes as well as
             *         more flexible methods for composing advanced orders or groups of
             *         orders. Each order contains an arbitrary number of items that may be
             *         spent (the "offer") along with an arbitrary number of items that must
             *         be received back by the indicated recipients (the "consideration").
             */
            contract Seaport is Consideration {
                /**
                 * @notice Derive and set hashes, reference chainId, and associated domain
                 *         separator during deployment.
                 *
                 * @param conduitController A contract that deploys conduits, or proxies
                 *                          that may optionally be used to transfer approved
                 *                          ERC20/721/1155 tokens.
                 */
                constructor(address conduitController) Consideration(conduitController) {}
                /**
                 * @dev Internal pure function to retrieve and return the name of this
                 *      contract.
                 *
                 * @return The name of this contract.
                 */
                function _name() internal pure override returns (string memory) {
                    // Return the name of the contract.
                    assembly {
                        mstore(0x20, 0x20)
                        mstore(0x47, 0x07536561706f7274)
                        return(0x20, 0x60)
                    }
                }
                /**
                 * @dev Internal pure function to retrieve the name of this contract as a
                 *      string that will be used to derive the name hash in the constructor.
                 *
                 * @return The name of this contract as a string.
                 */
                function _nameString() internal pure override returns (string memory) {
                    // Return the name of the contract.
                    return "Seaport";
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.17;
            import {
                ConsiderationInterface
            } from "../interfaces/ConsiderationInterface.sol";
            import {
                AdvancedOrder,
                BasicOrderParameters,
                CriteriaResolver,
                Execution,
                Fulfillment,
                FulfillmentComponent,
                Order,
                OrderComponents
            } from "./ConsiderationStructs.sol";
            import { OrderCombiner } from "./OrderCombiner.sol";
            import {
                CalldataStart,
                CalldataPointer
            } from "../helpers/PointerLibraries.sol";
            import {
                Offset_fulfillAdvancedOrder_criteriaResolvers,
                Offset_fulfillAvailableAdvancedOrders_cnsdrationFlflmnts,
                Offset_fulfillAvailableAdvancedOrders_criteriaResolvers,
                Offset_fulfillAvailableAdvancedOrders_offerFulfillments,
                Offset_fulfillAvailableOrders_considerationFulfillments,
                Offset_fulfillAvailableOrders_offerFulfillments,
                Offset_matchAdvancedOrders_criteriaResolvers,
                Offset_matchAdvancedOrders_fulfillments,
                Offset_matchOrders_fulfillments,
                OrderParameters_counter_offset
            } from "./ConsiderationConstants.sol";
            /**
             * @title Consideration
             * @author 0age (0age.eth)
             * @custom:coauthor d1ll0n (d1ll0n.eth)
             * @custom:coauthor transmissions11 (t11s.eth)
             * @custom:coauthor James Wenzel (emo.eth)
             * @custom:version 1.4
             * @notice Consideration is a generalized native token/ERC20/ERC721/ERC1155
             *         marketplace that provides lightweight methods for common routes as
             *         well as more flexible methods for composing advanced orders or groups
             *         of orders. Each order contains an arbitrary number of items that may
             *         be spent (the "offer") along with an arbitrary number of items that
             *         must be received back by the indicated recipients (the
             *         "consideration").
             */
            contract Consideration is ConsiderationInterface, OrderCombiner {
                /**
                 * @notice Derive and set hashes, reference chainId, and associated domain
                 *         separator during deployment.
                 *
                 * @param conduitController A contract that deploys conduits, or proxies
                 *                          that may optionally be used to transfer approved
                 *                          ERC20/721/1155 tokens.
                 */
                constructor(address conduitController) OrderCombiner(conduitController) {}
                /**
                 * @notice Accept native token transfers during execution that may then be
                 *         used to facilitate native token transfers, where any tokens that
                 *         remain will be transferred to the caller. Native tokens are only
                 *         acceptable mid-fulfillment (and not during basic fulfillment).
                 */
                receive() external payable {
                    // Ensure the reentrancy guard is currently set to accept native tokens.
                    _assertAcceptingNativeTokens();
                }
                /**
                 * @notice Fulfill an order offering an ERC20, ERC721, or ERC1155 item by
                 *         supplying Ether (or other native tokens), ERC20 tokens, an ERC721
                 *         item, or an ERC1155 item as consideration. Six permutations are
                 *         supported: Native token to ERC721, Native token to ERC1155, ERC20
                 *         to ERC721, ERC20 to ERC1155, ERC721 to ERC20, and ERC1155 to
                 *         ERC20 (with native tokens supplied as msg.value). For an order to
                 *         be eligible for fulfillment via this method, it must contain a
                 *         single offer item (though that item may have a greater amount if
                 *         the item is not an ERC721). An arbitrary number of "additional
                 *         recipients" may also be supplied which will each receive native
                 *         tokens or ERC20 items from the fulfiller as consideration. Refer
                 *         to the documentation for a more comprehensive summary of how to
                 *         utilize this method and what orders are compatible with it.
                 *
                 * @param parameters Additional information on the fulfilled order. Note
                 *                   that the offerer and the fulfiller must first approve
                 *                   this contract (or their chosen conduit if indicated)
                 *                   before any tokens can be transferred. Also note that
                 *                   contract recipients of ERC1155 consideration items must
                 *                   implement `onERC1155Received` to receive those items.
                 *
                 * @return fulfilled A boolean indicating whether the order has been
                 *                   successfully fulfilled.
                 */
                function fulfillBasicOrder(
                    BasicOrderParameters calldata parameters
                ) external payable override returns (bool fulfilled) {
                    // Validate and fulfill the basic order.
                    fulfilled = _validateAndFulfillBasicOrder(parameters);
                }
                /**
                 * @notice Fulfill an order offering an ERC20, ERC721, or ERC1155 item by
                 *         supplying Ether (or other native tokens), ERC20 tokens, an ERC721
                 *         item, or an ERC1155 item as consideration. Six permutations are
                 *         supported: Native token to ERC721, Native token to ERC1155, ERC20
                 *         to ERC721, ERC20 to ERC1155, ERC721 to ERC20, and ERC1155 to
                 *         ERC20 (with native tokens supplied as msg.value). For an order to
                 *         be eligible for fulfillment via this method, it must contain a
                 *         single offer item (though that item may have a greater amount if
                 *         the item is not an ERC721). An arbitrary number of "additional
                 *         recipients" may also be supplied which will each receive native
                 *         tokens or ERC20 items from the fulfiller as consideration. Refer
                 *         to the documentation for a more comprehensive summary of how to
                 *         utilize this method and what orders are compatible with it. Note
                 *         that this function costs less gas than `fulfillBasicOrder` due to
                 *         the zero bytes in the function selector (0x00000000) which also
                 *         results in earlier function dispatch.
                 *
                 * @param parameters Additional information on the fulfilled order. Note
                 *                   that the offerer and the fulfiller must first approve
                 *                   this contract (or their chosen conduit if indicated)
                 *                   before any tokens can be transferred. Also note that
                 *                   contract recipients of ERC1155 consideration items must
                 *                   implement `onERC1155Received` to receive those items.
                 *
                 * @return fulfilled A boolean indicating whether the order has been
                 *                   successfully fulfilled.
                 */
                function fulfillBasicOrder_efficient_6GL6yc(
                    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).
                 *
                 * @custom:param order        The order to fulfill. Note that both the
                 *                            offerer and the fulfiller must first approve
                 *                            this contract (or the corresponding conduit if
                 *                            indicated) to transfer any relevant tokens on
                 *                            their behalf and that contracts must implement
                 *                            `onERC1155Received` to receive ERC1155 tokens
                 *                            as consideration.
                 * @param fulfillerConduitKey A bytes32 value indicating what conduit, if
                 *                            any, to source the fulfiller's token approvals
                 *                            from. The zero hash signifies that no conduit
                 *                            should be used (and direct approvals set on
                 *                            this contract).
                 *
                 * @return fulfilled A boolean indicating whether the order has been
                 *                   successfully fulfilled.
                 */
                function fulfillOrder(
                    /**
                     * @custom:name order
                     */
                    Order calldata,
                    bytes32 fulfillerConduitKey
                ) external payable override returns (bool fulfilled) {
                    // Convert order to "advanced" order, then validate and fulfill it.
                    fulfilled = _validateAndFulfillAdvancedOrder(
                        _toAdvancedOrderReturnType(_decodeOrderAsAdvancedOrder)(
                            CalldataStart.pptr()
                        ),
                        new CriteriaResolver[](0), // No criteria resolvers supplied.
                        fulfillerConduitKey,
                        msg.sender
                    );
                }
                /**
                 * @notice Fill an order, fully or partially, with an arbitrary number of
                 *         items for offer and consideration alongside criteria resolvers
                 *         containing specific token identifiers and associated proofs.
                 *
                 * @custom:param advancedOrder     The order to fulfill along with the
                 *                                 fraction of the order to attempt to fill.
                 *                                 Note that both the offerer and the
                 *                                 fulfiller must first approve this
                 *                                 contract (or their conduit if indicated
                 *                                 by the order) to transfer any relevant
                 *                                 tokens on their behalf and that contracts
                 *                                 must implement `onERC1155Received` to
                 *                                 receive ERC1155 tokens as consideration.
                 *                                 Also note that all offer and
                 *                                 consideration components must have no
                 *                                 remainder after multiplication of the
                 *                                 respective amount with the supplied
                 *                                 fraction for the partial fill to be
                 *                                 considered valid.
                 * @custom:param criteriaResolvers An array where each element contains a
                 *                                 reference to a specific offer or
                 *                                 consideration, a token identifier, and a
                 *                                 proof that the supplied token identifier
                 *                                 is contained in the merkle root held by
                 *                                 the item in question's criteria element.
                 *                                 Note that an empty criteria indicates
                 *                                 that any (transferable) token identifier
                 *                                 on the token in question is valid and
                 *                                 that no associated proof needs to be
                 *                                 supplied.
                 * @param fulfillerConduitKey      A bytes32 value indicating what conduit,
                 *                                 if any, to source the fulfiller's token
                 *                                 approvals from. The zero hash signifies
                 *                                 that no conduit should be used (and
                 *                                 direct approvals set on this contract).
                 * @param recipient                The intended recipient for all received
                 *                                 items, with `address(0)` indicating that
                 *                                 the caller should receive the items.
                 *
                 * @return fulfilled A boolean indicating whether the order has been
                 *                   successfully fulfilled.
                 */
                function fulfillAdvancedOrder(
                    /**
                     * @custom:name advancedOrder
                     */
                    AdvancedOrder calldata,
                    /**
                     * @custom:name criteriaResolvers
                     */
                    CriteriaResolver[] calldata,
                    bytes32 fulfillerConduitKey,
                    address recipient
                ) external payable override returns (bool fulfilled) {
                    // Validate and fulfill the order.
                    fulfilled = _validateAndFulfillAdvancedOrder(
                        _toAdvancedOrderReturnType(_decodeAdvancedOrder)(
                            CalldataStart.pptr()
                        ),
                        _toCriteriaResolversReturnType(_decodeCriteriaResolvers)(
                            CalldataStart.pptr(
                                Offset_fulfillAdvancedOrder_criteriaResolvers
                            )
                        ),
                        fulfillerConduitKey,
                        _substituteCallerForEmptyRecipient(recipient)
                    );
                }
                /**
                 * @notice Attempt to fill a group of orders, each with an arbitrary number
                 *         of items for offer and consideration. Any order that is not
                 *         currently active, has already been fully filled, or has been
                 *         cancelled will be omitted. Remaining offer and consideration
                 *         items will then be aggregated where possible as indicated by the
                 *         supplied offer and consideration component arrays and aggregated
                 *         items will be transferred to the fulfiller or to each intended
                 *         recipient, respectively. Note that a failing item transfer or an
                 *         issue with order formatting will cause the entire batch to fail.
                 *         Note that this function does not support criteria-based orders or
                 *         partial filling of orders (though filling the remainder of a
                 *         partially-filled order is supported).
                 *
                 * @custom:param orders                    The orders to fulfill. Note that
                 *                                         both the offerer and the
                 *                                         fulfiller must first approve this
                 *                                         contract (or the corresponding
                 *                                         conduit if indicated) to transfer
                 *                                         any relevant tokens on their
                 *                                         behalf and that contracts must
                 *                                         implement `onERC1155Received` to
                 *                                         receive ERC1155 tokens as
                 *                                         consideration.
                 * @custom:param offerFulfillments         An array of FulfillmentComponent
                 *                                         arrays indicating which offer
                 *                                         items to attempt to aggregate
                 *                                         when preparing executions. Note
                 *                                         that any offer items not included
                 *                                         as part of a fulfillment will be
                 *                                         sent unaggregated to the caller.
                 * @custom:param considerationFulfillments An array of FulfillmentComponent
                 *                                         arrays indicating which
                 *                                         consideration items to attempt to
                 *                                         aggregate when preparing
                 *                                         executions.
                 * @param fulfillerConduitKey              A bytes32 value indicating what
                 *                                         conduit, if any, to source the
                 *                                         fulfiller's token approvals from.
                 *                                         The zero hash signifies that no
                 *                                         conduit should be used (and
                 *                                         direct approvals set on this
                 *                                         contract).
                 * @param maximumFulfilled                 The maximum number of orders to
                 *                                         fulfill.
                 *
                 * @return availableOrders An array of booleans indicating if each order
                 *                         with an index corresponding to the index of the
                 *                         returned boolean was fulfillable or not.
                 * @return executions      An array of elements indicating the sequence of
                 *                         transfers performed as part of matching the given
                 *                         orders.
                 */
                function fulfillAvailableOrders(
                    /**
                     * @custom:name orders
                     */
                    Order[] calldata,
                    /**
                     * @custom:name offerFulfillments
                     */
                    FulfillmentComponent[][] calldata,
                    /**
                     * @custom:name considerationFulfillments
                     */
                    FulfillmentComponent[][] calldata,
                    bytes32 fulfillerConduitKey,
                    uint256 maximumFulfilled
                )
                    external
                    payable
                    override
                    returns (
                        bool[] memory /* availableOrders */,
                        Execution[] memory /* executions */
                    )
                {
                    // Convert orders to "advanced" orders and fulfill all available orders.
                    return
                        _fulfillAvailableAdvancedOrders(
                            _toAdvancedOrdersReturnType(_decodeOrdersAsAdvancedOrders)(
                                CalldataStart.pptr()
                            ), // Convert to advanced orders.
                            new CriteriaResolver[](0), // No criteria resolvers supplied.
                            _toNestedFulfillmentComponentsReturnType(
                                _decodeNestedFulfillmentComponents
                            )(
                                CalldataStart.pptr(
                                    Offset_fulfillAvailableOrders_offerFulfillments
                                )
                            ),
                            _toNestedFulfillmentComponentsReturnType(
                                _decodeNestedFulfillmentComponents
                            )(
                                CalldataStart.pptr(
                                    Offset_fulfillAvailableOrders_considerationFulfillments
                                )
                            ),
                            fulfillerConduitKey,
                            msg.sender,
                            maximumFulfilled
                        );
                }
                /**
                 * @notice Attempt to fill a group of orders, fully or partially, with an
                 *         arbitrary number of items for offer and consideration per order
                 *         alongside criteria resolvers containing specific token
                 *         identifiers and associated proofs. Any order that is not
                 *         currently active, has already been fully filled, or has been
                 *         cancelled will be omitted. Remaining offer and consideration
                 *         items will then be aggregated where possible as indicated by the
                 *         supplied offer and consideration component arrays and aggregated
                 *         items will be transferred to the fulfiller or to each intended
                 *         recipient, respectively. Note that a failing item transfer or an
                 *         issue with order formatting will cause the entire batch to fail.
                 *
                 * @custom:param advancedOrders            The orders to fulfill along with
                 *                                         the fraction of those orders to
                 *                                         attempt to fill. Note that both
                 *                                         the offerer and the fulfiller
                 *                                         must first approve this contract
                 *                                         (or their conduit if indicated by
                 *                                         the order) to transfer any
                 *                                         relevant tokens on their behalf
                 *                                         and that contracts must implement
                 *                                         `onERC1155Received` to receive
                 *                                         ERC1155 tokens as consideration.
                 *                                         Also note that all offer and
                 *                                         consideration components must
                 *                                         have no remainder after
                 *                                         multiplication of the respective
                 *                                         amount with the supplied fraction
                 *                                         for an order's partial fill
                 *                                         amount to be considered valid.
                 * @custom:param criteriaResolvers         An array where each element
                 *                                         contains a reference to a
                 *                                         specific offer or consideration,
                 *                                         a token identifier, and a proof
                 *                                         that the supplied token
                 *                                         identifier is contained in the
                 *                                         merkle root held by the item in
                 *                                         question's criteria element. Note
                 *                                         that an empty criteria indicates
                 *                                         that any (transferable) token
                 *                                         identifier on the token in
                 *                                         question is valid and that no
                 *                                         associated proof needs to be
                 *                                         supplied.
                 * @custom:param offerFulfillments         An array of FulfillmentComponent
                 *                                         arrays indicating which offer
                 *                                         items to attempt to aggregate
                 *                                         when preparing executions. Note
                 *                                         that any offer items not included
                 *                                         as part of a fulfillment will be
                 *                                         sent unaggregated to the caller.
                 * @custom:param considerationFulfillments An array of FulfillmentComponent
                 *                                         arrays indicating which
                 *                                         consideration items to attempt to
                 *                                         aggregate when preparing
                 *                                         executions.
                 * @param fulfillerConduitKey              A bytes32 value indicating what
                 *                                         conduit, if any, to source the
                 *                                         fulfiller's token approvals from.
                 *                                         The zero hash signifies that no
                 *                                         conduit should be used (and
                 *                                         direct approvals set on this
                 *                                         contract).
                 * @param recipient                        The intended recipient for all
                 *                                         received items, with `address(0)`
                 *                                         indicating that the caller should
                 *                                         receive the offer items.
                 * @param maximumFulfilled                 The maximum number of orders to
                 *                                         fulfill.
                 *
                 * @return availableOrders An array of booleans indicating if each order
                 *                         with an index corresponding to the index of the
                 *                         returned boolean was fulfillable or not.
                 * @return executions      An array of elements indicating the sequence of
                 *                         transfers performed as part of matching the given
                 *                         orders.
                 */
                function fulfillAvailableAdvancedOrders(
                    /**
                     * @custom:name advancedOrders
                     */
                    AdvancedOrder[] calldata,
                    /**
                     * @custom:name criteriaResolvers
                     */
                    CriteriaResolver[] calldata,
                    /**
                     * @custom:name offerFulfillments
                     */
                    FulfillmentComponent[][] calldata,
                    /**
                     * @custom:name considerationFulfillments
                     */
                    FulfillmentComponent[][] calldata,
                    bytes32 fulfillerConduitKey,
                    address recipient,
                    uint256 maximumFulfilled
                )
                    external
                    payable
                    override
                    returns (
                        bool[] memory /* availableOrders */,
                        Execution[] memory /* executions */
                    )
                {
                    // Fulfill all available orders.
                    return
                        _fulfillAvailableAdvancedOrders(
                            _toAdvancedOrdersReturnType(_decodeAdvancedOrders)(
                                CalldataStart.pptr()
                            ),
                            _toCriteriaResolversReturnType(_decodeCriteriaResolvers)(
                                CalldataStart.pptr(
                                    Offset_fulfillAvailableAdvancedOrders_criteriaResolvers
                                )
                            ),
                            _toNestedFulfillmentComponentsReturnType(
                                _decodeNestedFulfillmentComponents
                            )(
                                CalldataStart.pptr(
                                    Offset_fulfillAvailableAdvancedOrders_offerFulfillments
                                )
                            ),
                            _toNestedFulfillmentComponentsReturnType(
                                _decodeNestedFulfillmentComponents
                            )(
                                CalldataStart.pptr(
                                    Offset_fulfillAvailableAdvancedOrders_cnsdrationFlflmnts
                                )
                            ),
                            fulfillerConduitKey,
                            _substituteCallerForEmptyRecipient(recipient),
                            maximumFulfilled
                        );
                }
                /**
                 * @notice Match an arbitrary number of orders, each with an arbitrary
                 *         number of items for offer and consideration along with a set of
                 *         fulfillments allocating offer components to consideration
                 *         components. Note that this function does not support
                 *         criteria-based or partial filling of orders (though filling the
                 *         remainder of a partially-filled order is supported). Any unspent
                 *         offer item amounts or native tokens will be transferred to the
                 *         caller.
                 *
                 * @custom:param orders       The orders to match. Note that both the
                 *                            offerer and fulfiller on each order must first
                 *                            approve this contract (or their conduit if
                 *                            indicated by the order) to transfer any
                 *                            relevant tokens on their behalf and each
                 *                            consideration recipient must implement
                 *                            `onERC1155Received` to receive ERC1155 tokens.
                 * @custom:param fulfillments An array of elements allocating offer
                 *                            components to consideration components. Note
                 *                            that each consideration component must be
                 *                            fully met for the match operation to be valid,
                 *                            and that any unspent offer items will be sent
                 *                            unaggregated to the caller.
                 *
                 * @return executions An array of elements indicating the sequence of
                 *                    transfers performed as part of matching the given
                 *                    orders. Note that unspent offer item amounts or native
                 *                    tokens will not be reflected as part of this array.
                 */
                function matchOrders(
                    /**
                     * @custom:name orders
                     */
                    Order[] calldata,
                    /**
                     * @custom:name fulfillments
                     */
                    Fulfillment[] calldata
                ) external payable override returns (Execution[] memory /* executions */) {
                    // Convert to advanced, validate, and match orders using fulfillments.
                    return
                        _matchAdvancedOrders(
                            _toAdvancedOrdersReturnType(_decodeOrdersAsAdvancedOrders)(
                                CalldataStart.pptr()
                            ),
                            new CriteriaResolver[](0), // No criteria resolvers supplied.
                            _toFulfillmentsReturnType(_decodeFulfillments)(
                                CalldataStart.pptr(Offset_matchOrders_fulfillments)
                            ),
                            msg.sender
                        );
                }
                /**
                 * @notice Match an arbitrary number of full, partial, or contract orders,
                 *         each with an arbitrary number of items for offer and
                 *         consideration, supplying criteria resolvers containing specific
                 *         token identifiers and associated proofs as well as fulfillments
                 *         allocating offer components to consideration components. Any
                 *         unspent offer item amounts will be transferred to the designated
                 *         recipient (with the null address signifying to use the caller)
                 *         and any unspent native tokens will be returned to the caller.
                 *
                 * @custom:param advancedOrders    The advanced orders to match. Note that
                 *                                 both the offerer and fulfiller on each
                 *                                 order must first approve this contract
                 *                                 (or their conduit if indicated by the
                 *                                 order) to transfer any relevant tokens on
                 *                                 their behalf and each consideration
                 *                                 recipient must implement
                 *                                 `onERC1155Received` to receive ERC1155
                 *                                 tokens. Also note that the offer and
                 *                                 consideration components for each order
                 *                                 must have no remainder after multiplying
                 *                                 the respective amount with the supplied
                 *                                 fraction for the group of partial fills
                 *                                 to be considered valid.
                 * @custom:param criteriaResolvers An array where each element contains a
                 *                                 reference to a specific offer or
                 *                                 consideration, a token identifier, and a
                 *                                 proof that the supplied token identifier
                 *                                 is contained in the merkle root held by
                 *                                 the item in question's criteria element.
                 *                                 Note that an empty criteria indicates
                 *                                 that any (transferable) token identifier
                 *                                 on the token in question is valid and
                 *                                 that no associated proof needs to be
                 *                                 supplied.
                 * @custom:param fulfillments      An array of elements allocating offer
                 *                                 components to consideration components.
                 *                                 Note that each consideration component
                 *                                 must be fully met for the match operation
                 *                                 to be valid, and that any unspent offer
                 *                                 items will be sent unaggregated to the
                 *                                 designated recipient.
                 * @param recipient                The intended recipient for all unspent
                 *                                 offer item amounts, or the caller if the
                 *                                 null address is supplied.
                 *
                 * @return executions An array of elements indicating the sequence of
                 *                     transfers performed as part of matching the given
                 *                     orders. Note that unspent offer item amounts or
                 *                     native tokens will not be reflected as part of this
                 *                     array.
                 */
                function matchAdvancedOrders(
                    /**
                     * @custom:name advancedOrders
                     */
                    AdvancedOrder[] calldata,
                    /**
                     * @custom:name criteriaResolvers
                     */
                    CriteriaResolver[] calldata,
                    /**
                     * @custom:name fulfillments
                     */
                    Fulfillment[] calldata,
                    address recipient
                ) external payable override returns (Execution[] memory /* executions */) {
                    // Validate and match the advanced orders using supplied fulfillments.
                    return
                        _matchAdvancedOrders(
                            _toAdvancedOrdersReturnType(_decodeAdvancedOrders)(
                                CalldataStart.pptr()
                            ),
                            _toCriteriaResolversReturnType(_decodeCriteriaResolvers)(
                                CalldataStart.pptr(
                                    Offset_matchAdvancedOrders_criteriaResolvers
                                )
                            ),
                            _toFulfillmentsReturnType(_decodeFulfillments)(
                                CalldataStart.pptr(Offset_matchAdvancedOrders_fulfillments)
                            ),
                            _substituteCallerForEmptyRecipient(recipient)
                        );
                }
                /**
                 * @notice Cancel an arbitrary number of orders. Note that only the offerer
                 *         or the zone of a given order may cancel it. Callers should ensure
                 *         that the intended order was cancelled by calling `getOrderStatus`
                 *         and confirming that `isCancelled` returns `true`.
                 *
                 * @param orders The orders to cancel.
                 *
                 * @return cancelled A boolean indicating whether the supplied orders have
                 *                   been successfully cancelled.
                 */
                function cancel(
                    OrderComponents[] calldata orders
                ) external override returns (bool cancelled) {
                    // Cancel the orders.
                    cancelled = _cancel(orders);
                }
                /**
                 * @notice Validate an arbitrary number of orders, thereby registering their
                 *         signatures as valid and allowing the fulfiller to skip signature
                 *         verification on fulfillment. Note that validated orders may still
                 *         be unfulfillable due to invalid item amounts or other factors;
                 *         callers should determine whether validated orders are fulfillable
                 *         by simulating the fulfillment call prior to execution. Also note
                 *         that anyone can validate a signed order, but only the offerer can
                 *         validate an order without supplying a signature.
                 *
                 * @custom:param orders The orders to validate.
                 *
                 * @return validated A boolean indicating whether the supplied orders have
                 *                   been successfully validated.
                 */
                function validate(
                    /**
                     * @custom:name orders
                     */
                    Order[] calldata
                ) external override returns (bool /* validated */) {
                    return
                        _validate(_toOrdersReturnType(_decodeOrders)(CalldataStart.pptr()));
                }
                /**
                 * @notice Cancel all orders from a given offerer with a given zone in bulk
                 *         by incrementing a counter. Note that only the offerer may
                 *         increment the counter.
                 *
                 * @return newCounter The new counter.
                 */
                function incrementCounter() external override returns (uint256 newCounter) {
                    // Increment current counter for the supplied offerer.  Note that the
                    // counter is incremented by a large, quasi-random interval.
                    newCounter = _incrementCounter();
                }
                /**
                 * @notice Retrieve the order hash for a given order.
                 *
                 * @custom:param order The components of the order.
                 *
                 * @return orderHash The order hash.
                 */
                function getOrderHash(
                    /**
                     * @custom:name order
                     */
                    OrderComponents calldata
                ) external view override returns (bytes32 orderHash) {
                    CalldataPointer orderPointer = CalldataStart.pptr();
                    // Derive order hash by supplying order parameters along with counter.
                    orderHash = _deriveOrderHash(
                        _toOrderParametersReturnType(
                            _decodeOrderComponentsAsOrderParameters
                        )(orderPointer),
                        // Read order counter
                        orderPointer.offset(OrderParameters_counter_offset).readUint256()
                    );
                }
                /**
                 * @notice Retrieve the status of a given order by hash, including whether
                 *         the order has been cancelled or validated and the fraction of the
                 *         order that has been filled. Since the _orderStatus[orderHash]
                 *         does not get set for contract orders, getOrderStatus will always
                 *         return (false, false, 0, 0) for those hashes. Note that this
                 *         function is susceptible to view reentrancy and so should be used
                 *         with care when calling from other contracts.
                 *
                 * @param orderHash The order hash in question.
                 *
                 * @return isValidated A boolean indicating whether the order in question
                 *                     has been validated (i.e. previously approved or
                 *                     partially filled).
                 * @return isCancelled A boolean indicating whether the order in question
                 *                     has been cancelled.
                 * @return totalFilled The total portion of the order that has been filled
                 *                     (i.e. the "numerator").
                 * @return totalSize   The total size of the order that is either filled or
                 *                     unfilled (i.e. the "denominator").
                 */
                function getOrderStatus(
                    bytes32 orderHash
                )
                    external
                    view
                    override
                    returns (
                        bool isValidated,
                        bool isCancelled,
                        uint256 totalFilled,
                        uint256 totalSize
                    )
                {
                    // Retrieve the order status using the order hash.
                    return _getOrderStatus(orderHash);
                }
                /**
                 * @notice Retrieve the current counter for a given offerer.
                 *
                 * @param offerer The offerer in question.
                 *
                 * @return counter The current counter.
                 */
                function getCounter(
                    address offerer
                ) external view override returns (uint256 counter) {
                    // Return the counter for the supplied offerer.
                    counter = _getCounter(offerer);
                }
                /**
                 * @notice Retrieve configuration information for this contract.
                 *
                 * @return version           The contract version.
                 * @return domainSeparator   The domain separator for this contract.
                 * @return conduitController The conduit Controller set for this contract.
                 */
                function information()
                    external
                    view
                    override
                    returns (
                        string memory version,
                        bytes32 domainSeparator,
                        address conduitController
                    )
                {
                    // Return the information for this contract.
                    return _information();
                }
                /**
                 * @dev Gets the contract offerer nonce for the specified contract offerer.
                 *      Note that this function is susceptible to view reentrancy and so
                 *      should be used with care when calling from other contracts.
                 *
                 * @param contractOfferer The contract offerer for which to get the nonce.
                 *
                 * @return nonce The contract offerer nonce.
                 */
                function getContractOffererNonce(
                    address contractOfferer
                ) external view override returns (uint256 nonce) {
                    nonce = _contractNonces[contractOfferer];
                }
                /**
                 * @notice Retrieve the name of this contract.
                 *
                 * @return contractName The name of this contract.
                 */
                function name()
                    external
                    pure
                    override
                    returns (string memory /* contractName */)
                {
                    // Return the name of the contract.
                    return _name();
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import {
                AdvancedOrder,
                BasicOrderParameters,
                CriteriaResolver,
                Execution,
                Fulfillment,
                FulfillmentComponent,
                Order,
                OrderComponents
            } from "../lib/ConsiderationStructs.sol";
            /**
             * @title ConsiderationInterface
             * @author 0age
             * @custom:version 1.4
             * @notice Consideration is a generalized native token/ERC20/ERC721/ERC1155
             *         marketplace. It minimizes external calls to the greatest extent
             *         possible and provides lightweight methods for common routes as well
             *         as more flexible methods for composing advanced orders.
             *
             * @dev ConsiderationInterface contains all external function interfaces for
             *      Consideration.
             */
            interface ConsiderationInterface {
                /**
                 * @notice Fulfill an order offering an ERC721 token by supplying Ether (or
                 *         the native token for the given chain) as consideration for the
                 *         order. An arbitrary number of "additional recipients" may also be
                 *         supplied which will each receive native tokens from the fulfiller
                 *         as consideration.
                 *
                 * @param parameters Additional information on the fulfilled order. Note
                 *                   that the offerer must first approve this contract (or
                 *                   their preferred conduit if indicated by the order) for
                 *                   their offered ERC721 token to be transferred.
                 *
                 * @return fulfilled A boolean indicating whether the order has been
                 *                   successfully fulfilled.
                 */
                function fulfillBasicOrder(
                    BasicOrderParameters calldata parameters
                ) external payable returns (bool fulfilled);
                /**
                 * @notice Fulfill an order with an arbitrary number of items for offer and
                 *         consideration. Note that this function does not support
                 *         criteria-based orders or partial filling of orders (though
                 *         filling the remainder of a partially-filled order is supported).
                 *
                 * @param order               The order to fulfill. Note that both the
                 *                            offerer and the fulfiller must first approve
                 *                            this contract (or the corresponding conduit if
                 *                            indicated) to transfer any relevant tokens on
                 *                            their behalf and that contracts must implement
                 *                            `onERC1155Received` to receive ERC1155 tokens
                 *                            as consideration.
                 * @param fulfillerConduitKey A bytes32 value indicating what conduit, if
                 *                            any, to source the fulfiller's token approvals
                 *                            from. The zero hash signifies that no conduit
                 *                            should be used, with direct approvals set on
                 *                            Consideration.
                 *
                 * @return fulfilled A boolean indicating whether the order has been
                 *                   successfully fulfilled.
                 */
                function fulfillOrder(
                    Order calldata order,
                    bytes32 fulfillerConduitKey
                ) external payable returns (bool fulfilled);
                /**
                 * @notice Fill an order, fully or partially, with an arbitrary number of
                 *         items for offer and consideration alongside criteria resolvers
                 *         containing specific token identifiers and associated proofs.
                 *
                 * @param advancedOrder       The order to fulfill along with the fraction
                 *                            of the order to attempt to fill. Note that
                 *                            both the offerer and the fulfiller must first
                 *                            approve this contract (or their preferred
                 *                            conduit if indicated by the order) to transfer
                 *                            any relevant tokens on their behalf and that
                 *                            contracts must implement `onERC1155Received`
                 *                            to receive ERC1155 tokens as consideration.
                 *                            Also note that all offer and consideration
                 *                            components must have no remainder after
                 *                            multiplication of the respective amount with
                 *                            the supplied fraction for the partial fill to
                 *                            be considered valid.
                 * @param criteriaResolvers   An array where each element contains a
                 *                            reference to a specific offer or
                 *                            consideration, a token identifier, and a proof
                 *                            that the supplied token identifier is
                 *                            contained in the merkle root held by the item
                 *                            in question's criteria element. Note that an
                 *                            empty criteria indicates that any
                 *                            (transferable) token identifier on the token
                 *                            in question is valid and that no associated
                 *                            proof needs to be supplied.
                 * @param fulfillerConduitKey A bytes32 value indicating what conduit, if
                 *                            any, to source the fulfiller's token approvals
                 *                            from. The zero hash signifies that no conduit
                 *                            should be used, with direct approvals set on
                 *                            Consideration.
                 * @param recipient           The intended recipient for all received items,
                 *                            with `address(0)` indicating that the caller
                 *                            should receive the items.
                 *
                 * @return fulfilled A boolean indicating whether the order has been
                 *                   successfully fulfilled.
                 */
                function fulfillAdvancedOrder(
                    AdvancedOrder calldata advancedOrder,
                    CriteriaResolver[] calldata criteriaResolvers,
                    bytes32 fulfillerConduitKey,
                    address recipient
                ) external payable returns (bool fulfilled);
                /**
                 * @notice Attempt to fill a group of orders, each with an arbitrary number
                 *         of items for offer and consideration. Any order that is not
                 *         currently active, has already been fully filled, or has been
                 *         cancelled will be omitted. Remaining offer and consideration
                 *         items will then be aggregated where possible as indicated by the
                 *         supplied offer and consideration component arrays and aggregated
                 *         items will be transferred to the fulfiller or to each intended
                 *         recipient, respectively. Note that a failing item transfer or an
                 *         issue with order formatting will cause the entire batch to fail.
                 *         Note that this function does not support criteria-based orders or
                 *         partial filling of orders (though filling the remainder of a
                 *         partially-filled order is supported).
                 *
                 * @param orders                    The orders to fulfill. Note that both
                 *                                  the offerer and the fulfiller must first
                 *                                  approve this contract (or the
                 *                                  corresponding conduit if indicated) to
                 *                                  transfer any relevant tokens on their
                 *                                  behalf and that contracts must implement
                 *                                  `onERC1155Received` to receive ERC1155
                 *                                  tokens as consideration.
                 * @param offerFulfillments         An array of FulfillmentComponent arrays
                 *                                  indicating which offer items to attempt
                 *                                  to aggregate when preparing executions.
                 * @param considerationFulfillments An array of FulfillmentComponent arrays
                 *                                  indicating which consideration items to
                 *                                  attempt to aggregate when preparing
                 *                                  executions.
                 * @param fulfillerConduitKey       A bytes32 value indicating what conduit,
                 *                                  if any, to source the fulfiller's token
                 *                                  approvals from. The zero hash signifies
                 *                                  that no conduit should be used, with
                 *                                  direct approvals set on this contract.
                 * @param maximumFulfilled          The maximum number of orders to fulfill.
                 *
                 * @return availableOrders An array of booleans indicating if each order
                 *                         with an index corresponding to the index of the
                 *                         returned boolean was fulfillable or not.
                 * @return executions      An array of elements indicating the sequence of
                 *                         transfers performed as part of matching the given
                 *                         orders. Note that unspent offer item amounts or
                 *                         native tokens will not be reflected as part of
                 *                         this array.
                 */
                function fulfillAvailableOrders(
                    Order[] calldata orders,
                    FulfillmentComponent[][] calldata offerFulfillments,
                    FulfillmentComponent[][] calldata considerationFulfillments,
                    bytes32 fulfillerConduitKey,
                    uint256 maximumFulfilled
                )
                    external
                    payable
                    returns (bool[] memory availableOrders, Execution[] memory executions);
                /**
                 * @notice Attempt to fill a group of orders, fully or partially, with an
                 *         arbitrary number of items for offer and consideration per order
                 *         alongside criteria resolvers containing specific token
                 *         identifiers and associated proofs. Any order that is not
                 *         currently active, has already been fully filled, or has been
                 *         cancelled will be omitted. Remaining offer and consideration
                 *         items will then be aggregated where possible as indicated by the
                 *         supplied offer and consideration component arrays and aggregated
                 *         items will be transferred to the fulfiller or to each intended
                 *         recipient, respectively. Note that a failing item transfer or an
                 *         issue with order formatting will cause the entire batch to fail.
                 *
                 * @param advancedOrders            The orders to fulfill along with the
                 *                                  fraction of those orders to attempt to
                 *                                  fill. Note that both the offerer and the
                 *                                  fulfiller must first approve this
                 *                                  contract (or their preferred conduit if
                 *                                  indicated by the order) to transfer any
                 *                                  relevant tokens on their behalf and that
                 *                                  contracts must implement
                 *                                  `onERC1155Received` to enable receipt of
                 *                                  ERC1155 tokens as consideration. Also
                 *                                  note that all offer and consideration
                 *                                  components must have no remainder after
                 *                                  multiplication of the respective amount
                 *                                  with the supplied fraction for an
                 *                                  order's partial fill amount to be
                 *                                  considered valid.
                 * @param criteriaResolvers         An array where each element contains a
                 *                                  reference to a specific offer or
                 *                                  consideration, a token identifier, and a
                 *                                  proof that the supplied token identifier
                 *                                  is contained in the merkle root held by
                 *                                  the item in question's criteria element.
                 *                                  Note that an empty criteria indicates
                 *                                  that any (transferable) token
                 *                                  identifier on the token in question is
                 *                                  valid and that no associated proof needs
                 *                                  to be supplied.
                 * @param offerFulfillments         An array of FulfillmentComponent arrays
                 *                                  indicating which offer items to attempt
                 *                                  to aggregate when preparing executions.
                 * @param considerationFulfillments An array of FulfillmentComponent arrays
                 *                                  indicating which consideration items to
                 *                                  attempt to aggregate when preparing
                 *                                  executions.
                 * @param fulfillerConduitKey       A bytes32 value indicating what conduit,
                 *                                  if any, to source the fulfiller's token
                 *                                  approvals from. The zero hash signifies
                 *                                  that no conduit should be used, with
                 *                                  direct approvals set on this contract.
                 * @param recipient                 The intended recipient for all received
                 *                                  items, with `address(0)` indicating that
                 *                                  the caller should receive the items.
                 * @param maximumFulfilled          The maximum number of orders to fulfill.
                 *
                 * @return availableOrders An array of booleans indicating if each order
                 *                         with an index corresponding to the index of the
                 *                         returned boolean was fulfillable or not.
                 * @return executions      An array of elements indicating the sequence of
                 *                         transfers performed as part of matching the given
                 *                         orders. Note that unspent offer item amounts or
                 *                         native tokens will not be reflected as part of
                 *                         this array.
                 */
                function fulfillAvailableAdvancedOrders(
                    AdvancedOrder[] calldata advancedOrders,
                    CriteriaResolver[] calldata criteriaResolvers,
                    FulfillmentComponent[][] calldata offerFulfillments,
                    FulfillmentComponent[][] calldata considerationFulfillments,
                    bytes32 fulfillerConduitKey,
                    address recipient,
                    uint256 maximumFulfilled
                )
                    external
                    payable
                    returns (bool[] memory availableOrders, Execution[] memory executions);
                /**
                 * @notice Match an arbitrary number of orders, each with an arbitrary
                 *         number of items for offer and consideration along with a set of
                 *         fulfillments allocating offer components to consideration
                 *         components. Note that this function does not support
                 *         criteria-based or partial filling of orders (though filling the
                 *         remainder of a partially-filled order is supported). Any unspent
                 *         offer item amounts or native tokens will be transferred to the
                 *         caller.
                 *
                 * @param orders       The orders to match. Note that both the offerer and
                 *                     fulfiller on each order must first approve this
                 *                     contract (or their conduit if indicated by the order)
                 *                     to transfer any relevant tokens on their behalf and
                 *                     each consideration recipient must implement
                 *                     `onERC1155Received` to enable ERC1155 token receipt.
                 * @param fulfillments An array of elements allocating offer components to
                 *                     consideration components. Note that each
                 *                     consideration component must be fully met for the
                 *                     match operation to be valid.
                 *
                 * @return executions An array of elements indicating the sequence of
                 *                    transfers performed as part of matching the given
                 *                    orders. Note that unspent offer item amounts or
                 *                    native tokens will not be reflected as part of this
                 *                    array.
                 */
                function matchOrders(
                    Order[] calldata orders,
                    Fulfillment[] calldata fulfillments
                ) external payable returns (Execution[] memory executions);
                /**
                 * @notice Match an arbitrary number of full or partial orders, each with an
                 *         arbitrary number of items for offer and consideration, supplying
                 *         criteria resolvers containing specific token identifiers and
                 *         associated proofs as well as fulfillments allocating offer
                 *         components to consideration components. Any unspent offer item
                 *         amounts will be transferred to the designated recipient (with the
                 *         null address signifying to use the caller) and any unspent native
                 *         tokens will be returned to the caller.
                 *
                 * @param orders            The advanced orders to match. Note that both the
                 *                          offerer and fulfiller on each order must first
                 *                          approve this contract (or a preferred conduit if
                 *                          indicated by the order) to transfer any relevant
                 *                          tokens on their behalf and each consideration
                 *                          recipient must implement `onERC1155Received` in
                 *                          order to receive ERC1155 tokens. Also note that
                 *                          the offer and consideration components for each
                 *                          order must have no remainder after multiplying
                 *                          the respective amount with the supplied fraction
                 *                          in order for the group of partial fills to be
                 *                          considered valid.
                 * @param criteriaResolvers An array where each element contains a reference
                 *                          to a specific order as well as that order's
                 *                          offer or consideration, a token identifier, and
                 *                          a proof that the supplied token identifier is
                 *                          contained in the order's merkle root. Note that
                 *                          an empty root indicates that any (transferable)
                 *                          token identifier is valid and that no associated
                 *                          proof needs to be supplied.
                 * @param fulfillments      An array of elements allocating offer components
                 *                          to consideration components. Note that each
                 *                          consideration component must be fully met in
                 *                          order for the match operation to be valid.
                 * @param recipient         The intended recipient for all unspent offer
                 *                          item amounts, or the caller if the null address
                 *                          is supplied.
                 *
                 * @return executions An array of elements indicating the sequence of
                 *                    transfers performed as part of matching the given
                 *                    orders. Note that unspent offer item amounts or native
                 *                    tokens will not be reflected as part of this array.
                 */
                function matchAdvancedOrders(
                    AdvancedOrder[] calldata orders,
                    CriteriaResolver[] calldata criteriaResolvers,
                    Fulfillment[] calldata fulfillments,
                    address recipient
                ) external payable returns (Execution[] memory executions);
                /**
                 * @notice Cancel an arbitrary number of orders. Note that only the offerer
                 *         or the zone of a given order may cancel it. Callers should ensure
                 *         that the intended order was cancelled by calling `getOrderStatus`
                 *         and confirming that `isCancelled` returns `true`.
                 *
                 * @param orders The orders to cancel.
                 *
                 * @return cancelled A boolean indicating whether the supplied orders have
                 *                   been successfully cancelled.
                 */
                function cancel(
                    OrderComponents[] calldata orders
                ) external returns (bool cancelled);
                /**
                 * @notice Validate an arbitrary number of orders, thereby registering their
                 *         signatures as valid and allowing the fulfiller to skip signature
                 *         verification on fulfillment. Note that validated orders may still
                 *         be unfulfillable due to invalid item amounts or other factors;
                 *         callers should determine whether validated orders are fulfillable
                 *         by simulating the fulfillment call prior to execution. Also note
                 *         that anyone can validate a signed order, but only the offerer can
                 *         validate an order without supplying a signature.
                 *
                 * @param orders The orders to validate.
                 *
                 * @return validated A boolean indicating whether the supplied orders have
                 *                   been successfully validated.
                 */
                function validate(
                    Order[] calldata orders
                ) external returns (bool validated);
                /**
                 * @notice Cancel all orders from a given offerer with a given zone in bulk
                 *         by incrementing a counter. Note that only the offerer may
                 *         increment the counter.
                 *
                 * @return newCounter The new counter.
                 */
                function incrementCounter() external returns (uint256 newCounter);
                /**
                 * @notice Fulfill an order offering an ERC721 token by supplying Ether (or
                 *         the native token for the given chain) as consideration for the
                 *         order. An arbitrary number of "additional recipients" may also be
                 *         supplied which will each receive native tokens from the fulfiller
                 *         as consideration. Note that this function costs less gas than
                 *         `fulfillBasicOrder` due to the zero bytes in the function
                 *         selector (0x00000000) which also results in earlier function
                 *         dispatch.
                 *
                 * @param parameters Additional information on the fulfilled order. Note
                 *                   that the offerer must first approve this contract (or
                 *                   their preferred conduit if indicated by the order) for
                 *                   their offered ERC721 token to be transferred.
                 *
                 * @return fulfilled A boolean indicating whether the order has been
                 *                   successfully fulfilled.
                 */
                function fulfillBasicOrder_efficient_6GL6yc(
                    BasicOrderParameters calldata parameters
                ) external payable returns (bool fulfilled);
                /**
                 * @notice Retrieve the order hash for a given order.
                 *
                 * @param order The components of the order.
                 *
                 * @return orderHash The order hash.
                 */
                function getOrderHash(
                    OrderComponents calldata order
                ) external view returns (bytes32 orderHash);
                /**
                 * @notice Retrieve the status of a given order by hash, including whether
                 *         the order has been cancelled or validated and the fraction of the
                 *         order that has been filled.
                 *
                 * @param orderHash The order hash in question.
                 *
                 * @return isValidated A boolean indicating whether the order in question
                 *                     has been validated (i.e. previously approved or
                 *                     partially filled).
                 * @return isCancelled A boolean indicating whether the order in question
                 *                     has been cancelled.
                 * @return totalFilled The total portion of the order that has been filled
                 *                     (i.e. the "numerator").
                 * @return totalSize   The total size of the order that is either filled or
                 *                     unfilled (i.e. the "denominator").
                 */
                function getOrderStatus(
                    bytes32 orderHash
                )
                    external
                    view
                    returns (
                        bool isValidated,
                        bool isCancelled,
                        uint256 totalFilled,
                        uint256 totalSize
                    );
                /**
                 * @notice Retrieve the current counter for a given offerer.
                 *
                 * @param offerer The offerer in question.
                 *
                 * @return counter The current counter.
                 */
                function getCounter(
                    address offerer
                ) external view returns (uint256 counter);
                /**
                 * @notice Retrieve configuration information for this contract.
                 *
                 * @return version           The contract version.
                 * @return domainSeparator   The domain separator for this contract.
                 * @return conduitController The conduit Controller set for this contract.
                 */
                function information()
                    external
                    view
                    returns (
                        string memory version,
                        bytes32 domainSeparator,
                        address conduitController
                    );
                function getContractOffererNonce(
                    address contractOfferer
                ) external view returns (uint256 nonce);
                /**
                 * @notice Retrieve the name of this contract.
                 *
                 * @return contractName The name of this contract.
                 */
                function name() external view returns (string memory contractName);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import {
                BasicOrderType,
                ItemType,
                OrderType,
                Side
            } from "./ConsiderationEnums.sol";
            import {
                CalldataPointer,
                MemoryPointer
            } from "../helpers/PointerLibraries.sol";
            /**
             * @dev An order contains eleven components: an offerer, a zone (or account that
             *      can cancel the order or restrict who can fulfill the order depending on
             *      the type), the order type (specifying partial fill support as well as
             *      restricted order status), the start and end time, a hash that will be
             *      provided to the zone when validating restricted orders, a salt, a key
             *      corresponding to a given conduit, a counter, and an arbitrary number of
             *      offer items that can be spent along with consideration items that must
             *      be received by their respective recipient.
             */
            struct OrderComponents {
                address offerer;
                address zone;
                OfferItem[] offer;
                ConsiderationItem[] consideration;
                OrderType orderType;
                uint256 startTime;
                uint256 endTime;
                bytes32 zoneHash;
                uint256 salt;
                bytes32 conduitKey;
                uint256 counter;
            }
            /**
             * @dev An offer item has five components: an item type (ETH or other native
             *      tokens, ERC20, ERC721, and ERC1155, as well as criteria-based ERC721 and
             *      ERC1155), a token address, a dual-purpose "identifierOrCriteria"
             *      component that will either represent a tokenId or a merkle root
             *      depending on the item type, and a start and end amount that support
             *      increasing or decreasing amounts over the duration of the respective
             *      order.
             */
            struct OfferItem {
                ItemType itemType;
                address token;
                uint256 identifierOrCriteria;
                uint256 startAmount;
                uint256 endAmount;
            }
            /**
             * @dev A consideration item has the same five components as an offer item and
             *      an additional sixth component designating the required recipient of the
             *      item.
             */
            struct ConsiderationItem {
                ItemType itemType;
                address token;
                uint256 identifierOrCriteria;
                uint256 startAmount;
                uint256 endAmount;
                address payable recipient;
            }
            /**
             * @dev A spent item is translated from a utilized offer item and has four
             *      components: an item type (ETH or other native tokens, ERC20, ERC721, and
             *      ERC1155), a token address, a tokenId, and an amount.
             */
            struct SpentItem {
                ItemType itemType;
                address token;
                uint256 identifier;
                uint256 amount;
            }
            /**
             * @dev A received item is translated from a utilized consideration item and has
             *      the same four components as a spent item, as well as an additional fifth
             *      component designating the required recipient of the item.
             */
            struct ReceivedItem {
                ItemType itemType;
                address token;
                uint256 identifier;
                uint256 amount;
                address payable recipient;
            }
            /**
             * @dev For basic orders involving ETH / native / ERC20 <=> ERC721 / ERC1155
             *      matching, a group of six functions may be called that only requires a
             *      subset of the usual order arguments. Note the use of a "basicOrderType"
             *      enum; this represents both the usual order type as well as the "route"
             *      of the basic order (a simple derivation function for the basic order
             *      type is `basicOrderType = orderType + (4 * basicOrderRoute)`.)
             */
            struct BasicOrderParameters {
                // calldata offset
                address considerationToken; // 0x24
                uint256 considerationIdentifier; // 0x44
                uint256 considerationAmount; // 0x64
                address payable offerer; // 0x84
                address zone; // 0xa4
                address offerToken; // 0xc4
                uint256 offerIdentifier; // 0xe4
                uint256 offerAmount; // 0x104
                BasicOrderType basicOrderType; // 0x124
                uint256 startTime; // 0x144
                uint256 endTime; // 0x164
                bytes32 zoneHash; // 0x184
                uint256 salt; // 0x1a4
                bytes32 offererConduitKey; // 0x1c4
                bytes32 fulfillerConduitKey; // 0x1e4
                uint256 totalOriginalAdditionalRecipients; // 0x204
                AdditionalRecipient[] additionalRecipients; // 0x224
                bytes signature; // 0x244
                // Total length, excluding dynamic array data: 0x264 (580)
            }
            /**
             * @dev Basic orders can supply any number of additional recipients, with the
             *      implied assumption that they are supplied from the offered ETH (or other
             *      native token) or ERC20 token for the order.
             */
            struct AdditionalRecipient {
                uint256 amount;
                address payable recipient;
            }
            /**
             * @dev The full set of order components, with the exception of the counter,
             *      must be supplied when fulfilling more sophisticated orders or groups of
             *      orders. The total number of original consideration items must also be
             *      supplied, as the caller may specify additional consideration items.
             */
            struct OrderParameters {
                address offerer; // 0x00
                address zone; // 0x20
                OfferItem[] offer; // 0x40
                ConsiderationItem[] consideration; // 0x60
                OrderType orderType; // 0x80
                uint256 startTime; // 0xa0
                uint256 endTime; // 0xc0
                bytes32 zoneHash; // 0xe0
                uint256 salt; // 0x100
                bytes32 conduitKey; // 0x120
                uint256 totalOriginalConsiderationItems; // 0x140
                // offer.length                          // 0x160
            }
            /**
             * @dev Orders require a signature in addition to the other order parameters.
             */
            struct Order {
                OrderParameters parameters;
                bytes signature;
            }
            /**
             * @dev Advanced orders include a numerator (i.e. a fraction to attempt to fill)
             *      and a denominator (the total size of the order) in addition to the
             *      signature and other order parameters. It also supports an optional field
             *      for supplying extra data; this data will be provided to the zone if the
             *      order type is restricted and the zone is not the caller, or will be
             *      provided to the offerer as context for contract order types.
             */
            struct AdvancedOrder {
                OrderParameters parameters;
                uint120 numerator;
                uint120 denominator;
                bytes signature;
                bytes extraData;
            }
            /**
             * @dev Orders can be validated (either explicitly via `validate`, or as a
             *      consequence of a full or partial fill), specifically cancelled (they can
             *      also be cancelled in bulk via incrementing a per-zone counter), and
             *      partially or fully filled (with the fraction filled represented by a
             *      numerator and denominator).
             */
            struct OrderStatus {
                bool isValidated;
                bool isCancelled;
                uint120 numerator;
                uint120 denominator;
            }
            /**
             * @dev A criteria resolver specifies an order, side (offer vs. consideration),
             *      and item index. It then provides a chosen identifier (i.e. tokenId)
             *      alongside a merkle proof demonstrating the identifier meets the required
             *      criteria.
             */
            struct CriteriaResolver {
                uint256 orderIndex;
                Side side;
                uint256 index;
                uint256 identifier;
                bytes32[] criteriaProof;
            }
            /**
             * @dev A fulfillment is applied to a group of orders. It decrements a series of
             *      offer and consideration items, then generates a single execution
             *      element. A given fulfillment can be applied to as many offer and
             *      consideration items as desired, but must contain at least one offer and
             *      at least one consideration that match. The fulfillment must also remain
             *      consistent on all key parameters across all offer items (same offerer,
             *      token, type, tokenId, and conduit preference) as well as across all
             *      consideration items (token, type, tokenId, and recipient).
             */
            struct Fulfillment {
                FulfillmentComponent[] offerComponents;
                FulfillmentComponent[] considerationComponents;
            }
            /**
             * @dev Each fulfillment component contains one index referencing a specific
             *      order and another referencing a specific offer or consideration item.
             */
            struct FulfillmentComponent {
                uint256 orderIndex;
                uint256 itemIndex;
            }
            /**
             * @dev An execution is triggered once all consideration items have been zeroed
             *      out. It sends the item in question from the offerer to the item's
             *      recipient, optionally sourcing approvals from either this contract
             *      directly or from the offerer's chosen conduit if one is specified. An
             *      execution is not provided as an argument, but rather is derived via
             *      orders, criteria resolvers, and fulfillments (where the total number of
             *      executions will be less than or equal to the total number of indicated
             *      fulfillments) and returned as part of `matchOrders`.
             */
            struct Execution {
                ReceivedItem item;
                address offerer;
                bytes32 conduitKey;
            }
            /**
             * @dev Restricted orders are validated post-execution by calling validateOrder
             *      on the zone. This struct provides context about the order fulfillment
             *      and any supplied extraData, as well as all order hashes fulfilled in a
             *      call to a match or fulfillAvailable method.
             */
            struct ZoneParameters {
                bytes32 orderHash;
                address fulfiller;
                address offerer;
                SpentItem[] offer;
                ReceivedItem[] consideration;
                bytes extraData;
                bytes32[] orderHashes;
                uint256 startTime;
                uint256 endTime;
                bytes32 zoneHash;
            }
            /**
             * @dev Zones and contract offerers can communicate which schemas they implement
             *      along with any associated metadata related to each schema.
             */
            struct Schema {
                uint256 id;
                bytes metadata;
            }
            using StructPointers for OrderComponents global;
            using StructPointers for OfferItem global;
            using StructPointers for ConsiderationItem global;
            using StructPointers for SpentItem global;
            using StructPointers for ReceivedItem global;
            using StructPointers for BasicOrderParameters global;
            using StructPointers for AdditionalRecipient global;
            using StructPointers for OrderParameters global;
            using StructPointers for Order global;
            using StructPointers for AdvancedOrder global;
            using StructPointers for OrderStatus global;
            using StructPointers for CriteriaResolver global;
            using StructPointers for Fulfillment global;
            using StructPointers for FulfillmentComponent global;
            using StructPointers for Execution global;
            using StructPointers for ZoneParameters global;
            /**
             * @dev This library provides a set of functions for converting structs to
             *      pointers.
             */
            library StructPointers {
                /**
                 * @dev Get a MemoryPointer from OrderComponents.
                 *
                 * @param obj The OrderComponents object.
                 *
                 * @return ptr The MemoryPointer.
                 */
                function toMemoryPointer(
                    OrderComponents memory obj
                ) internal pure returns (MemoryPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a CalldataPointer from OrderComponents.
                 *
                 * @param obj The OrderComponents object.
                 *
                 * @return ptr The CalldataPointer.
                 */
                function toCalldataPointer(
                    OrderComponents calldata obj
                ) internal pure returns (CalldataPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a MemoryPointer from OfferItem.
                 *
                 * @param obj The OfferItem object.
                 *
                 * @return ptr The MemoryPointer.
                 */
                function toMemoryPointer(
                    OfferItem memory obj
                ) internal pure returns (MemoryPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a CalldataPointer from OfferItem.
                 *
                 * @param obj The OfferItem object.
                 *
                 * @return ptr The CalldataPointer.
                 */
                function toCalldataPointer(
                    OfferItem calldata obj
                ) internal pure returns (CalldataPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a MemoryPointer from ConsiderationItem.
                 *
                 * @param obj The ConsiderationItem object.
                 *
                 * @return ptr The MemoryPointer.
                 */
                function toMemoryPointer(
                    ConsiderationItem memory obj
                ) internal pure returns (MemoryPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a CalldataPointer from ConsiderationItem.
                 *
                 * @param obj The ConsiderationItem object.
                 *
                 * @return ptr The CalldataPointer.
                 */
                function toCalldataPointer(
                    ConsiderationItem calldata obj
                ) internal pure returns (CalldataPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a MemoryPointer from SpentItem.
                 *
                 * @param obj The SpentItem object.
                 *
                 * @return ptr The MemoryPointer.
                 */
                function toMemoryPointer(
                    SpentItem memory obj
                ) internal pure returns (MemoryPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a CalldataPointer from SpentItem.
                 *
                 * @param obj The SpentItem object.
                 *
                 * @return ptr The CalldataPointer.
                 */
                function toCalldataPointer(
                    SpentItem calldata obj
                ) internal pure returns (CalldataPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a MemoryPointer from ReceivedItem.
                 *
                 * @param obj The ReceivedItem object.
                 *
                 * @return ptr The MemoryPointer.
                 */
                function toMemoryPointer(
                    ReceivedItem memory obj
                ) internal pure returns (MemoryPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a CalldataPointer from ReceivedItem.
                 *
                 * @param obj The ReceivedItem object.
                 *
                 * @return ptr The CalldataPointer.
                 */
                function toCalldataPointer(
                    ReceivedItem calldata obj
                ) internal pure returns (CalldataPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a MemoryPointer from BasicOrderParameters.
                 *
                 * @param obj The BasicOrderParameters object.
                 *
                 * @return ptr The MemoryPointer.
                 */
                function toMemoryPointer(
                    BasicOrderParameters memory obj
                ) internal pure returns (MemoryPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a CalldataPointer from BasicOrderParameters.
                 *
                 * @param obj The BasicOrderParameters object.
                 *
                 * @return ptr The CalldataPointer.
                 */
                function toCalldataPointer(
                    BasicOrderParameters calldata obj
                ) internal pure returns (CalldataPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a MemoryPointer from AdditionalRecipient.
                 *
                 * @param obj The AdditionalRecipient object.
                 *
                 * @return ptr The MemoryPointer.
                 */
                function toMemoryPointer(
                    AdditionalRecipient memory obj
                ) internal pure returns (MemoryPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a CalldataPointer from AdditionalRecipient.
                 *
                 * @param obj The AdditionalRecipient object.
                 *
                 * @return ptr The CalldataPointer.
                 */
                function toCalldataPointer(
                    AdditionalRecipient calldata obj
                ) internal pure returns (CalldataPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a MemoryPointer from OrderParameters.
                 *
                 * @param obj The OrderParameters object.
                 *
                 * @return ptr The MemoryPointer.
                 */
                function toMemoryPointer(
                    OrderParameters memory obj
                ) internal pure returns (MemoryPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a CalldataPointer from OrderParameters.
                 *
                 * @param obj The OrderParameters object.
                 *
                 * @return ptr The CalldataPointer.
                 */
                function toCalldataPointer(
                    OrderParameters calldata obj
                ) internal pure returns (CalldataPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a MemoryPointer from Order.
                 *
                 * @param obj The Order object.
                 *
                 * @return ptr The MemoryPointer.
                 */
                function toMemoryPointer(
                    Order memory obj
                ) internal pure returns (MemoryPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a CalldataPointer from Order.
                 *
                 * @param obj The Order object.
                 *
                 * @return ptr The CalldataPointer.
                 */
                function toCalldataPointer(
                    Order calldata obj
                ) internal pure returns (CalldataPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a MemoryPointer from AdvancedOrder.
                 *
                 * @param obj The AdvancedOrder object.
                 *
                 * @return ptr The MemoryPointer.
                 */
                function toMemoryPointer(
                    AdvancedOrder memory obj
                ) internal pure returns (MemoryPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a CalldataPointer from AdvancedOrder.
                 *
                 * @param obj The AdvancedOrder object.
                 *
                 * @return ptr The CalldataPointer.
                 */
                function toCalldataPointer(
                    AdvancedOrder calldata obj
                ) internal pure returns (CalldataPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a MemoryPointer from OrderStatus.
                 *
                 * @param obj The OrderStatus object.
                 *
                 * @return ptr The MemoryPointer.
                 */
                function toMemoryPointer(
                    OrderStatus memory obj
                ) internal pure returns (MemoryPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a CalldataPointer from OrderStatus.
                 *
                 * @param obj The OrderStatus object.
                 *
                 * @return ptr The CalldataPointer.
                 */
                function toCalldataPointer(
                    OrderStatus calldata obj
                ) internal pure returns (CalldataPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a MemoryPointer from CriteriaResolver.
                 *
                 * @param obj The CriteriaResolver object.
                 *
                 * @return ptr The MemoryPointer.
                 */
                function toMemoryPointer(
                    CriteriaResolver memory obj
                ) internal pure returns (MemoryPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a CalldataPointer from CriteriaResolver.
                 *
                 * @param obj The CriteriaResolver object.
                 *
                 * @return ptr The CalldataPointer.
                 */
                function toCalldataPointer(
                    CriteriaResolver calldata obj
                ) internal pure returns (CalldataPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a MemoryPointer from Fulfillment.
                 *
                 * @param obj The Fulfillment object.
                 *
                 * @return ptr The MemoryPointer.
                 */
                function toMemoryPointer(
                    Fulfillment memory obj
                ) internal pure returns (MemoryPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a CalldataPointer from Fulfillment.
                 *
                 * @param obj The Fulfillment object.
                 *
                 * @return ptr The CalldataPointer.
                 */
                function toCalldataPointer(
                    Fulfillment calldata obj
                ) internal pure returns (CalldataPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a MemoryPointer from FulfillmentComponent.
                 *
                 * @param obj The FulfillmentComponent object.
                 *
                 * @return ptr The MemoryPointer.
                 */
                function toMemoryPointer(
                    FulfillmentComponent memory obj
                ) internal pure returns (MemoryPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a CalldataPointer from FulfillmentComponent.
                 *
                 * @param obj The FulfillmentComponent object.
                 *
                 * @return ptr The CalldataPointer.
                 */
                function toCalldataPointer(
                    FulfillmentComponent calldata obj
                ) internal pure returns (CalldataPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a MemoryPointer from Execution.
                 *
                 * @param obj The Execution object.
                 *
                 * @return ptr The MemoryPointer.
                 */
                function toMemoryPointer(
                    Execution memory obj
                ) internal pure returns (MemoryPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a CalldataPointer from Execution.
                 *
                 * @param obj The Execution object.
                 *
                 * @return ptr The CalldataPointer.
                 */
                function toCalldataPointer(
                    Execution calldata obj
                ) internal pure returns (CalldataPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a MemoryPointer from ZoneParameters.
                 *
                 * @param obj The ZoneParameters object.
                 *
                 * @return ptr The MemoryPointer.
                 */
                function toMemoryPointer(
                    ZoneParameters memory obj
                ) internal pure returns (MemoryPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Get a CalldataPointer from ZoneParameters.
                 *
                 * @param obj The ZoneParameters object.
                 *
                 * @return ptr The CalldataPointer.
                 */
                function toCalldataPointer(
                    ZoneParameters calldata obj
                ) internal pure returns (CalldataPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.17;
            import { Side, ItemType, OrderType } from "./ConsiderationEnums.sol";
            import {
                AdvancedOrder,
                ConsiderationItem,
                CriteriaResolver,
                Execution,
                Fulfillment,
                FulfillmentComponent,
                OfferItem,
                OrderParameters,
                ReceivedItem
            } from "./ConsiderationStructs.sol";
            import { OrderFulfiller } from "./OrderFulfiller.sol";
            import { FulfillmentApplier } from "./FulfillmentApplier.sol";
            import {
                _revertConsiderationNotMet,
                _revertInsufficientNativeTokensSupplied,
                _revertInvalidNativeOfferItem,
                _revertNoSpecifiedOrdersAvailable
            } from "./ConsiderationErrors.sol";
            import {
                AccumulatorDisarmed,
                ConsiderationItem_recipient_offset,
                Execution_offerer_offset,
                NonMatchSelector_InvalidErrorValue,
                NonMatchSelector_MagicMask,
                OneWord,
                OneWordShift,
                OrdersMatchedTopic0,
                ReceivedItem_amount_offset,
                ReceivedItem_recipient_offset,
                TwoWords
            } from "./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[][] memory offerFulfillments,
                    FulfillmentComponent[][] memory considerationFulfillments,
                    bytes32 fulfillerConduitKey,
                    address recipient,
                    uint256 maximumFulfilled
                )
                    internal
                    returns (
                        bool[] memory /* availableOrders */,
                        Execution[] memory /* executions */
                    )
                {
                    // Validate orders, apply amounts, & determine if they utilize conduits.
                    (
                        bytes32[] memory orderHashes,
                        bool containsNonOpen
                    ) = _validateOrdersAndPrepareToFulfill(
                            advancedOrders,
                            criteriaResolvers,
                            false, // Signifies that invalid orders should NOT revert.
                            maximumFulfilled,
                            recipient
                        );
                    // Aggregate used offer and consideration items and execute transfers.
                    return
                        _executeAvailableFulfillments(
                            advancedOrders,
                            offerFulfillments,
                            considerationFulfillments,
                            fulfillerConduitKey,
                            recipient,
                            orderHashes,
                            containsNonOpen
                        );
                }
                /**
                 * @dev Internal function to validate a group of orders, update their
                 *      statuses, reduce amounts by their previously filled fractions, apply
                 *      criteria resolvers, and emit OrderFulfilled events. Note that this
                 *      function needs to be called before
                 *      _aggregateValidFulfillmentConsiderationItems to set the memory
                 *      layout that _aggregateValidFulfillmentConsiderationItems depends on.
                 *
                 * @param advancedOrders    The advanced orders to validate and reduce by
                 *                          their previously filled amounts.
                 * @param criteriaResolvers An array where each element contains a reference
                 *                          to a specific order as well as that order's
                 *                          offer or consideration, a token identifier, and
                 *                          a proof that the supplied token identifier is
                 *                          contained in the order's merkle root. Note that
                 *                          a root of zero indicates that any transferable
                 *                          token identifier is valid and that no proof
                 *                          needs to be supplied.
                 * @param revertOnInvalid   A boolean indicating whether to revert on any
                 *                          order being invalid; setting this to false will
                 *                          instead cause the invalid order to be skipped.
                 * @param maximumFulfilled  The maximum number of orders to fulfill.
                 * @param recipient         The intended recipient for all items that do not
                 *                          already have a designated recipient and are not
                 *                          already used as part of a provided fulfillment.
                 *
                 * @return orderHashes     The hashes of the orders being fulfilled.
                 * @return containsNonOpen A boolean indicating whether any restricted or
                 *                         contract orders are present within the provided
                 *                         array of advanced orders.
                 */
                function _validateOrdersAndPrepareToFulfill(
                    AdvancedOrder[] memory advancedOrders,
                    CriteriaResolver[] memory criteriaResolvers,
                    bool revertOnInvalid,
                    uint256 maximumFulfilled,
                    address recipient
                ) internal returns (bytes32[] memory orderHashes, bool containsNonOpen) {
                    // Ensure this function cannot be triggered during a reentrant call.
                    _setReentrancyGuard(true); // Native tokens accepted during execution.
                    // Declare an error buffer indicating status of any native offer items.
                    // Native tokens may only be provided as part of contract orders or when
                    // fulfilling via matchOrders or matchAdvancedOrders; if bits indicating
                    // these conditions are not met have been set, throw.
                    uint256 invalidNativeOfferItemErrorBuffer;
                    // Use assembly to set the value for the second bit of the error buffer.
                    assembly {
                        /**
                         * Use the 231st bit of the error buffer to indicate whether the
                         * current function is not matchAdvancedOrders or matchOrders.
                         *
                         * sig                                func
                         * -----------------------------------------------------------------
                         * 1010100000010111010001000 0 000100 matchOrders
                         * 1111001011010001001010110 0 010010 matchAdvancedOrders
                         * 1110110110011000101001010 1 110100 fulfillAvailableOrders
                         * 1000011100100000000110110 1 000001 fulfillAvailableAdvancedOrders
                         *                           ^ 7th bit
                         */
                        invalidNativeOfferItemErrorBuffer := and(
                            NonMatchSelector_MagicMask,
                            calldataload(0)
                        )
                    }
                    // Declare variables for later use.
                    AdvancedOrder memory advancedOrder;
                    uint256 terminalMemoryOffset;
                    unchecked {
                        // Read length of orders array and place on the stack.
                        uint256 totalOrders = advancedOrders.length;
                        // Track the order hash for each order being fulfilled.
                        orderHashes = new bytes32[](totalOrders);
                        // Determine the memory offset to terminate on during loops.
                        terminalMemoryOffset = (totalOrders + 1) << OneWordShift;
                    }
                    // Skip overflow checks as all for loops are indexed starting at zero.
                    unchecked {
                        // Declare inner variables.
                        OfferItem[] memory offer;
                        ConsiderationItem[] memory consideration;
                        // Iterate over each order.
                        for (uint256 i = OneWord; i < terminalMemoryOffset; i += OneWord) {
                            // Retrieve order using assembly to bypass out-of-range check.
                            assembly {
                                advancedOrder := mload(add(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;
                                // Continue iterating through the remaining orders.
                                continue;
                            }
                            // Validate it, update status, and determine fraction to fill.
                            (
                                bytes32 orderHash,
                                uint256 numerator,
                                uint256 denominator
                            ) = _validateOrderAndUpdateStatus(
                                    advancedOrder,
                                    revertOnInvalid
                                );
                            // 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.
                            assembly {
                                mstore(add(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.
                            offer = advancedOrder.parameters.offer;
                            // Read length of offer array and place on the stack.
                            uint256 totalOfferItems = offer.length;
                            {
                                // Determine the order type, used to check for eligibility
                                // for native token offer items as well as for the presence
                                // of restricted and contract orders (or non-open orders).
                                OrderType orderType = advancedOrder.parameters.orderType;
                                // Utilize assembly to efficiently check for order types.
                                // Note that these checks expect that there are no order
                                // types beyond the current set (0-4) and will need to be
                                // modified if more order types are added.
                                assembly {
                                    // Declare a variable indicating if the order is not a
                                    // contract order. Cache in scratch space to avoid stack
                                    // depth errors.
                                    let isNonContract := lt(orderType, 4)
                                    mstore(0, isNonContract)
                                    // Update the variable indicating if the order is not an
                                    // open order, remaining set if it has been set already.
                                    containsNonOpen := or(containsNonOpen, gt(orderType, 1))
                                }
                            }
                            // Iterate over each offer item on the order.
                            for (uint256 j = 0; j < totalOfferItems; ++j) {
                                // Retrieve the offer item.
                                OfferItem memory offerItem = offer[j];
                                // If the offer item is for the native token and the order
                                // type is not a contract order type, set the first bit of
                                // the error buffer to true.
                                assembly {
                                    invalidNativeOfferItemErrorBuffer := or(
                                        invalidNativeOfferItemErrorBuffer,
                                        lt(mload(offerItem), mload(0))
                                    )
                                }
                                // 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
                                    );
                                }
                                // Adjust offer amount using current time; round down.
                                uint256 currentAmount = _locateCurrentAmount(
                                    offerItem.startAmount,
                                    endAmount,
                                    startTime,
                                    endTime,
                                    false // round down
                                );
                                // Update amounts in memory to match the current amount.
                                // Note that the end amount is used to track spent amounts.
                                offerItem.startAmount = currentAmount;
                                offerItem.endAmount = currentAmount;
                            }
                            // Retrieve array of consideration items for order in question.
                            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
                                    );
                                }
                                // Adjust consideration amount using current time; round up.
                                uint256 currentAmount = (
                                    _locateCurrentAmount(
                                        considerationItem.startAmount,
                                        endAmount,
                                        startTime,
                                        endTime,
                                        true // round up
                                    )
                                );
                                considerationItem.startAmount = currentAmount;
                                // Utilize assembly to manually "shift" the recipient value,
                                // then to copy the start amount to the recipient.
                                // Note that this sets up the memory layout that is
                                // subsequently relied upon by
                                // _aggregateValidFulfillmentConsiderationItems.
                                assembly {
                                    // Derive the pointer to the recipient using the item
                                    // pointer along with the offset to the recipient.
                                    let considerationItemRecipientPtr := add(
                                        considerationItem,
                                        ConsiderationItem_recipient_offset // recipient
                                    )
                                    // 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(considerationItemRecipientPtr)
                                    )
                                    // Write startAmount to recipient, as recipient is not
                                    // used from this point on and can be repurposed to
                                    // track received amounts.
                                    mstore(considerationItemRecipientPtr, currentAmount)
                                }
                            }
                        }
                    }
                    // If the first bit is set, a native offer item was encountered on an
                    // order that is not a contract order. If the 231st bit is set in the
                    // error buffer, the current function is not matchOrders or
                    // matchAdvancedOrders. If the value is 1 + (1 << 230), then both the
                    // 1st and 231st bits were set; in that case, revert with an error.
                    if (
                        invalidNativeOfferItemErrorBuffer ==
                        NonMatchSelector_InvalidErrorValue
                    ) {
                        _revertInvalidNativeOfferItem();
                    }
                    // Apply criteria resolvers to each order as applicable.
                    _applyCriteriaResolvers(advancedOrders, criteriaResolvers);
                    // 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 {
                        bytes32 orderHash;
                        // Iterate over each order.
                        for (uint256 i = OneWord; i < terminalMemoryOffset; i += OneWord) {
                            assembly {
                                orderHash := mload(add(orderHashes, i))
                            }
                            // Do not emit an event if no order hash is present.
                            if (orderHash == bytes32(0)) {
                                continue;
                            }
                            // Retrieve order using assembly to bypass out-of-range check.
                            assembly {
                                advancedOrder := mload(add(advancedOrders, i))
                            }
                            // Retrieve parameters for the order in question.
                            OrderParameters memory orderParameters = (
                                advancedOrder.parameters
                            );
                            // Emit an OrderFulfilled event.
                            _emitOrderFulfilledEvent(
                                orderHash,
                                orderParameters.offerer,
                                orderParameters.zone,
                                recipient,
                                orderParameters.offer,
                                orderParameters.consideration
                            );
                        }
                    }
                }
                /**
                 * @dev Internal function to fulfill a group of validated orders, fully or
                 *      partially, with an arbitrary number of items for offer and
                 *      consideration per order and to execute transfers. Any order that is
                 *      not currently active, has already been fully filled, or has been
                 *      cancelled will be omitted. Remaining offer and consideration items
                 *      will then be aggregated where possible as indicated by the supplied
                 *      offer and consideration component arrays and aggregated items will
                 *      be transferred to the fulfiller or to each intended recipient,
                 *      respectively. Note that a failing item transfer or an issue with
                 *      order formatting will cause the entire batch to fail.
                 *
                 * @param advancedOrders            The orders to fulfill along with the
                 *                                  fraction of those orders to attempt to
                 *                                  fill. Note that both the offerer and the
                 *                                  fulfiller must first approve this
                 *                                  contract (or the conduit if indicated by
                 *                                  the order) to transfer any relevant
                 *                                  tokens on their behalf and that
                 *                                  contracts must implement
                 *                                  `onERC1155Received` in order to receive
                 *                                  ERC1155 tokens as consideration. Also
                 *                                  note that all offer and consideration
                 *                                  components must have no remainder after
                 *                                  multiplication of the respective amount
                 *                                  with the supplied fraction for an
                 *                                  order's partial fill amount to be
                 *                                  considered valid.
                 * @param offerFulfillments         An array of FulfillmentComponent arrays
                 *                                  indicating which offer items to attempt
                 *                                  to aggregate when preparing executions.
                 * @param considerationFulfillments An array of FulfillmentComponent arrays
                 *                                  indicating which consideration items to
                 *                                  attempt to aggregate when preparing
                 *                                  executions.
                 * @param fulfillerConduitKey       A bytes32 value indicating what conduit,
                 *                                  if any, to source the fulfiller's token
                 *                                  approvals from. The zero hash signifies
                 *                                  that no conduit should be used, with
                 *                                  direct approvals set on Consideration.
                 * @param recipient                 The intended recipient for all items
                 *                                  that do not already have a designated
                 *                                  recipient and are not already used as
                 *                                  part of a provided fulfillment.
                 * @param orderHashes               An array of order hashes for each order.
                 * @param containsNonOpen           A boolean indicating whether any
                 *                                  restricted or contract orders are
                 *                                  present within the provided array of
                 *                                  advanced orders.
                 *
                 * @return availableOrders An array of booleans indicating if each order
                 *                         with an index corresponding to the index of the
                 *                         returned boolean was fulfillable or not.
                 * @return executions      An array of elements indicating the sequence of
                 *                         transfers performed as part of matching the given
                 *                         orders.
                 */
                function _executeAvailableFulfillments(
                    AdvancedOrder[] memory advancedOrders,
                    FulfillmentComponent[][] memory offerFulfillments,
                    FulfillmentComponent[][] memory considerationFulfillments,
                    bytes32 fulfillerConduitKey,
                    address recipient,
                    bytes32[] memory orderHashes,
                    bool containsNonOpen
                )
                    internal
                    returns (bool[] memory availableOrders, Execution[] memory executions)
                {
                    // Retrieve length of offer fulfillments array and place on the stack.
                    uint256 totalOfferFulfillments = offerFulfillments.length;
                    // Retrieve length of consideration fulfillments array & place on stack.
                    uint256 totalConsiderationFulfillments = (
                        considerationFulfillments.length
                    );
                    // Allocate an execution for each offer and consideration fulfillment.
                    executions = new Execution[](
                        totalOfferFulfillments + totalConsiderationFulfillments
                    );
                    // Skip overflow checks as all for loops are indexed starting at zero.
                    unchecked {
                        // Track number of filtered executions.
                        uint256 totalFilteredExecutions = 0;
                        // Iterate over each offer fulfillment.
                        for (uint256 i = 0; i < totalOfferFulfillments; ) {
                            // Derive aggregated execution corresponding with fulfillment.
                            Execution memory execution = _aggregateAvailable(
                                advancedOrders,
                                Side.OFFER,
                                offerFulfillments[i],
                                fulfillerConduitKey,
                                recipient
                            );
                            // If the execution is filterable...
                            if (_isFilterableExecution(execution)) {
                                // Increment total filtered executions.
                                ++totalFilteredExecutions;
                            } else {
                                // Otherwise, assign the execution to the executions array.
                                executions[i - totalFilteredExecutions] = execution;
                            }
                            // Increment iterator.
                            ++i;
                        }
                        // Iterate over each consideration fulfillment.
                        for (uint256 i = 0; i < totalConsiderationFulfillments; ) {
                            // Derive aggregated execution corresponding with fulfillment.
                            Execution memory execution = _aggregateAvailable(
                                advancedOrders,
                                Side.CONSIDERATION,
                                considerationFulfillments[i],
                                fulfillerConduitKey,
                                address(0) // unused
                            );
                            // If the execution is filterable...
                            if (_isFilterableExecution(execution)) {
                                // Increment total filtered executions.
                                ++totalFilteredExecutions;
                            } else {
                                // Otherwise, assign the execution to the executions array.
                                executions[
                                    i + totalOfferFulfillments - totalFilteredExecutions
                                ] = execution;
                            }
                            // Increment iterator.
                            ++i;
                        }
                        // 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) {
                        _revertNoSpecifiedOrdersAvailable();
                    }
                    // Perform final checks and return.
                    availableOrders = _performFinalChecksAndExecuteOrders(
                        advancedOrders,
                        executions,
                        orderHashes,
                        recipient,
                        containsNonOpen
                    );
                    return (availableOrders, executions);
                }
                /**
                 * @dev Internal function to perform a final check that each consideration
                 *      item for an arbitrary number of fulfilled orders has been met and to
                 *      trigger associated executions, transferring the respective items.
                 *
                 * @param advancedOrders  The orders to check and perform executions for.
                 * @param executions      An array of elements indicating the sequence of
                 *                        transfers to perform when fulfilling the given
                 *                        orders.
                 * @param orderHashes     An array of order hashes for each order.
                 * @param recipient       The intended recipient for all items that do not
                 *                        already have a designated recipient and are not
                 *                        used as part of a provided fulfillment.
                 * @param containsNonOpen A boolean indicating whether any restricted or
                 *                        contract orders are present within the provided
                 *                        array of advanced orders.
                 *
                 * @return availableOrders An array of booleans indicating if each order
                 *                         with an index corresponding to the index of the
                 *                         returned boolean was fulfillable or not.
                 */
                function _performFinalChecksAndExecuteOrders(
                    AdvancedOrder[] memory advancedOrders,
                    Execution[] memory executions,
                    bytes32[] memory orderHashes,
                    address recipient,
                    bool containsNonOpen
                ) internal returns (bool[] memory /* availableOrders */) {
                    // Retrieve the length of the advanced orders array and place on stack.
                    uint256 totalOrders = advancedOrders.length;
                    // Initialize array for tracking available orders.
                    bool[] memory availableOrders = new bool[](totalOrders);
                    // Initialize an accumulator array. From this point forward, no new
                    // memory regions can be safely allocated until the accumulator is no
                    // longer being utilized, as the accumulator operates in an open-ended
                    // fashion from this memory pointer; existing memory may still be
                    // accessed and modified, however.
                    bytes memory accumulator = new bytes(AccumulatorDisarmed);
                    {
                        // Declare a variable for the available native token balance.
                        uint256 nativeTokenBalance;
                        // 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) {
                                // Get the current available balance of native tokens.
                                assembly {
                                    nativeTokenBalance := selfbalance()
                                }
                                // Ensure that sufficient native tokens are still available.
                                if (item.amount > nativeTokenBalance) {
                                    _revertInsufficientNativeTokensSupplied();
                                }
                            }
                            // 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;
                            }
                        }
                    }
                    // Skip overflow checks as all for loops are indexed starting at zero.
                    unchecked {
                        // Iterate over each order.
                        for (uint256 i = 0; i < totalOrders; ++i) {
                            // Retrieve the order in question.
                            AdvancedOrder memory advancedOrder = advancedOrders[i];
                            // Skip the order in question if not being not fulfilled.
                            if (advancedOrder.numerator == 0) {
                                // Explicitly set availableOrders at the given index to
                                // guard against the possibility of dirtied memory.
                                availableOrders[i] = false;
                                continue;
                            }
                            // Mark the order as available.
                            availableOrders[i] = true;
                            // Retrieve the order parameters.
                            OrderParameters memory parameters = advancedOrder.parameters;
                            {
                                // Retrieve offer items.
                                OfferItem[] memory offer = parameters.offer;
                                // Read length of offer array & place on the stack.
                                uint256 totalOfferItems = offer.length;
                                // Iterate over each offer item to restore it.
                                for (uint256 j = 0; j < totalOfferItems; ++j) {
                                    // Retrieve the offer item in question.
                                    OfferItem memory offerItem = offer[j];
                                    // Transfer to recipient if unspent amount is not zero.
                                    // Note that the transfer will not be reflected in the
                                    // executions array.
                                    if (offerItem.startAmount != 0) {
                                        _transfer(
                                            _fromOfferItemToReceivedItemWithRecipient(
                                                offerItem,
                                                recipient
                                            ),
                                            parameters.offerer,
                                            parameters.conduitKey,
                                            accumulator
                                        );
                                    }
                                    // Restore original amount on the offer item.
                                    offerItem.startAmount = offerItem.endAmount;
                                }
                            }
                            {
                                // Read consideration items & ensure they are fulfilled.
                                ConsiderationItem[] memory consideration = (
                                    parameters.consideration
                                );
                                // Read length of consideration array & place on stack.
                                uint256 totalConsiderationItems = consideration.length;
                                // Iterate over each consideration item.
                                for (uint256 j = 0; j < totalConsiderationItems; ++j) {
                                    ConsiderationItem memory considerationItem = (
                                        consideration[j]
                                    );
                                    // Retrieve remaining amount on consideration item.
                                    uint256 unmetAmount = considerationItem.startAmount;
                                    // Revert if the remaining amount is not zero.
                                    if (unmetAmount != 0) {
                                        _revertConsiderationNotMet(i, j, unmetAmount);
                                    }
                                    // Utilize assembly to restore the original value.
                                    assembly {
                                        // Write recipient to startAmount.
                                        mstore(
                                            add(
                                                considerationItem,
                                                ReceivedItem_amount_offset
                                            ),
                                            mload(
                                                add(
                                                    considerationItem,
                                                    ConsiderationItem_recipient_offset
                                                )
                                            )
                                        )
                                    }
                                }
                            }
                        }
                    }
                    // Trigger any accumulated transfers via call to the conduit.
                    _triggerIfArmed(accumulator);
                    // Determine whether any native token balance remains.
                    uint256 remainingNativeTokenBalance;
                    assembly {
                        remainingNativeTokenBalance := selfbalance()
                    }
                    // Return any remaining native token balance to the caller.
                    if (remainingNativeTokenBalance != 0) {
                        _transferNativeTokens(
                            payable(msg.sender),
                            remainingNativeTokenBalance
                        );
                    }
                    // If any restricted or contract orders are present in the group of
                    // orders being fulfilled, perform any validateOrder or ratifyOrder
                    // calls after all executions and related transfers are complete.
                    if (containsNonOpen) {
                        // Iterate over each order a second time.
                        for (uint256 i = 0; i < totalOrders; ) {
                            // Ensure the order in question is being fulfilled.
                            if (availableOrders[i]) {
                                // Check restricted orders and contract orders.
                                _assertRestrictedAdvancedOrderValidity(
                                    advancedOrders[i],
                                    orderHashes,
                                    orderHashes[i]
                                );
                            }
                            // Skip overflow checks as for loop is indexed starting at zero.
                            unchecked {
                                ++i;
                            }
                        }
                    }
                    // Clear the reentrancy guard.
                    _clearReentrancyGuard();
                    // Return the array containing available orders.
                    return availableOrders;
                }
                /**
                 * @dev Internal function to emit an OrdersMatched event using the same
                 *      memory region as the existing order hash array.
                 *
                 * @param orderHashes An array of order hashes to include as an argument for
                 *                    the OrdersMatched event.
                 */
                function _emitOrdersMatched(bytes32[] memory orderHashes) internal {
                    assembly {
                        // Load the array length from memory.
                        let length := mload(orderHashes)
                        // Get the full size of the event data - one word for the offset,
                        // one for the array length and one per hash.
                        let dataSize := add(TwoWords, shl(OneWordShift, length))
                        // Get pointer to start of data, reusing word before array length
                        // for the offset.
                        let dataPointer := sub(orderHashes, OneWord)
                        // Cache the existing word in memory at the offset pointer.
                        let cache := mload(dataPointer)
                        // Write an offset of 32.
                        mstore(dataPointer, OneWord)
                        // Emit the OrdersMatched event.
                        log1(dataPointer, dataSize, OrdersMatchedTopic0)
                        // Restore the cached word.
                        mstore(dataPointer, cache)
                    }
                }
                /**
                 * @dev Internal function to match an arbitrary number of full or partial
                 *      orders, each with an arbitrary number of items for offer and
                 *      consideration, supplying criteria resolvers containing specific
                 *      token identifiers and associated proofs as well as fulfillments
                 *      allocating offer components to consideration components.
                 *
                 * @param advancedOrders    The advanced orders to match. Note that both the
                 *                          offerer and fulfiller on each order must first
                 *                          approve this contract (or their conduit if
                 *                          indicated by the order) to transfer any relevant
                 *                          tokens on their behalf and each consideration
                 *                          recipient must implement `onERC1155Received` in
                 *                          order to receive ERC1155 tokens. Also note that
                 *                          the offer and consideration components for each
                 *                          order must have no remainder after multiplying
                 *                          the respective amount with the supplied fraction
                 *                          in order for the group of partial fills to be
                 *                          considered valid.
                 * @param criteriaResolvers An array where each element contains a reference
                 *                          to a specific order as well as that order's
                 *                          offer or consideration, a token identifier, and
                 *                          a proof that the supplied token identifier is
                 *                          contained in the order's merkle root. Note that
                 *                          an empty root indicates that any (transferable)
                 *                          token identifier is valid and that no associated
                 *                          proof needs to be supplied.
                 * @param fulfillments      An array of elements allocating offer components
                 *                          to consideration components. Note that each
                 *                          consideration component must be fully met in
                 *                          order for the match operation to be valid.
                 * @param recipient         The intended recipient for all unspent offer
                 *                          item amounts.
                 *
                 * @return executions An array of elements indicating the sequence of
                 *                    transfers performed as part of matching the given
                 *                    orders.
                 */
                function _matchAdvancedOrders(
                    AdvancedOrder[] memory advancedOrders,
                    CriteriaResolver[] memory criteriaResolvers,
                    Fulfillment[] memory fulfillments,
                    address recipient
                ) internal returns (Execution[] memory /* executions */) {
                    // Validate orders, update order status, and determine item amounts.
                    (
                        bytes32[] memory orderHashes,
                        bool containsNonOpen
                    ) = _validateOrdersAndPrepareToFulfill(
                            advancedOrders,
                            criteriaResolvers,
                            true, // Signifies that invalid orders should revert.
                            advancedOrders.length,
                            recipient
                        );
                    // Emit OrdersMatched event, providing an array of matched order hashes.
                    _emitOrdersMatched(orderHashes);
                    // Fulfill the orders using the supplied fulfillments and recipient.
                    return
                        _fulfillAdvancedOrders(
                            advancedOrders,
                            fulfillments,
                            orderHashes,
                            recipient,
                            containsNonOpen
                        );
                }
                /**
                 * @dev Internal function to fulfill an arbitrary number of orders, either
                 *      full or partial, after validating, adjusting amounts, and applying
                 *      criteria resolvers.
                 *
                 * @param advancedOrders  The orders to match, including a fraction to
                 *                        attempt to fill for each order.
                 * @param fulfillments    An array of elements allocating offer components
                 *                        to consideration components. Note that the final
                 *                        amount of each consideration component must be
                 *                        zero for a match operation to be considered valid.
                 * @param orderHashes     An array of order hashes for each order.
                 * @param recipient       The intended recipient for all items that do not
                 *                        already have a designated recipient and are not
                 *                        used as part of a provided fulfillment.
                 * @param containsNonOpen A boolean indicating whether any restricted or
                 *                        contract orders are present within the provided
                 *                        array of advanced orders.
                 *
                 * @return executions An array of elements indicating the sequence of
                 *                    transfers performed as part of matching the given
                 *                    orders.
                 */
                function _fulfillAdvancedOrders(
                    AdvancedOrder[] memory advancedOrders,
                    Fulfillment[] memory fulfillments,
                    bytes32[] memory orderHashes,
                    address recipient,
                    bool containsNonOpen
                ) internal returns (Execution[] memory executions) {
                    // Retrieve fulfillments array length and place on the stack.
                    uint256 totalFulfillments = fulfillments.length;
                    // Allocate executions by fulfillment and apply them to each execution.
                    executions = new Execution[](totalFulfillments);
                    // Skip overflow checks as all for loops are indexed starting at zero.
                    unchecked {
                        // 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 memory fulfillment = fulfillments[i];
                            // Derive the execution corresponding with the fulfillment.
                            Execution memory execution = _applyFulfillment(
                                advancedOrders,
                                fulfillment.offerComponents,
                                fulfillment.considerationComponents,
                                i
                            );
                            // If the execution is filterable...
                            if (_isFilterableExecution(execution)) {
                                // 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,
                        orderHashes,
                        recipient,
                        containsNonOpen
                    );
                    // Return the executions array.
                    return executions;
                }
                /**
                 * @dev Internal pure function to determine whether a given execution is
                 *      filterable and may be removed from the executions array. The offerer
                 *      and the recipient must be the same address and the item type cannot
                 *      indicate a native token transfer.
                 *
                 * @param execution The execution to check for filterability.
                 *
                 * @return filterable A boolean indicating whether the execution in question
                 *                    can be filtered from the executions array.
                 */
                function _isFilterableExecution(
                    Execution memory execution
                ) internal pure returns (bool filterable) {
                    // Utilize assembly to efficiently determine if execution is filterable.
                    assembly {
                        // Retrieve the received item referenced by the execution.
                        let item := mload(execution)
                        // Determine whether the execution is filterable.
                        filterable := and(
                            // Determine if offerer and recipient are the same address.
                            eq(
                                // Retrieve the recipient's address from the received item.
                                mload(add(item, ReceivedItem_recipient_offset)),
                                // Retrieve the offerer's address from the execution.
                                mload(add(execution, Execution_offerer_offset))
                            ),
                            // Determine if received item's item type is non-zero, thereby
                            // indicating that the execution does not involve native tokens.
                            iszero(iszero(mload(item)))
                        )
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            type CalldataPointer is uint256;
            type ReturndataPointer is uint256;
            type MemoryPointer is uint256;
            using CalldataPointerLib for CalldataPointer global;
            using MemoryPointerLib for MemoryPointer global;
            using ReturndataPointerLib for ReturndataPointer global;
            using CalldataReaders for CalldataPointer global;
            using ReturndataReaders for ReturndataPointer global;
            using MemoryReaders for MemoryPointer global;
            using MemoryWriters for MemoryPointer global;
            CalldataPointer constant CalldataStart = CalldataPointer.wrap(0x04);
            MemoryPointer constant FreeMemoryPPtr = MemoryPointer.wrap(0x40);
            uint256 constant IdentityPrecompileAddress = 0x4;
            uint256 constant OffsetOrLengthMask = 0xffffffff;
            uint256 constant _OneWord = 0x20;
            uint256 constant _FreeMemoryPointerSlot = 0x40;
            /// @dev Allocates `size` bytes in memory by increasing the free memory pointer
            ///    and returns the memory pointer to the first byte of the allocated region.
            // (Free functions cannot have visibility.)
            // solhint-disable-next-line func-visibility
            function malloc(uint256 size) pure returns (MemoryPointer mPtr) {
                assembly {
                    mPtr := mload(_FreeMemoryPointerSlot)
                    mstore(_FreeMemoryPointerSlot, add(mPtr, size))
                }
            }
            // (Free functions cannot have visibility.)
            // solhint-disable-next-line func-visibility
            function getFreeMemoryPointer() pure returns (MemoryPointer mPtr) {
                mPtr = FreeMemoryPPtr.readMemoryPointer();
            }
            // (Free functions cannot have visibility.)
            // solhint-disable-next-line func-visibility
            function setFreeMemoryPointer(MemoryPointer mPtr) pure {
                FreeMemoryPPtr.write(mPtr);
            }
            library CalldataPointerLib {
                function lt(
                    CalldataPointer a,
                    CalldataPointer b
                ) internal pure returns (bool c) {
                    assembly {
                        c := lt(a, b)
                    }
                }
                function gt(
                    CalldataPointer a,
                    CalldataPointer b
                ) internal pure returns (bool c) {
                    assembly {
                        c := gt(a, b)
                    }
                }
                function eq(
                    CalldataPointer a,
                    CalldataPointer b
                ) internal pure returns (bool c) {
                    assembly {
                        c := eq(a, b)
                    }
                }
                /// @dev Resolves an offset stored at `cdPtr + headOffset` to a calldata.
                ///      pointer `cdPtr` must point to some parent object with a dynamic
                ///      type's head stored at `cdPtr + headOffset`.
                function pptr(
                    CalldataPointer cdPtr,
                    uint256 headOffset
                ) internal pure returns (CalldataPointer cdPtrChild) {
                    cdPtrChild = cdPtr.offset(
                        cdPtr.offset(headOffset).readUint256() & OffsetOrLengthMask
                    );
                }
                /// @dev Resolves an offset stored at `cdPtr` to a calldata pointer.
                ///      `cdPtr` must point to some parent object with a dynamic type as its
                ///      first member, e.g. `struct { bytes data; }`
                function pptr(
                    CalldataPointer cdPtr
                ) internal pure returns (CalldataPointer cdPtrChild) {
                    cdPtrChild = cdPtr.offset(cdPtr.readUint256() & OffsetOrLengthMask);
                }
                /// @dev Returns the calldata pointer one word after `cdPtr`.
                function next(
                    CalldataPointer cdPtr
                ) internal pure returns (CalldataPointer cdPtrNext) {
                    assembly {
                        cdPtrNext := add(cdPtr, _OneWord)
                    }
                }
                /// @dev Returns the calldata pointer `_offset` bytes after `cdPtr`.
                function offset(
                    CalldataPointer cdPtr,
                    uint256 _offset
                ) internal pure returns (CalldataPointer cdPtrNext) {
                    assembly {
                        cdPtrNext := add(cdPtr, _offset)
                    }
                }
                /// @dev Copies `size` bytes from calldata starting at `src` to memory at
                ///      `dst`.
                function copy(
                    CalldataPointer src,
                    MemoryPointer dst,
                    uint256 size
                ) internal pure {
                    assembly {
                        calldatacopy(dst, src, size)
                    }
                }
            }
            library ReturndataPointerLib {
                function lt(
                    ReturndataPointer a,
                    ReturndataPointer b
                ) internal pure returns (bool c) {
                    assembly {
                        c := lt(a, b)
                    }
                }
                function gt(
                    ReturndataPointer a,
                    ReturndataPointer b
                ) internal pure returns (bool c) {
                    assembly {
                        c := gt(a, b)
                    }
                }
                function eq(
                    ReturndataPointer a,
                    ReturndataPointer b
                ) internal pure returns (bool c) {
                    assembly {
                        c := eq(a, b)
                    }
                }
                /// @dev Resolves an offset stored at `rdPtr + headOffset` to a returndata
                ///      pointer. `rdPtr` must point to some parent object with a dynamic
                ///      type's head stored at `rdPtr + headOffset`.
                function pptr(
                    ReturndataPointer rdPtr,
                    uint256 headOffset
                ) internal pure returns (ReturndataPointer rdPtrChild) {
                    rdPtrChild = rdPtr.offset(
                        rdPtr.offset(headOffset).readUint256() & OffsetOrLengthMask
                    );
                }
                /// @dev Resolves an offset stored at `rdPtr` to a returndata pointer.
                ///    `rdPtr` must point to some parent object with a dynamic type as its
                ///    first member, e.g. `struct { bytes data; }`
                function pptr(
                    ReturndataPointer rdPtr
                ) internal pure returns (ReturndataPointer rdPtrChild) {
                    rdPtrChild = rdPtr.offset(rdPtr.readUint256() & OffsetOrLengthMask);
                }
                /// @dev Returns the returndata pointer one word after `cdPtr`.
                function next(
                    ReturndataPointer rdPtr
                ) internal pure returns (ReturndataPointer rdPtrNext) {
                    assembly {
                        rdPtrNext := add(rdPtr, _OneWord)
                    }
                }
                /// @dev Returns the returndata pointer `_offset` bytes after `cdPtr`.
                function offset(
                    ReturndataPointer rdPtr,
                    uint256 _offset
                ) internal pure returns (ReturndataPointer rdPtrNext) {
                    assembly {
                        rdPtrNext := add(rdPtr, _offset)
                    }
                }
                /// @dev Copies `size` bytes from returndata starting at `src` to memory at
                /// `dst`.
                function copy(
                    ReturndataPointer src,
                    MemoryPointer dst,
                    uint256 size
                ) internal pure {
                    assembly {
                        returndatacopy(dst, src, size)
                    }
                }
            }
            library MemoryPointerLib {
                function copy(
                    MemoryPointer src,
                    MemoryPointer dst,
                    uint256 size
                ) internal view {
                    assembly {
                        let success := staticcall(
                            gas(),
                            IdentityPrecompileAddress,
                            src,
                            size,
                            dst,
                            size
                        )
                        if or(iszero(returndatasize()), iszero(success)) {
                            revert(0, 0)
                        }
                    }
                }
                function lt(
                    MemoryPointer a,
                    MemoryPointer b
                ) internal pure returns (bool c) {
                    assembly {
                        c := lt(a, b)
                    }
                }
                function gt(
                    MemoryPointer a,
                    MemoryPointer b
                ) internal pure returns (bool c) {
                    assembly {
                        c := gt(a, b)
                    }
                }
                function eq(
                    MemoryPointer a,
                    MemoryPointer b
                ) internal pure returns (bool c) {
                    assembly {
                        c := eq(a, b)
                    }
                }
                /// @dev Returns the memory pointer one word after `mPtr`.
                function next(
                    MemoryPointer mPtr
                ) internal pure returns (MemoryPointer mPtrNext) {
                    assembly {
                        mPtrNext := add(mPtr, _OneWord)
                    }
                }
                /// @dev Returns the memory pointer `_offset` bytes after `mPtr`.
                function offset(
                    MemoryPointer mPtr,
                    uint256 _offset
                ) internal pure returns (MemoryPointer mPtrNext) {
                    assembly {
                        mPtrNext := add(mPtr, _offset)
                    }
                }
                /// @dev Resolves a pointer pointer at `mPtr + headOffset` to a memory
                ///    pointer. `mPtr` must point to some parent object with a dynamic
                ///    type's pointer stored at `mPtr + headOffset`.
                function pptr(
                    MemoryPointer mPtr,
                    uint256 headOffset
                ) internal pure returns (MemoryPointer mPtrChild) {
                    mPtrChild = mPtr.offset(headOffset).readMemoryPointer();
                }
                /// @dev Resolves a pointer pointer stored at `mPtr` to a memory pointer.
                ///    `mPtr` must point to some parent object with a dynamic type as its
                ///    first member, e.g. `struct { bytes data; }`
                function pptr(
                    MemoryPointer mPtr
                ) internal pure returns (MemoryPointer mPtrChild) {
                    mPtrChild = mPtr.readMemoryPointer();
                }
            }
            library CalldataReaders {
                /// @dev Reads the value at `cdPtr` and applies a mask to return only the
                ///    last 4 bytes.
                function readMaskedUint256(
                    CalldataPointer cdPtr
                ) internal pure returns (uint256 value) {
                    value = cdPtr.readUint256() & OffsetOrLengthMask;
                }
                /// @dev Reads the bool at `cdPtr` in calldata.
                function readBool(
                    CalldataPointer cdPtr
                ) internal pure returns (bool value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the address at `cdPtr` in calldata.
                function readAddress(
                    CalldataPointer cdPtr
                ) internal pure returns (address value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes1 at `cdPtr` in calldata.
                function readBytes1(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes1 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes2 at `cdPtr` in calldata.
                function readBytes2(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes2 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes3 at `cdPtr` in calldata.
                function readBytes3(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes3 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes4 at `cdPtr` in calldata.
                function readBytes4(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes4 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes5 at `cdPtr` in calldata.
                function readBytes5(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes5 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes6 at `cdPtr` in calldata.
                function readBytes6(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes6 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes7 at `cdPtr` in calldata.
                function readBytes7(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes7 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes8 at `cdPtr` in calldata.
                function readBytes8(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes8 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes9 at `cdPtr` in calldata.
                function readBytes9(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes9 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes10 at `cdPtr` in calldata.
                function readBytes10(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes10 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes11 at `cdPtr` in calldata.
                function readBytes11(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes11 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes12 at `cdPtr` in calldata.
                function readBytes12(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes12 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes13 at `cdPtr` in calldata.
                function readBytes13(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes13 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes14 at `cdPtr` in calldata.
                function readBytes14(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes14 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes15 at `cdPtr` in calldata.
                function readBytes15(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes15 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes16 at `cdPtr` in calldata.
                function readBytes16(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes16 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes17 at `cdPtr` in calldata.
                function readBytes17(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes17 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes18 at `cdPtr` in calldata.
                function readBytes18(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes18 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes19 at `cdPtr` in calldata.
                function readBytes19(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes19 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes20 at `cdPtr` in calldata.
                function readBytes20(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes20 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes21 at `cdPtr` in calldata.
                function readBytes21(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes21 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes22 at `cdPtr` in calldata.
                function readBytes22(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes22 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes23 at `cdPtr` in calldata.
                function readBytes23(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes23 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes24 at `cdPtr` in calldata.
                function readBytes24(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes24 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes25 at `cdPtr` in calldata.
                function readBytes25(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes25 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes26 at `cdPtr` in calldata.
                function readBytes26(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes26 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes27 at `cdPtr` in calldata.
                function readBytes27(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes27 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes28 at `cdPtr` in calldata.
                function readBytes28(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes28 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes29 at `cdPtr` in calldata.
                function readBytes29(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes29 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes30 at `cdPtr` in calldata.
                function readBytes30(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes30 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes31 at `cdPtr` in calldata.
                function readBytes31(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes31 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the bytes32 at `cdPtr` in calldata.
                function readBytes32(
                    CalldataPointer cdPtr
                ) internal pure returns (bytes32 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint8 at `cdPtr` in calldata.
                function readUint8(
                    CalldataPointer cdPtr
                ) internal pure returns (uint8 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint16 at `cdPtr` in calldata.
                function readUint16(
                    CalldataPointer cdPtr
                ) internal pure returns (uint16 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint24 at `cdPtr` in calldata.
                function readUint24(
                    CalldataPointer cdPtr
                ) internal pure returns (uint24 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint32 at `cdPtr` in calldata.
                function readUint32(
                    CalldataPointer cdPtr
                ) internal pure returns (uint32 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint40 at `cdPtr` in calldata.
                function readUint40(
                    CalldataPointer cdPtr
                ) internal pure returns (uint40 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint48 at `cdPtr` in calldata.
                function readUint48(
                    CalldataPointer cdPtr
                ) internal pure returns (uint48 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint56 at `cdPtr` in calldata.
                function readUint56(
                    CalldataPointer cdPtr
                ) internal pure returns (uint56 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint64 at `cdPtr` in calldata.
                function readUint64(
                    CalldataPointer cdPtr
                ) internal pure returns (uint64 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint72 at `cdPtr` in calldata.
                function readUint72(
                    CalldataPointer cdPtr
                ) internal pure returns (uint72 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint80 at `cdPtr` in calldata.
                function readUint80(
                    CalldataPointer cdPtr
                ) internal pure returns (uint80 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint88 at `cdPtr` in calldata.
                function readUint88(
                    CalldataPointer cdPtr
                ) internal pure returns (uint88 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint96 at `cdPtr` in calldata.
                function readUint96(
                    CalldataPointer cdPtr
                ) internal pure returns (uint96 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint104 at `cdPtr` in calldata.
                function readUint104(
                    CalldataPointer cdPtr
                ) internal pure returns (uint104 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint112 at `cdPtr` in calldata.
                function readUint112(
                    CalldataPointer cdPtr
                ) internal pure returns (uint112 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint120 at `cdPtr` in calldata.
                function readUint120(
                    CalldataPointer cdPtr
                ) internal pure returns (uint120 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint128 at `cdPtr` in calldata.
                function readUint128(
                    CalldataPointer cdPtr
                ) internal pure returns (uint128 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint136 at `cdPtr` in calldata.
                function readUint136(
                    CalldataPointer cdPtr
                ) internal pure returns (uint136 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint144 at `cdPtr` in calldata.
                function readUint144(
                    CalldataPointer cdPtr
                ) internal pure returns (uint144 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint152 at `cdPtr` in calldata.
                function readUint152(
                    CalldataPointer cdPtr
                ) internal pure returns (uint152 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint160 at `cdPtr` in calldata.
                function readUint160(
                    CalldataPointer cdPtr
                ) internal pure returns (uint160 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint168 at `cdPtr` in calldata.
                function readUint168(
                    CalldataPointer cdPtr
                ) internal pure returns (uint168 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint176 at `cdPtr` in calldata.
                function readUint176(
                    CalldataPointer cdPtr
                ) internal pure returns (uint176 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint184 at `cdPtr` in calldata.
                function readUint184(
                    CalldataPointer cdPtr
                ) internal pure returns (uint184 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint192 at `cdPtr` in calldata.
                function readUint192(
                    CalldataPointer cdPtr
                ) internal pure returns (uint192 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint200 at `cdPtr` in calldata.
                function readUint200(
                    CalldataPointer cdPtr
                ) internal pure returns (uint200 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint208 at `cdPtr` in calldata.
                function readUint208(
                    CalldataPointer cdPtr
                ) internal pure returns (uint208 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint216 at `cdPtr` in calldata.
                function readUint216(
                    CalldataPointer cdPtr
                ) internal pure returns (uint216 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint224 at `cdPtr` in calldata.
                function readUint224(
                    CalldataPointer cdPtr
                ) internal pure returns (uint224 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint232 at `cdPtr` in calldata.
                function readUint232(
                    CalldataPointer cdPtr
                ) internal pure returns (uint232 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint240 at `cdPtr` in calldata.
                function readUint240(
                    CalldataPointer cdPtr
                ) internal pure returns (uint240 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint248 at `cdPtr` in calldata.
                function readUint248(
                    CalldataPointer cdPtr
                ) internal pure returns (uint248 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the uint256 at `cdPtr` in calldata.
                function readUint256(
                    CalldataPointer cdPtr
                ) internal pure returns (uint256 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int8 at `cdPtr` in calldata.
                function readInt8(
                    CalldataPointer cdPtr
                ) internal pure returns (int8 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int16 at `cdPtr` in calldata.
                function readInt16(
                    CalldataPointer cdPtr
                ) internal pure returns (int16 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int24 at `cdPtr` in calldata.
                function readInt24(
                    CalldataPointer cdPtr
                ) internal pure returns (int24 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int32 at `cdPtr` in calldata.
                function readInt32(
                    CalldataPointer cdPtr
                ) internal pure returns (int32 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int40 at `cdPtr` in calldata.
                function readInt40(
                    CalldataPointer cdPtr
                ) internal pure returns (int40 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int48 at `cdPtr` in calldata.
                function readInt48(
                    CalldataPointer cdPtr
                ) internal pure returns (int48 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int56 at `cdPtr` in calldata.
                function readInt56(
                    CalldataPointer cdPtr
                ) internal pure returns (int56 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int64 at `cdPtr` in calldata.
                function readInt64(
                    CalldataPointer cdPtr
                ) internal pure returns (int64 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int72 at `cdPtr` in calldata.
                function readInt72(
                    CalldataPointer cdPtr
                ) internal pure returns (int72 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int80 at `cdPtr` in calldata.
                function readInt80(
                    CalldataPointer cdPtr
                ) internal pure returns (int80 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int88 at `cdPtr` in calldata.
                function readInt88(
                    CalldataPointer cdPtr
                ) internal pure returns (int88 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int96 at `cdPtr` in calldata.
                function readInt96(
                    CalldataPointer cdPtr
                ) internal pure returns (int96 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int104 at `cdPtr` in calldata.
                function readInt104(
                    CalldataPointer cdPtr
                ) internal pure returns (int104 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int112 at `cdPtr` in calldata.
                function readInt112(
                    CalldataPointer cdPtr
                ) internal pure returns (int112 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int120 at `cdPtr` in calldata.
                function readInt120(
                    CalldataPointer cdPtr
                ) internal pure returns (int120 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int128 at `cdPtr` in calldata.
                function readInt128(
                    CalldataPointer cdPtr
                ) internal pure returns (int128 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int136 at `cdPtr` in calldata.
                function readInt136(
                    CalldataPointer cdPtr
                ) internal pure returns (int136 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int144 at `cdPtr` in calldata.
                function readInt144(
                    CalldataPointer cdPtr
                ) internal pure returns (int144 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int152 at `cdPtr` in calldata.
                function readInt152(
                    CalldataPointer cdPtr
                ) internal pure returns (int152 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int160 at `cdPtr` in calldata.
                function readInt160(
                    CalldataPointer cdPtr
                ) internal pure returns (int160 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int168 at `cdPtr` in calldata.
                function readInt168(
                    CalldataPointer cdPtr
                ) internal pure returns (int168 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int176 at `cdPtr` in calldata.
                function readInt176(
                    CalldataPointer cdPtr
                ) internal pure returns (int176 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int184 at `cdPtr` in calldata.
                function readInt184(
                    CalldataPointer cdPtr
                ) internal pure returns (int184 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int192 at `cdPtr` in calldata.
                function readInt192(
                    CalldataPointer cdPtr
                ) internal pure returns (int192 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int200 at `cdPtr` in calldata.
                function readInt200(
                    CalldataPointer cdPtr
                ) internal pure returns (int200 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int208 at `cdPtr` in calldata.
                function readInt208(
                    CalldataPointer cdPtr
                ) internal pure returns (int208 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int216 at `cdPtr` in calldata.
                function readInt216(
                    CalldataPointer cdPtr
                ) internal pure returns (int216 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int224 at `cdPtr` in calldata.
                function readInt224(
                    CalldataPointer cdPtr
                ) internal pure returns (int224 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int232 at `cdPtr` in calldata.
                function readInt232(
                    CalldataPointer cdPtr
                ) internal pure returns (int232 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int240 at `cdPtr` in calldata.
                function readInt240(
                    CalldataPointer cdPtr
                ) internal pure returns (int240 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int248 at `cdPtr` in calldata.
                function readInt248(
                    CalldataPointer cdPtr
                ) internal pure returns (int248 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
                /// @dev Reads the int256 at `cdPtr` in calldata.
                function readInt256(
                    CalldataPointer cdPtr
                ) internal pure returns (int256 value) {
                    assembly {
                        value := calldataload(cdPtr)
                    }
                }
            }
            library ReturndataReaders {
                /// @dev Reads value at `rdPtr` & applies a mask to return only last 4 bytes
                function readMaskedUint256(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint256 value) {
                    value = rdPtr.readUint256() & OffsetOrLengthMask;
                }
                /// @dev Reads the bool at `rdPtr` in returndata.
                function readBool(
                    ReturndataPointer rdPtr
                ) internal pure returns (bool value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the address at `rdPtr` in returndata.
                function readAddress(
                    ReturndataPointer rdPtr
                ) internal pure returns (address value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes1 at `rdPtr` in returndata.
                function readBytes1(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes1 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes2 at `rdPtr` in returndata.
                function readBytes2(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes2 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes3 at `rdPtr` in returndata.
                function readBytes3(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes3 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes4 at `rdPtr` in returndata.
                function readBytes4(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes4 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes5 at `rdPtr` in returndata.
                function readBytes5(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes5 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes6 at `rdPtr` in returndata.
                function readBytes6(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes6 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes7 at `rdPtr` in returndata.
                function readBytes7(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes7 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes8 at `rdPtr` in returndata.
                function readBytes8(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes8 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes9 at `rdPtr` in returndata.
                function readBytes9(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes9 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes10 at `rdPtr` in returndata.
                function readBytes10(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes10 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes11 at `rdPtr` in returndata.
                function readBytes11(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes11 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes12 at `rdPtr` in returndata.
                function readBytes12(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes12 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes13 at `rdPtr` in returndata.
                function readBytes13(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes13 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes14 at `rdPtr` in returndata.
                function readBytes14(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes14 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes15 at `rdPtr` in returndata.
                function readBytes15(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes15 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes16 at `rdPtr` in returndata.
                function readBytes16(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes16 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes17 at `rdPtr` in returndata.
                function readBytes17(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes17 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes18 at `rdPtr` in returndata.
                function readBytes18(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes18 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes19 at `rdPtr` in returndata.
                function readBytes19(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes19 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes20 at `rdPtr` in returndata.
                function readBytes20(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes20 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes21 at `rdPtr` in returndata.
                function readBytes21(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes21 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes22 at `rdPtr` in returndata.
                function readBytes22(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes22 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes23 at `rdPtr` in returndata.
                function readBytes23(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes23 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes24 at `rdPtr` in returndata.
                function readBytes24(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes24 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes25 at `rdPtr` in returndata.
                function readBytes25(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes25 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes26 at `rdPtr` in returndata.
                function readBytes26(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes26 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes27 at `rdPtr` in returndata.
                function readBytes27(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes27 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes28 at `rdPtr` in returndata.
                function readBytes28(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes28 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes29 at `rdPtr` in returndata.
                function readBytes29(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes29 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes30 at `rdPtr` in returndata.
                function readBytes30(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes30 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes31 at `rdPtr` in returndata.
                function readBytes31(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes31 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the bytes32 at `rdPtr` in returndata.
                function readBytes32(
                    ReturndataPointer rdPtr
                ) internal pure returns (bytes32 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint8 at `rdPtr` in returndata.
                function readUint8(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint8 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint16 at `rdPtr` in returndata.
                function readUint16(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint16 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint24 at `rdPtr` in returndata.
                function readUint24(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint24 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint32 at `rdPtr` in returndata.
                function readUint32(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint32 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint40 at `rdPtr` in returndata.
                function readUint40(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint40 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint48 at `rdPtr` in returndata.
                function readUint48(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint48 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint56 at `rdPtr` in returndata.
                function readUint56(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint56 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint64 at `rdPtr` in returndata.
                function readUint64(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint64 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint72 at `rdPtr` in returndata.
                function readUint72(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint72 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint80 at `rdPtr` in returndata.
                function readUint80(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint80 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint88 at `rdPtr` in returndata.
                function readUint88(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint88 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint96 at `rdPtr` in returndata.
                function readUint96(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint96 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint104 at `rdPtr` in returndata.
                function readUint104(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint104 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint112 at `rdPtr` in returndata.
                function readUint112(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint112 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint120 at `rdPtr` in returndata.
                function readUint120(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint120 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint128 at `rdPtr` in returndata.
                function readUint128(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint128 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint136 at `rdPtr` in returndata.
                function readUint136(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint136 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint144 at `rdPtr` in returndata.
                function readUint144(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint144 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint152 at `rdPtr` in returndata.
                function readUint152(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint152 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint160 at `rdPtr` in returndata.
                function readUint160(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint160 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint168 at `rdPtr` in returndata.
                function readUint168(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint168 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint176 at `rdPtr` in returndata.
                function readUint176(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint176 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint184 at `rdPtr` in returndata.
                function readUint184(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint184 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint192 at `rdPtr` in returndata.
                function readUint192(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint192 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint200 at `rdPtr` in returndata.
                function readUint200(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint200 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint208 at `rdPtr` in returndata.
                function readUint208(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint208 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint216 at `rdPtr` in returndata.
                function readUint216(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint216 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint224 at `rdPtr` in returndata.
                function readUint224(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint224 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint232 at `rdPtr` in returndata.
                function readUint232(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint232 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint240 at `rdPtr` in returndata.
                function readUint240(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint240 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint248 at `rdPtr` in returndata.
                function readUint248(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint248 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the uint256 at `rdPtr` in returndata.
                function readUint256(
                    ReturndataPointer rdPtr
                ) internal pure returns (uint256 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int8 at `rdPtr` in returndata.
                function readInt8(
                    ReturndataPointer rdPtr
                ) internal pure returns (int8 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int16 at `rdPtr` in returndata.
                function readInt16(
                    ReturndataPointer rdPtr
                ) internal pure returns (int16 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int24 at `rdPtr` in returndata.
                function readInt24(
                    ReturndataPointer rdPtr
                ) internal pure returns (int24 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int32 at `rdPtr` in returndata.
                function readInt32(
                    ReturndataPointer rdPtr
                ) internal pure returns (int32 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int40 at `rdPtr` in returndata.
                function readInt40(
                    ReturndataPointer rdPtr
                ) internal pure returns (int40 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int48 at `rdPtr` in returndata.
                function readInt48(
                    ReturndataPointer rdPtr
                ) internal pure returns (int48 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int56 at `rdPtr` in returndata.
                function readInt56(
                    ReturndataPointer rdPtr
                ) internal pure returns (int56 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int64 at `rdPtr` in returndata.
                function readInt64(
                    ReturndataPointer rdPtr
                ) internal pure returns (int64 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int72 at `rdPtr` in returndata.
                function readInt72(
                    ReturndataPointer rdPtr
                ) internal pure returns (int72 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int80 at `rdPtr` in returndata.
                function readInt80(
                    ReturndataPointer rdPtr
                ) internal pure returns (int80 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int88 at `rdPtr` in returndata.
                function readInt88(
                    ReturndataPointer rdPtr
                ) internal pure returns (int88 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int96 at `rdPtr` in returndata.
                function readInt96(
                    ReturndataPointer rdPtr
                ) internal pure returns (int96 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int104 at `rdPtr` in returndata.
                function readInt104(
                    ReturndataPointer rdPtr
                ) internal pure returns (int104 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int112 at `rdPtr` in returndata.
                function readInt112(
                    ReturndataPointer rdPtr
                ) internal pure returns (int112 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int120 at `rdPtr` in returndata.
                function readInt120(
                    ReturndataPointer rdPtr
                ) internal pure returns (int120 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int128 at `rdPtr` in returndata.
                function readInt128(
                    ReturndataPointer rdPtr
                ) internal pure returns (int128 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int136 at `rdPtr` in returndata.
                function readInt136(
                    ReturndataPointer rdPtr
                ) internal pure returns (int136 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int144 at `rdPtr` in returndata.
                function readInt144(
                    ReturndataPointer rdPtr
                ) internal pure returns (int144 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int152 at `rdPtr` in returndata.
                function readInt152(
                    ReturndataPointer rdPtr
                ) internal pure returns (int152 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int160 at `rdPtr` in returndata.
                function readInt160(
                    ReturndataPointer rdPtr
                ) internal pure returns (int160 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int168 at `rdPtr` in returndata.
                function readInt168(
                    ReturndataPointer rdPtr
                ) internal pure returns (int168 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int176 at `rdPtr` in returndata.
                function readInt176(
                    ReturndataPointer rdPtr
                ) internal pure returns (int176 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int184 at `rdPtr` in returndata.
                function readInt184(
                    ReturndataPointer rdPtr
                ) internal pure returns (int184 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int192 at `rdPtr` in returndata.
                function readInt192(
                    ReturndataPointer rdPtr
                ) internal pure returns (int192 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int200 at `rdPtr` in returndata.
                function readInt200(
                    ReturndataPointer rdPtr
                ) internal pure returns (int200 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int208 at `rdPtr` in returndata.
                function readInt208(
                    ReturndataPointer rdPtr
                ) internal pure returns (int208 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int216 at `rdPtr` in returndata.
                function readInt216(
                    ReturndataPointer rdPtr
                ) internal pure returns (int216 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int224 at `rdPtr` in returndata.
                function readInt224(
                    ReturndataPointer rdPtr
                ) internal pure returns (int224 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int232 at `rdPtr` in returndata.
                function readInt232(
                    ReturndataPointer rdPtr
                ) internal pure returns (int232 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int240 at `rdPtr` in returndata.
                function readInt240(
                    ReturndataPointer rdPtr
                ) internal pure returns (int240 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int248 at `rdPtr` in returndata.
                function readInt248(
                    ReturndataPointer rdPtr
                ) internal pure returns (int248 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
                /// @dev Reads the int256 at `rdPtr` in returndata.
                function readInt256(
                    ReturndataPointer rdPtr
                ) internal pure returns (int256 value) {
                    assembly {
                        returndatacopy(0, rdPtr, _OneWord)
                        value := mload(0)
                    }
                }
            }
            library MemoryReaders {
                /// @dev Reads the memory pointer at `mPtr` in memory.
                function readMemoryPointer(
                    MemoryPointer mPtr
                ) internal pure returns (MemoryPointer value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads value at `mPtr` & applies a mask to return only last 4 bytes
                function readMaskedUint256(
                    MemoryPointer mPtr
                ) internal pure returns (uint256 value) {
                    value = mPtr.readUint256() & OffsetOrLengthMask;
                }
                /// @dev Reads the bool at `mPtr` in memory.
                function readBool(MemoryPointer mPtr) internal pure returns (bool value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the address at `mPtr` in memory.
                function readAddress(
                    MemoryPointer mPtr
                ) internal pure returns (address value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes1 at `mPtr` in memory.
                function readBytes1(
                    MemoryPointer mPtr
                ) internal pure returns (bytes1 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes2 at `mPtr` in memory.
                function readBytes2(
                    MemoryPointer mPtr
                ) internal pure returns (bytes2 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes3 at `mPtr` in memory.
                function readBytes3(
                    MemoryPointer mPtr
                ) internal pure returns (bytes3 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes4 at `mPtr` in memory.
                function readBytes4(
                    MemoryPointer mPtr
                ) internal pure returns (bytes4 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes5 at `mPtr` in memory.
                function readBytes5(
                    MemoryPointer mPtr
                ) internal pure returns (bytes5 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes6 at `mPtr` in memory.
                function readBytes6(
                    MemoryPointer mPtr
                ) internal pure returns (bytes6 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes7 at `mPtr` in memory.
                function readBytes7(
                    MemoryPointer mPtr
                ) internal pure returns (bytes7 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes8 at `mPtr` in memory.
                function readBytes8(
                    MemoryPointer mPtr
                ) internal pure returns (bytes8 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes9 at `mPtr` in memory.
                function readBytes9(
                    MemoryPointer mPtr
                ) internal pure returns (bytes9 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes10 at `mPtr` in memory.
                function readBytes10(
                    MemoryPointer mPtr
                ) internal pure returns (bytes10 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes11 at `mPtr` in memory.
                function readBytes11(
                    MemoryPointer mPtr
                ) internal pure returns (bytes11 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes12 at `mPtr` in memory.
                function readBytes12(
                    MemoryPointer mPtr
                ) internal pure returns (bytes12 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes13 at `mPtr` in memory.
                function readBytes13(
                    MemoryPointer mPtr
                ) internal pure returns (bytes13 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes14 at `mPtr` in memory.
                function readBytes14(
                    MemoryPointer mPtr
                ) internal pure returns (bytes14 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes15 at `mPtr` in memory.
                function readBytes15(
                    MemoryPointer mPtr
                ) internal pure returns (bytes15 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes16 at `mPtr` in memory.
                function readBytes16(
                    MemoryPointer mPtr
                ) internal pure returns (bytes16 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes17 at `mPtr` in memory.
                function readBytes17(
                    MemoryPointer mPtr
                ) internal pure returns (bytes17 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes18 at `mPtr` in memory.
                function readBytes18(
                    MemoryPointer mPtr
                ) internal pure returns (bytes18 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes19 at `mPtr` in memory.
                function readBytes19(
                    MemoryPointer mPtr
                ) internal pure returns (bytes19 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes20 at `mPtr` in memory.
                function readBytes20(
                    MemoryPointer mPtr
                ) internal pure returns (bytes20 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes21 at `mPtr` in memory.
                function readBytes21(
                    MemoryPointer mPtr
                ) internal pure returns (bytes21 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes22 at `mPtr` in memory.
                function readBytes22(
                    MemoryPointer mPtr
                ) internal pure returns (bytes22 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes23 at `mPtr` in memory.
                function readBytes23(
                    MemoryPointer mPtr
                ) internal pure returns (bytes23 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes24 at `mPtr` in memory.
                function readBytes24(
                    MemoryPointer mPtr
                ) internal pure returns (bytes24 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes25 at `mPtr` in memory.
                function readBytes25(
                    MemoryPointer mPtr
                ) internal pure returns (bytes25 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes26 at `mPtr` in memory.
                function readBytes26(
                    MemoryPointer mPtr
                ) internal pure returns (bytes26 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes27 at `mPtr` in memory.
                function readBytes27(
                    MemoryPointer mPtr
                ) internal pure returns (bytes27 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes28 at `mPtr` in memory.
                function readBytes28(
                    MemoryPointer mPtr
                ) internal pure returns (bytes28 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes29 at `mPtr` in memory.
                function readBytes29(
                    MemoryPointer mPtr
                ) internal pure returns (bytes29 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes30 at `mPtr` in memory.
                function readBytes30(
                    MemoryPointer mPtr
                ) internal pure returns (bytes30 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes31 at `mPtr` in memory.
                function readBytes31(
                    MemoryPointer mPtr
                ) internal pure returns (bytes31 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the bytes32 at `mPtr` in memory.
                function readBytes32(
                    MemoryPointer mPtr
                ) internal pure returns (bytes32 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint8 at `mPtr` in memory.
                function readUint8(MemoryPointer mPtr) internal pure returns (uint8 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint16 at `mPtr` in memory.
                function readUint16(
                    MemoryPointer mPtr
                ) internal pure returns (uint16 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint24 at `mPtr` in memory.
                function readUint24(
                    MemoryPointer mPtr
                ) internal pure returns (uint24 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint32 at `mPtr` in memory.
                function readUint32(
                    MemoryPointer mPtr
                ) internal pure returns (uint32 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint40 at `mPtr` in memory.
                function readUint40(
                    MemoryPointer mPtr
                ) internal pure returns (uint40 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint48 at `mPtr` in memory.
                function readUint48(
                    MemoryPointer mPtr
                ) internal pure returns (uint48 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint56 at `mPtr` in memory.
                function readUint56(
                    MemoryPointer mPtr
                ) internal pure returns (uint56 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint64 at `mPtr` in memory.
                function readUint64(
                    MemoryPointer mPtr
                ) internal pure returns (uint64 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint72 at `mPtr` in memory.
                function readUint72(
                    MemoryPointer mPtr
                ) internal pure returns (uint72 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint80 at `mPtr` in memory.
                function readUint80(
                    MemoryPointer mPtr
                ) internal pure returns (uint80 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint88 at `mPtr` in memory.
                function readUint88(
                    MemoryPointer mPtr
                ) internal pure returns (uint88 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint96 at `mPtr` in memory.
                function readUint96(
                    MemoryPointer mPtr
                ) internal pure returns (uint96 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint104 at `mPtr` in memory.
                function readUint104(
                    MemoryPointer mPtr
                ) internal pure returns (uint104 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint112 at `mPtr` in memory.
                function readUint112(
                    MemoryPointer mPtr
                ) internal pure returns (uint112 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint120 at `mPtr` in memory.
                function readUint120(
                    MemoryPointer mPtr
                ) internal pure returns (uint120 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint128 at `mPtr` in memory.
                function readUint128(
                    MemoryPointer mPtr
                ) internal pure returns (uint128 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint136 at `mPtr` in memory.
                function readUint136(
                    MemoryPointer mPtr
                ) internal pure returns (uint136 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint144 at `mPtr` in memory.
                function readUint144(
                    MemoryPointer mPtr
                ) internal pure returns (uint144 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint152 at `mPtr` in memory.
                function readUint152(
                    MemoryPointer mPtr
                ) internal pure returns (uint152 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint160 at `mPtr` in memory.
                function readUint160(
                    MemoryPointer mPtr
                ) internal pure returns (uint160 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint168 at `mPtr` in memory.
                function readUint168(
                    MemoryPointer mPtr
                ) internal pure returns (uint168 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint176 at `mPtr` in memory.
                function readUint176(
                    MemoryPointer mPtr
                ) internal pure returns (uint176 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint184 at `mPtr` in memory.
                function readUint184(
                    MemoryPointer mPtr
                ) internal pure returns (uint184 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint192 at `mPtr` in memory.
                function readUint192(
                    MemoryPointer mPtr
                ) internal pure returns (uint192 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint200 at `mPtr` in memory.
                function readUint200(
                    MemoryPointer mPtr
                ) internal pure returns (uint200 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint208 at `mPtr` in memory.
                function readUint208(
                    MemoryPointer mPtr
                ) internal pure returns (uint208 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint216 at `mPtr` in memory.
                function readUint216(
                    MemoryPointer mPtr
                ) internal pure returns (uint216 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint224 at `mPtr` in memory.
                function readUint224(
                    MemoryPointer mPtr
                ) internal pure returns (uint224 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint232 at `mPtr` in memory.
                function readUint232(
                    MemoryPointer mPtr
                ) internal pure returns (uint232 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint240 at `mPtr` in memory.
                function readUint240(
                    MemoryPointer mPtr
                ) internal pure returns (uint240 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint248 at `mPtr` in memory.
                function readUint248(
                    MemoryPointer mPtr
                ) internal pure returns (uint248 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the uint256 at `mPtr` in memory.
                function readUint256(
                    MemoryPointer mPtr
                ) internal pure returns (uint256 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int8 at `mPtr` in memory.
                function readInt8(MemoryPointer mPtr) internal pure returns (int8 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int16 at `mPtr` in memory.
                function readInt16(MemoryPointer mPtr) internal pure returns (int16 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int24 at `mPtr` in memory.
                function readInt24(MemoryPointer mPtr) internal pure returns (int24 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int32 at `mPtr` in memory.
                function readInt32(MemoryPointer mPtr) internal pure returns (int32 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int40 at `mPtr` in memory.
                function readInt40(MemoryPointer mPtr) internal pure returns (int40 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int48 at `mPtr` in memory.
                function readInt48(MemoryPointer mPtr) internal pure returns (int48 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int56 at `mPtr` in memory.
                function readInt56(MemoryPointer mPtr) internal pure returns (int56 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int64 at `mPtr` in memory.
                function readInt64(MemoryPointer mPtr) internal pure returns (int64 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int72 at `mPtr` in memory.
                function readInt72(MemoryPointer mPtr) internal pure returns (int72 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int80 at `mPtr` in memory.
                function readInt80(MemoryPointer mPtr) internal pure returns (int80 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int88 at `mPtr` in memory.
                function readInt88(MemoryPointer mPtr) internal pure returns (int88 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int96 at `mPtr` in memory.
                function readInt96(MemoryPointer mPtr) internal pure returns (int96 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int104 at `mPtr` in memory.
                function readInt104(
                    MemoryPointer mPtr
                ) internal pure returns (int104 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int112 at `mPtr` in memory.
                function readInt112(
                    MemoryPointer mPtr
                ) internal pure returns (int112 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int120 at `mPtr` in memory.
                function readInt120(
                    MemoryPointer mPtr
                ) internal pure returns (int120 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int128 at `mPtr` in memory.
                function readInt128(
                    MemoryPointer mPtr
                ) internal pure returns (int128 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int136 at `mPtr` in memory.
                function readInt136(
                    MemoryPointer mPtr
                ) internal pure returns (int136 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int144 at `mPtr` in memory.
                function readInt144(
                    MemoryPointer mPtr
                ) internal pure returns (int144 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int152 at `mPtr` in memory.
                function readInt152(
                    MemoryPointer mPtr
                ) internal pure returns (int152 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int160 at `mPtr` in memory.
                function readInt160(
                    MemoryPointer mPtr
                ) internal pure returns (int160 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int168 at `mPtr` in memory.
                function readInt168(
                    MemoryPointer mPtr
                ) internal pure returns (int168 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int176 at `mPtr` in memory.
                function readInt176(
                    MemoryPointer mPtr
                ) internal pure returns (int176 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int184 at `mPtr` in memory.
                function readInt184(
                    MemoryPointer mPtr
                ) internal pure returns (int184 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int192 at `mPtr` in memory.
                function readInt192(
                    MemoryPointer mPtr
                ) internal pure returns (int192 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int200 at `mPtr` in memory.
                function readInt200(
                    MemoryPointer mPtr
                ) internal pure returns (int200 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int208 at `mPtr` in memory.
                function readInt208(
                    MemoryPointer mPtr
                ) internal pure returns (int208 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int216 at `mPtr` in memory.
                function readInt216(
                    MemoryPointer mPtr
                ) internal pure returns (int216 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int224 at `mPtr` in memory.
                function readInt224(
                    MemoryPointer mPtr
                ) internal pure returns (int224 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int232 at `mPtr` in memory.
                function readInt232(
                    MemoryPointer mPtr
                ) internal pure returns (int232 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int240 at `mPtr` in memory.
                function readInt240(
                    MemoryPointer mPtr
                ) internal pure returns (int240 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int248 at `mPtr` in memory.
                function readInt248(
                    MemoryPointer mPtr
                ) internal pure returns (int248 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
                /// @dev Reads the int256 at `mPtr` in memory.
                function readInt256(
                    MemoryPointer mPtr
                ) internal pure returns (int256 value) {
                    assembly {
                        value := mload(mPtr)
                    }
                }
            }
            library MemoryWriters {
                /// @dev Writes `valuePtr` to memory at `mPtr`.
                function write(MemoryPointer mPtr, MemoryPointer valuePtr) internal pure {
                    assembly {
                        mstore(mPtr, valuePtr)
                    }
                }
                /// @dev Writes a boolean `value` to `mPtr` in memory.
                function write(MemoryPointer mPtr, bool value) internal pure {
                    assembly {
                        mstore(mPtr, value)
                    }
                }
                /// @dev Writes an address `value` to `mPtr` in memory.
                function write(MemoryPointer mPtr, address value) internal pure {
                    assembly {
                        mstore(mPtr, value)
                    }
                }
                /// @dev Writes a bytes32 `value` to `mPtr` in memory.
                /// Separate name to disambiguate literal write parameters.
                function writeBytes32(MemoryPointer mPtr, bytes32 value) internal pure {
                    assembly {
                        mstore(mPtr, value)
                    }
                }
                /// @dev Writes a uint256 `value` to `mPtr` in memory.
                function write(MemoryPointer mPtr, uint256 value) internal pure {
                    assembly {
                        mstore(mPtr, value)
                    }
                }
                /// @dev Writes an int256 `value` to `mPtr` in memory.
                /// Separate name to disambiguate literal write parameters.
                function writeInt(MemoryPointer mPtr, int256 value) internal pure {
                    assembly {
                        mstore(mPtr, value)
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            /*
             * -------------------------- Disambiguation & Other Notes ---------------------
             *    - The term "head" is used as it is in the documentation for ABI encoding,
             *      but only in reference to dynamic types, i.e. it always refers to the
             *      offset or pointer to the body of a dynamic type. In calldata, the head
             *      is always an offset (relative to the parent object), while in memory,
             *      the head is always the pointer to the body. More information found here:
             *      https://docs.soliditylang.org/en/v0.8.17/abi-spec.html#argument-encoding
             *        - Note that the length of an array is separate from and precedes the
             *          head of the array.
             *
             *    - The term "body" is used in place of the term "head" used in the ABI
             *      documentation. It refers to the start of the data for a dynamic type,
             *      e.g. the first word of a struct or the first word of the first element
             *      in an array.
             *
             *    - The term "pointer" is used to describe the absolute position of a value
             *      and never an offset relative to another value.
             *        - The suffix "_ptr" refers to a memory pointer.
             *        - The suffix "_cdPtr" refers to a calldata pointer.
             *
             *    - The term "offset" is used to describe the position of a value relative
             *      to some parent value. For example, OrderParameters_conduit_offset is the
             *      offset to the "conduit" value in the OrderParameters struct relative to
             *      the start of the body.
             *        - Note: Offsets are used to derive pointers.
             *
             *    - Some structs have pointers defined for all of their fields in this file.
             *      Lines which are commented out are fields that are not used in the
             *      codebase but have been left in for readability.
             */
            // Declare constants for name, version, and reentrancy sentinel values.
            // Name is right padded, so it touches the length which is left padded. This
            // enables writing both values at once. Length goes at byte 95 in memory, and
            // name fills bytes 96-109, so both values can be written left-padded to 77.
            uint256 constant NameLengthPtr = 0x4D;
            uint256 constant NameWithLength = 0x0d436F6E73696465726174696F6E;
            uint256 constant information_version_offset = 0;
            uint256 constant information_version_cd_offset = 0x60;
            uint256 constant information_domainSeparator_offset = 0x20;
            uint256 constant information_conduitController_offset = 0x40;
            uint256 constant information_versionLengthPtr = 0x63;
            uint256 constant information_versionWithLength = 0x03312e34; // 1.4
            uint256 constant information_length = 0xa0;
            uint256 constant _NOT_ENTERED = 1;
            uint256 constant _ENTERED = 2;
            uint256 constant _ENTERED_AND_ACCEPTING_NATIVE_TOKENS = 3;
            uint256 constant Offset_fulfillAdvancedOrder_criteriaResolvers = 0x20;
            uint256 constant Offset_fulfillAvailableOrders_offerFulfillments = 0x20;
            uint256 constant Offset_fulfillAvailableOrders_considerationFulfillments = 0x40;
            uint256 constant Offset_fulfillAvailableAdvancedOrders_criteriaResolvers = 0x20;
            uint256 constant Offset_fulfillAvailableAdvancedOrders_offerFulfillments = 0x40;
            uint256 constant Offset_fulfillAvailableAdvancedOrders_cnsdrationFlflmnts = (
                0x60
            );
            uint256 constant Offset_matchOrders_fulfillments = 0x20;
            uint256 constant Offset_matchAdvancedOrders_criteriaResolvers = 0x20;
            uint256 constant Offset_matchAdvancedOrders_fulfillments = 0x40;
            // Common Offsets
            // Offsets for identically positioned fields shared by:
            // OfferItem, ConsiderationItem, SpentItem, ReceivedItem
            uint256 constant Selector_length = 0x4;
            uint256 constant Common_token_offset = 0x20;
            uint256 constant Common_identifier_offset = 0x40;
            uint256 constant Common_amount_offset = 0x60;
            uint256 constant Common_endAmount_offset = 0x80;
            uint256 constant SpentItem_size = 0x80;
            uint256 constant SpentItem_size_shift = 0x7;
            uint256 constant OfferItem_size = 0xa0;
            uint256 constant OfferItem_size_with_length = 0xc0;
            uint256 constant ReceivedItem_size_excluding_recipient = 0x80;
            uint256 constant ReceivedItem_size = 0xa0;
            uint256 constant ReceivedItem_amount_offset = 0x60;
            uint256 constant ReceivedItem_recipient_offset = 0x80;
            uint256 constant ReceivedItem_CommonParams_size = 0x60;
            uint256 constant ConsiderationItem_size = 0xc0;
            uint256 constant ConsiderationItem_size_with_length = 0xe0;
            uint256 constant ConsiderationItem_recipient_offset = 0xa0;
            // Store the same constant in an abbreviated format for a line length fix.
            uint256 constant ConsiderItem_recipient_offset = 0xa0;
            uint256 constant Execution_offerer_offset = 0x20;
            uint256 constant Execution_conduit_offset = 0x40;
            // uint256 constant OrderParameters_offerer_offset = 0x00;
            uint256 constant OrderParameters_zone_offset = 0x20;
            uint256 constant OrderParameters_offer_head_offset = 0x40;
            uint256 constant OrderParameters_consideration_head_offset = 0x60;
            // uint256 constant OrderParameters_orderType_offset = 0x80;
            uint256 constant OrderParameters_startTime_offset = 0xa0;
            uint256 constant OrderParameters_endTime_offset = 0xc0;
            uint256 constant OrderParameters_zoneHash_offset = 0xe0;
            // uint256 constant OrderParameters_salt_offset = 0x100;
            uint256 constant OrderParameters_conduit_offset = 0x120;
            uint256 constant OrderParameters_counter_offset = 0x140;
            uint256 constant Fulfillment_itemIndex_offset = 0x20;
            uint256 constant AdvancedOrder_head_size = 0xa0;
            uint256 constant AdvancedOrder_numerator_offset = 0x20;
            uint256 constant AdvancedOrder_denominator_offset = 0x40;
            uint256 constant AdvancedOrder_signature_offset = 0x60;
            uint256 constant AdvancedOrder_extraData_offset = 0x80;
            uint256 constant OrderStatus_ValidatedAndNotCancelled = 1;
            uint256 constant OrderStatus_filledNumerator_offset = 0x10;
            uint256 constant OrderStatus_filledDenominator_offset = 0x88;
            uint256 constant ThirtyOneBytes = 0x1f;
            uint256 constant OneWord = 0x20;
            uint256 constant TwoWords = 0x40;
            uint256 constant ThreeWords = 0x60;
            uint256 constant FourWords = 0x80;
            uint256 constant FiveWords = 0xa0;
            uint256 constant OneWordShift = 0x5;
            uint256 constant TwoWordsShift = 0x6;
            uint256 constant SixtyThreeBytes = 0x3f;
            uint256 constant OnlyFullWordMask = 0xffffffe0;
            uint256 constant FreeMemoryPointerSlot = 0x40;
            uint256 constant ZeroSlot = 0x60;
            uint256 constant DefaultFreeMemoryPointer = 0x80;
            uint256 constant Slot0x80 = 0x80;
            uint256 constant Slot0xA0 = 0xa0;
            // uint256 constant BasicOrder_endAmount_cdPtr = 0x104;
            uint256 constant BasicOrder_common_params_size = 0xa0;
            uint256 constant BasicOrder_considerationHashesArray_ptr = 0x160;
            uint256 constant BasicOrder_receivedItemByteMap = (
                0x0000010102030000000000000000000000000000000000000000000000000000
            );
            uint256 constant BasicOrder_offeredItemByteMap = (
                0x0203020301010000000000000000000000000000000000000000000000000000
            );
            bytes32 constant OrdersMatchedTopic0 = (
                0x4b9f2d36e1b4c93de62cc077b00b1a91d84b6c31b4a14e012718dcca230689e7
            );
            uint256 constant EIP712_Order_size = 0x180;
            uint256 constant EIP712_OfferItem_size = 0xc0;
            uint256 constant EIP712_ConsiderationItem_size = 0xe0;
            uint256 constant AdditionalRecipient_size = 0x40;
            uint256 constant AdditionalRecipient_size_shift = 0x6;
            uint256 constant EIP712_DomainSeparator_offset = 0x02;
            uint256 constant EIP712_OrderHash_offset = 0x22;
            uint256 constant EIP712_DigestPayload_size = 0x42;
            uint256 constant EIP712_domainData_nameHash_offset = 0x20;
            uint256 constant EIP712_domainData_versionHash_offset = 0x40;
            uint256 constant EIP712_domainData_chainId_offset = 0x60;
            uint256 constant EIP712_domainData_verifyingContract_offset = 0x80;
            uint256 constant EIP712_domainData_size = 0xa0;
            // Minimum BulkOrder proof size: 64 bytes for signature + 3 for key + 32 for 1
            // sibling. Maximum BulkOrder proof size: 65 bytes for signature + 3 for key +
            // 768 for 24 siblings.
            uint256 constant BulkOrderProof_minSize = 0x63;
            uint256 constant BulkOrderProof_rangeSize = 0x2e2;
            uint256 constant BulkOrderProof_lengthAdjustmentBeforeMask = 0x1d;
            uint256 constant BulkOrderProof_lengthRangeAfterMask = 0x2;
            uint256 constant BulkOrderProof_keyShift = 0xe8;
            uint256 constant BulkOrderProof_keySize = 0x3;
            uint256 constant BulkOrder_Typehash_Height_One = (
                0x3ca2711d29384747a8f61d60aad3c450405f7aaff5613541dee28df2d6986d32
            );
            uint256 constant BulkOrder_Typehash_Height_Two = (
                0xbf8e29b89f29ed9b529c154a63038ffca562f8d7cd1e2545dda53a1b582dde30
            );
            uint256 constant BulkOrder_Typehash_Height_Three = (
                0x53c6f6856e13104584dd0797ca2b2779202dc2597c6066a42e0d8fe990b0024d
            );
            uint256 constant BulkOrder_Typehash_Height_Four = (
                0xa02eb7ff164c884e5e2c336dc85f81c6a93329d8e9adf214b32729b894de2af1
            );
            uint256 constant BulkOrder_Typehash_Height_Five = (
                0x39c9d33c18e050dda0aeb9a8086fb16fc12d5d64536780e1da7405a800b0b9f6
            );
            uint256 constant BulkOrder_Typehash_Height_Six = (
                0x1c19f71958cdd8f081b4c31f7caf5c010b29d12950be2fa1c95070dc47e30b55
            );
            uint256 constant BulkOrder_Typehash_Height_Seven = (
                0xca74fab2fece9a1d58234a274220ad05ca096a92ef6a1ca1750b9d90c948955c
            );
            uint256 constant BulkOrder_Typehash_Height_Eight = (
                0x7ff98d9d4e55d876c5cfac10b43c04039522f3ddfb0ea9bfe70c68cfb5c7cc14
            );
            uint256 constant BulkOrder_Typehash_Height_Nine = (
                0xbed7be92d41c56f9e59ac7a6272185299b815ddfabc3f25deb51fe55fe2f9e8a
            );
            uint256 constant BulkOrder_Typehash_Height_Ten = (
                0xd1d97d1ef5eaa37a4ee5fbf234e6f6d64eb511eb562221cd7edfbdde0848da05
            );
            uint256 constant BulkOrder_Typehash_Height_Eleven = (
                0x896c3f349c4da741c19b37fec49ed2e44d738e775a21d9c9860a69d67a3dae53
            );
            uint256 constant BulkOrder_Typehash_Height_Twelve = (
                0xbb98d87cc12922b83759626c5f07d72266da9702d19ffad6a514c73a89002f5f
            );
            uint256 constant BulkOrder_Typehash_Height_Thirteen = (
                0xe6ae19322608dd1f8a8d56aab48ed9c28be489b689f4b6c91268563efc85f20e
            );
            uint256 constant BulkOrder_Typehash_Height_Fourteen = (
                0x6b5b04cbae4fcb1a9d78e7b2dfc51a36933d023cf6e347e03d517b472a852590
            );
            uint256 constant BulkOrder_Typehash_Height_Fifteen = (
                0xd1eb68309202b7106b891e109739dbbd334a1817fe5d6202c939e75cf5e35ca9
            );
            uint256 constant BulkOrder_Typehash_Height_Sixteen = (
                0x1da3eed3ecef6ebaa6e5023c057ec2c75150693fd0dac5c90f4a142f9879fde8
            );
            uint256 constant BulkOrder_Typehash_Height_Seventeen = (
                0xeee9a1392aa395c7002308119a58f2582777a75e54e0c1d5d5437bd2e8bf6222
            );
            uint256 constant BulkOrder_Typehash_Height_Eighteen = (
                0xc3939feff011e53ab8c35ca3370aad54c5df1fc2938cd62543174fa6e7d85877
            );
            uint256 constant BulkOrder_Typehash_Height_Nineteen = (
                0x0efca7572ac20f5ae84db0e2940674f7eca0a4726fa1060ffc2d18cef54b203d
            );
            uint256 constant BulkOrder_Typehash_Height_Twenty = (
                0x5a4f867d3d458dabecad65f6201ceeaba0096df2d0c491cc32e6ea4e64350017
            );
            uint256 constant BulkOrder_Typehash_Height_TwentyOne = (
                0x80987079d291feebf21c2230e69add0f283cee0b8be492ca8050b4185a2ff719
            );
            uint256 constant BulkOrder_Typehash_Height_TwentyTwo = (
                0x3bd8cff538aba49a9c374c806d277181e9651624b3e31111bc0624574f8bca1d
            );
            uint256 constant BulkOrder_Typehash_Height_TwentyThree = (
                0x5d6a3f098a0bc373f808c619b1bb4028208721b3c4f8d6bc8a874d659814eb76
            );
            uint256 constant BulkOrder_Typehash_Height_TwentyFour = (
                0x1d51df90cba8de7637ca3e8fe1e3511d1dc2f23487d05dbdecb781860c21ac1c
            );
            uint256 constant receivedItemsHash_ptr = 0x60;
            /*
             *  Memory layout in _prepareBasicFulfillmentFromCalldata of
             *  data for OrderFulfilled
             *
             *   event OrderFulfilled(
             *     bytes32 orderHash,
             *     address indexed offerer,
             *     address indexed zone,
             *     address fulfiller,
             *     SpentItem[] offer,
             *       > (itemType, token, id, amount)
             *     ReceivedItem[] consideration
             *       > (itemType, token, id, amount, recipient)
             *   )
             *
             *  - 0x00: orderHash
             *  - 0x20: fulfiller
             *  - 0x40: offer offset (0x80)
             *  - 0x60: consideration offset (0x120)
             *  - 0x80: offer.length (1)
             *  - 0xa0: offerItemType
             *  - 0xc0: offerToken
             *  - 0xe0: offerIdentifier
             *  - 0x100: offerAmount
             *  - 0x120: consideration.length (1 + additionalRecipients.length)
             *  - 0x140: considerationItemType
             *  - 0x160: considerationToken
             *  - 0x180: considerationIdentifier
             *  - 0x1a0: considerationAmount
             *  - 0x1c0: considerationRecipient
             *  - ...
             */
            // Minimum length of the OrderFulfilled event data.
            // Must be added to the size of the ReceivedItem array for additionalRecipients
            // (0xa0 * additionalRecipients.length) to calculate full size of the buffer.
            uint256 constant OrderFulfilled_baseSize = 0x1e0;
            uint256 constant OrderFulfilled_selector = (
                0x9d9af8e38d66c62e2c12f0225249fd9d721c54b83f48d9352c97c6cacdcb6f31
            );
            // Minimum offset in memory to OrderFulfilled event data.
            // Must be added to the size of the EIP712 hash array for additionalRecipients
            // (32 * additionalRecipients.length) to calculate the pointer to event data.
            uint256 constant OrderFulfilled_baseOffset = 0x180;
            uint256 constant OrderFulfilled_consideration_length_baseOffset = 0x2a0;
            uint256 constant OrderFulfilled_offer_length_baseOffset = 0x200;
            // Related constants used for restricted order checks on basic orders.
            uint256 constant OrderFulfilled_baseDataSize = 0x160;
            // uint256 constant ValidateOrder_offerDataOffset = 0x184;
            // uint256 constant RatifyOrder_offerDataOffset = 0xc4;
            // uint256 constant OrderFulfilled_orderHash_offset = 0x00;
            uint256 constant OrderFulfilled_fulfiller_offset = 0x20;
            uint256 constant OrderFulfilled_offer_head_offset = 0x40;
            uint256 constant OrderFulfilled_offer_body_offset = 0x80;
            uint256 constant OrderFulfilled_consideration_head_offset = 0x60;
            uint256 constant OrderFulfilled_consideration_body_offset = 0x120;
            // 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 = 0x80;
            uint256 constant BasicOrder_offerItem_itemType_ptr = 0xa0;
            uint256 constant BasicOrder_offerItem_token_ptr = 0xc0;
            // uint256 constant BasicOrder_offerItem_identifier_ptr = 0xe0;
            // uint256 constant BasicOrder_offerItem_startAmount_ptr = 0x100;
            uint256 constant BasicOrder_offerItem_endAmount_ptr = 0x120;
            /*
             *  Memory layout in _prepareBasicFulfillmentFromCalldata of
             *  EIP712 data for Order
             *   - 0x80:   Order EIP-712 typehash (constant)
             *   - 0xa0:   orderParameters.offerer
             *   - 0xc0:   orderParameters.zone
             *   - 0xe0:   keccak256(abi.encodePacked(offerHashes))
             *   - 0x100:  keccak256(abi.encodePacked(considerationHashes))
             *   - 0x120:  orderType
             *   - 0x140:  startTime
             *   - 0x160:  endTime
             *   - 0x180:  zoneHash
             *   - 0x1a0:  salt
             *   - 0x1c0:  conduit
             *   - 0x1e0:  _counters[orderParameters.offerer] (from storage)
             */
            uint256 constant BasicOrder_order_typeHash_ptr = 0x80;
            uint256 constant BasicOrder_order_offerer_ptr = 0xa0;
            // uint256 constant BasicOrder_order_zone_ptr = 0xc0;
            uint256 constant BasicOrder_order_offerHashes_ptr = 0xe0;
            uint256 constant BasicOrder_order_considerationHashes_ptr = 0x100;
            uint256 constant BasicOrder_order_orderType_ptr = 0x120;
            uint256 constant BasicOrder_order_startTime_ptr = 0x140;
            // uint256 constant BasicOrder_order_endTime_ptr = 0x160;
            // uint256 constant BasicOrder_order_zoneHash_ptr = 0x180;
            // uint256 constant BasicOrder_order_salt_ptr = 0x1a0;
            // uint256 constant BasicOrder_order_conduitKey_ptr = 0x1c0;
            uint256 constant BasicOrder_order_counter_ptr = 0x1e0;
            uint256 constant BasicOrder_additionalRecipients_head_ptr = 0x240;
            uint256 constant BasicOrder_signature_ptr = 0x260;
            uint256 constant BasicOrder_startTimeThroughZoneHash_size = 0x60;
            uint256 constant ContractOrder_orderHash_offerer_shift = 0x60;
            uint256 constant Counter_blockhash_shift = 0x80;
            // Signature-related
            bytes32 constant EIP2098_allButHighestBitMask = (
                0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
            );
            bytes32 constant ECDSA_twentySeventhAndTwentyEighthBytesSet = (
                0x0000000000000000000000000000000000000000000000000000000101000000
            );
            uint256 constant ECDSA_MaxLength = 65;
            uint256 constant ECDSA_signature_s_offset = 0x40;
            uint256 constant ECDSA_signature_v_offset = 0x60;
            bytes32 constant EIP1271_isValidSignature_selector = (
                0x1626ba7e00000000000000000000000000000000000000000000000000000000
            );
            uint256 constant EIP1271_isValidSignature_digest_negativeOffset = 0x40;
            uint256 constant EIP1271_isValidSignature_selector_negativeOffset = 0x44;
            uint256 constant EIP1271_isValidSignature_calldata_baseLength = 0x64;
            uint256 constant EIP1271_isValidSignature_signature_head_offset = 0x40;
            uint256 constant EIP_712_PREFIX = (
                0x1901000000000000000000000000000000000000000000000000000000000000
            );
            uint256 constant ExtraGasBuffer = 0x20;
            uint256 constant CostPerWord = 0x3;
            uint256 constant MemoryExpansionCoefficientShift = 0x9;
            uint256 constant Create2AddressDerivation_ptr = 0x0b;
            uint256 constant Create2AddressDerivation_length = 0x55;
            uint256 constant MaskOverByteTwelve = (
                0x0000000000000000000000ff0000000000000000000000000000000000000000
            );
            uint256 constant MaskOverLastTwentyBytes = (
                0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff
            );
            uint256 constant AddressDirtyUpperBitThreshold = (
                0x0000000000000000000000010000000000000000000000000000000000000000
            );
            uint256 constant MaskOverFirstFourBytes = (
                0xffffffff00000000000000000000000000000000000000000000000000000000
            );
            uint256 constant Conduit_execute_signature = (
                0x4ce34aa200000000000000000000000000000000000000000000000000000000
            );
            uint256 constant MaxUint8 = 0xff;
            uint256 constant MaxUint120 = 0xffffffffffffffffffffffffffffff;
            uint256 constant Conduit_execute_ConduitTransfer_ptr = 0x20;
            uint256 constant Conduit_execute_ConduitTransfer_length = 0x01;
            uint256 constant Conduit_execute_ConduitTransfer_offset_ptr = 0x04;
            uint256 constant Conduit_execute_ConduitTransfer_length_ptr = 0x24;
            uint256 constant Conduit_execute_transferItemType_ptr = 0x44;
            uint256 constant Conduit_execute_transferToken_ptr = 0x64;
            uint256 constant Conduit_execute_transferFrom_ptr = 0x84;
            uint256 constant Conduit_execute_transferTo_ptr = 0xa4;
            uint256 constant Conduit_execute_transferIdentifier_ptr = 0xc4;
            uint256 constant Conduit_execute_transferAmount_ptr = 0xe4;
            uint256 constant OneConduitExecute_size = 0x104;
            // Sentinel value to indicate that the conduit accumulator is not armed.
            uint256 constant AccumulatorDisarmed = 0x20;
            uint256 constant AccumulatorArmed = 0x40;
            uint256 constant Accumulator_conduitKey_ptr = 0x20;
            uint256 constant Accumulator_selector_ptr = 0x40;
            uint256 constant Accumulator_array_offset_ptr = 0x44;
            uint256 constant Accumulator_array_length_ptr = 0x64;
            uint256 constant Accumulator_itemSizeOffsetDifference = 0x3c;
            uint256 constant Accumulator_array_offset = 0x20;
            uint256 constant Conduit_transferItem_size = 0xc0;
            uint256 constant Conduit_transferItem_token_ptr = 0x20;
            uint256 constant Conduit_transferItem_from_ptr = 0x40;
            uint256 constant Conduit_transferItem_to_ptr = 0x60;
            uint256 constant Conduit_transferItem_identifier_ptr = 0x80;
            uint256 constant Conduit_transferItem_amount_ptr = 0xa0;
            uint256 constant Ecrecover_precompile = 0x1;
            uint256 constant Ecrecover_args_size = 0x80;
            uint256 constant Signature_lower_v = 27;
            // Bitmask that only gives a non-zero value if masked with a non-match selector.
            uint256 constant NonMatchSelector_MagicMask = (
                0x4000000000000000000000000000000000000000000000000000000000
            );
            // First bit indicates that a NATIVE offer items has been used and the 231st bit
            // indicates that a non match selector has been called.
            uint256 constant NonMatchSelector_InvalidErrorValue = (
                0x4000000000000000000000000000000000000000000000000000000001
            );
            /**
             * @dev Selector and offsets for generateOrder
             *
             * function generateOrder(
             *   address fulfiller,
             *   SpentItem[] calldata minimumReceived,
             *   SpentItem[] calldata maximumSpent,
             *   bytes calldata context
             * )
             */
            uint256 constant generateOrder_selector = 0x98919765;
            uint256 constant generateOrder_selector_offset = 0x1c;
            uint256 constant generateOrder_head_offset = 0x04;
            uint256 constant generateOrder_minimumReceived_head_offset = 0x20;
            uint256 constant generateOrder_maximumSpent_head_offset = 0x40;
            uint256 constant generateOrder_context_head_offset = 0x60;
            uint256 constant generateOrder_base_tail_offset = 0x80;
            uint256 constant generateOrder_maximum_returndatasize = 0xffff;
            uint256 constant ratifyOrder_selector = 0xf4dd92ce;
            uint256 constant ratifyOrder_selector_offset = 0x1c;
            uint256 constant ratifyOrder_head_offset = 0x04;
            // uint256 constant ratifyOrder_offer_head_offset = 0x00;
            uint256 constant ratifyOrder_consideration_head_offset = 0x20;
            uint256 constant ratifyOrder_context_head_offset = 0x40;
            uint256 constant ratifyOrder_orderHashes_head_offset = 0x60;
            uint256 constant ratifyOrder_contractNonce_offset = 0x80;
            uint256 constant ratifyOrder_base_tail_offset = 0xa0;
            uint256 constant validateOrder_selector = 0x17b1f942;
            uint256 constant validateOrder_selector_offset = 0x1c;
            uint256 constant validateOrder_head_offset = 0x04;
            uint256 constant validateOrder_zoneParameters_offset = 0x20;
            // uint256 constant ZoneParameters_orderHash_offset = 0x00;
            uint256 constant ZoneParameters_fulfiller_offset = 0x20;
            uint256 constant ZoneParameters_offerer_offset = 0x40;
            uint256 constant ZoneParameters_offer_head_offset = 0x60;
            uint256 constant ZoneParameters_consideration_head_offset = 0x80;
            uint256 constant ZoneParameters_extraData_head_offset = 0xa0;
            uint256 constant ZoneParameters_orderHashes_head_offset = 0xc0;
            uint256 constant ZoneParameters_startTime_offset = 0xe0;
            uint256 constant ZoneParameters_endTime_offset = 0x100;
            uint256 constant ZoneParameters_zoneHash_offset = 0x120;
            uint256 constant ZoneParameters_base_tail_offset = 0x140;
            uint256 constant ZoneParameters_selectorAndPointer_length = 0x24;
            uint256 constant ZoneParameters_basicOrderFixedElements_length = 0x64;
            // ConsiderationDecoder Constants
            uint256 constant OrderParameters_head_size = 0x0160;
            uint256 constant OrderParameters_totalOriginalConsiderationItems_offset = (
                0x0140
            );
            uint256 constant AdvancedOrderPlusOrderParameters_head_size = 0x0200;
            uint256 constant Order_signature_offset = 0x20;
            uint256 constant Order_head_size = 0x40;
            uint256 constant AdvancedOrder_fixed_segment_0 = 0x40;
            uint256 constant CriteriaResolver_head_size = 0xa0;
            uint256 constant CriteriaResolver_fixed_segment_0 = 0x80;
            uint256 constant CriteriaResolver_criteriaProof_offset = 0x80;
            uint256 constant FulfillmentComponent_mem_tail_size = 0x40;
            uint256 constant FulfillmentComponent_mem_tail_size_shift = 0x6;
            uint256 constant Fulfillment_head_size = 0x40;
            uint256 constant Fulfillment_considerationComponents_offset = 0x20;
            uint256 constant OrderComponents_OrderParameters_common_head_size = 0x0140;
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            enum OrderType {
                // 0: no partial fills, anyone can execute
                FULL_OPEN,
                // 1: partial fills supported, anyone can execute
                PARTIAL_OPEN,
                // 2: no partial fills, only offerer or zone can execute
                FULL_RESTRICTED,
                // 3: partial fills supported, only offerer or zone can execute
                PARTIAL_RESTRICTED,
                // 4: contract order type
                CONTRACT
            }
            enum BasicOrderType {
                // 0: no partial fills, anyone can execute
                ETH_TO_ERC721_FULL_OPEN,
                // 1: partial fills supported, anyone can execute
                ETH_TO_ERC721_PARTIAL_OPEN,
                // 2: no partial fills, only offerer or zone can execute
                ETH_TO_ERC721_FULL_RESTRICTED,
                // 3: partial fills supported, only offerer or zone can execute
                ETH_TO_ERC721_PARTIAL_RESTRICTED,
                // 4: no partial fills, anyone can execute
                ETH_TO_ERC1155_FULL_OPEN,
                // 5: partial fills supported, anyone can execute
                ETH_TO_ERC1155_PARTIAL_OPEN,
                // 6: no partial fills, only offerer or zone can execute
                ETH_TO_ERC1155_FULL_RESTRICTED,
                // 7: partial fills supported, only offerer or zone can execute
                ETH_TO_ERC1155_PARTIAL_RESTRICTED,
                // 8: no partial fills, anyone can execute
                ERC20_TO_ERC721_FULL_OPEN,
                // 9: partial fills supported, anyone can execute
                ERC20_TO_ERC721_PARTIAL_OPEN,
                // 10: no partial fills, only offerer or zone can execute
                ERC20_TO_ERC721_FULL_RESTRICTED,
                // 11: partial fills supported, only offerer or zone can execute
                ERC20_TO_ERC721_PARTIAL_RESTRICTED,
                // 12: no partial fills, anyone can execute
                ERC20_TO_ERC1155_FULL_OPEN,
                // 13: partial fills supported, anyone can execute
                ERC20_TO_ERC1155_PARTIAL_OPEN,
                // 14: no partial fills, only offerer or zone can execute
                ERC20_TO_ERC1155_FULL_RESTRICTED,
                // 15: partial fills supported, only offerer or zone can execute
                ERC20_TO_ERC1155_PARTIAL_RESTRICTED,
                // 16: no partial fills, anyone can execute
                ERC721_TO_ERC20_FULL_OPEN,
                // 17: partial fills supported, anyone can execute
                ERC721_TO_ERC20_PARTIAL_OPEN,
                // 18: no partial fills, only offerer or zone can execute
                ERC721_TO_ERC20_FULL_RESTRICTED,
                // 19: partial fills supported, only offerer or zone can execute
                ERC721_TO_ERC20_PARTIAL_RESTRICTED,
                // 20: no partial fills, anyone can execute
                ERC1155_TO_ERC20_FULL_OPEN,
                // 21: partial fills supported, anyone can execute
                ERC1155_TO_ERC20_PARTIAL_OPEN,
                // 22: no partial fills, only offerer or zone can execute
                ERC1155_TO_ERC20_FULL_RESTRICTED,
                // 23: partial fills supported, only offerer or zone can execute
                ERC1155_TO_ERC20_PARTIAL_RESTRICTED
            }
            enum BasicOrderRouteType {
                // 0: provide Ether (or other native token) to receive offered ERC721 item.
                ETH_TO_ERC721,
                // 1: provide Ether (or other native token) to receive offered ERC1155 item.
                ETH_TO_ERC1155,
                // 2: provide ERC20 item to receive offered ERC721 item.
                ERC20_TO_ERC721,
                // 3: provide ERC20 item to receive offered ERC1155 item.
                ERC20_TO_ERC1155,
                // 4: provide ERC721 item to receive offered ERC20 item.
                ERC721_TO_ERC20,
                // 5: provide ERC1155 item to receive offered ERC20 item.
                ERC1155_TO_ERC20
            }
            enum ItemType {
                // 0: ETH on mainnet, MATIC on polygon, etc.
                NATIVE,
                // 1: ERC20 items (ERC777 and ERC20 analogues could also technically work)
                ERC20,
                // 2: ERC721 items
                ERC721,
                // 3: ERC1155 items
                ERC1155,
                // 4: ERC721 items where a number of tokenIds are supported
                ERC721_WITH_CRITERIA,
                // 5: ERC1155 items where a number of ids are supported
                ERC1155_WITH_CRITERIA
            }
            enum Side {
                // 0: Items that can be spent
                OFFER,
                // 1: Items that must be received
                CONSIDERATION
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.17;
            import { ItemType, OrderType } from "./ConsiderationEnums.sol";
            import {
                AdvancedOrder,
                ConsiderationItem,
                CriteriaResolver,
                OfferItem,
                OrderParameters,
                ReceivedItem,
                SpentItem
            } from "./ConsiderationStructs.sol";
            import { BasicOrderFulfiller } from "./BasicOrderFulfiller.sol";
            import { CriteriaResolution } from "./CriteriaResolution.sol";
            import { AmountDeriver } from "./AmountDeriver.sol";
            import {
                _revertInsufficientNativeTokensSupplied,
                _revertInvalidNativeOfferItem
            } from "./ConsiderationErrors.sol";
            import {
                AccumulatorDisarmed,
                ConsiderationItem_recipient_offset,
                ReceivedItem_amount_offset,
                ReceivedItem_recipient_offset
            } from "./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(
                        // Native tokens accepted during execution for contract order types.
                        advancedOrder.parameters.orderType == OrderType.CONTRACT
                    );
                    // Validate order, update status, and determine fraction to fill.
                    (
                        bytes32 orderHash,
                        uint256 fillNumerator,
                        uint256 fillDenominator
                    ) = _validateOrderAndUpdateStatus(advancedOrder, true);
                    // 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
                    );
                    // Declare empty bytes32 array and populate with the order hash.
                    bytes32[] memory orderHashes = new bytes32[](1);
                    orderHashes[0] = orderHash;
                    // Ensure restricted orders have a valid submitter or pass a zone check.
                    _assertRestrictedAdvancedOrderValidity(
                        advancedOrders[0],
                        orderHashes,
                        orderHash
                    );
                    // Emit an event signifying that the order has been fulfilled.
                    _emitOrderFulfilledEvent(
                        orderHash,
                        orderParameters.offerer,
                        orderParameters.zone,
                        recipient,
                        orderParameters.offer,
                        orderParameters.consideration
                    );
                    // Clear the reentrancy guard.
                    _clearReentrancyGuard();
                    return true;
                }
                /**
                 * @dev Internal function to 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 a local variable to reference the internal function
                    // definition (using the same type), along with a local variable with
                    // the desired type, must first be created. Then, the original function
                    // pointer can be recast to the desired type.
                    /**
                     * Repurpose existing OfferItem memory regions on the offer array for
                     * the order by overriding the _transfer function pointer to accept a
                     * modified OfferItem argument in place of the usual ReceivedItem:
                     *
                     *   ========= OfferItem ==========   ====== ReceivedItem ======
                     *   ItemType itemType; ------------> ItemType itemType;
                     *   address token; ----------------> address token;
                     *   uint256 identifierOrCriteria; -> uint256 identifier;
                     *   uint256 startAmount; ----------> uint256 amount;
                     *   uint256 endAmount; ------------> address recipient;
                     */
                    // Declare a nested scope to minimize stack depth.
                    unchecked {
                        // Read offer array length from memory and place on stack.
                        uint256 totalOfferItems = orderParameters.offer.length;
                        // Create a variable to indicate whether the order has any
                        // native offer items
                        uint256 anyNativeItems;
                        // Iterate over each offer on the order.
                        // Skip overflow check as for loop is indexed starting at zero.
                        for (uint256 i = 0; i < totalOfferItems; ++i) {
                            // Retrieve the offer item.
                            OfferItem memory offerItem = orderParameters.offer[i];
                            // Offer items for the native token can not be received outside
                            // of a match order function except as part of a contract order.
                            {
                                ItemType itemType = offerItem.itemType;
                                assembly {
                                    anyNativeItems := or(anyNativeItems, iszero(itemType))
                                }
                            }
                            // Declare an additional nested scope to minimize stack depth.
                            {
                                // Apply fill fraction to get offer item amount to transfer.
                                uint256 amount = _applyFraction(
                                    offerItem.startAmount,
                                    offerItem.endAmount,
                                    numerator,
                                    denominator,
                                    startTime,
                                    endTime,
                                    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.
                            _toOfferItemInput(_transfer)(
                                offerItem,
                                orderParameters.offerer,
                                orderParameters.conduitKey,
                                accumulator
                            );
                        }
                        // If a non-contract order has native offer items, throw with an
                        // `InvalidNativeOfferItem` custom error.
                        {
                            OrderType orderType = orderParameters.orderType;
                            uint256 invalidNativeOfferItem;
                            assembly {
                                invalidNativeOfferItem := and(
                                    // Note that this check requires that there are no order
                                    // types beyond the current set (0-4).  It will need to
                                    // be modified if more order types are added.
                                    lt(orderType, 4),
                                    anyNativeItems
                                )
                            }
                            if (invalidNativeOfferItem != 0) {
                                _revertInvalidNativeOfferItem();
                            }
                        }
                    }
                    // Declare a variable for the available native token balance.
                    uint256 nativeTokenBalance;
                    /**
                     * Repurpose existing ConsiderationItem memory regions on the
                     * consideration array for the order by overriding the _transfer
                     * function pointer to accept a modified ConsiderationItem argument in
                     * place of the usual ReceivedItem:
                     *
                     *   ====== ConsiderationItem =====   ====== ReceivedItem ======
                     *   ItemType itemType; ------------> ItemType itemType;
                     *   address token; ----------------> address token;
                     *   uint256 identifierOrCriteria;--> uint256 identifier;
                     *   uint256 startAmount; ----------> uint256 amount;
                     *   uint256 endAmount;        /----> address recipient;
                     *   address recipient; ------/
                     */
                    // Declare a nested scope to minimize stack depth.
                    unchecked {
                        // Read consideration array length from memory and place on stack.
                        uint256 totalConsiderationItems = orderParameters
                            .consideration
                            .length;
                        // Iterate over each consideration item on the order.
                        // Skip overflow check as for loop is indexed starting at zero.
                        for (uint256 i = 0; i < totalConsiderationItems; ++i) {
                            // Retrieve the consideration item.
                            ConsiderationItem memory considerationItem = (
                                orderParameters.consideration[i]
                            );
                            // 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) {
                                // Get the current available balance of native tokens.
                                assembly {
                                    nativeTokenBalance := selfbalance()
                                }
                                // Ensure that sufficient native tokens are still available.
                                if (amount > nativeTokenBalance) {
                                    _revertInsufficientNativeTokensSupplied();
                                }
                            }
                            // Transfer item from caller to recipient specified by the item.
                            _toConsiderationItemInput(_transfer)(
                                considerationItem,
                                msg.sender,
                                fulfillerConduitKey,
                                accumulator
                            );
                        }
                    }
                    // Trigger any remaining accumulated transfers via call to the conduit.
                    _triggerIfArmed(accumulator);
                    // Determine whether any native token balance remains.
                    assembly {
                        nativeTokenBalance := selfbalance()
                    }
                    // Return any remaining native token balance to the caller.
                    if (nativeTokenBalance != 0) {
                        _transferNativeTokens(payable(msg.sender), nativeTokenBalance);
                    }
                }
                /**
                 * @dev Internal function to emit an OrderFulfilled event. OfferItems are
                 *      translated into SpentItems and ConsiderationItems are translated
                 *      into ReceivedItems.
                 *
                 * @param orderHash     The order hash.
                 * @param offerer       The offerer for the order.
                 * @param zone          The zone for the order.
                 * @param recipient     The recipient of the order, or the null address if
                 *                      the order was fulfilled via order matching.
                 * @param offer         The offer items for the order.
                 * @param consideration The consideration items for the order.
                 */
                function _emitOrderFulfilledEvent(
                    bytes32 orderHash,
                    address offerer,
                    address zone,
                    address recipient,
                    OfferItem[] memory offer,
                    ConsiderationItem[] memory consideration
                ) internal {
                    // Cast already-modified offer memory region as spent items.
                    SpentItem[] memory spentItems;
                    assembly {
                        spentItems := offer
                    }
                    // Cast already-modified consideration memory region as received items.
                    ReceivedItem[] memory receivedItems;
                    assembly {
                        receivedItems := consideration
                    }
                    // Emit an event signifying that the order has been fulfilled.
                    emit OrderFulfilled(
                        orderHash,
                        offerer,
                        zone,
                        recipient,
                        spentItems,
                        receivedItems
                    );
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.17;
            import { ItemType, Side } from "./ConsiderationEnums.sol";
            import {
                AdvancedOrder,
                Execution,
                FulfillmentComponent,
                ReceivedItem
            } from "./ConsiderationStructs.sol";
            import {
                _revertMismatchedFulfillmentOfferAndConsiderationComponents,
                _revertMissingFulfillmentComponentOnAggregation,
                _revertOfferAndConsiderationRequiredOnFulfillment
            } from "./ConsiderationErrors.sol";
            import {
                FulfillmentApplicationErrors
            } from "../interfaces/FulfillmentApplicationErrors.sol";
            import {
                AdvancedOrder_numerator_offset,
                Common_amount_offset,
                Common_identifier_offset,
                Common_token_offset,
                Execution_conduit_offset,
                Execution_offerer_offset,
                Fulfillment_itemIndex_offset,
                OneWord,
                OneWordShift,
                OrderParameters_conduit_offset,
                OrderParameters_consideration_head_offset,
                OrderParameters_offer_head_offset,
                ReceivedItem_CommonParams_size,
                ReceivedItem_recipient_offset,
                ReceivedItem_size
            } from "./ConsiderationConstants.sol";
            import {
                Error_selector_offset,
                InvalidFulfillmentComponentData_error_length,
                InvalidFulfillmentComponentData_error_selector,
                MissingItemAmount_error_length,
                MissingItemAmount_error_selector,
                Panic_arithmetic,
                Panic_error_code_ptr,
                Panic_error_length,
                Panic_error_selector
            } from "./ConsiderationErrorConstants.sol";
            /**
             * @title FulfillmentApplier
             * @author 0age
             * @notice FulfillmentApplier contains logic related to applying fulfillments,
             *         both as part of order matching (where offer items are matched to
             *         consideration items) as well as fulfilling available orders (where
             *         order items and consideration items are independently aggregated).
             */
            contract FulfillmentApplier is FulfillmentApplicationErrors {
                /**
                 * @dev Internal pure function to match offer items to consideration items
                 *      on a group of orders via a supplied fulfillment.
                 *
                 * @param advancedOrders          The orders to match.
                 * @param offerComponents         An array designating offer components to
                 *                                match to consideration components.
                 * @param considerationComponents An array designating consideration
                 *                                components to match to offer components.
                 *                                Note that each consideration amount must
                 *                                be zero in order for the match operation
                 *                                to be valid.
                 * @param fulfillmentIndex        The index of the fulfillment being
                 *                                applied.
                 *
                 * @return execution The transfer performed as a result of the fulfillment.
                 */
                function _applyFulfillment(
                    AdvancedOrder[] memory advancedOrders,
                    FulfillmentComponent[] memory offerComponents,
                    FulfillmentComponent[] memory considerationComponents,
                    uint256 fulfillmentIndex
                ) internal pure returns (Execution memory execution) {
                    // Ensure 1+ of both offer and consideration components are supplied.
                    if (
                        offerComponents.length == 0 || considerationComponents.length == 0
                    ) {
                        _revertOfferAndConsiderationRequiredOnFulfillment();
                    }
                    // 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;
                    // Skip aggregating offer items if no consideration items are available.
                    if (considerationItem.amount == 0) {
                        // Set the offerer and recipient to null address and the item type
                        // to a non-native item type if the execution amount is zero. This
                        // will cause the execution item to be skipped.
                        considerationExecution.offerer = address(0);
                        considerationExecution.item.recipient = payable(0);
                        considerationExecution.item.itemType = ItemType.ERC20;
                        return considerationExecution;
                    }
                    // 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 & consideration item types, tokens, & identifiers match.
                    // (a != b || c != d || e != f) == (((a ^ b) | (c ^ d) | (e ^ f)) != 0),
                    // but the second expression requires less gas to evaluate.
                    if (
                        ((uint8(execution.item.itemType) ^
                            uint8(considerationItem.itemType)) |
                            (uint160(execution.item.token) ^
                                uint160(considerationItem.token)) |
                            (execution.item.identifier ^ considerationItem.identifier)) != 0
                    ) {
                        _revertMismatchedFulfillmentOfferAndConsiderationComponents(
                            fulfillmentIndex
                        );
                    }
                    // 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);
                        }
                    } 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) {
                            _revertMissingFulfillmentComponentOnAggregation(side);
                        }
                        // Retrieve the received item on the execution being returned.
                        ReceivedItem memory item = execution.item;
                        // If the fulfillment components are offer components...
                        if (side == Side.OFFER) {
                            // Set the supplied recipient on the execution item.
                            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 and the item type
                        // to a non-native item type if the execution amount is zero. This
                        // will cause the execution item to be skipped.
                        if (item.amount == 0) {
                            execution.offerer = address(0);
                            item.recipient = payable(0);
                            item.itemType = ItemType.ERC20;
                        }
                    }
                }
                /**
                 * @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 a variable for the final aggregated item amount.
                        let amount
                        // Declare a variable to track errors encountered with amount.
                        let errorBuffer
                        // Declare a variable for the hash of itemType, token, & identifier.
                        let dataHash
                        // Iterate over each offer component.
                        for {
                            // Create variable to track position in offerComponents head.
                            let fulfillmentHeadPtr := offerComponents
                            // Get position one word past last element in head of array.
                            let endPtr := add(
                                offerComponents,
                                shl(OneWordShift, mload(offerComponents))
                            )
                        } lt(fulfillmentHeadPtr, endPtr) {
                        } {
                            // Increment position in considerationComponents head.
                            fulfillmentHeadPtr := add(fulfillmentHeadPtr, OneWord)
                            // 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),
                                    shl(OneWordShift, orderIndex)
                                )
                            )
                            // Read the pointer to OrderParameters from the AdvancedOrder.
                            let paramsPtr := mload(orderPtr)
                            // Retrieve item index using an offset of fulfillment pointer.
                            let itemIndex := mload(
                                add(mload(fulfillmentHeadPtr), Fulfillment_itemIndex_offset)
                            )
                            let offerItemPtr
                            {
                                // Load the offer array pointer.
                                let offerArrPtr := mload(
                                    add(paramsPtr, OrderParameters_offer_head_offset)
                                )
                                // If the offer item index is out of range or the numerator
                                // is zero, skip this item.
                                if or(
                                    iszero(lt(itemIndex, mload(offerArrPtr))),
                                    iszero(
                                        mload(add(orderPtr, AdvancedOrder_numerator_offset))
                                    )
                                ) {
                                    continue
                                }
                                // Retrieve offer item pointer using the item index.
                                offerItemPtr := mload(
                                    add(
                                        // Get pointer to beginning of receivedItem.
                                        add(offerArrPtr, OneWord),
                                        // Calculate offset to pointer for desired order.
                                        shl(OneWordShift, itemIndex)
                                    )
                                )
                            }
                            // Declare a separate scope for the amount update.
                            {
                                // Retrieve amount pointer using consideration item pointer.
                                let amountPtr := add(offerItemPtr, Common_amount_offset)
                                // Add offer item amount to execution amount.
                                let newAmount := add(amount, mload(amountPtr))
                                // Update error buffer:
                                // 1 = zero amount, 2 = overflow, 3 = both.
                                errorBuffer := or(
                                    errorBuffer,
                                    or(
                                        shl(1, lt(newAmount, amount)),
                                        iszero(mload(amountPtr))
                                    )
                                )
                                // Update the amount to the new, summed amount.
                                amount := newAmount
                                // Zero out amount on original item to indicate it is spent.
                                mstore(amountPtr, 0)
                            }
                            // Retrieve ReceivedItem pointer from Execution.
                            let receivedItem := mload(execution)
                            // Check if this is the first valid fulfillment item.
                            switch iszero(dataHash)
                            case 1 {
                                // On first valid item, populate the received item in memory
                                // for later comparison.
                                // Set the item type on the received item.
                                mstore(receivedItem, mload(offerItemPtr))
                                // Set the token on the received item.
                                mstore(
                                    add(receivedItem, Common_token_offset),
                                    mload(add(offerItemPtr, Common_token_offset))
                                )
                                // Set the identifier on the received item.
                                mstore(
                                    add(receivedItem, Common_identifier_offset),
                                    mload(add(offerItemPtr, Common_identifier_offset))
                                )
                                // Set offerer on returned execution using order pointer.
                                mstore(
                                    add(execution, Execution_offerer_offset),
                                    mload(paramsPtr)
                                )
                                // Set execution conduitKey via order pointer offset.
                                mstore(
                                    add(execution, Execution_conduit_offset),
                                    mload(add(paramsPtr, OrderParameters_conduit_offset))
                                )
                                // Calculate the hash of (itemType, token, identifier).
                                dataHash := keccak256(
                                    receivedItem,
                                    ReceivedItem_CommonParams_size
                                )
                                // If component index > 0, swap component pointer with
                                // pointer to first component so that any remainder after
                                // fulfillment can be added back to the first item.
                                let firstFulfillmentHeadPtr := add(offerComponents, OneWord)
                                if xor(firstFulfillmentHeadPtr, fulfillmentHeadPtr) {
                                    let firstFulfillmentPtr := mload(
                                        firstFulfillmentHeadPtr
                                    )
                                    let fulfillmentPtr := mload(fulfillmentHeadPtr)
                                    mstore(firstFulfillmentHeadPtr, fulfillmentPtr)
                                }
                            }
                            default {
                                // Compare every subsequent item to the first.
                                if or(
                                    or(
                                        // The offerer must match on both items.
                                        xor(
                                            mload(paramsPtr),
                                            mload(add(execution, Execution_offerer_offset))
                                        ),
                                        // The conduit key must match on both items.
                                        xor(
                                            mload(
                                                add(
                                                    paramsPtr,
                                                    OrderParameters_conduit_offset
                                                )
                                            ),
                                            mload(add(execution, Execution_conduit_offset))
                                        )
                                    ),
                                    // The itemType, token, and identifier must match.
                                    xor(
                                        dataHash,
                                        keccak256(
                                            offerItemPtr,
                                            ReceivedItem_CommonParams_size
                                        )
                                    )
                                ) {
                                    // Throw if any of the requirements are not met.
                                    throwInvalidFulfillmentComponentData()
                                }
                            }
                        }
                        // Write final amount to execution.
                        mstore(add(mload(execution), Common_amount_offset), amount)
                        // Determine whether the error buffer contains a nonzero error code.
                        if errorBuffer {
                            // If errorBuffer is 1, an item had an amount of zero.
                            if eq(errorBuffer, 1) {
                                // Store left-padded selector with push4 (reduces bytecode)
                                // mem[28:32] = selector
                                mstore(0, MissingItemAmount_error_selector)
                                // revert(abi.encodeWithSignature("MissingItemAmount()"))
                                revert(
                                    Error_selector_offset,
                                    MissingItemAmount_error_length
                                )
                            }
                            // If errorBuffer is not 1 or 0, the sum overflowed.
                            // Panic!
                            throwOverflow()
                        }
                        // Declare function for reverts on invalid fulfillment data.
                        function throwInvalidFulfillmentComponentData() {
                            // Store left-padded selector (uses push4 and reduces code size)
                            mstore(0, InvalidFulfillmentComponentData_error_selector)
                            // revert(abi.encodeWithSignature(
                            //     "InvalidFulfillmentComponentData()"
                            // ))
                            revert(
                                Error_selector_offset,
                                InvalidFulfillmentComponentData_error_length
                            )
                        }
                        // Declare function for reverts due to arithmetic overflows.
                        function throwOverflow() {
                            // Store the Panic error signature.
                            mstore(0, Panic_error_selector)
                            // Store the arithmetic (0x11) panic code.
                            mstore(Panic_error_code_ptr, Panic_arithmetic)
                            // revert(abi.encodeWithSignature("Panic(uint256)", 0x11))
                            revert(Error_selector_offset, Panic_error_length)
                        }
                    }
                }
                /**
                 * @dev Internal pure function to aggregate a group of consideration items
                 *      using supplied directives on which component items are candidates
                 *      for aggregation, skipping items on orders that are not available.
                 *      Note that this function depends on memory layout affected by an
                 *      earlier call to _validateOrdersAndPrepareToFulfill.  The memory for
                 *      the consideration arrays needs to be updated before calling
                 *      _aggregateValidFulfillmentConsiderationItems.
                 *      _validateOrdersAndPrepareToFulfill is called in _matchAdvancedOrders
                 *      and _fulfillAvailableAdvancedOrders in the current version.
                 *
                 * @param advancedOrders          The orders to aggregate consideration
                 *                                items from.
                 * @param considerationComponents An array of FulfillmentComponent structs
                 *                                indicating the order index and item index
                 *                                of each candidate consideration item for
                 *                                aggregation.
                 * @param execution               The execution to apply the aggregation to.
                 */
                function _aggregateValidFulfillmentConsiderationItems(
                    AdvancedOrder[] memory advancedOrders,
                    FulfillmentComponent[] memory considerationComponents,
                    Execution memory execution
                ) internal pure {
                    // Utilize assembly in order to efficiently aggregate the items.
                    assembly {
                        // Declare a variable for the final aggregated item amount.
                        let amount
                        // Create variable to track errors encountered with amount.
                        let errorBuffer
                        // Declare variable for hash(itemType, token, identifier, recipient)
                        let dataHash
                        // Iterate over each consideration component.
                        for {
                            // Track position in considerationComponents head.
                            let fulfillmentHeadPtr := considerationComponents
                            // Get position one word past last element in head of array.
                            let endPtr := add(
                                considerationComponents,
                                shl(OneWordShift, mload(considerationComponents))
                            )
                        } lt(fulfillmentHeadPtr, endPtr) {
                        } {
                            // Increment position in considerationComponents head.
                            fulfillmentHeadPtr := add(fulfillmentHeadPtr, OneWord)
                            // Retrieve the order index using the fulfillment pointer.
                            let orderIndex := mload(mload(fulfillmentHeadPtr))
                            // Ensure that the order index is not out of range.
                            if iszero(lt(orderIndex, mload(advancedOrders))) {
                                throwInvalidFulfillmentComponentData()
                            }
                            // Read advancedOrders[orderIndex] pointer from its array head.
                            let orderPtr := mload(
                                // Calculate head position of advancedOrders[orderIndex].
                                add(
                                    add(advancedOrders, OneWord),
                                    shl(OneWordShift, orderIndex)
                                )
                            )
                            // Retrieve item index using an offset of fulfillment pointer.
                            let itemIndex := mload(
                                add(mload(fulfillmentHeadPtr), Fulfillment_itemIndex_offset)
                            )
                            let considerationItemPtr
                            {
                                // Load consideration array pointer.
                                let considerationArrPtr := mload(
                                    add(
                                        // Read OrderParameters pointer from AdvancedOrder.
                                        mload(orderPtr),
                                        OrderParameters_consideration_head_offset
                                    )
                                )
                                // If the consideration item index is out of range or the
                                // numerator is zero, skip this item.
                                if or(
                                    iszero(lt(itemIndex, mload(considerationArrPtr))),
                                    iszero(
                                        mload(add(orderPtr, AdvancedOrder_numerator_offset))
                                    )
                                ) {
                                    continue
                                }
                                // Retrieve consideration item pointer using the item index.
                                considerationItemPtr := mload(
                                    add(
                                        // Get pointer to beginning of receivedItem.
                                        add(considerationArrPtr, OneWord),
                                        // Calculate offset to pointer for desired order.
                                        shl(OneWordShift, itemIndex)
                                    )
                                )
                            }
                            // Declare a separate scope for the amount update.
                            {
                                // Retrieve amount pointer using consideration item pointer.
                                let amountPtr := add(
                                    considerationItemPtr,
                                    Common_amount_offset
                                )
                                // Add consideration item amount to execution amount.
                                let newAmount := add(amount, mload(amountPtr))
                                // Update error buffer:
                                // 1 = zero amount, 2 = overflow, 3 = both.
                                errorBuffer := or(
                                    errorBuffer,
                                    or(
                                        shl(1, lt(newAmount, amount)),
                                        iszero(mload(amountPtr))
                                    )
                                )
                                // Update the amount to the new, summed amount.
                                amount := newAmount
                                // Zero out original item amount to indicate it is credited.
                                mstore(amountPtr, 0)
                            }
                            // Retrieve ReceivedItem pointer from Execution.
                            let receivedItem := mload(execution)
                            switch iszero(dataHash)
                            case 1 {
                                // On first valid item, populate the received item in
                                // memory for later comparison.
                                // Set the item type on the received item.
                                mstore(receivedItem, mload(considerationItemPtr))
                                // Set the token on the received item.
                                mstore(
                                    add(receivedItem, Common_token_offset),
                                    mload(add(considerationItemPtr, Common_token_offset))
                                )
                                // Set the identifier on the received item.
                                mstore(
                                    add(receivedItem, Common_identifier_offset),
                                    mload(
                                        add(considerationItemPtr, Common_identifier_offset)
                                    )
                                )
                                // Set the recipient on the received item. Note that this
                                // depends on the memory layout established by the
                                // _validateOrdersAndPrepareToFulfill function.
                                mstore(
                                    add(receivedItem, ReceivedItem_recipient_offset),
                                    mload(
                                        add(
                                            considerationItemPtr,
                                            ReceivedItem_recipient_offset
                                        )
                                    )
                                )
                                // Calculate the hash of (itemType, token, identifier,
                                // recipient). This is run after amount is set to zero, so
                                // there will be one blank word after identifier included in
                                // the hash buffer.
                                dataHash := keccak256(
                                    considerationItemPtr,
                                    ReceivedItem_size
                                )
                                // If component index > 0, swap component pointer with
                                // pointer to first component so that any remainder after
                                // fulfillment can be added back to the first item.
                                let firstFulfillmentHeadPtr := add(
                                    considerationComponents,
                                    OneWord
                                )
                                if xor(firstFulfillmentHeadPtr, fulfillmentHeadPtr) {
                                    let firstFulfillmentPtr := mload(
                                        firstFulfillmentHeadPtr
                                    )
                                    let fulfillmentPtr := mload(fulfillmentHeadPtr)
                                    mstore(firstFulfillmentHeadPtr, fulfillmentPtr)
                                }
                            }
                            default {
                                // Compare every subsequent item to the first; the item
                                // type, token, identifier and recipient must match.
                                if xor(
                                    dataHash,
                                    // Calculate the hash of (itemType, token, identifier,
                                    // recipient). This is run after amount is set to zero,
                                    // so there will be one blank word after identifier
                                    // included in the hash buffer.
                                    keccak256(considerationItemPtr, ReceivedItem_size)
                                ) {
                                    // Throw if any of the requirements are not met.
                                    throwInvalidFulfillmentComponentData()
                                }
                            }
                        }
                        // Retrieve ReceivedItem pointer from Execution.
                        let receivedItem := mload(execution)
                        // Write final amount to execution.
                        mstore(add(receivedItem, Common_amount_offset), amount)
                        // Determine whether the error buffer contains a nonzero error code.
                        if errorBuffer {
                            // If errorBuffer is 1, an item had an amount of zero.
                            if eq(errorBuffer, 1) {
                                // Store left-padded selector with push4, mem[28:32]
                                mstore(0, MissingItemAmount_error_selector)
                                // revert(abi.encodeWithSignature("MissingItemAmount()"))
                                revert(
                                    Error_selector_offset,
                                    MissingItemAmount_error_length
                                )
                            }
                            // If errorBuffer is not 1 or 0, `amount` overflowed.
                            // Panic!
                            throwOverflow()
                        }
                        // Declare function for reverts on invalid fulfillment data.
                        function throwInvalidFulfillmentComponentData() {
                            // Store the InvalidFulfillmentComponentData error signature.
                            mstore(0, InvalidFulfillmentComponentData_error_selector)
                            // revert(abi.encodeWithSignature(
                            //     "InvalidFulfillmentComponentData()"
                            // ))
                            revert(
                                Error_selector_offset,
                                InvalidFulfillmentComponentData_error_length
                            )
                        }
                        // Declare function for reverts due to arithmetic overflows.
                        function throwOverflow() {
                            // Store the Panic error signature.
                            mstore(0, Panic_error_selector)
                            // Store the arithmetic (0x11) panic code.
                            mstore(Panic_error_code_ptr, Panic_arithmetic)
                            // revert(abi.encodeWithSignature("Panic(uint256)", 0x11))
                            revert(Error_selector_offset, Panic_error_length)
                        }
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.17;
            import { Side } from "./ConsiderationEnums.sol";
            import {
                BadFraction_error_length,
                BadFraction_error_selector,
                CannotCancelOrder_error_length,
                CannotCancelOrder_error_selector,
                ConsiderationLengthNotEqualToTotalOriginal_error_length,
                ConsiderationLengthNotEqualToTotalOriginal_error_selector,
                ConsiderationNotMet_error_considerationIndex_ptr,
                ConsiderationNotMet_error_length,
                ConsiderationNotMet_error_orderIndex_ptr,
                ConsiderationNotMet_error_selector,
                ConsiderationNotMet_error_shortfallAmount_ptr,
                CriteriaNotEnabledForItem_error_length,
                CriteriaNotEnabledForItem_error_selector,
                Error_selector_offset,
                InsufficientNativeTokensSupplied_error_length,
                InsufficientNativeTokensSupplied_error_selector,
                InvalidBasicOrderParameterEncoding_error_length,
                InvalidBasicOrderParameterEncoding_error_selector,
                InvalidCallToConduit_error_conduit_ptr,
                InvalidCallToConduit_error_length,
                InvalidCallToConduit_error_selector,
                InvalidConduit_error_conduit_ptr,
                InvalidConduit_error_conduitKey_ptr,
                InvalidConduit_error_length,
                InvalidConduit_error_selector,
                InvalidContractOrder_error_length,
                InvalidContractOrder_error_orderHash_ptr,
                InvalidContractOrder_error_selector,
                InvalidERC721TransferAmount_error_amount_ptr,
                InvalidERC721TransferAmount_error_length,
                InvalidERC721TransferAmount_error_selector,
                InvalidMsgValue_error_length,
                InvalidMsgValue_error_selector,
                InvalidMsgValue_error_value_ptr,
                InvalidNativeOfferItem_error_length,
                InvalidNativeOfferItem_error_selector,
                InvalidProof_error_length,
                InvalidProof_error_selector,
                InvalidTime_error_endTime_ptr,
                InvalidTime_error_length,
                InvalidTime_error_selector,
                InvalidTime_error_startTime_ptr,
                MismatchedOfferAndConsiderationComponents_error_idx_ptr,
                MismatchedOfferAndConsiderationComponents_error_length,
                MismatchedOfferAndConsiderationComponents_error_selector,
                MissingFulfillmentComponentOnAggregation_error_length,
                MissingFulfillmentComponentOnAggregation_error_selector,
                MissingFulfillmentComponentOnAggregation_error_side_ptr,
                MissingOriginalConsiderationItems_error_length,
                MissingOriginalConsiderationItems_error_selector,
                NoReentrantCalls_error_length,
                NoReentrantCalls_error_selector,
                NoSpecifiedOrdersAvailable_error_length,
                NoSpecifiedOrdersAvailable_error_selector,
                OfferAndConsiderationRequiredOnFulfillment_error_length,
                OfferAndConsiderationRequiredOnFulfillment_error_selector,
                OrderAlreadyFilled_error_length,
                OrderAlreadyFilled_error_orderHash_ptr,
                OrderAlreadyFilled_error_selector,
                OrderCriteriaResolverOutOfRange_error_length,
                OrderCriteriaResolverOutOfRange_error_selector,
                OrderCriteriaResolverOutOfRange_error_side_ptr,
                OrderIsCancelled_error_length,
                OrderIsCancelled_error_orderHash_ptr,
                OrderIsCancelled_error_selector,
                OrderPartiallyFilled_error_length,
                OrderPartiallyFilled_error_orderHash_ptr,
                OrderPartiallyFilled_error_selector,
                PartialFillsNotEnabledForOrder_error_length,
                PartialFillsNotEnabledForOrder_error_selector,
                UnresolvedConsiderationCriteria_error_considerationIdx_ptr,
                UnresolvedConsiderationCriteria_error_length,
                UnresolvedConsiderationCriteria_error_orderIndex_ptr,
                UnresolvedConsiderationCriteria_error_selector,
                UnresolvedOfferCriteria_error_length,
                UnresolvedOfferCriteria_error_offerIndex_ptr,
                UnresolvedOfferCriteria_error_orderIndex_ptr,
                UnresolvedOfferCriteria_error_selector,
                UnusedItemParameters_error_length,
                UnusedItemParameters_error_selector
            } from "./ConsiderationErrorConstants.sol";
            /**
             * @dev Reverts the current transaction with a "BadFraction" error message.
             */
            function _revertBadFraction() pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, BadFraction_error_selector)
                    // revert(abi.encodeWithSignature("BadFraction()"))
                    revert(Error_selector_offset, BadFraction_error_length)
                }
            }
            /**
             * @dev Reverts the current transaction with a "ConsiderationNotMet" error
             *      message, including the provided order index, consideration index, and
             *      shortfall amount.
             *
             * @param orderIndex         The index of the order that did not meet the
             *                           consideration criteria.
             * @param considerationIndex The index of the consideration item that did not
             *                           meet its criteria.
             * @param shortfallAmount    The amount by which the consideration criteria were
             *                           not met.
             */
            function _revertConsiderationNotMet(
                uint256 orderIndex,
                uint256 considerationIndex,
                uint256 shortfallAmount
            ) pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, ConsiderationNotMet_error_selector)
                    // Store arguments.
                    mstore(ConsiderationNotMet_error_orderIndex_ptr, orderIndex)
                    mstore(
                        ConsiderationNotMet_error_considerationIndex_ptr,
                        considerationIndex
                    )
                    mstore(ConsiderationNotMet_error_shortfallAmount_ptr, shortfallAmount)
                    // revert(abi.encodeWithSignature(
                    //     "ConsiderationNotMet(uint256,uint256,uint256)",
                    //     orderIndex,
                    //     considerationIndex,
                    //     shortfallAmount
                    // ))
                    revert(Error_selector_offset, ConsiderationNotMet_error_length)
                }
            }
            /**
             * @dev Reverts the current transaction with a "CriteriaNotEnabledForItem" error
             *      message.
             */
            function _revertCriteriaNotEnabledForItem() pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, CriteriaNotEnabledForItem_error_selector)
                    // revert(abi.encodeWithSignature("CriteriaNotEnabledForItem()"))
                    revert(Error_selector_offset, CriteriaNotEnabledForItem_error_length)
                }
            }
            /**
             * @dev Reverts the current transaction with an
             *      "InsufficientNativeTokensSupplied" error message.
             */
            function _revertInsufficientNativeTokensSupplied() pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, InsufficientNativeTokensSupplied_error_selector)
                    // revert(abi.encodeWithSignature("InsufficientNativeTokensSupplied()"))
                    revert(
                        Error_selector_offset,
                        InsufficientNativeTokensSupplied_error_length
                    )
                }
            }
            /**
             * @dev Reverts the current transaction with an
             *      "InvalidBasicOrderParameterEncoding" error message.
             */
            function _revertInvalidBasicOrderParameterEncoding() pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, InvalidBasicOrderParameterEncoding_error_selector)
                    // revert(abi.encodeWithSignature(
                    //     "InvalidBasicOrderParameterEncoding()"
                    // ))
                    revert(
                        Error_selector_offset,
                        InvalidBasicOrderParameterEncoding_error_length
                    )
                }
            }
            /**
             * @dev Reverts the current transaction with an "InvalidCallToConduit" error
             *      message, including the provided address of the conduit that was called
             *      improperly.
             *
             * @param conduit The address of the conduit that was called improperly.
             */
            function _revertInvalidCallToConduit(address conduit) pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, InvalidCallToConduit_error_selector)
                    // Store argument.
                    mstore(InvalidCallToConduit_error_conduit_ptr, conduit)
                    // revert(abi.encodeWithSignature(
                    //     "InvalidCallToConduit(address)",
                    //     conduit
                    // ))
                    revert(Error_selector_offset, InvalidCallToConduit_error_length)
                }
            }
            /**
             * @dev Reverts the current transaction with an "CannotCancelOrder" error
             *      message.
             */
            function _revertCannotCancelOrder() pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, CannotCancelOrder_error_selector)
                    // revert(abi.encodeWithSignature("CannotCancelOrder()"))
                    revert(Error_selector_offset, CannotCancelOrder_error_length)
                }
            }
            /**
             * @dev Reverts the current transaction with an "InvalidConduit" error message,
             *      including the provided key and address of the invalid conduit.
             *
             * @param conduitKey    The key of the invalid conduit.
             * @param conduit       The address of the invalid conduit.
             */
            function _revertInvalidConduit(bytes32 conduitKey, address conduit) pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, InvalidConduit_error_selector)
                    // Store arguments.
                    mstore(InvalidConduit_error_conduitKey_ptr, conduitKey)
                    mstore(InvalidConduit_error_conduit_ptr, conduit)
                    // revert(abi.encodeWithSignature(
                    //     "InvalidConduit(bytes32,address)",
                    //     conduitKey,
                    //     conduit
                    // ))
                    revert(Error_selector_offset, InvalidConduit_error_length)
                }
            }
            /**
             * @dev Reverts the current transaction with an "InvalidERC721TransferAmount"
             *      error message.
             *
             * @param amount The invalid amount.
             */
            function _revertInvalidERC721TransferAmount(uint256 amount) pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, InvalidERC721TransferAmount_error_selector)
                    // Store argument.
                    mstore(InvalidERC721TransferAmount_error_amount_ptr, amount)
                    // revert(abi.encodeWithSignature(
                    //     "InvalidERC721TransferAmount(uint256)",
                    //     amount
                    // ))
                    revert(Error_selector_offset, InvalidERC721TransferAmount_error_length)
                }
            }
            /**
             * @dev Reverts the current transaction with an "InvalidMsgValue" error message,
             *      including the invalid value that was sent in the transaction's
             *      `msg.value` field.
             *
             * @param value The invalid value that was sent in the transaction's `msg.value`
             *              field.
             */
            function _revertInvalidMsgValue(uint256 value) pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, InvalidMsgValue_error_selector)
                    // Store argument.
                    mstore(InvalidMsgValue_error_value_ptr, value)
                    // revert(abi.encodeWithSignature("InvalidMsgValue(uint256)", value))
                    revert(Error_selector_offset, InvalidMsgValue_error_length)
                }
            }
            /**
             * @dev Reverts the current transaction with an "InvalidNativeOfferItem" error
             *      message.
             */
            function _revertInvalidNativeOfferItem() pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, InvalidNativeOfferItem_error_selector)
                    // revert(abi.encodeWithSignature("InvalidNativeOfferItem()"))
                    revert(Error_selector_offset, InvalidNativeOfferItem_error_length)
                }
            }
            /**
             * @dev Reverts the current transaction with an "InvalidProof" error message.
             */
            function _revertInvalidProof() pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, InvalidProof_error_selector)
                    // revert(abi.encodeWithSignature("InvalidProof()"))
                    revert(Error_selector_offset, InvalidProof_error_length)
                }
            }
            /**
             * @dev Reverts the current transaction with an "InvalidContractOrder" error
             *      message.
             *
             * @param orderHash The hash of the contract order that caused the error.
             */
            function _revertInvalidContractOrder(bytes32 orderHash) pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, InvalidContractOrder_error_selector)
                    // Store arguments.
                    mstore(InvalidContractOrder_error_orderHash_ptr, orderHash)
                    // revert(abi.encodeWithSignature(
                    //     "InvalidContractOrder(bytes32)",
                    //     orderHash
                    // ))
                    revert(Error_selector_offset, InvalidContractOrder_error_length)
                }
            }
            /**
             * @dev Reverts the current transaction with an "InvalidTime" error message.
             *
             * @param startTime       The time at which the order becomes active.
             * @param endTime         The time at which the order becomes inactive.
             */
            function _revertInvalidTime(uint256 startTime, uint256 endTime) pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, InvalidTime_error_selector)
                    // Store arguments.
                    mstore(InvalidTime_error_startTime_ptr, startTime)
                    mstore(InvalidTime_error_endTime_ptr, endTime)
                    // revert(abi.encodeWithSignature(
                    //     "InvalidTime(uint256,uint256)",
                    //     startTime,
                    //     endTime
                    // ))
                    revert(Error_selector_offset, InvalidTime_error_length)
                }
            }
            /**
             * @dev Reverts execution with a
             *      "MismatchedFulfillmentOfferAndConsiderationComponents" error message.
             *
             * @param fulfillmentIndex         The index of the fulfillment that caused the
             *                                 error.
             */
            function _revertMismatchedFulfillmentOfferAndConsiderationComponents(
                uint256 fulfillmentIndex
            ) pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, MismatchedOfferAndConsiderationComponents_error_selector)
                    // Store fulfillment index argument.
                    mstore(
                        MismatchedOfferAndConsiderationComponents_error_idx_ptr,
                        fulfillmentIndex
                    )
                    // revert(abi.encodeWithSignature(
                    //     "MismatchedFulfillmentOfferAndConsiderationComponents(uint256)",
                    //     fulfillmentIndex
                    // ))
                    revert(
                        Error_selector_offset,
                        MismatchedOfferAndConsiderationComponents_error_length
                    )
                }
            }
            /**
             * @dev Reverts execution with a "MissingFulfillmentComponentOnAggregation"
             *       error message.
             *
             * @param side The side of the fulfillment component that is missing (0 for
             *             offer, 1 for consideration).
             *
             */
            function _revertMissingFulfillmentComponentOnAggregation(Side side) pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, MissingFulfillmentComponentOnAggregation_error_selector)
                    // Store argument.
                    mstore(MissingFulfillmentComponentOnAggregation_error_side_ptr, side)
                    // revert(abi.encodeWithSignature(
                    //     "MissingFulfillmentComponentOnAggregation(uint8)",
                    //     side
                    // ))
                    revert(
                        Error_selector_offset,
                        MissingFulfillmentComponentOnAggregation_error_length
                    )
                }
            }
            /**
             * @dev Reverts execution with a "MissingOriginalConsiderationItems" error
             *      message.
             */
            function _revertMissingOriginalConsiderationItems() pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, MissingOriginalConsiderationItems_error_selector)
                    // revert(abi.encodeWithSignature(
                    //     "MissingOriginalConsiderationItems()"
                    // ))
                    revert(
                        Error_selector_offset,
                        MissingOriginalConsiderationItems_error_length
                    )
                }
            }
            /**
             * @dev Reverts execution with a "NoReentrantCalls" error message.
             */
            function _revertNoReentrantCalls() pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, NoReentrantCalls_error_selector)
                    // revert(abi.encodeWithSignature("NoReentrantCalls()"))
                    revert(Error_selector_offset, NoReentrantCalls_error_length)
                }
            }
            /**
             * @dev Reverts execution with a "NoSpecifiedOrdersAvailable" error message.
             */
            function _revertNoSpecifiedOrdersAvailable() pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, NoSpecifiedOrdersAvailable_error_selector)
                    // revert(abi.encodeWithSignature("NoSpecifiedOrdersAvailable()"))
                    revert(Error_selector_offset, NoSpecifiedOrdersAvailable_error_length)
                }
            }
            /**
             * @dev Reverts execution with a "OfferAndConsiderationRequiredOnFulfillment"
             *      error message.
             */
            function _revertOfferAndConsiderationRequiredOnFulfillment() pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, OfferAndConsiderationRequiredOnFulfillment_error_selector)
                    // revert(abi.encodeWithSignature(
                    //     "OfferAndConsiderationRequiredOnFulfillment()"
                    // ))
                    revert(
                        Error_selector_offset,
                        OfferAndConsiderationRequiredOnFulfillment_error_length
                    )
                }
            }
            /**
             * @dev Reverts execution with an "OrderAlreadyFilled" error message.
             *
             * @param orderHash The hash of the order that has already been filled.
             */
            function _revertOrderAlreadyFilled(bytes32 orderHash) pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, OrderAlreadyFilled_error_selector)
                    // Store argument.
                    mstore(OrderAlreadyFilled_error_orderHash_ptr, orderHash)
                    // revert(abi.encodeWithSignature(
                    //     "OrderAlreadyFilled(bytes32)",
                    //     orderHash
                    // ))
                    revert(Error_selector_offset, OrderAlreadyFilled_error_length)
                }
            }
            /**
             * @dev Reverts execution with an "OrderCriteriaResolverOutOfRange" error
             *      message.
             *
             * @param side The side of the criteria that is missing (0 for offer, 1 for
             *             consideration).
             *
             */
            function _revertOrderCriteriaResolverOutOfRange(Side side) pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, OrderCriteriaResolverOutOfRange_error_selector)
                    // Store argument.
                    mstore(OrderCriteriaResolverOutOfRange_error_side_ptr, side)
                    // revert(abi.encodeWithSignature(
                    //     "OrderCriteriaResolverOutOfRange(uint8)",
                    //     side
                    // ))
                    revert(
                        Error_selector_offset,
                        OrderCriteriaResolverOutOfRange_error_length
                    )
                }
            }
            /**
             * @dev Reverts execution with an "OrderIsCancelled" error message.
             *
             * @param orderHash The hash of the order that has already been cancelled.
             */
            function _revertOrderIsCancelled(bytes32 orderHash) pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, OrderIsCancelled_error_selector)
                    // Store argument.
                    mstore(OrderIsCancelled_error_orderHash_ptr, orderHash)
                    // revert(abi.encodeWithSignature(
                    //     "OrderIsCancelled(bytes32)",
                    //     orderHash
                    // ))
                    revert(Error_selector_offset, OrderIsCancelled_error_length)
                }
            }
            /**
             * @dev Reverts execution with an "OrderPartiallyFilled" error message.
             *
             * @param orderHash The hash of the order that has already been partially
             *                  filled.
             */
            function _revertOrderPartiallyFilled(bytes32 orderHash) pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, OrderPartiallyFilled_error_selector)
                    // Store argument.
                    mstore(OrderPartiallyFilled_error_orderHash_ptr, orderHash)
                    // revert(abi.encodeWithSignature(
                    //     "OrderPartiallyFilled(bytes32)",
                    //     orderHash
                    // ))
                    revert(Error_selector_offset, OrderPartiallyFilled_error_length)
                }
            }
            /**
             * @dev Reverts execution with a "PartialFillsNotEnabledForOrder" error message.
             */
            function _revertPartialFillsNotEnabledForOrder() pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, PartialFillsNotEnabledForOrder_error_selector)
                    // revert(abi.encodeWithSignature("PartialFillsNotEnabledForOrder()"))
                    revert(
                        Error_selector_offset,
                        PartialFillsNotEnabledForOrder_error_length
                    )
                }
            }
            /**
             * @dev Reverts execution with an "UnresolvedConsiderationCriteria" error
             *      message.
             */
            function _revertUnresolvedConsiderationCriteria(
                uint256 orderIndex,
                uint256 considerationIndex
            ) pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, UnresolvedConsiderationCriteria_error_selector)
                    // Store orderIndex and considerationIndex arguments.
                    mstore(UnresolvedConsiderationCriteria_error_orderIndex_ptr, orderIndex)
                    mstore(
                        UnresolvedConsiderationCriteria_error_considerationIdx_ptr,
                        considerationIndex
                    )
                    // revert(abi.encodeWithSignature(
                    //     "UnresolvedConsiderationCriteria(uint256, uint256)",
                    //     orderIndex,
                    //     considerationIndex
                    // ))
                    revert(
                        Error_selector_offset,
                        UnresolvedConsiderationCriteria_error_length
                    )
                }
            }
            /**
             * @dev Reverts execution with an "UnresolvedOfferCriteria" error message.
             */
            function _revertUnresolvedOfferCriteria(
                uint256 orderIndex,
                uint256 offerIndex
            ) pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, UnresolvedOfferCriteria_error_selector)
                    // Store arguments.
                    mstore(UnresolvedOfferCriteria_error_orderIndex_ptr, orderIndex)
                    mstore(UnresolvedOfferCriteria_error_offerIndex_ptr, offerIndex)
                    // revert(abi.encodeWithSignature(
                    //     "UnresolvedOfferCriteria(uint256, uint256)",
                    //     orderIndex,
                    //     offerIndex
                    // ))
                    revert(Error_selector_offset, UnresolvedOfferCriteria_error_length)
                }
            }
            /**
             * @dev Reverts execution with an "UnusedItemParameters" error message.
             */
            function _revertUnusedItemParameters() pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, UnusedItemParameters_error_selector)
                    // revert(abi.encodeWithSignature("UnusedItemParameters()"))
                    revert(Error_selector_offset, UnusedItemParameters_error_length)
                }
            }
            /**
             * @dev Reverts execution with a "ConsiderationLengthNotEqualToTotalOriginal"
             *      error message.
             */
            function _revertConsiderationLengthNotEqualToTotalOriginal() pure {
                assembly {
                    // Store left-padded selector with push4 (reduces bytecode),
                    // mem[28:32] = selector
                    mstore(0, ConsiderationLengthNotEqualToTotalOriginal_error_selector)
                    // revert(abi.encodeWithSignature(
                    //     "ConsiderationLengthNotEqualToTotalOriginal()"
                    // ))
                    revert(
                        Error_selector_offset,
                        ConsiderationLengthNotEqualToTotalOriginal_error_length
                    )
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.17;
            import {
                BasicOrderRouteType,
                ItemType,
                OrderType
            } from "./ConsiderationEnums.sol";
            import { BasicOrderParameters } from "./ConsiderationStructs.sol";
            import { OrderValidator } from "./OrderValidator.sol";
            import {
                _revertInsufficientNativeTokensSupplied,
                _revertInvalidMsgValue,
                _revertInvalidERC721TransferAmount,
                _revertUnusedItemParameters
            } from "./ConsiderationErrors.sol";
            import {
                AccumulatorDisarmed,
                AdditionalRecipient_size_shift,
                AdditionalRecipient_size,
                BasicOrder_additionalRecipients_data_cdPtr,
                BasicOrder_additionalRecipients_length_cdPtr,
                BasicOrder_basicOrderType_cdPtr,
                BasicOrder_common_params_size,
                BasicOrder_considerationAmount_cdPtr,
                BasicOrder_considerationHashesArray_ptr,
                BasicOrder_considerationIdentifier_cdPtr,
                BasicOrder_considerationItem_endAmount_ptr,
                BasicOrder_considerationItem_identifier_ptr,
                BasicOrder_considerationItem_itemType_ptr,
                BasicOrder_considerationItem_startAmount_ptr,
                BasicOrder_considerationItem_token_ptr,
                BasicOrder_considerationItem_typeHash_ptr,
                BasicOrder_considerationToken_cdPtr,
                BasicOrder_endTime_cdPtr,
                BasicOrder_fulfillerConduit_cdPtr,
                BasicOrder_offerAmount_cdPtr,
                BasicOrder_offeredItemByteMap,
                BasicOrder_offerer_cdPtr,
                BasicOrder_offererConduit_cdPtr,
                BasicOrder_offerIdentifier_cdPtr,
                BasicOrder_offerItem_endAmount_ptr,
                BasicOrder_offerItem_itemType_ptr,
                BasicOrder_offerItem_token_ptr,
                BasicOrder_offerItem_typeHash_ptr,
                BasicOrder_offerToken_cdPtr,
                BasicOrder_order_considerationHashes_ptr,
                BasicOrder_order_counter_ptr,
                BasicOrder_order_offerer_ptr,
                BasicOrder_order_offerHashes_ptr,
                BasicOrder_order_orderType_ptr,
                BasicOrder_order_startTime_ptr,
                BasicOrder_order_typeHash_ptr,
                BasicOrder_receivedItemByteMap,
                BasicOrder_startTime_cdPtr,
                BasicOrder_totalOriginalAdditionalRecipients_cdPtr,
                BasicOrder_zone_cdPtr,
                Common_token_offset,
                Conduit_execute_ConduitTransfer_length_ptr,
                Conduit_execute_ConduitTransfer_length,
                Conduit_execute_ConduitTransfer_offset_ptr,
                Conduit_execute_ConduitTransfer_ptr,
                Conduit_execute_signature,
                Conduit_execute_transferAmount_ptr,
                Conduit_execute_transferIdentifier_ptr,
                Conduit_execute_transferFrom_ptr,
                Conduit_execute_transferItemType_ptr,
                Conduit_execute_transferTo_ptr,
                Conduit_execute_transferToken_ptr,
                EIP712_ConsiderationItem_size,
                EIP712_OfferItem_size,
                EIP712_Order_size,
                FiveWords,
                FourWords,
                FreeMemoryPointerSlot,
                MaskOverLastTwentyBytes,
                OneConduitExecute_size,
                OneWord,
                OneWordShift,
                OrderFulfilled_baseOffset,
                OrderFulfilled_baseSize,
                OrderFulfilled_consideration_body_offset,
                OrderFulfilled_consideration_head_offset,
                OrderFulfilled_consideration_length_baseOffset,
                OrderFulfilled_fulfiller_offset,
                OrderFulfilled_offer_body_offset,
                OrderFulfilled_offer_head_offset,
                OrderFulfilled_offer_length_baseOffset,
                OrderFulfilled_selector,
                ReceivedItem_amount_offset,
                ReceivedItem_size,
                receivedItemsHash_ptr,
                ThreeWords,
                TwoWords,
                ZeroSlot
            } from "./ConsiderationConstants.sol";
            import {
                Error_selector_offset,
                InvalidBasicOrderParameterEncoding_error_length,
                InvalidBasicOrderParameterEncoding_error_selector,
                InvalidTime_error_endTime_ptr,
                InvalidTime_error_length,
                InvalidTime_error_selector,
                InvalidTime_error_startTime_ptr,
                MissingOriginalConsiderationItems_error_length,
                MissingOriginalConsiderationItems_error_selector,
                UnusedItemParameters_error_length,
                UnusedItemParameters_error_selector
            } from "./ConsiderationErrorConstants.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;
                    bytes32 orderHash;
                    // Utilize assembly to extract the order type and the basic order route.
                    assembly {
                        // Read basicOrderType from calldata.
                        let basicOrderType := calldataload(BasicOrder_basicOrderType_cdPtr)
                        // Mask all but 2 least-significant bits to derive the order type.
                        orderType := and(basicOrderType, 3)
                        // Divide basicOrderType by four to derive the route.
                        route := shr(2, basicOrderType)
                        // If route > 1 additionalRecipient items are ERC20 (1) else native
                        // token (0).
                        additionalRecipientsItemType := gt(route, 1)
                    }
                    {
                        // Declare temporary variable for enforcing payable status.
                        bool correctPayableStatus;
                        // Utilize assembly to compare the route to the callvalue.
                        assembly {
                            // route 0 and 1 are payable, otherwise route is not payable.
                            correctPayableStatus := eq(
                                additionalRecipientsItemType,
                                iszero(callvalue())
                            )
                        }
                        // Revert if msg.value has not been supplied as part of payable
                        // routes or has been supplied as part of non-payable routes.
                        if (!correctPayableStatus) {
                            _revertInvalidMsgValue(msg.value);
                        }
                    }
                    // Declare more arguments that will be derived from route and calldata.
                    address additionalRecipientsToken;
                    ItemType offeredItemType;
                    bool offerTypeIsAdditionalRecipientsType;
                    // Declare scope for received item type to manage stack pressure.
                    {
                        ItemType receivedItemType;
                        // Utilize assembly to retrieve function arguments and cast types.
                        assembly {
                            // Check if offered item type == additional recipient item type.
                            offerTypeIsAdditionalRecipientsType := gt(route, 3)
                            // If route > 3 additionalRecipientsToken is at 0xc4 else 0x24.
                            additionalRecipientsToken := calldataload(
                                add(
                                    BasicOrder_considerationToken_cdPtr,
                                    mul(
                                        offerTypeIsAdditionalRecipientsType,
                                        BasicOrder_common_params_size
                                    )
                                )
                            )
                            // If route > 2, receivedItemType is route - 2. If route is 2,
                            // the receivedItemType is ERC20 (1). Otherwise, it is native
                            // token (0).
                            receivedItemType := byte(route, BasicOrder_receivedItemByteMap)
                            // If route > 3, offeredItemType is ERC20 (1). Route is 2 or 3,
                            // offeredItemType = route. Route is 0 or 1, it is route + 2.
                            offeredItemType := byte(route, BasicOrder_offeredItemByteMap)
                        }
                        // Derive & validate order using parameters and update order status.
                        orderHash = _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,
                                shl(OneWordShift, offerTypeIsAdditionalRecipientsType)
                            )
                        )
                    }
                    // Transfer tokens based on the route.
                    if (additionalRecipientsItemType == ItemType.NATIVE) {
                        // Ensure neither consideration token nor identifier are set. Note
                        // that dirty upper bits in the consideration token will still cause
                        // this error to be thrown.
                        assembly {
                            if or(
                                calldataload(BasicOrder_considerationToken_cdPtr),
                                calldataload(BasicOrder_considerationIdentifier_cdPtr)
                            ) {
                                // Store left-padded selector with push4 (reduces bytecode),
                                // mem[28:32] = selector
                                mstore(0, UnusedItemParameters_error_selector)
                                // revert(abi.encodeWithSignature("UnusedItemParameters()"))
                                revert(
                                    Error_selector_offset,
                                    UnusedItemParameters_error_length
                                )
                            }
                        }
                        // Transfer the ERC721 or ERC1155 item, bypassing the accumulator.
                        _transferIndividual721Or1155Item(offeredItemType, conduitKey);
                        // Transfer native to recipients, return excess to caller & wrap up.
                        _transferNativeTokensAndFinalize();
                    } else {
                        // Initialize an accumulator array. From this point forward, no new
                        // memory regions can be safely allocated until the accumulator is
                        // no longer being utilized, as the accumulator operates in an
                        // open-ended fashion from this memory pointer; existing memory may
                        // still be accessed and modified, however.
                        bytes memory accumulator = new bytes(AccumulatorDisarmed);
                        // Choose transfer method for ERC721 or ERC1155 item based on route.
                        if (route == BasicOrderRouteType.ERC20_TO_ERC721) {
                            // Transfer ERC721 to caller using offerer's conduit preference.
                            _transferERC721(
                                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(
                            offerTypeIsAdditionalRecipientsType,
                            accumulator
                        );
                        // Trigger any remaining accumulated transfers via call to conduit.
                        _triggerIfArmed(accumulator);
                    }
                    // Determine whether order is restricted and, if so, that it is valid.
                    _assertRestrictedBasicOrderValidity(orderHash, orderType, parameters);
                    // Clear the reentrancy guard.
                    _clearReentrancyGuard();
                    return true;
                }
                /**
                 * @dev Internal function to prepare fulfillment of a basic order with
                 *      manual calldata and memory access. This calculates the order hash,
                 *      emits an OrderFulfilled event, and asserts basic order validity.
                 *      Note that calldata offsets must be validated as this function
                 *      accesses constant calldata pointers for dynamic types that match
                 *      default ABI encoding, but valid ABI encoding can use arbitrary
                 *      offsets. Checking that the offsets were produced by default encoding
                 *      will ensure that other functions using Solidity's calldata accessors
                 *      (which calculate pointers from the stored offsets) are reading the
                 *      same data as the order hash is derived from. Also note that this
                 *      function accesses memory directly.
                 *
                 * @param 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.
                 * @return orderHash The calculated order hash.
                 */
                function _prepareBasicFulfillmentFromCalldata(
                    BasicOrderParameters calldata parameters,
                    OrderType orderType,
                    ItemType receivedItemType,
                    ItemType additionalRecipientsItemType,
                    address additionalRecipientsToken,
                    ItemType offeredItemType
                ) internal returns (bytes32 orderHash) {
                    // Ensure this function cannot be triggered during a reentrant call.
                    _setReentrancyGuard(false); // Native tokens rejected during execution.
                    // Verify that calldata offsets for all dynamic types were produced by
                    // default encoding. This ensures that the constants used for calldata
                    // pointers to dynamic types are the same as those calculated by
                    // Solidity using their offsets. Also verify that the basic order type
                    // is within range.
                    _assertValidBasicOrderParameters();
                    // Check for invalid time and missing original consideration items.
                    // Utilize assembly so that constant calldata pointers can be applied.
                    assembly {
                        // Ensure current timestamp is between order start time & end time.
                        if or(
                            gt(calldataload(BasicOrder_startTime_cdPtr), timestamp()),
                            iszero(gt(calldataload(BasicOrder_endTime_cdPtr), timestamp()))
                        ) {
                            // Store left-padded selector with push4 (reduces bytecode),
                            // mem[28:32] = selector
                            mstore(0, InvalidTime_error_selector)
                            // Store arguments.
                            mstore(
                                InvalidTime_error_startTime_ptr,
                                calldataload(BasicOrder_startTime_cdPtr)
                            )
                            mstore(
                                InvalidTime_error_endTime_ptr,
                                calldataload(BasicOrder_endTime_cdPtr)
                            )
                            // revert(abi.encodeWithSignature(
                            //     "InvalidTime(uint256,uint256)",
                            //     startTime,
                            //     endTime
                            // ))
                            revert(Error_selector_offset, InvalidTime_error_length)
                        }
                        // Ensure consideration array length isn't less than total original.
                        if lt(
                            calldataload(BasicOrder_additionalRecipients_length_cdPtr),
                            calldataload(BasicOrder_totalOriginalAdditionalRecipients_cdPtr)
                        ) {
                            // Store left-padded selector with push4 (reduces bytecode),
                            // mem[28:32] = selector
                            mstore(0, MissingOriginalConsiderationItems_error_selector)
                            // revert(abi.encodeWithSignature(
                            //     "MissingOriginalConsiderationItems()"
                            // ))
                            revert(
                                Error_selector_offset,
                                MissingOriginalConsiderationItems_error_length
                            )
                        }
                    }
                    {
                        /**
                         * First, handle consideration items. Memory Layout:
                         *  0x60: final hash of the array of consideration item hashes
                         *  0x80-0x160: reused space for EIP712 hashing of each item
                         *   - 0x80: ConsiderationItem EIP-712 typehash (constant)
                         *   - 0xa0: itemType
                         *   - 0xc0: token
                         *   - 0xe0: identifier
                         *   - 0x100: startAmount
                         *   - 0x120: endAmount
                         *   - 0x140: recipient
                         *  0x160-END_ARR: array of consideration item hashes
                         *   - 0x160: primary consideration item EIP712 hash
                         *   - 0x180-END_ARR: additional recipient item EIP712 hashes
                         *  END_ARR: beginning of data for OrderFulfilled event
                         *   - END_ARR + 0x120: length of ReceivedItem array
                         *   - END_ARR + 0x140: beginning of data for first ReceivedItem
                         * (Note: END_ARR = 0x180 + RECIPIENTS_LENGTH * 0x20)
                         */
                        // Load consideration item typehash from runtime and place on stack.
                        bytes32 typeHash = _CONSIDERATION_ITEM_TYPEHASH;
                        // Utilize assembly to enable reuse of memory regions and use
                        // constant pointers when possible.
                        assembly {
                            /*
                             * 1. Calculate the EIP712 ConsiderationItem hash for the
                             * primary consideration item of the basic order.
                             */
                            // Write ConsiderationItem type hash and item type to memory.
                            mstore(BasicOrder_considerationItem_typeHash_ptr, typeHash)
                            mstore(
                                BasicOrder_considerationItem_itemType_ptr,
                                receivedItemType
                            )
                            // Copy calldata region with (token, identifier, amount) from
                            // BasicOrderParameters to ConsiderationItem. The
                            // considerationAmount is written to startAmount and endAmount
                            // as basic orders do not have dynamic amounts.
                            calldatacopy(
                                BasicOrder_considerationItem_token_ptr,
                                BasicOrder_considerationToken_cdPtr,
                                ThreeWords
                            )
                            // Copy calldata region with considerationAmount and offerer
                            // from BasicOrderParameters to endAmount and recipient in
                            // ConsiderationItem.
                            calldatacopy(
                                BasicOrder_considerationItem_endAmount_ptr,
                                BasicOrder_considerationAmount_cdPtr,
                                TwoWords
                            )
                            // Calculate EIP712 ConsiderationItem hash and store it in the
                            // array of EIP712 consideration hashes.
                            mstore(
                                BasicOrder_considerationHashesArray_ptr,
                                keccak256(
                                    BasicOrder_considerationItem_typeHash_ptr,
                                    EIP712_ConsiderationItem_size
                                )
                            )
                            /*
                             * 2. Write a ReceivedItem struct for the primary consideration
                             * item to the consideration array in OrderFulfilled.
                             */
                            // Get the 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,
                                shl(OneWordShift, totalAdditionalRecipients)
                            )
                            // Set the length of the consideration array to the number of
                            // additional recipients, plus one for the primary consideration
                            // item.
                            mstore(
                                eventConsiderationArrPtr,
                                add(totalAdditionalRecipients, 1)
                            )
                            // Overwrite the consideration array pointer so it points to the
                            // body of the first element
                            eventConsiderationArrPtr := add(
                                eventConsiderationArrPtr,
                                OneWord
                            )
                            // Set itemType at start of the ReceivedItem memory region.
                            mstore(eventConsiderationArrPtr, receivedItemType)
                            // Copy calldata region (token, identifier, amount & recipient)
                            // from BasicOrderParameters to ReceivedItem memory.
                            calldatacopy(
                                add(eventConsiderationArrPtr, Common_token_offset),
                                BasicOrder_considerationToken_cdPtr,
                                FourWords
                            )
                            /*
                             * 3. Calculate EIP712 ConsiderationItem hashes for original
                             * additional recipients and add a ReceivedItem for each to the
                             * consideration array in the OrderFulfilled event. The original
                             * additional recipients are all the consideration items signed
                             * by the offerer aside from the primary consideration items of
                             * the order. Uses memory region from 0x80-0x160 as a buffer for
                             * calculating EIP712 ConsiderationItem hashes.
                             */
                            // Put pointer to consideration hashes array on the stack.
                            // This will be updated as each additional recipient is hashed
                            let
                                considerationHashesPtr
                            := BasicOrder_considerationHashesArray_ptr
                            // Write item type, token, & identifier for additional recipient
                            // to memory region for hashing EIP712 ConsiderationItem; these
                            // values will be reused for each recipient.
                            mstore(
                                BasicOrder_considerationItem_itemType_ptr,
                                additionalRecipientsItemType
                            )
                            mstore(
                                BasicOrder_considerationItem_token_ptr,
                                additionalRecipientsToken
                            )
                            mstore(BasicOrder_considerationItem_identifier_ptr, 0)
                            // Declare a stack variable where all additional recipients will
                            // be combined to guard against providing dirty upper bits.
                            let combinedAdditionalRecipients
                            // Read length of the additionalRecipients array from calldata
                            // and iterate.
                            totalAdditionalRecipients := calldataload(
                                BasicOrder_totalOriginalAdditionalRecipients_cdPtr
                            )
                            let i := 0
                            for {} lt(i, totalAdditionalRecipients) {
                                i := add(i, 1)
                            } {
                                /*
                                 * Calculate EIP712 ConsiderationItem hash for recipient.
                                 */
                                // Retrieve calldata pointer for additional recipient.
                                let additionalRecipientCdPtr := add(
                                    BasicOrder_additionalRecipients_data_cdPtr,
                                    mul(AdditionalRecipient_size, i)
                                )
                                // Copy startAmount from calldata to the ConsiderationItem
                                // struct.
                                calldatacopy(
                                    BasicOrder_considerationItem_startAmount_ptr,
                                    additionalRecipientCdPtr,
                                    OneWord
                                )
                                // Copy endAmount and recipient from calldata to the
                                // ConsiderationItem struct.
                                calldatacopy(
                                    BasicOrder_considerationItem_endAmount_ptr,
                                    additionalRecipientCdPtr,
                                    AdditionalRecipient_size
                                )
                                // Include the recipient as part of combined recipients.
                                combinedAdditionalRecipients := or(
                                    combinedAdditionalRecipients,
                                    calldataload(add(additionalRecipientCdPtr, OneWord))
                                )
                                // Add 1 word to the pointer as part of each loop to reduce
                                // operations needed to get local offset into the array.
                                considerationHashesPtr := add(
                                    considerationHashesPtr,
                                    OneWord
                                )
                                // Calculate EIP712 ConsiderationItem hash and store it in
                                // the array of consideration hashes.
                                mstore(
                                    considerationHashesPtr,
                                    keccak256(
                                        BasicOrder_considerationItem_typeHash_ptr,
                                        EIP712_ConsiderationItem_size
                                    )
                                )
                                /*
                                 * Write ReceivedItem to OrderFulfilled data.
                                 */
                                // At this point, eventConsiderationArrPtr points to the
                                // beginning of the ReceivedItem struct of the previous
                                // element in the array. Increase it by the size of the
                                // struct to arrive at the pointer for the current element.
                                eventConsiderationArrPtr := add(
                                    eventConsiderationArrPtr,
                                    ReceivedItem_size
                                )
                                // Write itemType to the ReceivedItem struct.
                                mstore(
                                    eventConsiderationArrPtr,
                                    additionalRecipientsItemType
                                )
                                // Write token to the next word of the ReceivedItem struct.
                                mstore(
                                    add(eventConsiderationArrPtr, OneWord),
                                    additionalRecipientsToken
                                )
                                // Copy endAmount & recipient words to ReceivedItem struct.
                                calldatacopy(
                                    add(
                                        eventConsiderationArrPtr,
                                        ReceivedItem_amount_offset
                                    ),
                                    additionalRecipientCdPtr,
                                    TwoWords
                                )
                            }
                            /*
                             * 4. Hash packed array of ConsiderationItem EIP712 hashes:
                             *   `keccak256(abi.encodePacked(receivedItemHashes))`
                             * Note that it is set at 0x60 — all other memory begins at
                             * 0x80. 0x60 is the "zero slot" and will be restored at the end
                             * of the assembly section and before required by the compiler.
                             */
                            mstore(
                                receivedItemsHash_ptr,
                                keccak256(
                                    BasicOrder_considerationHashesArray_ptr,
                                    shl(OneWordShift, add(totalAdditionalRecipients, 1))
                                )
                            )
                            /*
                             * 5. Add a ReceivedItem for each tip to the consideration array
                             * in the OrderFulfilled event. The tips are all the
                             * consideration items that were not signed by the offerer and
                             * were provided by the fulfiller.
                             */
                            // Overwrite length to length of the additionalRecipients array.
                            totalAdditionalRecipients := calldataload(
                                BasicOrder_additionalRecipients_length_cdPtr
                            )
                            for {} lt(i, totalAdditionalRecipients) {
                                i := add(i, 1)
                            } {
                                // Retrieve calldata pointer for additional recipient.
                                let additionalRecipientCdPtr := add(
                                    BasicOrder_additionalRecipients_data_cdPtr,
                                    mul(AdditionalRecipient_size, i)
                                )
                                // At this point, eventConsiderationArrPtr points to the
                                // beginning of the ReceivedItem struct of the previous
                                // element in the array. Increase it by the size of the
                                // struct to arrive at the pointer for the current element.
                                eventConsiderationArrPtr := add(
                                    eventConsiderationArrPtr,
                                    ReceivedItem_size
                                )
                                // Write itemType to the ReceivedItem struct.
                                mstore(
                                    eventConsiderationArrPtr,
                                    additionalRecipientsItemType
                                )
                                // Write token to the next word of the ReceivedItem struct.
                                mstore(
                                    add(eventConsiderationArrPtr, OneWord),
                                    additionalRecipientsToken
                                )
                                // Copy endAmount & recipient words to ReceivedItem struct.
                                calldatacopy(
                                    add(
                                        eventConsiderationArrPtr,
                                        ReceivedItem_amount_offset
                                    ),
                                    additionalRecipientCdPtr,
                                    TwoWords
                                )
                                // Include the recipient as part of combined recipients.
                                combinedAdditionalRecipients := or(
                                    combinedAdditionalRecipients,
                                    calldataload(add(additionalRecipientCdPtr, OneWord))
                                )
                            }
                            // Ensure no dirty upper bits on combined additional recipients.
                            if gt(combinedAdditionalRecipients, MaskOverLastTwentyBytes) {
                                // Store left-padded selector with push4 (reduces bytecode),
                                // mem[28:32] = selector
                                mstore(0, InvalidBasicOrderParameterEncoding_error_selector)
                                // revert(abi.encodeWithSignature(
                                //     "InvalidBasicOrderParameterEncoding()"
                                // ))
                                revert(
                                    Error_selector_offset,
                                    InvalidBasicOrderParameterEncoding_error_length
                                )
                            }
                        }
                    }
                    {
                        /**
                         * Next, handle offered items. Memory Layout:
                         *  EIP712 data for OfferItem
                         *   - 0x80:  OfferItem EIP-712 typehash (constant)
                         *   - 0xa0:  itemType
                         *   - 0xc0:  token
                         *   - 0xe0:  identifier (reused for offeredItemsHash)
                         *   - 0x100: startAmount
                         *   - 0x120: endAmount
                         */
                        // Place offer item typehash on the stack.
                        bytes32 typeHash = _OFFER_ITEM_TYPEHASH;
                        // Utilize assembly to enable reuse of memory regions when possible.
                        assembly {
                            /*
                             * 1. Calculate OfferItem EIP712 hash
                             */
                            // Write the OfferItem typeHash to memory.
                            mstore(BasicOrder_offerItem_typeHash_ptr, typeHash)
                            // Write the OfferItem item type to memory.
                            mstore(BasicOrder_offerItem_itemType_ptr, offeredItemType)
                            // Copy calldata region with (offerToken, offerIdentifier,
                            // offerAmount) from OrderParameters to (token, identifier,
                            // startAmount) in OfferItem struct. The offerAmount is written
                            // to startAmount and endAmount as basic orders do not have
                            // dynamic amounts.
                            calldatacopy(
                                BasicOrder_offerItem_token_ptr,
                                BasicOrder_offerToken_cdPtr,
                                ThreeWords
                            )
                            // Copy offerAmount from calldata to endAmount in OfferItem
                            // struct.
                            calldatacopy(
                                BasicOrder_offerItem_endAmount_ptr,
                                BasicOrder_offerAmount_cdPtr,
                                OneWord
                            )
                            // Compute EIP712 OfferItem hash, write result to scratch space:
                            //   `keccak256(abi.encode(offeredItem))`
                            mstore(
                                0,
                                keccak256(
                                    BasicOrder_offerItem_typeHash_ptr,
                                    EIP712_OfferItem_size
                                )
                            )
                            /*
                             * 2. Calculate hash of array of EIP712 hashes and write the
                             * result to the corresponding OfferItem struct:
                             *   `keccak256(abi.encodePacked(offerItemHashes))`
                             */
                            mstore(BasicOrder_order_offerHashes_ptr, keccak256(0, OneWord))
                            /*
                             * 3. Write SpentItem to offer array in OrderFulfilled event.
                             */
                            let eventConsiderationArrPtr := add(
                                OrderFulfilled_offer_length_baseOffset,
                                shl(
                                    OneWordShift,
                                    calldataload(
                                        BasicOrder_additionalRecipients_length_cdPtr
                                    )
                                )
                            )
                            // 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, AdditionalRecipient_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,
                            shl(
                                OneWordShift,
                                calldataload(BasicOrder_additionalRecipients_length_cdPtr)
                            )
                        )
                        // Write the order hash to the head of the event's data region.
                        mstore(eventDataPtr, orderHash)
                        // Write the fulfiller (i.e. the caller) next for receiver argument.
                        mstore(add(eventDataPtr, OrderFulfilled_fulfiller_offset), caller())
                        // Write the SpentItem and ReceivedItem array offsets (constants).
                        mstore(
                            // SpentItem array offset
                            add(eventDataPtr, OrderFulfilled_offer_head_offset),
                            OrderFulfilled_offer_body_offset
                        )
                        mstore(
                            // ReceivedItem array offset
                            add(eventDataPtr, OrderFulfilled_consideration_head_offset),
                            OrderFulfilled_consideration_body_offset
                        )
                        // 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)
                        // Update the free memory pointer so that event data is persisted.
                        mstore(FreeMemoryPointerSlot, add(eventDataPtr, dataSize))
                    }
                    // Verify and update the status of the derived order.
                    _validateBasicOrderAndUpdateStatus(orderHash, parameters.signature);
                    // Return the derived order hash.
                    return orderHash;
                }
                /**
                 * @dev Internal function to transfer an individual ERC721 or ERC1155 item
                 *      from a given originator to a given recipient. The accumulator will
                 *      be bypassed, meaning that this function should be utilized in cases
                 *      where multiple item transfers can be accumulated into a single
                 *      conduit call. Sufficient approvals must be set, either on the
                 *      respective conduit or on this contract. Note that this function may
                 *      only be safely called as part of basic orders, as it assumes a
                 *      specific calldata encoding structure that must first be validated.
                 *
                 * @param itemType   The type of item to transfer, either ERC721 or ERC1155.
                 * @param conduitKey A bytes32 value indicating what corresponding conduit,
                 *                   if any, to source token approvals from. The zero hash
                 *                   signifies that no conduit should be used, with direct
                 *                   approvals set on this contract.
                 */
                function _transferIndividual721Or1155Item(
                    ItemType itemType,
                    bytes32 conduitKey
                ) internal {
                    // Retrieve token, from, identifier, and amount from calldata using
                    // fixed calldata offsets based on strict basic parameter encoding.
                    address token;
                    address from;
                    uint256 identifier;
                    uint256 amount;
                    assembly {
                        token := calldataload(BasicOrder_offerToken_cdPtr)
                        from := calldataload(BasicOrder_offerer_cdPtr)
                        identifier := calldataload(BasicOrder_offerIdentifier_cdPtr)
                        amount := calldataload(BasicOrder_offerAmount_cdPtr)
                    }
                    // Determine if the transfer is to be performed via a conduit.
                    if (conduitKey != bytes32(0)) {
                        // Use free memory pointer as calldata offset for the conduit call.
                        uint256 callDataOffset;
                        // Utilize assembly to place each argument in free memory.
                        assembly {
                            // Retrieve the free memory pointer and use it as the offset.
                            callDataOffset := mload(FreeMemoryPointerSlot)
                            // Write ConduitInterface.execute.selector to memory.
                            mstore(callDataOffset, Conduit_execute_signature)
                            // Write the offset to the ConduitTransfer array in memory.
                            mstore(
                                add(
                                    callDataOffset,
                                    Conduit_execute_ConduitTransfer_offset_ptr
                                ),
                                Conduit_execute_ConduitTransfer_ptr
                            )
                            // Write the length of the ConduitTransfer array to memory.
                            mstore(
                                add(
                                    callDataOffset,
                                    Conduit_execute_ConduitTransfer_length_ptr
                                ),
                                Conduit_execute_ConduitTransfer_length
                            )
                            // Write the item type to memory.
                            mstore(
                                add(callDataOffset, Conduit_execute_transferItemType_ptr),
                                itemType
                            )
                            // Write the token to memory.
                            mstore(
                                add(callDataOffset, Conduit_execute_transferToken_ptr),
                                token
                            )
                            // Write the transfer source to memory.
                            mstore(
                                add(callDataOffset, Conduit_execute_transferFrom_ptr),
                                from
                            )
                            // Write the transfer recipient (the caller) to memory.
                            mstore(
                                add(callDataOffset, Conduit_execute_transferTo_ptr),
                                caller()
                            )
                            // Write the token identifier to memory.
                            mstore(
                                add(callDataOffset, Conduit_execute_transferIdentifier_ptr),
                                identifier
                            )
                            // Write the transfer amount to memory.
                            mstore(
                                add(callDataOffset, Conduit_execute_transferAmount_ptr),
                                amount
                            )
                        }
                        // Perform the call to the conduit.
                        _callConduitUsingOffsets(
                            conduitKey,
                            callDataOffset,
                            OneConduitExecute_size
                        );
                    } else {
                        // Otherwise, determine whether it is an ERC721 or ERC1155 item.
                        if (itemType == ItemType.ERC721) {
                            // Ensure that exactly one 721 item is being transferred.
                            if (amount != 1) {
                                _revertInvalidERC721TransferAmount(amount);
                            }
                            // Perform transfer to caller via the token contract directly.
                            _performERC721Transfer(token, from, msg.sender, identifier);
                        } else {
                            // Perform transfer to caller via the token contract directly.
                            _performERC1155Transfer(
                                token,
                                from,
                                msg.sender,
                                identifier,
                                amount
                            );
                        }
                    }
                }
                /**
                 * @dev Internal function to transfer Ether (or other native tokens) to a
                 *      given recipient as part of basic order fulfillment. Note that
                 *      conduits are not utilized for native tokens as the transferred
                 *      amount must be provided as msg.value. Also note that this function
                 *      may only be safely called as part of basic orders, as it assumes a
                 *      specific calldata encoding structure that must first be validated.
                 */
                function _transferNativeTokensAndFinalize() internal {
                    // Put native token value supplied by the caller on the stack.
                    uint256 nativeTokensRemaining = msg.value;
                    // Retrieve consideration amount, offerer, and total size of additional
                    // recipients data from calldata using fixed offsets and place on stack.
                    uint256 amount;
                    address payable to;
                    uint256 totalAdditionalRecipientsDataSize;
                    assembly {
                        amount := calldataload(BasicOrder_considerationAmount_cdPtr)
                        to := calldataload(BasicOrder_offerer_cdPtr)
                        totalAdditionalRecipientsDataSize := shl(
                            AdditionalRecipient_size_shift,
                            calldataload(BasicOrder_additionalRecipients_length_cdPtr)
                        )
                    }
                    uint256 additionalRecipientAmount;
                    address payable recipient;
                    // Skip overflow check as for loop is indexed starting at zero.
                    unchecked {
                        // Iterate over additional recipient data by two-word element.
                        for (
                            uint256 i = 0;
                            i < totalAdditionalRecipientsDataSize;
                            i += AdditionalRecipient_size
                        ) {
                            assembly {
                                // Retrieve calldata pointer for additional recipient.
                                let additionalRecipientCdPtr := add(
                                    BasicOrder_additionalRecipients_data_cdPtr,
                                    i
                                )
                                additionalRecipientAmount := calldataload(
                                    additionalRecipientCdPtr
                                )
                                recipient := calldataload(
                                    add(OneWord, additionalRecipientCdPtr)
                                )
                            }
                            // Ensure that sufficient native tokens are available.
                            if (additionalRecipientAmount > nativeTokensRemaining) {
                                _revertInsufficientNativeTokensSupplied();
                            }
                            // Reduce native token value available. Skip underflow check as
                            // subtracted value is confirmed above as less than remaining.
                            nativeTokensRemaining -= additionalRecipientAmount;
                            // Transfer native tokens to the additional recipient.
                            _transferNativeTokens(recipient, additionalRecipientAmount);
                        }
                    }
                    // Ensure that sufficient native tokens are still available.
                    if (amount > nativeTokensRemaining) {
                        _revertInsufficientNativeTokensSupplied();
                    }
                    // Transfer native tokens to the offerer.
                    _transferNativeTokens(to, amount);
                    // If any native tokens remain after transfers, return to the caller.
                    if (nativeTokensRemaining > amount) {
                        // Skip underflow check as nativeTokensRemaining > amount.
                        unchecked {
                            // Transfer remaining native tokens to the caller.
                            _transferNativeTokens(
                                payable(msg.sender),
                                nativeTokensRemaining - amount
                            );
                        }
                    }
                }
                /**
                 * @dev Internal function to transfer ERC20 tokens to a given recipient as
                 *      part of basic order fulfillment. Note that this function may only be
                 *      safely called as part of basic orders, as it assumes a specific
                 *      calldata encoding structure that must first be validated. Also note
                 *      that basic order parameters are retrieved using fixed offsets, this
                 *      requires that strict basic order encoding has already been verified.
                 *
                 * @param fromOfferer A boolean indicating whether to decrement amount from
                 *                    the offered amount.
                 * @param accumulator An open-ended array that collects transfers to execute
                 *                    against a given conduit in a single call.
                 */
                function _transferERC20AndFinalize(
                    bool fromOfferer,
                    bytes memory accumulator
                ) internal {
                    // Declare from and to variables determined by fromOfferer value.
                    address from;
                    address to;
                    // Declare token and amount variables determined by fromOfferer value.
                    address token;
                    uint256 amount;
                    // Declare and check identifier variable within an isolated scope.
                    {
                        // Declare identifier variable determined by fromOfferer value.
                        uint256 identifier;
                        // Set ERC20 token transfer variables based on fromOfferer boolean.
                        if (fromOfferer) {
                            // Use offerer as from value, msg.sender as to value, and offer
                            // token, identifier, & amount values if token is from offerer.
                            assembly {
                                from := calldataload(BasicOrder_offerer_cdPtr)
                                to := caller()
                                token := calldataload(BasicOrder_offerToken_cdPtr)
                                identifier := calldataload(BasicOrder_offerIdentifier_cdPtr)
                                amount := calldataload(BasicOrder_offerAmount_cdPtr)
                            }
                        } else {
                            // Otherwise, use msg.sender as from value, offerer as to value,
                            // and consideration token, identifier, and amount values.
                            assembly {
                                from := caller()
                                to := calldataload(BasicOrder_offerer_cdPtr)
                                token := calldataload(BasicOrder_considerationToken_cdPtr)
                                identifier := calldataload(
                                    BasicOrder_considerationIdentifier_cdPtr
                                )
                                amount := calldataload(BasicOrder_considerationAmount_cdPtr)
                            }
                        }
                        // Ensure that no identifier is supplied.
                        if (identifier != 0) {
                            _revertUnusedItemParameters();
                        }
                    }
                    // Determine the appropriate conduit to utilize.
                    bytes32 conduitKey;
                    // Utilize assembly to derive conduit (if relevant) based on route.
                    assembly {
                        // Use offerer conduit if fromOfferer, fulfiller conduit otherwise.
                        conduitKey := calldataload(
                            sub(
                                BasicOrder_fulfillerConduit_cdPtr,
                                shl(OneWordShift, fromOfferer)
                            )
                        )
                    }
                    // Retrieve total size of additional recipients data and place on stack.
                    uint256 totalAdditionalRecipientsDataSize;
                    assembly {
                        totalAdditionalRecipientsDataSize := shl(
                            AdditionalRecipient_size_shift,
                            calldataload(BasicOrder_additionalRecipients_length_cdPtr)
                        )
                    }
                    uint256 additionalRecipientAmount;
                    address recipient;
                    // Iterate over each additional recipient.
                    for (uint256 i = 0; i < totalAdditionalRecipientsDataSize; ) {
                        assembly {
                            // Retrieve calldata pointer for additional recipient.
                            let additionalRecipientCdPtr := add(
                                BasicOrder_additionalRecipients_data_cdPtr,
                                i
                            )
                            additionalRecipientAmount := calldataload(
                                additionalRecipientCdPtr
                            )
                            recipient := calldataload(
                                add(OneWord, additionalRecipientCdPtr)
                            )
                        }
                        // Decrement the amount to transfer to fulfiller if indicated.
                        if (fromOfferer) {
                            amount -= additionalRecipientAmount;
                        }
                        // Transfer ERC20 tokens to additional recipient given approval.
                        _transferERC20(
                            token,
                            from,
                            recipient,
                            additionalRecipientAmount,
                            conduitKey,
                            accumulator
                        );
                        // Skip overflow check as for loop is indexed starting at zero.
                        unchecked {
                            i += AdditionalRecipient_size;
                        }
                    }
                    // Transfer ERC20 token amount (from account must have proper approval).
                    _transferERC20(token, from, to, amount, conduitKey, accumulator);
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.17;
            import { ItemType, Side } from "./ConsiderationEnums.sol";
            import {
                AdvancedOrder,
                CriteriaResolver,
                MemoryPointer,
                OfferItem,
                OrderParameters
            } from "./ConsiderationStructs.sol";
            import {
                _revertCriteriaNotEnabledForItem,
                _revertInvalidProof,
                _revertOrderCriteriaResolverOutOfRange,
                _revertUnresolvedConsiderationCriteria,
                _revertUnresolvedOfferCriteria
            } from "./ConsiderationErrors.sol";
            import {
                CriteriaResolutionErrors
            } from "../interfaces/CriteriaResolutionErrors.sol";
            import {
                OneWord,
                OneWordShift,
                OrderParameters_consideration_head_offset,
                Selector_length,
                TwoWords
            } from "./ConsiderationConstants.sol";
            import {
                ConsiderationCriteriaResolverOutOfRange_err_selector,
                Error_selector_offset,
                OfferCriteriaResolverOutOfRange_error_selector
            } from "./ConsiderationErrorConstants.sol";
            /**
             * @title CriteriaResolution
             * @author 0age
             * @notice CriteriaResolution contains a collection of pure functions related to
             *         resolving criteria-based items.
             */
            contract CriteriaResolution is CriteriaResolutionErrors {
                /**
                 * @dev Internal pure function to apply criteria resolvers containing
                 *      specific token identifiers and associated proofs to order items.
                 *
                 * @param advancedOrders     The orders to apply criteria resolvers to.
                 * @param criteriaResolvers  An array where each element contains a
                 *                           reference to a specific order as well as that
                 *                           order's offer or consideration, a token
                 *                           identifier, and a proof that the supplied token
                 *                           identifier is contained in the order's merkle
                 *                           root. Note that a root of zero indicates that
                 *                           any transferable token identifier is valid and
                 *                           that no proof needs to be supplied.
                 */
                function _applyCriteriaResolvers(
                    AdvancedOrder[] memory advancedOrders,
                    CriteriaResolver[] memory criteriaResolvers
                ) internal pure {
                    // Skip overflow checks as all for loops are indexed starting at zero.
                    unchecked {
                        // Retrieve length of criteria resolvers array and place on stack.
                        uint256 totalCriteriaResolvers = criteriaResolvers.length;
                        // Retrieve length of orders array and place on stack.
                        uint256 totalAdvancedOrders = advancedOrders.length;
                        // Iterate over each criteria resolver.
                        for (uint256 i = 0; i < totalCriteriaResolvers; ++i) {
                            // Retrieve the criteria resolver.
                            CriteriaResolver memory criteriaResolver = (
                                criteriaResolvers[i]
                            );
                            // Read the order index from memory and place it on the stack.
                            uint256 orderIndex = criteriaResolver.orderIndex;
                            // Ensure that the order index is in range.
                            if (orderIndex >= totalAdvancedOrders) {
                                _revertOrderCriteriaResolverOutOfRange(
                                    criteriaResolver.side
                                );
                            }
                            // Retrieve the referenced advanced order.
                            AdvancedOrder memory advancedOrder = advancedOrders[orderIndex];
                            // Skip criteria resolution for order if not fulfilled.
                            if (advancedOrder.numerator == 0) {
                                continue;
                            }
                            // Retrieve the parameters for the order.
                            OrderParameters memory orderParameters = (
                                advancedOrder.parameters
                            );
                            {
                                // Get a pointer to the list of items to give to
                                // _updateCriteriaItem. If the resolver refers to a
                                // consideration item, this array pointer will be replaced
                                // with the consideration array.
                                OfferItem[] memory items = orderParameters.offer;
                                // Read component index from memory and place it on stack.
                                uint256 componentIndex = criteriaResolver.index;
                                // Get error selector for `OfferCriteriaResolverOutOfRange`.
                                uint256 errorSelector = (
                                    OfferCriteriaResolverOutOfRange_error_selector
                                );
                                // If the resolver refers to a consideration item...
                                if (criteriaResolver.side != Side.OFFER) {
                                    // Get the pointer to `orderParameters.consideration`
                                    // Using the array directly has a significant impact on
                                    // the optimized compiler output.
                                    MemoryPointer considerationPtr = orderParameters
                                        .toMemoryPointer()
                                        .pptr(OrderParameters_consideration_head_offset);
                                    // Replace the items pointer with a pointer to the
                                    // consideration array.
                                    assembly {
                                        items := considerationPtr
                                    }
                                    // Replace the error selector with the selector for
                                    // `ConsiderationCriteriaResolverOutOfRange`.
                                    errorSelector = (
                                        ConsiderationCriteriaResolverOutOfRange_err_selector
                                    );
                                }
                                // Ensure that the component index is in range.
                                if (componentIndex >= items.length) {
                                    assembly {
                                        // Revert with either
                                        // `OfferCriteriaResolverOutOfRange()` or
                                        // `ConsiderationCriteriaResolverOutOfRange()`,
                                        // depending on whether the resolver refers to a
                                        // consideration item.
                                        mstore(0, errorSelector)
                                        // revert(abi.encodeWithSignature(
                                        //    "OfferCriteriaResolverOutOfRange()"
                                        // ))
                                        // or
                                        // revert(abi.encodeWithSignature(
                                        //    "ConsiderationCriteriaResolverOutOfRange()"
                                        // ))
                                        revert(Error_selector_offset, Selector_length)
                                    }
                                }
                                // Apply the criteria resolver to the item in question.
                                _updateCriteriaItem(
                                    items,
                                    componentIndex,
                                    criteriaResolver
                                );
                            }
                        }
                        // Iterate over each advanced order.
                        for (uint256 i = 0; i < totalAdvancedOrders; ++i) {
                            // Retrieve the advanced order.
                            AdvancedOrder memory advancedOrder = advancedOrders[i];
                            // Skip criteria resolution for order if not fulfilled.
                            if (advancedOrder.numerator == 0) {
                                continue;
                            }
                            // Retrieve the parameters for the order.
                            OrderParameters memory orderParameters = (
                                advancedOrder.parameters
                            );
                            // 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
                                    )
                                ) {
                                    _revertUnresolvedConsiderationCriteria(i, j);
                                }
                            }
                            // 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)
                                ) {
                                    _revertUnresolvedOfferCriteria(i, j);
                                }
                            }
                        }
                    }
                }
                /**
                 * @dev Internal pure function to update a criteria item.
                 *
                 * @param offer             The offer containing the item to update.
                 * @param componentIndex    The index of the item to update.
                 * @param criteriaResolver  The criteria resolver to use to update the item.
                 */
                function _updateCriteriaItem(
                    OfferItem[] memory offer,
                    uint256 componentIndex,
                    CriteriaResolver memory criteriaResolver
                ) internal pure {
                    // Retrieve relevant item using the component index.
                    OfferItem memory offerItem = offer[componentIndex];
                    // Read item type and criteria from memory & place on stack.
                    ItemType itemType = offerItem.itemType;
                    // Ensure the specified item type indicates criteria usage.
                    if (!_isItemWithCriteria(itemType)) {
                        _revertCriteriaNotEnabledForItem();
                    }
                    uint256 identifierOrCriteria = offerItem.identifierOrCriteria;
                    // If criteria is not 0 (i.e. a collection-wide criteria-based item)...
                    if (identifierOrCriteria != uint256(0)) {
                        // Verify identifier inclusion in criteria root using proof.
                        _verifyProof(
                            criteriaResolver.identifier,
                            identifierOrCriteria,
                            criteriaResolver.criteriaProof
                        );
                    } else if (criteriaResolver.criteriaProof.length != 0) {
                        // Revert if non-empty proof is supplied for a collection-wide item.
                        _revertInvalidProof();
                    }
                    // Update item type to remove criteria usage.
                    // Use assembly to operate on ItemType enum as a number.
                    ItemType newItemType;
                    assembly {
                        // Item type 4 becomes 2 and item type 5 becomes 3.
                        newItemType := sub(3, eq(itemType, 4))
                    }
                    offerItem.itemType = newItemType;
                    // Update identifier w/ supplied identifier.
                    offerItem.identifierOrCriteria = criteriaResolver.identifier;
                }
                /**
                 * @dev Internal pure function to check whether a given item type represents
                 *      a criteria-based ERC721 or ERC1155 item (e.g. an item that can be
                 *      resolved to one of a number of different identifiers at the time of
                 *      order fulfillment).
                 *
                 * @param itemType The item type in question.
                 *
                 * @return withCriteria A boolean indicating that the item type in question
                 *                      represents a criteria-based item.
                 */
                function _isItemWithCriteria(
                    ItemType itemType
                ) internal pure returns (bool withCriteria) {
                    // ERC721WithCriteria is ItemType 4. ERC1155WithCriteria is ItemType 5.
                    assembly {
                        withCriteria := gt(itemType, 3)
                    }
                }
                /**
                 * @dev Internal pure function to ensure that a given element is contained
                 *      in a merkle root via a supplied proof.
                 *
                 * @param leaf  The element for which to prove inclusion.
                 * @param root  The merkle root that inclusion will be proved against.
                 * @param proof The merkle proof.
                 */
                function _verifyProof(
                    uint256 leaf,
                    uint256 root,
                    bytes32[] memory proof
                ) internal pure {
                    // Declare a variable that will be used to determine proof validity.
                    bool isValid;
                    // Utilize assembly to efficiently verify the proof against the root.
                    assembly {
                        // Store the leaf at the beginning of scratch space.
                        mstore(0, leaf)
                        // Derive the hash of the leaf to use as the initial proof element.
                        let computedHash := keccak256(0, OneWord)
                        // Get memory start location of the first element in proof array.
                        let data := add(proof, OneWord)
                        // Iterate over each proof element to compute the root hash.
                        for {
                            // Left shift by 5 is equivalent to multiplying by 0x20.
                            let end := add(data, shl(OneWordShift, mload(proof)))
                        } lt(data, end) {
                            // Increment by one word at a time.
                            data := add(data, OneWord)
                        } {
                            // Get the proof element.
                            let loadedData := mload(data)
                            // Sort proof elements and place them in scratch space.
                            // Slot of `computedHash` in scratch space.
                            // If the condition is true: 0x20, otherwise: 0x00.
                            let scratch := shl(OneWordShift, gt(computedHash, loadedData))
                            // Store elements to hash contiguously in scratch space. Scratch
                            // space is 64 bytes (0x00 - 0x3f) & both elements are 32 bytes.
                            mstore(scratch, computedHash)
                            mstore(xor(scratch, OneWord), loadedData)
                            // Derive the updated hash.
                            computedHash := keccak256(0, TwoWords)
                        }
                        // Compare the final hash to the supplied root.
                        isValid := eq(computedHash, root)
                    }
                    // Revert if computed hash does not equal supplied root.
                    if (!isValid) {
                        _revertInvalidProof();
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.17;
            import {
                AmountDerivationErrors
            } from "../interfaces/AmountDerivationErrors.sol";
            import {
                Error_selector_offset,
                InexactFraction_error_length,
                InexactFraction_error_selector
            } from "./ConsiderationErrorConstants.sol";
            /**
             * @title AmountDeriver
             * @author 0age
             * @notice AmountDeriver contains view and pure functions related to deriving
             *         item amounts based on partial fill quantity and on linear
             *         interpolation based on current time when the start amount and end
             *         amount differ.
             */
            contract AmountDeriver is AmountDerivationErrors {
                /**
                 * @dev Internal view function to derive the current amount of a given item
                 *      based on the current price, the starting price, and the ending
                 *      price. If the start and end prices differ, the current price will be
                 *      interpolated on a linear basis. Note that this function expects that
                 *      the startTime parameter of orderParameters is not greater than the
                 *      current block timestamp and that the endTime parameter is greater
                 *      than the current block timestamp. If this condition is not upheld,
                 *      duration / elapsed / remaining variables will underflow.
                 *
                 * @param startAmount The starting amount of the item.
                 * @param endAmount   The ending amount of the item.
                 * @param startTime   The starting time of the order.
                 * @param endTime     The end time of the order.
                 * @param roundUp     A boolean indicating whether the resultant amount
                 *                    should be rounded up or down.
                 *
                 * @return amount The current amount.
                 */
                function _locateCurrentAmount(
                    uint256 startAmount,
                    uint256 endAmount,
                    uint256 startTime,
                    uint256 endTime,
                    bool roundUp
                ) internal view returns (uint256 amount) {
                    // Only modify end amount if it doesn't already equal start amount.
                    if (startAmount != endAmount) {
                        // Declare variables to derive in the subsequent unchecked scope.
                        uint256 duration;
                        uint256 elapsed;
                        uint256 remaining;
                        // Skip underflow checks as startTime <= block.timestamp < endTime.
                        unchecked {
                            // Derive the duration for the order and place it on the stack.
                            duration = endTime - startTime;
                            // Derive time elapsed since the order started & place on stack.
                            elapsed = block.timestamp - startTime;
                            // Derive time remaining until order expires and place on stack.
                            remaining = duration - elapsed;
                        }
                        // Aggregate new amounts weighted by time with rounding factor.
                        uint256 totalBeforeDivision = ((startAmount * remaining) +
                            (endAmount * elapsed));
                        // Use assembly to combine operations and skip divide-by-zero check.
                        assembly {
                            // Multiply by iszero(iszero(totalBeforeDivision)) to ensure
                            // amount is set to zero if totalBeforeDivision is zero,
                            // as intermediate overflow can occur if it is zero.
                            amount := mul(
                                iszero(iszero(totalBeforeDivision)),
                                // Subtract 1 from the numerator and add 1 to the result if
                                // roundUp is true to get 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) {
                            // Store left-padded selector with push4, mem[28:32] = selector
                            mstore(0, InexactFraction_error_selector)
                            // revert(abi.encodeWithSignature("InexactFraction()"))
                            revert(Error_selector_offset, InexactFraction_error_length)
                        }
                    }
                    // Multiply the numerator by the value and ensure no overflow occurs.
                    uint256 valueTimesNumerator = value * numerator;
                    // Divide 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.17;
            import { OrderType } from "./ConsiderationEnums.sol";
            import {
                AdvancedOrder,
                ConsiderationItem,
                OfferItem,
                Order,
                OrderComponents,
                OrderParameters,
                OrderStatus
            } from "./ConsiderationStructs.sol";
            import {
                _revertBadFraction,
                _revertCannotCancelOrder,
                _revertConsiderationLengthNotEqualToTotalOriginal,
                _revertInvalidContractOrder,
                _revertPartialFillsNotEnabledForOrder
            } from "./ConsiderationErrors.sol";
            import { Executor } from "./Executor.sol";
            import { ZoneInteraction } from "./ZoneInteraction.sol";
            import { MemoryPointer } from "../helpers/PointerLibraries.sol";
            import {
                AdvancedOrder_denominator_offset,
                AdvancedOrder_numerator_offset,
                BasicOrder_offerer_cdPtr,
                Common_amount_offset,
                Common_endAmount_offset,
                Common_identifier_offset,
                Common_token_offset,
                ConsiderItem_recipient_offset,
                ContractOrder_orderHash_offerer_shift,
                MaxUint120,
                OrderStatus_filledDenominator_offset,
                OrderStatus_filledNumerator_offset,
                OrderStatus_ValidatedAndNotCancelled
            } from "./ConsiderationConstants.sol";
            import {
                Error_selector_offset,
                Panic_arithmetic,
                Panic_error_code_ptr,
                Panic_error_length,
                Panic_error_selector
            } from "./ConsiderationErrorConstants.sol";
            /**
             * @title OrderValidator
             * @author 0age
             * @notice OrderValidator contains functionality related to validating orders
             *         and updating their status.
             */
            contract OrderValidator is Executor, ZoneInteraction {
                // Track status of each order (validated, cancelled, and fraction filled).
                mapping(bytes32 => OrderStatus) private _orderStatus;
                // Track nonces for contract offerers.
                mapping(address => uint256) internal _contractNonces;
                /**
                 * @dev Derive and set hashes, reference chainId, and associated domain
                 *      separator during deployment.
                 *
                 * @param conduitController A contract that deploys conduits, or proxies
                 *                          that may optionally be used to transfer approved
                 *                          ERC20/721/1155 tokens.
                 */
                constructor(address conduitController) Executor(conduitController) {}
                /**
                 * @dev Internal function to verify and update the status of a basic order.
                 *      Note that this function may only be safely called as part of basic
                 *      orders, as it assumes a specific calldata encoding structure that
                 *      must first be validated.
                 *
                 * @param orderHash The hash of the order.
                 * @param signature A signature from the offerer indicating that the order
                 *                  has been approved.
                 */
                function _validateBasicOrderAndUpdateStatus(
                    bytes32 orderHash,
                    bytes calldata signature
                ) internal {
                    // Retrieve offerer directly using fixed calldata offset based on strict
                    // basic parameter encoding.
                    address offerer;
                    assembly {
                        offerer := calldataload(BasicOrder_offerer_cdPtr)
                    }
                    // Retrieve the order status for the given order hash.
                    OrderStatus 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 revertOnInvalid   A boolean indicating whether to revert if the
                 *                          order is invalid due to the time or status.
                 *
                 * @return orderHash      The order hash.
                 * @return numerator      A value indicating the portion of the order that
                 *                        will be filled.
                 * @return denominator    A value indicating the total size of the order.
                 */
                function _validateOrderAndUpdateStatus(
                    AdvancedOrder memory advancedOrder,
                    bool revertOnInvalid
                )
                    internal
                    returns (bytes32 orderHash, uint256 numerator, uint256 denominator)
                {
                    // Retrieve the parameters for the order.
                    OrderParameters memory orderParameters = advancedOrder.parameters;
                    // Ensure current timestamp falls between order start time and end time.
                    if (
                        !_verifyTime(
                            orderParameters.startTime,
                            orderParameters.endTime,
                            revertOnInvalid
                        )
                    ) {
                        // Assuming an invalid time and no revert, return zeroed out values.
                        return (bytes32(0), 0, 0);
                    }
                    // Read numerator and denominator from memory and place on the stack.
                    // Note that overflowed values are masked.
                    assembly {
                        numerator := and(
                            mload(add(advancedOrder, AdvancedOrder_numerator_offset)),
                            MaxUint120
                        )
                        denominator := and(
                            mload(add(advancedOrder, AdvancedOrder_denominator_offset)),
                            MaxUint120
                        )
                    }
                    // Declare variable for tracking the validity of the supplied fraction.
                    bool invalidFraction;
                    // If the order is a contract order, return the generated order.
                    if (orderParameters.orderType == OrderType.CONTRACT) {
                        // Ensure that the numerator and denominator are both equal to 1.
                        assembly {
                            // (1 ^ nd =/= 0) => (nd =/= 1) => (n =/= 1) || (d =/= 1)
                            // It's important that the values are 120-bit masked before
                            // multiplication is applied. Otherwise, the last implication
                            // above is not correct (mod 2^256).
                            invalidFraction := xor(mul(numerator, denominator), 1)
                        }
                        // Revert if the supplied numerator and denominator are not valid.
                        if (invalidFraction) {
                            _revertBadFraction();
                        }
                        // Return the generated order based on the order params and the
                        // provided extra data. If revertOnInvalid is true, the function
                        // will revert if the input is invalid.
                        return
                            _getGeneratedOrder(
                                orderParameters,
                                advancedOrder.extraData,
                                revertOnInvalid
                            );
                    }
                    // Ensure numerator does not exceed denominator and is not zero.
                    assembly {
                        invalidFraction := or(gt(numerator, denominator), iszero(numerator))
                    }
                    // Revert if the supplied numerator and denominator are not valid.
                    if (invalidFraction) {
                        _revertBadFraction();
                    }
                    // If attempting partial fill (n < d) check order type & ensure support.
                    if (
                        _doesNotSupportPartialFills(
                            orderParameters.orderType,
                            numerator,
                            denominator
                        )
                    ) {
                        // Revert if partial fill was attempted on an unsupported order.
                        _revertPartialFillsNotEnabledForOrder();
                    }
                    // Retrieve current counter & use it w/ parameters to derive order hash.
                    orderHash = _assertConsiderationLengthAndGetOrderHash(orderParameters);
                    // Retrieve the order status using the derived order hash.
                    OrderStatus storage orderStatus = _orderStatus[orderHash];
                    // Ensure order is fillable and is not cancelled.
                    if (
                        !_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
                        );
                    }
                    assembly {
                        let orderStatusSlot := orderStatus.slot
                        // Read filled amount as numerator and denominator and put on stack.
                        let filledNumerator := sload(orderStatusSlot)
                        let filledDenominator := shr(
                            OrderStatus_filledDenominator_offset,
                            filledNumerator
                        )
                        for {
                        } 1 {
                        } {
                            if iszero(filledDenominator) {
                                filledNumerator := numerator
                                break
                            }
                            // Shift and mask to calculate the current filled numerator.
                            filledNumerator := and(
                                shr(OrderStatus_filledNumerator_offset, filledNumerator),
                                MaxUint120
                            )
                            // If denominator of 1 supplied, fill entire remaining amount.
                            if eq(denominator, 1) {
                                numerator := sub(filledDenominator, filledNumerator)
                                denominator := filledDenominator
                                filledNumerator := filledDenominator
                                break
                            }
                            // If supplied denominator equals to the current one:
                            if eq(denominator, filledDenominator) {
                                // Increment the filled numerator by the new numerator.
                                filledNumerator := add(numerator, filledNumerator)
                                // Once adjusted, if current + supplied numerator exceeds
                                // the denominator:
                                let carry := mul(
                                    sub(filledNumerator, denominator),
                                    gt(filledNumerator, denominator)
                                )
                                numerator := sub(numerator, carry)
                                filledNumerator := sub(filledNumerator, carry)
                                break
                            }
                            // Otherwise, if supplied denominator differs from current one:
                            filledNumerator := mul(filledNumerator, denominator)
                            numerator := mul(numerator, filledDenominator)
                            denominator := mul(denominator, filledDenominator)
                            // Increment the filled numerator by the new numerator.
                            filledNumerator := add(numerator, filledNumerator)
                            // Once adjusted, if current + supplied numerator exceeds
                            // denominator:
                            let carry := mul(
                                sub(filledNumerator, denominator),
                                gt(filledNumerator, denominator)
                            )
                            numerator := sub(numerator, carry)
                            filledNumerator := sub(filledNumerator, carry)
                            // 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_selector)
                                    // Store the arithmetic (0x11) panic code.
                                    mstore(Panic_error_code_ptr, Panic_arithmetic)
                                    // revert(abi.encodeWithSignature(
                                    //     "Panic(uint256)", 0x11
                                    // ))
                                    revert(Error_selector_offset, Panic_error_length)
                                }
                            }
                            break
                        }
                        // Update order status and fill amount, packing struct values.
                        // [denominator: 15 bytes] [numerator: 15 bytes]
                        // [isCancelled: 1 byte] [isValidated: 1 byte]
                        sstore(
                            orderStatusSlot,
                            or(
                                OrderStatus_ValidatedAndNotCancelled,
                                or(
                                    shl(
                                        OrderStatus_filledNumerator_offset,
                                        filledNumerator
                                    ),
                                    shl(OrderStatus_filledDenominator_offset, denominator)
                                )
                            )
                        )
                    }
                }
                /**
                 * @dev Internal pure function to check the compatibility of two offer
                 *      or consideration items for contract orders.  Note that the itemType
                 *      and identifier are reset in cases where criteria = 0 (collection-
                 *      wide offers), which means that a contract offerer has full latitude
                 *      to choose any identifier it wants mid-flight, in contrast to the
                 *      normal behavior, where the fulfiller can pick which identifier to
                 *      receive by providing a CriteriaResolver.
                 *
                 * @param originalItem The original offer or consideration item.
                 * @param newItem      The new offer or consideration item.
                 *
                 * @return isInvalid Error buffer indicating if items are incompatible.
                 */
                function _compareItems(
                    MemoryPointer originalItem,
                    MemoryPointer newItem
                ) internal pure returns (uint256 isInvalid) {
                    assembly {
                        let itemType := mload(originalItem)
                        let identifier := mload(add(originalItem, Common_identifier_offset))
                        // Set returned identifier for criteria-based items w/ criteria = 0.
                        if and(gt(itemType, 3), iszero(identifier)) {
                            // replace item type
                            itemType := sub(3, eq(itemType, 4))
                            identifier := mload(add(newItem, Common_identifier_offset))
                        }
                        let originalAmount := mload(add(originalItem, Common_amount_offset))
                        let newAmount := mload(add(newItem, Common_amount_offset))
                        isInvalid := iszero(
                            and(
                                // originalItem.token == newItem.token &&
                                // originalItem.itemType == newItem.itemType
                                and(
                                    eq(
                                        mload(add(originalItem, Common_token_offset)),
                                        mload(add(newItem, Common_token_offset))
                                    ),
                                    eq(itemType, mload(newItem))
                                ),
                                // originalItem.identifier == newItem.identifier &&
                                // originalItem.startAmount == originalItem.endAmount
                                and(
                                    eq(
                                        identifier,
                                        mload(add(newItem, Common_identifier_offset))
                                    ),
                                    eq(
                                        originalAmount,
                                        mload(add(originalItem, Common_endAmount_offset))
                                    )
                                )
                            )
                        )
                    }
                }
                /**
                 * @dev Internal pure function to check the compatibility of two recipients
                 *      on consideration items for contract orders. This check is skipped if
                 *      no recipient is originally supplied.
                 *
                 * @param originalRecipient The original consideration item recipient.
                 * @param newRecipient      The new consideration item recipient.
                 *
                 * @return isInvalid Error buffer indicating if recipients are incompatible.
                 */
                function _checkRecipients(
                    address originalRecipient,
                    address newRecipient
                ) internal pure returns (uint256 isInvalid) {
                    assembly {
                        isInvalid := iszero(
                            or(
                                iszero(originalRecipient),
                                eq(newRecipient, originalRecipient)
                            )
                        )
                    }
                }
                /**
                 * @dev Internal function to generate a contract order. When a
                 *      collection-wide criteria-based item (criteria = 0) is provided as an
                 *      input to a contract order, the contract offerer has full latitude to
                 *      choose any identifier it wants mid-flight, which differs from the
                 *      usual behavior.  For regular criteria-based orders with
                 *      identifierOrCriteria = 0, the fulfiller can pick which identifier to
                 *      receive by providing a CriteriaResolver. For contract offers with
                 *      identifierOrCriteria = 0, Seaport does not expect a corresponding
                 *      CriteriaResolver, and will revert if one is provided.
                 *
                 * @param orderParameters The parameters for the order.
                 * @param context         The context for generating the order.
                 * @param revertOnInvalid Whether to revert on invalid input.
                 *
                 * @return orderHash   The order hash.
                 * @return numerator   The numerator.
                 * @return denominator The denominator.
                 */
                function _getGeneratedOrder(
                    OrderParameters memory orderParameters,
                    bytes memory context,
                    bool revertOnInvalid
                )
                    internal
                    returns (bytes32 orderHash, uint256 numerator, uint256 denominator)
                {
                    // Ensure that consideration array length is equal to the total original
                    // consideration items value.
                    if (
                        orderParameters.consideration.length !=
                        orderParameters.totalOriginalConsiderationItems
                    ) {
                        _revertConsiderationLengthNotEqualToTotalOriginal();
                    }
                    {
                        address offerer = orderParameters.offerer;
                        bool success;
                        (MemoryPointer cdPtr, uint256 size) = _encodeGenerateOrder(
                            orderParameters,
                            context
                        );
                        assembly {
                            success := call(gas(), offerer, 0, cdPtr, size, 0, 0)
                        }
                        {
                            // Note: overflow impossible; nonce can't increment that high.
                            uint256 contractNonce;
                            unchecked {
                                // Note: nonce will be incremented even for skipped orders,
                                // and  even if generateOrder's return data does not satisfy
                                // all the constraints. This is the case when errorBuffer
                                // != 0 and revertOnInvalid == false.
                                contractNonce = _contractNonces[offerer]++;
                            }
                            assembly {
                                // Shift offerer address up 96 bytes and combine with nonce.
                                orderHash := xor(
                                    contractNonce,
                                    shl(ContractOrder_orderHash_offerer_shift, offerer)
                                )
                            }
                        }
                        // Revert or skip if the call to generate the contract order failed.
                        if (!success) {
                            return _revertOrReturnEmpty(revertOnInvalid, orderHash);
                        }
                    }
                    // From this point onward, do not allow for skipping orders as the
                    // contract offerer may have modified state in expectation of any named
                    // consideration items being sent to their designated recipients.
                    // Decode the returned contract order and/or update the error buffer.
                    (
                        uint256 errorBuffer,
                        OfferItem[] memory offer,
                        ConsiderationItem[] memory consideration
                    ) = _convertGetGeneratedOrderResult(_decodeGenerateOrderReturndata)();
                    // Revert if the returndata could not be decoded correctly.
                    if (errorBuffer != 0) {
                        _revertInvalidContractOrder(orderHash);
                    }
                    {
                        // Designate lengths.
                        uint256 originalOfferLength = orderParameters.offer.length;
                        uint256 newOfferLength = offer.length;
                        // Explicitly specified offer items cannot be removed.
                        if (originalOfferLength > newOfferLength) {
                            _revertInvalidContractOrder(orderHash);
                        }
                        // Iterate over each specified offer (e.g. minimumReceived) item.
                        for (uint256 i = 0; i < originalOfferLength; ) {
                            // Retrieve the pointer to the originally supplied item.
                            MemoryPointer mPtrOriginal = orderParameters
                                .offer[i]
                                .toMemoryPointer();
                            // Retrieve the pointer to the newly returned item.
                            MemoryPointer mPtrNew = offer[i].toMemoryPointer();
                            // Compare the items and update the error buffer accordingly.
                            errorBuffer |=
                                _cast(
                                    mPtrOriginal
                                        .offset(Common_amount_offset)
                                        .readUint256() >
                                        mPtrNew.offset(Common_amount_offset).readUint256()
                                ) |
                                _compareItems(mPtrOriginal, mPtrNew);
                            // Increment the array (cannot overflow as index starts at 0).
                            unchecked {
                                ++i;
                            }
                        }
                        // Assign the returned offer item in place of the original item.
                        orderParameters.offer = offer;
                    }
                    {
                        // Designate lengths & memory locations.
                        ConsiderationItem[] memory originalConsiderationArray = (
                            orderParameters.consideration
                        );
                        uint256 newConsiderationLength = consideration.length;
                        // New consideration items cannot be created.
                        if (newConsiderationLength > originalConsiderationArray.length) {
                            _revertInvalidContractOrder(orderHash);
                        }
                        // Iterate over returned consideration & do not exceed maximumSpent.
                        for (uint256 i = 0; i < newConsiderationLength; ) {
                            // Retrieve the pointer to the originally supplied item.
                            MemoryPointer mPtrOriginal = originalConsiderationArray[i]
                                .toMemoryPointer();
                            // Retrieve the pointer to the newly returned item.
                            MemoryPointer mPtrNew = consideration[i].toMemoryPointer();
                            // Compare the items and update the error buffer accordingly
                            // and ensure that the recipients are equal when provided.
                            errorBuffer |=
                                _cast(
                                    mPtrNew.offset(Common_amount_offset).readUint256() >
                                        mPtrOriginal
                                            .offset(Common_amount_offset)
                                            .readUint256()
                                ) |
                                _compareItems(mPtrOriginal, mPtrNew) |
                                _checkRecipients(
                                    mPtrOriginal
                                        .offset(ConsiderItem_recipient_offset)
                                        .readAddress(),
                                    mPtrNew
                                        .offset(ConsiderItem_recipient_offset)
                                        .readAddress()
                                );
                            // Increment the array (cannot overflow as index starts at 0).
                            unchecked {
                                ++i;
                            }
                        }
                        // Assign returned consideration item in place of the original item.
                        orderParameters.consideration = consideration;
                    }
                    // Revert if any item comparison failed.
                    if (errorBuffer != 0) {
                        _revertInvalidContractOrder(orderHash);
                    }
                    // Return order hash and full fill amount (numerator & denominator = 1).
                    return (orderHash, 1, 1);
                }
                /**
                 * @dev Internal function to cancel an arbitrary number of orders. Note that
                 *      only the offerer or the zone of a given order may cancel it. Callers
                 *      should ensure that the intended order was cancelled by calling
                 *      `getOrderStatus` and confirming that `isCancelled` returns `true`.
                 *      Also note that contract orders are not cancellable.
                 *
                 * @param orders The orders to cancel.
                 *
                 * @return cancelled A boolean indicating whether the supplied orders were
                 *                   successfully cancelled.
                 */
                function _cancel(
                    OrderComponents[] calldata orders
                ) internal returns (bool cancelled) {
                    // Ensure that the reentrancy guard is not currently set.
                    _assertNonReentrant();
                    // Declare variables outside of the loop.
                    OrderStatus storage orderStatus;
                    // Declare a variable for tracking invariants in the loop.
                    bool anyInvalidCallerOrContractOrder;
                    // Skip overflow check as for loop is indexed starting at zero.
                    unchecked {
                        // Read length of the orders array from memory and place on stack.
                        uint256 totalOrders = orders.length;
                        // Iterate over each order.
                        for (uint256 i = 0; i < totalOrders; ) {
                            // Retrieve the order.
                            OrderComponents calldata order = orders[i];
                            address offerer = order.offerer;
                            address zone = order.zone;
                            OrderType orderType = order.orderType;
                            assembly {
                                // If caller is neither the offerer nor zone, or a contract
                                // order is present, flag anyInvalidCallerOrContractOrder.
                                anyInvalidCallerOrContractOrder := or(
                                    anyInvalidCallerOrContractOrder,
                                    // orderType == CONTRACT ||
                                    // !(caller == offerer || caller == zone)
                                    or(
                                        eq(orderType, 4),
                                        iszero(
                                            or(eq(caller(), offerer), eq(caller(), zone))
                                        )
                                    )
                                )
                            }
                            bytes32 orderHash = _deriveOrderHash(
                                _toOrderParametersReturnType(
                                    _decodeOrderComponentsAsOrderParameters
                                )(order.toCalldataPointer()),
                                order.counter
                            );
                            // Retrieve the order status using the derived order hash.
                            orderStatus = _orderStatus[orderHash];
                            // Update the order status as not valid and cancelled.
                            orderStatus.isValidated = false;
                            orderStatus.isCancelled = true;
                            // Emit an event signifying that the order has been cancelled.
                            emit OrderCancelled(orderHash, offerer, zone);
                            // Increment counter inside body of loop for gas efficiency.
                            ++i;
                        }
                    }
                    if (anyInvalidCallerOrContractOrder) {
                        _revertCannotCancelOrder();
                    }
                    // Return a boolean indicating that orders were successfully cancelled.
                    cancelled = true;
                }
                /**
                 * @dev Internal function to validate an arbitrary number of orders, thereby
                 *      registering their signatures as valid and allowing the fulfiller to
                 *      skip signature verification on fulfillment. Note that validated
                 *      orders may still be unfulfillable due to invalid item amounts or
                 *      other factors; callers should determine whether validated orders are
                 *      fulfillable by simulating the fulfillment call prior to execution.
                 *      Also note that anyone can validate a signed order, but only the
                 *      offerer can validate an order without supplying a signature.
                 *
                 * @param orders The orders to validate.
                 *
                 * @return validated A boolean indicating whether the supplied orders were
                 *                   successfully validated.
                 */
                function _validate(
                    Order[] memory orders
                ) internal returns (bool validated) {
                    // Ensure that the reentrancy guard is not currently set.
                    _assertNonReentrant();
                    // Declare variables outside of the loop.
                    OrderStatus storage orderStatus;
                    bytes32 orderHash;
                    address offerer;
                    // Skip overflow check as for loop is indexed starting at zero.
                    unchecked {
                        // Read length of the orders array from memory and place on stack.
                        uint256 totalOrders = orders.length;
                        // Iterate over each order.
                        for (uint256 i = 0; i < totalOrders; ++i) {
                            // Retrieve the order.
                            Order memory order = orders[i];
                            // Retrieve the order parameters.
                            OrderParameters memory orderParameters = order.parameters;
                            // Skip contract orders.
                            if (orderParameters.orderType == OrderType.CONTRACT) {
                                continue;
                            }
                            // Move offerer from memory to the stack.
                            offerer = orderParameters.offerer;
                            // Get current counter & use it w/ params to derive order hash.
                            orderHash = _assertConsiderationLengthAndGetOrderHash(
                                orderParameters
                            );
                            // Retrieve the order status using the derived order hash.
                            orderStatus = _orderStatus[orderHash];
                            // Ensure order is fillable and retrieve the filled amount.
                            _verifyOrderStatus(
                                orderHash,
                                orderStatus,
                                false, // Signifies that partially filled orders are valid.
                                true // Signifies to revert if the order is invalid.
                            );
                            // If the order has not already been validated...
                            if (!orderStatus.isValidated) {
                                // Ensure that consideration array length is equal to the
                                // total original consideration items value.
                                if (
                                    orderParameters.consideration.length !=
                                    orderParameters.totalOriginalConsiderationItems
                                ) {
                                    _revertConsiderationLengthNotEqualToTotalOriginal();
                                }
                                // Verify the supplied signature.
                                _verifySignature(offerer, orderHash, order.signature);
                                // Update order status to mark the order as valid.
                                orderStatus.isValidated = true;
                                // Emit an event signifying the order has been validated.
                                emit OrderValidated(orderHash, orderParameters);
                            }
                        }
                    }
                    // Return a boolean indicating that orders were successfully validated.
                    validated = true;
                }
                /**
                 * @dev Internal view function to retrieve the status of a given order by
                 *      hash, including whether the order has been cancelled or validated
                 *      and the fraction of the order that has been filled.
                 *
                 * @param orderHash The order hash in question.
                 *
                 * @return isValidated A boolean indicating whether the order in question
                 *                     has been validated (i.e. previously approved or
                 *                     partially filled).
                 * @return isCancelled A boolean indicating whether the order in question
                 *                     has been cancelled.
                 * @return totalFilled The total portion of the order that has been filled
                 *                     (i.e. the "numerator").
                 * @return totalSize   The total size of the order that is either filled or
                 *                     unfilled (i.e. the "denominator").
                 */
                function _getOrderStatus(
                    bytes32 orderHash
                )
                    internal
                    view
                    returns (
                        bool isValidated,
                        bool isCancelled,
                        uint256 totalFilled,
                        uint256 totalSize
                    )
                {
                    // Retrieve the order status using the order hash.
                    OrderStatus storage orderStatus = _orderStatus[orderHash];
                    // Return the fields on the order status.
                    return (
                        orderStatus.isValidated,
                        orderStatus.isCancelled,
                        orderStatus.numerator,
                        orderStatus.denominator
                    );
                }
                /**
                 * @dev Internal pure function to either revert or return an empty tuple
                 *      depending on the value of `revertOnInvalid`.
                 *
                 * @param revertOnInvalid   Whether to revert on invalid input.
                 * @param contractOrderHash The contract order hash.
                 *
                 * @return orderHash   The order hash.
                 * @return numerator   The numerator.
                 * @return denominator The denominator.
                 */
                function _revertOrReturnEmpty(
                    bool revertOnInvalid,
                    bytes32 contractOrderHash
                )
                    internal
                    pure
                    returns (bytes32 orderHash, uint256 numerator, uint256 denominator)
                {
                    if (revertOnInvalid) {
                        _revertInvalidContractOrder(contractOrderHash);
                    }
                    return (contractOrderHash, 0, 0);
                }
                /**
                 * @dev Internal pure function to check whether a given order type indicates
                 *      that partial fills are not supported (e.g. only "full fills" are
                 *      allowed for the order in question).
                 *
                 * @param orderType   The order type in question.
                 * @param numerator   The numerator in question.
                 * @param denominator The denominator in question.
                 *
                 * @return isFullOrder A boolean indicating whether the order type only
                 *                     supports full fills.
                 */
                function _doesNotSupportPartialFills(
                    OrderType orderType,
                    uint256 numerator,
                    uint256 denominator
                ) internal pure returns (bool isFullOrder) {
                    // The "full" order types are even, while "partial" order types are odd.
                    // Bitwise and by 1 is equivalent to modulo by 2, but 2 gas cheaper. The
                    // check is only necessary if numerator is less than denominator.
                    assembly {
                        // Equivalent to `uint256(orderType) & 1 == 0`.
                        isFullOrder := and(
                            lt(numerator, denominator),
                            iszero(and(orderType, 1))
                        )
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            uint256 constant Error_selector_offset = 0x1c;
            /*
             *  error MissingFulfillmentComponentOnAggregation(uint8 side)
             *    - Defined in FulfillmentApplicationErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             *    - 0x20: side
             * Revert buffer is memory[0x1c:0x40]
             */
            uint256 constant MissingFulfillmentComponentOnAggregation_error_selector = (
                0x375c24c1
            );
            uint256 constant MissingFulfillmentComponentOnAggregation_error_side_ptr = 0x20;
            uint256 constant MissingFulfillmentComponentOnAggregation_error_length = 0x24;
            /*
             *  error OfferAndConsiderationRequiredOnFulfillment()
             *    - Defined in FulfillmentApplicationErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             * Revert buffer is memory[0x1c:0x20]
             */
            uint256 constant OfferAndConsiderationRequiredOnFulfillment_error_selector = (
                0x98e9db6e
            );
            uint256 constant OfferAndConsiderationRequiredOnFulfillment_error_length = 0x04;
            /*
             *  error MismatchedFulfillmentOfferAndConsiderationComponents(
             *      uint256 fulfillmentIndex
             *  )
             *    - Defined in FulfillmentApplicationErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             *    - 0x20: fulfillmentIndex
             * Revert buffer is memory[0x1c:0x40]
             */
            uint256 constant MismatchedOfferAndConsiderationComponents_error_selector = (
                0xbced929d
            );
            uint256 constant MismatchedOfferAndConsiderationComponents_error_idx_ptr = 0x20;
            uint256 constant MismatchedOfferAndConsiderationComponents_error_length = 0x24;
            /*
             *  error InvalidFulfillmentComponentData()
             *    - Defined in FulfillmentApplicationErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             * Revert buffer is memory[0x1c:0x20]
             */
            uint256 constant InvalidFulfillmentComponentData_error_selector = 0x7fda7279;
            uint256 constant InvalidFulfillmentComponentData_error_length = 0x04;
            /*
             *  error InexactFraction()
             *    - Defined in AmountDerivationErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             * Revert buffer is memory[0x1c:0x20]
             */
            uint256 constant InexactFraction_error_selector = 0xc63cf089;
            uint256 constant InexactFraction_error_length = 0x04;
            /*
             *  error OrderCriteriaResolverOutOfRange(uint8 side)
             *    - Defined in CriteriaResolutionErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             *    - 0x20: side
             * Revert buffer is memory[0x1c:0x40]
             */
            uint256 constant OrderCriteriaResolverOutOfRange_error_selector = 0x133c37c6;
            uint256 constant OrderCriteriaResolverOutOfRange_error_side_ptr = 0x20;
            uint256 constant OrderCriteriaResolverOutOfRange_error_length = 0x24;
            /*
             *  error UnresolvedOfferCriteria(uint256 orderIndex, uint256 offerIndex)
             *    - Defined in CriteriaResolutionErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             *    - 0x20: orderIndex
             *    - 0x40: offerIndex
             * Revert buffer is memory[0x1c:0x60]
             */
            uint256 constant UnresolvedOfferCriteria_error_selector = 0xd6929332;
            uint256 constant UnresolvedOfferCriteria_error_orderIndex_ptr = 0x20;
            uint256 constant UnresolvedOfferCriteria_error_offerIndex_ptr = 0x40;
            uint256 constant UnresolvedOfferCriteria_error_length = 0x44;
            /*
             *  error UnresolvedConsiderationCriteria(
             *      uint256 orderIndex,
             *      uint256 considerationIndex
             *  )
             *    - Defined in CriteriaResolutionErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             *    - 0x20: orderIndex
             *    - 0x40: considerationIndex
             * Revert buffer is memory[0x1c:0x60]
             */
            uint256 constant UnresolvedConsiderationCriteria_error_selector = 0xa8930e9a;
            uint256 constant UnresolvedConsiderationCriteria_error_orderIndex_ptr = 0x20;
            uint256 constant UnresolvedConsiderationCriteria_error_considerationIdx_ptr = (
                0x40
            );
            uint256 constant UnresolvedConsiderationCriteria_error_length = 0x44;
            /*
             *  error OfferCriteriaResolverOutOfRange()
             *    - Defined in CriteriaResolutionErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             * Revert buffer is memory[0x1c:0x20]
             */
            uint256 constant OfferCriteriaResolverOutOfRange_error_selector = 0xbfb3f8ce;
            // uint256 constant OfferCriteriaResolverOutOfRange_error_length = 0x04;
            /*
             *  error ConsiderationCriteriaResolverOutOfRange()
             *    - Defined in CriteriaResolutionErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             * Revert buffer is memory[0x1c:0x20]
             */
            uint256 constant ConsiderationCriteriaResolverOutOfRange_error_selector = (
                0x6088d7de
            );
            uint256 constant ConsiderationCriteriaResolverOutOfRange_err_selector = (
                0x6088d7de
            );
            // uint256 constant ConsiderationCriteriaResolverOutOfRange_error_length = 0x04;
            /*
             *  error CriteriaNotEnabledForItem()
             *    - Defined in CriteriaResolutionErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             * Revert buffer is memory[0x1c:0x20]
             */
            uint256 constant CriteriaNotEnabledForItem_error_selector = 0x94eb6af6;
            uint256 constant CriteriaNotEnabledForItem_error_length = 0x04;
            /*
             *  error InvalidProof()
             *    - Defined in CriteriaResolutionErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             * Revert buffer is memory[0x1c:0x20]
             */
            uint256 constant InvalidProof_error_selector = 0x09bde339;
            uint256 constant InvalidProof_error_length = 0x04;
            /*
             *  error InvalidRestrictedOrder(bytes32 orderHash)
             *    - Defined in ZoneInteractionErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             *    - 0x20: orderHash
             * Revert buffer is memory[0x1c:0x40]
             */
            uint256 constant InvalidRestrictedOrder_error_selector = 0xfb5014fc;
            uint256 constant InvalidRestrictedOrder_error_orderHash_ptr = 0x20;
            uint256 constant InvalidRestrictedOrder_error_length = 0x24;
            /*
             *  error InvalidContractOrder(bytes32 orderHash)
             *    - Defined in ZoneInteractionErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             *    - 0x20: orderHash
             * Revert buffer is memory[0x1c:0x40]
             */
            uint256 constant InvalidContractOrder_error_selector = 0x93979285;
            uint256 constant InvalidContractOrder_error_orderHash_ptr = 0x20;
            uint256 constant InvalidContractOrder_error_length = 0x24;
            /*
             *  error BadSignatureV(uint8 v)
             *    - Defined in SignatureVerificationErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             *    - 0x20: v
             * Revert buffer is memory[0x1c:0x40]
             */
            uint256 constant BadSignatureV_error_selector = 0x1f003d0a;
            uint256 constant BadSignatureV_error_v_ptr = 0x20;
            uint256 constant BadSignatureV_error_length = 0x24;
            /*
             *  error InvalidSigner()
             *    - Defined in SignatureVerificationErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             * Revert buffer is memory[0x1c:0x20]
             */
            uint256 constant InvalidSigner_error_selector = 0x815e1d64;
            uint256 constant InvalidSigner_error_length = 0x04;
            /*
             *  error InvalidSignature()
             *    - Defined in SignatureVerificationErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             * Revert buffer is memory[0x1c:0x20]
             */
            uint256 constant InvalidSignature_error_selector = 0x8baa579f;
            uint256 constant InvalidSignature_error_length = 0x04;
            /*
             *  error BadContractSignature()
             *    - Defined in SignatureVerificationErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             * Revert buffer is memory[0x1c:0x20]
             */
            uint256 constant BadContractSignature_error_selector = 0x4f7fb80d;
            uint256 constant BadContractSignature_error_length = 0x04;
            /*
             *  error InvalidERC721TransferAmount(uint256 amount)
             *    - Defined in TokenTransferrerErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             *    - 0x20: amount
             * Revert buffer is memory[0x1c:0x40]
             */
            uint256 constant InvalidERC721TransferAmount_error_selector = 0x69f95827;
            uint256 constant InvalidERC721TransferAmount_error_amount_ptr = 0x20;
            uint256 constant InvalidERC721TransferAmount_error_length = 0x24;
            /*
             *  error MissingItemAmount()
             *    - Defined in TokenTransferrerErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             * Revert buffer is memory[0x1c:0x20]
             */
            uint256 constant MissingItemAmount_error_selector = 0x91b3e514;
            uint256 constant MissingItemAmount_error_length = 0x04;
            /*
             *  error UnusedItemParameters()
             *    - Defined in TokenTransferrerErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             * Revert buffer is memory[0x1c:0x20]
             */
            uint256 constant UnusedItemParameters_error_selector = 0x6ab37ce7;
            uint256 constant UnusedItemParameters_error_length = 0x04;
            /*
             *  error NoReentrantCalls()
             *    - Defined in ReentrancyErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             * Revert buffer is memory[0x1c:0x20]
             */
            uint256 constant NoReentrantCalls_error_selector = 0x7fa8a987;
            uint256 constant NoReentrantCalls_error_length = 0x04;
            /*
             *  error OrderAlreadyFilled(bytes32 orderHash)
             *    - Defined in ConsiderationEventsAndErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             *    - 0x20: orderHash
             * Revert buffer is memory[0x1c:0x40]
             */
            uint256 constant OrderAlreadyFilled_error_selector = 0x10fda3e1;
            uint256 constant OrderAlreadyFilled_error_orderHash_ptr = 0x20;
            uint256 constant OrderAlreadyFilled_error_length = 0x24;
            /*
             *  error InvalidTime(uint256 startTime, uint256 endTime)
             *    - Defined in ConsiderationEventsAndErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             *    - 0x20: startTime
             *    - 0x40: endTime
             * Revert buffer is memory[0x1c:0x60]
             */
            uint256 constant InvalidTime_error_selector = 0x21ccfeb7;
            uint256 constant InvalidTime_error_startTime_ptr = 0x20;
            uint256 constant InvalidTime_error_endTime_ptr = 0x40;
            uint256 constant InvalidTime_error_length = 0x44;
            /*
             *  error InvalidConduit(bytes32 conduitKey, address conduit)
             *    - Defined in ConsiderationEventsAndErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             *    - 0x20: conduitKey
             *    - 0x40: conduit
             * Revert buffer is memory[0x1c:0x60]
             */
            uint256 constant InvalidConduit_error_selector = 0x1cf99b26;
            uint256 constant InvalidConduit_error_conduitKey_ptr = 0x20;
            uint256 constant InvalidConduit_error_conduit_ptr = 0x40;
            uint256 constant InvalidConduit_error_length = 0x44;
            /*
             *  error MissingOriginalConsiderationItems()
             *    - Defined in ConsiderationEventsAndErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             * Revert buffer is memory[0x1c:0x20]
             */
            uint256 constant MissingOriginalConsiderationItems_error_selector = 0x466aa616;
            uint256 constant MissingOriginalConsiderationItems_error_length = 0x04;
            /*
             *  error InvalidCallToConduit(address conduit)
             *    - Defined in ConsiderationEventsAndErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             *    - 0x20: conduit
             * Revert buffer is memory[0x1c:0x40]
             */
            uint256 constant InvalidCallToConduit_error_selector = 0xd13d53d4;
            uint256 constant InvalidCallToConduit_error_conduit_ptr = 0x20;
            uint256 constant InvalidCallToConduit_error_length = 0x24;
            /*
             *  error ConsiderationNotMet(
             *      uint256 orderIndex,
             *      uint256 considerationIndex,
             *      uint256 shortfallAmount
             *  )
             *    - Defined in ConsiderationEventsAndErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             *    - 0x20: orderIndex
             *    - 0x40: considerationIndex
             *    - 0x60: shortfallAmount
             * Revert buffer is memory[0x1c:0x80]
             */
            uint256 constant ConsiderationNotMet_error_selector = 0xa5f54208;
            uint256 constant ConsiderationNotMet_error_orderIndex_ptr = 0x20;
            uint256 constant ConsiderationNotMet_error_considerationIndex_ptr = 0x40;
            uint256 constant ConsiderationNotMet_error_shortfallAmount_ptr = 0x60;
            uint256 constant ConsiderationNotMet_error_length = 0x64;
            /*
             *  error InsufficientNativeTokensSupplied()
             *    - Defined in ConsiderationEventsAndErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             * Revert buffer is memory[0x1c:0x20]
             */
            uint256 constant InsufficientNativeTokensSupplied_error_selector = 0x8ffff980;
            uint256 constant InsufficientNativeTokensSupplied_error_length = 0x04;
            /*
             *  error NativeTokenTransferGenericFailure(address account, uint256 amount)
             *    - Defined in ConsiderationEventsAndErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             *    - 0x20: account
             *    - 0x40: amount
             * Revert buffer is memory[0x1c:0x60]
             */
            uint256 constant NativeTokenTransferGenericFailure_error_selector = 0xbc806b96;
            uint256 constant NativeTokenTransferGenericFailure_error_account_ptr = 0x20;
            uint256 constant NativeTokenTransferGenericFailure_error_amount_ptr = 0x40;
            uint256 constant NativeTokenTransferGenericFailure_error_length = 0x44;
            /*
             *  error PartialFillsNotEnabledForOrder()
             *    - Defined in ConsiderationEventsAndErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             * Revert buffer is memory[0x1c:0x20]
             */
            uint256 constant PartialFillsNotEnabledForOrder_error_selector = 0xa11b63ff;
            uint256 constant PartialFillsNotEnabledForOrder_error_length = 0x04;
            /*
             *  error OrderIsCancelled(bytes32 orderHash)
             *    - Defined in ConsiderationEventsAndErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             *    - 0x20: orderHash
             * Revert buffer is memory[0x1c:0x40]
             */
            uint256 constant OrderIsCancelled_error_selector = 0x1a515574;
            uint256 constant OrderIsCancelled_error_orderHash_ptr = 0x20;
            uint256 constant OrderIsCancelled_error_length = 0x24;
            /*
             *  error OrderPartiallyFilled(bytes32 orderHash)
             *    - Defined in ConsiderationEventsAndErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             *    - 0x20: orderHash
             * Revert buffer is memory[0x1c:0x40]
             */
            uint256 constant OrderPartiallyFilled_error_selector = 0xee9e0e63;
            uint256 constant OrderPartiallyFilled_error_orderHash_ptr = 0x20;
            uint256 constant OrderPartiallyFilled_error_length = 0x24;
            /*
             *  error CannotCancelOrder()
             *    - Defined in ConsiderationEventsAndErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             * Revert buffer is memory[0x1c:0x20]
             */
            uint256 constant CannotCancelOrder_error_selector = 0xfed398fc;
            uint256 constant CannotCancelOrder_error_length = 0x04;
            /*
             *  error BadFraction()
             *    - Defined in ConsiderationEventsAndErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             * Revert buffer is memory[0x1c:0x20]
             */
            uint256 constant BadFraction_error_selector = 0x5a052b32;
            uint256 constant BadFraction_error_length = 0x04;
            /*
             *  error InvalidMsgValue(uint256 value)
             *    - Defined in ConsiderationEventsAndErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             *    - 0x20: value
             * Revert buffer is memory[0x1c:0x40]
             */
            uint256 constant InvalidMsgValue_error_selector = 0xa61be9f0;
            uint256 constant InvalidMsgValue_error_value_ptr = 0x20;
            uint256 constant InvalidMsgValue_error_length = 0x24;
            /*
             *  error InvalidBasicOrderParameterEncoding()
             *    - Defined in ConsiderationEventsAndErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             * Revert buffer is memory[0x1c:0x20]
             */
            uint256 constant InvalidBasicOrderParameterEncoding_error_selector = 0x39f3e3fd;
            uint256 constant InvalidBasicOrderParameterEncoding_error_length = 0x04;
            /*
             *  error NoSpecifiedOrdersAvailable()
             *    - Defined in ConsiderationEventsAndErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             * Revert buffer is memory[0x1c:0x20]
             */
            uint256 constant NoSpecifiedOrdersAvailable_error_selector = 0xd5da9a1b;
            uint256 constant NoSpecifiedOrdersAvailable_error_length = 0x04;
            /*
             *  error InvalidNativeOfferItem()
             *    - Defined in ConsiderationEventsAndErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             * Revert buffer is memory[0x1c:0x20]
             */
            uint256 constant InvalidNativeOfferItem_error_selector = 0x12d3f5a3;
            uint256 constant InvalidNativeOfferItem_error_length = 0x04;
            /*
             *  error ConsiderationLengthNotEqualToTotalOriginal()
             *    - Defined in ConsiderationEventsAndErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             * Revert buffer is memory[0x1c:0x20]
             */
            uint256 constant ConsiderationLengthNotEqualToTotalOriginal_error_selector = (
                0x2165628a
            );
            uint256 constant ConsiderationLengthNotEqualToTotalOriginal_error_length = 0x04;
            /*
             *  error Panic(uint256 code)
             *    - Built-in Solidity error
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             *    - 0x20: code
             * Revert buffer is memory[0x1c:0x40]
             */
            uint256 constant Panic_error_selector = 0x4e487b71;
            uint256 constant Panic_error_code_ptr = 0x20;
            uint256 constant Panic_error_length = 0x24;
            uint256 constant Panic_arithmetic = 0x11;
            // uint256 constant Panic_resource = 0x41;
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.17;
            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 {
                Accumulator_array_length_ptr,
                Accumulator_array_offset_ptr,
                Accumulator_array_offset,
                Accumulator_conduitKey_ptr,
                Accumulator_itemSizeOffsetDifference,
                Accumulator_selector_ptr,
                AccumulatorArmed,
                AccumulatorDisarmed,
                Conduit_transferItem_amount_ptr,
                Conduit_transferItem_from_ptr,
                Conduit_transferItem_identifier_ptr,
                Conduit_transferItem_size,
                Conduit_transferItem_to_ptr,
                Conduit_transferItem_token_ptr,
                FreeMemoryPointerSlot,
                OneWord,
                TwoWords
            } from "./ConsiderationConstants.sol";
            import {
                Error_selector_offset,
                NativeTokenTransferGenericFailure_error_account_ptr,
                NativeTokenTransferGenericFailure_error_amount_ptr,
                NativeTokenTransferGenericFailure_error_length,
                NativeTokenTransferGenericFailure_error_selector
            } from "./ConsiderationErrorConstants.sol";
            import {
                _revertInvalidCallToConduit,
                _revertInvalidConduit,
                _revertInvalidERC721TransferAmount,
                _revertUnusedItemParameters
            } from "./ConsiderationErrors.sol";
            /**
             * @title Executor
             * @author 0age
             * @notice Executor contains functions related to processing executions (i.e.
             *         transferring items, either directly or via conduits).
             */
            contract Executor is Verifiers, TokenTransferrer {
                /**
                 * @dev Derive and set hashes, reference chainId, and associated domain
                 *      separator during deployment.
                 *
                 * @param conduitController A contract that deploys conduits, or proxies
                 *                          that may optionally be used to transfer approved
                 *                          ERC20/721/1155 tokens.
                 */
                constructor(address conduitController) Verifiers(conduitController) {}
                /**
                 * @dev Internal function to transfer a given item, either directly or via
                 *      a corresponding conduit.
                 *
                 * @param item        The item to transfer, including an amount and a
                 *                    recipient.
                 * @param from        The account supplying the item.
                 * @param conduitKey  A bytes32 value indicating what corresponding conduit,
                 *                    if any, to source token approvals from. The zero hash
                 *                    signifies that no conduit should be used, with direct
                 *                    approvals set on this contract.
                 * @param accumulator An open-ended array that collects transfers to execute
                 *                    against a given conduit in a single call.
                 */
                function _transfer(
                    ReceivedItem memory item,
                    address from,
                    bytes32 conduitKey,
                    bytes memory accumulator
                ) internal {
                    // If the item type indicates Ether or a native token...
                    if (item.itemType == ItemType.NATIVE) {
                        // Ensure neither the token nor the identifier parameters are set.
                        if ((uint160(item.token) | item.identifier) != 0) {
                            _revertUnusedItemParameters();
                        }
                        // transfer the native tokens to the recipient.
                        _transferNativeTokens(item.recipient, item.amount);
                    } else if (item.itemType == ItemType.ERC20) {
                        // Ensure that no identifier is supplied.
                        if (item.identifier != 0) {
                            _revertUnusedItemParameters();
                        }
                        // Transfer ERC20 tokens from the source to the recipient.
                        _transferERC20(
                            item.token,
                            from,
                            item.recipient,
                            item.amount,
                            conduitKey,
                            accumulator
                        );
                    } else if (item.itemType == ItemType.ERC721) {
                        // Transfer ERC721 token from the source to the recipient.
                        _transferERC721(
                            item.token,
                            from,
                            item.recipient,
                            item.identifier,
                            item.amount,
                            conduitKey,
                            accumulator
                        );
                    } else {
                        // Transfer ERC1155 token from the source to the recipient.
                        _transferERC1155(
                            item.token,
                            from,
                            item.recipient,
                            item.identifier,
                            item.amount,
                            conduitKey,
                            accumulator
                        );
                    }
                }
                /**
                 * @dev Internal function to transfer Ether or other native tokens to a
                 *      given recipient.
                 *
                 * @param to     The recipient of the transfer.
                 * @param amount The amount to transfer.
                 */
                function _transferNativeTokens(
                    address payable to,
                    uint256 amount
                ) internal {
                    // Ensure that the supplied amount is non-zero.
                    _assertNonZeroAmount(amount);
                    // Declare a variable indicating whether the call was successful or not.
                    bool success;
                    assembly {
                        // Transfer the native token and store if it succeeded or not.
                        success := call(gas(), to, amount, 0, 0, 0, 0)
                    }
                    // If the call fails...
                    if (!success) {
                        // Revert and pass the revert reason along if one was returned.
                        _revertWithReasonIfOneIsReturned();
                        // Otherwise, revert with a generic error message.
                        assembly {
                            // Store left-padded selector with push4, mem[28:32] = selector
                            mstore(0, NativeTokenTransferGenericFailure_error_selector)
                            // Write `to` and `amount` arguments.
                            mstore(NativeTokenTransferGenericFailure_error_account_ptr, to)
                            mstore(
                                NativeTokenTransferGenericFailure_error_amount_ptr,
                                amount
                            )
                            // revert(abi.encodeWithSignature(
                            //     "NativeTokenTransferGenericFailure(address,uint256)",
                            //     to,
                            //     amount
                            // ))
                            revert(
                                Error_selector_offset,
                                NativeTokenTransferGenericFailure_error_length
                            )
                        }
                    }
                }
                /**
                 * @dev Internal function to transfer ERC20 tokens from a given originator
                 *      to a given recipient using a given conduit if applicable. Sufficient
                 *      approvals must be set on this contract or on a respective conduit.
                 *
                 * @param token       The ERC20 token to transfer.
                 * @param from        The originator of the transfer.
                 * @param to          The recipient of the transfer.
                 * @param amount      The amount to transfer.
                 * @param conduitKey  A bytes32 value indicating what corresponding conduit,
                 *                    if any, to source token approvals from. The zero hash
                 *                    signifies that no conduit should be used, with direct
                 *                    approvals set on this contract.
                 * @param accumulator An open-ended array that collects transfers to execute
                 *                    against a given conduit in a single call.
                 */
                function _transferERC20(
                    address token,
                    address from,
                    address to,
                    uint256 amount,
                    bytes32 conduitKey,
                    bytes memory accumulator
                ) internal {
                    // Ensure that the supplied amount is non-zero.
                    _assertNonZeroAmount(amount);
                    // Trigger accumulated transfers if the conduits differ.
                    _triggerIfArmedAndNotAccumulatable(accumulator, conduitKey);
                    // If no conduit has been specified...
                    if (conduitKey == bytes32(0)) {
                        // Perform the token transfer directly.
                        _performERC20Transfer(token, from, to, amount);
                    } else {
                        // Insert the call to the conduit into the accumulator.
                        _insert(
                            conduitKey,
                            accumulator,
                            ConduitItemType.ERC20,
                            token,
                            from,
                            to,
                            uint256(0),
                            amount
                        );
                    }
                }
                /**
                 * @dev Internal function to transfer a single ERC721 token from a given
                 *      originator to a given recipient. Sufficient approvals must be set,
                 *      either on the respective conduit or on this contract itself.
                 *
                 * @param token       The ERC721 token to transfer.
                 * @param from        The originator of the transfer.
                 * @param to          The recipient of the transfer.
                 * @param identifier  The tokenId to transfer (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) {
                            _revertInvalidERC721TransferAmount(amount);
                        }
                        // Perform transfer via the token contract directly.
                        _performERC721Transfer(token, from, to, identifier);
                    } else {
                        // Insert the call to the conduit into the accumulator.
                        _insert(
                            conduitKey,
                            accumulator,
                            ConduitItemType.ERC721,
                            token,
                            from,
                            to,
                            identifier,
                            amount
                        );
                    }
                }
                /**
                 * @dev Internal function to transfer ERC1155 tokens from a given originator
                 *      to a given recipient. Sufficient approvals must be set, either on
                 *      the respective conduit or on this contract itself.
                 *
                 * @param token       The ERC1155 token to transfer.
                 * @param from        The originator of the transfer.
                 * @param to          The recipient of the transfer.
                 * @param identifier  The id to transfer.
                 * @param amount      The amount to transfer.
                 * @param conduitKey  A bytes32 value indicating what corresponding conduit,
                 *                    if any, to source token approvals from. The zero hash
                 *                    signifies that no conduit should be used, with direct
                 *                    approvals set on this contract.
                 * @param accumulator An open-ended array that collects transfers to execute
                 *                    against a given conduit in a single call.
                 */
                function _transferERC1155(
                    address token,
                    address from,
                    address to,
                    uint256 identifier,
                    uint256 amount,
                    bytes32 conduitKey,
                    bytes memory accumulator
                ) internal {
                    // Ensure that the supplied amount is non-zero.
                    _assertNonZeroAmount(amount);
                    // Trigger accumulated transfers if the conduits differ.
                    _triggerIfArmedAndNotAccumulatable(accumulator, conduitKey);
                    // If no conduit has been specified...
                    if (conduitKey == bytes32(0)) {
                        // Perform transfer via the token contract directly.
                        _performERC1155Transfer(token, from, to, identifier, amount);
                    } else {
                        // Insert the call to the conduit into the accumulator.
                        _insert(
                            conduitKey,
                            accumulator,
                            ConduitItemType.ERC1155,
                            token,
                            from,
                            to,
                            identifier,
                            amount
                        );
                    }
                }
                /**
                 * @dev Internal function to trigger a call to the conduit currently held by
                 *      the accumulator if the accumulator contains item transfers (i.e. it
                 *      is "armed") and the supplied conduit key does not match the key held
                 *      by the accumulator.
                 *
                 * @param accumulator An open-ended array that collects transfers to execute
                 *                    against a given conduit in a single call.
                 * @param conduitKey  A bytes32 value indicating what corresponding conduit,
                 *                    if any, to source token approvals from. The zero hash
                 *                    signifies that no conduit should be used, with direct
                 *                    approvals set on this contract.
                 */
                function _triggerIfArmedAndNotAccumulatable(
                    bytes memory accumulator,
                    bytes32 conduitKey
                ) internal {
                    // Retrieve the current conduit key from the accumulator.
                    bytes32 accumulatorConduitKey = _getAccumulatorConduitKey(accumulator);
                    // Perform conduit call if the set key does not match the supplied key.
                    if (accumulatorConduitKey != conduitKey) {
                        _triggerIfArmed(accumulator);
                    }
                }
                /**
                 * @dev Internal function to trigger a call to the conduit currently held by
                 *      the accumulator if the accumulator contains item transfers (i.e. it
                 *      is "armed").
                 *
                 * @param accumulator An open-ended array that collects transfers to execute
                 *                    against a given conduit in a single call.
                 */
                function _triggerIfArmed(bytes memory accumulator) internal {
                    // Exit if the accumulator is not "armed".
                    if (accumulator.length != AccumulatorArmed) {
                        return;
                    }
                    // Retrieve the current conduit key from the accumulator.
                    bytes32 accumulatorConduitKey = _getAccumulatorConduitKey(accumulator);
                    // Perform conduit call.
                    _trigger(accumulatorConduitKey, accumulator);
                }
                /**
                 * @dev Internal function to trigger a call to the conduit corresponding to
                 *      a given conduit key, supplying all accumulated item transfers. The
                 *      accumulator will be "disarmed" and reset in the process.
                 *
                 * @param conduitKey  A bytes32 value indicating what corresponding conduit,
                 *                    if any, to source token approvals from. The zero hash
                 *                    signifies that no conduit should be used, with direct
                 *                    approvals set on this contract.
                 * @param accumulator An open-ended array that collects transfers to execute
                 *                    against a given conduit in a single call.
                 */
                function _trigger(bytes32 conduitKey, bytes memory accumulator) internal {
                    // Declare variables for offset in memory & size of calldata to conduit.
                    uint256 callDataOffset;
                    uint256 callDataSize;
                    // Call the conduit with all the accumulated transfers.
                    assembly {
                        // Call begins at third word; the first is length or "armed" status,
                        // and the second is the current conduit key.
                        callDataOffset := add(accumulator, TwoWords)
                        // 68 + items * 192
                        callDataSize := add(
                            Accumulator_array_offset_ptr,
                            mul(
                                mload(add(accumulator, Accumulator_array_length_ptr)),
                                Conduit_transferItem_size
                            )
                        )
                    }
                    // Call conduit derived from conduit key & supply accumulated transfers.
                    _callConduitUsingOffsets(conduitKey, callDataOffset, callDataSize);
                    // Reset accumulator length to signal that it is now "disarmed".
                    assembly {
                        mstore(accumulator, AccumulatorDisarmed)
                    }
                }
                /**
                 * @dev Internal function to perform a call to the conduit corresponding to
                 *      a given conduit key based on the offset and size of the calldata in
                 *      question in memory.
                 *
                 * @param conduitKey     A bytes32 value indicating what corresponding
                 *                       conduit, if any, to source token approvals from.
                 *                       The zero hash signifies that no conduit should be
                 *                       used, with direct approvals set on this contract.
                 * @param callDataOffset The memory pointer where calldata is contained.
                 * @param callDataSize   The size of calldata in memory.
                 */
                function _callConduitUsingOffsets(
                    bytes32 conduitKey,
                    uint256 callDataOffset,
                    uint256 callDataSize
                ) internal {
                    // Derive the address of the conduit using the conduit key.
                    address conduit = _deriveConduit(conduitKey);
                    bool success;
                    bytes4 result;
                    // call the conduit.
                    assembly {
                        // Ensure first word of scratch space is empty.
                        mstore(0, 0)
                        // Perform call, placing first word of return data in scratch space.
                        success := call(
                            gas(),
                            conduit,
                            0,
                            callDataOffset,
                            callDataSize,
                            0,
                            OneWord
                        )
                        // Take value from scratch space and place it on the stack.
                        result := mload(0)
                    }
                    // If the call failed...
                    if (!success) {
                        // Pass along whatever revert reason was given by the conduit.
                        _revertWithReasonIfOneIsReturned();
                        // Otherwise, revert with a generic error.
                        _revertInvalidCallToConduit(conduit);
                    }
                    // Ensure result was extracted and matches EIP-1271 magic value.
                    if (result != ConduitInterface.execute.selector) {
                        _revertInvalidConduit(conduitKey, conduit);
                    }
                }
                /**
                 * @dev Internal pure function to retrieve the current conduit key set for
                 *      the accumulator.
                 *
                 * @param accumulator An open-ended array that collects transfers to execute
                 *                    against a given conduit in a single call.
                 *
                 * @return accumulatorConduitKey The conduit key currently set for the
                 *                               accumulator.
                 */
                function _getAccumulatorConduitKey(
                    bytes memory accumulator
                ) internal pure returns (bytes32 accumulatorConduitKey) {
                    // Retrieve the current conduit key from the accumulator.
                    assembly {
                        accumulatorConduitKey := mload(
                            add(accumulator, Accumulator_conduitKey_ptr)
                        )
                    }
                }
                /**
                 * @dev Internal pure function to place an item transfer into an accumulator
                 *      that collects a series of transfers to execute against a given
                 *      conduit in a single call.
                 *
                 * @param conduitKey  A bytes32 value indicating what corresponding conduit,
                 *                    if any, to source token approvals from. The zero hash
                 *                    signifies that no conduit should be used, with direct
                 *                    approvals set on this contract.
                 * @param accumulator An open-ended array that collects transfers to execute
                 *                    against a given conduit in a single call.
                 * @param itemType    The type of the item to transfer.
                 * @param token       The token to transfer.
                 * @param from        The originator of the transfer.
                 * @param to          The recipient of the transfer.
                 * @param identifier  The tokenId to transfer.
                 * @param amount      The amount to transfer.
                 */
                function _insert(
                    bytes32 conduitKey,
                    bytes memory accumulator,
                    ConduitItemType itemType,
                    address token,
                    address from,
                    address to,
                    uint256 identifier,
                    uint256 amount
                ) internal pure {
                    uint256 elements;
                    // "Arm" and prime accumulator if it's not already armed. The sentinel
                    // value is held in the length of the accumulator array.
                    if (accumulator.length == AccumulatorDisarmed) {
                        elements = 1;
                        bytes4 selector = ConduitInterface.execute.selector;
                        assembly {
                            mstore(accumulator, AccumulatorArmed) // "arm" the accumulator.
                            mstore(add(accumulator, Accumulator_conduitKey_ptr), conduitKey)
                            mstore(add(accumulator, Accumulator_selector_ptr), selector)
                            mstore(
                                add(accumulator, Accumulator_array_offset_ptr),
                                Accumulator_array_offset
                            )
                            mstore(add(accumulator, Accumulator_array_length_ptr), elements)
                        }
                    } else {
                        // Otherwise, increase the number of elements by one.
                        assembly {
                            elements := add(
                                mload(add(accumulator, Accumulator_array_length_ptr)),
                                1
                            )
                            mstore(add(accumulator, Accumulator_array_length_ptr), elements)
                        }
                    }
                    // Insert the item.
                    assembly {
                        let itemPointer := sub(
                            add(accumulator, mul(elements, Conduit_transferItem_size)),
                            Accumulator_itemSizeOffsetDifference
                        )
                        mstore(itemPointer, itemType)
                        mstore(add(itemPointer, Conduit_transferItem_token_ptr), token)
                        mstore(add(itemPointer, Conduit_transferItem_from_ptr), from)
                        mstore(add(itemPointer, Conduit_transferItem_to_ptr), to)
                        mstore(
                            add(itemPointer, Conduit_transferItem_identifier_ptr),
                            identifier
                        )
                        mstore(add(itemPointer, Conduit_transferItem_amount_ptr), amount)
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.17;
            import { OrderType } from "./ConsiderationEnums.sol";
            import {
                AdvancedOrder,
                BasicOrderParameters,
                OrderParameters
            } from "./ConsiderationStructs.sol";
            import { ZoneInteractionErrors } from "../interfaces/ZoneInteractionErrors.sol";
            import { LowLevelHelpers } from "./LowLevelHelpers.sol";
            import { ConsiderationEncoder } from "./ConsiderationEncoder.sol";
            import { MemoryPointer } from "../helpers/PointerLibraries.sol";
            import {
                ContractOrder_orderHash_offerer_shift,
                MaskOverFirstFourBytes,
                OneWord,
                OrderParameters_zone_offset
            } from "./ConsiderationConstants.sol";
            import {
                Error_selector_offset,
                InvalidContractOrder_error_selector,
                InvalidRestrictedOrder_error_length,
                InvalidRestrictedOrder_error_orderHash_ptr,
                InvalidRestrictedOrder_error_selector
            } from "./ConsiderationErrorConstants.sol";
            /**
             * @title ZoneInteraction
             * @author 0age
             * @notice ZoneInteraction contains logic related to interacting with zones.
             */
            contract ZoneInteraction is
                ConsiderationEncoder,
                ZoneInteractionErrors,
                LowLevelHelpers
            {
                /**
                 * @dev Internal function to determine if an order has a restricted order
                 *      type and, if so, to ensure that either the zone is the caller or
                 *      that a call to `validateOrder` on the zone returns a magic value
                 *      indicating that the order is currently valid. Note that contract
                 *      orders are not accessible via the basic fulfillment method.
                 *
                 * @param orderHash  The hash of the order.
                 * @param orderType  The order type.
                 * @param parameters The parameters of the basic order.
                 */
                function _assertRestrictedBasicOrderValidity(
                    bytes32 orderHash,
                    OrderType orderType,
                    BasicOrderParameters calldata parameters
                ) internal {
                    // Order type 2-3 require zone be caller or zone to approve.
                    // Note that in cases where fulfiller == zone, the restricted order
                    // validation will be skipped.
                    if (_isRestrictedAndCallerNotZone(orderType, parameters.zone)) {
                        // Encode the `validateOrder` call in memory.
                        (MemoryPointer callData, uint256 size) = _encodeValidateBasicOrder(
                            orderHash,
                            parameters
                        );
                        // Perform `validateOrder` call and ensure magic value was returned.
                        _callAndCheckStatus(
                            parameters.zone,
                            orderHash,
                            callData,
                            size,
                            InvalidRestrictedOrder_error_selector
                        );
                    }
                }
                /**
                 * @dev Internal function to determine the post-execution validity of
                 *      restricted and contract orders. Restricted orders where the caller
                 *      is not the zone must successfully call `validateOrder` with the
                 *      correct magic value returned. Contract orders must successfully call
                 *      `ratifyOrder` with the correct magic value returned.
                 *
                 * @param advancedOrder The advanced order in question.
                 * @param orderHashes   The order hashes of each order included as part of
                 *                      the current fulfillment.
                 * @param orderHash     The hash of the order.
                 */
                function _assertRestrictedAdvancedOrderValidity(
                    AdvancedOrder memory advancedOrder,
                    bytes32[] memory orderHashes,
                    bytes32 orderHash
                ) internal {
                    // Declare variables that will be assigned based on the order type.
                    address target;
                    uint256 errorSelector;
                    MemoryPointer callData;
                    uint256 size;
                    // Retrieve the parameters of the order in question.
                    OrderParameters memory parameters = advancedOrder.parameters;
                    // OrderType 2-3 require zone to be caller or approve via validateOrder.
                    if (
                        _isRestrictedAndCallerNotZone(parameters.orderType, parameters.zone)
                    ) {
                        // Encode the `validateOrder` call in memory.
                        (callData, size) = _encodeValidateOrder(
                            orderHash,
                            parameters,
                            advancedOrder.extraData,
                            orderHashes
                        );
                        // Set the target to the zone.
                        target = (
                            parameters
                                .toMemoryPointer()
                                .offset(OrderParameters_zone_offset)
                                .readAddress()
                        );
                        // Set the restricted-order-specific error selector.
                        errorSelector = InvalidRestrictedOrder_error_selector;
                    } else if (parameters.orderType == OrderType.CONTRACT) {
                        // Set the target to the offerer (note the offerer has no offset).
                        target = parameters.toMemoryPointer().readAddress();
                        // Shift the target 96 bits to the left.
                        uint256 shiftedOfferer;
                        assembly {
                            shiftedOfferer := shl(
                                ContractOrder_orderHash_offerer_shift,
                                target
                            )
                        }
                        // Encode the `ratifyOrder` call in memory.
                        (callData, size) = _encodeRatifyOrder(
                            orderHash,
                            parameters,
                            advancedOrder.extraData,
                            orderHashes,
                            shiftedOfferer
                        );
                        // Set the contract-order-specific error selector.
                        errorSelector = InvalidContractOrder_error_selector;
                    } else {
                        return;
                    }
                    // Perform call and ensure a corresponding magic value was returned.
                    _callAndCheckStatus(target, orderHash, callData, size, errorSelector);
                }
                /**
                 * @dev Determines whether the specified order type is restricted and the
                 *      caller is not the specified zone.
                 *
                 * @param orderType     The type of the order to check.
                 * @param zone          The address of the zone to check against.
                 *
                 * @return mustValidate True if the order type is restricted and the caller
                 *                      is not the specified zone, false otherwise.
                 */
                function _isRestrictedAndCallerNotZone(
                    OrderType orderType,
                    address zone
                ) internal view returns (bool mustValidate) {
                    assembly {
                        mustValidate := and(
                            // Note that this check requires that there are no order types
                            // beyond the current set (0-4).  It will need to be modified if
                            // more order types are added.
                            and(lt(orderType, 4), gt(orderType, 1)),
                            iszero(eq(caller(), zone))
                        )
                    }
                }
                /**
                 * @dev Calls the specified target with the given data and checks the status
                 *      of the call. Revert reasons will be "bubbled up" if one is returned,
                 *      otherwise reverting calls will throw a generic error based on the
                 *      supplied error handler.
                 *
                 * @param target        The address of the contract to call.
                 * @param orderHash     The hash of the order associated with the call.
                 * @param callData      The data to pass to the contract call.
                 * @param size          The size of calldata.
                 * @param errorSelector The error handling function to call if the call
                 *                      fails or the magic value does not match.
                 */
                function _callAndCheckStatus(
                    address target,
                    bytes32 orderHash,
                    MemoryPointer callData,
                    uint256 size,
                    uint256 errorSelector
                ) internal {
                    bool success;
                    bool magicMatch;
                    assembly {
                        // Get magic value from the selector at start of provided calldata.
                        let magic := and(mload(callData), MaskOverFirstFourBytes)
                        // Clear the start of scratch space.
                        mstore(0, 0)
                        // Perform call, placing result in the first word of scratch space.
                        success := call(gas(), target, 0, callData, size, 0, OneWord)
                        // Determine if returned magic value matches the calldata selector.
                        magicMatch := eq(magic, mload(0))
                    }
                    // Revert if the call was not successful.
                    if (!success) {
                        // Revert and pass reason along if one was returned.
                        _revertWithReasonIfOneIsReturned();
                        // If no reason was returned, revert with supplied error selector.
                        assembly {
                            mstore(0, errorSelector)
                            mstore(InvalidRestrictedOrder_error_orderHash_ptr, orderHash)
                            // revert(abi.encodeWithSelector(
                            //     "InvalidRestrictedOrder(bytes32)",
                            //     orderHash
                            // ))
                            revert(
                                Error_selector_offset,
                                InvalidRestrictedOrder_error_length
                            )
                        }
                    }
                    // Revert if the correct magic value was not returned.
                    if (!magicMatch) {
                        // Revert with a generic error message.
                        assembly {
                            mstore(0, errorSelector)
                            mstore(InvalidRestrictedOrder_error_orderHash_ptr, orderHash)
                            // revert(abi.encodeWithSelector(
                            //     "InvalidRestrictedOrder(bytes32)",
                            //     orderHash
                            // ))
                            revert(
                                Error_selector_offset,
                                InvalidRestrictedOrder_error_length
                            )
                        }
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import {
                ConduitBatch1155Transfer,
                ConduitTransfer
            } from "../conduit/lib/ConduitStructs.sol";
            /**
             * @title ConduitInterface
             * @author 0age
             * @notice ConduitInterface contains all external function interfaces, events,
             *         and errors for conduit contracts.
             */
            interface ConduitInterface {
                /**
                 * @dev Revert with an error when attempting to execute transfers using a
                 *      caller that does not have an open channel.
                 */
                error ChannelClosed(address channel);
                /**
                 * @dev Revert with an error when attempting to update a channel to the
                 *      current status of that channel.
                 */
                error ChannelStatusAlreadySet(address channel, bool isOpen);
                /**
                 * @dev Revert with an error when attempting to execute a transfer for an
                 *      item that does not have an ERC20/721/1155 item type.
                 */
                error InvalidItemType();
                /**
                 * @dev Revert with an error when attempting to update the status of a
                 *      channel from a caller that is not the conduit controller.
                 */
                error InvalidController();
                /**
                 * @dev Emit an event whenever a channel is opened or closed.
                 *
                 * @param channel The channel that has been updated.
                 * @param open    A boolean indicating whether the conduit is open or not.
                 */
                event ChannelUpdated(address indexed channel, bool open);
                /**
                 * @notice Execute a sequence of ERC20/721/1155 transfers. Only a caller
                 *         with an open channel can call this function.
                 *
                 * @param transfers The ERC20/721/1155 transfers to perform.
                 *
                 * @return magicValue A magic value indicating that the transfers were
                 *                    performed successfully.
                 */
                function execute(
                    ConduitTransfer[] calldata transfers
                ) external returns (bytes4 magicValue);
                /**
                 * @notice Execute a sequence of batch 1155 transfers. Only a caller with an
                 *         open channel can call this function.
                 *
                 * @param batch1155Transfers The 1155 batch transfers to perform.
                 *
                 * @return magicValue A magic value indicating that the transfers were
                 *                    performed successfully.
                 */
                function executeBatch1155(
                    ConduitBatch1155Transfer[] calldata batch1155Transfers
                ) external returns (bytes4 magicValue);
                /**
                 * @notice Execute a sequence of transfers, both single and batch 1155. Only
                 *         a caller with an open channel can call this function.
                 *
                 * @param standardTransfers  The ERC20/721/1155 transfers to perform.
                 * @param batch1155Transfers The 1155 batch transfers to perform.
                 *
                 * @return magicValue A magic value indicating that the transfers were
                 *                    performed successfully.
                 */
                function executeWithBatch1155(
                    ConduitTransfer[] calldata standardTransfers,
                    ConduitBatch1155Transfer[] calldata batch1155Transfers
                ) external returns (bytes4 magicValue);
                /**
                 * @notice Open or close a given channel. Only callable by the controller.
                 *
                 * @param channel The channel to open or close.
                 * @param isOpen  The status of the channel (either open or closed).
                 */
                function updateChannel(address channel, bool isOpen) external;
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            enum ConduitItemType {
                NATIVE, // unused
                ERC20,
                ERC721,
                ERC1155
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.17;
            import { OrderStatus } from "./ConsiderationStructs.sol";
            import { Assertions } from "./Assertions.sol";
            import { SignatureVerification } from "./SignatureVerification.sol";
            import {
                _revertInvalidTime,
                _revertOrderAlreadyFilled,
                _revertOrderIsCancelled,
                _revertOrderPartiallyFilled
            } from "./ConsiderationErrors.sol";
            import {
                BulkOrderProof_keyShift,
                BulkOrderProof_keySize,
                BulkOrderProof_lengthAdjustmentBeforeMask,
                BulkOrderProof_lengthRangeAfterMask,
                BulkOrderProof_minSize,
                BulkOrderProof_rangeSize,
                ECDSA_MaxLength,
                OneWord,
                OneWordShift,
                ThirtyOneBytes,
                TwoWords
            } from "./ConsiderationConstants.sol";
            /**
             * @title Verifiers
             * @author 0age
             * @notice Verifiers contains functions for performing verifications.
             */
            contract Verifiers is Assertions, SignatureVerification {
                /**
                 * @dev Derive and set hashes, reference chainId, and associated domain
                 *      separator during deployment.
                 *
                 * @param conduitController A contract that deploys conduits, or proxies
                 *                          that may optionally be used to transfer approved
                 *                          ERC20/721/1155 tokens.
                 */
                constructor(address conduitController) Assertions(conduitController) {}
                /**
                 * @dev Internal view function to ensure that the current time falls within
                 *      an order's valid timespan.
                 *
                 * @param startTime       The time at which the order becomes active.
                 * @param endTime         The time at which the order becomes inactive.
                 * @param revertOnInvalid A boolean indicating whether to revert if the
                 *                        order is not active.
                 *
                 * @return valid A boolean indicating whether the order is active.
                 */
                function _verifyTime(
                    uint256 startTime,
                    uint256 endTime,
                    bool revertOnInvalid
                ) internal view returns (bool valid) {
                    // Mark as valid if order has started and has not already ended.
                    assembly {
                        valid := and(
                            iszero(gt(startTime, timestamp())),
                            gt(endTime, timestamp())
                        )
                    }
                    // Only revert on invalid if revertOnInvalid has been supplied as true.
                    if (revertOnInvalid && !valid) {
                        _revertInvalidTime(startTime, endTime);
                    }
                }
                /**
                 * @dev Internal view function to verify the signature of an order. An
                 *      ERC-1271 fallback will be attempted if either the signature length
                 *      is not 64 or 65 bytes or if the recovered signer does not match the
                 *      supplied offerer. Note that in cases where a 64 or 65 byte signature
                 *      is supplied, only standard ECDSA signatures that recover to a
                 *      non-zero address are supported.
                 *
                 * @param offerer   The offerer for the order.
                 * @param orderHash The order hash.
                 * @param signature A signature from the offerer indicating that the order
                 *                  has been approved.
                 */
                function _verifySignature(
                    address offerer,
                    bytes32 orderHash,
                    bytes memory signature
                ) internal view {
                    // Determine whether the offerer is the caller.
                    bool offererIsCaller;
                    assembly {
                        offererIsCaller := eq(offerer, caller())
                    }
                    // Skip signature verification if the offerer is the caller.
                    if (offererIsCaller) {
                        return;
                    }
                    // Derive the EIP-712 domain separator.
                    bytes32 domainSeparator = _domainSeparator();
                    // Derive original EIP-712 digest using domain separator and order hash.
                    bytes32 originalDigest = _deriveEIP712Digest(
                        domainSeparator,
                        orderHash
                    );
                    // Read the length of the signature from memory and place on the stack.
                    uint256 originalSignatureLength = signature.length;
                    // Determine effective digest if signature has a valid bulk order size.
                    bytes32 digest;
                    if (_isValidBulkOrderSize(originalSignatureLength)) {
                        // Rederive order hash and digest using bulk order proof.
                        (orderHash) = _computeBulkOrderProof(signature, orderHash);
                        digest = _deriveEIP712Digest(domainSeparator, orderHash);
                    } else {
                        // Supply the original digest as the effective digest.
                        digest = originalDigest;
                    }
                    // Ensure that the signature for the digest is valid for the offerer.
                    _assertValidSignature(
                        offerer,
                        digest,
                        originalDigest,
                        originalSignatureLength,
                        signature
                    );
                }
                /**
                 * @dev Determines whether the specified bulk order size is valid.
                 *
                 * @param signatureLength The signature length of the bulk order to check.
                 *
                 * @return validLength True if bulk order size is valid, false otherwise.
                 */
                function _isValidBulkOrderSize(
                    uint256 signatureLength
                ) internal pure returns (bool validLength) {
                    // Utilize assembly to validate the length; the equivalent logic is
                    // (64 + x) + 3 + 32y where (0 <= x <= 1) and (1 <= y <= 24).
                    assembly {
                        validLength := and(
                            lt(
                                sub(signatureLength, BulkOrderProof_minSize),
                                BulkOrderProof_rangeSize
                            ),
                            lt(
                                and(
                                    add(
                                        signatureLength,
                                        BulkOrderProof_lengthAdjustmentBeforeMask
                                    ),
                                    ThirtyOneBytes
                                ),
                                BulkOrderProof_lengthRangeAfterMask
                            )
                        )
                    }
                }
                /**
                 * @dev Computes the bulk order hash for the specified proof and leaf. Note
                 *      that if an index that exceeds the number of orders in the bulk order
                 *      payload will instead "wrap around" and refer to an earlier index.
                 *
                 * @param proofAndSignature The proof and signature of the bulk order.
                 * @param leaf              The leaf of the bulk order tree.
                 *
                 * @return bulkOrderHash The bulk order hash.
                 */
                function _computeBulkOrderProof(
                    bytes memory proofAndSignature,
                    bytes32 leaf
                ) internal pure returns (bytes32 bulkOrderHash) {
                    // Declare arguments for the root hash and the height of the proof.
                    bytes32 root;
                    uint256 height;
                    // Utilize assembly to efficiently derive the root hash using the proof.
                    assembly {
                        // Retrieve the length of the proof, key, and signature combined.
                        let fullLength := mload(proofAndSignature)
                        // If proofAndSignature has odd length, it is a compact signature
                        // with 64 bytes.
                        let signatureLength := sub(ECDSA_MaxLength, and(fullLength, 1))
                        // Derive height (or depth of tree) with signature and proof length.
                        height := shr(OneWordShift, sub(fullLength, signatureLength))
                        // Update the length in memory to only include the signature.
                        mstore(proofAndSignature, signatureLength)
                        // Derive the pointer for the key using the signature length.
                        let keyPtr := add(proofAndSignature, add(OneWord, signatureLength))
                        // Retrieve the three-byte key using the derived pointer.
                        let key := shr(BulkOrderProof_keyShift, mload(keyPtr))
                        /// Retrieve pointer to first proof element by applying a constant
                        // for the key size to the derived key pointer.
                        let proof := add(keyPtr, BulkOrderProof_keySize)
                        // Compute level 1.
                        let scratchPtr1 := shl(OneWordShift, and(key, 1))
                        mstore(scratchPtr1, leaf)
                        mstore(xor(scratchPtr1, OneWord), mload(proof))
                        // Compute remaining proofs.
                        for {
                            let i := 1
                        } lt(i, height) {
                            i := add(i, 1)
                        } {
                            proof := add(proof, OneWord)
                            let scratchPtr := shl(OneWordShift, and(shr(i, key), 1))
                            mstore(scratchPtr, keccak256(0, TwoWords))
                            mstore(xor(scratchPtr, OneWord), mload(proof))
                        }
                        // Compute root hash.
                        root := keccak256(0, TwoWords)
                    }
                    // Retrieve appropriate typehash constant based on height.
                    bytes32 rootTypeHash = _lookupBulkOrderTypehash(height);
                    // Use the typehash and the root hash to derive final bulk order hash.
                    assembly {
                        mstore(0, rootTypeHash)
                        mstore(OneWord, root)
                        bulkOrderHash := keccak256(0, TwoWords)
                    }
                }
                /**
                 * @dev Internal view function to validate that a given order is fillable
                 *      and not cancelled based on the order status.
                 *
                 * @param orderHash       The order hash.
                 * @param orderStatus     The status of the order, including whether it has
                 *                        been cancelled and the fraction filled.
                 * @param onlyAllowUnused A boolean flag indicating whether partial fills
                 *                        are supported by the calling function.
                 * @param revertOnInvalid A boolean indicating whether to revert if the
                 *                        order has been cancelled or filled beyond the
                 *                        allowable amount.
                 *
                 * @return valid A boolean indicating whether the order is valid.
                 */
                function _verifyOrderStatus(
                    bytes32 orderHash,
                    OrderStatus storage orderStatus,
                    bool onlyAllowUnused,
                    bool revertOnInvalid
                ) internal view returns (bool valid) {
                    // Ensure that the order has not been cancelled.
                    if (orderStatus.isCancelled) {
                        // Only revert if revertOnInvalid has been supplied as true.
                        if (revertOnInvalid) {
                            _revertOrderIsCancelled(orderHash);
                        }
                        // Return false as the order status is invalid.
                        return false;
                    }
                    // Read order status numerator from storage and place on stack.
                    uint256 orderStatusNumerator = orderStatus.numerator;
                    // If the order is not entirely unused...
                    if (orderStatusNumerator != 0) {
                        // ensure the order has not been partially filled when not allowed.
                        if (onlyAllowUnused) {
                            // Always revert on partial fills when onlyAllowUnused is true.
                            _revertOrderPartiallyFilled(orderHash);
                        }
                        // Otherwise, ensure that order has not been entirely filled.
                        else if (orderStatusNumerator >= orderStatus.denominator) {
                            // Only revert if revertOnInvalid has been supplied as true.
                            if (revertOnInvalid) {
                                _revertOrderAlreadyFilled(orderHash);
                            }
                            // Return false as the order status is invalid.
                            return false;
                        }
                    }
                    // Return true as the order status is valid.
                    valid = true;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import {
                BadReturnValueFromERC20OnTransfer_error_amount_ptr,
                BadReturnValueFromERC20OnTransfer_error_from_ptr,
                BadReturnValueFromERC20OnTransfer_error_length,
                BadReturnValueFromERC20OnTransfer_error_selector,
                BadReturnValueFromERC20OnTransfer_error_to_ptr,
                BadReturnValueFromERC20OnTransfer_error_token_ptr,
                BatchTransfer1155Params_amounts_head_ptr,
                BatchTransfer1155Params_calldata_baseSize,
                BatchTransfer1155Params_data_head_ptr,
                BatchTransfer1155Params_data_length_basePtr,
                BatchTransfer1155Params_ids_head_ptr,
                BatchTransfer1155Params_ids_length_offset,
                BatchTransfer1155Params_ids_length_ptr,
                BatchTransfer1155Params_ptr,
                ConduitBatch1155Transfer_amounts_length_baseOffset,
                ConduitBatch1155Transfer_from_offset,
                ConduitBatch1155Transfer_ids_head_offset,
                ConduitBatch1155Transfer_ids_length_offset,
                ConduitBatch1155Transfer_usable_head_size,
                ConduitBatchTransfer_amounts_head_offset,
                CostPerWord,
                DefaultFreeMemoryPointer,
                ERC1155_safeBatchTransferFrom_signature,
                ERC1155_safeTransferFrom_amount_ptr,
                ERC1155_safeTransferFrom_data_length_offset,
                ERC1155_safeTransferFrom_data_length_ptr,
                ERC1155_safeTransferFrom_data_offset_ptr,
                ERC1155_safeTransferFrom_from_ptr,
                ERC1155_safeTransferFrom_id_ptr,
                ERC1155_safeTransferFrom_length,
                ERC1155_safeTransferFrom_sig_ptr,
                ERC1155_safeTransferFrom_signature,
                ERC1155_safeTransferFrom_to_ptr,
                ERC1155BatchTransferGenericFailure_error_signature,
                ERC1155BatchTransferGenericFailure_ids_offset,
                ERC1155BatchTransferGenericFailure_token_ptr,
                ERC20_transferFrom_amount_ptr,
                ERC20_transferFrom_from_ptr,
                ERC20_transferFrom_length,
                ERC20_transferFrom_sig_ptr,
                ERC20_transferFrom_signature,
                ERC20_transferFrom_to_ptr,
                ERC721_transferFrom_from_ptr,
                ERC721_transferFrom_id_ptr,
                ERC721_transferFrom_length,
                ERC721_transferFrom_sig_ptr,
                ERC721_transferFrom_signature,
                ERC721_transferFrom_to_ptr,
                ExtraGasBuffer,
                FreeMemoryPointerSlot,
                Generic_error_selector_offset,
                Invalid1155BatchTransferEncoding_length,
                Invalid1155BatchTransferEncoding_ptr,
                Invalid1155BatchTransferEncoding_selector,
                MemoryExpansionCoefficientShift,
                NoContract_error_account_ptr,
                NoContract_error_length,
                NoContract_error_selector,
                OneWord,
                OneWordShift,
                Slot0x80,
                Slot0xA0,
                Slot0xC0,
                ThirtyOneBytes,
                TokenTransferGenericFailure_err_identifier_ptr,
                TokenTransferGenericFailure_error_amount_ptr,
                TokenTransferGenericFailure_error_from_ptr,
                TokenTransferGenericFailure_error_identifier_ptr,
                TokenTransferGenericFailure_error_length,
                TokenTransferGenericFailure_error_selector,
                TokenTransferGenericFailure_error_to_ptr,
                TokenTransferGenericFailure_error_token_ptr,
                TwoWords,
                TwoWordsShift,
                ZeroSlot
            } from "./TokenTransferrerConstants.sol";
            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 := shr(
                                                OneWordShift,
                                                add(returndatasize(), ThirtyOneBytes)
                                            )
                                            // Note: use the free memory pointer in place of
                                            // msize() to work around a Yul warning that
                                            // prevents accessing msize directly when the IR
                                            // pipeline is activated.
                                            let msizeWords := shr(OneWordShift, memPointer)
                                            // Next, compute the cost of the returndatacopy.
                                            let cost := mul(CostPerWord, returnDataWords)
                                            // Then, compute cost of new memory allocation.
                                            if gt(returnDataWords, msizeWords) {
                                                cost := add(
                                                    cost,
                                                    add(
                                                        mul(
                                                            sub(
                                                                returnDataWords,
                                                                msizeWords
                                                            ),
                                                            CostPerWord
                                                        ),
                                                        shr(
                                                            MemoryExpansionCoefficientShift,
                                                            sub(
                                                                mul(
                                                                    returnDataWords,
                                                                    returnDataWords
                                                                ),
                                                                mul(msizeWords, msizeWords)
                                                            )
                                                        )
                                                    )
                                                )
                                            }
                                            // Finally, add a small constant and compare to
                                            // gas remaining; bubble up the revert data if
                                            // enough gas is still available.
                                            if lt(add(cost, ExtraGasBuffer), gas()) {
                                                // Copy returndata to memory; overwrite
                                                // existing memory.
                                                returndatacopy(0, 0, returndatasize())
                                                // Revert, specifying memory region with
                                                // copied returndata.
                                                revert(0, returndatasize())
                                            }
                                        }
                                        // Store left-padded selector with push4, mem[28:32]
                                        mstore(
                                            0,
                                            TokenTransferGenericFailure_error_selector
                                        )
                                        mstore(
                                            TokenTransferGenericFailure_error_token_ptr,
                                            token
                                        )
                                        mstore(
                                            TokenTransferGenericFailure_error_from_ptr,
                                            from
                                        )
                                        mstore(TokenTransferGenericFailure_error_to_ptr, to)
                                        mstore(
                                            TokenTransferGenericFailure_err_identifier_ptr,
                                            0
                                        )
                                        mstore(
                                            TokenTransferGenericFailure_error_amount_ptr,
                                            amount
                                        )
                                        // revert(abi.encodeWithSignature(
                                        //     "TokenTransferGenericFailure(
                                        //         address,address,address,uint256,uint256
                                        //     )", token, from, to, identifier, amount
                                        // ))
                                        revert(
                                            Generic_error_selector_offset,
                                            TokenTransferGenericFailure_error_length
                                        )
                                    }
                                    // Otherwise revert with a message about the token
                                    // returning false or non-compliant return values.
                                    // Store left-padded selector with push4, mem[28:32]
                                    mstore(
                                        0,
                                        BadReturnValueFromERC20OnTransfer_error_selector
                                    )
                                    mstore(
                                        BadReturnValueFromERC20OnTransfer_error_token_ptr,
                                        token
                                    )
                                    mstore(
                                        BadReturnValueFromERC20OnTransfer_error_from_ptr,
                                        from
                                    )
                                    mstore(
                                        BadReturnValueFromERC20OnTransfer_error_to_ptr,
                                        to
                                    )
                                    mstore(
                                        BadReturnValueFromERC20OnTransfer_error_amount_ptr,
                                        amount
                                    )
                                    // revert(abi.encodeWithSignature(
                                    //     "BadReturnValueFromERC20OnTransfer(
                                    //         address,address,address,uint256
                                    //     )", token, from, to, amount
                                    // ))
                                    revert(
                                        Generic_error_selector_offset,
                                        BadReturnValueFromERC20OnTransfer_error_length
                                    )
                                }
                                // Otherwise, revert with error about token not having code:
                                // Store left-padded selector with push4, mem[28:32]
                                mstore(0, NoContract_error_selector)
                                mstore(NoContract_error_account_ptr, token)
                                // revert(abi.encodeWithSignature(
                                //      "NoContract(address)", account
                                // ))
                                revert(
                                    Generic_error_selector_offset,
                                    NoContract_error_length
                                )
                            }
                            // Otherwise, the token just returned no data despite the call
                            // having succeeded; no need to optimize for this as it's not
                            // technically ERC20 compliant.
                        }
                        // Restore the original free memory pointer.
                        mstore(FreeMemoryPointerSlot, memPointer)
                        // Restore the zero slot to zero.
                        mstore(ZeroSlot, 0)
                    }
                }
                /**
                 * @dev Internal function to transfer an ERC721 token from a given
                 *      originator to a given recipient. Sufficient approvals must be set on
                 *      the contract performing the transfer. Note that this function does
                 *      not check whether the receiver can accept the ERC721 token (i.e. it
                 *      does not use `safeTransferFrom`).
                 *
                 * @param token      The ERC721 token to transfer.
                 * @param from       The originator of the transfer.
                 * @param to         The recipient of the transfer.
                 * @param identifier The tokenId to transfer.
                 */
                function _performERC721Transfer(
                    address token,
                    address from,
                    address to,
                    uint256 identifier
                ) internal {
                    // Utilize assembly to perform an optimized ERC721 token transfer.
                    assembly {
                        // If the token has no code, revert.
                        if iszero(extcodesize(token)) {
                            // Store left-padded selector with push4, mem[28:32] = selector
                            mstore(0, NoContract_error_selector)
                            mstore(NoContract_error_account_ptr, token)
                            // revert(abi.encodeWithSignature(
                            //     "NoContract(address)", account
                            // ))
                            revert(Generic_error_selector_offset, NoContract_error_length)
                        }
                        // The free memory pointer memory slot will be used when populating
                        // call data for the transfer; read the value and restore it later.
                        let memPointer := mload(FreeMemoryPointerSlot)
                        // Write call data to memory starting with function selector.
                        mstore(ERC721_transferFrom_sig_ptr, ERC721_transferFrom_signature)
                        mstore(ERC721_transferFrom_from_ptr, from)
                        mstore(ERC721_transferFrom_to_ptr, to)
                        mstore(ERC721_transferFrom_id_ptr, identifier)
                        // Perform the call, ignoring return data.
                        let success := call(
                            gas(),
                            token,
                            0,
                            ERC721_transferFrom_sig_ptr,
                            ERC721_transferFrom_length,
                            0,
                            0
                        )
                        // If the transfer reverted:
                        if iszero(success) {
                            // If it returned a message, bubble it up as long as sufficient
                            // gas remains to do so:
                            if returndatasize() {
                                // Ensure that sufficient gas is available to copy
                                // returndata while expanding memory where necessary. Start
                                // by computing word size of returndata & allocated memory.
                                // Round up to the nearest full word.
                                let returnDataWords := shr(
                                    OneWordShift,
                                    add(returndatasize(), ThirtyOneBytes)
                                )
                                // Note: use the free memory pointer in place of msize() to
                                // work around a Yul warning that prevents accessing msize
                                // directly when the IR pipeline is activated.
                                let msizeWords := shr(OneWordShift, memPointer)
                                // Next, compute the cost of the returndatacopy.
                                let cost := mul(CostPerWord, returnDataWords)
                                // Then, compute cost of new memory allocation.
                                if gt(returnDataWords, msizeWords) {
                                    cost := add(
                                        cost,
                                        add(
                                            mul(
                                                sub(returnDataWords, msizeWords),
                                                CostPerWord
                                            ),
                                            shr(
                                                MemoryExpansionCoefficientShift,
                                                sub(
                                                    mul(returnDataWords, returnDataWords),
                                                    mul(msizeWords, msizeWords)
                                                )
                                            )
                                        )
                                    )
                                }
                                // Finally, add a small constant and compare to gas
                                // remaining; bubble up the revert data if enough gas is
                                // still available.
                                if lt(add(cost, ExtraGasBuffer), gas()) {
                                    // Copy returndata to memory; overwrite existing memory.
                                    returndatacopy(0, 0, returndatasize())
                                    // Revert, giving memory region with copied returndata.
                                    revert(0, returndatasize())
                                }
                            }
                            // Otherwise revert with a generic error message.
                            // Store left-padded selector with push4, mem[28:32] = selector
                            mstore(0, TokenTransferGenericFailure_error_selector)
                            mstore(TokenTransferGenericFailure_error_token_ptr, token)
                            mstore(TokenTransferGenericFailure_error_from_ptr, from)
                            mstore(TokenTransferGenericFailure_error_to_ptr, to)
                            mstore(
                                TokenTransferGenericFailure_error_identifier_ptr,
                                identifier
                            )
                            mstore(TokenTransferGenericFailure_error_amount_ptr, 1)
                            // revert(abi.encodeWithSignature(
                            //     "TokenTransferGenericFailure(
                            //         address,address,address,uint256,uint256
                            //     )", token, from, to, identifier, amount
                            // ))
                            revert(
                                Generic_error_selector_offset,
                                TokenTransferGenericFailure_error_length
                            )
                        }
                        // Restore the original free memory pointer.
                        mstore(FreeMemoryPointerSlot, memPointer)
                        // Restore the zero slot to zero.
                        mstore(ZeroSlot, 0)
                    }
                }
                /**
                 * @dev Internal function to transfer ERC1155 tokens from a given
                 *      originator to a given recipient. Sufficient approvals must be set on
                 *      the contract performing the transfer and contract recipients must
                 *      implement the ERC1155TokenReceiver interface to indicate that they
                 *      are willing to accept the transfer.
                 *
                 * @param token      The ERC1155 token to transfer.
                 * @param from       The originator of the transfer.
                 * @param to         The recipient of the transfer.
                 * @param identifier The id to transfer.
                 * @param amount     The amount to transfer.
                 */
                function _performERC1155Transfer(
                    address token,
                    address from,
                    address to,
                    uint256 identifier,
                    uint256 amount
                ) internal {
                    // Utilize assembly to perform an optimized ERC1155 token transfer.
                    assembly {
                        // If the token has no code, revert.
                        if iszero(extcodesize(token)) {
                            // Store left-padded selector with push4, mem[28:32] = selector
                            mstore(0, NoContract_error_selector)
                            mstore(NoContract_error_account_ptr, token)
                            // revert(abi.encodeWithSignature(
                            //     "NoContract(address)", account
                            // ))
                            revert(Generic_error_selector_offset, NoContract_error_length)
                        }
                        // The following memory slots will be used when populating call data
                        // for the transfer; read the values and restore them later.
                        let memPointer := mload(FreeMemoryPointerSlot)
                        let slot0x80 := mload(Slot0x80)
                        let slot0xA0 := mload(Slot0xA0)
                        let slot0xC0 := mload(Slot0xC0)
                        // Write call data into memory, beginning with function selector.
                        mstore(
                            ERC1155_safeTransferFrom_sig_ptr,
                            ERC1155_safeTransferFrom_signature
                        )
                        mstore(ERC1155_safeTransferFrom_from_ptr, from)
                        mstore(ERC1155_safeTransferFrom_to_ptr, to)
                        mstore(ERC1155_safeTransferFrom_id_ptr, identifier)
                        mstore(ERC1155_safeTransferFrom_amount_ptr, amount)
                        mstore(
                            ERC1155_safeTransferFrom_data_offset_ptr,
                            ERC1155_safeTransferFrom_data_length_offset
                        )
                        mstore(ERC1155_safeTransferFrom_data_length_ptr, 0)
                        // Perform the call, ignoring return data.
                        let success := call(
                            gas(),
                            token,
                            0,
                            ERC1155_safeTransferFrom_sig_ptr,
                            ERC1155_safeTransferFrom_length,
                            0,
                            0
                        )
                        // If the transfer reverted:
                        if iszero(success) {
                            // If it returned a message, bubble it up as long as sufficient
                            // gas remains to do so:
                            if returndatasize() {
                                // Ensure that sufficient gas is available to copy
                                // returndata while expanding memory where necessary. Start
                                // by computing word size of returndata & allocated memory.
                                // Round up to the nearest full word.
                                let returnDataWords := shr(
                                    OneWordShift,
                                    add(returndatasize(), ThirtyOneBytes)
                                )
                                // Note: use the free memory pointer in place of msize() to
                                // work around a Yul warning that prevents accessing msize
                                // directly when the IR pipeline is activated.
                                let msizeWords := shr(OneWordShift, memPointer)
                                // Next, compute the cost of the returndatacopy.
                                let cost := mul(CostPerWord, returnDataWords)
                                // Then, compute cost of new memory allocation.
                                if gt(returnDataWords, msizeWords) {
                                    cost := add(
                                        cost,
                                        add(
                                            mul(
                                                sub(returnDataWords, msizeWords),
                                                CostPerWord
                                            ),
                                            shr(
                                                MemoryExpansionCoefficientShift,
                                                sub(
                                                    mul(returnDataWords, returnDataWords),
                                                    mul(msizeWords, msizeWords)
                                                )
                                            )
                                        )
                                    )
                                }
                                // Finally, add a small constant and compare to gas
                                // remaining; bubble up the revert data if enough gas is
                                // still available.
                                if lt(add(cost, ExtraGasBuffer), gas()) {
                                    // Copy returndata to memory; overwrite existing memory.
                                    returndatacopy(0, 0, returndatasize())
                                    // Revert, giving memory region with copied returndata.
                                    revert(0, returndatasize())
                                }
                            }
                            // Otherwise revert with a generic error message.
                            // Store left-padded selector with push4, mem[28:32] = selector
                            mstore(0, TokenTransferGenericFailure_error_selector)
                            mstore(TokenTransferGenericFailure_error_token_ptr, token)
                            mstore(TokenTransferGenericFailure_error_from_ptr, from)
                            mstore(TokenTransferGenericFailure_error_to_ptr, to)
                            mstore(
                                TokenTransferGenericFailure_error_identifier_ptr,
                                identifier
                            )
                            mstore(TokenTransferGenericFailure_error_amount_ptr, amount)
                            // revert(abi.encodeWithSignature(
                            //     "TokenTransferGenericFailure(
                            //         address,address,address,uint256,uint256
                            //     )", token, from, to, identifier, amount
                            // ))
                            revert(
                                Generic_error_selector_offset,
                                TokenTransferGenericFailure_error_length
                            )
                        }
                        mstore(Slot0x80, slot0x80) // Restore slot 0x80.
                        mstore(Slot0xA0, slot0xA0) // Restore slot 0xA0.
                        mstore(Slot0xC0, slot0xC0) // Restore slot 0xC0.
                        // Restore the original free memory pointer.
                        mstore(FreeMemoryPointerSlot, memPointer)
                        // Restore the zero slot to zero.
                        mstore(ZeroSlot, 0)
                    }
                }
                /**
                 * @dev Internal function to transfer ERC1155 tokens from a given
                 *      originator to a given recipient. Sufficient approvals must be set on
                 *      the contract performing the transfer and contract recipients must
                 *      implement the ERC1155TokenReceiver interface to indicate that they
                 *      are willing to accept the transfer. NOTE: this function is not
                 *      memory-safe; it will overwrite existing memory, restore the free
                 *      memory pointer to the default value, and overwrite the zero slot.
                 *      This function should only be called once memory is no longer
                 *      required and when uninitialized arrays are not utilized, and memory
                 *      should be considered fully corrupted (aside from the existence of a
                 *      default-value free memory pointer) after calling this function.
                 *
                 * @param batchTransfers The group of 1155 batch transfers to perform.
                 */
                function _performERC1155BatchTransfers(
                    ConduitBatch1155Transfer[] calldata batchTransfers
                ) internal {
                    // Utilize assembly to perform optimized batch 1155 transfers.
                    assembly {
                        let len := batchTransfers.length
                        // Pointer to first head in the array, which is offset to the struct
                        // at each index. This gets incremented after each loop to avoid
                        // multiplying by 32 to get the offset for each element.
                        let nextElementHeadPtr := batchTransfers.offset
                        // Pointer to beginning of the head of the array. This is the
                        // reference position each offset references. It's held static to
                        // let each loop calculate the data position for an element.
                        let arrayHeadPtr := nextElementHeadPtr
                        // Write the function selector, which will be reused for each call:
                        // safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)
                        mstore(
                            ConduitBatch1155Transfer_from_offset,
                            ERC1155_safeBatchTransferFrom_signature
                        )
                        // Iterate over each batch transfer.
                        for {
                            let i := 0
                        } lt(i, len) {
                            i := add(i, 1)
                        } {
                            // Read the offset to the beginning of the element and add
                            // it to pointer to the beginning of the array head to get
                            // the absolute position of the element in calldata.
                            let elementPtr := add(
                                arrayHeadPtr,
                                calldataload(nextElementHeadPtr)
                            )
                            // Retrieve the token from calldata.
                            let token := calldataload(elementPtr)
                            // If the token has no code, revert.
                            if iszero(extcodesize(token)) {
                                // Store left-padded selector with push4, mem[28:32]
                                mstore(0, NoContract_error_selector)
                                mstore(NoContract_error_account_ptr, token)
                                // revert(abi.encodeWithSignature(
                                //     "NoContract(address)", account
                                // ))
                                revert(
                                    Generic_error_selector_offset,
                                    NoContract_error_length
                                )
                            }
                            // Get the total number of supplied ids.
                            let idsLength := calldataload(
                                add(elementPtr, ConduitBatch1155Transfer_ids_length_offset)
                            )
                            // Determine the expected offset for the amounts array.
                            let expectedAmountsOffset := add(
                                ConduitBatch1155Transfer_amounts_length_baseOffset,
                                shl(OneWordShift, idsLength)
                            )
                            // Validate struct encoding.
                            let invalidEncoding := iszero(
                                and(
                                    // ids.length == amounts.length
                                    eq(
                                        idsLength,
                                        calldataload(add(elementPtr, expectedAmountsOffset))
                                    ),
                                    and(
                                        // ids_offset == 0xa0
                                        eq(
                                            calldataload(
                                                add(
                                                    elementPtr,
                                                    ConduitBatch1155Transfer_ids_head_offset
                                                )
                                            ),
                                            ConduitBatch1155Transfer_ids_length_offset
                                        ),
                                        // amounts_offset == 0xc0 + ids.length*32
                                        eq(
                                            calldataload(
                                                add(
                                                    elementPtr,
                                                    ConduitBatchTransfer_amounts_head_offset
                                                )
                                            ),
                                            expectedAmountsOffset
                                        )
                                    )
                                )
                            )
                            // Revert with an error if the encoding is not valid.
                            if invalidEncoding {
                                // Store left-padded selector with push4, mem[28:32]
                                mstore(
                                    Invalid1155BatchTransferEncoding_ptr,
                                    Invalid1155BatchTransferEncoding_selector
                                )
                                // revert(abi.encodeWithSignature(
                                //     "Invalid1155BatchTransferEncoding()"
                                // ))
                                revert(
                                    Invalid1155BatchTransferEncoding_ptr,
                                    Invalid1155BatchTransferEncoding_length
                                )
                            }
                            // Update the offset position for the next loop
                            nextElementHeadPtr := add(nextElementHeadPtr, OneWord)
                            // Copy the first section of calldata (before dynamic values).
                            calldatacopy(
                                BatchTransfer1155Params_ptr,
                                add(elementPtr, ConduitBatch1155Transfer_from_offset),
                                ConduitBatch1155Transfer_usable_head_size
                            )
                            // Determine size of calldata required for ids and amounts. Note
                            // that the size includes both lengths as well as the data.
                            let idsAndAmountsSize := add(
                                TwoWords,
                                shl(TwoWordsShift, idsLength)
                            )
                            // Update the offset for the data array in memory.
                            mstore(
                                BatchTransfer1155Params_data_head_ptr,
                                add(
                                    BatchTransfer1155Params_ids_length_offset,
                                    idsAndAmountsSize
                                )
                            )
                            // Set the length of the data array in memory to zero.
                            mstore(
                                add(
                                    BatchTransfer1155Params_data_length_basePtr,
                                    idsAndAmountsSize
                                ),
                                0
                            )
                            // Determine the total calldata size for the call to transfer.
                            let transferDataSize := add(
                                BatchTransfer1155Params_calldata_baseSize,
                                idsAndAmountsSize
                            )
                            // Copy second section of calldata (including dynamic values).
                            calldatacopy(
                                BatchTransfer1155Params_ids_length_ptr,
                                add(elementPtr, ConduitBatch1155Transfer_ids_length_offset),
                                idsAndAmountsSize
                            )
                            // Perform the call to transfer 1155 tokens.
                            let success := call(
                                gas(),
                                token,
                                0,
                                ConduitBatch1155Transfer_from_offset, // Data 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 := shr(
                                        OneWordShift,
                                        add(returndatasize(), ThirtyOneBytes)
                                    )
                                    // Note: use transferDataSize in place of msize() to
                                    // work around a Yul warning that prevents accessing
                                    // msize directly when the IR pipeline is activated.
                                    // The free memory pointer is not used here because
                                    // this function does almost all memory management
                                    // manually and does not update it, and transferDataSize
                                    // should be the largest memory value used (unless a
                                    // previous batch was larger).
                                    let msizeWords := shr(OneWordShift, transferDataSize)
                                    // Next, compute the cost of the returndatacopy.
                                    let cost := mul(CostPerWord, returnDataWords)
                                    // Then, compute cost of new memory allocation.
                                    if gt(returnDataWords, msizeWords) {
                                        cost := add(
                                            cost,
                                            add(
                                                mul(
                                                    sub(returnDataWords, msizeWords),
                                                    CostPerWord
                                                ),
                                                shr(
                                                    MemoryExpansionCoefficientShift,
                                                    sub(
                                                        mul(
                                                            returnDataWords,
                                                            returnDataWords
                                                        ),
                                                        mul(msizeWords, msizeWords)
                                                    )
                                                )
                                            )
                                        )
                                    }
                                    // Finally, add a small constant and compare to gas
                                    // remaining; bubble up the revert data if enough gas is
                                    // still available.
                                    if lt(add(cost, ExtraGasBuffer), gas()) {
                                        // Copy returndata to memory; overwrite existing.
                                        returndatacopy(0, 0, returndatasize())
                                        // Revert with memory region containing returndata.
                                        revert(0, returndatasize())
                                    }
                                }
                                // Set the error signature.
                                mstore(
                                    0,
                                    ERC1155BatchTransferGenericFailure_error_signature
                                )
                                // Write the token.
                                mstore(ERC1155BatchTransferGenericFailure_token_ptr, token)
                                // Increase the offset to ids by 32.
                                mstore(
                                    BatchTransfer1155Params_ids_head_ptr,
                                    ERC1155BatchTransferGenericFailure_ids_offset
                                )
                                // Increase the offset to amounts by 32.
                                mstore(
                                    BatchTransfer1155Params_amounts_head_ptr,
                                    add(
                                        OneWord,
                                        mload(BatchTransfer1155Params_amounts_head_ptr)
                                    )
                                )
                                // Return modified region. The total size stays the same as
                                // `token` uses the same number of bytes as `data.length`.
                                revert(0, transferDataSize)
                            }
                        }
                        // Reset the free memory pointer to the default value; memory must
                        // be assumed to be dirtied and not reused from this point forward.
                        // Also note that the zero slot is not reset to zero, meaning empty
                        // arrays cannot be safely created or utilized until it is restored.
                        mstore(FreeMemoryPointerSlot, DefaultFreeMemoryPointer)
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import { ConduitItemType } from "./ConduitEnums.sol";
            /**
             * @dev A ConduitTransfer is a struct that contains the information needed for a
             *      conduit to transfer an item from one address to another.
             */
            struct ConduitTransfer {
                ConduitItemType itemType;
                address token;
                address from;
                address to;
                uint256 identifier;
                uint256 amount;
            }
            /**
             * @dev A ConduitBatch1155Transfer is a struct that contains the information
             *      needed for a conduit to transfer a batch of ERC-1155 tokens from one
             *      address to another.
             */
            struct ConduitBatch1155Transfer {
                address token;
                address from;
                address to;
                uint256[] ids;
                uint256[] amounts;
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.17;
            import { OrderParameters } from "./ConsiderationStructs.sol";
            import { GettersAndDerivers } from "./GettersAndDerivers.sol";
            import {
                TokenTransferrerErrors
            } from "../interfaces/TokenTransferrerErrors.sol";
            import { CounterManager } from "./CounterManager.sol";
            import {
                AdditionalRecipient_size_shift,
                AddressDirtyUpperBitThreshold,
                BasicOrder_additionalRecipients_head_cdPtr,
                BasicOrder_additionalRecipients_head_ptr,
                BasicOrder_additionalRecipients_length_cdPtr,
                BasicOrder_basicOrderType_cdPtr,
                BasicOrder_basicOrderType_range,
                BasicOrder_considerationToken_cdPtr,
                BasicOrder_offerer_cdPtr,
                BasicOrder_offerToken_cdPtr,
                BasicOrder_parameters_cdPtr,
                BasicOrder_parameters_ptr,
                BasicOrder_signature_cdPtr,
                BasicOrder_signature_ptr,
                BasicOrder_zone_cdPtr
            } from "./ConsiderationConstants.sol";
            import {
                Error_selector_offset,
                MissingItemAmount_error_length,
                MissingItemAmount_error_selector
            } from "./ConsiderationErrorConstants.sol";
            import {
                _revertInvalidBasicOrderParameterEncoding,
                _revertMissingOriginalConsiderationItems
            } from "./ConsiderationErrors.sol";
            /**
             * @title Assertions
             * @author 0age
             * @notice Assertions contains logic for making various assertions that do not
             *         fit neatly within a dedicated semantic scope.
             */
            contract Assertions is
                GettersAndDerivers,
                CounterManager,
                TokenTransferrerErrors
            {
                /**
                 * @dev Derive and set hashes, reference chainId, and associated domain
                 *      separator during deployment.
                 *
                 * @param conduitController A contract that deploys conduits, or proxies
                 *                          that may optionally be used to transfer approved
                 *                          ERC20/721/1155 tokens.
                 */
                constructor(
                    address conduitController
                ) GettersAndDerivers(conduitController) {}
                /**
                 * @dev Internal view function to ensure that the supplied consideration
                 *      array length on a given set of order parameters is not less than the
                 *      original consideration array length for that order and to retrieve
                 *      the current counter for a given order's offerer and zone and use it
                 *      to derive the order hash.
                 *
                 * @param orderParameters The parameters of the order to hash.
                 *
                 * @return The hash.
                 */
                function _assertConsiderationLengthAndGetOrderHash(
                    OrderParameters memory orderParameters
                ) internal view returns (bytes32) {
                    // Ensure supplied consideration array length is not less than original.
                    _assertConsiderationLengthIsNotLessThanOriginalConsiderationLength(
                        orderParameters.consideration.length,
                        orderParameters.totalOriginalConsiderationItems
                    );
                    // Derive and return order hash using current counter for the offerer.
                    return
                        _deriveOrderHash(
                            orderParameters,
                            _getCounter(orderParameters.offerer)
                        );
                }
                /**
                 * @dev Internal pure function to ensure that the supplied consideration
                 *      array length for an order to be fulfilled is not less than the
                 *      original consideration array length for that order.
                 *
                 * @param suppliedConsiderationItemTotal The number of consideration items
                 *                                       supplied when fulfilling the order.
                 * @param originalConsiderationItemTotal The number of consideration items
                 *                                       supplied on initial order creation.
                 */
                function _assertConsiderationLengthIsNotLessThanOriginalConsiderationLength(
                    uint256 suppliedConsiderationItemTotal,
                    uint256 originalConsiderationItemTotal
                ) internal pure {
                    // Ensure supplied consideration array length is not less than original.
                    if (suppliedConsiderationItemTotal < originalConsiderationItemTotal) {
                        _revertMissingOriginalConsiderationItems();
                    }
                }
                /**
                 * @dev Internal pure function to ensure that a given item amount is not
                 *      zero.
                 *
                 * @param amount The amount to check.
                 */
                function _assertNonZeroAmount(uint256 amount) internal pure {
                    assembly {
                        if iszero(amount) {
                            // Store left-padded selector with push4, mem[28:32] = selector
                            mstore(0, MissingItemAmount_error_selector)
                            // revert(abi.encodeWithSignature("MissingItemAmount()"))
                            revert(Error_selector_offset, MissingItemAmount_error_length)
                        }
                    }
                }
                /**
                 * @dev Internal pure function to validate calldata offsets for dynamic
                 *      types in BasicOrderParameters and other parameters. This ensures
                 *      that functions using the calldata object normally will be using the
                 *      same data as the assembly functions and that values that are bound
                 *      to a given range are within that range. Note that no parameters are
                 *      supplied as all basic order functions use the same calldata
                 *      encoding.
                 */
                function _assertValidBasicOrderParameters() internal pure {
                    // Declare a boolean designating basic order parameter offset validity.
                    bool validOffsets;
                    // Utilize assembly in order to read offset data directly from calldata.
                    assembly {
                        /*
                         * Checks:
                         * 1. Order parameters struct offset == 0x20
                         * 2. Additional recipients arr offset == 0x240
                         * 3. Signature offset == 0x260 + (recipients.length * 0x40)
                         * 4. BasicOrderType between 0 and 23 (i.e. < 24)
                         * 5. Offerer, zone, offer token, and consideration token have no
                         *    upper dirty bits — each argument is type(uint160).max or less
                         */
                        validOffsets := and(
                            and(
                                and(
                                    // Order parameters at cd 0x04 must have offset of 0x20.
                                    eq(
                                        calldataload(BasicOrder_parameters_cdPtr),
                                        BasicOrder_parameters_ptr
                                    ),
                                    // Additional recipients (cd 0x224) arr offset == 0x240.
                                    eq(
                                        calldataload(
                                            BasicOrder_additionalRecipients_head_cdPtr
                                        ),
                                        BasicOrder_additionalRecipients_head_ptr
                                    )
                                ),
                                // Signature offset == 0x260 + (recipients.length * 0x40).
                                eq(
                                    // Load signature offset from calldata 0x244.
                                    calldataload(BasicOrder_signature_cdPtr),
                                    // Expected offset is start of recipients + len * 64.
                                    add(
                                        BasicOrder_signature_ptr,
                                        shl(
                                            // Each additional recipient has length of 0x40.
                                            AdditionalRecipient_size_shift,
                                            // Additional recipients length at cd 0x264.
                                            calldataload(
                                                BasicOrder_additionalRecipients_length_cdPtr
                                            )
                                        )
                                    )
                                )
                            ),
                            and(
                                // Ensure BasicOrderType parameter is less than 0x18.
                                lt(
                                    // BasicOrderType parameter at calldata offset 0x124.
                                    calldataload(BasicOrder_basicOrderType_cdPtr),
                                    // Value should be less than 24.
                                    BasicOrder_basicOrderType_range
                                ),
                                // Ensure no dirty upper bits are present on offerer, zone,
                                // offer token, or consideration token.
                                lt(
                                    or(
                                        or(
                                            // Offerer parameter at calldata offset 0x84.
                                            calldataload(BasicOrder_offerer_cdPtr),
                                            // Zone parameter at calldata offset 0xa4.
                                            calldataload(BasicOrder_zone_cdPtr)
                                        ),
                                        or(
                                            // Offer token parameter at cd offset 0xc4.
                                            calldataload(BasicOrder_offerToken_cdPtr),
                                            // Consideration token parameter at offset 0x24.
                                            calldataload(
                                                BasicOrder_considerationToken_cdPtr
                                            )
                                        )
                                    ),
                                    AddressDirtyUpperBitThreshold
                                )
                            )
                        )
                    }
                    // Revert with an error if basic order parameter offsets are invalid.
                    if (!validOffsets) {
                        _revertInvalidBasicOrderParameterEncoding();
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.17;
            import {
                SignatureVerificationErrors
            } from "../interfaces/SignatureVerificationErrors.sol";
            import { LowLevelHelpers } from "./LowLevelHelpers.sol";
            import {
                ECDSA_MaxLength,
                ECDSA_signature_s_offset,
                ECDSA_signature_v_offset,
                ECDSA_twentySeventhAndTwentyEighthBytesSet,
                Ecrecover_args_size,
                Ecrecover_precompile,
                EIP1271_isValidSignature_calldata_baseLength,
                EIP1271_isValidSignature_digest_negativeOffset,
                EIP1271_isValidSignature_selector_negativeOffset,
                EIP1271_isValidSignature_selector,
                EIP1271_isValidSignature_signature_head_offset,
                EIP2098_allButHighestBitMask,
                MaxUint8,
                OneWord,
                Signature_lower_v
            } from "./ConsiderationConstants.sol";
            import {
                BadContractSignature_error_length,
                BadContractSignature_error_selector,
                BadSignatureV_error_length,
                BadSignatureV_error_selector,
                BadSignatureV_error_v_ptr,
                Error_selector_offset,
                InvalidSignature_error_length,
                InvalidSignature_error_selector,
                InvalidSigner_error_length,
                InvalidSigner_error_selector
            } from "./ConsiderationErrorConstants.sol";
            /**
             * @title SignatureVerification
             * @author 0age
             * @notice SignatureVerification contains logic for verifying signatures.
             */
            contract SignatureVerification is SignatureVerificationErrors, LowLevelHelpers {
                /**
                 * @dev Internal view function to verify the signature of an order. An
                 *      ERC-1271 fallback will be attempted if either the signature length
                 *      is not 64 or 65 bytes or if the recovered signer does not match the
                 *      supplied signer.
                 *
                 * @param signer                  The signer for the order.
                 * @param digest                  The digest to verify signature against.
                 * @param originalDigest          The original digest to verify signature
                 *                                against.
                 * @param originalSignatureLength The original signature length.
                 * @param signature               A signature from the signer indicating
                 *                                that the order has been approved.
                 */
                function _assertValidSignature(
                    address signer,
                    bytes32 digest,
                    bytes32 originalDigest,
                    uint256 originalSignatureLength,
                    bytes memory signature
                ) internal view {
                    // Declare value for ecrecover equality or 1271 call success status.
                    bool success;
                    // Utilize assembly to perform optimized signature verification check.
                    assembly {
                        // Ensure that first word of scratch space is empty.
                        mstore(0, 0)
                        // Get the length of the signature.
                        let signatureLength := mload(signature)
                        // Get the pointer to the value preceding the signature length.
                        // This will be used for temporary memory overrides - either the
                        // signature head for isValidSignature or the digest for ecrecover.
                        let wordBeforeSignaturePtr := sub(signature, OneWord)
                        // Cache the current value behind the signature to restore it later.
                        let cachedWordBeforeSignature := mload(wordBeforeSignaturePtr)
                        // Declare lenDiff + recoveredSigner scope to manage stack pressure.
                        {
                            // Take the difference between the max ECDSA signature length
                            // and the actual signature length. Overflow desired for any
                            // values > 65. If the diff is not 0 or 1, it is not a valid
                            // ECDSA signature - move on to EIP1271 check.
                            let lenDiff := sub(ECDSA_MaxLength, signatureLength)
                            // Declare variable for recovered signer.
                            let recoveredSigner
                            // If diff is 0 or 1, it may be an ECDSA signature.
                            // Try to recover signer.
                            if iszero(gt(lenDiff, 1)) {
                                // Read the signature `s` value.
                                let originalSignatureS := mload(
                                    add(signature, ECDSA_signature_s_offset)
                                )
                                // Read the first byte of the word after `s`. If the
                                // signature is 65 bytes, this will be the real `v` value.
                                // If not, it will need to be modified - doing it this way
                                // saves an extra condition.
                                let v := byte(
                                    0,
                                    mload(add(signature, ECDSA_signature_v_offset))
                                )
                                // If lenDiff is 1, parse 64-byte signature as ECDSA.
                                if lenDiff {
                                    // Extract yParity from highest bit of vs and add 27 to
                                    // get v.
                                    v := add(
                                        shr(MaxUint8, originalSignatureS),
                                        Signature_lower_v
                                    )
                                    // Extract canonical s from vs, all but the highest bit.
                                    // Temporarily overwrite the original `s` value in the
                                    // signature.
                                    mstore(
                                        add(signature, ECDSA_signature_s_offset),
                                        and(
                                            originalSignatureS,
                                            EIP2098_allButHighestBitMask
                                        )
                                    )
                                }
                                // Temporarily overwrite the signature length with `v` to
                                // conform to the expected input for ecrecover.
                                mstore(signature, v)
                                // Temporarily overwrite the word before the length with
                                // `digest` to conform to the expected input for ecrecover.
                                mstore(wordBeforeSignaturePtr, digest)
                                // Attempt to recover the signer for the given signature. Do
                                // not check the call status as ecrecover will return a null
                                // address if the signature is invalid.
                                pop(
                                    staticcall(
                                        gas(),
                                        Ecrecover_precompile, // Call ecrecover precompile.
                                        wordBeforeSignaturePtr, // Use data memory location.
                                        Ecrecover_args_size, // Size of digest, v, r, and s.
                                        0, // Write result to scratch space.
                                        OneWord // Provide size of returned result.
                                    )
                                )
                                // Restore cached word before signature.
                                mstore(wordBeforeSignaturePtr, cachedWordBeforeSignature)
                                // Restore cached signature length.
                                mstore(signature, signatureLength)
                                // Restore cached signature `s` value.
                                mstore(
                                    add(signature, ECDSA_signature_s_offset),
                                    originalSignatureS
                                )
                                // Read the recovered signer from the buffer given as return
                                // space for ecrecover.
                                recoveredSigner := mload(0)
                            }
                            // Set success to true if the signature provided was a valid
                            // ECDSA signature and the signer is not the null address. Use
                            // gt instead of direct as success is used outside of assembly.
                            success := and(eq(signer, recoveredSigner), gt(signer, 0))
                        }
                        // If the signature was not verified with ecrecover, try EIP1271.
                        if iszero(success) {
                            // Reset the original signature length.
                            mstore(signature, originalSignatureLength)
                            // Temporarily overwrite the word before the signature length
                            // and use it as the head of the signature input to
                            // `isValidSignature`, which has a value of 64.
                            mstore(
                                wordBeforeSignaturePtr,
                                EIP1271_isValidSignature_signature_head_offset
                            )
                            // Get pointer to use for the selector of `isValidSignature`.
                            let selectorPtr := sub(
                                signature,
                                EIP1271_isValidSignature_selector_negativeOffset
                            )
                            // Cache the value currently stored at the selector pointer.
                            let cachedWordOverwrittenBySelector := mload(selectorPtr)
                            // Cache the value currently stored at the digest pointer.
                            let cachedWordOverwrittenByDigest := mload(
                                sub(
                                    signature,
                                    EIP1271_isValidSignature_digest_negativeOffset
                                )
                            )
                            // Write the selector first, since it overlaps the digest.
                            mstore(selectorPtr, EIP1271_isValidSignature_selector)
                            // Next, write the original digest.
                            mstore(
                                sub(
                                    signature,
                                    EIP1271_isValidSignature_digest_negativeOffset
                                ),
                                originalDigest
                            )
                            // Call signer with `isValidSignature` to validate signature.
                            success := staticcall(
                                gas(),
                                signer,
                                selectorPtr,
                                add(
                                    originalSignatureLength,
                                    EIP1271_isValidSignature_calldata_baseLength
                                ),
                                0,
                                OneWord
                            )
                            // Determine if the signature is valid on successful calls.
                            if success {
                                // If first word of scratch space does not contain EIP-1271
                                // signature selector, revert.
                                if iszero(eq(mload(0), EIP1271_isValidSignature_selector)) {
                                    // Revert with bad 1271 signature if signer has code.
                                    if extcodesize(signer) {
                                        // Bad contract signature.
                                        // Store left-padded selector with push4, mem[28:32]
                                        mstore(0, BadContractSignature_error_selector)
                                        // revert(abi.encodeWithSignature(
                                        //     "BadContractSignature()"
                                        // ))
                                        revert(
                                            Error_selector_offset,
                                            BadContractSignature_error_length
                                        )
                                    }
                                    // Check if signature length was invalid.
                                    if gt(sub(ECDSA_MaxLength, signatureLength), 1) {
                                        // Revert with generic invalid signature error.
                                        // Store left-padded selector with push4, mem[28:32]
                                        mstore(0, InvalidSignature_error_selector)
                                        // revert(abi.encodeWithSignature(
                                        //     "InvalidSignature()"
                                        // ))
                                        revert(
                                            Error_selector_offset,
                                            InvalidSignature_error_length
                                        )
                                    }
                                    // Check if v was invalid.
                                    if and(
                                        eq(signatureLength, ECDSA_MaxLength),
                                        iszero(
                                            byte(
                                                byte(
                                                    0,
                                                    mload(
                                                        add(
                                                            signature,
                                                            ECDSA_signature_v_offset
                                                        )
                                                    )
                                                ),
                                                ECDSA_twentySeventhAndTwentyEighthBytesSet
                                            )
                                        )
                                    ) {
                                        // Revert with invalid v value.
                                        // Store left-padded selector with push4, mem[28:32]
                                        mstore(0, BadSignatureV_error_selector)
                                        mstore(
                                            BadSignatureV_error_v_ptr,
                                            byte(
                                                0,
                                                mload(
                                                    add(signature, ECDSA_signature_v_offset)
                                                )
                                            )
                                        )
                                        // revert(abi.encodeWithSignature(
                                        //     "BadSignatureV(uint8)", v
                                        // ))
                                        revert(
                                            Error_selector_offset,
                                            BadSignatureV_error_length
                                        )
                                    }
                                    // Revert with generic invalid signer error message.
                                    // Store left-padded selector with push4, mem[28:32]
                                    mstore(0, InvalidSigner_error_selector)
                                    // revert(abi.encodeWithSignature("InvalidSigner()"))
                                    revert(
                                        Error_selector_offset,
                                        InvalidSigner_error_length
                                    )
                                }
                            }
                            // Restore the cached values overwritten by selector, digest and
                            // signature head.
                            mstore(wordBeforeSignaturePtr, cachedWordBeforeSignature)
                            mstore(selectorPtr, cachedWordOverwrittenBySelector)
                            mstore(
                                sub(
                                    signature,
                                    EIP1271_isValidSignature_digest_negativeOffset
                                ),
                                cachedWordOverwrittenByDigest
                            )
                        }
                    }
                    // If the call failed...
                    if (!success) {
                        // Revert and pass reason along if one was returned.
                        _revertWithReasonIfOneIsReturned();
                        // Otherwise, revert with error indicating bad contract signature.
                        assembly {
                            // Store left-padded selector with push4, mem[28:32] = selector
                            mstore(0, BadContractSignature_error_selector)
                            // revert(abi.encodeWithSignature("BadContractSignature()"))
                            revert(Error_selector_offset, BadContractSignature_error_length)
                        }
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.17;
            import { OrderParameters } from "./ConsiderationStructs.sol";
            import { ConsiderationBase } from "./ConsiderationBase.sol";
            import {
                Create2AddressDerivation_length,
                Create2AddressDerivation_ptr,
                EIP_712_PREFIX,
                EIP712_ConsiderationItem_size,
                EIP712_DigestPayload_size,
                EIP712_DomainSeparator_offset,
                EIP712_OfferItem_size,
                EIP712_Order_size,
                EIP712_OrderHash_offset,
                FreeMemoryPointerSlot,
                information_conduitController_offset,
                information_domainSeparator_offset,
                information_length,
                information_version_cd_offset,
                information_version_offset,
                information_versionLengthPtr,
                information_versionWithLength,
                MaskOverByteTwelve,
                MaskOverLastTwentyBytes,
                OneWord,
                OneWordShift,
                OrderParameters_consideration_head_offset,
                OrderParameters_counter_offset,
                OrderParameters_offer_head_offset,
                TwoWords
            } from "./ConsiderationConstants.sol";
            /**
             * @title GettersAndDerivers
             * @author 0age
             * @notice ConsiderationInternal contains pure and internal view functions
             *         related to getting or deriving various values.
             */
            contract GettersAndDerivers is ConsiderationBase {
                /**
                 * @dev Derive and set hashes, reference chainId, and associated domain
                 *      separator during deployment.
                 *
                 * @param conduitController A contract that deploys conduits, or proxies
                 *                          that may optionally be used to transfer approved
                 *                          ERC20/721/1155 tokens.
                 */
                constructor(
                    address conduitController
                ) ConsiderationBase(conduitController) {}
                /**
                 * @dev Internal view function to derive the order hash for a given order.
                 *      Note that only the original consideration items are included in the
                 *      order hash, as additional consideration items may be supplied by the
                 *      caller.
                 *
                 * @param orderParameters The parameters of the order to hash.
                 * @param counter         The counter of the order to hash.
                 *
                 * @return orderHash The hash.
                 */
                function _deriveOrderHash(
                    OrderParameters memory orderParameters,
                    uint256 counter
                ) internal view returns (bytes32 orderHash) {
                    // Get length of original consideration array and place it on the stack.
                    uint256 originalConsiderationLength = (
                        orderParameters.totalOriginalConsiderationItems
                    );
                    /*
                     * Memory layout for an array of structs (dynamic or not) is similar
                     * to ABI encoding of dynamic types, with a head segment followed by
                     * a data segment. The main difference is that the head of an element
                     * is a memory pointer rather than an offset.
                     */
                    // Declare a variable for the derived hash of the offer array.
                    bytes32 offerHash;
                    // Read offer item EIP-712 typehash from runtime code & place on stack.
                    bytes32 typeHash = _OFFER_ITEM_TYPEHASH;
                    // Utilize assembly so that memory regions can be reused across hashes.
                    assembly {
                        // Retrieve the free memory pointer and place on the stack.
                        let hashArrPtr := mload(FreeMemoryPointerSlot)
                        // Get the pointer to the offers array.
                        let offerArrPtr := mload(
                            add(orderParameters, OrderParameters_offer_head_offset)
                        )
                        // Load the length.
                        let offerLength := mload(offerArrPtr)
                        // Set the pointer to the first offer's head.
                        offerArrPtr := add(offerArrPtr, OneWord)
                        // Iterate over the offer items.
                        for { let i := 0 } lt(i, offerLength) {
                            i := add(i, 1)
                        } {
                            // Read the pointer to the offer data and subtract one word
                            // to get typeHash pointer.
                            let ptr := sub(mload(offerArrPtr), OneWord)
                            // Read the current value before the offer data.
                            let value := mload(ptr)
                            // Write the type hash to the previous word.
                            mstore(ptr, typeHash)
                            // Take the EIP712 hash and store it in the hash array.
                            mstore(hashArrPtr, keccak256(ptr, EIP712_OfferItem_size))
                            // Restore the previous word.
                            mstore(ptr, value)
                            // Increment the array pointers by one word.
                            offerArrPtr := add(offerArrPtr, OneWord)
                            hashArrPtr := add(hashArrPtr, OneWord)
                        }
                        // Derive the offer hash using the hashes of each item.
                        offerHash := keccak256(
                            mload(FreeMemoryPointerSlot),
                            shl(OneWordShift, offerLength)
                        )
                    }
                    // Declare a variable for the derived hash of the consideration array.
                    bytes32 considerationHash;
                    // Read consideration item typehash from runtime code & place on stack.
                    typeHash = _CONSIDERATION_ITEM_TYPEHASH;
                    // Utilize assembly so that memory regions can be reused across hashes.
                    assembly {
                        // Retrieve the free memory pointer and place on the stack.
                        let hashArrPtr := mload(FreeMemoryPointerSlot)
                        // Get the pointer to the consideration array.
                        let considerationArrPtr := add(
                            mload(
                                add(
                                    orderParameters,
                                    OrderParameters_consideration_head_offset
                                )
                            ),
                            OneWord
                        )
                        // Iterate over the consideration items (not including tips).
                        for { let i := 0 } lt(i, originalConsiderationLength) {
                            i := add(i, 1)
                        } {
                            // Read the pointer to the consideration data and subtract one
                            // word to get typeHash pointer.
                            let ptr := sub(mload(considerationArrPtr), OneWord)
                            // Read the current value before the consideration data.
                            let value := mload(ptr)
                            // Write the type hash to the previous word.
                            mstore(ptr, typeHash)
                            // Take the EIP712 hash and store it in the hash array.
                            mstore(
                                hashArrPtr,
                                keccak256(ptr, EIP712_ConsiderationItem_size)
                            )
                            // Restore the previous word.
                            mstore(ptr, value)
                            // Increment the array pointers by one word.
                            considerationArrPtr := add(considerationArrPtr, OneWord)
                            hashArrPtr := add(hashArrPtr, OneWord)
                        }
                        // Derive the consideration hash using the hashes of each item.
                        considerationHash := keccak256(
                            mload(FreeMemoryPointerSlot),
                            shl(OneWordShift, originalConsiderationLength)
                        )
                    }
                    // Read order item EIP-712 typehash from runtime code & place on stack.
                    typeHash = _ORDER_TYPEHASH;
                    // Utilize assembly to access derived hashes & other arguments directly.
                    assembly {
                        // Retrieve pointer to the region located just behind parameters.
                        let typeHashPtr := sub(orderParameters, OneWord)
                        // Store the value at that pointer location to restore later.
                        let previousValue := mload(typeHashPtr)
                        // Store the order item EIP-712 typehash at the typehash location.
                        mstore(typeHashPtr, typeHash)
                        // Retrieve the pointer for the offer array head.
                        let offerHeadPtr := add(
                            orderParameters,
                            OrderParameters_offer_head_offset
                        )
                        // Retrieve the data pointer referenced by the offer head.
                        let offerDataPtr := mload(offerHeadPtr)
                        // Store the offer hash at the retrieved memory location.
                        mstore(offerHeadPtr, offerHash)
                        // Retrieve the pointer for the consideration array head.
                        let considerationHeadPtr := add(
                            orderParameters,
                            OrderParameters_consideration_head_offset
                        )
                        // Retrieve the data pointer referenced by the consideration head.
                        let considerationDataPtr := mload(considerationHeadPtr)
                        // Store the consideration hash at the retrieved memory location.
                        mstore(considerationHeadPtr, considerationHash)
                        // Retrieve the pointer for the counter.
                        let counterPtr := add(
                            orderParameters,
                            OrderParameters_counter_offset
                        )
                        // Store the counter at the retrieved memory location.
                        mstore(counterPtr, counter)
                        // Derive the order hash using the full range of order parameters.
                        orderHash := keccak256(typeHashPtr, EIP712_Order_size)
                        // Restore the value previously held at typehash pointer location.
                        mstore(typeHashPtr, previousValue)
                        // Restore offer data pointer at the offer head pointer location.
                        mstore(offerHeadPtr, offerDataPtr)
                        // Restore consideration data pointer at the consideration head ptr.
                        mstore(considerationHeadPtr, considerationDataPtr)
                        // Restore consideration item length at the counter pointer.
                        mstore(counterPtr, originalConsiderationLength)
                    }
                }
                /**
                 * @dev Internal view function to derive the address of a given conduit
                 *      using a corresponding conduit key.
                 *
                 * @param conduitKey A bytes32 value indicating what corresponding conduit,
                 *                   if any, to source token approvals from. This value is
                 *                   the "salt" parameter supplied by the deployer (i.e. the
                 *                   conduit controller) when deploying the given conduit.
                 *
                 * @return conduit The address of the conduit associated with the given
                 *                 conduit key.
                 */
                function _deriveConduit(
                    bytes32 conduitKey
                ) internal view returns (address conduit) {
                    // Read conduit controller address from runtime and place on the stack.
                    address conduitController = address(_CONDUIT_CONTROLLER);
                    // Read conduit creation code hash from runtime and place on the stack.
                    bytes32 conduitCreationCodeHash = _CONDUIT_CREATION_CODE_HASH;
                    // Leverage scratch space to perform an efficient hash.
                    assembly {
                        // Retrieve the free memory pointer; it will be replaced afterwards.
                        let freeMemoryPointer := mload(FreeMemoryPointerSlot)
                        // Place the control character and the conduit controller in scratch
                        // space; note that eleven bytes at the beginning are left unused.
                        mstore(0, or(MaskOverByteTwelve, conduitController))
                        // Place the conduit key in the next region of scratch space.
                        mstore(OneWord, conduitKey)
                        // Place conduit creation code hash in free memory pointer location.
                        mstore(TwoWords, conduitCreationCodeHash)
                        // Derive conduit by hashing and applying a mask over last 20 bytes.
                        conduit := and(
                            // Hash the relevant region.
                            keccak256(
                                // The region starts at memory pointer 11.
                                Create2AddressDerivation_ptr,
                                // The region is 85 bytes long (1 + 20 + 32 + 32).
                                Create2AddressDerivation_length
                            ),
                            // The address equals the last twenty bytes of the hash.
                            MaskOverLastTwentyBytes
                        )
                        // Restore the free memory pointer.
                        mstore(FreeMemoryPointerSlot, freeMemoryPointer)
                    }
                }
                /**
                 * @dev Internal view function to get the EIP-712 domain separator. If the
                 *      chainId matches the chainId set on deployment, the cached domain
                 *      separator will be returned; otherwise, it will be derived from
                 *      scratch.
                 *
                 * @return The domain separator.
                 */
                function _domainSeparator() internal view returns (bytes32) {
                    return block.chainid == _CHAIN_ID
                        ? _DOMAIN_SEPARATOR
                        : _deriveDomainSeparator();
                }
                /**
                 * @dev Internal view function to retrieve configuration information for
                 *      this contract.
                 *
                 * @return The contract version.
                 * @return The domain separator for this contract.
                 * @return The conduit Controller set for this contract.
                 */
                function _information()
                    internal
                    view
                    returns (
                        string memory /* version */,
                        bytes32 /* domainSeparator */,
                        address /* conduitController */
                    )
                {
                    // Derive the domain separator.
                    bytes32 domainSeparator = _domainSeparator();
                    // Declare variable as immutables cannot be accessed within assembly.
                    address conduitController = address(_CONDUIT_CONTROLLER);
                    // Return the version, domain separator, and conduit controller.
                    assembly {
                        mstore(information_version_offset, information_version_cd_offset)
                        mstore(information_domainSeparator_offset, domainSeparator)
                        mstore(information_conduitController_offset, conduitController)
                        mstore(information_versionLengthPtr, information_versionWithLength)
                        return(information_version_offset, information_length)
                    }
                }
                /**
                 * @dev Internal pure function to efficiently derive an digest to sign for
                 *      an order in accordance with EIP-712.
                 *
                 * @param domainSeparator The domain separator.
                 * @param orderHash       The order hash.
                 *
                 * @return value The hash.
                 */
                function _deriveEIP712Digest(
                    bytes32 domainSeparator,
                    bytes32 orderHash
                ) internal pure returns (bytes32 value) {
                    // Leverage scratch space to perform an efficient hash.
                    assembly {
                        // Place the EIP-712 prefix at the start of scratch space.
                        mstore(0, EIP_712_PREFIX)
                        // Place the domain separator in the next region of scratch space.
                        mstore(EIP712_DomainSeparator_offset, domainSeparator)
                        // Place the order hash in scratch space, spilling into the first
                        // two bytes of the free memory pointer — this should never be set
                        // as memory cannot be expanded to that size, and will be zeroed out
                        // after the hash is performed.
                        mstore(EIP712_OrderHash_offset, orderHash)
                        // Hash the relevant region (65 bytes).
                        value := keccak256(0, EIP712_DigestPayload_size)
                        // Clear out the dirtied bits in the memory pointer.
                        mstore(EIP712_OrderHash_offset, 0)
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            /**
             * @title TokenTransferrerErrors
             */
            interface TokenTransferrerErrors {
                /**
                 * @dev Revert with an error when an ERC721 transfer with amount other than
                 *      one is attempted.
                 *
                 * @param amount The amount of the ERC721 tokens to transfer.
                 */
                error InvalidERC721TransferAmount(uint256 amount);
                /**
                 * @dev Revert with an error when attempting to fulfill an order where an
                 *      item has an amount of zero.
                 */
                error MissingItemAmount();
                /**
                 * @dev Revert with an error when attempting to fulfill an order where an
                 *      item has unused parameters. This includes both the token and the
                 *      identifier parameters for native transfers as well as the identifier
                 *      parameter for ERC20 transfers. Note that the conduit does not
                 *      perform this check, leaving it up to the calling channel to enforce
                 *      when desired.
                 */
                error UnusedItemParameters();
                /**
                 * @dev Revert with an error when an ERC20, ERC721, or ERC1155 token
                 *      transfer reverts.
                 *
                 * @param token      The token for which the transfer was attempted.
                 * @param from       The source of the attempted transfer.
                 * @param to         The recipient of the attempted transfer.
                 * @param identifier The identifier for the attempted transfer.
                 * @param amount     The amount for the attempted transfer.
                 */
                error TokenTransferGenericFailure(
                    address token,
                    address from,
                    address to,
                    uint256 identifier,
                    uint256 amount
                );
                /**
                 * @dev Revert with an error when a batch ERC1155 token transfer reverts.
                 *
                 * @param token       The token for which the transfer was attempted.
                 * @param from        The source of the attempted transfer.
                 * @param to          The recipient of the attempted transfer.
                 * @param identifiers The identifiers for the attempted transfer.
                 * @param amounts     The amounts for the attempted transfer.
                 */
                error ERC1155BatchTransferGenericFailure(
                    address token,
                    address from,
                    address to,
                    uint256[] identifiers,
                    uint256[] amounts
                );
                /**
                 * @dev Revert with an error when an ERC20 token transfer returns a falsey
                 *      value.
                 *
                 * @param token      The token for which the ERC20 transfer was attempted.
                 * @param from       The source of the attempted ERC20 transfer.
                 * @param to         The recipient of the attempted ERC20 transfer.
                 * @param amount     The amount for the attempted ERC20 transfer.
                 */
                error BadReturnValueFromERC20OnTransfer(
                    address token,
                    address from,
                    address to,
                    uint256 amount
                );
                /**
                 * @dev Revert with an error when an account being called as an assumed
                 *      contract does not have code and returns no data.
                 *
                 * @param account The account that should contain code.
                 */
                error NoContract(address account);
                /**
                 * @dev Revert with an error when attempting to execute an 1155 batch
                 *      transfer using calldata not produced by default ABI encoding or with
                 *      different lengths for ids and amounts arrays.
                 */
                error Invalid1155BatchTransferEncoding();
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.17;
            import {
                ConsiderationEventsAndErrors
            } from "../interfaces/ConsiderationEventsAndErrors.sol";
            import { ReentrancyGuard } from "./ReentrancyGuard.sol";
            import {
                Counter_blockhash_shift,
                OneWord,
                TwoWords
            } from "./ConsiderationConstants.sol";
            /**
             * @title CounterManager
             * @author 0age
             * @notice CounterManager contains a storage mapping and related functionality
             *         for retrieving and incrementing a per-offerer counter.
             */
            contract CounterManager is ConsiderationEventsAndErrors, ReentrancyGuard {
                // Only orders signed using an offerer's current counter are fulfillable.
                mapping(address => uint256) private _counters;
                /**
                 * @dev Internal function to cancel all orders from a given offerer in bulk
                 *      by incrementing a counter by a large, quasi-random interval. Note
                 *      that only the offerer may increment the counter. Note that the
                 *      counter is incremented by a large, quasi-random interval, which
                 *      makes it infeasible to "activate" signed orders by incrementing the
                 *      counter.  This activation functionality can be achieved instead with
                 *      restricted orders or contract orders.
                 *
                 * @return newCounter The new counter.
                 */
                function _incrementCounter() internal returns (uint256 newCounter) {
                    // Ensure that the reentrancy guard is not currently set.
                    _assertNonReentrant();
                    // Utilize assembly to access counters storage mapping directly. Skip
                    // overflow check as counter cannot be incremented that far.
                    assembly {
                        // Use second half of previous block hash as a quasi-random number.
                        let quasiRandomNumber := shr(
                            Counter_blockhash_shift,
                            blockhash(sub(number(), 1))
                        )
                        // Write the caller to scratch space.
                        mstore(0, caller())
                        // Write the storage slot for _counters to scratch space.
                        mstore(OneWord, _counters.slot)
                        // Derive the storage pointer for the counter value.
                        let storagePointer := keccak256(0, TwoWords)
                        // Derive new counter value using random number and original value.
                        newCounter := add(quasiRandomNumber, sload(storagePointer))
                        // Store the updated counter value.
                        sstore(storagePointer, newCounter)
                    }
                    // Emit an event containing the new counter.
                    emit CounterIncremented(newCounter, msg.sender);
                }
                /**
                 * @dev Internal view function to retrieve the current counter for a given
                 *      offerer.
                 *
                 * @param offerer The offerer in question.
                 *
                 * @return currentCounter The current counter.
                 */
                function _getCounter(
                    address offerer
                ) internal view returns (uint256 currentCounter) {
                    // Return the counter for the supplied offerer.
                    currentCounter = _counters[offerer];
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.17;
            import {
                ConduitControllerInterface
            } from "../interfaces/ConduitControllerInterface.sol";
            import {
                ConsiderationEventsAndErrors
            } from "../interfaces/ConsiderationEventsAndErrors.sol";
            import {
                BulkOrder_Typehash_Height_One,
                BulkOrder_Typehash_Height_Two,
                BulkOrder_Typehash_Height_Three,
                BulkOrder_Typehash_Height_Four,
                BulkOrder_Typehash_Height_Five,
                BulkOrder_Typehash_Height_Six,
                BulkOrder_Typehash_Height_Seven,
                BulkOrder_Typehash_Height_Eight,
                BulkOrder_Typehash_Height_Nine,
                BulkOrder_Typehash_Height_Ten,
                BulkOrder_Typehash_Height_Eleven,
                BulkOrder_Typehash_Height_Twelve,
                BulkOrder_Typehash_Height_Thirteen,
                BulkOrder_Typehash_Height_Fourteen,
                BulkOrder_Typehash_Height_Fifteen,
                BulkOrder_Typehash_Height_Sixteen,
                BulkOrder_Typehash_Height_Seventeen,
                BulkOrder_Typehash_Height_Eighteen,
                BulkOrder_Typehash_Height_Nineteen,
                BulkOrder_Typehash_Height_Twenty,
                BulkOrder_Typehash_Height_TwentyOne,
                BulkOrder_Typehash_Height_TwentyTwo,
                BulkOrder_Typehash_Height_TwentyThree,
                BulkOrder_Typehash_Height_TwentyFour,
                EIP712_domainData_chainId_offset,
                EIP712_domainData_nameHash_offset,
                EIP712_domainData_size,
                EIP712_domainData_verifyingContract_offset,
                EIP712_domainData_versionHash_offset,
                FreeMemoryPointerSlot,
                NameLengthPtr,
                NameWithLength,
                OneWord,
                OneWordShift,
                Slot0x80,
                ThreeWords,
                ZeroSlot
            } from "./ConsiderationConstants.sol";
            import { ConsiderationDecoder } from "./ConsiderationDecoder.sol";
            import { ConsiderationEncoder } from "./ConsiderationEncoder.sol";
            /**
             * @title ConsiderationBase
             * @author 0age
             * @notice ConsiderationBase contains immutable constants and constructor logic.
             */
            contract ConsiderationBase is
                ConsiderationDecoder,
                ConsiderationEncoder,
                ConsiderationEventsAndErrors
            {
                // Precompute hashes, original chainId, and domain separator on deployment.
                bytes32 internal immutable _NAME_HASH;
                bytes32 internal immutable _VERSION_HASH;
                bytes32 internal immutable _EIP_712_DOMAIN_TYPEHASH;
                bytes32 internal immutable _OFFER_ITEM_TYPEHASH;
                bytes32 internal immutable _CONSIDERATION_ITEM_TYPEHASH;
                bytes32 internal immutable _ORDER_TYPEHASH;
                uint256 internal immutable _CHAIN_ID;
                bytes32 internal immutable _DOMAIN_SEPARATOR;
                // Allow for interaction with the conduit controller.
                ConduitControllerInterface internal immutable _CONDUIT_CONTROLLER;
                // Cache the conduit creation code hash used by the conduit controller.
                bytes32 internal immutable _CONDUIT_CREATION_CODE_HASH;
                /**
                 * @dev Derive and set hashes, reference chainId, and associated domain
                 *      separator during deployment.
                 *
                 * @param conduitController A contract that deploys conduits, or proxies
                 *                          that may optionally be used to transfer approved
                 *                          ERC20/721/1155 tokens.
                 */
                constructor(address conduitController) {
                    // Derive name and version hashes alongside required EIP-712 typehashes.
                    (
                        _NAME_HASH,
                        _VERSION_HASH,
                        _EIP_712_DOMAIN_TYPEHASH,
                        _OFFER_ITEM_TYPEHASH,
                        _CONSIDERATION_ITEM_TYPEHASH,
                        _ORDER_TYPEHASH
                    ) = _deriveTypehashes();
                    // Store the current chainId and derive the current domain separator.
                    _CHAIN_ID = block.chainid;
                    _DOMAIN_SEPARATOR = _deriveDomainSeparator();
                    // Set the supplied conduit controller.
                    _CONDUIT_CONTROLLER = ConduitControllerInterface(conduitController);
                    // Retrieve the conduit creation code hash from the supplied controller.
                    (_CONDUIT_CREATION_CODE_HASH, ) = (
                        _CONDUIT_CONTROLLER.getConduitCodeHashes()
                    );
                }
                /**
                 * @dev Internal view function to derive the EIP-712 domain separator.
                 *
                 * @return domainSeparator The derived domain separator.
                 */
                function _deriveDomainSeparator()
                    internal
                    view
                    returns (bytes32 domainSeparator)
                {
                    bytes32 typehash = _EIP_712_DOMAIN_TYPEHASH;
                    bytes32 nameHash = _NAME_HASH;
                    bytes32 versionHash = _VERSION_HASH;
                    // Leverage scratch space and other memory to perform an efficient hash.
                    assembly {
                        // Retrieve the free memory pointer; it will be replaced afterwards.
                        let freeMemoryPointer := mload(FreeMemoryPointerSlot)
                        // Retrieve value at 0x80; it will also be replaced afterwards.
                        let slot0x80 := mload(Slot0x80)
                        // Place typehash, name hash, and version hash at start of memory.
                        mstore(0, typehash)
                        mstore(EIP712_domainData_nameHash_offset, nameHash)
                        mstore(EIP712_domainData_versionHash_offset, versionHash)
                        // Place chainId in the next memory location.
                        mstore(EIP712_domainData_chainId_offset, chainid())
                        // Place the address of this contract in the next memory location.
                        mstore(EIP712_domainData_verifyingContract_offset, address())
                        // Hash relevant region of memory to derive the domain separator.
                        domainSeparator := keccak256(0, EIP712_domainData_size)
                        // Restore the free memory pointer.
                        mstore(FreeMemoryPointerSlot, freeMemoryPointer)
                        // Restore the zero slot to zero.
                        mstore(ZeroSlot, 0)
                        // Restore the value at 0x80.
                        mstore(Slot0x80, slot0x80)
                    }
                }
                /**
                 * @dev Internal pure function to retrieve the default name of this
                 *      contract and return.
                 *
                 * @return The name of this contract.
                 */
                function _name() internal pure virtual returns (string memory) {
                    // Return the name of the contract.
                    assembly {
                        // First element is the offset for the returned string. Offset the
                        // value in memory by one word so that the free memory pointer will
                        // be overwritten by the next write.
                        mstore(OneWord, OneWord)
                        // Name is right padded, so it touches the length which is left
                        // padded. This enables writing both values at once. The free memory
                        // pointer will be overwritten in the process.
                        mstore(NameLengthPtr, NameWithLength)
                        // Standard ABI encoding pads returned data to the nearest word. Use
                        // the already empty zero slot memory region for this purpose and
                        // return the final name string, offset by the original single word.
                        return(OneWord, ThreeWords)
                    }
                }
                /**
                 * @dev Internal pure function to retrieve the default name of this contract
                 *      as a string that can be used internally.
                 *
                 * @return The name of this contract.
                 */
                function _nameString() internal pure virtual returns (string memory) {
                    // Return the name of the contract.
                    return "Consideration";
                }
                /**
                 * @dev Internal pure function to derive required EIP-712 typehashes and
                 *      other hashes during contract creation.
                 *
                 * @return nameHash                  The hash of the name of the contract.
                 * @return versionHash               The hash of the version string of the
                 *                                   contract.
                 * @return eip712DomainTypehash      The primary EIP-712 domain typehash.
                 * @return offerItemTypehash         The EIP-712 typehash for OfferItem
                 *                                   types.
                 * @return considerationItemTypehash The EIP-712 typehash for
                 *                                   ConsiderationItem types.
                 * @return orderTypehash             The EIP-712 typehash for Order types.
                 */
                function _deriveTypehashes()
                    internal
                    pure
                    returns (
                        bytes32 nameHash,
                        bytes32 versionHash,
                        bytes32 eip712DomainTypehash,
                        bytes32 offerItemTypehash,
                        bytes32 considerationItemTypehash,
                        bytes32 orderTypehash
                    )
                {
                    // Derive hash of the name of the contract.
                    nameHash = keccak256(bytes(_nameString()));
                    // Derive hash of the version string of the contract.
                    versionHash = keccak256(bytes("1.4"));
                    // Construct the OfferItem type string.
                    bytes memory offerItemTypeString = bytes(
                        "OfferItem("
                        "uint8 itemType,"
                        "address token,"
                        "uint256 identifierOrCriteria,"
                        "uint256 startAmount,"
                        "uint256 endAmount"
                        ")"
                    );
                    // Construct the ConsiderationItem type string.
                    bytes memory considerationItemTypeString = bytes(
                        "ConsiderationItem("
                        "uint8 itemType,"
                        "address token,"
                        "uint256 identifierOrCriteria,"
                        "uint256 startAmount,"
                        "uint256 endAmount,"
                        "address recipient"
                        ")"
                    );
                    // Construct the OrderComponents type string, not including the above.
                    bytes memory orderComponentsPartialTypeString = bytes(
                        "OrderComponents("
                        "address offerer,"
                        "address zone,"
                        "OfferItem[] offer,"
                        "ConsiderationItem[] consideration,"
                        "uint8 orderType,"
                        "uint256 startTime,"
                        "uint256 endTime,"
                        "bytes32 zoneHash,"
                        "uint256 salt,"
                        "bytes32 conduitKey,"
                        "uint256 counter"
                        ")"
                    );
                    // Construct the primary EIP-712 domain type string.
                    eip712DomainTypehash = keccak256(
                        bytes(
                            "EIP712Domain("
                            "string name,"
                            "string version,"
                            "uint256 chainId,"
                            "address verifyingContract"
                            ")"
                        )
                    );
                    // Derive the OfferItem type hash using the corresponding type string.
                    offerItemTypehash = keccak256(offerItemTypeString);
                    // Derive ConsiderationItem type hash using corresponding type string.
                    considerationItemTypehash = keccak256(considerationItemTypeString);
                    bytes memory orderTypeString = bytes.concat(
                        orderComponentsPartialTypeString,
                        considerationItemTypeString,
                        offerItemTypeString
                    );
                    // Derive OrderItem type hash via combination of relevant type strings.
                    orderTypehash = keccak256(orderTypeString);
                }
                /**
                 * @dev Internal pure function to look up one of twenty-four potential bulk
                 *      order typehash constants based on the height of the bulk order tree.
                 *      Note that values between one and twenty-four are supported, which is
                 *      enforced by _isValidBulkOrderSize.
                 *
                 * @param _treeHeight The height of the bulk order tree. The value must be
                 *                    between one and twenty-four.
                 *
                 * @return _typeHash The EIP-712 typehash for the bulk order type with the
                 *                   given height.
                 */
                function _lookupBulkOrderTypehash(
                    uint256 _treeHeight
                ) internal pure returns (bytes32 _typeHash) {
                    // Utilize assembly to efficiently retrieve correct bulk order typehash.
                    assembly {
                        // Use a Yul function to enable use of the `leave` keyword
                        // to stop searching once the appropriate type hash is found.
                        function lookupTypeHash(treeHeight) -> typeHash {
                            // Handle tree heights one through eight.
                            if lt(treeHeight, 9) {
                                // Handle tree heights one through four.
                                if lt(treeHeight, 5) {
                                    // Handle tree heights one and two.
                                    if lt(treeHeight, 3) {
                                        // Utilize branchless logic to determine typehash.
                                        typeHash := ternary(
                                            eq(treeHeight, 1),
                                            BulkOrder_Typehash_Height_One,
                                            BulkOrder_Typehash_Height_Two
                                        )
                                        // Exit the function once typehash has been located.
                                        leave
                                    }
                                    // Handle height three and four via branchless logic.
                                    typeHash := ternary(
                                        eq(treeHeight, 3),
                                        BulkOrder_Typehash_Height_Three,
                                        BulkOrder_Typehash_Height_Four
                                    )
                                    // Exit the function once typehash has been located.
                                    leave
                                }
                                // Handle tree height five and six.
                                if lt(treeHeight, 7) {
                                    // Utilize branchless logic to determine typehash.
                                    typeHash := ternary(
                                        eq(treeHeight, 5),
                                        BulkOrder_Typehash_Height_Five,
                                        BulkOrder_Typehash_Height_Six
                                    )
                                    // Exit the function once typehash has been located.
                                    leave
                                }
                                // Handle height seven and eight via branchless logic.
                                typeHash := ternary(
                                    eq(treeHeight, 7),
                                    BulkOrder_Typehash_Height_Seven,
                                    BulkOrder_Typehash_Height_Eight
                                )
                                // Exit the function once typehash has been located.
                                leave
                            }
                            // Handle tree height nine through sixteen.
                            if lt(treeHeight, 17) {
                                // Handle tree height nine through twelve.
                                if lt(treeHeight, 13) {
                                    // Handle tree height nine and ten.
                                    if lt(treeHeight, 11) {
                                        // Utilize branchless logic to determine typehash.
                                        typeHash := ternary(
                                            eq(treeHeight, 9),
                                            BulkOrder_Typehash_Height_Nine,
                                            BulkOrder_Typehash_Height_Ten
                                        )
                                        // Exit the function once typehash has been located.
                                        leave
                                    }
                                    // Handle height eleven and twelve via branchless logic.
                                    typeHash := ternary(
                                        eq(treeHeight, 11),
                                        BulkOrder_Typehash_Height_Eleven,
                                        BulkOrder_Typehash_Height_Twelve
                                    )
                                    // Exit the function once typehash has been located.
                                    leave
                                }
                                // Handle tree height thirteen and fourteen.
                                if lt(treeHeight, 15) {
                                    // Utilize branchless logic to determine typehash.
                                    typeHash := ternary(
                                        eq(treeHeight, 13),
                                        BulkOrder_Typehash_Height_Thirteen,
                                        BulkOrder_Typehash_Height_Fourteen
                                    )
                                    // Exit the function once typehash has been located.
                                    leave
                                }
                                // Handle height fifteen and sixteen via branchless logic.
                                typeHash := ternary(
                                    eq(treeHeight, 15),
                                    BulkOrder_Typehash_Height_Fifteen,
                                    BulkOrder_Typehash_Height_Sixteen
                                )
                                // Exit the function once typehash has been located.
                                leave
                            }
                            // Handle tree height seventeen through twenty.
                            if lt(treeHeight, 21) {
                                // Handle tree height seventeen and eighteen.
                                if lt(treeHeight, 19) {
                                    // Utilize branchless logic to determine typehash.
                                    typeHash := ternary(
                                        eq(treeHeight, 17),
                                        BulkOrder_Typehash_Height_Seventeen,
                                        BulkOrder_Typehash_Height_Eighteen
                                    )
                                    // Exit the function once typehash has been located.
                                    leave
                                }
                                // Handle height nineteen and twenty via branchless logic.
                                typeHash := ternary(
                                    eq(treeHeight, 19),
                                    BulkOrder_Typehash_Height_Nineteen,
                                    BulkOrder_Typehash_Height_Twenty
                                )
                                // Exit the function once typehash has been located.
                                leave
                            }
                            // Handle tree height twenty-one and twenty-two.
                            if lt(treeHeight, 23) {
                                // Utilize branchless logic to determine typehash.
                                typeHash := ternary(
                                    eq(treeHeight, 21),
                                    BulkOrder_Typehash_Height_TwentyOne,
                                    BulkOrder_Typehash_Height_TwentyTwo
                                )
                                // Exit the function once typehash has been located.
                                leave
                            }
                            // Handle height twenty-three & twenty-four w/ branchless logic.
                            typeHash := ternary(
                                eq(treeHeight, 23),
                                BulkOrder_Typehash_Height_TwentyThree,
                                BulkOrder_Typehash_Height_TwentyFour
                            )
                            // Exit the function once typehash has been located.
                            leave
                        }
                        // Implement ternary conditional using branchless logic.
                        function ternary(cond, ifTrue, ifFalse) -> c {
                            c := xor(ifFalse, mul(cond, xor(ifFalse, ifTrue)))
                        }
                        // Look up the typehash using the supplied tree height.
                        _typeHash := lookupTypeHash(_treeHeight)
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            /**
             * @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.13;
            import {
                OrderParameters,
                ReceivedItem,
                SpentItem
            } from "../lib/ConsiderationStructs.sol";
            /**
             * @title ConsiderationEventsAndErrors
             * @author 0age
             * @notice ConsiderationEventsAndErrors contains all events and errors.
             */
            interface ConsiderationEventsAndErrors {
                /**
                 * @dev Emit an event whenever an order is successfully fulfilled.
                 *
                 * @param orderHash     The hash of the fulfilled order.
                 * @param offerer       The offerer of the fulfilled order.
                 * @param zone          The zone of the fulfilled order.
                 * @param recipient     The recipient of each spent item on the fulfilled
                 *                      order, or the null address if there is no specific
                 *                      fulfiller (i.e. the order is part of a group of
                 *                      orders). Defaults to the caller unless explicitly
                 *                      specified otherwise by the fulfiller.
                 * @param offer         The offer items spent as part of the order.
                 * @param consideration The consideration items received as part of the
                 *                      order along with the recipients of each item.
                 */
                event OrderFulfilled(
                    bytes32 orderHash,
                    address indexed offerer,
                    address indexed zone,
                    address recipient,
                    SpentItem[] offer,
                    ReceivedItem[] consideration
                );
                /**
                 * @dev Emit an event whenever an order is successfully cancelled.
                 *
                 * @param orderHash The hash of the cancelled order.
                 * @param offerer   The offerer of the cancelled order.
                 * @param zone      The zone of the cancelled order.
                 */
                event OrderCancelled(
                    bytes32 orderHash,
                    address indexed offerer,
                    address indexed zone
                );
                /**
                 * @dev Emit an event whenever an order is explicitly validated. Note that
                 *      this event will not be emitted on partial fills even though they do
                 *      validate the order as part of partial fulfillment.
                 *
                 * @param orderHash        The hash of the validated order.
                 * @param orderParameters  The parameters of the validated order.
                 */
                event OrderValidated(bytes32 orderHash, OrderParameters orderParameters);
                /**
                 * @dev Emit an event whenever one or more orders are matched using either
                 *      matchOrders or matchAdvancedOrders.
                 *
                 * @param orderHashes The order hashes of the matched orders.
                 */
                event OrdersMatched(bytes32[] orderHashes);
                /**
                 * @dev Emit an event whenever a counter for a given offerer is incremented.
                 *
                 * @param newCounter The new counter for the offerer.
                 * @param offerer    The offerer in question.
                 */
                event CounterIncremented(uint256 newCounter, address indexed offerer);
                /**
                 * @dev Revert with an error when attempting to fill an order that has
                 *      already been fully filled.
                 *
                 * @param orderHash The order hash on which a fill was attempted.
                 */
                error OrderAlreadyFilled(bytes32 orderHash);
                /**
                 * @dev Revert with an error when attempting to fill an order outside the
                 *      specified start time and end time.
                 *
                 * @param startTime The time at which the order becomes active.
                 * @param endTime   The time at which the order becomes inactive.
                 */
                error InvalidTime(uint256 startTime, uint256 endTime);
                /**
                 * @dev Revert with an error when attempting to fill an order referencing an
                 *      invalid conduit (i.e. one that has not been deployed).
                 */
                error InvalidConduit(bytes32 conduitKey, address conduit);
                /**
                 * @dev Revert with an error when an order is supplied for fulfillment with
                 *      a consideration array that is shorter than the original array.
                 */
                error MissingOriginalConsiderationItems();
                /**
                 * @dev Revert with an error when an order is validated and the length of
                 *      the consideration array is not equal to the supplied total original
                 *      consideration items value. This error is also thrown when contract
                 *      orders supply a total original consideration items value that does
                 *      not match the supplied consideration array length.
                 */
                error ConsiderationLengthNotEqualToTotalOriginal();
                /**
                 * @dev Revert with an error when a call to a conduit fails with revert data
                 *      that is too expensive to return.
                 */
                error InvalidCallToConduit(address conduit);
                /**
                 * @dev Revert with an error if a consideration amount has not been fully
                 *      zeroed out after applying all fulfillments.
                 *
                 * @param orderIndex         The index of the order with the consideration
                 *                           item with a shortfall.
                 * @param considerationIndex The index of the consideration item on the
                 *                           order.
                 * @param shortfallAmount    The unfulfilled consideration amount.
                 */
                error ConsiderationNotMet(
                    uint256 orderIndex,
                    uint256 considerationIndex,
                    uint256 shortfallAmount
                );
                /**
                 * @dev Revert with an error when insufficient native tokens are supplied as
                 *      part of msg.value when fulfilling orders.
                 */
                error InsufficientNativeTokensSupplied();
                /**
                 * @dev Revert with an error when a native token transfer reverts.
                 */
                error NativeTokenTransferGenericFailure(address account, uint256 amount);
                /**
                 * @dev Revert with an error when a partial fill is attempted on an order
                 *      that does not specify partial fill support in its order type.
                 */
                error PartialFillsNotEnabledForOrder();
                /**
                 * @dev Revert with an error when attempting to fill an order that has been
                 *      cancelled.
                 *
                 * @param orderHash The hash of the cancelled order.
                 */
                error OrderIsCancelled(bytes32 orderHash);
                /**
                 * @dev Revert with an error when attempting to fill a basic order that has
                 *      been partially filled.
                 *
                 * @param orderHash The hash of the partially used order.
                 */
                error OrderPartiallyFilled(bytes32 orderHash);
                /**
                 * @dev Revert with an error when attempting to cancel an order as a caller
                 *      other than the indicated offerer or zone or when attempting to
                 *      cancel a contract order.
                 */
                error CannotCancelOrder();
                /**
                 * @dev Revert with an error when supplying a fraction with a value of zero
                 *      for the numerator or denominator, or one where the numerator exceeds
                 *      the denominator.
                 */
                error BadFraction();
                /**
                 * @dev Revert with an error when a caller attempts to supply callvalue to a
                 *      non-payable basic order route or does not supply any callvalue to a
                 *      payable basic order route.
                 */
                error InvalidMsgValue(uint256 value);
                /**
                 * @dev Revert with an error when attempting to fill a basic order using
                 *      calldata not produced by default ABI encoding.
                 */
                error InvalidBasicOrderParameterEncoding();
                /**
                 * @dev Revert with an error when attempting to fulfill any number of
                 *      available orders when none are fulfillable.
                 */
                error NoSpecifiedOrdersAvailable();
                /**
                 * @dev Revert with an error when attempting to fulfill an order with an
                 *      offer for a native token outside of matching orders.
                 */
                error InvalidNativeOfferItem();
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.17;
            import {
                AdvancedOrder,
                ConsiderationItem,
                CriteriaResolver,
                Fulfillment,
                FulfillmentComponent,
                OfferItem,
                Order,
                OrderParameters,
                ReceivedItem
            } from "./ConsiderationStructs.sol";
            import {
                AdvancedOrder_denominator_offset,
                AdvancedOrder_extraData_offset,
                AdvancedOrder_fixed_segment_0,
                AdvancedOrder_head_size,
                AdvancedOrder_numerator_offset,
                AdvancedOrder_signature_offset,
                AdvancedOrderPlusOrderParameters_head_size,
                Common_amount_offset,
                Common_endAmount_offset,
                ConsiderationItem_size_with_length,
                ConsiderationItem_size,
                CriteriaResolver_criteriaProof_offset,
                CriteriaResolver_fixed_segment_0,
                CriteriaResolver_head_size,
                FourWords,
                FreeMemoryPointerSlot,
                Fulfillment_considerationComponents_offset,
                Fulfillment_head_size,
                FulfillmentComponent_mem_tail_size_shift,
                FulfillmentComponent_mem_tail_size,
                generateOrder_maximum_returndatasize,
                OfferItem_size_with_length,
                OfferItem_size,
                OneWord,
                OneWordShift,
                OnlyFullWordMask,
                Order_head_size,
                Order_signature_offset,
                OrderComponents_OrderParameters_common_head_size,
                OrderParameters_consideration_head_offset,
                OrderParameters_head_size,
                OrderParameters_offer_head_offset,
                OrderParameters_totalOriginalConsiderationItems_offset,
                ReceivedItem_recipient_offset,
                ReceivedItem_size,
                ReceivedItem_size_excluding_recipient,
                SpentItem_size_shift,
                SpentItem_size,
                ThirtyOneBytes,
                TwoWords
            } from "./ConsiderationConstants.sol";
            import {
                CalldataPointer,
                malloc,
                MemoryPointer,
                OffsetOrLengthMask
            } from "../helpers/PointerLibraries.sol";
            contract ConsiderationDecoder {
                /**
                 * @dev Takes a bytes array from calldata and copies it into memory.
                 *
                 * @param cdPtrLength A calldata pointer to the start of the bytes array in
                 *                    calldata which contains the length of the array.
                 *
                 * @return mPtrLength A memory pointer to the start of the bytes array in
                 *                    memory which contains the length of the array.
                 */
                function _decodeBytes(
                    CalldataPointer cdPtrLength
                ) internal pure returns (MemoryPointer mPtrLength) {
                    assembly {
                        // Get the current free memory pointer.
                        mPtrLength := mload(FreeMemoryPointerSlot)
                        // Derive the size of the bytes array, rounding up to nearest word
                        // and adding a word for the length field. Note: masking
                        // `calldataload(cdPtrLength)` is redundant here.
                        let size := add(
                            and(
                                add(calldataload(cdPtrLength), ThirtyOneBytes),
                                OnlyFullWordMask
                            ),
                            OneWord
                        )
                        // Copy bytes from calldata into memory based on pointers and size.
                        calldatacopy(mPtrLength, cdPtrLength, size)
                        // Store the masked value in memory. Note: the value of `size` is at
                        // least 32, meaning the calldatacopy above will at least write to
                        // `[mPtrLength, mPtrLength + 32)`.
                        mstore(
                            mPtrLength,
                            and(calldataload(cdPtrLength), OffsetOrLengthMask)
                        )
                        // Update free memory pointer based on the size of the bytes array.
                        mstore(FreeMemoryPointerSlot, add(mPtrLength, size))
                    }
                }
                /**
                 * @dev Takes an offer array from calldata and copies it into memory.
                 *
                 * @param cdPtrLength A calldata pointer to the start of the offer array
                 *                    in calldata which contains the length of the array.
                 *
                 * @return mPtrLength A memory pointer to the start of the offer array in
                 *                    memory which contains the length of the array.
                 */
                function _decodeOffer(
                    CalldataPointer cdPtrLength
                ) internal pure returns (MemoryPointer mPtrLength) {
                    assembly {
                        // Retrieve length of array, masking to prevent potential overflow.
                        let arrLength := and(calldataload(cdPtrLength), OffsetOrLengthMask)
                        // Get the current free memory pointer.
                        mPtrLength := mload(FreeMemoryPointerSlot)
                        // Write the array length to memory.
                        mstore(mPtrLength, arrLength)
                        // Derive the head by adding one word to the length pointer.
                        let mPtrHead := add(mPtrLength, OneWord)
                        // Derive the tail by adding one word per element (note that structs
                        // are written to memory with an offset per struct element).
                        let mPtrTail := add(mPtrHead, shl(OneWordShift, arrLength))
                        // Track the next tail, beginning with the initial tail value.
                        let mPtrTailNext := mPtrTail
                        // Copy all offer array data into memory at the tail pointer.
                        calldatacopy(
                            mPtrTail,
                            add(cdPtrLength, OneWord),
                            mul(arrLength, OfferItem_size)
                        )
                        // Track the next head pointer, starting with initial head value.
                        let mPtrHeadNext := mPtrHead
                        // Iterate over each head pointer until it reaches the tail.
                        for {
                        } lt(mPtrHeadNext, mPtrTail) {
                        } {
                            // Write the next tail pointer to next head pointer in memory.
                            mstore(mPtrHeadNext, mPtrTailNext)
                            // Increment the next head pointer by one word.
                            mPtrHeadNext := add(mPtrHeadNext, OneWord)
                            // Increment the next tail pointer by the size of an offer item.
                            mPtrTailNext := add(mPtrTailNext, OfferItem_size)
                        }
                        // Update free memory pointer to allocate memory up to end of tail.
                        mstore(FreeMemoryPointerSlot, mPtrTailNext)
                    }
                }
                /**
                 * @dev Takes a consideration array from calldata and copies it into memory.
                 *
                 * @param cdPtrLength A calldata pointer to the start of the consideration
                 *                    array in calldata which contains the length of the
                 *                    array.
                 *
                 * @return mPtrLength A memory pointer to the start of the consideration
                 *                    array in memory which contains the length of the
                 *                    array.
                 */
                function _decodeConsideration(
                    CalldataPointer cdPtrLength
                ) internal pure returns (MemoryPointer mPtrLength) {
                    assembly {
                        // Retrieve length of array, masking to prevent potential overflow.
                        let arrLength := and(calldataload(cdPtrLength), OffsetOrLengthMask)
                        // Get the current free memory pointer.
                        mPtrLength := mload(FreeMemoryPointerSlot)
                        // Write the array length to memory.
                        mstore(mPtrLength, arrLength)
                        // Derive the head by adding one word to the length pointer.
                        let mPtrHead := add(mPtrLength, OneWord)
                        // Derive the tail by adding one word per element (note that structs
                        // are written to memory with an offset per struct element).
                        let mPtrTail := add(mPtrHead, shl(OneWordShift, arrLength))
                        // Track the next tail, beginning with the initial tail value.
                        let mPtrTailNext := mPtrTail
                        // Copy all consideration array data into memory at tail pointer.
                        calldatacopy(
                            mPtrTail,
                            add(cdPtrLength, OneWord),
                            mul(arrLength, ConsiderationItem_size)
                        )
                        // Track the next head pointer, starting with initial head value.
                        let mPtrHeadNext := mPtrHead
                        // Iterate over each head pointer until it reaches the tail.
                        for {
                        } lt(mPtrHeadNext, mPtrTail) {
                        } {
                            // Write the next tail pointer to next head pointer in memory.
                            mstore(mPtrHeadNext, mPtrTailNext)
                            // Increment the next head pointer by one word.
                            mPtrHeadNext := add(mPtrHeadNext, OneWord)
                            // Increment next tail pointer by size of a consideration item.
                            mPtrTailNext := add(mPtrTailNext, ConsiderationItem_size)
                        }
                        // Update free memory pointer to allocate memory up to end of tail.
                        mstore(FreeMemoryPointerSlot, mPtrTailNext)
                    }
                }
                /**
                 * @dev Takes a calldata pointer and memory pointer and copies a referenced
                 *      OrderParameters struct and associated offer and consideration data
                 *      to memory.
                 *
                 * @param cdPtr A calldata pointer for the OrderParameters struct.
                 * @param mPtr A memory pointer to the OrderParameters struct head.
                 */
                function _decodeOrderParametersTo(
                    CalldataPointer cdPtr,
                    MemoryPointer mPtr
                ) internal pure {
                    // Copy the full OrderParameters head from calldata to memory.
                    cdPtr.copy(mPtr, OrderParameters_head_size);
                    // Resolve the offer calldata offset, use that to decode and copy offer
                    // from calldata, and write resultant memory offset to head in memory.
                    mPtr.offset(OrderParameters_offer_head_offset).write(
                        _decodeOffer(cdPtr.pptr(OrderParameters_offer_head_offset))
                    );
                    // Resolve consideration calldata offset, use that to copy consideration
                    // from calldata, and write resultant memory offset to head in memory.
                    mPtr.offset(OrderParameters_consideration_head_offset).write(
                        _decodeConsideration(
                            cdPtr.pptr(OrderParameters_consideration_head_offset)
                        )
                    );
                }
                /**
                 * @dev Takes a calldata pointer to an OrderParameters struct and copies the
                 *      decoded struct to memory.
                 *
                 * @param cdPtr A calldata pointer for the OrderParameters struct.
                 *
                 * @return mPtr A memory pointer to the OrderParameters struct head.
                 */
                function _decodeOrderParameters(
                    CalldataPointer cdPtr
                ) internal pure returns (MemoryPointer mPtr) {
                    // Allocate required memory for the OrderParameters head (offer and
                    // consideration are allocated independently).
                    mPtr = malloc(OrderParameters_head_size);
                    // Decode and copy the order parameters to the newly allocated memory.
                    _decodeOrderParametersTo(cdPtr, mPtr);
                }
                /**
                 * @dev Takes a calldata pointer to an Order struct and copies the decoded
                 *      struct to memory.
                 *
                 * @param cdPtr A calldata pointer for the Order struct.
                 *
                 * @return mPtr A memory pointer to the Order struct head.
                 */
                function _decodeOrder(
                    CalldataPointer cdPtr
                ) internal pure returns (MemoryPointer mPtr) {
                    // Allocate required memory for the Order head (OrderParameters and
                    // signature are allocated independently).
                    mPtr = malloc(Order_head_size);
                    // Resolve OrderParameters calldata offset, use it to decode and copy
                    // from calldata, and write resultant memory offset to head in memory.
                    mPtr.write(_decodeOrderParameters(cdPtr.pptr()));
                    // Resolve signature calldata offset, use that to decode and copy from
                    // calldata, and write resultant memory offset to head in memory.
                    mPtr.offset(Order_signature_offset).write(
                        _decodeBytes(cdPtr.pptr(Order_signature_offset))
                    );
                }
                /**
                 * @dev Takes a calldata pointer to an AdvancedOrder struct and copies the
                 *      decoded struct to memory.
                 *
                 * @param cdPtr A calldata pointer for the AdvancedOrder struct.
                 *
                 * @return mPtr A memory pointer to the AdvancedOrder struct head.
                 */
                function _decodeAdvancedOrder(
                    CalldataPointer cdPtr
                ) internal pure returns (MemoryPointer mPtr) {
                    // Allocate memory for AdvancedOrder head and OrderParameters head.
                    mPtr = malloc(AdvancedOrderPlusOrderParameters_head_size);
                    // Use numerator + denominator calldata offset to decode and copy
                    // from calldata and write resultant memory offset to head in memory.
                    cdPtr.offset(AdvancedOrder_numerator_offset).copy(
                        mPtr.offset(AdvancedOrder_numerator_offset),
                        AdvancedOrder_fixed_segment_0
                    );
                    // Get pointer to memory immediately after advanced order.
                    MemoryPointer mPtrParameters = mPtr.offset(AdvancedOrder_head_size);
                    // Write pptr for advanced order parameters to memory.
                    mPtr.write(mPtrParameters);
                    // Resolve OrderParameters calldata pointer & write to allocated region.
                    _decodeOrderParametersTo(cdPtr.pptr(), mPtrParameters);
                    // Resolve signature calldata offset, use that to decode and copy from
                    // calldata, and write resultant memory offset to head in memory.
                    mPtr.offset(AdvancedOrder_signature_offset).write(
                        _decodeBytes(cdPtr.pptr(AdvancedOrder_signature_offset))
                    );
                    // Resolve extraData calldata offset, use that to decode and copy from
                    // calldata, and write resultant memory offset to head in memory.
                    mPtr.offset(AdvancedOrder_extraData_offset).write(
                        _decodeBytes(cdPtr.pptr(AdvancedOrder_extraData_offset))
                    );
                }
                /**
                 * @dev Allocates a single word of empty bytes in memory and returns the
                 *      pointer to that memory region.
                 *
                 * @return mPtr The memory pointer to the new empty word in memory.
                 */
                function _getEmptyBytesOrArray()
                    internal
                    pure
                    returns (MemoryPointer mPtr)
                {
                    mPtr = malloc(OneWord);
                    mPtr.write(0);
                }
                /**
                 * @dev Takes a calldata pointer to an Order struct and copies the decoded
                 *      struct to memory as an AdvancedOrder.
                 *
                 * @param cdPtr A calldata pointer for the Order struct.
                 *
                 * @return mPtr A memory pointer to the AdvancedOrder struct head.
                 */
                function _decodeOrderAsAdvancedOrder(
                    CalldataPointer cdPtr
                ) internal pure returns (MemoryPointer mPtr) {
                    // Allocate memory for AdvancedOrder head and OrderParameters head.
                    mPtr = malloc(AdvancedOrderPlusOrderParameters_head_size);
                    // Get pointer to memory immediately after advanced order.
                    MemoryPointer mPtrParameters = mPtr.offset(AdvancedOrder_head_size);
                    // Write pptr for advanced order parameters.
                    mPtr.write(mPtrParameters);
                    // Resolve OrderParameters calldata pointer & write to allocated region.
                    _decodeOrderParametersTo(cdPtr.pptr(), mPtrParameters);
                    // Write default Order numerator and denominator values (i.e. 1/1).
                    mPtr.offset(AdvancedOrder_numerator_offset).write(1);
                    mPtr.offset(AdvancedOrder_denominator_offset).write(1);
                    // Resolve signature calldata offset, use that to decode and copy from
                    // calldata, and write resultant memory offset to head in memory.
                    mPtr.offset(AdvancedOrder_signature_offset).write(
                        _decodeBytes(cdPtr.pptr(Order_signature_offset))
                    );
                    // Resolve extraData calldata offset, use that to decode and copy from
                    // calldata, and write resultant memory offset to head in memory.
                    mPtr.offset(AdvancedOrder_extraData_offset).write(
                        _getEmptyBytesOrArray()
                    );
                }
                /**
                 * @dev Takes a calldata pointer to an array of Order structs and copies the
                 *      decoded array to memory as an array of AdvancedOrder structs.
                 *
                 * @param cdPtrLength A calldata pointer to the start of the orders array in
                 *                    calldata which contains the length of the array.
                 *
                 * @return mPtrLength A memory pointer to the start of the array of advanced
                 *                    orders in memory which contains length of the array.
                 */
                function _decodeOrdersAsAdvancedOrders(
                    CalldataPointer cdPtrLength
                ) internal pure returns (MemoryPointer mPtrLength) {
                    // Retrieve length of array, masking to prevent potential overflow.
                    uint256 arrLength = cdPtrLength.readMaskedUint256();
                    unchecked {
                        // Derive offset to the tail based on one word per array element.
                        uint256 tailOffset = arrLength << OneWordShift;
                        // Add one additional word for the length and allocate memory.
                        mPtrLength = malloc(tailOffset + OneWord);
                        // Write the length of the array to memory.
                        mPtrLength.write(arrLength);
                        // Advance to first memory & calldata pointers (e.g. after length).
                        MemoryPointer mPtrHead = mPtrLength.next();
                        CalldataPointer cdPtrHead = cdPtrLength.next();
                        // Iterate over each pointer, word by word, until tail is reached.
                        for (uint256 offset = 0; offset < tailOffset; offset += OneWord) {
                            // Resolve Order calldata offset, use it to decode and copy from
                            // calldata, and write resultant AdvancedOrder offset to memory.
                            mPtrHead.offset(offset).write(
                                _decodeOrderAsAdvancedOrder(cdPtrHead.pptr(offset))
                            );
                        }
                    }
                }
                /**
                 * @dev Takes a calldata pointer to a criteria proof, or an array bytes32
                 *      types, and copies the decoded proof to memory.
                 *
                 * @param cdPtrLength A calldata pointer to the start of the criteria proof
                 *                    in calldata which contains the length of the array.
                 *
                 * @return mPtrLength A memory pointer to the start of the criteria proof
                 *                    in memory which contains length of the array.
                 */
                function _decodeCriteriaProof(
                    CalldataPointer cdPtrLength
                ) internal pure returns (MemoryPointer mPtrLength) {
                    // Retrieve length of array, masking to prevent potential overflow.
                    uint256 arrLength = cdPtrLength.readMaskedUint256();
                    unchecked {
                        // Derive array size based on one word per array element and length.
                        uint256 arrSize = (arrLength + 1) << OneWordShift;
                        // Allocate memory equal to the array size.
                        mPtrLength = malloc(arrSize);
                        // Copy the array from calldata into memory.
                        cdPtrLength.copy(mPtrLength, arrSize);
                    }
                }
                /**
                 * @dev Takes a calldata pointer to a CriteriaResolver struct and copies the
                 *      decoded struct to memory.
                 *
                 * @param cdPtr A calldata pointer for the CriteriaResolver struct.
                 *
                 * @return mPtr A memory pointer to the CriteriaResolver struct head.
                 */
                function _decodeCriteriaResolver(
                    CalldataPointer cdPtr
                ) internal pure returns (MemoryPointer mPtr) {
                    // Allocate required memory for the CriteriaResolver head (the criteria
                    // proof bytes32 array is allocated independently).
                    mPtr = malloc(CriteriaResolver_head_size);
                    // Decode and copy order index, side, index, and identifier from
                    // calldata and write resultant memory offset to head in memory.
                    cdPtr.copy(mPtr, CriteriaResolver_fixed_segment_0);
                    // Resolve criteria proof calldata offset, use it to decode and copy
                    // from calldata, and write resultant memory offset to head in memory.
                    mPtr.offset(CriteriaResolver_criteriaProof_offset).write(
                        _decodeCriteriaProof(
                            cdPtr.pptr(CriteriaResolver_criteriaProof_offset)
                        )
                    );
                }
                /**
                 * @dev Takes an array of criteria resolvers from calldata and copies it
                 *      into memory.
                 *
                 * @param cdPtrLength A calldata pointer to the start of the criteria
                 *                    resolver array in calldata which contains the length
                 *                    of the array.
                 *
                 * @return mPtrLength A memory pointer to the start of the criteria resolver
                 *                    array in memory which contains the length of the
                 *                    array.
                 */
                function _decodeCriteriaResolvers(
                    CalldataPointer cdPtrLength
                ) internal pure returns (MemoryPointer mPtrLength) {
                    // Retrieve length of array, masking to prevent potential overflow.
                    uint256 arrLength = cdPtrLength.readMaskedUint256();
                    unchecked {
                        // Derive offset to the tail based on one word per array element.
                        uint256 tailOffset = arrLength << OneWordShift;
                        // Add one additional word for the length and allocate memory.
                        mPtrLength = malloc(tailOffset + OneWord);
                        // Write the length of the array to memory.
                        mPtrLength.write(arrLength);
                        // Advance to first memory & calldata pointers (e.g. after length).
                        MemoryPointer mPtrHead = mPtrLength.next();
                        CalldataPointer cdPtrHead = cdPtrLength.next();
                        // Iterate over each pointer, word by word, until tail is reached.
                        for (uint256 offset = 0; offset < tailOffset; offset += OneWord) {
                            // Resolve CriteriaResolver calldata offset, use it to decode
                            // and copy from calldata, and write resultant memory offset.
                            mPtrHead.offset(offset).write(
                                _decodeCriteriaResolver(cdPtrHead.pptr(offset))
                            );
                        }
                    }
                }
                /**
                 * @dev Takes an array of orders from calldata and copies it into memory.
                 *
                 * @param cdPtrLength A calldata pointer to the start of the orders array in
                 *                    calldata which contains the length of the array.
                 *
                 * @return mPtrLength A memory pointer to the start of the orders array
                 *                    in memory which contains the length of the array.
                 */
                function _decodeOrders(
                    CalldataPointer cdPtrLength
                ) internal pure returns (MemoryPointer mPtrLength) {
                    // Retrieve length of array, masking to prevent potential overflow.
                    uint256 arrLength = cdPtrLength.readMaskedUint256();
                    unchecked {
                        // Derive offset to the tail based on one word per array element.
                        uint256 tailOffset = arrLength << OneWordShift;
                        // Add one additional word for the length and allocate memory.
                        mPtrLength = malloc(tailOffset + OneWord);
                        // Write the length of the array to memory.
                        mPtrLength.write(arrLength);
                        // Advance to first memory & calldata pointers (e.g. after length).
                        MemoryPointer mPtrHead = mPtrLength.next();
                        CalldataPointer cdPtrHead = cdPtrLength.next();
                        // Iterate over each pointer, word by word, until tail is reached.
                        for (uint256 offset = 0; offset < tailOffset; offset += OneWord) {
                            // Resolve Order calldata offset, use it to decode and copy
                            // from calldata, and write resultant memory offset.
                            mPtrHead.offset(offset).write(
                                _decodeOrder(cdPtrHead.pptr(offset))
                            );
                        }
                    }
                }
                /**
                 * @dev Takes an array of fulfillment components from calldata and copies it
                 *      into memory.
                 *
                 * @param cdPtrLength A calldata pointer to the start of the fulfillment
                 *                    components array in calldata which contains the length
                 *                    of the array.
                 *
                 * @return mPtrLength A memory pointer to the start of the fulfillment
                 *                    components array in memory which contains the length
                 *                    of the array.
                 */
                function _decodeFulfillmentComponents(
                    CalldataPointer cdPtrLength
                ) internal pure returns (MemoryPointer mPtrLength) {
                    assembly {
                        let arrLength := and(calldataload(cdPtrLength), OffsetOrLengthMask)
                        // Get the current free memory pointer.
                        mPtrLength := mload(FreeMemoryPointerSlot)
                        mstore(mPtrLength, arrLength)
                        let mPtrHead := add(mPtrLength, OneWord)
                        let mPtrTail := add(mPtrHead, shl(OneWordShift, arrLength))
                        let mPtrTailNext := mPtrTail
                        calldatacopy(
                            mPtrTail,
                            add(cdPtrLength, OneWord),
                            shl(FulfillmentComponent_mem_tail_size_shift, arrLength)
                        )
                        let mPtrHeadNext := mPtrHead
                        for {
                        } lt(mPtrHeadNext, mPtrTail) {
                        } {
                            mstore(mPtrHeadNext, mPtrTailNext)
                            mPtrHeadNext := add(mPtrHeadNext, OneWord)
                            mPtrTailNext := add(
                                mPtrTailNext,
                                FulfillmentComponent_mem_tail_size
                            )
                        }
                        // Update the free memory pointer.
                        mstore(FreeMemoryPointerSlot, mPtrTailNext)
                    }
                }
                /**
                 * @dev Takes a nested array of fulfillment components from calldata and
                 *      copies it into memory.
                 *
                 * @param cdPtrLength A calldata pointer to the start of the nested
                 *                    fulfillment components array in calldata which
                 *                    contains the length of the array.
                 *
                 * @return mPtrLength A memory pointer to the start of the nested
                 *                    fulfillment components array in memory which
                 *                    contains the length of the array.
                 */
                function _decodeNestedFulfillmentComponents(
                    CalldataPointer cdPtrLength
                ) internal pure returns (MemoryPointer mPtrLength) {
                    // Retrieve length of array, masking to prevent potential overflow.
                    uint256 arrLength = cdPtrLength.readMaskedUint256();
                    unchecked {
                        // Derive offset to the tail based on one word per array element.
                        uint256 tailOffset = arrLength << OneWordShift;
                        // Add one additional word for the length and allocate memory.
                        mPtrLength = malloc(tailOffset + OneWord);
                        // Write the length of the array to memory.
                        mPtrLength.write(arrLength);
                        // Advance to first memory & calldata pointers (e.g. after length).
                        MemoryPointer mPtrHead = mPtrLength.next();
                        CalldataPointer cdPtrHead = cdPtrLength.next();
                        // Iterate over each pointer, word by word, until tail is reached.
                        for (uint256 offset = 0; offset < tailOffset; offset += OneWord) {
                            // Resolve FulfillmentComponents array calldata offset, use it
                            // to decode and copy from calldata, and write memory offset.
                            mPtrHead.offset(offset).write(
                                _decodeFulfillmentComponents(cdPtrHead.pptr(offset))
                            );
                        }
                    }
                }
                /**
                 * @dev Takes an array of advanced orders from calldata and copies it into
                 *      memory.
                 *
                 * @param cdPtrLength A calldata pointer to the start of the advanced orders
                 *                    array in calldata which contains the length of the
                 *                    array.
                 *
                 * @return mPtrLength A memory pointer to the start of the advanced orders
                 *                    array in memory which contains the length of the
                 *                    array.
                 */
                function _decodeAdvancedOrders(
                    CalldataPointer cdPtrLength
                ) internal pure returns (MemoryPointer mPtrLength) {
                    // Retrieve length of array, masking to prevent potential overflow.
                    uint256 arrLength = cdPtrLength.readMaskedUint256();
                    unchecked {
                        // Derive offset to the tail based on one word per array element.
                        uint256 tailOffset = arrLength << OneWordShift;
                        // Add one additional word for the length and allocate memory.
                        mPtrLength = malloc(tailOffset + OneWord);
                        // Write the length of the array to memory.
                        mPtrLength.write(arrLength);
                        // Advance to first memory & calldata pointers (e.g. after length).
                        MemoryPointer mPtrHead = mPtrLength.next();
                        CalldataPointer cdPtrHead = cdPtrLength.next();
                        // Iterate over each pointer, word by word, until tail is reached.
                        for (uint256 offset = 0; offset < tailOffset; offset += OneWord) {
                            // Resolve AdvancedOrder calldata offset, use it to decode and
                            // copy from calldata, and write resultant memory offset.
                            mPtrHead.offset(offset).write(
                                _decodeAdvancedOrder(cdPtrHead.pptr(offset))
                            );
                        }
                    }
                }
                /**
                 * @dev Takes a calldata pointer to a Fulfillment struct and copies the
                 *      decoded struct to memory.
                 *
                 * @param cdPtr A calldata pointer for the Fulfillment struct.
                 *
                 * @return mPtr A memory pointer to the Fulfillment struct head.
                 */
                function _decodeFulfillment(
                    CalldataPointer cdPtr
                ) internal pure returns (MemoryPointer mPtr) {
                    // Allocate required memory for the Fulfillment head (the fulfillment
                    // components arrays are allocated independently).
                    mPtr = malloc(Fulfillment_head_size);
                    // Resolve offerComponents calldata offset, use it to decode and copy
                    // from calldata, and write resultant memory offset to head in memory.
                    mPtr.write(_decodeFulfillmentComponents(cdPtr.pptr()));
                    // Resolve considerationComponents calldata offset, use it to decode and
                    // copy from calldata, and write resultant memory offset to memory head.
                    mPtr.offset(Fulfillment_considerationComponents_offset).write(
                        _decodeFulfillmentComponents(
                            cdPtr.pptr(Fulfillment_considerationComponents_offset)
                        )
                    );
                }
                /**
                 * @dev Takes an array of fulfillments from calldata and copies it into
                 *      memory.
                 *
                 * @param cdPtrLength A calldata pointer to the start of the fulfillments
                 *                    array in calldata which contains the length of the
                 *                    array.
                 *
                 * @return mPtrLength A memory pointer to the start of the fulfillments
                 *                    array in memory which contains the length of the
                 *                    array.
                 */
                function _decodeFulfillments(
                    CalldataPointer cdPtrLength
                ) internal pure returns (MemoryPointer mPtrLength) {
                    // Retrieve length of array, masking to prevent potential overflow.
                    uint256 arrLength = cdPtrLength.readMaskedUint256();
                    unchecked {
                        // Derive offset to the tail based on one word per array element.
                        uint256 tailOffset = arrLength << OneWordShift;
                        // Add one additional word for the length and allocate memory.
                        mPtrLength = malloc(tailOffset + OneWord);
                        // Write the length of the array to memory.
                        mPtrLength.write(arrLength);
                        // Advance to first memory & calldata pointers (e.g. after length).
                        MemoryPointer mPtrHead = mPtrLength.next();
                        CalldataPointer cdPtrHead = cdPtrLength.next();
                        // Iterate over each pointer, word by word, until tail is reached.
                        for (uint256 offset = 0; offset < tailOffset; offset += OneWord) {
                            // Resolve Fulfillment calldata offset, use it to decode and
                            // copy from calldata, and write resultant memory offset.
                            mPtrHead.offset(offset).write(
                                _decodeFulfillment(cdPtrHead.pptr(offset))
                            );
                        }
                    }
                }
                /**
                 * @dev Takes a calldata pointer to an OrderComponents struct and copies the
                 *      decoded struct to memory as an OrderParameters struct (with the
                 *      totalOriginalConsiderationItems value set equal to the length of the
                 *      supplied consideration array).
                 *
                 * @param cdPtr A calldata pointer for the OrderComponents struct.
                 *
                 * @return mPtr A memory pointer to the OrderParameters struct head.
                 */
                function _decodeOrderComponentsAsOrderParameters(
                    CalldataPointer cdPtr
                ) internal pure returns (MemoryPointer mPtr) {
                    // Allocate memory for the OrderParameters head.
                    mPtr = malloc(OrderParameters_head_size);
                    // Copy the full OrderComponents head from calldata to memory.
                    cdPtr.copy(mPtr, OrderComponents_OrderParameters_common_head_size);
                    // Resolve the offer calldata offset, use that to decode and copy offer
                    // from calldata, and write resultant memory offset to head in memory.
                    mPtr.offset(OrderParameters_offer_head_offset).write(
                        _decodeOffer(cdPtr.pptr(OrderParameters_offer_head_offset))
                    );
                    // Resolve consideration calldata offset, use that to copy consideration
                    // from calldata, and write resultant memory offset to head in memory.
                    MemoryPointer consideration = _decodeConsideration(
                        cdPtr.pptr(OrderParameters_consideration_head_offset)
                    );
                    mPtr.offset(OrderParameters_consideration_head_offset).write(
                        consideration
                    );
                    // Write masked consideration length to totalOriginalConsiderationItems.
                    mPtr
                        .offset(OrderParameters_totalOriginalConsiderationItems_offset)
                        .write(consideration.readUint256());
                }
                /**
                 * @dev Decodes the returndata from a call to generateOrder, or returns
                 *      empty arrays and a boolean signifying that the returndata does not
                 *      adhere to a valid encoding scheme if it cannot be decoded.
                 *
                 * @return invalidEncoding A boolean signifying whether the returndata has
                 *                         an invalid encoding.
                 * @return offer           The decoded offer array.
                 * @return consideration   The decoded consideration array.
                 */
                function _decodeGenerateOrderReturndata()
                    internal
                    pure
                    returns (
                        uint256 invalidEncoding,
                        MemoryPointer offer,
                        MemoryPointer consideration
                    )
                {
                    assembly {
                        // Check that returndatasize is at least four words: offerOffset,
                        // considerationOffset, offerLength, & considerationLength
                        invalidEncoding := lt(returndatasize(), FourWords)
                        let offsetOffer
                        let offsetConsideration
                        let offerLength
                        let considerationLength
                        // Proceed if enough returndata is present to continue evaluation.
                        if iszero(invalidEncoding) {
                            // Copy first two words of returndata (the offsets to offer and
                            // consideration array lengths) to scratch space.
                            returndatacopy(0, 0, TwoWords)
                            offsetOffer := mload(0)
                            offsetConsideration := mload(OneWord)
                            // If valid length, check that offsets are within returndata.
                            let invalidOfferOffset := gt(offsetOffer, returndatasize())
                            let invalidConsiderationOffset := gt(
                                offsetConsideration,
                                returndatasize()
                            )
                            // Only proceed if length (and thus encoding) is valid so far.
                            invalidEncoding := or(
                                invalidOfferOffset,
                                invalidConsiderationOffset
                            )
                            if iszero(invalidEncoding) {
                                // Copy length of offer array to scratch space.
                                returndatacopy(0, offsetOffer, OneWord)
                                offerLength := mload(0)
                                // Copy length of consideration array to scratch space.
                                returndatacopy(OneWord, offsetConsideration, OneWord)
                                considerationLength := mload(OneWord)
                                {
                                    // Calculate total size of offer & consideration arrays.
                                    let totalOfferSize := shl(
                                        SpentItem_size_shift,
                                        offerLength
                                    )
                                    let totalConsiderationSize := mul(
                                        ReceivedItem_size,
                                        considerationLength
                                    )
                                    // Add 4 words to total size to cover the offset and
                                    // length fields of the two arrays.
                                    let totalSize := add(
                                        FourWords,
                                        add(totalOfferSize, totalConsiderationSize)
                                    )
                                    // Don't continue if returndatasize exceeds 65535 bytes
                                    // or is greater than the calculated size.
                                    invalidEncoding := or(
                                        gt(
                                            or(offerLength, considerationLength),
                                            generateOrder_maximum_returndatasize
                                        ),
                                        gt(totalSize, returndatasize())
                                    )
                                    // Set first word of scratch space to 0 so length of
                                    // offer/consideration are set to 0 on invalid encoding.
                                    mstore(0, 0)
                                }
                            }
                        }
                        if iszero(invalidEncoding) {
                            offer := copySpentItemsAsOfferItems(
                                add(offsetOffer, OneWord),
                                offerLength
                            )
                            consideration := copyReceivedItemsAsConsiderationItems(
                                add(offsetConsideration, OneWord),
                                considerationLength
                            )
                        }
                        function copySpentItemsAsOfferItems(rdPtrHead, length)
                            -> mPtrLength
                        {
                            // Retrieve the current free memory pointer.
                            mPtrLength := mload(FreeMemoryPointerSlot)
                            // Allocate memory for the array.
                            mstore(
                                FreeMemoryPointerSlot,
                                add(
                                    mPtrLength,
                                    add(OneWord, mul(length, OfferItem_size_with_length))
                                )
                            )
                            // Write the length of the array to the start of free memory.
                            mstore(mPtrLength, length)
                            // Use offset from length to minimize stack depth.
                            let headOffsetFromLength := OneWord
                            let headSizeWithLength := shl(OneWordShift, add(1, length))
                            let mPtrTailNext := add(mPtrLength, headSizeWithLength)
                            // Iterate over each element.
                            for {
                            } lt(headOffsetFromLength, headSizeWithLength) {
                            } {
                                // Write the memory pointer to the accompanying head offset.
                                mstore(add(mPtrLength, headOffsetFromLength), mPtrTailNext)
                                // Copy itemType, token, identifier and amount.
                                returndatacopy(mPtrTailNext, rdPtrHead, SpentItem_size)
                                // Copy amount to endAmount.
                                mstore(
                                    add(mPtrTailNext, Common_endAmount_offset),
                                    mload(add(mPtrTailNext, Common_amount_offset))
                                )
                                // Update read pointer, next tail pointer, and head offset.
                                rdPtrHead := add(rdPtrHead, SpentItem_size)
                                mPtrTailNext := add(mPtrTailNext, OfferItem_size)
                                headOffsetFromLength := add(headOffsetFromLength, OneWord)
                            }
                        }
                        function copyReceivedItemsAsConsiderationItems(rdPtrHead, length)
                            -> mPtrLength
                        {
                            // Retrieve the current free memory pointer.
                            mPtrLength := mload(FreeMemoryPointerSlot)
                            // Allocate memory for the array.
                            mstore(
                                FreeMemoryPointerSlot,
                                add(
                                    mPtrLength,
                                    add(
                                        OneWord,
                                        mul(length, ConsiderationItem_size_with_length)
                                    )
                                )
                            )
                            // Write the length of the array to the start of free memory.
                            mstore(mPtrLength, length)
                            // Use offset from length to minimize stack depth.
                            let headOffsetFromLength := OneWord
                            let headSizeWithLength := shl(OneWordShift, add(1, length))
                            let mPtrTailNext := add(mPtrLength, headSizeWithLength)
                            // Iterate over each element.
                            for {
                            } lt(headOffsetFromLength, headSizeWithLength) {
                            } {
                                // Write the memory pointer to the accompanying head offset.
                                mstore(add(mPtrLength, headOffsetFromLength), mPtrTailNext)
                                // Copy itemType, token, identifier and amount.
                                returndatacopy(
                                    mPtrTailNext,
                                    rdPtrHead,
                                    ReceivedItem_size_excluding_recipient
                                )
                                // Copy amount and recipient.
                                returndatacopy(
                                    add(mPtrTailNext, Common_endAmount_offset),
                                    add(rdPtrHead, Common_amount_offset),
                                    TwoWords
                                )
                                // Update read pointer, next tail pointer, and head offset.
                                rdPtrHead := add(rdPtrHead, ReceivedItem_size)
                                mPtrTailNext := add(mPtrTailNext, ConsiderationItem_size)
                                headOffsetFromLength := add(headOffsetFromLength, OneWord)
                            }
                        }
                    }
                }
                /**
                 * @dev Converts a function returning _decodeGenerateOrderReturndata types
                 *      into a function returning offer and consideration types.
                 *
                 * @param inFn The input function, taking no arguments and returning an
                 *             error buffer, spent item array, and received item array.
                 *
                 * @return outFn The output function, taking no arguments and returning an
                 *               error buffer, offer array, and consideration array.
                 */
                function _convertGetGeneratedOrderResult(
                    function()
                        internal
                        pure
                        returns (uint256, MemoryPointer, MemoryPointer) inFn
                )
                    internal
                    pure
                    returns (
                        function()
                            internal
                            pure
                            returns (
                                uint256,
                                OfferItem[] memory,
                                ConsiderationItem[] memory
                            ) outFn
                    )
                {
                    assembly {
                        outFn := inFn
                    }
                }
                /**
                 * @dev Converts a function taking ReceivedItem, address, bytes32, and bytes
                 *      types (e.g. the _transfer function) into a function taking
                 *      OfferItem, address, bytes32, and bytes types.
                 *
                 * @param inFn The input function, taking ReceivedItem, address, bytes32,
                 *             and bytes types (e.g. the _transfer function).
                 *
                 * @return outFn The output function, taking OfferItem, address, bytes32,
                 *               and bytes types.
                 */
                function _toOfferItemInput(
                    function(ReceivedItem memory, address, bytes32, bytes memory)
                        internal inFn
                )
                    internal
                    pure
                    returns (
                        function(OfferItem memory, address, bytes32, bytes memory)
                            internal outFn
                    )
                {
                    assembly {
                        outFn := inFn
                    }
                }
                /**
                 * @dev Converts a function taking ReceivedItem, address, bytes32, and bytes
                 *      types (e.g. the _transfer function) into a function taking
                 *      ConsiderationItem, address, bytes32, and bytes types.
                 *
                 * @param inFn The input function, taking ReceivedItem, address, bytes32,
                 *             and bytes types (e.g. the _transfer function).
                 *
                 * @return outFn The output function, taking ConsiderationItem, address,
                 *               bytes32, and bytes types.
                 */
                function _toConsiderationItemInput(
                    function(ReceivedItem memory, address, bytes32, bytes memory)
                        internal inFn
                )
                    internal
                    pure
                    returns (
                        function(ConsiderationItem memory, address, bytes32, bytes memory)
                            internal outFn
                    )
                {
                    assembly {
                        outFn := inFn
                    }
                }
                /**
                 * @dev Converts a function taking a calldata pointer and returning a memory
                 *      pointer into a function taking that calldata pointer and returning
                 *      an OrderParameters type.
                 *
                 * @param inFn The input function, taking an arbitrary calldata pointer and
                 *             returning an arbitrary memory pointer.
                 *
                 * @return outFn The output function, taking an arbitrary calldata pointer
                 *               and returning an OrderParameters type.
                 */
                function _toOrderParametersReturnType(
                    function(CalldataPointer) internal pure returns (MemoryPointer) inFn
                )
                    internal
                    pure
                    returns (
                        function(CalldataPointer)
                            internal
                            pure
                            returns (OrderParameters memory) outFn
                    )
                {
                    assembly {
                        outFn := inFn
                    }
                }
                /**
                 * @dev Converts a function taking a calldata pointer and returning a memory
                 *      pointer into a function taking that calldata pointer and returning
                 *      an AdvancedOrder type.
                 *
                 * @param inFn The input function, taking an arbitrary calldata pointer and
                 *             returning an arbitrary memory pointer.
                 *
                 * @return outFn The output function, taking an arbitrary calldata pointer
                 *               and returning an AdvancedOrder type.
                 */
                function _toAdvancedOrderReturnType(
                    function(CalldataPointer) internal pure returns (MemoryPointer) inFn
                )
                    internal
                    pure
                    returns (
                        function(CalldataPointer)
                            internal
                            pure
                            returns (AdvancedOrder memory) outFn
                    )
                {
                    assembly {
                        outFn := inFn
                    }
                }
                /**
                 * @dev Converts a function taking a calldata pointer and returning a memory
                 *      pointer into a function taking that calldata pointer and returning
                 *      a dynamic array of CriteriaResolver types.
                 *
                 * @param inFn The input function, taking an arbitrary calldata pointer and
                 *             returning an arbitrary memory pointer.
                 *
                 * @return outFn The output function, taking an arbitrary calldata pointer
                 *               and returning a dynamic array of CriteriaResolver types.
                 */
                function _toCriteriaResolversReturnType(
                    function(CalldataPointer) internal pure returns (MemoryPointer) inFn
                )
                    internal
                    pure
                    returns (
                        function(CalldataPointer)
                            internal
                            pure
                            returns (CriteriaResolver[] memory) outFn
                    )
                {
                    assembly {
                        outFn := inFn
                    }
                }
                /**
                 * @dev Converts a function taking a calldata pointer and returning a memory
                 *      pointer into a function taking that calldata pointer and returning
                 *      a dynamic array of Order types.
                 *
                 * @param inFn The input function, taking an arbitrary calldata pointer and
                 *             returning an arbitrary memory pointer.
                 *
                 * @return outFn The output function, taking an arbitrary calldata pointer
                 *               and returning a dynamic array of Order types.
                 */
                function _toOrdersReturnType(
                    function(CalldataPointer) internal pure returns (MemoryPointer) inFn
                )
                    internal
                    pure
                    returns (
                        function(CalldataPointer)
                            internal
                            pure
                            returns (Order[] memory) outFn
                    )
                {
                    assembly {
                        outFn := inFn
                    }
                }
                /**
                 * @dev Converts a function taking a calldata pointer and returning a memory
                 *      pointer into a function taking that calldata pointer and returning
                 *      a nested dynamic array of dynamic arrays of FulfillmentComponent
                 *      types.
                 *
                 * @param inFn The input function, taking an arbitrary calldata pointer and
                 *             returning an arbitrary memory pointer.
                 *
                 * @return outFn The output function, taking an arbitrary calldata pointer
                 *               and returning a nested dynamic array of dynamic arrays of
                 *               FulfillmentComponent types.
                 */
                function _toNestedFulfillmentComponentsReturnType(
                    function(CalldataPointer) internal pure returns (MemoryPointer) inFn
                )
                    internal
                    pure
                    returns (
                        function(CalldataPointer)
                            internal
                            pure
                            returns (FulfillmentComponent[][] memory) outFn
                    )
                {
                    assembly {
                        outFn := inFn
                    }
                }
                /**
                 * @dev Converts a function taking a calldata pointer and returning a memory
                 *      pointer into a function taking that calldata pointer and returning
                 *      a dynamic array of AdvancedOrder types.
                 *
                 * @param inFn The input function, taking an arbitrary calldata pointer and
                 *             returning an arbitrary memory pointer.
                 *
                 * @return outFn The output function, taking an arbitrary calldata pointer
                 *               and returning a dynamic array of AdvancedOrder types.
                 */
                function _toAdvancedOrdersReturnType(
                    function(CalldataPointer) internal pure returns (MemoryPointer) inFn
                )
                    internal
                    pure
                    returns (
                        function(CalldataPointer)
                            internal
                            pure
                            returns (AdvancedOrder[] memory) outFn
                    )
                {
                    assembly {
                        outFn := inFn
                    }
                }
                /**
                 * @dev Converts a function taking a calldata pointer and returning a memory
                 *      pointer into a function taking that calldata pointer and returning
                 *      a dynamic array of Fulfillment types.
                 *
                 * @param inFn The input function, taking an arbitrary calldata pointer and
                 *             returning an arbitrary memory pointer.
                 *
                 * @return outFn The output function, taking an arbitrary calldata pointer
                 *               and returning a dynamic array of Fulfillment types.
                 */
                function _toFulfillmentsReturnType(
                    function(CalldataPointer) internal pure returns (MemoryPointer) inFn
                )
                    internal
                    pure
                    returns (
                        function(CalldataPointer)
                            internal
                            pure
                            returns (Fulfillment[] memory) outFn
                    )
                {
                    assembly {
                        outFn := inFn
                    }
                }
                /**
                 * @dev Converts an offer item into a received item, applying a given
                 *      recipient.
                 *
                 * @param offerItem The offer item.
                 * @param recipient The recipient.
                 *
                 * @return receivedItem The received item.
                 */
                function _fromOfferItemToReceivedItemWithRecipient(
                    OfferItem memory offerItem,
                    address recipient
                ) internal pure returns (ReceivedItem memory receivedItem) {
                    assembly {
                        receivedItem := offerItem
                        mstore(add(receivedItem, ReceivedItem_recipient_offset), recipient)
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.17;
            import {
                BasicOrder_additionalRecipients_length_cdPtr,
                BasicOrder_common_params_size,
                BasicOrder_startTime_cdPtr,
                BasicOrder_startTimeThroughZoneHash_size,
                Common_amount_offset,
                Common_identifier_offset,
                Common_token_offset,
                generateOrder_base_tail_offset,
                generateOrder_context_head_offset,
                generateOrder_head_offset,
                generateOrder_maximumSpent_head_offset,
                generateOrder_minimumReceived_head_offset,
                generateOrder_selector_offset,
                generateOrder_selector,
                OneWord,
                OneWordShift,
                OnlyFullWordMask,
                OrderFulfilled_baseDataSize,
                OrderFulfilled_offer_length_baseOffset,
                OrderParameters_consideration_head_offset,
                OrderParameters_endTime_offset,
                OrderParameters_offer_head_offset,
                OrderParameters_startTime_offset,
                OrderParameters_zoneHash_offset,
                ratifyOrder_base_tail_offset,
                ratifyOrder_consideration_head_offset,
                ratifyOrder_context_head_offset,
                ratifyOrder_contractNonce_offset,
                ratifyOrder_head_offset,
                ratifyOrder_orderHashes_head_offset,
                ratifyOrder_selector_offset,
                ratifyOrder_selector,
                ReceivedItem_size,
                Selector_length,
                SixtyThreeBytes,
                SpentItem_size_shift,
                SpentItem_size,
                validateOrder_head_offset,
                validateOrder_selector_offset,
                validateOrder_selector,
                validateOrder_zoneParameters_offset,
                ZoneParameters_base_tail_offset,
                ZoneParameters_basicOrderFixedElements_length,
                ZoneParameters_consideration_head_offset,
                ZoneParameters_endTime_offset,
                ZoneParameters_extraData_head_offset,
                ZoneParameters_fulfiller_offset,
                ZoneParameters_offer_head_offset,
                ZoneParameters_offerer_offset,
                ZoneParameters_orderHashes_head_offset,
                ZoneParameters_selectorAndPointer_length,
                ZoneParameters_startTime_offset,
                ZoneParameters_zoneHash_offset
            } from "./ConsiderationConstants.sol";
            import {
                BasicOrderParameters,
                OrderParameters
            } from "./ConsiderationStructs.sol";
            import {
                CalldataPointer,
                getFreeMemoryPointer,
                MemoryPointer
            } from "../helpers/PointerLibraries.sol";
            contract ConsiderationEncoder {
                /**
                 * @dev Takes a bytes array and casts it to a memory pointer.
                 *
                 * @param obj A bytes array in memory.
                 *
                 * @return ptr A memory pointer to the start of the bytes array in memory.
                 */
                function toMemoryPointer(
                    bytes memory obj
                ) internal pure returns (MemoryPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Takes an array of bytes32 types and casts it to a memory pointer.
                 *
                 * @param obj An array of bytes32 types in memory.
                 *
                 * @return ptr A memory pointer to the start of the array of bytes32 types
                 *             in memory.
                 */
                function toMemoryPointer(
                    bytes32[] memory obj
                ) internal pure returns (MemoryPointer ptr) {
                    assembly {
                        ptr := obj
                    }
                }
                /**
                 * @dev Takes a bytes array in memory and copies it to a new location in
                 *      memory.
                 *
                 * @param src A memory pointer referencing the bytes array to be copied (and
                 *            pointing to the length of the bytes array).
                 * @param src A memory pointer referencing the location in memory to copy
                 *            the bytes array to (and pointing to the length of the copied
                 *            bytes array).
                 *
                 * @return size The size of the bytes array.
                 */
                function _encodeBytes(
                    MemoryPointer src,
                    MemoryPointer dst
                ) internal view returns (uint256 size) {
                    unchecked {
                        // Mask the length of the bytes array to protect against overflow
                        // and round up to the nearest word.
                        // Note: `size` also includes the 1 word that stores the length.
                        size = (src.readUint256() + SixtyThreeBytes) & OnlyFullWordMask;
                        // Copy the bytes array to the new memory location.
                        src.copy(dst, size);
                    }
                }
                /**
                 * @dev Takes an OrderParameters struct and a context bytes array in memory
                 *      and encodes it as `generateOrder` calldata.
                 *
                 * @param orderParameters The OrderParameters struct used to construct the
                 *                        encoded `generateOrder` calldata.
                 * @param context         The context bytes array used to construct the
                 *                        encoded `generateOrder` calldata.
                 *
                 * @return dst  A memory pointer referencing the encoded `generateOrder`
                 *              calldata.
                 * @return size The size of the bytes array.
                 */
                function _encodeGenerateOrder(
                    OrderParameters memory orderParameters,
                    bytes memory context
                ) internal view returns (MemoryPointer dst, uint256 size) {
                    // Get the memory pointer for the OrderParameters struct.
                    MemoryPointer src = orderParameters.toMemoryPointer();
                    // Get free memory pointer to write calldata to.
                    dst = getFreeMemoryPointer();
                    // Write generateOrder selector and get pointer to start of calldata.
                    dst.write(generateOrder_selector);
                    dst = dst.offset(generateOrder_selector_offset);
                    // Get pointer to the beginning of the encoded data.
                    MemoryPointer dstHead = dst.offset(generateOrder_head_offset);
                    // Write `fulfiller` to calldata.
                    dstHead.write(msg.sender);
                    // Initialize tail offset, used to populate the minimumReceived array.
                    uint256 tailOffset = generateOrder_base_tail_offset;
                    // Write offset to minimumReceived.
                    dstHead.offset(generateOrder_minimumReceived_head_offset).write(
                        tailOffset
                    );
                    // Get memory pointer to `orderParameters.offer.length`.
                    MemoryPointer srcOfferPointer = src
                        .offset(OrderParameters_offer_head_offset)
                        .readMemoryPointer();
                    // Encode the offer array as a `SpentItem[]`.
                    uint256 minimumReceivedSize = _encodeSpentItems(
                        srcOfferPointer,
                        dstHead.offset(tailOffset)
                    );
                    unchecked {
                        // Increment tail offset, now used to populate maximumSpent array.
                        tailOffset += minimumReceivedSize;
                    }
                    // Write offset to maximumSpent.
                    dstHead.offset(generateOrder_maximumSpent_head_offset).write(
                        tailOffset
                    );
                    // Get memory pointer to `orderParameters.consideration.length`.
                    MemoryPointer srcConsiderationPointer = src
                        .offset(OrderParameters_consideration_head_offset)
                        .readMemoryPointer();
                    // Encode the consideration array as a `SpentItem[]`.
                    uint256 maximumSpentSize = _encodeSpentItems(
                        srcConsiderationPointer,
                        dstHead.offset(tailOffset)
                    );
                    unchecked {
                        // Increment tail offset, now used to populate context array.
                        tailOffset += maximumSpentSize;
                    }
                    // Write offset to context.
                    dstHead.offset(generateOrder_context_head_offset).write(tailOffset);
                    // Get memory pointer to context.
                    MemoryPointer srcContext = toMemoryPointer(context);
                    // Encode context as a bytes array.
                    uint256 contextSize = _encodeBytes(
                        srcContext,
                        dstHead.offset(tailOffset)
                    );
                    unchecked {
                        // Increment the tail offset, now used to determine final size.
                        tailOffset += contextSize;
                        // Derive the final size by including the selector.
                        size = Selector_length + tailOffset;
                    }
                }
                /**
                 * @dev Takes an order hash (e.g. offerer shifted 96 bits to the left XOR'd
                 *      with the contract nonce in the case of contract orders), an
                 *      OrderParameters struct, context bytes array, and an array of order
                 *      hashes for each order included as part of the current fulfillment
                 *      and encodes it as `ratifyOrder` calldata.
                 *
                 * @param orderHash       The order hash (e.g. shl(0x60, offerer) ^ nonce).
                 * @param orderParameters The OrderParameters struct used to construct the
                 *                        encoded `ratifyOrder` calldata.
                 * @param context         The context bytes array used to construct the
                 *                        encoded `ratifyOrder` calldata.
                 * @param orderHashes     An array of bytes32 values representing the order
                 *                        hashes of all orders included as part of the
                 *                        current fulfillment.
                 * @param shiftedOfferer  The offerer for the order, shifted 96 bits to the
                 *                        left.
                 *
                 * @return dst  A memory pointer referencing the encoded `ratifyOrder`
                 *              calldata.
                 * @return size The size of the bytes array.
                 */
                function _encodeRatifyOrder(
                    bytes32 orderHash, // e.g. shl(0x60, offerer) ^ contract nonce
                    OrderParameters memory orderParameters,
                    bytes memory context, // encoded based on the schemaID
                    bytes32[] memory orderHashes,
                    uint256 shiftedOfferer
                ) internal view returns (MemoryPointer dst, uint256 size) {
                    // Get free memory pointer to write calldata to. This isn't allocated as
                    // it is only used for a single function call.
                    dst = getFreeMemoryPointer();
                    // Write ratifyOrder selector and get pointer to start of calldata.
                    dst.write(ratifyOrder_selector);
                    dst = dst.offset(ratifyOrder_selector_offset);
                    // Get pointer to the beginning of the encoded data.
                    MemoryPointer dstHead = dst.offset(ratifyOrder_head_offset);
                    // Write contractNonce to calldata via xor(orderHash, shiftedOfferer).
                    dstHead.offset(ratifyOrder_contractNonce_offset).write(
                        uint256(orderHash) ^ shiftedOfferer
                    );
                    // Initialize tail offset, used to populate the offer array.
                    uint256 tailOffset = ratifyOrder_base_tail_offset;
                    MemoryPointer src = orderParameters.toMemoryPointer();
                    // Write offset to `offer`.
                    dstHead.write(tailOffset);
                    // Get memory pointer to `orderParameters.offer.length`.
                    MemoryPointer srcOfferPointer = src
                        .offset(OrderParameters_offer_head_offset)
                        .readMemoryPointer();
                    // Encode the offer array as a `SpentItem[]`.
                    uint256 offerSize = _encodeSpentItems(
                        srcOfferPointer,
                        dstHead.offset(tailOffset)
                    );
                    unchecked {
                        // Increment tail offset, now used to populate consideration array.
                        tailOffset += offerSize;
                    }
                    // Write offset to consideration.
                    dstHead.offset(ratifyOrder_consideration_head_offset).write(tailOffset);
                    // Get pointer to `orderParameters.consideration.length`.
                    MemoryPointer srcConsiderationPointer = src
                        .offset(OrderParameters_consideration_head_offset)
                        .readMemoryPointer();
                    // Encode the consideration array as a `ReceivedItem[]`.
                    uint256 considerationSize = _encodeConsiderationAsReceivedItems(
                        srcConsiderationPointer,
                        dstHead.offset(tailOffset)
                    );
                    unchecked {
                        // Increment tail offset, now used to populate context array.
                        tailOffset += considerationSize;
                    }
                    // Write offset to context.
                    dstHead.offset(ratifyOrder_context_head_offset).write(tailOffset);
                    // Encode context.
                    uint256 contextSize = _encodeBytes(
                        toMemoryPointer(context),
                        dstHead.offset(tailOffset)
                    );
                    unchecked {
                        // Increment tail offset, now used to populate orderHashes array.
                        tailOffset += contextSize;
                    }
                    // Write offset to orderHashes.
                    dstHead.offset(ratifyOrder_orderHashes_head_offset).write(tailOffset);
                    // Encode orderHashes.
                    uint256 orderHashesSize = _encodeOrderHashes(
                        toMemoryPointer(orderHashes),
                        dstHead.offset(tailOffset)
                    );
                    unchecked {
                        // Increment the tail offset, now used to determine final size.
                        tailOffset += orderHashesSize;
                        // Derive the final size by including the selector.
                        size = Selector_length + tailOffset;
                    }
                }
                /**
                 * @dev Takes an order hash, OrderParameters struct, extraData bytes array,
                 *      and array of order hashes for each order included as part of the
                 *      current fulfillment and encodes it as `validateOrder` calldata.
                 *      Note that future, new versions of this contract may end up writing
                 *      to a memory region that might have been potentially dirtied by the
                 *      accumulator. Since the book-keeping for the accumulator does not
                 *      update the free memory pointer, it will be necessary to ensure that
                 *      all bytes in the memory in the range [dst, dst+size) are fully
                 *      updated/written to in this function.
                 *
                 * @param orderHash       The order hash.
                 * @param orderParameters The OrderParameters struct used to construct the
                 *                        encoded `validateOrder` calldata.
                 * @param extraData       The extraData bytes array used to construct the
                 *                        encoded `validateOrder` calldata.
                 * @param orderHashes     An array of bytes32 values representing the order
                 *                        hashes of all orders included as part of the
                 *                        current fulfillment.
                 *
                 * @return dst  A memory pointer referencing the encoded `validateOrder`
                 *              calldata.
                 * @return size The size of the bytes array.
                 */
                function _encodeValidateOrder(
                    bytes32 orderHash,
                    OrderParameters memory orderParameters,
                    bytes memory extraData,
                    bytes32[] memory orderHashes
                ) internal view returns (MemoryPointer dst, uint256 size) {
                    // Get free memory pointer to write calldata to. This isn't allocated as
                    // it is only used for a single function call.
                    dst = getFreeMemoryPointer();
                    // Write validateOrder selector and get pointer to start of calldata.
                    dst.write(validateOrder_selector);
                    dst = dst.offset(validateOrder_selector_offset);
                    // Get pointer to the beginning of the encoded data.
                    MemoryPointer dstHead = dst.offset(validateOrder_head_offset);
                    // Write offset to zoneParameters to start of calldata.
                    dstHead.write(validateOrder_zoneParameters_offset);
                    // Reuse `dstHead` as pointer to zoneParameters.
                    dstHead = dstHead.offset(validateOrder_zoneParameters_offset);
                    // Write orderHash and fulfiller to zoneParameters.
                    dstHead.writeBytes32(orderHash);
                    dstHead.offset(ZoneParameters_fulfiller_offset).write(msg.sender);
                    // Get the memory pointer to the order parameters struct.
                    MemoryPointer src = orderParameters.toMemoryPointer();
                    // Copy offerer, startTime, endTime and zoneHash to zoneParameters.
                    dstHead.offset(ZoneParameters_offerer_offset).write(src.readUint256());
                    dstHead.offset(ZoneParameters_startTime_offset).write(
                        src.offset(OrderParameters_startTime_offset).readUint256()
                    );
                    dstHead.offset(ZoneParameters_endTime_offset).write(
                        src.offset(OrderParameters_endTime_offset).readUint256()
                    );
                    dstHead.offset(ZoneParameters_zoneHash_offset).write(
                        src.offset(OrderParameters_zoneHash_offset).readUint256()
                    );
                    // Initialize tail offset, used to populate the offer array.
                    uint256 tailOffset = ZoneParameters_base_tail_offset;
                    // Write offset to `offer`.
                    dstHead.offset(ZoneParameters_offer_head_offset).write(tailOffset);
                    // Get pointer to `orderParameters.offer.length`.
                    MemoryPointer srcOfferPointer = src
                        .offset(OrderParameters_offer_head_offset)
                        .readMemoryPointer();
                    // Encode the offer array as a `SpentItem[]`.
                    uint256 offerSize = _encodeSpentItems(
                        srcOfferPointer,
                        dstHead.offset(tailOffset)
                    );
                    unchecked {
                        // Increment tail offset, now used to populate consideration array.
                        tailOffset += offerSize;
                    }
                    // Write offset to consideration.
                    dstHead.offset(ZoneParameters_consideration_head_offset).write(
                        tailOffset
                    );
                    // Get pointer to `orderParameters.consideration.length`.
                    MemoryPointer srcConsiderationPointer = src
                        .offset(OrderParameters_consideration_head_offset)
                        .readMemoryPointer();
                    // Encode the consideration array as a `ReceivedItem[]`.
                    uint256 considerationSize = _encodeConsiderationAsReceivedItems(
                        srcConsiderationPointer,
                        dstHead.offset(tailOffset)
                    );
                    unchecked {
                        // Increment tail offset, now used to populate extraData array.
                        tailOffset += considerationSize;
                    }
                    // Write offset to extraData.
                    dstHead.offset(ZoneParameters_extraData_head_offset).write(tailOffset);
                    // Copy extraData.
                    uint256 extraDataSize = _encodeBytes(
                        toMemoryPointer(extraData),
                        dstHead.offset(tailOffset)
                    );
                    unchecked {
                        // Increment tail offset, now used to populate orderHashes array.
                        tailOffset += extraDataSize;
                    }
                    // Write offset to orderHashes.
                    dstHead.offset(ZoneParameters_orderHashes_head_offset).write(
                        tailOffset
                    );
                    // Encode the order hashes array.
                    uint256 orderHashesSize = _encodeOrderHashes(
                        toMemoryPointer(orderHashes),
                        dstHead.offset(tailOffset)
                    );
                    unchecked {
                        // Increment the tail offset, now used to determine final size.
                        tailOffset += orderHashesSize;
                        // Derive final size including selector and ZoneParameters pointer.
                        size = ZoneParameters_selectorAndPointer_length + tailOffset;
                    }
                }
                /**
                 * @dev Takes an order hash and BasicOrderParameters struct (from calldata)
                 *      and encodes it as `validateOrder` calldata.
                 *
                 * @param orderHash  The order hash.
                 * @param parameters The BasicOrderParameters struct used to construct the
                 *                   encoded `validateOrder` calldata.
                 *
                 * @return dst  A memory pointer referencing the encoded `validateOrder`
                 *              calldata.
                 * @return size The size of the bytes array.
                 */
                function _encodeValidateBasicOrder(
                    bytes32 orderHash,
                    BasicOrderParameters calldata parameters
                ) internal view returns (MemoryPointer dst, uint256 size) {
                    // Get free memory pointer to write calldata to. This isn't allocated as
                    // it is only used for a single function call.
                    dst = getFreeMemoryPointer();
                    // Write validateOrder selector and get pointer to start of calldata.
                    dst.write(validateOrder_selector);
                    dst = dst.offset(validateOrder_selector_offset);
                    // Get pointer to the beginning of the encoded data.
                    MemoryPointer dstHead = dst.offset(validateOrder_head_offset);
                    // Write offset to zoneParameters to start of calldata.
                    dstHead.write(validateOrder_zoneParameters_offset);
                    // Reuse `dstHead` as pointer to zoneParameters.
                    dstHead = dstHead.offset(validateOrder_zoneParameters_offset);
                    // Write offerer, orderHash and fulfiller to zoneParameters.
                    dstHead.writeBytes32(orderHash);
                    dstHead.offset(ZoneParameters_fulfiller_offset).write(msg.sender);
                    dstHead.offset(ZoneParameters_offerer_offset).write(parameters.offerer);
                    // Copy startTime, endTime and zoneHash to zoneParameters.
                    CalldataPointer.wrap(BasicOrder_startTime_cdPtr).copy(
                        dstHead.offset(ZoneParameters_startTime_offset),
                        BasicOrder_startTimeThroughZoneHash_size
                    );
                    // Initialize tail offset, used for the offer + consideration arrays.
                    uint256 tailOffset = ZoneParameters_base_tail_offset;
                    // Write offset to offer from event data into target calldata.
                    dstHead.offset(ZoneParameters_offer_head_offset).write(tailOffset);
                    unchecked {
                        // Write consideration offset next (located 5 words after offer).
                        dstHead.offset(ZoneParameters_consideration_head_offset).write(
                            tailOffset + BasicOrder_common_params_size
                        );
                        // Retrieve the offset to the length of additional recipients.
                        uint256 additionalRecipientsLength = CalldataPointer
                            .wrap(BasicOrder_additionalRecipients_length_cdPtr)
                            .readUint256();
                        // Derive offset to event data using base offset & total recipients.
                        uint256 offerDataOffset = OrderFulfilled_offer_length_baseOffset +
                            additionalRecipientsLength *
                            OneWord;
                        // Derive size of offer and consideration data.
                        // 2 words (lengths) + 4 (offer data) + 5 (consideration 1) + 5 * ar
                        uint256 offerAndConsiderationSize = OrderFulfilled_baseDataSize +
                            (additionalRecipientsLength * ReceivedItem_size);
                        // Copy offer and consideration data from event data to calldata.
                        MemoryPointer.wrap(offerDataOffset).copy(
                            dstHead.offset(tailOffset),
                            offerAndConsiderationSize
                        );
                        // Increment tail offset, now used to populate extraData array.
                        tailOffset += offerAndConsiderationSize;
                    }
                    // Write empty bytes for extraData.
                    dstHead.offset(ZoneParameters_extraData_head_offset).write(tailOffset);
                    dstHead.offset(tailOffset).write(0);
                    unchecked {
                        // Increment tail offset, now used to populate orderHashes array.
                        tailOffset += OneWord;
                    }
                    // Write offset to orderHashes.
                    dstHead.offset(ZoneParameters_orderHashes_head_offset).write(
                        tailOffset
                    );
                    // Write length = 1 to the orderHashes array.
                    dstHead.offset(tailOffset).write(1);
                    unchecked {
                        // Write the single order hash to the orderHashes array.
                        dstHead.offset(tailOffset + OneWord).writeBytes32(orderHash);
                        // Final size: selector, ZoneParameters pointer, orderHashes & tail.
                        size = ZoneParameters_basicOrderFixedElements_length + tailOffset;
                    }
                }
                /**
                 * @dev Takes a memory pointer to an array of bytes32 values representing
                 *      the order hashes included as part of the fulfillment and a memory
                 *      pointer to a location to copy it to, and copies the source data to
                 *      the destination in memory.
                 *
                 * @param srcLength A memory pointer referencing the order hashes array to
                 *                  be copied (and pointing to the length of the array).
                 * @param dstLength A memory pointer referencing the location in memory to
                 *                  copy the orderHashes array to (and pointing to the
                 *                  length of the copied array).
                 *
                 * @return size The size of the order hashes array (including the length).
                 */
                function _encodeOrderHashes(
                    MemoryPointer srcLength,
                    MemoryPointer dstLength
                ) internal view returns (uint256 size) {
                    // Read length of the array from source and write to destination.
                    uint256 length = srcLength.readUint256();
                    dstLength.write(length);
                    unchecked {
                        // Determine head & tail size as one word per element in the array.
                        uint256 headAndTailSize = length << OneWordShift;
                        // Copy the tail starting from the next element of the source to the
                        // next element of the destination.
                        srcLength.next().copy(dstLength.next(), headAndTailSize);
                        // Set size to the length of the tail plus one word for length.
                        size = headAndTailSize + OneWord;
                    }
                }
                /**
                 * @dev Takes a memory pointer to an offer or consideration array and a
                 *      memory pointer to a location to copy it to, and copies the source
                 *      data to the destination in memory as a SpentItem array.
                 *
                 * @param srcLength A memory pointer referencing the offer or consideration
                 *                  array to be copied as a SpentItem array (and pointing to
                 *                  the length of the original array).
                 * @param dstLength A memory pointer referencing the location in memory to
                 *                  copy the offer array to (and pointing to the length of
                 *                  the copied array).
                 *
                 * @return size The size of the SpentItem array (including the length).
                 */
                function _encodeSpentItems(
                    MemoryPointer srcLength,
                    MemoryPointer dstLength
                ) internal pure returns (uint256 size) {
                    assembly {
                        // Read length of the array from source and write to destination.
                        let length := mload(srcLength)
                        mstore(dstLength, length)
                        // Get pointer to first item's head position in the array,
                        // containing the item's pointer in memory. The head pointer will be
                        // incremented until it reaches the tail position (start of the
                        // array data).
                        let mPtrHead := add(srcLength, OneWord)
                        // Position in memory to write next item for calldata. Since
                        // SpentItem has a fixed length, the array elements do not contain
                        // head elements in calldata, they are concatenated together after
                        // the array length.
                        let cdPtrData := add(dstLength, OneWord)
                        // Pointer to end of array head in memory.
                        let mPtrHeadEnd := add(mPtrHead, shl(OneWordShift, length))
                        for {
                        } lt(mPtrHead, mPtrHeadEnd) {
                        } {
                            // Read pointer to data for array element from head position.
                            let mPtrTail := mload(mPtrHead)
                            // Copy itemType, token, identifier, amount to calldata.
                            mstore(cdPtrData, mload(mPtrTail))
                            mstore(
                                add(cdPtrData, Common_token_offset),
                                mload(add(mPtrTail, Common_token_offset))
                            )
                            mstore(
                                add(cdPtrData, Common_identifier_offset),
                                mload(add(mPtrTail, Common_identifier_offset))
                            )
                            mstore(
                                add(cdPtrData, Common_amount_offset),
                                mload(add(mPtrTail, Common_amount_offset))
                            )
                            mPtrHead := add(mPtrHead, OneWord)
                            cdPtrData := add(cdPtrData, SpentItem_size)
                        }
                        size := add(OneWord, shl(SpentItem_size_shift, length))
                    }
                }
                /**
                 * @dev Takes a memory pointer to an consideration array and a memory
                 *      pointer to a location to copy it to, and copies the source data to
                 *      the destination in memory as a ReceivedItem array.
                 *
                 * @param srcLength A memory pointer referencing the consideration array to
                 *                  be copied as a ReceivedItem array (and pointing to the
                 *                  length of the original array).
                 * @param dstLength A memory pointer referencing the location in memory to
                 *                  copy the consideration array to as a ReceivedItem array
                 *                  (and pointing to the length of the new array).
                 *
                 * @return size The size of the ReceivedItem array (including the length).
                 */
                function _encodeConsiderationAsReceivedItems(
                    MemoryPointer srcLength,
                    MemoryPointer dstLength
                ) internal view returns (uint256 size) {
                    unchecked {
                        // Read length of the array from source and write to destination.
                        uint256 length = srcLength.readUint256();
                        dstLength.write(length);
                        // Get pointer to first item's head position in the array,
                        // containing the item's pointer in memory. The head pointer will be
                        // incremented until it reaches the tail position (start of the
                        // array data).
                        MemoryPointer srcHead = srcLength.next();
                        MemoryPointer srcHeadEnd = srcHead.offset(length << OneWordShift);
                        // Position in memory to write next item for calldata. Since
                        // ReceivedItem has a fixed length, the array elements do not
                        // contain offsets in calldata, they are concatenated together after
                        // the array length.
                        MemoryPointer dstHead = dstLength.next();
                        while (srcHead.lt(srcHeadEnd)) {
                            MemoryPointer srcTail = srcHead.pptr();
                            srcTail.copy(dstHead, ReceivedItem_size);
                            srcHead = srcHead.next();
                            dstHead = dstHead.offset(ReceivedItem_size);
                        }
                        size = OneWord + (length * ReceivedItem_size);
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.17;
            import { ReentrancyErrors } from "../interfaces/ReentrancyErrors.sol";
            import { LowLevelHelpers } from "./LowLevelHelpers.sol";
            import {
                _revertInvalidMsgValue,
                _revertNoReentrantCalls
            } from "./ConsiderationErrors.sol";
            import {
                _ENTERED_AND_ACCEPTING_NATIVE_TOKENS,
                _ENTERED,
                _NOT_ENTERED
            } from "./ConsiderationConstants.sol";
            /**
             * @title ReentrancyGuard
             * @author 0age
             * @notice ReentrancyGuard contains a storage variable and related functionality
             *         for protecting against reentrancy.
             */
            contract ReentrancyGuard is ReentrancyErrors, LowLevelHelpers {
                // 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 a sentinel value for the reentrancy
                 *      guard is not currently set and, if not, to set a sentinel value for
                 *      the reentrancy guard based on whether or not native tokens may be
                 *      received during execution or not.
                 *
                 * @param acceptNativeTokens A boolean indicating whether native tokens may
                 *                           be received during execution or not.
                 */
                function _setReentrancyGuard(bool acceptNativeTokens) internal {
                    // Ensure that the reentrancy guard is not already set.
                    _assertNonReentrant();
                    // Set the reentrancy guard. A value of 2 indicates that native tokens
                    // may not be accepted during execution, whereas a value of 3 indicates
                    // that they will be accepted (with any remaining native tokens returned
                    // to the caller).
                    unchecked {
                        _reentrancyGuard = _ENTERED + _cast(acceptNativeTokens);
                    }
                }
                /**
                 * @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 a 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) {
                        _revertNoReentrantCalls();
                    }
                }
                /**
                 * @dev Internal view function to ensure that the sentinel value indicating
                 *      native tokens may be received during execution is currently set.
                 */
                function _assertAcceptingNativeTokens() internal view {
                    // Ensure that the reentrancy guard is not currently set.
                    if (_reentrancyGuard != _ENTERED_AND_ACCEPTING_NATIVE_TOKENS) {
                        _revertInvalidMsgValue(msg.value);
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            /**
             * @title ReentrancyErrors
             * @author 0age
             * @notice ReentrancyErrors contains errors related to reentrancy.
             */
            interface ReentrancyErrors {
                /**
                 * @dev Revert with an error when a caller attempts to reenter a protected
                 *      function.
                 */
                error NoReentrantCalls();
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.17;
            import {
                CostPerWord,
                ExtraGasBuffer,
                FreeMemoryPointerSlot,
                MemoryExpansionCoefficientShift,
                OneWord,
                OneWordShift,
                ThirtyOneBytes
            } from "./ConsiderationConstants.sol";
            /**
             * @title LowLevelHelpers
             * @author 0age
             * @notice LowLevelHelpers contains logic for performing various low-level
             *         operations.
             */
            contract LowLevelHelpers {
                /**
                 * @dev Internal view function to revert and pass along the revert reason if
                 *      data was returned by the last call and that the size of that data
                 *      does not exceed the currently allocated memory size.
                 */
                function _revertWithReasonIfOneIsReturned() internal view {
                    assembly {
                        // If it returned a message, bubble it up as long as sufficient gas
                        // remains to do so:
                        if returndatasize() {
                            // Ensure that sufficient gas is available to copy returndata
                            // while expanding memory where necessary. Start by computing
                            // the word size of returndata and allocated memory.
                            let returnDataWords := shr(
                                OneWordShift,
                                add(returndatasize(), ThirtyOneBytes)
                            )
                            // Note: use the free memory pointer in place of msize() to work
                            // around a Yul warning that prevents accessing msize directly
                            // when the IR pipeline is activated.
                            let msizeWords := shr(
                                OneWordShift,
                                mload(FreeMemoryPointerSlot)
                            )
                            // Next, compute the cost of the returndatacopy.
                            let cost := mul(CostPerWord, returnDataWords)
                            // Then, compute cost of new memory allocation.
                            if gt(returnDataWords, msizeWords) {
                                cost := add(
                                    cost,
                                    add(
                                        mul(sub(returnDataWords, msizeWords), CostPerWord),
                                        shr(
                                            MemoryExpansionCoefficientShift,
                                            sub(
                                                mul(returnDataWords, returnDataWords),
                                                mul(msizeWords, msizeWords)
                                            )
                                        )
                                    )
                                )
                            }
                            // Finally, add a small constant and compare to gas remaining;
                            // bubble up the revert data if enough gas is still available.
                            if lt(add(cost, ExtraGasBuffer), gas()) {
                                // Copy returndata to memory; overwrite existing memory.
                                returndatacopy(0, 0, returndatasize())
                                // Revert, specifying memory region with copied returndata.
                                revert(0, returndatasize())
                            }
                        }
                    }
                }
                /**
                 * @dev Internal view function to branchlessly select either the caller (if
                 *      a supplied recipient is equal to zero) or the supplied recipient (if
                 *      that recipient is a nonzero value).
                 *
                 * @param recipient The supplied recipient.
                 *
                 * @return updatedRecipient The updated recipient.
                 */
                function _substituteCallerForEmptyRecipient(
                    address recipient
                ) internal view returns (address updatedRecipient) {
                    // Utilize assembly to perform a branchless operation on the recipient.
                    assembly {
                        // Add caller to recipient if recipient equals 0; otherwise add 0.
                        updatedRecipient := add(recipient, mul(iszero(recipient), caller()))
                    }
                }
                /**
                 * @dev Internal pure function to cast a `bool` value to a `uint256` value.
                 *
                 * @param b The `bool` value to cast.
                 *
                 * @return u The `uint256` value.
                 */
                function _cast(bool b) internal pure returns (uint256 u) {
                    assembly {
                        u := b
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            /**
             * @title SignatureVerificationErrors
             * @author 0age
             * @notice SignatureVerificationErrors contains all errors related to signature
             *         verification.
             */
            interface SignatureVerificationErrors {
                /**
                 * @dev Revert with an error when a signature that does not contain a v
                 *      value of 27 or 28 has been supplied.
                 *
                 * @param v The invalid v value.
                 */
                error BadSignatureV(uint8 v);
                /**
                 * @dev Revert with an error when the signer recovered by the supplied
                 *      signature does not match the offerer or an allowed EIP-1271 signer
                 *      as specified by the offerer in the event they are a contract.
                 */
                error InvalidSigner();
                /**
                 * @dev Revert with an error when a signer cannot be recovered from the
                 *      supplied signature.
                 */
                error InvalidSignature();
                /**
                 * @dev Revert with an error when an EIP-1271 call to an account fails.
                 */
                error BadContractSignature();
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            /*
             * -------------------------- Disambiguation & Other Notes ---------------------
             *    - The term "head" is used as it is in the documentation for ABI encoding,
             *      but only in reference to dynamic types, i.e. it always refers to the
             *      offset or pointer to the body of a dynamic type. In calldata, the head
             *      is always an offset (relative to the parent object), while in memory,
             *      the head is always the pointer to the body. More information found here:
             *      https://docs.soliditylang.org/en/v0.8.17/abi-spec.html#argument-encoding
             *        - Note that the length of an array is separate from and precedes the
             *          head of the array.
             *
             *    - The term "body" is used in place of the term "head" used in the ABI
             *      documentation. It refers to the start of the data for a dynamic type,
             *      e.g. the first word of a struct or the first word of the first element
             *      in an array.
             *
             *    - The term "pointer" is used to describe the absolute position of a value
             *      and never an offset relative to another value.
             *        - The suffix "_ptr" refers to a memory pointer.
             *        - The suffix "_cdPtr" refers to a calldata pointer.
             *
             *    - The term "offset" is used to describe the position of a value relative
             *      to some parent value. For example, OrderParameters_conduit_offset is the
             *      offset to the "conduit" value in the OrderParameters struct relative to
             *      the start of the body.
             *        - Note: Offsets are used to derive pointers.
             *
             *    - Some structs have pointers defined for all of their fields in this file.
             *      Lines which are commented out are fields that are not used in the
             *      codebase but have been left in for readability.
             */
            uint256 constant ThirtyOneBytes = 0x1f;
            uint256 constant OneWord = 0x20;
            uint256 constant TwoWords = 0x40;
            uint256 constant ThreeWords = 0x60;
            uint256 constant OneWordShift = 0x5;
            uint256 constant TwoWordsShift = 0x6;
            uint256 constant FreeMemoryPointerSlot = 0x40;
            uint256 constant ZeroSlot = 0x60;
            uint256 constant DefaultFreeMemoryPointer = 0x80;
            uint256 constant Slot0x80 = 0x80;
            uint256 constant Slot0xA0 = 0xa0;
            uint256 constant Slot0xC0 = 0xc0;
            uint256 constant Generic_error_selector_offset = 0x1c;
            // abi.encodeWithSignature("transferFrom(address,address,uint256)")
            uint256 constant ERC20_transferFrom_signature = (
                0x23b872dd00000000000000000000000000000000000000000000000000000000
            );
            uint256 constant ERC20_transferFrom_sig_ptr = 0x0;
            uint256 constant ERC20_transferFrom_from_ptr = 0x04;
            uint256 constant ERC20_transferFrom_to_ptr = 0x24;
            uint256 constant ERC20_transferFrom_amount_ptr = 0x44;
            uint256 constant ERC20_transferFrom_length = 0x64; // 4 + 32 * 3 == 100
            // abi.encodeWithSignature(
            //     "safeTransferFrom(address,address,uint256,uint256,bytes)"
            // )
            uint256 constant ERC1155_safeTransferFrom_signature = (
                0xf242432a00000000000000000000000000000000000000000000000000000000
            );
            uint256 constant ERC1155_safeTransferFrom_sig_ptr = 0x0;
            uint256 constant ERC1155_safeTransferFrom_from_ptr = 0x04;
            uint256 constant ERC1155_safeTransferFrom_to_ptr = 0x24;
            uint256 constant ERC1155_safeTransferFrom_id_ptr = 0x44;
            uint256 constant ERC1155_safeTransferFrom_amount_ptr = 0x64;
            uint256 constant ERC1155_safeTransferFrom_data_offset_ptr = 0x84;
            uint256 constant ERC1155_safeTransferFrom_data_length_ptr = 0xa4;
            uint256 constant ERC1155_safeTransferFrom_length = 0xc4; // 4 + 32 * 6 == 196
            uint256 constant ERC1155_safeTransferFrom_data_length_offset = 0xa0;
            // abi.encodeWithSignature(
            //     "safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)"
            // )
            uint256 constant ERC1155_safeBatchTransferFrom_signature = (
                0x2eb2c2d600000000000000000000000000000000000000000000000000000000
            );
            // bytes4 constant ERC1155_safeBatchTransferFrom_selector = bytes4(
            //     bytes32(ERC1155_safeBatchTransferFrom_signature)
            // );
            uint256 constant ERC721_transferFrom_signature = (
                0x23b872dd00000000000000000000000000000000000000000000000000000000
            );
            uint256 constant ERC721_transferFrom_sig_ptr = 0x0;
            uint256 constant ERC721_transferFrom_from_ptr = 0x04;
            uint256 constant ERC721_transferFrom_to_ptr = 0x24;
            uint256 constant ERC721_transferFrom_id_ptr = 0x44;
            uint256 constant ERC721_transferFrom_length = 0x64; // 4 + 32 * 3 == 100
            /*
             *  error NoContract(address account)
             *    - Defined in TokenTransferrerErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             *    - 0x00: account
             * Revert buffer is memory[0x1c:0x40]
             */
            uint256 constant NoContract_error_selector = 0x5f15d672;
            uint256 constant NoContract_error_account_ptr = 0x20;
            uint256 constant NoContract_error_length = 0x24;
            /*
             *  error TokenTransferGenericFailure(
             *      address token,
             *      address from,
             *      address to,
             *      uint256 identifier,
             *      uint256 amount
             *  )
             *    - Defined in TokenTransferrerErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             *    - 0x20: token
             *    - 0x40: from
             *    - 0x60: to
             *    - 0x80: identifier
             *    - 0xa0: amount
             * Revert buffer is memory[0x1c:0xc0]
             */
            uint256 constant TokenTransferGenericFailure_error_selector = 0xf486bc87;
            uint256 constant TokenTransferGenericFailure_error_token_ptr = 0x20;
            uint256 constant TokenTransferGenericFailure_error_from_ptr = 0x40;
            uint256 constant TokenTransferGenericFailure_error_to_ptr = 0x60;
            uint256 constant TokenTransferGenericFailure_error_identifier_ptr = 0x80;
            uint256 constant TokenTransferGenericFailure_err_identifier_ptr = 0x80;
            uint256 constant TokenTransferGenericFailure_error_amount_ptr = 0xa0;
            uint256 constant TokenTransferGenericFailure_error_length = 0xa4;
            uint256 constant ExtraGasBuffer = 0x20;
            uint256 constant CostPerWord = 0x3;
            uint256 constant MemoryExpansionCoefficientShift = 0x9;
            // Values are offset by 32 bytes in order to write the token to the beginning
            // in the event of a revert
            uint256 constant BatchTransfer1155Params_ptr = 0x24;
            uint256 constant BatchTransfer1155Params_ids_head_ptr = 0x64;
            uint256 constant BatchTransfer1155Params_amounts_head_ptr = 0x84;
            uint256 constant BatchTransfer1155Params_data_head_ptr = 0xa4;
            uint256 constant BatchTransfer1155Params_data_length_basePtr = 0xc4;
            uint256 constant BatchTransfer1155Params_calldata_baseSize = 0xc4;
            uint256 constant BatchTransfer1155Params_ids_length_ptr = 0xc4;
            uint256 constant BatchTransfer1155Params_ids_length_offset = 0xa0;
            // uint256 constant BatchTransfer1155Params_amounts_length_baseOffset = 0xc0;
            // uint256 constant BatchTransfer1155Params_data_length_baseOffset = 0xe0;
            uint256 constant ConduitBatch1155Transfer_usable_head_size = 0x80;
            uint256 constant ConduitBatch1155Transfer_from_offset = 0x20;
            uint256 constant ConduitBatch1155Transfer_ids_head_offset = 0x60;
            // uint256 constant ConduitBatch1155Transfer_amounts_head_offset = 0x80;
            uint256 constant ConduitBatch1155Transfer_ids_length_offset = 0xa0;
            uint256 constant ConduitBatch1155Transfer_amounts_length_baseOffset = 0xc0;
            // uint256 constant ConduitBatch1155Transfer_calldata_baseSize = 0xc0;
            // Note: abbreviated version of above constant to adhere to line length limit.
            uint256 constant ConduitBatchTransfer_amounts_head_offset = 0x80;
            uint256 constant Invalid1155BatchTransferEncoding_ptr = 0x00;
            uint256 constant Invalid1155BatchTransferEncoding_length = 0x04;
            uint256 constant Invalid1155BatchTransferEncoding_selector = (
                0xeba2084c00000000000000000000000000000000000000000000000000000000
            );
            uint256 constant ERC1155BatchTransferGenericFailure_error_signature = (
                0xafc445e200000000000000000000000000000000000000000000000000000000
            );
            uint256 constant ERC1155BatchTransferGenericFailure_token_ptr = 0x04;
            uint256 constant ERC1155BatchTransferGenericFailure_ids_offset = 0xc0;
            /*
             *  error BadReturnValueFromERC20OnTransfer(
             *      address token, address from, address to, uint256 amount
             *  )
             *    - Defined in TokenTransferrerErrors.sol
             *  Memory layout:
             *    - 0x00: Left-padded selector (data begins at 0x1c)
             *    - 0x00: token
             *    - 0x20: from
             *    - 0x40: to
             *    - 0x60: amount
             * Revert buffer is memory[0x1c:0xa0]
             */
            uint256 constant BadReturnValueFromERC20OnTransfer_error_selector = 0x98891923;
            uint256 constant BadReturnValueFromERC20OnTransfer_error_token_ptr = 0x20;
            uint256 constant BadReturnValueFromERC20OnTransfer_error_from_ptr = 0x40;
            uint256 constant BadReturnValueFromERC20OnTransfer_error_to_ptr = 0x60;
            uint256 constant BadReturnValueFromERC20OnTransfer_error_amount_ptr = 0x80;
            uint256 constant BadReturnValueFromERC20OnTransfer_error_length = 0x84;
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            /**
             * @title ZoneInteractionErrors
             * @author 0age
             * @notice ZoneInteractionErrors contains errors related to zone interaction.
             */
            interface ZoneInteractionErrors {
                /**
                 * @dev Revert with an error when attempting to fill an order that specifies
                 *      a restricted submitter as its order type when not submitted by
                 *      either the offerer or the order's zone or approved as valid by the
                 *      zone in question via a call to `isValidOrder`.
                 *
                 * @param orderHash The order hash for the invalid restricted order.
                 */
                error InvalidRestrictedOrder(bytes32 orderHash);
                /**
                 * @dev Revert with an error when attempting to fill a contract order that
                 *      fails to generate an order successfully, that does not adhere to the
                 *      requirements for minimum spent or maximum received supplied by the
                 *      fulfiller, or that fails the post-execution `ratifyOrder` check..
                 *
                 * @param orderHash The order hash for the invalid contract order.
                 */
                error InvalidContractOrder(bytes32 orderHash);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import { Side } from "../lib/ConsiderationEnums.sol";
            /**
             * @title CriteriaResolutionErrors
             * @author 0age
             * @notice CriteriaResolutionErrors contains all errors related to criteria
             *         resolution.
             */
            interface CriteriaResolutionErrors {
                /**
                 * @dev Revert with an error when providing a criteria resolver that refers
                 *      to an order that has not been supplied.
                 *
                 * @param side The side of the order that was not supplied.
                 */
                error OrderCriteriaResolverOutOfRange(Side side);
                /**
                 * @dev Revert with an error if an offer item still has unresolved criteria
                 *      after applying all criteria resolvers.
                 *
                 * @param orderIndex The index of the order that contains the offer item.
                 * @param offerIndex The index of the offer item that still has unresolved
                 *                   criteria.
                 */
                error UnresolvedOfferCriteria(uint256 orderIndex, uint256 offerIndex);
                /**
                 * @dev Revert with an error if a consideration item still has unresolved
                 *      criteria after applying all criteria resolvers.
                 *
                 * @param orderIndex         The index of the order that contains the
                 *                           consideration item.
                 * @param considerationIndex The index of the consideration item that still
                 *                           has unresolved criteria.
                 */
                error UnresolvedConsiderationCriteria(
                    uint256 orderIndex,
                    uint256 considerationIndex
                );
                /**
                 * @dev Revert with an error when providing a criteria resolver that refers
                 *      to an order with an offer item that has not been supplied.
                 */
                error OfferCriteriaResolverOutOfRange();
                /**
                 * @dev Revert with an error when providing a criteria resolver that refers
                 *      to an order with a consideration item that has not been supplied.
                 */
                error ConsiderationCriteriaResolverOutOfRange();
                /**
                 * @dev Revert with an error when providing a criteria resolver that refers
                 *      to an order with an item that does not expect a criteria to be
                 *      resolved.
                 */
                error CriteriaNotEnabledForItem();
                /**
                 * @dev Revert with an error when providing a criteria resolver that
                 *      contains an invalid proof with respect to the given item and
                 *      chosen identifier.
                 */
                error InvalidProof();
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            /**
             * @title AmountDerivationErrors
             * @author 0age
             * @notice AmountDerivationErrors contains errors related to amount derivation.
             */
            interface AmountDerivationErrors {
                /**
                 * @dev Revert with an error when attempting to apply a fraction as part of
                 *      a partial fill that does not divide the target amount cleanly.
                 */
                error InexactFraction();
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import { Side } from "../lib/ConsiderationEnums.sol";
            /**
             * @title FulfillmentApplicationErrors
             * @author 0age
             * @notice FulfillmentApplicationErrors contains errors related to fulfillment
             *         application and aggregation.
             */
            interface FulfillmentApplicationErrors {
                /**
                 * @dev Revert with an error when a fulfillment is provided that does not
                 *      declare at least one component as part of a call to fulfill
                 *      available orders.
                 */
                error MissingFulfillmentComponentOnAggregation(Side side);
                /**
                 * @dev Revert with an error when a fulfillment is provided that does not
                 *      declare at least one offer component and at least one consideration
                 *      component.
                 */
                error OfferAndConsiderationRequiredOnFulfillment();
                /**
                 * @dev Revert with an error when the initial offer item named by a
                 *      fulfillment component does not match the type, token, identifier,
                 *      or conduit preference of the initial consideration item.
                 *
                 * @param fulfillmentIndex The index of the fulfillment component that
                 *                         does not match the initial offer item.
                 */
                error MismatchedFulfillmentOfferAndConsiderationComponents(
                    uint256 fulfillmentIndex
                );
                /**
                 * @dev Revert with an error when an order or item index are out of range
                 *      or a fulfillment component does not match the type, token,
                 *      identifier, or conduit preference of the initial consideration item.
                 */
                error InvalidFulfillmentComponentData();
            }
            // SPDX-License-Identifier: MIT
            pragma solidity 0.8.17;
            import {
                FreeMemoryPointerSlot,
                OneWord,
                OneWordShift,
                ThirtyOneBytes
            } from "../lib/ConsiderationConstants.sol";
            /**
             * @title TypehashDirectory
             * @notice The typehash directory contains 24 bulk order EIP-712 typehashes,
             *         depending on the height of the tree in each bulk order payload, as
             *         its runtime code (with an invalid opcode prefix so that the contract
             *         cannot be called normally). This runtime code is designed to be read
             *         from by Seaport using `extcodecopy` while verifying bulk signatures.
             */
            contract TypehashDirectory {
                // Encodes "[2]" for use in deriving typehashes.
                bytes3 internal constant twoSubstring = 0x5B325D;
                uint256 internal constant twoSubstringLength = 0x3;
                // Dictates maximum bulk order group size; 24 => 2^24 => 16,777,216 orders.
                uint256 internal constant MaxTreeHeight = 0x18;
                uint256 internal constant InvalidOpcode = 0xfe;
                /**
                 * @dev Derive 24 bulk order EIP-712 typehashes, one for each supported
                 *      tree height from 1 to 24, and write them to runtime code.
                 */
                constructor() {
                    // Declare an array where each type hash will be written.
                    bytes32[] memory typeHashes = new bytes32[](MaxTreeHeight);
                    // Derive a string of 24 "[2]" substrings.
                    bytes memory brackets = getMaxTreeBrackets(MaxTreeHeight);
                    // Derive a string of subtypes for the order parameters.
                    bytes memory subTypes = getTreeSubTypes();
                    // Cache memory pointer before each loop so memory doesn't expand by the
                    // full string size on each loop.
                    uint256 freeMemoryPointer;
                    assembly {
                        freeMemoryPointer := mload(FreeMemoryPointerSlot)
                    }
                    // Iterate over each tree height.
                    for (uint256 i = 0; i < MaxTreeHeight; ) {
                        // The actual height is one greater than its respective index.
                        uint256 height = i + 1;
                        // Slice brackets length to size needed for `height`.
                        assembly {
                            mstore(brackets, mul(twoSubstringLength, height))
                        }
                        // Encode the type string for the BulkOrder struct.
                        bytes memory bulkOrderTypeString = bytes.concat(
                            "BulkOrder(OrderComponents",
                            brackets,
                            " tree)",
                            subTypes
                        );
                        // Derive EIP712 type hash.
                        bytes32 typeHash = keccak256(bulkOrderTypeString);
                        typeHashes[i] = typeHash;
                        // Reset the free memory pointer.
                        assembly {
                            mstore(FreeMemoryPointerSlot, freeMemoryPointer)
                        }
                        unchecked {
                            ++i;
                        }
                    }
                    assembly {
                        // Overwrite length with zero to give the contract an INVALID prefix
                        // and deploy the type hashes array as a contract.
                        mstore(typeHashes, InvalidOpcode)
                        return(
                            add(typeHashes, ThirtyOneBytes),
                            add(shl(OneWordShift, MaxTreeHeight), 1)
                        )
                    }
                }
                /**
                 * @dev Internal pure function that returns a string of "[2]" substrings,
                 *      with a number of substrings equal to the provided height.
                 *
                 * @param maxHeight The number of "[2]" substrings to include.
                 *
                 * @return A bytes array representing the string.
                 */
                function getMaxTreeBrackets(
                    uint256 maxHeight
                ) internal pure returns (bytes memory) {
                    bytes memory suffixes = new bytes(twoSubstringLength * maxHeight);
                    assembly {
                        // Retrieve the pointer to the array head.
                        let ptr := add(suffixes, OneWord)
                        // Derive the terminal pointer.
                        let endPtr := add(ptr, mul(maxHeight, twoSubstringLength))
                        // Iterate over each pointer until terminal pointer is reached.
                        for {
                        } lt(ptr, endPtr) {
                            ptr := add(ptr, twoSubstringLength)
                        } {
                            // Insert "[2]" substring directly at current pointer location.
                            mstore(ptr, twoSubstring)
                        }
                    }
                    // Return the fully populated array of substrings.
                    return suffixes;
                }
                /**
                 * @dev Internal pure function that returns a string of subtypes used in
                 *      generating bulk order EIP-712 typehashes.
                 *
                 * @return A bytes array representing the string.
                 */
                function getTreeSubTypes() internal pure returns (bytes memory) {
                    // Construct the OfferItem type string.
                    bytes memory offerItemTypeString = bytes(
                            "OfferItem("
                                "uint8 itemType,"
                                "address token,"
                                "uint256 identifierOrCriteria,"
                                "uint256 startAmount,"
                                "uint256 endAmount"
                            ")"
                        );
                    // Construct the ConsiderationItem type string.
                    bytes memory considerationItemTypeString = bytes(
                            "ConsiderationItem("
                                "uint8 itemType,"
                                "address token,"
                                "uint256 identifierOrCriteria,"
                                "uint256 startAmount,"
                                "uint256 endAmount,"
                                "address recipient"
                            ")"
                        );
                    // Construct the OrderComponents type string, not including the above.
                    bytes memory orderComponentsPartialTypeString = bytes(
                            "OrderComponents("
                                "address offerer,"
                                "address zone,"
                                "OfferItem[] offer,"
                                "ConsiderationItem[] consideration,"
                                "uint8 orderType,"
                                "uint256 startTime,"
                                "uint256 endTime,"
                                "bytes32 zoneHash,"
                                "uint256 salt,"
                                "bytes32 conduitKey,"
                                "uint256 counter"
                            ")"
                        );
                    // Return the combined string.
                    return
                        bytes.concat(
                            considerationItemTypeString,
                            offerItemTypeString,
                            orderComponentsPartialTypeString
                        );
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import { SeaportInterface } from "../../interfaces/SeaportInterface.sol";
            import {
                AdvancedOrder,
                CriteriaResolver,
                Execution,
                Fulfillment,
                Order,
                OrderComponents
            } 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(address payee) 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.13;
            import {
                AdvancedOrder,
                BasicOrderParameters,
                CriteriaResolver,
                Execution,
                Fulfillment,
                FulfillmentComponent,
                Order,
                OrderComponents
            } from "../lib/ConsiderationStructs.sol";
            /**
             * @title SeaportInterface
             * @author 0age
             * @custom:version 1.4
             * @notice Seaport is a generalized native token/ERC20/ERC721/ERC1155
             *         marketplace. It minimizes external calls to the greatest extent
             *         possible and provides lightweight methods for common routes as well
             *         as more flexible methods for composing advanced orders.
             *
             * @dev 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. Note that unspent offer item amounts or
                 *                         native tokens will not be reflected as part of
                 *                         this array.
                 */
                function fulfillAvailableOrders(
                    Order[] calldata orders,
                    FulfillmentComponent[][] calldata offerFulfillments,
                    FulfillmentComponent[][] calldata considerationFulfillments,
                    bytes32 fulfillerConduitKey,
                    uint256 maximumFulfilled
                )
                    external
                    payable
                    returns (bool[] memory availableOrders, Execution[] memory executions);
                /**
                 * @notice Attempt to fill a group of orders, fully or partially, with an
                 *         arbitrary number of items for offer and consideration per order
                 *         alongside criteria resolvers containing specific token
                 *         identifiers and associated proofs. Any order that is not
                 *         currently active, has already been fully filled, or has been
                 *         cancelled will be omitted. Remaining offer and consideration
                 *         items will then be aggregated where possible as indicated by the
                 *         supplied offer and consideration component arrays and aggregated
                 *         items will be transferred to the fulfiller or to each intended
                 *         recipient, respectively. Note that a failing item transfer or an
                 *         issue with order formatting will cause the entire batch to fail.
                 *
                 * @param advancedOrders            The orders to fulfill along with the
                 *                                  fraction of those orders to attempt to
                 *                                  fill. Note that both the offerer and the
                 *                                  fulfiller must first approve this
                 *                                  contract (or their preferred conduit if
                 *                                  indicated by the order) to transfer any
                 *                                  relevant tokens on their behalf and that
                 *                                  contracts must implement
                 *                                  `onERC1155Received` to enable receipt of
                 *                                  ERC1155 tokens as consideration. Also
                 *                                  note that all offer and consideration
                 *                                  components must have no remainder after
                 *                                  multiplication of the respective amount
                 *                                  with the supplied fraction for an
                 *                                  order's partial fill amount to be
                 *                                  considered valid.
                 * @param criteriaResolvers         An array where each element contains a
                 *                                  reference to a specific offer or
                 *                                  consideration, a token identifier, and a
                 *                                  proof that the supplied token identifier
                 *                                  is contained in the merkle root held by
                 *                                  the item in question's criteria element.
                 *                                  Note that an empty criteria indicates
                 *                                  that any (transferable) token
                 *                                  identifier on the token in question is
                 *                                  valid and that no associated proof needs
                 *                                  to be supplied.
                 * @param offerFulfillments         An array of FulfillmentComponent arrays
                 *                                  indicating which offer items to attempt
                 *                                  to aggregate when preparing executions.
                 * @param considerationFulfillments An array of FulfillmentComponent arrays
                 *                                  indicating which consideration items to
                 *                                  attempt to aggregate when preparing
                 *                                  executions.
                 * @param fulfillerConduitKey       A bytes32 value indicating what conduit,
                 *                                  if any, to source the fulfiller's token
                 *                                  approvals from. The zero hash signifies
                 *                                  that no conduit should be used, with
                 *                                  direct approvals set on this contract.
                 * @param recipient                 The intended recipient for all received
                 *                                  items, with `address(0)` indicating that
                 *                                  the caller should receive the items.
                 * @param maximumFulfilled          The maximum number of orders to fulfill.
                 *
                 * @return availableOrders An array of booleans indicating if each order
                 *                         with an index corresponding to the index of the
                 *                         returned boolean was fulfillable or not.
                 * @return executions      An array of elements indicating the sequence of
                 *                         transfers performed as part of matching the given
                 *                         orders. Note that unspent offer item amounts or
                 *                         native tokens will not be reflected as part of
                 *                         this array.
                 */
                function fulfillAvailableAdvancedOrders(
                    AdvancedOrder[] calldata advancedOrders,
                    CriteriaResolver[] calldata criteriaResolvers,
                    FulfillmentComponent[][] calldata offerFulfillments,
                    FulfillmentComponent[][] calldata considerationFulfillments,
                    bytes32 fulfillerConduitKey,
                    address recipient,
                    uint256 maximumFulfilled
                )
                    external
                    payable
                    returns (bool[] memory availableOrders, Execution[] memory executions);
                /**
                 * @notice Match an arbitrary number of orders, each with an arbitrary
                 *         number of items for offer and consideration along with a set of
                 *         fulfillments allocating offer components to consideration
                 *         components. Note that this function does not support
                 *         criteria-based or partial filling of orders (though filling the
                 *         remainder of a partially-filled order is supported). Any unspent
                 *         offer item amounts or native tokens will be transferred to the
                 *         caller.
                 *
                 * @param orders       The orders to match. Note that both the offerer and
                 *                     fulfiller on each order must first approve this
                 *                     contract (or their conduit if indicated by the order)
                 *                     to transfer any relevant tokens on their behalf and
                 *                     each consideration recipient must implement
                 *                     `onERC1155Received` to enable ERC1155 token receipt.
                 * @param fulfillments An array of elements allocating offer components to
                 *                     consideration components. Note that each
                 *                     consideration component must be fully met for the
                 *                     match operation to be valid.
                 *
                 * @return executions An array of elements indicating the sequence of
                 *                    transfers performed as part of matching the given
                 *                    orders. Note that unspent offer item amounts or
                 *                    native tokens will not be reflected as part of this
                 *                    array.
                 */
                function matchOrders(
                    Order[] calldata orders,
                    Fulfillment[] calldata fulfillments
                ) external payable returns (Execution[] memory executions);
                /**
                 * @notice Match an arbitrary number of full or partial orders, each with an
                 *         arbitrary number of items for offer and consideration, supplying
                 *         criteria resolvers containing specific token identifiers and
                 *         associated proofs as well as fulfillments allocating offer
                 *         components to consideration components. Any unspent offer item
                 *         amounts will be transferred to the designated recipient (with the
                 *         null address signifying to use the caller) and any unspent native
                 *         tokens will be returned to the caller.
                 *
                 * @param orders            The advanced orders to match. Note that both the
                 *                          offerer and fulfiller on each order must first
                 *                          approve this contract (or a preferred conduit if
                 *                          indicated by the order) to transfer any relevant
                 *                          tokens on their behalf and each consideration
                 *                          recipient must implement `onERC1155Received` in
                 *                          order to receive ERC1155 tokens. Also note that
                 *                          the offer and consideration components for each
                 *                          order must have no remainder after multiplying
                 *                          the respective amount with the supplied fraction
                 *                          in order for the group of partial fills to be
                 *                          considered valid.
                 * @param criteriaResolvers An array where each element contains a reference
                 *                          to a specific order as well as that order's
                 *                          offer or consideration, a token identifier, and
                 *                          a proof that the supplied token identifier is
                 *                          contained in the order's merkle root. Note that
                 *                          an empty root indicates that any (transferable)
                 *                          token identifier is valid and that no associated
                 *                          proof needs to be supplied.
                 * @param fulfillments      An array of elements allocating offer components
                 *                          to consideration components. Note that each
                 *                          consideration component must be fully met in
                 *                          order for the match operation to be valid.
                 * @param recipient         The intended recipient for all unspent offer
                 *                          item amounts, or the caller if the null address
                 *                          is supplied.
                 *
                 * @return executions An array of elements indicating the sequence of
                 *                    transfers performed as part of matching the given
                 *                    orders. Note that unspent offer item amounts or native
                 *                    tokens will not be reflected as part of this array.
                 */
                function matchAdvancedOrders(
                    AdvancedOrder[] calldata orders,
                    CriteriaResolver[] calldata criteriaResolvers,
                    Fulfillment[] calldata fulfillments,
                    address recipient
                ) external payable returns (Execution[] memory executions);
                /**
                 * @notice Cancel an arbitrary number of orders. Note that only the offerer
                 *         or the zone of a given order may cancel it. Callers should ensure
                 *         that the intended order was cancelled by calling `getOrderStatus`
                 *         and confirming that `isCancelled` returns `true`.
                 *
                 * @param orders The orders to cancel.
                 *
                 * @return cancelled A boolean indicating whether the supplied orders have
                 *                   been successfully cancelled.
                 */
                function cancel(
                    OrderComponents[] calldata orders
                ) external returns (bool cancelled);
                /**
                 * @notice Validate an arbitrary number of orders, thereby registering their
                 *         signatures as valid and allowing the fulfiller to skip signature
                 *         verification on fulfillment. Note that validated orders may still
                 *         be unfulfillable due to invalid item amounts or other factors;
                 *         callers should determine whether validated orders are fulfillable
                 *         by simulating the fulfillment call prior to execution. Also note
                 *         that anyone can validate a signed order, but only the offerer can
                 *         validate an order without supplying a signature.
                 *
                 * @param orders The orders to validate.
                 *
                 * @return validated A boolean indicating whether the supplied orders have
                 *                   been successfully validated.
                 */
                function validate(
                    Order[] calldata orders
                ) external returns (bool validated);
                /**
                 * @notice Cancel all orders from a given offerer with a given zone in bulk
                 *         by incrementing a counter. Note that only the offerer may
                 *         increment the counter.
                 *
                 * @return newCounter The new counter.
                 */
                function incrementCounter() external returns (uint256 newCounter);
                /**
                 * @notice Fulfill an order offering an ERC721 token by supplying Ether (or
                 *         the native token for the given chain) as consideration for the
                 *         order. An arbitrary number of "additional recipients" may also be
                 *         supplied which will each receive native tokens from the fulfiller
                 *         as consideration. Note that this function costs less gas than
                 *         `fulfillBasicOrder` due to the zero bytes in the function
                 *         selector (0x00000000) which also results in earlier function
                 *         dispatch.
                 *
                 * @param parameters Additional information on the fulfilled order. Note
                 *                   that the offerer must first approve this contract (or
                 *                   their preferred conduit if indicated by the order) for
                 *                   their offered ERC721 token to be transferred.
                 *
                 * @return fulfilled A boolean indicating whether the order has been
                 *                   successfully fulfilled.
                 */
                function fulfillBasicOrder_efficient_6GL6yc(
                    BasicOrderParameters calldata parameters
                ) external payable returns (bool fulfilled);
                /**
                 * @notice Retrieve the order hash for a given order.
                 *
                 * @param order The components of the order.
                 *
                 * @return orderHash The order hash.
                 */
                function getOrderHash(
                    OrderComponents calldata order
                ) external view returns (bytes32 orderHash);
                /**
                 * @notice Retrieve the status of a given order by hash, including whether
                 *         the order has been cancelled or validated and the fraction of the
                 *         order that has been filled.
                 *
                 * @param orderHash The order hash in question.
                 *
                 * @return isValidated A boolean indicating whether the order in question
                 *                     has been validated (i.e. previously approved or
                 *                     partially filled).
                 * @return isCancelled A boolean indicating whether the order in question
                 *                     has been cancelled.
                 * @return totalFilled The total portion of the order that has been filled
                 *                     (i.e. the "numerator").
                 * @return totalSize   The total size of the order that is either filled or
                 *                     unfilled (i.e. the "denominator").
                 */
                function getOrderStatus(
                    bytes32 orderHash
                )
                    external
                    view
                    returns (
                        bool isValidated,
                        bool isCancelled,
                        uint256 totalFilled,
                        uint256 totalSize
                    );
                /**
                 * @notice Retrieve the current counter for a given offerer.
                 *
                 * @param offerer The offerer in question.
                 *
                 * @return counter The current counter.
                 */
                function getCounter(
                    address offerer
                ) external view returns (uint256 counter);
                /**
                 * @notice Retrieve configuration information for this contract.
                 *
                 * @return version           The contract version.
                 * @return domainSeparator   The domain separator for this contract.
                 * @return conduitController The conduit Controller set for this contract.
                 */
                function information()
                    external
                    view
                    returns (
                        string memory version,
                        bytes32 domainSeparator,
                        address conduitController
                    );
                function getContractOffererNonce(
                    address contractOfferer
                ) external view returns (uint256 nonce);
                /**
                 * @notice Retrieve the name of this contract.
                 *
                 * @return contractName The name of this contract.
                 */
                function name() external view returns (string memory contractName);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import {
                AdvancedOrder,
                CriteriaResolver,
                Execution,
                Fulfillment,
                Order,
                OrderComponents
            } from "../../lib/ConsiderationStructs.sol";
            import { SeaportInterface } from "../../interfaces/SeaportInterface.sol";
            /**
             * @title  PausableZoneController
             * @author cupOJoseph, BCLeFevre, stuckinaboot
             * @notice PausableZoneController enables deploying, pausing and executing
             *         orders on PausableZones. This deployer is designed to be owned
             *         by a gnosis safe, DAO, or trusted party.
             */
            interface PausableZoneControllerInterface {
                /**
                 * @notice Deploy a PausableZone to a precomputed address.
                 *
                 * @param salt The salt to be used to derive the zone address
                 *
                 * @return derivedAddress The derived address for the zone.
                 */
                function createZone(bytes32 salt) external returns (address derivedAddress);
                /**
                 * @notice Pause orders on a given zone.
                 *
                 * @param zone The address of the zone to be paused.
                 *
                 * @return success A boolean indicating the zone has been paused.
                 */
                function pause(address zone) external returns (bool success);
                /**
                 * @notice Cancel Seaport offers on a given zone.
                 *
                 * @param pausableZoneAddress The zone that manages the orders to be
                 *                            cancelled.
                 * @param seaportAddress      The Seaport address.
                 * @param orders              The orders to cancel.
                 */
                function cancelOrders(
                    address pausableZoneAddress,
                    SeaportInterface seaportAddress,
                    OrderComponents[] calldata orders
                ) external;
                /**
                 * @notice Execute an arbitrary number of matched orders on a given zone.
                 *
                 * @param pausableZoneAddress The zone that manages the orders to be
                 *                            cancelled.
                 * @param seaportAddress      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(
                    address pausableZoneAddress,
                    SeaportInterface seaportAddress,
                    Order[] calldata orders,
                    Fulfillment[] calldata fulfillments
                ) external payable returns (Execution[] memory executions);
                /**
                 * @notice Execute an arbitrary number of matched advanced orders on a
                 *         given zone.
                 *
                 * @param pausableZoneAddress The zone that manages the orders to be
                 *                            cancelled.
                 * @param seaportAddress      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(
                    address pausableZoneAddress,
                    SeaportInterface seaportAddress,
                    AdvancedOrder[] calldata orders,
                    CriteriaResolver[] calldata criteriaResolvers,
                    Fulfillment[] calldata fulfillments
                ) external payable returns (Execution[] memory executions);
                /**
                 * @notice Initiate Zone ownership transfer by assigning a new potential
                 *         owner this contract. Once set, the new potential owner
                 *         may call `acceptOwnership` to claim ownership.
                 *         Only the owner in question may call this function.
                 *
                 * @param newPotentialOwner The address for which to initiate ownership
                 *                          transfer to.
                 */
                function transferOwnership(address newPotentialOwner) external;
                /**
                 * @notice Clear the currently set potential owner, if any.
                 *         Only the owner of this contract may call this function.
                 */
                function cancelOwnershipTransfer() external;
                /**
                 * @notice Accept ownership of this contract. Only the account that the
                 *         current owner has set as the new potential owner may call this
                 *         function.
                 */
                function acceptOwnership() external;
                /**
                 * @notice Assign the given address with the ability to pause the zone.
                 *
                 * @param pauserToAssign The address to assign the pauser role.
                 */
                function assignPauser(address pauserToAssign) external;
                /**
                 * @notice Assign the given address with the ability to operate the
                 *         given zone.
                 *
                 * @param pausableZoneAddress The zone address to assign operator role.
                 * @param operatorToAssign    The address to assign as operator.
                 */
                function assignOperator(
                    address pausableZoneAddress,
                    address operatorToAssign
                ) external;
                /**
                 * @notice An external view function that returns the owner.
                 *
                 * @return The address of the owner.
                 */
                function owner() external view returns (address);
                /**
                 * @notice An external view function that return the potential owner.
                 *
                 * @return The address of the potential owner.
                 */
                function potentialOwner() external view returns (address);
                /**
                 * @notice An external view function that returns the pauser.
                 *
                 * @return The address of the pauser.
                 */
                function pauser() external view returns (address);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import { PausableZone } from "./PausableZone.sol";
            import {
                PausableZoneControllerInterface
            } from "./interfaces/PausableZoneControllerInterface.sol";
            import {
                PausableZoneEventsAndErrors
            } from "./interfaces/PausableZoneEventsAndErrors.sol";
            import {
                AdvancedOrder,
                CriteriaResolver,
                Execution,
                Fulfillment,
                Order,
                OrderComponents
            } from "../lib/ConsiderationStructs.sol";
            import { SeaportInterface } from "../interfaces/SeaportInterface.sol";
            /**
             * @title  PausableZoneController
             * @author cupOJoseph, BCLeFevre, stuckinaboot, stephankmin
             * @notice PausableZoneController enables deploying, pausing and executing
             *         orders on PausableZones. This deployer is designed to be owned
             *         by a gnosis safe, DAO, or trusted party.
             */
            contract PausableZoneController is
                PausableZoneControllerInterface,
                PausableZoneEventsAndErrors
            {
                // Set the owner that can deploy, pause and execute orders on PausableZones.
                address internal _owner;
                // Set the address of the new potential owner of the zone.
                address private _potentialOwner;
                // Set the address with the ability to pause the zone.
                address internal _pauser;
                // Set the immutable zone creation code hash.
                bytes32 public immutable zoneCreationCode;
                /**
                 * @dev Throws if called by any account other than the owner or pauser.
                 */
                modifier isPauser() {
                    if (msg.sender != _pauser && msg.sender != _owner) {
                        revert InvalidPauser();
                    }
                    _;
                }
                /**
                 * @notice Set the owner of the controller and store
                 *         the zone creation code.
                 *
                 * @param ownerAddress The deployer to be set as the owner.
                 */
                constructor(address ownerAddress) {
                    // Set the owner address as the owner.
                    _owner = ownerAddress;
                    // Hash and store the zone creation code.
                    zoneCreationCode = keccak256(type(PausableZone).creationCode);
                }
                /**
                 * @notice Deploy a PausableZone to a precomputed address.
                 *
                 * @param salt The salt to be used to derive the zone address
                 *
                 * @return derivedAddress The derived address for the zone.
                 */
                function createZone(
                    bytes32 salt
                ) external override returns (address derivedAddress) {
                    // Ensure the caller is the owner.
                    if (msg.sender != _owner) {
                        revert CallerIsNotOwner();
                    }
                    // Derive the PausableZone address.
                    // This expression demonstrates address computation but is not required.
                    derivedAddress = address(
                        uint160(
                            uint256(
                                keccak256(
                                    abi.encodePacked(
                                        bytes1(0xff),
                                        address(this),
                                        salt,
                                        zoneCreationCode
                                    )
                                )
                            )
                        )
                    );
                    // Revert if a zone is currently deployed to the derived address.
                    if (derivedAddress.code.length != 0) {
                        revert ZoneAlreadyExists(derivedAddress);
                    }
                    // Deploy the zone using the supplied salt.
                    new PausableZone{ salt: salt }();
                    // Emit an event signifying that the zone was created.
                    emit ZoneCreated(derivedAddress, salt);
                }
                /**
                 * @notice Pause orders on a given zone.
                 *
                 * @param zone The address of the zone to be paused.
                 *
                 * @return success A boolean indicating the zone has been paused.
                 */
                function pause(
                    address zone
                ) external override isPauser returns (bool success) {
                    // Call pause on the given zone.
                    PausableZone(zone).pause(msg.sender);
                    // Return a boolean indicating the pause was successful.
                    success = true;
                }
                /**
                 * @notice Cancel Seaport orders on a given zone.
                 *
                 * @param pausableZoneAddress The zone that manages the
                 * orders to be cancelled.
                 * @param seaportAddress      The Seaport address.
                 * @param orders              The orders to cancel.
                 */
                function cancelOrders(
                    address pausableZoneAddress,
                    SeaportInterface seaportAddress,
                    OrderComponents[] calldata orders
                ) external override {
                    // Ensure the caller is the owner.
                    if (msg.sender != _owner) {
                        revert CallerIsNotOwner();
                    }
                    // Create a zone object from the zone address.
                    PausableZone zone = PausableZone(pausableZoneAddress);
                    // Call cancelOrders on the given zone.
                    zone.cancelOrders(seaportAddress, orders);
                }
                /**
                 * @notice Execute an arbitrary number of matched orders on a given zone.
                 *
                 * @param pausableZoneAddress The zone that manages the orders
                 * to be cancelled.
                 * @param seaportAddress      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(
                    address pausableZoneAddress,
                    SeaportInterface seaportAddress,
                    Order[] calldata orders,
                    Fulfillment[] calldata fulfillments
                ) external payable override returns (Execution[] memory executions) {
                    // Ensure the caller is the owner.
                    if (msg.sender != _owner) {
                        revert CallerIsNotOwner();
                    }
                    // Create a zone object from the zone address.
                    PausableZone zone = PausableZone(pausableZoneAddress);
                    // Call executeMatchOrders on the given zone and return the sequence
                    // of transfers performed as part of matching the given orders.
                    executions = zone.executeMatchOrders{ value: msg.value }(
                        seaportAddress,
                        orders,
                        fulfillments
                    );
                }
                /**
                 * @notice Execute an arbitrary number of matched advanced orders on a given
                 *         zone.
                 *
                 * @param pausableZoneAddress The zone that manages the orders to be
                 *                            cancelled.
                 * @param seaportAddress      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(
                    address pausableZoneAddress,
                    SeaportInterface seaportAddress,
                    AdvancedOrder[] calldata orders,
                    CriteriaResolver[] calldata criteriaResolvers,
                    Fulfillment[] calldata fulfillments
                ) external payable override returns (Execution[] memory executions) {
                    // Ensure the caller is the owner.
                    if (msg.sender != _owner) {
                        revert CallerIsNotOwner();
                    }
                    // Create a zone object from the zone address.
                    PausableZone zone = PausableZone(pausableZoneAddress);
                    // Call executeMatchOrders on the given zone and return the sequence
                    // of transfers performed as part of matching the given orders.
                    executions = zone.executeMatchAdvancedOrders{ value: msg.value }(
                        seaportAddress,
                        orders,
                        criteriaResolvers,
                        fulfillments
                    );
                }
                /**
                 * @notice Initiate Zone ownership transfer by assigning a new potential
                 *         owner this contract. Once set, the new potential owner
                 *         may call `acceptOwnership` to claim ownership.
                 *         Only the owner in question may call this function.
                 *
                 * @param newPotentialOwner The address for which to initiate ownership
                 *                          transfer to.
                 */
                function transferOwnership(address newPotentialOwner) external override {
                    // Ensure the caller is the owner.
                    if (msg.sender != _owner) {
                        revert CallerIsNotOwner();
                    }
                    // Ensure the new potential owner is not an invalid address.
                    if (newPotentialOwner == address(0)) {
                        revert OwnerCanNotBeSetAsZero();
                    }
                    // Emit an event indicating that the potential owner has been updated.
                    emit PotentialOwnerUpdated(newPotentialOwner);
                    // Set the new potential owner as the potential owner.
                    _potentialOwner = newPotentialOwner;
                }
                /**
                 * @notice Clear the currently set potential owner, if any.
                 *         Only the owner of this contract may call this function.
                 */
                function cancelOwnershipTransfer() external override {
                    // Ensure the caller is the current owner.
                    if (msg.sender != _owner) {
                        revert CallerIsNotOwner();
                    }
                    // Emit an event indicating that the potential owner has been cleared.
                    emit PotentialOwnerUpdated(address(0));
                    // Clear the current new potential owner.
                    delete _potentialOwner;
                }
                /**
                 * @notice Accept ownership of this contract. Only the account that the
                 *         current owner has set as the new potential owner may call this
                 *         function.
                 */
                function acceptOwnership() external override {
                    // Ensure the caller is the potential owner.
                    if (msg.sender != _potentialOwner) {
                        revert CallerIsNotPotentialOwner();
                    }
                    // Emit an event indicating that the potential owner has been cleared.
                    emit PotentialOwnerUpdated(address(0));
                    // Clear the current new potential owner
                    delete _potentialOwner;
                    // Emit an event indicating ownership has been transferred.
                    emit OwnershipTransferred(_owner, msg.sender);
                    // Set the caller as the owner of this contract.
                    _owner = msg.sender;
                }
                /**
                 * @notice Assign the given address with the ability to pause the zone.
                 *
                 * @param pauserToAssign The address to assign the pauser role.
                 */
                function assignPauser(address pauserToAssign) external override {
                    // Ensure the caller is the owner.
                    if (msg.sender != _owner) {
                        revert CallerIsNotOwner();
                    }
                    // Ensure the pauser to assign is not an invalid address.
                    if (pauserToAssign == address(0)) {
                        revert PauserCanNotBeSetAsZero();
                    }
                    // Set the given account as the pauser.
                    _pauser = pauserToAssign;
                    // Emit an event indicating the pauser has been assigned.
                    emit PauserUpdated(pauserToAssign);
                }
                /**
                 * @notice Assign the given address with the ability to operate the
                 *         given zone.
                 *
                 * @param pausableZoneAddress The zone address to assign operator role.
                 * @param operatorToAssign    The address to assign as operator.
                 */
                function assignOperator(
                    address pausableZoneAddress,
                    address operatorToAssign
                ) external override {
                    // Ensure the caller is the owner.
                    if (msg.sender != _owner) {
                        revert CallerIsNotOwner();
                    }
                    // Create a zone object from the zone address.
                    PausableZone zone = PausableZone(pausableZoneAddress);
                    // Call assignOperator on the zone by passing in the given
                    // operator address.
                    zone.assignOperator(operatorToAssign);
                }
                /**
                 * @notice An external view function that returns the owner.
                 *
                 * @return The address of the owner.
                 */
                function owner() external view override returns (address) {
                    return _owner;
                }
                /**
                 * @notice An external view function that return the potential owner.
                 *
                 * @return The address of the potential owner.
                 */
                function potentialOwner() external view override returns (address) {
                    return _potentialOwner;
                }
                /**
                 * @notice An external view function that returns the pauser.
                 *
                 * @return The address of the pauser.
                 */
                function pauser() external view override returns (address) {
                    return _pauser;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import { ZoneInterface } from "../interfaces/ZoneInterface.sol";
            import {
                PausableZoneEventsAndErrors
            } from "./interfaces/PausableZoneEventsAndErrors.sol";
            import { SeaportInterface } from "../interfaces/SeaportInterface.sol";
            import {
                AdvancedOrder,
                CriteriaResolver,
                Execution,
                Fulfillment,
                Order,
                OrderComponents,
                Schema,
                ZoneParameters
            } 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. Note that this zone
             *         cannot execute orders that return native tokens to the fulfiller.
             */
            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 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 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(address payee) external override isController {
                    // Emit an event signifying that the zone is paused.
                    emit Paused();
                    // Destroy the zone, sending any native tokens to the transaction
                    // submitter.
                    selfdestruct(payable(payee));
                }
                /**
                 * @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.
                    if (operatorToAssign == address(0)) {
                        revert PauserCanNotBeSetAsZero();
                    }
                    // Set the given address as the new operator.
                    operator = operatorToAssign;
                    // Emit an event indicating the operator has been updated.
                    emit OperatorUpdated(operatorToAssign);
                }
                /**
                 * @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. Note that this call will revert if
                 *         excess native tokens are returned by Seaport.
                 *
                 * @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. Note that this call
                 *         will revert if excess native tokens are returned by Seaport.
                 *
                 * @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,
                        msg.sender
                    );
                }
                /**
                 * @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.
                 *
                 * @custom:param zoneParameters A struct that provides context about the
                 *                              order fulfillment and any supplied
                 *                              extraData, as well as all order hashes
                 *                              fulfilled in a call to a match or
                 *                              fulfillAvailable method.
                 *
                 * @return validOrderMagicValue A magic value indicating if the order is
                 *                              currently valid.
                 */
                function validateOrder(
                    /**
                     * @custom:name zoneParameters
                     */
                    ZoneParameters calldata
                ) external pure override returns (bytes4 validOrderMagicValue) {
                    // Return the selector of isValidOrder as the magic value.
                    validOrderMagicValue = ZoneInterface.validateOrder.selector;
                }
                /**
                 * @dev Returns the metadata for this zone.
                 */
                function getSeaportMetadata()
                    external
                    pure
                    override
                    returns (
                        string memory name,
                        Schema[] memory schemas // map to Seaport Improvement Proposal IDs
                    )
                {
                    schemas = new Schema[](1);
                    schemas[0].id = 3003;
                    schemas[0].metadata = new bytes(0);
                    return ("PausableZone", schemas);
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            /**
             * @notice PausableZoneEventsAndErrors contains errors and events
             *         related to zone interaction.
             */
            interface PausableZoneEventsAndErrors {
                /**
                 * @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();
                /**
                 * @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);
                /**
                 * @dev Revert with an error when the caller does not have the _owner role
                 *
                 */
                error CallerIsNotOwner();
                /**
                 * @dev Revert with an error when the caller does not have the operator role
                 *
                 */
                error CallerIsNotOperator();
                /**
                 * @dev Revert with an error when attempting to set the new potential owner
                 *      as the 0 address.
                 *
                 */
                error OwnerCanNotBeSetAsZero();
                /**
                 * @dev Revert with an error when attempting to set the new potential pauser
                 *      as the 0 address.
                 *
                 */
                error PauserCanNotBeSetAsZero();
                /**
                 * @dev Revert with an error when the caller does not have
                 *      the potentialOwner role.
                 */
                error CallerIsNotPotentialOwner();
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import { ZoneParameters, Schema } from "../lib/ConsiderationStructs.sol";
            /**
             * @title  ZoneInterface
             * @notice Contains functions exposed by a zone.
             */
            interface ZoneInterface {
                /**
                 * @dev Validates an order.
                 *
                 * @param zoneParameters The context about the order fulfillment and any
                 *                       supplied extraData.
                 *
                 * @return validOrderMagicValue The magic value that indicates a valid
                 *                              order.
                 */
                function validateOrder(
                    ZoneParameters calldata zoneParameters
                ) external returns (bytes4 validOrderMagicValue);
                /**
                 * @dev Returns the metadata for this zone.
                 *
                 * @return name The name of the zone.
                 * @return schemas The schemas that the zone implements.
                 */
                function getSeaportMetadata()
                    external
                    view
                    returns (
                        string memory name,
                        Schema[] memory schemas // map to Seaport Improvement Proposal IDs
                    );
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import { ZoneInterface } from "../interfaces/ZoneInterface.sol";
            import { Schema, ZoneParameters } from "../lib/ConsiderationStructs.sol";
            contract TestZone is ZoneInterface {
                function validateOrder(
                    ZoneParameters calldata zoneParameters
                ) external pure override returns (bytes4 validOrderMagicValue) {
                    if (zoneParameters.extraData.length == 0) {
                        if (zoneParameters.zoneHash == bytes32(uint256(1))) {
                            revert("Revert on zone hash 1");
                        } else if (zoneParameters.zoneHash == bytes32(uint256(2))) {
                            assembly {
                                revert(0, 0)
                            }
                        }
                    } else if (zoneParameters.extraData.length == 4) {
                        revert("Revert on extraData length 4");
                    } else if (zoneParameters.extraData.length == 5) {
                        assembly {
                            revert(0, 0)
                        }
                    } else if (
                        zoneParameters.extraData.length > 32 &&
                        zoneParameters.extraData.length % 32 == 0
                    ) {
                        bytes32[] memory expectedOrderHashes = abi.decode(
                            zoneParameters.extraData,
                            (bytes32[])
                        );
                        uint256 expectedLength = expectedOrderHashes.length;
                        if (expectedLength != zoneParameters.orderHashes.length) {
                            revert("Revert on unexpected order hashes length");
                        }
                        for (uint256 i = 0; i < expectedLength; ++i) {
                            if (expectedOrderHashes[i] != zoneParameters.orderHashes[i]) {
                                revert("Revert on unexpected order hash");
                            }
                        }
                    }
                    validOrderMagicValue = zoneParameters.zoneHash != bytes32(uint256(3))
                        ? ZoneInterface.validateOrder.selector
                        : bytes4(0xffffffff);
                }
                /**
                 * @dev Returns the metadata for this zone.
                 */
                function getSeaportMetadata()
                    external
                    pure
                    override
                    returns (
                        string memory name,
                        Schema[] memory schemas // map to Seaport Improvement Proposal IDs
                    )
                {
                    schemas = new Schema[](1);
                    schemas[0].id = 3003;
                    schemas[0].metadata = new bytes(0);
                    return ("TestZone", schemas);
                }
            }
            //SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import {
                ERC20Interface,
                ERC721Interface,
                ERC1155Interface
            } from "../interfaces/AbridgedTokenInterfaces.sol";
            import {
                ReceivedItem,
                Schema,
                SpentItem,
                ZoneParameters
            } from "../lib/ConsiderationStructs.sol";
            import { ItemType } from "../lib/ConsiderationEnums.sol";
            import {
                ContractOffererInterface
            } from "../interfaces/ContractOffererInterface.sol";
            import { ZoneInterface } from "../interfaces/ZoneInterface.sol";
            contract TestTransferValidationZoneOfferer is
                ContractOffererInterface,
                ZoneInterface
            {
                error InvalidBalance();
                error InvalidOwner();
                constructor() {}
                /**
                 * @dev Validates that the parties have received the correct items.
                 *
                 * @param zoneParameters The zone parameters, including the SpentItem and
                 *                       ReceivedItem arrays.
                 *
                 * @return validOrderMagicValue The magic value to indicate things are OK.
                 */
                function validateOrder(
                    ZoneParameters calldata zoneParameters
                ) external view override returns (bytes4 validOrderMagicValue) {
                    // Validate the order.
                    // Currently assumes that the balances of all tokens of addresses are
                    // zero at the start of the transaction.
                    // Check if all consideration items have been received.
                    _assertValidReceivedItems(zoneParameters.consideration);
                    // Check if all offer items have been spent.
                    _assertValidSpentItems(zoneParameters.fulfiller, zoneParameters.offer);
                    // Return the selector of validateOrder as the magic value.
                    validOrderMagicValue = ZoneInterface.validateOrder.selector;
                }
                /**
                 * @dev Generates an order with the specified minimum and maximum spent
                 *      items.
                 */
                function generateOrder(
                    address,
                    SpentItem[] calldata a,
                    SpentItem[] calldata b,
                    bytes calldata c
                )
                    external
                    virtual
                    override
                    returns (SpentItem[] memory offer, ReceivedItem[] memory consideration)
                {
                    return previewOrder(address(this), address(this), a, b, c);
                }
                /**
                 * @dev View function to preview an order generated in response to a minimum
                 *      set of received items, maximum set of spent items, and context
                 *      (supplied as extraData).
                 */
                function previewOrder(
                    address,
                    address,
                    SpentItem[] calldata a,
                    SpentItem[] calldata b,
                    bytes calldata
                )
                    public
                    view
                    override
                    returns (SpentItem[] memory offer, ReceivedItem[] memory consideration)
                {
                    return (a, _convertSpentToReceived(b));
                }
                /**
                 * @dev Ratifies that the parties have received the correct items.
                 *
                 * @param minimumReceived The minimum items that the caller was willing to
                 *                        receive.
                 * @param maximumSpent    The maximum items that the caller was willing to
                 *                        spend.
                 * @param context         The context of the order.
                 * @ param orderHashes     The order hashes, unused here.
                 * @ param contractNonce   The contract nonce, unused here.
                 *
                 * @return ratifyOrderMagicValue The magic value to indicate things are OK.
                 */
                function ratifyOrder(
                    SpentItem[] calldata minimumReceived /* offer */,
                    ReceivedItem[] calldata maximumSpent /* consideration */,
                    bytes calldata context /* context */,
                    bytes32[] calldata /* orderHashes */,
                    uint256 /* contractNonce */
                ) external view override returns (bytes4 /* ratifyOrderMagicValue */) {
                    // Ratify the order.
                    // Ensure that the offerer or recipient has received all consideration
                    // items.
                    _assertValidReceivedItems(maximumSpent);
                    // Get the fulfiller address from the context.
                    address fulfiller = address(bytes20(context[0:20]));
                    // Ensure that the fulfiller has received all offer items.
                    _assertValidSpentItems(fulfiller, minimumReceived);
                    return this.ratifyOrder.selector;
                }
                function getSeaportMetadata()
                    external
                    pure
                    override(ContractOffererInterface, ZoneInterface)
                    returns (string memory name, Schema[] memory schemas)
                {
                    // Return the metadata.
                    name = "TestTransferValidationZoneOfferer";
                    schemas = new Schema[](1);
                    schemas[0].id = 1337;
                    schemas[0].metadata = new bytes(0);
                }
                function _convertSpentToReceived(
                    SpentItem[] calldata spentItems
                ) internal view returns (ReceivedItem[] memory) {
                    ReceivedItem[] memory receivedItems = new ReceivedItem[](
                        spentItems.length
                    );
                    for (uint256 i = 0; i < spentItems.length; ++i) {
                        receivedItems[i] = _convertSpentToReceived(spentItems[i]);
                    }
                    return receivedItems;
                }
                function _convertSpentToReceived(
                    SpentItem calldata spentItem
                ) internal view returns (ReceivedItem memory) {
                    return
                        ReceivedItem({
                            itemType: spentItem.itemType,
                            token: spentItem.token,
                            identifier: spentItem.identifier,
                            amount: spentItem.amount,
                            recipient: payable(address(this))
                        });
                }
                function _assertValidReceivedItems(
                    ReceivedItem[] calldata receivedItems
                ) internal view {
                    address recipient;
                    ItemType itemType;
                    ReceivedItem memory receivedItem;
                    // Check if all consideration items have been received.
                    for (uint256 i = 0; i < receivedItems.length; i++) {
                        // Check if the consideration item has been received.
                        receivedItem = receivedItems[i];
                        // Get the recipient of the consideration item.
                        recipient = receivedItem.recipient;
                        // Get item type.
                        itemType = receivedItem.itemType;
                        // Check balance/ownerOf depending on item type.
                        if (itemType == ItemType.NATIVE) {
                            // NATIVE Token
                            _assertNativeTokenTransfer(receivedItem.amount, recipient);
                        } else if (itemType == ItemType.ERC20) {
                            // ERC20 Token
                            _assertERC20Transfer(
                                receivedItem.amount,
                                receivedItem.token,
                                recipient
                            );
                        } else if (itemType == ItemType.ERC721) {
                            // ERC721 Token
                            _assertERC721Transfer(
                                receivedItem.identifier,
                                receivedItem.token,
                                recipient
                            );
                        } else if (itemType == ItemType.ERC1155) {
                            // ERC1155 Token
                            _assertERC1155Transfer(
                                receivedItem.amount,
                                receivedItem.identifier,
                                receivedItem.token,
                                recipient
                            );
                        }
                    }
                }
                function _assertValidSpentItems(
                    address fulfiller,
                    SpentItem[] calldata spentItems
                ) internal view {
                    SpentItem memory spentItem;
                    ItemType itemType;
                    // Check if all offer items have been spent.
                    for (uint256 i = 0; i < spentItems.length; i++) {
                        // Check if the offer item has been spent.
                        spentItem = spentItems[i];
                        // Get item type.
                        itemType = spentItem.itemType;
                        // Check balance/ownerOf depending on item type.
                        if (itemType == ItemType.NATIVE) {
                            // NATIVE Token
                            _assertNativeTokenTransfer(spentItem.amount, fulfiller);
                        } else if (itemType == ItemType.ERC20) {
                            // ERC20 Token
                            _assertERC20Transfer(
                                spentItem.amount,
                                spentItem.token,
                                fulfiller
                            );
                        } else if (itemType == ItemType.ERC721) {
                            // ERC721 Token
                            _assertERC721Transfer(
                                spentItem.identifier,
                                spentItem.token,
                                fulfiller
                            );
                        } else if (itemType == ItemType.ERC1155) {
                            // ERC1155 Token
                            _assertERC1155Transfer(
                                spentItem.amount,
                                spentItem.identifier,
                                spentItem.token,
                                fulfiller
                            );
                        }
                    }
                }
                function _assertNativeTokenTransfer(
                    uint256 amount,
                    address recipient
                ) internal view {
                    if (amount > address(recipient).balance) {
                        revert InvalidBalance();
                    }
                }
                function _assertERC20Transfer(
                    uint256 amount,
                    address token,
                    address recipient
                ) internal view {
                    if (amount > ERC20Interface(token).balanceOf(recipient)) {
                        revert InvalidBalance();
                    }
                }
                function _assertERC721Transfer(
                    uint256 identifier,
                    address token,
                    address recipient
                ) internal view {
                    if (recipient != ERC721Interface(token).ownerOf(identifier)) {
                        revert InvalidOwner();
                    }
                }
                function _assertERC1155Transfer(
                    uint256 amount,
                    uint256 identifier,
                    address token,
                    address recipient
                ) internal view {
                    if (amount > ERC1155Interface(token).balanceOf(recipient, identifier)) {
                        revert InvalidBalance();
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            /**
             * @title ERC20Interface
             * @notice Contains the minimum interfaces needed to interact with ERC20s.
             */
            interface ERC20Interface {
                /**
                 * @dev Allows an operator to transfer tokens on behalf of an owner.
                 *
                 * @param from  The address of the owner.
                 * @param to    The address of the recipient.
                 * @param value The amount of tokens to transfer.
                 *
                 * @return success True if the transfer was successful.
                 */
                function transferFrom(
                    address from,
                    address to,
                    uint256 value
                ) external returns (bool success);
                /**
                 * @dev Allows an operator to approve a spender to transfer tokens on behalf
                 *      of a user.
                 *
                 * @param spender The address of the spender.
                 * @param value   The amount of tokens to approve.
                 *
                 * @return success True if the approval was successful.
                 */
                function approve(
                    address spender,
                    uint256 value
                ) external returns (bool success);
                /**
                 * @dev Returns the amount of tokens owned by `account`.
                 *
                 * @param account The address of the account to check the balance of.
                 *
                 * @return balance The amount of tokens owned by `account`.
                 */
                function balanceOf(address account) external view returns (uint256);
            }
            /**
             * @title ERC721Interface
             * @notice Contains the minimum interfaces needed to interact with ERC721s.
             */
            interface ERC721Interface {
                /**
                 * @dev Allows an operator to transfer tokens on behalf of an owner.
                 *
                 * @param from    The address of the owner.
                 * @param to      The address of the recipient.
                 * @param tokenId The ID of the token to transfer.
                 */
                function transferFrom(address from, address to, uint256 tokenId) external;
                /**
                 * @dev Allows an owner to approve an operator to transfer all tokens on a
                 *      contract on behalf of the owner.
                 *
                 * @param to       The address of the operator.
                 * @param approved Whether the operator is approved.
                 */
                function setApprovalForAll(address to, bool approved) external;
                /**
                 * @dev Returns the owner of a given token ID.
                 *
                 * @param tokenId The token ID.
                 *
                 * @return owner The owner of the token.
                 */
                function ownerOf(uint256 tokenId) external view returns (address owner);
            }
            /**
             * @title ERC1155Interface
             * @notice Contains the minimum interfaces needed to interact with ERC1155s.
             */
            interface ERC1155Interface {
                /**
                 * @dev Allows an operator to transfer tokens on behalf of an owner.
                 *
                 * @param from   The address of the owner.
                 * @param to     The address of the recipient.
                 * @param id     The ID of the token(s) to transfer.
                 * @param amount The amount of tokens to transfer.
                 * @param data   Additional data.
                 */
                function safeTransferFrom(
                    address from,
                    address to,
                    uint256 id,
                    uint256 amount,
                    bytes calldata data
                ) external;
                /**
                 * @dev Allows an operator to transfer tokens on behalf of an owner.
                 *
                 * @param from    The address of the owner.
                 * @param to      The address of the recipient.
                 * @param ids     The IDs of the token(s) to transfer.
                 * @param amounts The amounts of tokens to transfer.
                 * @param data    Additional data.
                 */
                function safeBatchTransferFrom(
                    address from,
                    address to,
                    uint256[] calldata ids,
                    uint256[] calldata amounts,
                    bytes calldata data
                ) external;
                /**
                 * @dev Allows an owner to approve an operator to transfer all tokens on a
                 *      contract on behalf of the owner.
                 *
                 * @param to       The address of the operator.
                 * @param approved Whether the operator is approved.
                 */
                function setApprovalForAll(address to, bool approved) external;
                /**
                 * @dev Returns the owner of a given token ID.
                 *
                 * @param account The address of the account to check the balance of.
                 * @param id      The token ID.
                 *
                 * @return balance The balance of the token.
                 */
                function balanceOf(
                    address account,
                    uint256 id
                ) external view returns (uint256);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import {
                ReceivedItem,
                Schema,
                SpentItem
            } from "../lib/ConsiderationStructs.sol";
            /**
             * @title ContractOffererInterface
             * @notice Contains the minimum interfaces needed to interact with a contract
             *         offerer.
             */
            interface ContractOffererInterface {
                /**
                 * @dev Generates an order with the specified minimum and maximum spent
                 *      items, and optional context (supplied as extraData).
                 *
                 * @param fulfiller       The address of the fulfiller.
                 * @param minimumReceived The minimum items that the caller is willing to
                 *                        receive.
                 * @param maximumSpent    The maximum items the caller is willing to spend.
                 * @param context         Additional context of the order.
                 *
                 * @return offer         A tuple containing the offer items.
                 * @return consideration A tuple containing the consideration items.
                 */
                function generateOrder(
                    address fulfiller,
                    SpentItem[] calldata minimumReceived,
                    SpentItem[] calldata maximumSpent,
                    bytes calldata context // encoded based on the schemaID
                )
                    external
                    returns (SpentItem[] memory offer, ReceivedItem[] memory consideration);
                /**
                 * @dev Ratifies an order with the specified offer, consideration, and
                 *      optional context (supplied as extraData).
                 *
                 * @param offer         The offer items.
                 * @param consideration The consideration items.
                 * @param context       Additional context of the order.
                 * @param orderHashes   The hashes to ratify.
                 * @param contractNonce The nonce of the contract.
                 *
                 * @return ratifyOrderMagicValue The magic value returned by the contract
                 *                               offerer.
                 */
                function ratifyOrder(
                    SpentItem[] calldata offer,
                    ReceivedItem[] calldata consideration,
                    bytes calldata context, // encoded based on the schemaID
                    bytes32[] calldata orderHashes,
                    uint256 contractNonce
                ) external returns (bytes4 ratifyOrderMagicValue);
                /**
                 * @dev View function to preview an order generated in response to a minimum
                 *      set of received items, maximum set of spent items, and context
                 *      (supplied as extraData).
                 *
                 * @param caller          The address of the caller (e.g. Seaport).
                 * @param fulfiller       The address of the fulfiller (e.g. the account
                 *                        calling Seaport).
                 * @param minimumReceived The minimum items that the caller is willing to
                 *                        receive.
                 * @param maximumSpent    The maximum items the caller is willing to spend.
                 * @param context         Additional context of the order.
                 *
                 * @return offer         A tuple containing the offer items.
                 * @return consideration A tuple containing the consideration items.
                 */
                function previewOrder(
                    address caller,
                    address fulfiller,
                    SpentItem[] calldata minimumReceived,
                    SpentItem[] calldata maximumSpent,
                    bytes calldata context // encoded based on the schemaID
                )
                    external
                    view
                    returns (SpentItem[] memory offer, ReceivedItem[] memory consideration);
                /**
                 * @dev Gets the metadata for this contract offerer.
                 *
                 * @return name    The name of the contract offerer.
                 * @return schemas The schemas supported by the contract offerer.
                 */
                function getSeaportMetadata()
                    external
                    view
                    returns (
                        string memory name,
                        Schema[] memory schemas // map to Seaport Improvement Proposal IDs
                    );
                // Additional functions and/or events based on implemented schemaIDs
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import {
                ERC721Interface,
                ERC1155Interface
            } from "../interfaces/AbridgedTokenInterfaces.sol";
            import {
                ContractOffererInterface
            } from "../interfaces/ContractOffererInterface.sol";
            import { ItemType } from "../lib/ConsiderationEnums.sol";
            import {
                ReceivedItem,
                Schema,
                SpentItem
            } from "../lib/ConsiderationStructs.sol";
            /**
             * @title TestContractOffererNativeToken
             */
            contract TestContractOffererNativeToken is ContractOffererInterface {
                error OrderUnavailable();
                address private immutable _SEAPORT;
                SpentItem private _available;
                SpentItem private _required;
                bool public ready;
                bool public fulfilled;
                uint256 public extraAvailable;
                uint256 public extraRequired;
                constructor(address seaport) {
                    // Set immutable values and storage variables.
                    _SEAPORT = seaport;
                    fulfilled = false;
                    ready = false;
                    extraAvailable = 0;
                    extraRequired = 0;
                }
                receive() external payable {}
                function activate(
                    SpentItem memory available,
                    SpentItem memory required
                ) public payable {
                    if (ready || fulfilled) {
                        revert OrderUnavailable();
                    }
                    // Set storage variables.
                    _available = available;
                    _required = required;
                    ready = true;
                }
                /// In case of criteria based orders and non-wildcard items, the member
                /// `available.identifier` would correspond to the `identifierOrCriteria`
                /// i.e., the merkle-root.
                /// @param identifier corresponds to the actual token-id that gets transferred.
                function activateWithCriteria(
                    SpentItem memory available,
                    SpentItem memory required,
                    uint256 identifier
                ) public {
                    if (ready || fulfilled) {
                        revert OrderUnavailable();
                    }
                    if (available.itemType == ItemType.ERC721_WITH_CRITERIA) {
                        ERC721Interface token = ERC721Interface(available.token);
                        token.transferFrom(msg.sender, address(this), identifier);
                        token.setApprovalForAll(_SEAPORT, true);
                    } else if (available.itemType == ItemType.ERC1155_WITH_CRITERIA) {
                        ERC1155Interface token = ERC1155Interface(available.token);
                        token.safeTransferFrom(
                            msg.sender,
                            address(this),
                            identifier,
                            available.amount,
                            ""
                        );
                        token.setApprovalForAll(_SEAPORT, true);
                    }
                    // Set storage variables.
                    _available = available;
                    _required = required;
                    ready = true;
                }
                function extendAvailable() public {
                    if (!ready || fulfilled) {
                        revert OrderUnavailable();
                    }
                    extraAvailable++;
                    _available.amount /= 2;
                }
                function extendRequired() public {
                    if (!ready || fulfilled) {
                        revert OrderUnavailable();
                    }
                    extraRequired++;
                }
                function generateOrder(
                    address,
                    SpentItem[] calldata minimumReceived,
                    SpentItem[] calldata maximumSpent,
                    bytes calldata /* context */
                )
                    external
                    virtual
                    override
                    returns (SpentItem[] memory offer, ReceivedItem[] memory consideration)
                {
                    // Set the offer and consideration that were supplied during deployment.
                    offer = new SpentItem[](1);
                    consideration = new ReceivedItem[](1);
                    // Send eth to Seaport.
                    (bool success, ) = _SEAPORT.call{ value: minimumReceived[0].amount }(
                        ""
                    );
                    // Revert if transaction fails.
                    if (!success) {
                        assembly {
                            returndatacopy(0, 0, returndatasize())
                            revert(0, returndatasize())
                        }
                    }
                    // Set the offer item as the _available item in storage.
                    offer[0] = minimumReceived[0];
                    // Set the erc721 consideration item.
                    consideration[0] = ReceivedItem({
                        itemType: ItemType.ERC721,
                        token: maximumSpent[0].token,
                        identifier: maximumSpent[0].identifier,
                        amount: maximumSpent[0].amount,
                        recipient: payable(address(this))
                    });
                    // Update storage to reflect that the order has been fulfilled.
                    fulfilled = true;
                }
                function previewOrder(
                    address caller,
                    address,
                    SpentItem[] calldata,
                    SpentItem[] calldata,
                    bytes calldata context
                )
                    external
                    view
                    override
                    returns (SpentItem[] memory offer, ReceivedItem[] memory consideration)
                {
                    // Ensure the caller is Seaport & the order has not yet been fulfilled.
                    if (!ready || fulfilled || caller != _SEAPORT || context.length != 0) {
                        revert OrderUnavailable();
                    }
                    // Set the offer and consideration that were supplied during deployment.
                    offer = new SpentItem[](1 + extraAvailable);
                    consideration = new ReceivedItem[](1 + extraRequired);
                    for (uint256 i = 0; i < 1 + extraAvailable; ++i) {
                        offer[i] = _available;
                    }
                    for (uint256 i = 0; i < 1 + extraRequired; ++i) {
                        consideration[i] = ReceivedItem({
                            itemType: _required.itemType,
                            token: _required.token,
                            identifier: _required.identifier,
                            amount: _required.amount,
                            recipient: payable(address(this))
                        });
                    }
                }
                function getInventory()
                    external
                    view
                    returns (SpentItem[] memory offerable, SpentItem[] memory receivable)
                {
                    // Set offerable and receivable supplied at deployment if unfulfilled.
                    if (!ready || fulfilled) {
                        offerable = new SpentItem[](0);
                        receivable = new SpentItem[](0);
                    } else {
                        offerable = new SpentItem[](1 + extraAvailable);
                        for (uint256 i = 0; i < 1 + extraAvailable; ++i) {
                            offerable[i] = _available;
                        }
                        receivable = new SpentItem[](1 + extraRequired);
                        for (uint256 i = 0; i < 1 + extraRequired; ++i) {
                            receivable[i] = _required;
                        }
                    }
                }
                function ratifyOrder(
                    SpentItem[] calldata /* offer */,
                    ReceivedItem[] calldata /* consideration */,
                    bytes calldata /* context */,
                    bytes32[] calldata /* orderHashes */,
                    uint256 /* contractNonce */
                )
                    external
                    pure
                    virtual
                    override
                    returns (bytes4 /* ratifyOrderMagicValue */)
                {
                    return ContractOffererInterface.ratifyOrder.selector;
                }
                function onERC1155Received(
                    address,
                    address,
                    uint256,
                    uint256,
                    bytes calldata
                ) external pure returns (bytes4) {
                    return bytes4(0xf23a6e61);
                }
                /**
                 * @dev Returns the metadata for this contract offerer.
                 */
                function getSeaportMetadata()
                    external
                    pure
                    override
                    returns (
                        string memory name,
                        Schema[] memory schemas // map to Seaport Improvement Proposal IDs
                    )
                {
                    schemas = new Schema[](1);
                    schemas[0].id = 1337;
                    schemas[0].metadata = new bytes(0);
                    return ("TestContractOffererNativeToken", schemas);
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import { ZoneInterface } from "../interfaces/ZoneInterface.sol";
            import { ERC721Interface } from "../interfaces/AbridgedTokenInterfaces.sol";
            import { ItemType } from "../lib/ConsiderationEnums.sol";
            import {
                ReceivedItem,
                Schema,
                ZoneParameters
            } from "../lib/ConsiderationStructs.sol";
            contract TestPostExecution is ZoneInterface {
                function validateOrder(
                    ZoneParameters calldata zoneParameters
                ) external view override returns (bytes4 validOrderMagicValue) {
                    if (zoneParameters.consideration.length == 0) {
                        revert("No consideration items supplied");
                    }
                    ReceivedItem memory receivedItem = zoneParameters.consideration[0];
                    address currentOwner;
                    try
                        ERC721Interface(receivedItem.token).ownerOf(receivedItem.identifier)
                    returns (address owner) {
                        currentOwner = owner;
                    } catch {
                        revert("Unsupported consideration token type (must implement 721)");
                    }
                    if (receivedItem.itemType != ItemType.ERC721) {
                        revert("Validity check performed with unsupported item type");
                    }
                    // Note that endAmount has been repurposed as recipient; this interface
                    // still needs to be modified to return spent / received items.
                    if (receivedItem.amount != 1) {
                        // Note that this is currently failing in the matchOrder case.
                        revert("Returned item amount incorrectly modified");
                    }
                    if (currentOwner != receivedItem.recipient) {
                        revert("Validity check performed prior to execution");
                    }
                    validOrderMagicValue = ZoneInterface.validateOrder.selector;
                }
                /**
                 * @dev Returns the metadata for this zone.
                 */
                function getSeaportMetadata()
                    external
                    pure
                    override
                    returns (
                        string memory name,
                        Schema[] memory schemas // map to Seaport Improvement Proposal IDs
                    )
                {
                    schemas = new Schema[](1);
                    schemas[0].id = 3003;
                    schemas[0].metadata = new bytes(0);
                    return ("TestPostExecution", schemas);
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import {
                ERC20Interface,
                ERC721Interface,
                ERC1155Interface
            } from "../interfaces/AbridgedTokenInterfaces.sol";
            import {
                ContractOffererInterface
            } from "../interfaces/ContractOffererInterface.sol";
            import { ItemType } from "../lib/ConsiderationEnums.sol";
            import {
                ReceivedItem,
                Schema,
                SpentItem
            } from "../lib/ConsiderationStructs.sol";
            /**
             * @title TestContractOfferer
             * @author 0age
             * @notice TestContractOfferer is a maximally simple contract offerer. It offers
             *         a single item and expects to receive back another single item, and
             *         ignores all parameters supplied to it when previewing or generating
             *         an order. The offered item is placed into this contract as part of
             *         deployment and the corresponding token approvals are set for Seaport.
             */
            contract TestContractOfferer is ContractOffererInterface {
                error OrderUnavailable();
                address private immutable _SEAPORT;
                SpentItem private _available;
                SpentItem private _required;
                bool public ready;
                bool public fulfilled;
                uint256 public extraAvailable;
                uint256 public extraRequired;
                constructor(address seaport) {
                    // Set immutable values and storage variables.
                    _SEAPORT = seaport;
                    fulfilled = false;
                    ready = false;
                    extraAvailable = 0;
                    extraRequired = 0;
                }
                receive() external payable {}
                /// In case of criteria based orders and non-wildcard items, the member
                /// `available.identifier` would correspond to the `identifierOrCriteria`
                /// i.e., the merkle-root.
                /// @param identifier corresponds to the actual token-id that gets transferred.
                function activateWithCriteria(
                    SpentItem memory available,
                    SpentItem memory required,
                    uint256 identifier
                ) public {
                    if (ready || fulfilled) {
                        revert OrderUnavailable();
                    }
                    if (available.itemType == ItemType.ERC721_WITH_CRITERIA) {
                        ERC721Interface token = ERC721Interface(available.token);
                        token.transferFrom(msg.sender, address(this), identifier);
                        token.setApprovalForAll(_SEAPORT, true);
                    } else if (available.itemType == ItemType.ERC1155_WITH_CRITERIA) {
                        ERC1155Interface token = ERC1155Interface(available.token);
                        token.safeTransferFrom(
                            msg.sender,
                            address(this),
                            identifier,
                            available.amount,
                            ""
                        );
                        token.setApprovalForAll(_SEAPORT, true);
                    }
                    // Set storage variables.
                    _available = available;
                    _required = required;
                    ready = true;
                }
                function activate(
                    SpentItem memory available,
                    SpentItem memory required
                ) public payable {
                    if (ready || fulfilled) {
                        revert OrderUnavailable();
                    }
                    // Retrieve the offered item and set associated approvals.
                    if (available.itemType == ItemType.NATIVE) {
                        available.amount = address(this).balance;
                    } else if (available.itemType == ItemType.ERC20) {
                        ERC20Interface token = ERC20Interface(available.token);
                        token.transferFrom(msg.sender, address(this), available.amount);
                        token.approve(_SEAPORT, available.amount);
                    } else if (available.itemType == ItemType.ERC721) {
                        ERC721Interface token = ERC721Interface(available.token);
                        token.transferFrom(msg.sender, address(this), available.identifier);
                        token.setApprovalForAll(_SEAPORT, true);
                    } else if (available.itemType == ItemType.ERC1155) {
                        ERC1155Interface token = ERC1155Interface(available.token);
                        token.safeTransferFrom(
                            msg.sender,
                            address(this),
                            available.identifier,
                            available.amount,
                            ""
                        );
                        token.setApprovalForAll(_SEAPORT, true);
                    }
                    // Set storage variables.
                    _available = available;
                    _required = required;
                    ready = true;
                }
                function extendAvailable() public {
                    if (!ready || fulfilled) {
                        revert OrderUnavailable();
                    }
                    extraAvailable++;
                    _available.amount /= 2;
                }
                function extendRequired() public {
                    if (!ready || fulfilled) {
                        revert OrderUnavailable();
                    }
                    extraRequired++;
                }
                function generateOrder(
                    address,
                    SpentItem[] calldata,
                    SpentItem[] calldata,
                    bytes calldata context
                )
                    external
                    virtual
                    override
                    returns (SpentItem[] memory offer, ReceivedItem[] memory consideration)
                {
                    // Ensure the caller is Seaport & the order has not yet been fulfilled.
                    if (
                        !ready ||
                        fulfilled ||
                        msg.sender != _SEAPORT ||
                        context.length % 32 != 0
                    ) {
                        revert OrderUnavailable();
                    }
                    // Set the offer and consideration that were supplied during deployment.
                    offer = new SpentItem[](1 + extraAvailable);
                    consideration = new ReceivedItem[](1 + extraRequired);
                    for (uint256 i = 0; i < 1 + extraAvailable; ++i) {
                        offer[i] = _available;
                    }
                    for (uint256 i = 0; i < 1 + extraRequired; ++i) {
                        consideration[i] = ReceivedItem({
                            itemType: _required.itemType,
                            token: _required.token,
                            identifier: _required.identifier,
                            amount: _required.amount,
                            recipient: payable(address(this))
                        });
                    }
                    // Update storage to reflect that the order has been fulfilled.
                    fulfilled = true;
                }
                function previewOrder(
                    address caller,
                    address,
                    SpentItem[] calldata,
                    SpentItem[] calldata,
                    bytes calldata context
                )
                    external
                    view
                    override
                    returns (SpentItem[] memory offer, ReceivedItem[] memory consideration)
                {
                    // Ensure the caller is Seaport & the order has not yet been fulfilled.
                    if (
                        !ready ||
                        fulfilled ||
                        caller != _SEAPORT ||
                        context.length % 32 != 0
                    ) {
                        revert OrderUnavailable();
                    }
                    // Set the offer and consideration that were supplied during deployment.
                    offer = new SpentItem[](1 + extraAvailable);
                    consideration = new ReceivedItem[](1 + extraRequired);
                    for (uint256 i = 0; i < 1 + extraAvailable; ++i) {
                        offer[i] = _available;
                    }
                    for (uint256 i = 0; i < 1 + extraRequired; ++i) {
                        consideration[i] = ReceivedItem({
                            itemType: _required.itemType,
                            token: _required.token,
                            identifier: _required.identifier,
                            amount: _required.amount,
                            recipient: payable(address(this))
                        });
                    }
                }
                function getInventory()
                    external
                    view
                    returns (SpentItem[] memory offerable, SpentItem[] memory receivable)
                {
                    // Set offerable and receivable supplied at deployment if unfulfilled.
                    if (!ready || fulfilled) {
                        offerable = new SpentItem[](0);
                        receivable = new SpentItem[](0);
                    } else {
                        offerable = new SpentItem[](1 + extraAvailable);
                        for (uint256 i = 0; i < 1 + extraAvailable; ++i) {
                            offerable[i] = _available;
                        }
                        receivable = new SpentItem[](1 + extraRequired);
                        for (uint256 i = 0; i < 1 + extraRequired; ++i) {
                            receivable[i] = _required;
                        }
                    }
                }
                function ratifyOrder(
                    SpentItem[] calldata /* offer */,
                    ReceivedItem[] calldata /* consideration */,
                    bytes calldata context,
                    bytes32[] calldata orderHashes,
                    uint256 /* contractNonce */
                )
                    external
                    pure
                    virtual
                    override
                    returns (bytes4 /* ratifyOrderMagicValue */)
                {
                    if (context.length > 32 && context.length % 32 == 0) {
                        bytes32[] memory expectedOrderHashes = abi.decode(
                            context,
                            (bytes32[])
                        );
                        uint256 expectedLength = expectedOrderHashes.length;
                        if (expectedLength != orderHashes.length) {
                            revert("Revert on unexpected order hashes length");
                        }
                        for (uint256 i = 0; i < expectedLength; ++i) {
                            if (expectedOrderHashes[i] != orderHashes[i]) {
                                revert("Revert on unexpected order hash");
                            }
                        }
                    }
                    return ContractOffererInterface.ratifyOrder.selector;
                }
                function onERC1155Received(
                    address,
                    address,
                    uint256,
                    uint256,
                    bytes calldata
                ) external pure returns (bytes4) {
                    return bytes4(0xf23a6e61);
                }
                /**
                 * @dev Returns the metadata for this contract offerer.
                 */
                function getSeaportMetadata()
                    external
                    pure
                    override
                    returns (
                        string memory name,
                        Schema[] memory schemas // map to Seaport Improvement Proposal IDs
                    )
                {
                    schemas = new Schema[](1);
                    schemas[0].id = 1337;
                    schemas[0].metadata = new bytes(0);
                    return ("TestContractOfferer", schemas);
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import { ReceivedItem, SpentItem } from "../lib/ConsiderationStructs.sol";
            import { TestContractOfferer } from "./TestContractOfferer.sol";
            contract TestInvalidContractOffererRatifyOrder is TestContractOfferer {
                constructor(address seaport) TestContractOfferer(seaport) {}
                function ratifyOrder(
                    SpentItem[] calldata,
                    ReceivedItem[] calldata,
                    bytes calldata,
                    bytes32[] calldata,
                    uint256
                ) external pure override returns (bytes4) {
                    return bytes4(keccak256("throw"));
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import { ReceivedItem, SpentItem } from "../lib/ConsiderationStructs.sol";
            import { TestContractOfferer } from "./TestContractOfferer.sol";
            contract TestInvalidContractOfferer is TestContractOfferer {
                error RevertWithData(bytes revertData);
                constructor(address seaport) TestContractOfferer(seaport) {}
                function generateOrder(
                    address,
                    SpentItem[] calldata,
                    SpentItem[] calldata,
                    bytes calldata context
                )
                    external
                    pure
                    override
                    returns (SpentItem[] memory, ReceivedItem[] memory)
                {
                    revert RevertWithData(context);
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import { ERC721Interface } from "../interfaces/AbridgedTokenInterfaces.sol";
            import {
                ContractOffererInterface
            } from "../interfaces/ContractOffererInterface.sol";
            import { ItemType } from "../lib/ConsiderationEnums.sol";
            import {
                ReceivedItem,
                Schema,
                SpentItem
            } from "../lib/ConsiderationStructs.sol";
            contract TestBadContractOfferer is ContractOffererInterface {
                error IntentionalRevert();
                address private immutable seaport;
                ERC721Interface token;
                constructor(address _seaport, ERC721Interface _token) {
                    seaport = _seaport;
                    token = _token;
                    ERC721Interface(token).setApprovalForAll(seaport, true);
                }
                receive() external payable {}
                /**
                 * @dev Generates an order with the specified minimum and maximum spent items,
                 * and the optional extra data.
                 *
                 * @param a               Fulfiller, unused here.
                 * @param b               The minimum items that the caller is willing to
                 *                        receive.
                 * @param c               maximumSent, unused here.
                 * @param d               context, unused here.
                 *
                 * @return offer         A tuple containing the offer items.
                 * @return consideration A tuple containing the consideration items.
                 */
                function generateOrder(
                    address a,
                    SpentItem[] calldata b,
                    SpentItem[] calldata c,
                    bytes calldata d
                )
                    external
                    virtual
                    override
                    returns (SpentItem[] memory offer, ReceivedItem[] memory consideration)
                {
                    return previewOrder(a, a, b, c, d);
                }
                /**
                 * @dev View function to preview an order generated in response to a minimum
                 *      set of received items, maximum set of spent items, and context
                 *      (supplied as extraData).
                 *
                 * @param -               caller, unused here.
                 * @param -               fulfiller, unused here.
                 * @param minimumReceived The minimum received set.
                 * @param -               maximumSpent, unused here.
                 * @param -               context, unused here.
                 *
                 * @return offer         The offer for the order.
                 * @return consideration The consideration for the order.
                 */
                function previewOrder(
                    address,
                    address,
                    SpentItem[] calldata minimumReceived,
                    SpentItem[] calldata maximumSpent,
                    bytes calldata
                )
                    public
                    view
                    override
                    returns (SpentItem[] memory offer, ReceivedItem[] memory consideration)
                {
                    if (minimumReceived[0].identifier == 1) {
                        offer = minimumReceived;
                        consideration = new ReceivedItem[](1);
                        consideration[0] = ReceivedItem({
                            itemType: ItemType.NATIVE,
                            token: address(0),
                            identifier: 0,
                            amount: 100,
                            recipient: payable(address(this))
                        });
                        return (offer, consideration);
                    } else if (minimumReceived[0].identifier == 2) {
                        // return nothing
                        assembly {
                            return(0, 0)
                        }
                    } else if (minimumReceived[0].identifier == 3) {
                        revert IntentionalRevert();
                    } else {
                        // return garbage
                        bytes32 h1 = keccak256(abi.encode(minimumReceived));
                        bytes32 h2 = keccak256(abi.encode(maximumSpent));
                        assembly {
                            mstore(0x00, h1)
                            mstore(0x20, h2)
                            return(0, 0x100)
                        }
                    }
                }
                function ratifyOrder(
                    SpentItem[] calldata /* offer */,
                    ReceivedItem[] calldata /* consideration */,
                    bytes calldata /* context */,
                    bytes32[] calldata /* orderHashes */,
                    uint256 /* contractNonce */
                ) external pure override returns (bytes4 /* ratifyOrderMagicValue */) {
                    return TestBadContractOfferer.ratifyOrder.selector;
                }
                /**
                 * @dev Returns the metadata for this contract offerer.
                 */
                function getSeaportMetadata()
                    external
                    pure
                    override
                    returns (
                        string memory name,
                        Schema[] memory schemas // map to Seaport Improvement Proposal IDs
                    )
                {
                    schemas = new Schema[](1);
                    schemas[0].id = 1337;
                    schemas[0].metadata = new bytes(0);
                    return ("TestBadContractOfferer", schemas);
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import { ConduitInterface } from "../interfaces/ConduitInterface.sol";
            import {
                ConduitBatch1155Transfer,
                ConduitTransfer
            } from "../conduit/lib/ConduitStructs.sol";
            contract ConduitMockRevertNoReason is ConduitInterface {
                constructor() {}
                function execute(
                    ConduitTransfer[] calldata /* transfers */
                ) external pure override returns (bytes4) {
                    // Revert without reason string.
                    revert();
                }
                function executeBatch1155(
                    ConduitBatch1155Transfer[] calldata /*  batch1155Transfers */
                ) external view override returns (bytes4 magicValue) {}
                function executeWithBatch1155(
                    ConduitTransfer[] calldata /* standardTransfers */,
                    ConduitBatch1155Transfer[] calldata /*  batch1155Transfers */
                ) external view override returns (bytes4 magicValue) {}
                function updateChannel(address channel, bool isOpen) external override {}
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import { ConduitInterface } from "../interfaces/ConduitInterface.sol";
            import {
                ConduitBatch1155Transfer,
                ConduitTransfer
            } from "../conduit/lib/ConduitStructs.sol";
            contract ConduitMockRevertBytes is ConduitInterface {
                constructor() {}
                error CustomError();
                function execute(
                    ConduitTransfer[] calldata /* transfers */
                ) external pure override returns (bytes4) {
                    revert CustomError();
                }
                function executeBatch1155(
                    ConduitBatch1155Transfer[] calldata /*  batch1155Transfers */
                ) external view override returns (bytes4 magicValue) {}
                function executeWithBatch1155(
                    ConduitTransfer[] calldata /* standardTransfers */,
                    ConduitBatch1155Transfer[] calldata /*  batch1155Transfers */
                ) external view override returns (bytes4 magicValue) {}
                function updateChannel(address channel, bool isOpen) external override {}
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import {
                ConduitControllerInterface
            } from "../interfaces/ConduitControllerInterface.sol";
            import { ConduitInterface } from "../interfaces/ConduitInterface.sol";
            import { ConduitMock } from "../test/ConduitMock.sol";
            import { ConduitMockInvalidMagic } from "../test/ConduitMockInvalidMagic.sol";
            import {
                ConduitMockRevertNoReason
            } from "../test/ConduitMockRevertNoReason.sol";
            import { ConduitMockRevertBytes } from "../test/ConduitMockRevertBytes.sol";
            contract ConduitControllerMock is ConduitControllerInterface {
                // Register keys, owners, new potential owners, and channels by conduit.
                mapping(address => ConduitProperties) internal _conduits;
                // Set conduit creation code and runtime code hashes as immutable arguments.
                bytes32 internal immutable _CONDUIT_CREATION_CODE_HASH;
                bytes32 internal immutable _CONDUIT_RUNTIME_CODE_HASH;
                uint256 private conduitNum;
                /**
                 * @dev Initialize contract by deploying a conduit and setting the creation
                 *      code and runtime code hashes as immutable arguments.
                 */
                constructor(uint256 _conduitNum) {
                    conduitNum = _conduitNum;
                    bytes32 creationCodeHash;
                    bytes32 runtimeCodeHash;
                    if (conduitNum == 0) {
                        creationCodeHash = keccak256(type(ConduitMock).creationCode);
                        ConduitMock zeroConduit = new ConduitMock{ salt: bytes32(0) }();
                        runtimeCodeHash = address(zeroConduit).codehash;
                    } else if (conduitNum == 1) {
                        creationCodeHash = keccak256(
                            type(ConduitMockRevertNoReason).creationCode
                        );
                        ConduitMockRevertNoReason zeroConduit = new ConduitMockRevertNoReason{
                                salt: bytes32(0)
                            }();
                        runtimeCodeHash = address(zeroConduit).codehash;
                    } else if (conduitNum == 2) {
                        creationCodeHash = keccak256(
                            type(ConduitMockInvalidMagic).creationCode
                        );
                        ConduitMockInvalidMagic zeroConduit = new ConduitMockInvalidMagic{
                            salt: bytes32(0)
                        }();
                        runtimeCodeHash = address(zeroConduit).codehash;
                    } else if (conduitNum == 3) {
                        creationCodeHash = keccak256(
                            type(ConduitMockRevertBytes).creationCode
                        );
                        ConduitMockRevertBytes zeroConduit = new ConduitMockRevertBytes{
                            salt: bytes32(0)
                        }();
                        runtimeCodeHash = address(zeroConduit).codehash;
                    }
                    _CONDUIT_CREATION_CODE_HASH = creationCodeHash;
                    _CONDUIT_RUNTIME_CODE_HASH = runtimeCodeHash;
                }
                /**
                 * @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 override returns (address conduit) {
                    // Ensure that an initial owner has been supplied.
                    if (initialOwner == address(0)) {
                        revert InvalidInitialOwner();
                    }
                    // If the first 20 bytes of the conduit key do not match the caller...
                    if (address(uint160(bytes20(conduitKey))) != msg.sender) {
                        // Revert with an error indicating that the creator is invalid.
                        revert InvalidCreator();
                    }
                    // Derive address from deployer, conduit key and creation code hash.
                    conduit = address(
                        uint160(
                            uint256(
                                keccak256(
                                    abi.encodePacked(
                                        bytes1(0xff),
                                        address(this),
                                        conduitKey,
                                        _CONDUIT_CREATION_CODE_HASH
                                    )
                                )
                            )
                        )
                    );
                    // If derived conduit exists, as evidenced by comparing runtime code...
                    if (conduit.codehash == _CONDUIT_RUNTIME_CODE_HASH) {
                        // Revert with an error indicating that the conduit already exists.
                        revert ConduitAlreadyExists(conduit);
                    }
                    // Deploy the conduit via CREATE2 using the conduit key as the salt.
                    if (conduitNum == 0) {
                        new ConduitMock{ salt: conduitKey }();
                    } else if (conduitNum == 1) {
                        new ConduitMockRevertNoReason{ salt: conduitKey }();
                    } else if (conduitNum == 2) {
                        new ConduitMockInvalidMagic{ salt: conduitKey }();
                    } else if (conduitNum == 3) {
                        new ConduitMockRevertBytes{ salt: conduitKey }();
                    }
                    // Initialize storage variable referencing conduit properties.
                    ConduitProperties storage conduitProperties = _conduits[conduit];
                    // Set the supplied initial owner as the owner of the conduit.
                    conduitProperties.owner = initialOwner;
                    // Set conduit key used to deploy the conduit to enable reverse lookup.
                    conduitProperties.key = conduitKey;
                    // Emit an event indicating that the conduit has been deployed.
                    emit NewConduit(conduit, conduitKey);
                    // Emit an event indicating that conduit ownership has been assigned.
                    emit OwnershipTransferred(conduit, address(0), initialOwner);
                }
                /**
                 * @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 override {
                    // Ensure the caller is the current owner of the conduit in question.
                    _assertCallerIsConduitOwner(conduit);
                    // Call the conduit, updating the channel.
                    ConduitInterface(conduit).updateChannel(channel, isOpen);
                    // Retrieve storage region where channels for the conduit are tracked.
                    ConduitProperties storage conduitProperties = _conduits[conduit];
                    // Retrieve the index, if one currently exists, for the updated channel.
                    uint256 channelIndexPlusOne = (
                        conduitProperties.channelIndexesPlusOne[channel]
                    );
                    // Determine whether the updated channel is already tracked as open.
                    bool channelPreviouslyOpen = channelIndexPlusOne != 0;
                    // If the channel has been set to open and was previously closed...
                    if (isOpen && !channelPreviouslyOpen) {
                        // Add the channel to the channels array for the conduit.
                        conduitProperties.channels.push(channel);
                        // Add new open channel length to associated mapping as index + 1.
                        conduitProperties.channelIndexesPlusOne[channel] = (
                            conduitProperties.channels.length
                        );
                    } else if (!isOpen && channelPreviouslyOpen) {
                        // Set a previously open channel as closed via "swap & pop" method.
                        // Decrement located index to get the index of the closed channel.
                        uint256 removedChannelIndex;
                        // Skip underflow check as channelPreviouslyOpen being true ensures
                        // that channelIndexPlusOne is nonzero.
                        unchecked {
                            removedChannelIndex = channelIndexPlusOne - 1;
                        }
                        // Use length of channels array to determine index of last channel.
                        uint256 finalChannelIndex = conduitProperties.channels.length - 1;
                        // If closed channel is not last channel in the channels array...
                        if (finalChannelIndex != removedChannelIndex) {
                            // Retrieve the final channel and place the value on the stack.
                            address finalChannel = (
                                conduitProperties.channels[finalChannelIndex]
                            );
                            // Overwrite the removed channel using the final channel value.
                            conduitProperties.channels[removedChannelIndex] = finalChannel;
                            // Update final index in associated mapping to removed index.
                            conduitProperties.channelIndexesPlusOne[finalChannel] = (
                                channelIndexPlusOne
                            );
                        }
                        // Remove the last channel from the channels array for the conduit.
                        conduitProperties.channels.pop();
                        // Remove the closed channel from associated mapping of indexes.
                        delete conduitProperties.channelIndexesPlusOne[channel];
                    }
                }
                /**
                 * @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 override {
                    // Ensure the caller is the current owner of the conduit in question.
                    _assertCallerIsConduitOwner(conduit);
                    // Ensure the new potential owner is not an invalid address.
                    if (newPotentialOwner == address(0)) {
                        revert NewPotentialOwnerIsZeroAddress(conduit);
                    }
                    // Ensure the new potential owner is not already set.
                    if (newPotentialOwner == _conduits[conduit].potentialOwner) {
                        revert NewPotentialOwnerAlreadySet(conduit, newPotentialOwner);
                    }
                    // Emit an event indicating that the potential owner has been updated.
                    emit PotentialOwnerUpdated(newPotentialOwner);
                    // Set the new potential owner as the potential owner of the conduit.
                    _conduits[conduit].potentialOwner = newPotentialOwner;
                }
                /**
                 * @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 override {
                    // Ensure the caller is the current owner of the conduit in question.
                    _assertCallerIsConduitOwner(conduit);
                    // Ensure that ownership transfer is currently possible.
                    if (_conduits[conduit].potentialOwner == address(0)) {
                        revert NoPotentialOwnerCurrentlySet(conduit);
                    }
                    // Emit an event indicating that the potential owner has been cleared.
                    emit PotentialOwnerUpdated(address(0));
                    // Clear the current new potential owner from the conduit.
                    _conduits[conduit].potentialOwner = address(0);
                }
                /**
                 * @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 override {
                    // Ensure that the conduit in question exists.
                    _assertConduitExists(conduit);
                    // If caller does not match current potential owner of the conduit...
                    if (msg.sender != _conduits[conduit].potentialOwner) {
                        // Revert, indicating that caller is not current potential owner.
                        revert CallerIsNotNewPotentialOwner(conduit);
                    }
                    // Emit an event indicating that the potential owner has been cleared.
                    emit PotentialOwnerUpdated(address(0));
                    // Clear the current new potential owner from the conduit.
                    _conduits[conduit].potentialOwner = address(0);
                    // Emit an event indicating conduit ownership has been transferred.
                    emit OwnershipTransferred(
                        conduit,
                        _conduits[conduit].owner,
                        msg.sender
                    );
                    // Set the caller as the owner of the conduit.
                    _conduits[conduit].owner = msg.sender;
                }
                /**
                 * @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 override returns (address owner) {
                    // Ensure that the conduit in question exists.
                    _assertConduitExists(conduit);
                    // Retrieve the current owner of the conduit in question.
                    owner = _conduits[conduit].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 override returns (bytes32 conduitKey) {
                    // Attempt to retrieve a conduit key for the conduit in question.
                    conduitKey = _conduits[conduit].key;
                    // Revert if no conduit key was located.
                    if (conduitKey == bytes32(0)) {
                        revert NoConduit();
                    }
                }
                /**
                 * @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 override returns (address conduit, bool exists) {
                    // Derive address from deployer, conduit key and creation code hash.
                    conduit = address(
                        uint160(
                            uint256(
                                keccak256(
                                    abi.encodePacked(
                                        bytes1(0xff),
                                        address(this),
                                        conduitKey,
                                        _CONDUIT_CREATION_CODE_HASH
                                    )
                                )
                            )
                        )
                    );
                    // Determine whether conduit exists by retrieving its runtime code.
                    exists = (conduit.codehash == _CONDUIT_RUNTIME_CODE_HASH);
                }
                /**
                 * @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 override returns (address potentialOwner) {
                    // Ensure that the conduit in question exists.
                    _assertConduitExists(conduit);
                    // Retrieve the current potential owner of the conduit in question.
                    potentialOwner = _conduits[conduit].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 override returns (bool isOpen) {
                    // Ensure that the conduit in question exists.
                    _assertConduitExists(conduit);
                    // Retrieve the current channel status for the conduit in question.
                    isOpen = _conduits[conduit].channelIndexesPlusOne[channel] != 0;
                }
                /**
                 * @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 override returns (uint256 totalChannels) {
                    // Ensure that the conduit in question exists.
                    _assertConduitExists(conduit);
                    // Retrieve the total open channel count for the conduit in question.
                    totalChannels = _conduits[conduit].channels.length;
                }
                /**
                 * @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 override returns (address channel) {
                    // Ensure that the conduit in question exists.
                    _assertConduitExists(conduit);
                    // Retrieve the total open channel count for the conduit in question.
                    uint256 totalChannels = _conduits[conduit].channels.length;
                    // Ensure that the supplied index is within range.
                    if (channelIndex >= totalChannels) {
                        revert ChannelOutOfRange(conduit);
                    }
                    // Retrieve the channel at the given index.
                    channel = _conduits[conduit].channels[channelIndex];
                }
                /**
                 * @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 override returns (address[] memory channels) {
                    // Ensure that the conduit in question exists.
                    _assertConduitExists(conduit);
                    // Retrieve all of the open channels on the conduit in question.
                    channels = _conduits[conduit].channels;
                }
                /**
                 * @dev Retrieve the conduit creation code and runtime code hashes.
                 */
                function getConduitCodeHashes()
                    external
                    view
                    override
                    returns (bytes32 creationCodeHash, bytes32 runtimeCodeHash)
                {
                    // Retrieve the conduit creation code hash from runtime.
                    creationCodeHash = _CONDUIT_CREATION_CODE_HASH;
                    // Retrieve the conduit runtime code hash from runtime.
                    runtimeCodeHash = _CONDUIT_RUNTIME_CODE_HASH;
                }
                /**
                 * @dev Private view function to revert if the caller is not the owner of a
                 *      given conduit.
                 *
                 * @param conduit The conduit for which to assert ownership.
                 */
                function _assertCallerIsConduitOwner(address conduit) private view {
                    // Ensure that the conduit in question exists.
                    _assertConduitExists(conduit);
                    // If the caller does not match the current owner of the conduit...
                    if (msg.sender != _conduits[conduit].owner) {
                        // Revert, indicating that the caller is not the owner.
                        revert CallerIsNotOwner(conduit);
                    }
                }
                /**
                 * @dev Private view function to revert if a given conduit does not exist.
                 *
                 * @param conduit The conduit for which to assert existence.
                 */
                function _assertConduitExists(address conduit) private view {
                    // Attempt to retrieve a conduit key for the conduit in question.
                    if (_conduits[conduit].key == bytes32(0)) {
                        // Revert if no conduit key was located.
                        revert NoConduit();
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import { ConduitInterface } from "../interfaces/ConduitInterface.sol";
            import {
                ConduitBatch1155Transfer,
                ConduitTransfer
            } from "../conduit/lib/ConduitStructs.sol";
            contract ConduitMock is ConduitInterface {
                constructor() {}
                function execute(
                    ConduitTransfer[] calldata /* transfers */
                ) external pure override returns (bytes4) {
                    // Return the valid magic value.
                    return 0x4ce34aa2;
                }
                function executeBatch1155(
                    ConduitBatch1155Transfer[] calldata /*  batch1155Transfers */
                ) external view override returns (bytes4 magicValue) {}
                function executeWithBatch1155(
                    ConduitTransfer[] calldata /* standardTransfers */,
                    ConduitBatch1155Transfer[] calldata /*  batch1155Transfers */
                ) external view override returns (bytes4 magicValue) {}
                function updateChannel(address channel, bool isOpen) external override {}
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import { ConduitInterface } from "../interfaces/ConduitInterface.sol";
            import {
                ConduitBatch1155Transfer,
                ConduitTransfer
            } from "../conduit/lib/ConduitStructs.sol";
            contract ConduitMockInvalidMagic is ConduitInterface {
                constructor() {}
                function execute(
                    ConduitTransfer[] calldata /* transfers */
                ) external pure override returns (bytes4) {
                    return 0xabcd0000;
                }
                function executeBatch1155(
                    ConduitBatch1155Transfer[] calldata /*  batch1155Transfers */
                ) external view override returns (bytes4 magicValue) {}
                function executeWithBatch1155(
                    ConduitTransfer[] calldata /* standardTransfers */,
                    ConduitBatch1155Transfer[] calldata /*  batch1155Transfers */
                ) external view override returns (bytes4 magicValue) {}
                function updateChannel(address channel, bool isOpen) external override {}
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import { IERC721Receiver } from "../interfaces/IERC721Receiver.sol";
            import {
                TransferHelperItem,
                TransferHelperItemsWithRecipient
            } from "./TransferHelperStructs.sol";
            import { ConduitItemType } from "../conduit/lib/ConduitEnums.sol";
            import { ConduitInterface } from "../interfaces/ConduitInterface.sol";
            import {
                ConduitControllerInterface
            } from "../interfaces/ConduitControllerInterface.sol";
            import { ConduitTransfer } from "../conduit/lib/ConduitStructs.sol";
            import {
                TransferHelperInterface
            } from "../interfaces/TransferHelperInterface.sol";
            import { TransferHelperErrors } from "../interfaces/TransferHelperErrors.sol";
            /**
             * @title TransferHelper
             * @author stephankmin, stuckinaboot, ryanio
             * @notice TransferHelper is a utility contract for transferring
             *         ERC20/ERC721/ERC1155 items in bulk to specific recipients.
             */
            contract TransferHelper is TransferHelperInterface, TransferHelperErrors {
                // Allow for interaction with the conduit controller.
                ConduitControllerInterface internal immutable _CONDUIT_CONTROLLER;
                // Set conduit creation code and runtime code hashes as immutable arguments.
                bytes32 internal immutable _CONDUIT_CREATION_CODE_HASH;
                bytes32 internal immutable _CONDUIT_RUNTIME_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 and runtime code hashes from the
                    // supplied conduit controller and set them as an immutable.
                    ConduitControllerInterface controller = ConduitControllerInterface(
                        conduitController
                    );
                    (_CONDUIT_CREATION_CODE_HASH, _CONDUIT_RUNTIME_CODE_HASH) = controller
                        .getConduitCodeHashes();
                    // Set the supplied conduit controller as an immutable.
                    _CONDUIT_CONTROLLER = controller;
                }
                /**
                 * @notice Transfer multiple ERC20/ERC721/ERC1155 items to
                 *         specified recipients.
                 *
                 * @param items      The items to transfer to an intended recipient.
                 * @param conduitKey A mandatory conduit key referring to a conduit through
                 *                   which the bulk transfer should occur.
                 *
                 * @return magicValue A value indicating that the transfers were successful.
                 */
                function bulkTransfer(
                    TransferHelperItemsWithRecipient[] calldata items,
                    bytes32 conduitKey
                ) external override returns (bytes4 magicValue) {
                    // Ensure that a conduit key has been supplied.
                    if (conduitKey == bytes32(0)) {
                        revert InvalidConduit(conduitKey, address(0));
                    }
                    // Use conduit derived from supplied conduit key to perform transfers.
                    _performTransfersWithConduit(items, conduitKey);
                    // Return a magic value indicating that the transfers were performed.
                    magicValue = this.bulkTransfer.selector;
                }
                /**
                 * @notice Perform multiple transfers to specified recipients via the
                 *         conduit derived from the provided conduit key.
                 *
                 * @param transfers  The items to transfer.
                 * @param conduitKey The conduit key referring to the conduit through
                 *                   which the bulk transfer should occur.
                 */
                function _performTransfersWithConduit(
                    TransferHelperItemsWithRecipient[] calldata transfers,
                    bytes32 conduitKey
                ) internal {
                    // Retrieve total number of transfers and place on stack.
                    uint256 numTransfers = transfers.length;
                    // 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 variable to store the sum of all items across transfers.
                    uint256 sumOfItemsAcrossAllTransfers;
                    // Skip overflow checks: all for loops are indexed starting at zero.
                    unchecked {
                        // Iterate over each transfer.
                        for (uint256 i = 0; i < numTransfers; ++i) {
                            // Retrieve the transfer in question.
                            TransferHelperItemsWithRecipient calldata transfer = transfers[
                                i
                            ];
                            // Increment totalItems by the number of items in the transfer.
                            sumOfItemsAcrossAllTransfers += transfer.items.length;
                        }
                    }
                    // Declare a new array in memory with length totalItems to populate with
                    // each conduit transfer.
                    ConduitTransfer[] memory conduitTransfers = new ConduitTransfer[](
                        sumOfItemsAcrossAllTransfers
                    );
                    // Declare an index for storing ConduitTransfers in conduitTransfers.
                    uint256 itemIndex;
                    // Skip overflow checks: all for loops are indexed starting at zero.
                    unchecked {
                        // Iterate over each transfer.
                        for (uint256 i = 0; i < numTransfers; ++i) {
                            // Retrieve the transfer in question.
                            TransferHelperItemsWithRecipient calldata transfer = transfers[
                                i
                            ];
                            // Retrieve the items of the transfer in question.
                            TransferHelperItem[] calldata transferItems = transfer.items;
                            // Ensure recipient is not the zero address.
                            _checkRecipientIsNotZeroAddress(transfer.recipient);
                            // Create a boolean indicating whether validateERC721Receiver
                            // is true and recipient is a contract.
                            bool callERC721Receiver = transfer.validateERC721Receiver &&
                                transfer.recipient.code.length != 0;
                            // Retrieve the total number of items in the transfer and
                            // place on stack.
                            uint256 numItemsInTransfer = transferItems.length;
                            // Iterate over each item in the transfer to create a
                            // corresponding ConduitTransfer.
                            for (uint256 j = 0; j < numItemsInTransfer; ++j) {
                                // Retrieve the item from the transfer.
                                TransferHelperItem calldata item = transferItems[j];
                                if (item.itemType == ConduitItemType.ERC20) {
                                    // Ensure that the identifier of an ERC20 token is 0.
                                    if (item.identifier != 0) {
                                        revert InvalidERC20Identifier();
                                    }
                                }
                                // If the item is an ERC721 token and
                                // callERC721Receiver is true...
                                if (item.itemType == ConduitItemType.ERC721) {
                                    if (callERC721Receiver) {
                                        // Check if the recipient implements
                                        // onERC721Received for the given tokenId.
                                        _checkERC721Receiver(
                                            conduit,
                                            transfer.recipient,
                                            item.identifier
                                        );
                                    }
                                }
                                // Create a ConduitTransfer corresponding to each
                                // TransferHelperItem.
                                conduitTransfers[itemIndex] = ConduitTransfer(
                                    item.itemType,
                                    item.token,
                                    msg.sender,
                                    transfer.recipient,
                                    item.identifier,
                                    item.amount
                                );
                                // Increment the index for storing ConduitTransfers.
                                ++itemIndex;
                            }
                        }
                    }
                    // Attempt the external call to transfer tokens via the derived conduit.
                    try ConduitInterface(conduit).execute(conduitTransfers) returns (
                        bytes4 conduitMagicValue
                    ) {
                        // Check if the value returned from the external call matches
                        // the conduit `execute` selector.
                        if (conduitMagicValue != ConduitInterface.execute.selector) {
                            // If the external call fails, revert with the conduit key
                            // and conduit address.
                            revert InvalidConduit(conduitKey, conduit);
                        }
                    } catch Error(string memory reason) {
                        // Catch reverts with a provided reason string and
                        // revert with the reason, conduit key and conduit address.
                        revert ConduitErrorRevertString(reason, conduitKey, conduit);
                    } catch (bytes memory data) {
                        // Conduits will throw a custom error when attempting to transfer
                        // native token item types or an ERC721 item amount other than 1.
                        // Bubble up these custom errors when encountered. Note that the
                        // conduit itself will bubble up revert reasons from transfers as
                        // well, meaning that these errors are not necessarily indicative of
                        // an issue with the item type or amount in cases where the same
                        // custom error signature is encountered during a conduit transfer.
                        // Set initial value of first four bytes of revert data to the mask.
                        bytes4 customErrorSelector = bytes4(0xffffffff);
                        // Utilize assembly to read first four bytes (if present) directly.
                        assembly {
                            // Combine original mask with first four bytes of revert data.
                            customErrorSelector := and(
                                mload(add(data, 0x20)), // Data begins after length offset.
                                customErrorSelector
                            )
                        }
                        // Pass through the custom error in question if the revert data is
                        // the correct length and matches an expected custom error selector.
                        if (
                            data.length == 4 &&
                            customErrorSelector == InvalidItemType.selector
                        ) {
                            // "Bubble up" the revert reason.
                            assembly {
                                revert(add(data, 0x20), 0x04)
                            }
                        } else if (
                            data.length == 36 &&
                            customErrorSelector == InvalidERC721TransferAmount.selector
                        ) {
                            // "Bubble up" the revert reason.
                            assembly {
                                revert(add(data, 0x20), 0x24)
                            }
                        }
                        // Catch all other reverts from the external call to the conduit and
                        // include the conduit's raw revert reason as a data argument to a
                        // new custom error.
                        revert ConduitErrorRevertBytes(data, conduitKey, conduit);
                    }
                }
                /**
                 * @notice An internal function to check if a recipient address implements
                 *         onERC721Received for a given tokenId. Note that this check does
                 *         not adhere to the safe transfer specification and is only meant
                 *         to provide an additional layer of assurance that the recipient
                 *         can receive the tokens — any hooks or post-transfer checks will
                 *         fail and the caller will be the transfer helper rather than the
                 *         ERC721 contract. Note that the conduit is set as the operator, as
                 *         it will be the caller once the transfer is performed.
                 *
                 * @param conduit   The conduit to provide as the operator when calling
                 *                  onERC721Received.
                 * @param recipient The ERC721 recipient on which to call onERC721Received.
                 * @param tokenId   The ERC721 tokenId of the token being transferred.
                 */
                function _checkERC721Receiver(
                    address conduit,
                    address recipient,
                    uint256 tokenId
                ) internal {
                    // Check if recipient can receive ERC721 tokens.
                    try
                        IERC721Receiver(recipient).onERC721Received(
                            conduit,
                            msg.sender,
                            tokenId,
                            ""
                        )
                    returns (bytes4 selector) {
                        // Check if onERC721Received selector is valid.
                        if (selector != IERC721Receiver.onERC721Received.selector) {
                            // Revert if recipient cannot accept
                            // ERC721 tokens.
                            revert InvalidERC721Recipient(recipient);
                        }
                    } catch (bytes memory data) {
                        // "Bubble up" recipient's revert reason.
                        revert ERC721ReceiverErrorRevertBytes(
                            data,
                            recipient,
                            msg.sender,
                            tokenId
                        );
                    } catch Error(string memory reason) {
                        // "Bubble up" recipient's revert reason.
                        revert ERC721ReceiverErrorRevertString(
                            reason,
                            recipient,
                            msg.sender,
                            tokenId
                        );
                    }
                }
                /**
                 * @notice An internal function that reverts if the passed-in recipient
                 *         is the zero address.
                 *
                 * @param recipient The recipient on which to perform the check.
                 */
                function _checkRecipientIsNotZeroAddress(address recipient) internal pure {
                    // Revert if the recipient is the zero address.
                    if (recipient == address(0x0)) {
                        revert RecipientCannotBeZeroAddress();
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            /**
             * @title ERC721 token receiver interface
             * @dev Interface for any contract that wants to support safeTransfers
             *      from ERC721 asset contracts.
             */
            interface IERC721Receiver {
                /**
                 * @dev Whenever an ERC721 token is transferred to this contract via
                 *      safeTransferFrom, this function is called.
                 *
                 * @param operator  The address of the operator.
                 * @param from      The address of the sender.
                 * @param tokenId   The ID of the ERC721.
                 * @param data      Additional data.
                 *
                 * @return bytes4 The magic value, unless throwing.
                 */
                function onERC721Received(
                    address operator,
                    address from,
                    uint256 tokenId,
                    bytes calldata data
                ) external returns (bytes4);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import { ConduitItemType } from "../conduit/lib/ConduitEnums.sol";
            /**
             * @dev A TransferHelperItem specifies the itemType (ERC20/ERC721/ERC1155),
             *      token address, token identifier, and amount of the token to be
             *      transferred via the TransferHelper. For ERC20 tokens, identifier
             *      must be 0. For ERC721 tokens, amount must be 1.
             */
            struct TransferHelperItem {
                ConduitItemType itemType;
                address token;
                uint256 identifier;
                uint256 amount;
            }
            /**
             * @dev A TransferHelperItemsWithRecipient specifies the tokens to transfer
             *      via the TransferHelper, their intended recipient, and a boolean flag
             *      indicating whether onERC721Received should be called on a recipient
             *      contract.
             */
            struct TransferHelperItemsWithRecipient {
                TransferHelperItem[] items;
                address recipient;
                bool validateERC721Receiver;
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import {
                TransferHelperItemsWithRecipient
            } from "../helpers/TransferHelperStructs.sol";
            interface TransferHelperInterface {
                /**
                 * @notice Transfer multiple items to a single recipient.
                 *
                 * @param items The items to transfer.
                 * @param conduitKey  The key of the conduit performing the bulk transfer.
                 */
                function bulkTransfer(
                    TransferHelperItemsWithRecipient[] calldata items,
                    bytes32 conduitKey
                ) external returns (bytes4);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            /**
             * @title TransferHelperErrors
             */
            interface TransferHelperErrors {
                /**
                 * @dev Revert with an error when attempting to execute transfers with a
                 *      NATIVE itemType.
                 */
                error InvalidItemType();
                /**
                 * @dev Revert with an error when an ERC721 transfer with amount other than
                 *      one is attempted.
                 *
                 * @param amount The amount of the ERC721 tokens to transfer.
                 */
                error InvalidERC721TransferAmount(uint256 amount);
                /**
                 * @dev Revert with an error when attempting to execute an ERC721 transfer
                 *      to an invalid recipient.
                 */
                error InvalidERC721Recipient(address recipient);
                /**
                 * @dev Revert with an error when a call to an ERC721 receiver reverts with
                 *      bytes data.
                 */
                error ERC721ReceiverErrorRevertBytes(
                    bytes reason,
                    address receiver,
                    address sender,
                    uint256 identifier
                );
                /**
                 * @dev Revert with an error when a call to an ERC721 receiver reverts with
                 *      string reason.
                 */
                error ERC721ReceiverErrorRevertString(
                    string reason,
                    address receiver,
                    address sender,
                    uint256 identifier
                );
                /**
                 * @dev Revert with an error when an ERC20 token has an invalid identifier.
                 */
                error InvalidERC20Identifier();
                /**
                 * @dev Revert with an error if the recipient is the zero address.
                 */
                error RecipientCannotBeZeroAddress();
                /**
                 * @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 a call to a conduit reverts with a
                 *      reason string.
                 */
                error ConduitErrorRevertString(
                    string reason,
                    bytes32 conduitKey,
                    address conduit
                );
                /**
                 * @dev Revert with an error when a call to a conduit reverts with bytes
                 *      data.
                 */
                error ConduitErrorRevertBytes(
                    bytes reason,
                    bytes32 conduitKey,
                    address conduit
                );
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            // 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 { IERC721Receiver } from "../interfaces/IERC721Receiver.sol";
            contract ERC721ReceiverMock is IERC721Receiver {
                enum Error {
                    None,
                    RevertWithMessage,
                    RevertWithoutMessage,
                    Panic
                }
                bytes4 private immutable _retval;
                Error private immutable _error;
                event Received(
                    address operator,
                    address from,
                    uint256 tokenId,
                    bytes data,
                    uint256 gas
                );
                constructor(bytes4 retval, Error error) {
                    _retval = retval;
                    _error = error;
                }
                function onERC721Received(
                    address operator,
                    address from,
                    uint256 tokenId,
                    bytes memory data
                ) public override returns (bytes4) {
                    if (_error == Error.RevertWithMessage) {
                        revert("ERC721ReceiverMock: reverting");
                    } else if (_error == Error.RevertWithoutMessage) {
                        revert();
                    } else if (_error == Error.Panic) {
                        uint256 a = uint256(0) / uint256(0);
                        a;
                    }
                    emit Received(operator, from, tokenId, data, gasleft());
                    return _retval;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.17;
            import { SpentItem, OfferItem } from "../../../lib/ConsiderationStructs.sol";
            import { ItemType } from "../../../lib/ConsiderationEnums.sol";
            import { StructCopier } from "./StructCopier.sol";
            library SpentItemLib {
                bytes32 private constant SPENT_ITEM_MAP_POSITION =
                    keccak256("seaport.SpentItemDefaults");
                bytes32 private constant SPENT_ITEMS_MAP_POSITION =
                    keccak256("seaport.SpentItemsDefaults");
                function empty() internal pure returns (SpentItem memory) {
                    return SpentItem(ItemType(0), address(0), 0, 0);
                }
                function clear(SpentItem storage item) internal {
                    // clear all fields
                    item.itemType = ItemType(0);
                    item.token = address(0);
                    item.identifier = 0;
                    item.amount = 0;
                }
                function clearMany(SpentItem[] storage items) internal {
                    while (items.length > 0) {
                        clear(items[items.length - 1]);
                        items.pop();
                    }
                }
                /**
                 * @notice clears a default SpentItem from storage
                 * @param defaultName the name of the default to clear
                 */
                function clear(string memory defaultName) internal {
                    mapping(string => SpentItem) storage spentItemMap = _spentItemMap();
                    SpentItem storage item = spentItemMap[defaultName];
                    clear(item);
                }
                function clearMany(string memory defaultsName) internal {
                    mapping(string => SpentItem[]) storage spentItemsMap = _spentItemsMap();
                    SpentItem[] storage items = spentItemsMap[defaultsName];
                    clearMany(items);
                }
                /**
                 * @notice gets a default SpentItem from storage
                 * @param defaultName the name of the default for retrieval
                 */
                function fromDefault(
                    string memory defaultName
                ) internal view returns (SpentItem memory item) {
                    mapping(string => SpentItem) storage spentItemMap = _spentItemMap();
                    item = spentItemMap[defaultName];
                }
                function fromDefaultMany(
                    string memory defaultsName
                ) internal view returns (SpentItem[] memory items) {
                    mapping(string => SpentItem[]) storage spentItemsMap = _spentItemsMap();
                    items = spentItemsMap[defaultsName];
                }
                /**
                 * @notice saves an SpentItem as a named default
                 * @param spentItem the SpentItem to save as a default
                 * @param defaultName the name of the default for retrieval
                 */
                function saveDefault(
                    SpentItem memory spentItem,
                    string memory defaultName
                ) internal returns (SpentItem memory _spentItem) {
                    mapping(string => SpentItem) storage spentItemMap = _spentItemMap();
                    spentItemMap[defaultName] = spentItem;
                    return spentItem;
                }
                function saveDefaultMany(
                    SpentItem[] memory spentItems,
                    string memory defaultsName
                ) internal returns (SpentItem[] memory _spentItems) {
                    mapping(string => SpentItem[]) storage spentItemsMap = _spentItemsMap();
                    SpentItem[] storage items = spentItemsMap[defaultsName];
                    setSpentItems(items, spentItems);
                    return spentItems;
                }
                function setSpentItems(
                    SpentItem[] storage items,
                    SpentItem[] memory newItems
                ) internal {
                    clearMany(items);
                    for (uint256 i = 0; i < newItems.length; i++) {
                        items.push(newItems[i]);
                    }
                }
                /**
                 * @notice makes a copy of an SpentItem in-memory
                 * @param item the SpentItem to make a copy of in-memory
                 */
                function copy(
                    SpentItem memory item
                ) internal pure returns (SpentItem memory) {
                    return
                        SpentItem({
                            itemType: item.itemType,
                            token: item.token,
                            identifier: item.identifier,
                            amount: item.amount
                        });
                }
                function copy(
                    SpentItem[] memory items
                ) internal pure returns (SpentItem[] memory) {
                    SpentItem[] memory copiedItems = new SpentItem[](items.length);
                    for (uint256 i = 0; i < items.length; i++) {
                        copiedItems[i] = copy(items[i]);
                    }
                    return copiedItems;
                }
                /**
                 * @notice gets the storage position of the default SpentItem map
                 */
                function _spentItemMap()
                    private
                    pure
                    returns (mapping(string => SpentItem) storage spentItemMap)
                {
                    bytes32 position = SPENT_ITEM_MAP_POSITION;
                    assembly {
                        spentItemMap.slot := position
                    }
                }
                function _spentItemsMap()
                    private
                    pure
                    returns (mapping(string => SpentItem[]) storage spentItemsMap)
                {
                    bytes32 position = SPENT_ITEMS_MAP_POSITION;
                    assembly {
                        spentItemsMap.slot := position
                    }
                }
                // methods for configuring a single of each of an SpentItem's fields, which modifies the SpentItem in-place and
                // returns it
                /**
                 * @notice sets the item type
                 * @param item the SpentItem to modify
                 * @param itemType the item type to set
                 * @return the modified SpentItem
                 */
                function withItemType(
                    SpentItem memory item,
                    ItemType itemType
                ) internal pure returns (SpentItem memory) {
                    item.itemType = itemType;
                    return item;
                }
                /**
                 * @notice sets the token address
                 * @param item the SpentItem to modify
                 * @param token the token address to set
                 * @return the modified SpentItem
                 */
                function withToken(
                    SpentItem memory item,
                    address token
                ) internal pure returns (SpentItem memory) {
                    item.token = token;
                    return item;
                }
                /**
                 * @notice sets the identifier or criteria
                 * @param item the SpentItem to modify
                 * @param identifier the identifier or criteria to set
                 * @return the modified SpentItem
                 */
                function withIdentifier(
                    SpentItem memory item,
                    uint256 identifier
                ) internal pure returns (SpentItem memory) {
                    item.identifier = identifier;
                    return item;
                }
                /**
                 * @notice sets the start amount
                 * @param item the SpentItem to modify
                 * @param amount the start amount to set
                 * @return the modified SpentItem
                 */
                function withAmount(
                    SpentItem memory item,
                    uint256 amount
                ) internal pure returns (SpentItem memory) {
                    item.amount = amount;
                    return item;
                }
                function toOfferItem(
                    SpentItem memory item
                ) internal pure returns (OfferItem memory) {
                    return
                        OfferItem({
                            itemType: item.itemType,
                            token: item.token,
                            identifierOrCriteria: item.identifier,
                            startAmount: item.amount,
                            endAmount: item.amount
                        });
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import {
                BasicOrderParameters,
                CriteriaResolver,
                AdvancedOrder,
                AdditionalRecipient,
                OfferItem,
                Order,
                ConsiderationItem,
                Fulfillment,
                FulfillmentComponent,
                OrderParameters,
                OrderComponents,
                Execution
            } from "../../../lib/ConsiderationStructs.sol";
            import {
                ConsiderationInterface
            } from "../../../interfaces/ConsiderationInterface.sol";
            import { ArrayLib } from "./ArrayLib.sol";
            library StructCopier {
                function _basicOrderParameters()
                    private
                    pure
                    returns (BasicOrderParameters storage empty)
                {
                    bytes32 position = keccak256("StructCopier.EmptyBasicOrderParameters");
                    assembly {
                        empty.slot := position
                    }
                    return empty;
                }
                function _criteriaResolver()
                    private
                    pure
                    returns (CriteriaResolver storage empty)
                {
                    bytes32 position = keccak256("StructCopier.EmptyCriteriaResolver");
                    assembly {
                        empty.slot := position
                    }
                    return empty;
                }
                function _fulfillment() private pure returns (Fulfillment storage empty) {
                    bytes32 position = keccak256("StructCopier.EmptyFulfillment");
                    assembly {
                        empty.slot := position
                    }
                    return empty;
                }
                function _orderComponents()
                    private
                    pure
                    returns (OrderComponents storage empty)
                {
                    bytes32 position = keccak256("StructCopier.EmptyOrderComponents");
                    assembly {
                        empty.slot := position
                    }
                    return empty;
                }
                function _orderParameters()
                    private
                    pure
                    returns (OrderParameters storage empty)
                {
                    bytes32 position = keccak256("StructCopier.EmptyOrderParameters");
                    assembly {
                        empty.slot := position
                    }
                    return empty;
                }
                function _order() private pure returns (Order storage empty) {
                    bytes32 position = keccak256("StructCopier.EmptyOrder");
                    assembly {
                        empty.slot := position
                    }
                    return empty;
                }
                function setBasicOrderParameters(
                    BasicOrderParameters storage dest,
                    BasicOrderParameters memory src
                ) internal {
                    dest.considerationToken = src.considerationToken;
                    dest.considerationIdentifier = src.considerationIdentifier;
                    dest.considerationAmount = src.considerationAmount;
                    dest.offerer = src.offerer;
                    dest.zone = src.zone;
                    dest.offerToken = src.offerToken;
                    dest.offerIdentifier = src.offerIdentifier;
                    dest.offerAmount = src.offerAmount;
                    dest.basicOrderType = src.basicOrderType;
                    dest.startTime = src.startTime;
                    dest.endTime = src.endTime;
                    dest.zoneHash = src.zoneHash;
                    dest.salt = src.salt;
                    dest.offererConduitKey = src.offererConduitKey;
                    dest.fulfillerConduitKey = src.fulfillerConduitKey;
                    dest.totalOriginalAdditionalRecipients = src
                        .totalOriginalAdditionalRecipients;
                    setAdditionalRecipients(
                        dest.additionalRecipients,
                        src.additionalRecipients
                    );
                    dest.signature = src.signature;
                }
                function setOrderComponents(
                    OrderComponents storage dest,
                    OrderComponents memory src
                ) internal {
                    dest.offerer = src.offerer;
                    dest.zone = src.zone;
                    setOfferItems(dest.offer, src.offer);
                    setConsiderationItems(dest.consideration, src.consideration);
                    dest.orderType = src.orderType;
                    dest.startTime = src.startTime;
                    dest.endTime = src.endTime;
                    dest.zoneHash = src.zoneHash;
                    dest.salt = src.salt;
                    dest.conduitKey = src.conduitKey;
                    dest.counter = src.counter;
                }
                function setOrderComponents(
                    OrderComponents[] storage dest,
                    OrderComponents[] memory src
                ) internal {
                    while (dest.length != 0) {
                        dest.pop();
                    }
                    OrderComponents storage empty = _orderComponents();
                    for (uint256 i = 0; i < src.length; ++i) {
                        dest.push(empty);
                        setOrderComponents(dest[i], src[i]);
                    }
                }
                function setBasicOrderParameters(
                    BasicOrderParameters[] storage dest,
                    BasicOrderParameters[] memory src
                ) internal {
                    while (dest.length != 0) {
                        dest.pop();
                    }
                    BasicOrderParameters storage empty = _basicOrderParameters();
                    for (uint256 i = 0; i < src.length; ++i) {
                        dest.push(empty);
                        setBasicOrderParameters(dest[i], src[i]);
                    }
                }
                function setAdditionalRecipients(
                    AdditionalRecipient[] storage dest,
                    AdditionalRecipient[] memory src
                ) internal {
                    while (dest.length != 0) {
                        dest.pop();
                    }
                    for (uint256 i = 0; i < src.length; ++i) {
                        dest.push(src[i]);
                    }
                }
                function setCriteriaResolver(
                    CriteriaResolver storage dest,
                    CriteriaResolver memory src
                ) internal {
                    dest.orderIndex = src.orderIndex;
                    dest.side = src.side;
                    dest.index = src.index;
                    dest.identifier = src.identifier;
                    ArrayLib.setBytes32s(dest.criteriaProof, src.criteriaProof);
                }
                function setCriteriaResolvers(
                    CriteriaResolver[] storage dest,
                    CriteriaResolver[] memory src
                ) internal {
                    while (dest.length != 0) {
                        dest.pop();
                    }
                    CriteriaResolver storage empty = _criteriaResolver();
                    for (uint256 i = 0; i < src.length; ++i) {
                        dest.push(empty);
                        setCriteriaResolver(dest[i], src[i]);
                    }
                }
                function setOrder(Order storage dest, Order memory src) internal {
                    setOrderParameters(dest.parameters, src.parameters);
                    dest.signature = src.signature;
                }
                bytes32 constant TEMP_ORDER = keccak256("seaport-sol.temp.Order");
                bytes32 constant TEMP_COUNTER_SLOT = keccak256("seaport-sol.temp.Counter");
                /**
                 * @notice Get a counter used to derive a temporary storage slot.
                 * @dev    Solidity does not allow copying dynamic types from memory to storage.
                 *         We need a "clean" (empty) temp pointer to make an exact copy of a struct with dynamic members, but
                 *         Solidity does not allow calling "delete" on a storage pointer either.
                 *         By hashing a struct's temp slot with a monotonically increasing counter, we can derive a new temp slot
                 *         that is basically "guaranteed" to have all successive storage slots empty.
                 *         TODO: We can revisit adding "clear" methods that definitively wipe all dynamic components of a struct,
                 *         but that will require an equal amount of SSTOREs; this is obviously more expensive gas-wise, but may not
                 *         make a difference performance-wise when running simiulations locally (though this needs to be tested)
                 */
                function _getAndIncrementTempCounter() internal returns (uint256 counter) {
                    // get counter slot
                    bytes32 counterSlot = TEMP_COUNTER_SLOT;
                    assembly {
                        // load current value
                        counter := sload(counterSlot)
                        // store incremented value
                        sstore(counterSlot, add(counter, 1))
                    }
                    // return original value
                    return counter;
                }
                function _deriveTempSlotWithCounter(
                    bytes32 libSlot
                ) internal returns (uint256 derivedSlot) {
                    uint256 counter = _getAndIncrementTempCounter();
                    assembly {
                        // store lib slot in first mem position
                        mstore(0x0, libSlot)
                        // store temp counter in second position
                        mstore(0x20, counter)
                        // hash original slot with counter to get new temp slot, which has a low probability of being dirty
                        // (~1/2**256)
                        derivedSlot := keccak256(0x0, 0x40)
                    }
                }
                function _getTempOrder() internal returns (Order storage _tempOrder) {
                    uint256 position = _deriveTempSlotWithCounter(TEMP_ORDER);
                    assembly {
                        _tempOrder.slot := position
                    }
                }
                function setOrders(Order[] storage dest, Order[] memory src) internal {
                    while (dest.length != 0) {
                        dest.pop();
                    }
                    Order storage empty = _order();
                    for (uint256 i = 0; i < src.length; ++i) {
                        dest.push(empty);
                        setOrder(dest[i], src[i]);
                    }
                }
                function setAdvancedOrder(
                    AdvancedOrder storage dest,
                    AdvancedOrder memory src
                ) internal {
                    setOrderParameters(dest.parameters, src.parameters);
                    dest.numerator = src.numerator;
                    dest.denominator = src.denominator;
                    dest.signature = src.signature;
                    dest.extraData = src.extraData;
                }
                bytes32 constant TEMP_ADVANCED_ORDER =
                    keccak256("seaport-sol.temp.AdvancedOrder");
                function _getTempAdvancedOrder()
                    internal
                    returns (AdvancedOrder storage _tempAdvancedOrder)
                {
                    uint256 position = _deriveTempSlotWithCounter(TEMP_ADVANCED_ORDER);
                    assembly {
                        _tempAdvancedOrder.slot := position
                    }
                }
                function setAdvancedOrders(
                    AdvancedOrder[] storage dest,
                    AdvancedOrder[] memory src
                ) internal {
                    AdvancedOrder storage _tempAdvancedOrder = _getTempAdvancedOrder();
                    while (dest.length != 0) {
                        dest.pop();
                    }
                    for (uint256 i = 0; i < src.length; ++i) {
                        setAdvancedOrder(_tempAdvancedOrder, src[i]);
                        dest.push(_tempAdvancedOrder);
                    }
                }
                function setOrderParameters(
                    OrderParameters storage dest,
                    OrderParameters memory src
                ) internal {
                    dest.offerer = src.offerer;
                    dest.zone = src.zone;
                    setOfferItems(dest.offer, src.offer);
                    setConsiderationItems(dest.consideration, src.consideration);
                    dest.orderType = src.orderType;
                    dest.startTime = src.startTime;
                    dest.endTime = src.endTime;
                    dest.zoneHash = src.zoneHash;
                    dest.salt = src.salt;
                    dest.conduitKey = src.conduitKey;
                    dest.totalOriginalConsiderationItems = src
                        .totalOriginalConsiderationItems;
                }
                function setOfferItems(
                    OfferItem[] storage dest,
                    OfferItem[] memory src
                ) internal {
                    while (dest.length != 0) {
                        dest.pop();
                    }
                    for (uint256 i = 0; i < src.length; ++i) {
                        dest.push(src[i]);
                    }
                }
                function setConsiderationItems(
                    ConsiderationItem[] storage dest,
                    ConsiderationItem[] memory src
                ) internal {
                    while (dest.length != 0) {
                        dest.pop();
                    }
                    for (uint256 i = 0; i < src.length; ++i) {
                        dest.push(src[i]);
                    }
                }
                function setFulfillment(
                    Fulfillment storage dest,
                    Fulfillment memory src
                ) internal {
                    setFulfillmentComponents(dest.offerComponents, src.offerComponents);
                    setFulfillmentComponents(
                        dest.considerationComponents,
                        src.considerationComponents
                    );
                }
                function setFulfillments(
                    Fulfillment[] storage dest,
                    Fulfillment[] memory src
                ) internal {
                    while (dest.length != 0) {
                        dest.pop();
                    }
                    Fulfillment storage empty = _fulfillment();
                    for (uint256 i = 0; i < src.length; ++i) {
                        dest.push(empty);
                        setFulfillment(dest[i], src[i]);
                    }
                }
                function setFulfillmentComponents(
                    FulfillmentComponent[] storage dest,
                    FulfillmentComponent[] memory src
                ) internal {
                    while (dest.length != 0) {
                        dest.pop();
                    }
                    for (uint256 i = 0; i < src.length; ++i) {
                        dest.push(src[i]);
                    }
                }
                bytes32 constant TEMP_FULFILLMENT_COMPONENTS =
                    keccak256("seaport-sol.temp.FulfillmentComponents");
                function _getTempFulfillmentComponents()
                    internal
                    pure
                    returns (FulfillmentComponent[] storage _tempFulfillmentComponents)
                {
                    bytes32 position = TEMP_FULFILLMENT_COMPONENTS;
                    assembly {
                        _tempFulfillmentComponents.slot := position
                    }
                }
                function pushFulFillmentComponents(
                    FulfillmentComponent[][] storage dest,
                    FulfillmentComponent[] memory src
                ) internal {
                    FulfillmentComponent[]
                        storage _tempFulfillmentComponents = _getTempFulfillmentComponents();
                    setFulfillmentComponents(_tempFulfillmentComponents, src);
                    dest.push(_tempFulfillmentComponents);
                }
                function setFulfillmentComponentsArray(
                    FulfillmentComponent[][] storage dest,
                    FulfillmentComponent[][] memory src
                ) internal {
                    while (dest.length != 0) {
                        dest.pop();
                    }
                    for (uint256 i = 0; i < src.length; ++i) {
                        pushFulFillmentComponents(dest, src[i]);
                    }
                }
                function toConsiderationItems(
                    OfferItem[] memory _offerItems,
                    address payable receiver
                ) internal pure returns (ConsiderationItem[] memory) {
                    ConsiderationItem[] memory considerationItems = new ConsiderationItem[](
                        _offerItems.length
                    );
                    for (uint256 i = 0; i < _offerItems.length; ++i) {
                        considerationItems[i] = ConsiderationItem(
                            _offerItems[i].itemType,
                            _offerItems[i].token,
                            _offerItems[i].identifierOrCriteria,
                            _offerItems[i].startAmount,
                            _offerItems[i].endAmount,
                            receiver
                        );
                    }
                    return considerationItems;
                }
                function toOfferItems(
                    ConsiderationItem[] memory _considerationItems
                ) internal pure returns (OfferItem[] memory) {
                    OfferItem[] memory _offerItems = new OfferItem[](
                        _considerationItems.length
                    );
                    for (uint256 i = 0; i < _offerItems.length; i++) {
                        _offerItems[i] = OfferItem(
                            _considerationItems[i].itemType,
                            _considerationItems[i].token,
                            _considerationItems[i].identifierOrCriteria,
                            _considerationItems[i].startAmount,
                            _considerationItems[i].endAmount
                        );
                    }
                    return _offerItems;
                }
                function createMirrorOrderParameters(
                    OrderParameters memory orderParameters,
                    address payable offerer,
                    address zone,
                    bytes32 conduitKey
                ) public pure returns (OrderParameters memory) {
                    OfferItem[] memory _offerItems = toOfferItems(
                        orderParameters.consideration
                    );
                    ConsiderationItem[] memory _considerationItems = toConsiderationItems(
                        orderParameters.offer,
                        offerer
                    );
                    OrderParameters memory _mirrorOrderParameters = OrderParameters(
                        offerer,
                        zone,
                        _offerItems,
                        _considerationItems,
                        orderParameters.orderType,
                        orderParameters.startTime,
                        orderParameters.endTime,
                        orderParameters.zoneHash,
                        orderParameters.salt,
                        conduitKey,
                        _considerationItems.length
                    );
                    return _mirrorOrderParameters;
                }
                function setExecutions(
                    Execution[] storage dest,
                    Execution[] memory src
                ) internal {
                    while (dest.length != 0) {
                        dest.pop();
                    }
                    for (uint256 i = 0; i < src.length; ++i) {
                        dest.push(src[i]);
                    }
                }
                function setOrderParameters(
                    OrderParameters[] storage dest,
                    OrderParameters[] memory src
                ) internal {
                    while (dest.length != 0) {
                        dest.pop();
                    }
                    OrderParameters storage empty = _orderParameters();
                    for (uint256 i = 0; i < src.length; ++i) {
                        dest.push(empty);
                        setOrderParameters(dest[i], src[i]);
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.17;
            library ArrayLib {
                function setBytes32s(
                    bytes32[] storage array,
                    bytes32[] memory values
                ) internal {
                    while (array.length > 0) {
                        array.pop();
                    }
                    for (uint256 i = 0; i < values.length; i++) {
                        array.push(values[i]);
                    }
                }
                function copy(
                    bytes32[] memory array
                ) internal pure returns (bytes32[] memory) {
                    bytes32[] memory copiedArray = new bytes32[](array.length);
                    for (uint256 i = 0; i < array.length; i++) {
                        copiedArray[i] = array[i];
                    }
                    return copiedArray;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.17;
            import { AdditionalRecipientLib } from "./AdditionalRecipientLib.sol";
            import { AdvancedOrderLib } from "./AdvancedOrderLib.sol";
            import { ArrayLib } from "./ArrayLib.sol";
            import { BasicOrderParametersLib } from "./BasicOrderParametersLib.sol";
            import { ConsiderationItemLib } from "./ConsiderationItemLib.sol";
            import { CriteriaResolverLib } from "./CriteriaResolverLib.sol";
            import { ExecutionLib } from "./ExecutionLib.sol";
            import { FulfillmentComponentLib } from "./FulfillmentComponentLib.sol";
            import { FulfillmentLib } from "./FulfillmentLib.sol";
            import { OfferItemLib } from "./OfferItemLib.sol";
            import { OrderComponentsLib } from "./OrderComponentsLib.sol";
            import { OrderLib } from "./OrderLib.sol";
            import { OrderParametersLib } from "./OrderParametersLib.sol";
            import { ReceivedItemLib } from "./ReceivedItemLib.sol";
            import { SpentItemLib } from "./SpentItemLib.sol";
            import { StructCopier } from "./StructCopier.sol";
            import { SeaportArrays } from "./SeaportArrays.sol";
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.17;
            import { AdditionalRecipient } from "../../../lib/ConsiderationStructs.sol";
            import { StructCopier } from "./StructCopier.sol";
            library AdditionalRecipientLib {
                bytes32 private constant ADDITIONAL_RECIPIENT_MAP_POSITION =
                    keccak256("seaport.AdditionalRecipientDefaults");
                bytes32 private constant ADDITIONAL_RECIPIENTS_MAP_POSITION =
                    keccak256("seaport.AdditionalRecipientsDefaults");
                /**
                 * @notice clears a default AdditionalRecipient from storage
                 * @param defaultName the name of the default to clear
                 */
                function clear(string memory defaultName) internal {
                    mapping(string => AdditionalRecipient)
                        storage additionalRecipientMap = _additionalRecipientMap();
                    AdditionalRecipient storage item = additionalRecipientMap[defaultName];
                    clear(item);
                }
                function clear(AdditionalRecipient storage item) internal {
                    // clear all fields
                    item.amount = 0;
                    item.recipient = payable(address(0));
                }
                function clear(AdditionalRecipient[] storage item) internal {
                    while (item.length > 0) {
                        clear(item[item.length - 1]);
                        item.pop();
                    }
                }
                /**
                 * @notice gets a default AdditionalRecipient from storage
                 * @param defaultName the name of the default for retrieval
                 */
                function fromDefault(
                    string memory defaultName
                ) internal view returns (AdditionalRecipient memory item) {
                    mapping(string => AdditionalRecipient)
                        storage additionalRecipientMap = _additionalRecipientMap();
                    item = additionalRecipientMap[defaultName];
                }
                function fromDefaultMany(
                    string memory defaultName
                ) internal view returns (AdditionalRecipient[] memory items) {
                    mapping(string => AdditionalRecipient[])
                        storage additionalRecipientsMap = _additionalRecipientsMap();
                    items = additionalRecipientsMap[defaultName];
                }
                /**
                 * @notice saves an AdditionalRecipient as a named default
                 * @param additionalRecipient the AdditionalRecipient to save as a default
                 * @param defaultName the name of the default for retrieval
                 */
                function saveDefault(
                    AdditionalRecipient memory additionalRecipient,
                    string memory defaultName
                ) internal returns (AdditionalRecipient memory _additionalRecipient) {
                    mapping(string => AdditionalRecipient)
                        storage additionalRecipientMap = _additionalRecipientMap();
                    additionalRecipientMap[defaultName] = additionalRecipient;
                    return additionalRecipient;
                }
                function saveDefaultMany(
                    AdditionalRecipient[] memory additionalRecipients,
                    string memory defaultName
                ) internal returns (AdditionalRecipient[] memory _additionalRecipients) {
                    mapping(string => AdditionalRecipient[])
                        storage additionalRecipientsMap = _additionalRecipientsMap();
                    StructCopier.setAdditionalRecipients(
                        additionalRecipientsMap[defaultName],
                        additionalRecipients
                    );
                    return additionalRecipients;
                }
                /**
                 * @notice makes a copy of an AdditionalRecipient in-memory
                 * @param item the AdditionalRecipient to make a copy of in-memory
                 */
                function copy(
                    AdditionalRecipient memory item
                ) internal pure returns (AdditionalRecipient memory) {
                    return
                        AdditionalRecipient({
                            amount: item.amount,
                            recipient: item.recipient
                        });
                }
                function copy(
                    AdditionalRecipient[] memory items
                ) internal pure returns (AdditionalRecipient[] memory) {
                    AdditionalRecipient[] memory copiedItems = new AdditionalRecipient[](
                        items.length
                    );
                    for (uint256 i = 0; i < items.length; i++) {
                        copiedItems[i] = copy(items[i]);
                    }
                    return copiedItems;
                }
                function empty() internal pure returns (AdditionalRecipient memory) {
                    return
                        AdditionalRecipient({ amount: 0, recipient: payable(address(0)) });
                }
                /**
                 * @notice gets the storage position of the default AdditionalRecipient map
                 */
                function _additionalRecipientMap()
                    private
                    pure
                    returns (
                        mapping(string => AdditionalRecipient)
                            storage additionalRecipientMap
                    )
                {
                    bytes32 position = ADDITIONAL_RECIPIENT_MAP_POSITION;
                    assembly {
                        additionalRecipientMap.slot := position
                    }
                }
                function _additionalRecipientsMap()
                    private
                    pure
                    returns (
                        mapping(string => AdditionalRecipient[])
                            storage additionalRecipientsMap
                    )
                {
                    bytes32 position = ADDITIONAL_RECIPIENTS_MAP_POSITION;
                    assembly {
                        additionalRecipientsMap.slot := position
                    }
                }
                // methods for configuring a single of each of an AdditionalRecipient's fields, which modifies the
                // AdditionalRecipient in-place and
                // returns it
                function withAmount(
                    AdditionalRecipient memory item,
                    uint256 amount
                ) internal pure returns (AdditionalRecipient memory) {
                    item.amount = amount;
                    return item;
                }
                function withRecipient(
                    AdditionalRecipient memory item,
                    address recipient
                ) internal pure returns (AdditionalRecipient memory) {
                    item.recipient = payable(recipient);
                    return item;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.17;
            import {
                AdvancedOrder,
                Order,
                OrderParameters
            } from "../../../lib/ConsiderationStructs.sol";
            import { OrderParametersLib } from "./OrderParametersLib.sol";
            import { StructCopier } from "./StructCopier.sol";
            library AdvancedOrderLib {
                bytes32 private constant ADVANCED_ORDER_MAP_POSITION =
                    keccak256("seaport.AdvancedOrderDefaults");
                bytes32 private constant ADVANCED_ORDERS_MAP_POSITION =
                    keccak256("seaport.AdvancedOrdersDefaults");
                using OrderParametersLib for OrderParameters;
                /**
                 * @notice clears a default AdvancedOrder from storage
                 * @param defaultName the name of the default to clear
                 */
                function clear(string memory defaultName) internal {
                    mapping(string => AdvancedOrder)
                        storage advancedOrderMap = _advancedOrderMap();
                    AdvancedOrder storage item = advancedOrderMap[defaultName];
                    clear(item);
                }
                function clear(AdvancedOrder storage item) internal {
                    // clear all fields
                    item.parameters.clear();
                    item.signature = "";
                    item.numerator = 0;
                    item.denominator = 0;
                    item.extraData = "";
                }
                function clear(AdvancedOrder[] storage items) internal {
                    while (items.length > 0) {
                        clear(items[items.length - 1]);
                        items.pop();
                    }
                }
                /**
                 * @notice gets a default AdvancedOrder from storage
                 * @param defaultName the name of the default for retrieval
                 */
                function fromDefault(
                    string memory defaultName
                ) internal view returns (AdvancedOrder memory item) {
                    mapping(string => AdvancedOrder)
                        storage advancedOrderMap = _advancedOrderMap();
                    item = advancedOrderMap[defaultName];
                }
                function fromDefaultMany(
                    string memory defaultName
                ) internal view returns (AdvancedOrder[] memory items) {
                    mapping(string => AdvancedOrder[])
                        storage advancedOrdersMap = _advancedOrdersMap();
                    items = advancedOrdersMap[defaultName];
                }
                function empty() internal pure returns (AdvancedOrder memory) {
                    return AdvancedOrder(OrderParametersLib.empty(), 0, 0, "", "");
                }
                /**
                 * @notice saves an AdvancedOrder as a named default
                 * @param advancedOrder the AdvancedOrder to save as a default
                 * @param defaultName the name of the default for retrieval
                 */
                function saveDefault(
                    AdvancedOrder memory advancedOrder,
                    string memory defaultName
                ) internal returns (AdvancedOrder memory _advancedOrder) {
                    mapping(string => AdvancedOrder)
                        storage advancedOrderMap = _advancedOrderMap();
                    StructCopier.setAdvancedOrder(
                        advancedOrderMap[defaultName],
                        advancedOrder
                    );
                    return advancedOrder;
                }
                function saveDefaultMany(
                    AdvancedOrder[] memory advancedOrders,
                    string memory defaultName
                ) internal returns (AdvancedOrder[] memory _advancedOrders) {
                    mapping(string => AdvancedOrder[])
                        storage advancedOrdersMap = _advancedOrdersMap();
                    StructCopier.setAdvancedOrders(
                        advancedOrdersMap[defaultName],
                        advancedOrders
                    );
                    return advancedOrders;
                }
                /**
                 * @notice makes a copy of an AdvancedOrder in-memory
                 * @param item the AdvancedOrder to make a copy of in-memory
                 */
                function copy(
                    AdvancedOrder memory item
                ) internal pure returns (AdvancedOrder memory) {
                    return
                        AdvancedOrder({
                            parameters: item.parameters.copy(),
                            numerator: item.numerator,
                            denominator: item.denominator,
                            signature: item.signature,
                            extraData: item.extraData
                        });
                }
                function copy(
                    AdvancedOrder[] memory items
                ) internal pure returns (AdvancedOrder[] memory) {
                    AdvancedOrder[] memory copiedItems = new AdvancedOrder[](items.length);
                    for (uint256 i = 0; i < items.length; i++) {
                        copiedItems[i] = copy(items[i]);
                    }
                    return copiedItems;
                }
                /**
                 * @notice gets the storage position of the default AdvancedOrder map
                 */
                function _advancedOrderMap()
                    private
                    pure
                    returns (mapping(string => AdvancedOrder) storage advancedOrderMap)
                {
                    bytes32 position = ADVANCED_ORDER_MAP_POSITION;
                    assembly {
                        advancedOrderMap.slot := position
                    }
                }
                function _advancedOrdersMap()
                    private
                    pure
                    returns (mapping(string => AdvancedOrder[]) storage advancedOrdersMap)
                {
                    bytes32 position = ADVANCED_ORDERS_MAP_POSITION;
                    assembly {
                        advancedOrdersMap.slot := position
                    }
                }
                // methods for configuring a single of each of an AdvancedOrder's fields, which modifies the AdvancedOrder in-place
                // and
                // returns it
                function withParameters(
                    AdvancedOrder memory advancedOrder,
                    OrderParameters memory parameters
                ) internal pure returns (AdvancedOrder memory) {
                    advancedOrder.parameters = parameters.copy();
                    return advancedOrder;
                }
                function withNumerator(
                    AdvancedOrder memory advancedOrder,
                    uint120 numerator
                ) internal pure returns (AdvancedOrder memory) {
                    advancedOrder.numerator = numerator;
                    return advancedOrder;
                }
                function withDenominator(
                    AdvancedOrder memory advancedOrder,
                    uint120 denominator
                ) internal pure returns (AdvancedOrder memory) {
                    advancedOrder.denominator = denominator;
                    return advancedOrder;
                }
                function withSignature(
                    AdvancedOrder memory advancedOrder,
                    bytes memory signature
                ) internal pure returns (AdvancedOrder memory) {
                    advancedOrder.signature = signature;
                    return advancedOrder;
                }
                function withExtraData(
                    AdvancedOrder memory advancedOrder,
                    bytes memory extraData
                ) internal pure returns (AdvancedOrder memory) {
                    advancedOrder.extraData = extraData;
                    return advancedOrder;
                }
                function toOrder(
                    AdvancedOrder memory advancedOrder
                ) internal pure returns (Order memory order) {
                    order.parameters = advancedOrder.parameters.copy();
                    order.signature = advancedOrder.signature;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.17;
            import {
                BasicOrderParameters,
                OrderComponents,
                OrderParameters,
                ConsiderationItem,
                OrderParameters,
                OfferItem,
                AdditionalRecipient
            } from "../../../lib/ConsiderationStructs.sol";
            import {
                OrderType,
                ItemType,
                BasicOrderType
            } from "../../../lib/ConsiderationEnums.sol";
            import { StructCopier } from "./StructCopier.sol";
            import { AdditionalRecipientLib } from "./AdditionalRecipientLib.sol";
            library BasicOrderParametersLib {
                using BasicOrderParametersLib for BasicOrderParameters;
                using AdditionalRecipientLib for AdditionalRecipient[];
                bytes32 private constant BASIC_ORDER_PARAMETERS_MAP_POSITION =
                    keccak256("seaport.BasicOrderParametersDefaults");
                bytes32 private constant BASIC_ORDER_PARAMETERS_ARRAY_MAP_POSITION =
                    keccak256("seaport.BasicOrderParametersArrayDefaults");
                function clear(BasicOrderParameters storage basicParameters) internal {
                    // uninitialized pointers take up no new memory (versus one word for initializing length-0)
                    AdditionalRecipient[] memory additionalRecipients;
                    basicParameters.considerationToken = address(0);
                    basicParameters.considerationIdentifier = 0;
                    basicParameters.considerationAmount = 0;
                    basicParameters.offerer = payable(address(0));
                    basicParameters.zone = address(0);
                    basicParameters.offerToken = address(0);
                    basicParameters.offerIdentifier = 0;
                    basicParameters.offerAmount = 0;
                    basicParameters.basicOrderType = BasicOrderType(0);
                    basicParameters.startTime = 0;
                    basicParameters.endTime = 0;
                    basicParameters.zoneHash = bytes32(0);
                    basicParameters.salt = 0;
                    basicParameters.offererConduitKey = bytes32(0);
                    basicParameters.fulfillerConduitKey = bytes32(0);
                    basicParameters.totalOriginalAdditionalRecipients = 0;
                    StructCopier.setAdditionalRecipients(
                        basicParameters.additionalRecipients,
                        additionalRecipients
                    );
                    basicParameters.signature = new bytes(0);
                }
                function clear(
                    BasicOrderParameters[] storage basicParametersArray
                ) internal {
                    while (basicParametersArray.length > 0) {
                        basicParametersArray[basicParametersArray.length - 1].clear();
                        basicParametersArray.pop();
                    }
                }
                /**
                 * @notice clears a default BasicOrderParameters from storage
                 * @param defaultName the name of the default to clear
                 */
                function clear(string memory defaultName) internal {
                    mapping(string => BasicOrderParameters)
                        storage orderComponentsMap = _orderComponentsMap();
                    BasicOrderParameters storage basicParameters = orderComponentsMap[
                        defaultName
                    ];
                    basicParameters.clear();
                }
                function empty() internal pure returns (BasicOrderParameters memory item) {
                    AdditionalRecipient[] memory additionalRecipients;
                    item = BasicOrderParameters({
                        considerationToken: address(0),
                        considerationIdentifier: 0,
                        considerationAmount: 0,
                        offerer: payable(address(0)),
                        zone: address(0),
                        offerToken: address(0),
                        offerIdentifier: 0,
                        offerAmount: 0,
                        basicOrderType: BasicOrderType(0),
                        startTime: 0,
                        endTime: 0,
                        zoneHash: bytes32(0),
                        salt: 0,
                        offererConduitKey: bytes32(0),
                        fulfillerConduitKey: bytes32(0),
                        totalOriginalAdditionalRecipients: 0,
                        additionalRecipients: additionalRecipients,
                        signature: new bytes(0)
                    });
                }
                /**
                 * @notice gets a default BasicOrderParameters from storage
                 * @param defaultName the name of the default for retrieval
                 */
                function fromDefault(
                    string memory defaultName
                ) internal view returns (BasicOrderParameters memory item) {
                    mapping(string => BasicOrderParameters)
                        storage orderComponentsMap = _orderComponentsMap();
                    item = orderComponentsMap[defaultName];
                }
                function fromDefaultMany(
                    string memory defaultName
                ) internal view returns (BasicOrderParameters[] memory items) {
                    mapping(string => BasicOrderParameters[])
                        storage orderComponentsArrayMap = _orderComponentsArrayMap();
                    items = orderComponentsArrayMap[defaultName];
                }
                /**
                 * @notice saves an BasicOrderParameters as a named default
                 * @param orderComponents the BasicOrderParameters to save as a default
                 * @param defaultName the name of the default for retrieval
                 */
                function saveDefault(
                    BasicOrderParameters memory orderComponents,
                    string memory defaultName
                ) internal returns (BasicOrderParameters memory _orderComponents) {
                    mapping(string => BasicOrderParameters)
                        storage orderComponentsMap = _orderComponentsMap();
                    BasicOrderParameters storage destination = orderComponentsMap[
                        defaultName
                    ];
                    StructCopier.setBasicOrderParameters(destination, orderComponents);
                    return orderComponents;
                }
                function saveDefaultMany(
                    BasicOrderParameters[] memory orderComponents,
                    string memory defaultName
                ) internal returns (BasicOrderParameters[] memory _orderComponents) {
                    mapping(string => BasicOrderParameters[])
                        storage orderComponentsArrayMap = _orderComponentsArrayMap();
                    BasicOrderParameters[] storage destination = orderComponentsArrayMap[
                        defaultName
                    ];
                    StructCopier.setBasicOrderParameters(destination, orderComponents);
                    return orderComponents;
                }
                /**
                 * @notice makes a copy of an BasicOrderParameters in-memory
                 * @param item the BasicOrderParameters to make a copy of in-memory
                 */
                function copy(
                    BasicOrderParameters memory item
                ) internal pure returns (BasicOrderParameters memory) {
                    return
                        BasicOrderParameters({
                            considerationToken: item.considerationToken,
                            considerationIdentifier: item.considerationIdentifier,
                            considerationAmount: item.considerationAmount,
                            offerer: item.offerer,
                            zone: item.zone,
                            offerToken: item.offerToken,
                            offerIdentifier: item.offerIdentifier,
                            offerAmount: item.offerAmount,
                            basicOrderType: item.basicOrderType,
                            startTime: item.startTime,
                            endTime: item.endTime,
                            zoneHash: item.zoneHash,
                            salt: item.salt,
                            offererConduitKey: item.offererConduitKey,
                            fulfillerConduitKey: item.fulfillerConduitKey,
                            totalOriginalAdditionalRecipients: item
                                .totalOriginalAdditionalRecipients,
                            additionalRecipients: item.additionalRecipients.copy(),
                            signature: item.signature
                        });
                }
                /**
                 * @notice gets the storage position of the default BasicOrderParameters map
                 */
                function _orderComponentsMap()
                    private
                    pure
                    returns (
                        mapping(string => BasicOrderParameters) storage orderComponentsMap
                    )
                {
                    bytes32 position = BASIC_ORDER_PARAMETERS_MAP_POSITION;
                    assembly {
                        orderComponentsMap.slot := position
                    }
                }
                function _orderComponentsArrayMap()
                    private
                    pure
                    returns (
                        mapping(string => BasicOrderParameters[])
                            storage orderComponentsArrayMap
                    )
                {
                    bytes32 position = BASIC_ORDER_PARAMETERS_ARRAY_MAP_POSITION;
                    assembly {
                        orderComponentsArrayMap.slot := position
                    }
                }
                // methods for configuring a single of each of an in-memory BasicOrderParameters's fields, which modifies the
                // BasicOrderParameters in-memory and returns it
                function withConsiderationToken(
                    BasicOrderParameters memory item,
                    address value
                ) internal pure returns (BasicOrderParameters memory) {
                    item.considerationToken = value;
                    return item;
                }
                function withConsiderationIdentifier(
                    BasicOrderParameters memory item,
                    uint256 value
                ) internal pure returns (BasicOrderParameters memory) {
                    item.considerationIdentifier = value;
                    return item;
                }
                function withConsiderationAmount(
                    BasicOrderParameters memory item,
                    uint256 value
                ) internal pure returns (BasicOrderParameters memory) {
                    item.considerationAmount = value;
                    return item;
                }
                function withOfferer(
                    BasicOrderParameters memory item,
                    address value
                ) internal pure returns (BasicOrderParameters memory) {
                    item.offerer = payable(value);
                    return item;
                }
                function withZone(
                    BasicOrderParameters memory item,
                    address value
                ) internal pure returns (BasicOrderParameters memory) {
                    item.zone = value;
                    return item;
                }
                function withOfferToken(
                    BasicOrderParameters memory item,
                    address value
                ) internal pure returns (BasicOrderParameters memory) {
                    item.offerToken = value;
                    return item;
                }
                function withOfferIdentifier(
                    BasicOrderParameters memory item,
                    uint256 value
                ) internal pure returns (BasicOrderParameters memory) {
                    item.offerIdentifier = value;
                    return item;
                }
                function withOfferAmount(
                    BasicOrderParameters memory item,
                    uint256 value
                ) internal pure returns (BasicOrderParameters memory) {
                    item.offerAmount = value;
                    return item;
                }
                function withBasicOrderType(
                    BasicOrderParameters memory item,
                    BasicOrderType value
                ) internal pure returns (BasicOrderParameters memory) {
                    item.basicOrderType = value;
                    return item;
                }
                function withStartTime(
                    BasicOrderParameters memory item,
                    uint256 value
                ) internal pure returns (BasicOrderParameters memory) {
                    item.startTime = value;
                    return item;
                }
                function withEndTime(
                    BasicOrderParameters memory item,
                    uint256 value
                ) internal pure returns (BasicOrderParameters memory) {
                    item.endTime = value;
                    return item;
                }
                function withZoneHash(
                    BasicOrderParameters memory item,
                    bytes32 value
                ) internal pure returns (BasicOrderParameters memory) {
                    item.zoneHash = value;
                    return item;
                }
                function withSalt(
                    BasicOrderParameters memory item,
                    uint256 value
                ) internal pure returns (BasicOrderParameters memory) {
                    item.salt = value;
                    return item;
                }
                function withOffererConduitKey(
                    BasicOrderParameters memory item,
                    bytes32 value
                ) internal pure returns (BasicOrderParameters memory) {
                    item.offererConduitKey = value;
                    return item;
                }
                function withFulfillerConduitKey(
                    BasicOrderParameters memory item,
                    bytes32 value
                ) internal pure returns (BasicOrderParameters memory) {
                    item.fulfillerConduitKey = value;
                    return item;
                }
                function withTotalOriginalAdditionalRecipients(
                    BasicOrderParameters memory item,
                    uint256 value
                ) internal pure returns (BasicOrderParameters memory) {
                    item.totalOriginalAdditionalRecipients = value;
                    return item;
                }
                function withAdditionalRecipients(
                    BasicOrderParameters memory item,
                    AdditionalRecipient[] memory value
                ) internal pure returns (BasicOrderParameters memory) {
                    item.additionalRecipients = value;
                    return item;
                }
                function withSignature(
                    BasicOrderParameters memory item,
                    bytes memory value
                ) internal pure returns (BasicOrderParameters memory) {
                    item.signature = value;
                    return item;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.17;
            import {
                ConsiderationItem,
                ReceivedItem
            } from "../../../lib/ConsiderationStructs.sol";
            import { ItemType } from "../../../lib/ConsiderationEnums.sol";
            import { StructCopier } from "./StructCopier.sol";
            library ConsiderationItemLib {
                bytes32 private constant CONSIDERATION_ITEM_MAP_POSITION =
                    keccak256("seaport.ConsiderationItemDefaults");
                bytes32 private constant CONSIDERATION_ITEMS_MAP_POSITION =
                    keccak256("seaport.ConsiderationItemsDefaults");
                function _clear(ConsiderationItem storage item) internal {
                    // clear all fields
                    item.itemType = ItemType.NATIVE;
                    item.token = address(0);
                    item.identifierOrCriteria = 0;
                    item.startAmount = 0;
                    item.endAmount = 0;
                    item.recipient = payable(address(0));
                }
                /**
                 * @notice clears a default ConsiderationItem from storage
                 * @param defaultName the name of the default to clear
                 */
                function clear(string memory defaultName) internal {
                    mapping(string => ConsiderationItem)
                        storage considerationItemMap = _considerationItemMap();
                    ConsiderationItem storage item = considerationItemMap[defaultName];
                    _clear(item);
                }
                function clearMany(string memory defaultsName) internal {
                    mapping(string => ConsiderationItem[])
                        storage considerationItemsMap = _considerationItemsMap();
                    ConsiderationItem[] storage items = considerationItemsMap[defaultsName];
                    while (items.length > 0) {
                        _clear(items[items.length - 1]);
                        items.pop();
                    }
                }
                /**
                 * @notice gets a default ConsiderationItem from storage
                 * @param defaultName the name of the default for retrieval
                 */
                function fromDefault(
                    string memory defaultName
                ) internal view returns (ConsiderationItem memory item) {
                    mapping(string => ConsiderationItem)
                        storage considerationItemMap = _considerationItemMap();
                    item = considerationItemMap[defaultName];
                }
                function fromDefaultMany(
                    string memory defaultsName
                ) internal view returns (ConsiderationItem[] memory items) {
                    mapping(string => ConsiderationItem[])
                        storage considerationItemsMap = _considerationItemsMap();
                    items = considerationItemsMap[defaultsName];
                }
                function empty() internal pure returns (ConsiderationItem memory) {
                    return
                        ConsiderationItem({
                            itemType: ItemType(0),
                            token: address(0),
                            identifierOrCriteria: 0,
                            startAmount: 0,
                            endAmount: 0,
                            recipient: payable(address(0))
                        });
                }
                /**
                 * @notice saves an ConsiderationItem as a named default
                 * @param considerationItem the ConsiderationItem to save as a default
                 * @param defaultName the name of the default for retrieval
                 */
                function saveDefault(
                    ConsiderationItem memory considerationItem,
                    string memory defaultName
                ) internal returns (ConsiderationItem memory _considerationItem) {
                    mapping(string => ConsiderationItem)
                        storage considerationItemMap = _considerationItemMap();
                    considerationItemMap[defaultName] = considerationItem;
                    return considerationItem;
                }
                function saveDefaultMany(
                    ConsiderationItem[] memory considerationItems,
                    string memory defaultsName
                ) internal returns (ConsiderationItem[] memory _considerationItems) {
                    mapping(string => ConsiderationItem[])
                        storage considerationItemsMap = _considerationItemsMap();
                    ConsiderationItem[] storage items = considerationItemsMap[defaultsName];
                    clearMany(defaultsName);
                    StructCopier.setConsiderationItems(items, considerationItems);
                    return considerationItems;
                }
                /**
                 * @notice makes a copy of an ConsiderationItem in-memory
                 * @param item the ConsiderationItem to make a copy of in-memory
                 */
                function copy(
                    ConsiderationItem memory item
                ) internal pure returns (ConsiderationItem memory) {
                    return
                        ConsiderationItem({
                            itemType: item.itemType,
                            token: item.token,
                            identifierOrCriteria: item.identifierOrCriteria,
                            startAmount: item.startAmount,
                            endAmount: item.endAmount,
                            recipient: item.recipient
                        });
                }
                function copy(
                    ConsiderationItem[] memory item
                ) internal pure returns (ConsiderationItem[] memory) {
                    ConsiderationItem[] memory copies = new ConsiderationItem[](
                        item.length
                    );
                    for (uint256 i = 0; i < item.length; i++) {
                        copies[i] = ConsiderationItem({
                            itemType: item[i].itemType,
                            token: item[i].token,
                            identifierOrCriteria: item[i].identifierOrCriteria,
                            startAmount: item[i].startAmount,
                            endAmount: item[i].endAmount,
                            recipient: item[i].recipient
                        });
                    }
                    return copies;
                }
                /**
                 * @notice gets the storage position of the default ConsiderationItem map
                 */
                function _considerationItemMap()
                    private
                    pure
                    returns (
                        mapping(string => ConsiderationItem) storage considerationItemMap
                    )
                {
                    bytes32 position = CONSIDERATION_ITEM_MAP_POSITION;
                    assembly {
                        considerationItemMap.slot := position
                    }
                }
                function _considerationItemsMap()
                    private
                    pure
                    returns (
                        mapping(string => ConsiderationItem[]) storage considerationItemsMap
                    )
                {
                    bytes32 position = CONSIDERATION_ITEMS_MAP_POSITION;
                    assembly {
                        considerationItemsMap.slot := position
                    }
                }
                // methods for configuring a single of each of an ConsiderationItem's fields, which modifies the ConsiderationItem
                // in-place and
                // returns it
                /**
                 * @notice sets the item type
                 * @param item the ConsiderationItem to modify
                 * @param itemType the item type to set
                 * @return the modified ConsiderationItem
                 */
                function withItemType(
                    ConsiderationItem memory item,
                    ItemType itemType
                ) internal pure returns (ConsiderationItem memory) {
                    item.itemType = itemType;
                    return item;
                }
                /**
                 * @notice sets the token address
                 * @param item the ConsiderationItem to modify
                 * @param token the token address to set
                 * @return the modified ConsiderationItem
                 */
                function withToken(
                    ConsiderationItem memory item,
                    address token
                ) internal pure returns (ConsiderationItem memory) {
                    item.token = token;
                    return item;
                }
                /**
                 * @notice sets the identifier or criteria
                 * @param item the ConsiderationItem to modify
                 * @param identifierOrCriteria the identifier or criteria to set
                 * @return the modified ConsiderationItem
                 */
                function withIdentifierOrCriteria(
                    ConsiderationItem memory item,
                    uint256 identifierOrCriteria
                ) internal pure returns (ConsiderationItem memory) {
                    item.identifierOrCriteria = identifierOrCriteria;
                    return item;
                }
                /**
                 * @notice sets the start amount
                 * @param item the ConsiderationItem to modify
                 * @param startAmount the start amount to set
                 * @return the modified ConsiderationItem
                 */
                function withStartAmount(
                    ConsiderationItem memory item,
                    uint256 startAmount
                ) internal pure returns (ConsiderationItem memory) {
                    item.startAmount = startAmount;
                    return item;
                }
                /**
                 * @notice sets the end amount
                 * @param item the ConsiderationItem to modify
                 * @param endAmount the end amount to set
                 * @return the modified ConsiderationItem
                 */
                function withEndAmount(
                    ConsiderationItem memory item,
                    uint256 endAmount
                ) internal pure returns (ConsiderationItem memory) {
                    item.endAmount = endAmount;
                    return item;
                }
                /**
                 * @notice sets the recipient
                 * @param item the ConsiderationItem to modify
                 * @param recipient the recipient to set
                 * @return the modified ConsiderationItem
                 */
                function withRecipient(
                    ConsiderationItem memory item,
                    address recipient
                ) internal pure returns (ConsiderationItem memory) {
                    item.recipient = payable(recipient);
                    return item;
                }
                function toReceivedItem(
                    ConsiderationItem memory item
                ) internal pure returns (ReceivedItem memory) {
                    return
                        ReceivedItem({
                            itemType: item.itemType,
                            token: item.token,
                            identifier: item.identifierOrCriteria,
                            amount: item.startAmount,
                            recipient: item.recipient
                        });
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.17;
            import {
                CriteriaResolver,
                OfferItem
            } from "../../../lib/ConsiderationStructs.sol";
            import { Side } from "../../../lib/ConsiderationEnums.sol";
            import { ArrayLib } from "./ArrayLib.sol";
            import { StructCopier } from "./StructCopier.sol";
            library CriteriaResolverLib {
                bytes32 private constant CRITERIA_RESOLVER_MAP_POSITION =
                    keccak256("seaport.CriteriaResolverDefaults");
                bytes32 private constant CRITERIA_RESOLVERS_MAP_POSITION =
                    keccak256("seaport.CriteriaResolversDefaults");
                using ArrayLib for bytes32[];
                /**
                 * @notice clears a default CriteriaResolver from storage
                 * @param defaultName the name of the default to clear
                 */
                function clear(string memory defaultName) internal {
                    mapping(string => CriteriaResolver)
                        storage criteriaResolverMap = _criteriaResolverMap();
                    CriteriaResolver storage resolver = criteriaResolverMap[defaultName];
                    // clear all fields
                    clear(resolver);
                }
                function clear(CriteriaResolver storage resolver) internal {
                    bytes32[] memory criteriaProof;
                    resolver.orderIndex = 0;
                    resolver.side = Side(0);
                    resolver.index = 0;
                    resolver.identifier = 0;
                    ArrayLib.setBytes32s(resolver.criteriaProof, criteriaProof);
                }
                function clear(CriteriaResolver[] storage resolvers) internal {
                    while (resolvers.length > 0) {
                        clear(resolvers[resolvers.length - 1]);
                        resolvers.pop();
                    }
                }
                /**
                 * @notice gets a default CriteriaResolver from storage
                 * @param defaultName the name of the default for retrieval
                 */
                function fromDefault(
                    string memory defaultName
                ) internal view returns (CriteriaResolver memory resolver) {
                    mapping(string => CriteriaResolver)
                        storage criteriaResolverMap = _criteriaResolverMap();
                    resolver = criteriaResolverMap[defaultName];
                }
                function fromDefaultMany(
                    string memory defaultsName
                ) internal view returns (CriteriaResolver[] memory resolvers) {
                    mapping(string => CriteriaResolver[])
                        storage criteriaResolversMap = _criteriaResolversMap();
                    resolvers = criteriaResolversMap[defaultsName];
                }
                /**
                 * @notice saves an CriteriaResolver as a named default
                 * @param criteriaResolver the CriteriaResolver to save as a default
                 * @param defaultName the name of the default for retrieval
                 */
                function saveDefault(
                    CriteriaResolver memory criteriaResolver,
                    string memory defaultName
                ) internal returns (CriteriaResolver memory _criteriaResolver) {
                    mapping(string => CriteriaResolver)
                        storage criteriaResolverMap = _criteriaResolverMap();
                    CriteriaResolver storage resolver = criteriaResolverMap[defaultName];
                    resolver.orderIndex = criteriaResolver.orderIndex;
                    resolver.side = criteriaResolver.side;
                    resolver.index = criteriaResolver.index;
                    resolver.identifier = criteriaResolver.identifier;
                    ArrayLib.setBytes32s(
                        resolver.criteriaProof,
                        criteriaResolver.criteriaProof
                    );
                    return criteriaResolver;
                }
                function saveDefaultMany(
                    CriteriaResolver[] memory criteriaResolvers,
                    string memory defaultName
                ) internal returns (CriteriaResolver[] memory _criteriaResolvers) {
                    mapping(string => CriteriaResolver[])
                        storage criteriaResolversMap = _criteriaResolversMap();
                    CriteriaResolver[] storage resolvers = criteriaResolversMap[
                        defaultName
                    ];
                    // todo: make sure we do this elsewhere
                    clear(resolvers);
                    StructCopier.setCriteriaResolvers(resolvers, criteriaResolvers);
                    return criteriaResolvers;
                }
                /**
                 * @notice makes a copy of an CriteriaResolver in-memory
                 * @param resolver the CriteriaResolver to make a copy of in-memory
                 */
                function copy(
                    CriteriaResolver memory resolver
                ) internal pure returns (CriteriaResolver memory) {
                    return
                        CriteriaResolver({
                            orderIndex: resolver.orderIndex,
                            side: resolver.side,
                            index: resolver.index,
                            identifier: resolver.identifier,
                            criteriaProof: resolver.criteriaProof.copy()
                        });
                }
                function copy(
                    CriteriaResolver[] memory resolvers
                ) internal pure returns (CriteriaResolver[] memory) {
                    CriteriaResolver[] memory copiedItems = new CriteriaResolver[](
                        resolvers.length
                    );
                    for (uint256 i = 0; i < resolvers.length; i++) {
                        copiedItems[i] = copy(resolvers[i]);
                    }
                    return copiedItems;
                }
                function empty() internal pure returns (CriteriaResolver memory) {
                    bytes32[] memory proof;
                    return
                        CriteriaResolver({
                            orderIndex: 0,
                            side: Side(0),
                            index: 0,
                            identifier: 0,
                            criteriaProof: proof
                        });
                }
                /**
                 * @notice gets the storage position of the default CriteriaResolver map
                 */
                function _criteriaResolverMap()
                    private
                    pure
                    returns (
                        mapping(string => CriteriaResolver) storage criteriaResolverMap
                    )
                {
                    bytes32 position = CRITERIA_RESOLVER_MAP_POSITION;
                    assembly {
                        criteriaResolverMap.slot := position
                    }
                }
                function _criteriaResolversMap()
                    private
                    pure
                    returns (
                        mapping(string => CriteriaResolver[]) storage criteriaResolversMap
                    )
                {
                    bytes32 position = CRITERIA_RESOLVERS_MAP_POSITION;
                    assembly {
                        criteriaResolversMap.slot := position
                    }
                }
                // methods for configuring a single of each of an CriteriaResolver's fields, which modifies the CriteriaResolver
                // in-place and
                // returns it
                function withOrderIndex(
                    CriteriaResolver memory resolver,
                    uint256 orderIndex
                ) internal pure returns (CriteriaResolver memory) {
                    resolver.orderIndex = orderIndex;
                    return resolver;
                }
                function withSide(
                    CriteriaResolver memory resolver,
                    Side side
                ) internal pure returns (CriteriaResolver memory) {
                    resolver.side = side;
                    return resolver;
                }
                function withIndex(
                    CriteriaResolver memory resolver,
                    uint256 index
                ) internal pure returns (CriteriaResolver memory) {
                    resolver.index = index;
                    return resolver;
                }
                function withIdentifier(
                    CriteriaResolver memory resolver,
                    uint256 identifier
                ) internal pure returns (CriteriaResolver memory) {
                    resolver.identifier = identifier;
                    return resolver;
                }
                function withCriteriaProof(
                    CriteriaResolver memory resolver,
                    bytes32[] memory criteriaProof
                ) internal pure returns (CriteriaResolver memory) {
                    // todo: consider copying?
                    resolver.criteriaProof = criteriaProof;
                    return resolver;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.17;
            import { Execution, ReceivedItem } from "../../../lib/ConsiderationStructs.sol";
            import { ReceivedItemLib } from "./ReceivedItemLib.sol";
            import { StructCopier } from "./StructCopier.sol";
            library ExecutionLib {
                bytes32 private constant EXECUTION_MAP_POSITION =
                    keccak256("seaport.ExecutionDefaults");
                bytes32 private constant EXECUTIONS_MAP_POSITION =
                    keccak256("seaport.ExecutionsDefaults");
                using ReceivedItemLib for ReceivedItem;
                using ReceivedItemLib for ReceivedItem[];
                /**
                 * @notice clears a default Execution from storage
                 * @param defaultName the name of the default to clear
                 */
                function clear(string memory defaultName) internal {
                    mapping(string => Execution) storage executionMap = _executionMap();
                    Execution storage item = executionMap[defaultName];
                    clear(item);
                }
                function clear(Execution storage execution) internal {
                    // clear all fields
                    execution.item = ReceivedItemLib.empty();
                    execution.offerer = address(0);
                    execution.conduitKey = bytes32(0);
                }
                function clear(Execution[] storage executions) internal {
                    while (executions.length > 0) {
                        clear(executions[executions.length - 1]);
                        executions.pop();
                    }
                }
                /**
                 * @notice gets a default Execution from storage
                 * @param defaultName the name of the default for retrieval
                 */
                function fromDefault(
                    string memory defaultName
                ) internal view returns (Execution memory item) {
                    mapping(string => Execution) storage executionMap = _executionMap();
                    item = executionMap[defaultName];
                }
                function fromDefaultMany(
                    string memory defaultName
                ) internal view returns (Execution[] memory items) {
                    mapping(string => Execution[]) storage executionsMap = _executionsMap();
                    items = executionsMap[defaultName];
                }
                /**
                 * @notice saves an Execution as a named default
                 * @param execution the Execution to save as a default
                 * @param defaultName the name of the default for retrieval
                 */
                function saveDefault(
                    Execution memory execution,
                    string memory defaultName
                ) internal returns (Execution memory _execution) {
                    mapping(string => Execution) storage executionMap = _executionMap();
                    executionMap[defaultName] = execution;
                    return execution;
                }
                function saveDefaultMany(
                    Execution[] memory executions,
                    string memory defaultName
                ) internal returns (Execution[] memory _executions) {
                    mapping(string => Execution[]) storage executionsMap = _executionsMap();
                    StructCopier.setExecutions(executionsMap[defaultName], executions);
                    return executions;
                }
                /**
                 * @notice makes a copy of an Execution in-memory
                 * @param item the Execution to make a copy of in-memory
                 */
                function copy(
                    Execution memory item
                ) internal pure returns (Execution memory) {
                    return
                        Execution({
                            item: item.item.copy(),
                            offerer: item.offerer,
                            conduitKey: item.conduitKey
                        });
                }
                function copy(
                    Execution[] memory item
                ) internal pure returns (Execution[] memory) {
                    Execution[] memory copies = new Execution[](item.length);
                    for (uint256 i = 0; i < item.length; i++) {
                        copies[i] = copy(item[i]);
                    }
                    return copies;
                }
                function empty() internal pure returns (Execution memory) {
                    return
                        Execution({
                            item: ReceivedItemLib.empty(),
                            offerer: address(0),
                            conduitKey: bytes32(0)
                        });
                }
                /**
                 * @notice gets the storage position of the default Execution map
                 */
                function _executionMap()
                    private
                    pure
                    returns (mapping(string => Execution) storage executionMap)
                {
                    bytes32 position = EXECUTION_MAP_POSITION;
                    assembly {
                        executionMap.slot := position
                    }
                }
                function _executionsMap()
                    private
                    pure
                    returns (mapping(string => Execution[]) storage executionsMap)
                {
                    bytes32 position = EXECUTIONS_MAP_POSITION;
                    assembly {
                        executionsMap.slot := position
                    }
                }
                // methods for configuring a single of each of an Execution's fields, which modifies the Execution
                // in-place and
                // returns it
                function withItem(
                    Execution memory execution,
                    ReceivedItem memory item
                ) internal pure returns (Execution memory) {
                    execution.item = item.copy();
                    return execution;
                }
                function withOfferer(
                    Execution memory execution,
                    address offerer
                ) internal pure returns (Execution memory) {
                    execution.offerer = offerer;
                    return execution;
                }
                function withConduitKey(
                    Execution memory execution,
                    bytes32 conduitKey
                ) internal pure returns (Execution memory) {
                    execution.conduitKey = conduitKey;
                    return execution;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.17;
            import {
                FulfillmentComponent,
                OfferItem
            } from "../../../lib/ConsiderationStructs.sol";
            import { Side } from "../../../lib/ConsiderationEnums.sol";
            import { ArrayLib } from "./ArrayLib.sol";
            import { StructCopier } from "./StructCopier.sol";
            library FulfillmentComponentLib {
                bytes32 private constant FULFILLMENT_COMPONENT_MAP_POSITION =
                    keccak256("seaport.FulfillmentComponentDefaults");
                bytes32 private constant FULFILLMENT_COMPONENTS_MAP_POSITION =
                    keccak256("seaport.FulfillmentComponentsDefaults");
                using ArrayLib for bytes32[];
                /**
                 * @notice clears a default FulfillmentComponent from storage
                 * @param defaultName the name of the default to clear
                 */
                function clear(string memory defaultName) internal {
                    mapping(string => FulfillmentComponent)
                        storage fulfillmentComponentMap = _fulfillmentComponentMap();
                    FulfillmentComponent storage component = fulfillmentComponentMap[
                        defaultName
                    ];
                    clear(component);
                }
                function clear(FulfillmentComponent storage component) internal {
                    component.orderIndex = 0;
                    component.itemIndex = 0;
                }
                function clear(FulfillmentComponent[] storage components) internal {
                    while (components.length > 0) {
                        clear(components[components.length - 1]);
                        components.pop();
                    }
                }
                /**
                 * @notice gets a default FulfillmentComponent from storage
                 * @param defaultName the name of the default for retrieval
                 */
                function fromDefault(
                    string memory defaultName
                ) internal view returns (FulfillmentComponent memory component) {
                    mapping(string => FulfillmentComponent)
                        storage fulfillmentComponentMap = _fulfillmentComponentMap();
                    component = fulfillmentComponentMap[defaultName];
                }
                function fromDefaultMany(
                    string memory defaultName
                ) internal view returns (FulfillmentComponent[] memory components) {
                    mapping(string => FulfillmentComponent[])
                        storage fulfillmentComponentMap = _fulfillmentComponentsMap();
                    components = fulfillmentComponentMap[defaultName];
                }
                /**
                 * @notice saves an FulfillmentComponent as a named default
                 * @param fulfillmentComponent the FulfillmentComponent to save as a default
                 * @param defaultName the name of the default for retrieval
                 */
                function saveDefault(
                    FulfillmentComponent memory fulfillmentComponent,
                    string memory defaultName
                ) internal returns (FulfillmentComponent memory _fulfillmentComponent) {
                    mapping(string => FulfillmentComponent)
                        storage fulfillmentComponentMap = _fulfillmentComponentMap();
                    FulfillmentComponent storage component = fulfillmentComponentMap[
                        defaultName
                    ];
                    component.orderIndex = fulfillmentComponent.orderIndex;
                    component.itemIndex = fulfillmentComponent.itemIndex;
                    return fulfillmentComponent;
                }
                function saveDefaultMany(
                    FulfillmentComponent[] memory fulfillmentComponents,
                    string memory defaultName
                ) internal returns (FulfillmentComponent[] memory _fulfillmentComponents) {
                    mapping(string => FulfillmentComponent[])
                        storage fulfillmentComponentsMap = _fulfillmentComponentsMap();
                    FulfillmentComponent[] storage components = fulfillmentComponentsMap[
                        defaultName
                    ];
                    clear(components);
                    StructCopier.setFulfillmentComponents(
                        components,
                        fulfillmentComponents
                    );
                    return fulfillmentComponents;
                }
                /**
                 * @notice makes a copy of an FulfillmentComponent in-memory
                 * @param component the FulfillmentComponent to make a copy of in-memory
                 */
                function copy(
                    FulfillmentComponent memory component
                ) internal pure returns (FulfillmentComponent memory) {
                    return
                        FulfillmentComponent({
                            orderIndex: component.orderIndex,
                            itemIndex: component.itemIndex
                        });
                }
                function copy(
                    FulfillmentComponent[] memory components
                ) internal pure returns (FulfillmentComponent[] memory) {
                    FulfillmentComponent[] memory copiedItems = new FulfillmentComponent[](
                        components.length
                    );
                    for (uint256 i = 0; i < components.length; i++) {
                        copiedItems[i] = copy(components[i]);
                    }
                    return copiedItems;
                }
                function empty() internal pure returns (FulfillmentComponent memory) {
                    return FulfillmentComponent({ orderIndex: 0, itemIndex: 0 });
                }
                /**
                 * @notice gets the storage position of the default FulfillmentComponent map
                 */
                function _fulfillmentComponentMap()
                    private
                    pure
                    returns (
                        mapping(string => FulfillmentComponent)
                            storage fulfillmentComponentMap
                    )
                {
                    bytes32 position = FULFILLMENT_COMPONENT_MAP_POSITION;
                    assembly {
                        fulfillmentComponentMap.slot := position
                    }
                }
                function _fulfillmentComponentsMap()
                    private
                    pure
                    returns (
                        mapping(string => FulfillmentComponent[])
                            storage fulfillmentComponentsMap
                    )
                {
                    bytes32 position = FULFILLMENT_COMPONENTS_MAP_POSITION;
                    assembly {
                        fulfillmentComponentsMap.slot := position
                    }
                }
                // methods for configuring a single of each of an FulfillmentComponent's fields, which modifies the
                // FulfillmentComponent
                // in-place and
                // returns it
                function withOrderIndex(
                    FulfillmentComponent memory component,
                    uint256 orderIndex
                ) internal pure returns (FulfillmentComponent memory) {
                    component.orderIndex = orderIndex;
                    return component;
                }
                function withItemIndex(
                    FulfillmentComponent memory component,
                    uint256 itemIndex
                ) internal pure returns (FulfillmentComponent memory) {
                    component.itemIndex = itemIndex;
                    return component;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.17;
            import {
                Fulfillment,
                FulfillmentComponent
            } from "../../../lib/ConsiderationStructs.sol";
            import { Side } from "../../../lib/ConsiderationEnums.sol";
            import { ArrayLib } from "./ArrayLib.sol";
            import { FulfillmentComponentLib } from "./FulfillmentComponentLib.sol";
            import { StructCopier } from "./StructCopier.sol";
            library FulfillmentLib {
                bytes32 private constant FULFILLMENT_MAP_POSITION =
                    keccak256("seaport.FulfillmentDefaults");
                bytes32 private constant FULFILLMENTS_MAP_POSITION =
                    keccak256("seaport.FulfillmentsDefaults");
                using FulfillmentComponentLib for FulfillmentComponent[];
                using StructCopier for FulfillmentComponent[];
                /**
                 * @notice clears a default Fulfillment from storage
                 * @param defaultName the name of the default to clear
                 */
                function clear(string memory defaultName) internal {
                    mapping(string => Fulfillment)
                        storage fulfillmentMap = _fulfillmentMap();
                    Fulfillment storage _fulfillment = fulfillmentMap[defaultName];
                    // clear all fields
                    FulfillmentComponent[] memory components;
                    _fulfillment.offerComponents.setFulfillmentComponents(components);
                    _fulfillment.considerationComponents.setFulfillmentComponents(
                        components
                    );
                }
                /**
                 * @notice gets a default Fulfillment from storage
                 * @param defaultName the name of the default for retrieval
                 */
                function fromDefault(
                    string memory defaultName
                ) internal view returns (Fulfillment memory _fulfillment) {
                    mapping(string => Fulfillment)
                        storage fulfillmentMap = _fulfillmentMap();
                    _fulfillment = fulfillmentMap[defaultName];
                }
                function fromDefaultMany(
                    string memory defaultName
                ) internal view returns (Fulfillment[] memory _fulfillments) {
                    mapping(string => Fulfillment[])
                        storage fulfillmentsMap = _fulfillmentsMap();
                    _fulfillments = fulfillmentsMap[defaultName];
                }
                /**
                 * @notice saves an Fulfillment as a named default
                 * @param fulfillment the Fulfillment to save as a default
                 * @param defaultName the name of the default for retrieval
                 */
                function saveDefault(
                    Fulfillment memory fulfillment,
                    string memory defaultName
                ) internal returns (Fulfillment memory _fulfillment) {
                    mapping(string => Fulfillment)
                        storage fulfillmentMap = _fulfillmentMap();
                    StructCopier.setFulfillment(fulfillmentMap[defaultName], fulfillment);
                    return fulfillment;
                }
                function saveDefaultMany(
                    Fulfillment[] memory fulfillments,
                    string memory defaultName
                ) internal returns (Fulfillment[] memory _fulfillments) {
                    mapping(string => Fulfillment[])
                        storage fulfillmentsMap = _fulfillmentsMap();
                    StructCopier.setFulfillments(
                        fulfillmentsMap[defaultName],
                        fulfillments
                    );
                    return fulfillments;
                }
                /**
                 * @notice makes a copy of an Fulfillment in-memory
                 * @param _fulfillment the Fulfillment to make a copy of in-memory
                 */
                function copy(
                    Fulfillment memory _fulfillment
                ) internal pure returns (Fulfillment memory) {
                    return
                        Fulfillment({
                            offerComponents: _fulfillment.offerComponents.copy(),
                            considerationComponents: _fulfillment
                                .considerationComponents
                                .copy()
                        });
                }
                function copy(
                    Fulfillment[] memory _fulfillments
                ) internal pure returns (Fulfillment[] memory) {
                    Fulfillment[] memory copiedItems = new Fulfillment[](
                        _fulfillments.length
                    );
                    for (uint256 i = 0; i < _fulfillments.length; i++) {
                        copiedItems[i] = copy(_fulfillments[i]);
                    }
                    return copiedItems;
                }
                function empty() internal pure returns (Fulfillment memory) {
                    FulfillmentComponent[] memory components;
                    return
                        Fulfillment({
                            offerComponents: components,
                            considerationComponents: components
                        });
                }
                /**
                 * @notice gets the storage position of the default Fulfillment map
                 */
                function _fulfillmentMap()
                    private
                    pure
                    returns (mapping(string => Fulfillment) storage fulfillmentMap)
                {
                    bytes32 position = FULFILLMENT_MAP_POSITION;
                    assembly {
                        fulfillmentMap.slot := position
                    }
                }
                function _fulfillmentsMap()
                    private
                    pure
                    returns (mapping(string => Fulfillment[]) storage fulfillmentsMap)
                {
                    bytes32 position = FULFILLMENTS_MAP_POSITION;
                    assembly {
                        fulfillmentsMap.slot := position
                    }
                }
                // methods for configuring a single of each of an Fulfillment's fields, which modifies the
                // Fulfillment
                // in-place and
                // returns it
                function withOfferComponents(
                    Fulfillment memory _fulfillment,
                    FulfillmentComponent[] memory components
                ) internal pure returns (Fulfillment memory) {
                    _fulfillment.offerComponents = components.copy();
                    return _fulfillment;
                }
                function withConsiderationComponents(
                    Fulfillment memory _fulfillment,
                    FulfillmentComponent[] memory components
                ) internal pure returns (Fulfillment memory) {
                    _fulfillment.considerationComponents = components.copy();
                    return _fulfillment;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.17;
            import { OfferItem, SpentItem } from "../../../lib/ConsiderationStructs.sol";
            import { ItemType } from "../../../lib/ConsiderationEnums.sol";
            import { StructCopier } from "./StructCopier.sol";
            library OfferItemLib {
                bytes32 private constant OFFER_ITEM_MAP_POSITION =
                    keccak256("seaport.OfferItemDefaults");
                bytes32 private constant OFFER_ITEMS_MAP_POSITION =
                    keccak256("seaport.OfferItemsDefaults");
                function _clear(OfferItem storage item) internal {
                    // clear all fields
                    item.itemType = ItemType.NATIVE;
                    item.token = address(0);
                    item.identifierOrCriteria = 0;
                    item.startAmount = 0;
                    item.endAmount = 0;
                }
                /**
                 * @notice clears a default OfferItem from storage
                 * @param defaultName the name of the default to clear
                 */
                function clear(string memory defaultName) internal {
                    mapping(string => OfferItem) storage offerItemMap = _offerItemMap();
                    OfferItem storage item = offerItemMap[defaultName];
                    _clear(item);
                }
                function clearMany(string memory defaultsName) internal {
                    mapping(string => OfferItem[]) storage offerItemsMap = _offerItemsMap();
                    OfferItem[] storage items = offerItemsMap[defaultsName];
                    while (items.length > 0) {
                        _clear(items[items.length - 1]);
                        items.pop();
                    }
                }
                /**
                 * @notice gets a default OfferItem from storage
                 * @param defaultName the name of the default for retrieval
                 */
                function fromDefault(
                    string memory defaultName
                ) internal view returns (OfferItem memory item) {
                    mapping(string => OfferItem) storage offerItemMap = _offerItemMap();
                    item = offerItemMap[defaultName];
                }
                function fromDefaultMany(
                    string memory defaultsName
                ) internal view returns (OfferItem[] memory items) {
                    mapping(string => OfferItem[]) storage offerItemsMap = _offerItemsMap();
                    items = offerItemsMap[defaultsName];
                }
                /**
                 * @notice saves an OfferItem as a named default
                 * @param offerItem the OfferItem to save as a default
                 * @param defaultName the name of the default for retrieval
                 */
                function saveDefault(
                    OfferItem memory offerItem,
                    string memory defaultName
                ) internal returns (OfferItem memory _offerItem) {
                    mapping(string => OfferItem) storage offerItemMap = _offerItemMap();
                    offerItemMap[defaultName] = offerItem;
                    return offerItem;
                }
                function saveDefaultMany(
                    OfferItem[] memory offerItems,
                    string memory defaultsName
                ) internal returns (OfferItem[] memory _offerItems) {
                    mapping(string => OfferItem[]) storage offerItemsMap = _offerItemsMap();
                    OfferItem[] storage items = offerItemsMap[defaultsName];
                    clearMany(defaultsName);
                    StructCopier.setOfferItems(items, offerItems);
                    return offerItems;
                }
                /**
                 * @notice makes a copy of an OfferItem in-memory
                 * @param item the OfferItem to make a copy of in-memory
                 */
                function copy(
                    OfferItem memory item
                ) internal pure returns (OfferItem memory) {
                    return
                        OfferItem({
                            itemType: item.itemType,
                            token: item.token,
                            identifierOrCriteria: item.identifierOrCriteria,
                            startAmount: item.startAmount,
                            endAmount: item.endAmount
                        });
                }
                function copy(
                    OfferItem[] memory items
                ) internal pure returns (OfferItem[] memory) {
                    OfferItem[] memory copiedItems = new OfferItem[](items.length);
                    for (uint256 i = 0; i < items.length; i++) {
                        copiedItems[i] = copy(items[i]);
                    }
                    return copiedItems;
                }
                function empty() internal pure returns (OfferItem memory) {
                    return
                        OfferItem({
                            itemType: ItemType.NATIVE,
                            token: address(0),
                            identifierOrCriteria: 0,
                            startAmount: 0,
                            endAmount: 0
                        });
                }
                /**
                 * @notice gets the storage position of the default OfferItem map
                 */
                function _offerItemMap()
                    private
                    pure
                    returns (mapping(string => OfferItem) storage offerItemMap)
                {
                    bytes32 position = OFFER_ITEM_MAP_POSITION;
                    assembly {
                        offerItemMap.slot := position
                    }
                }
                /**
                 * @notice gets the storage position of the default OfferItem[] map
                 */
                function _offerItemsMap()
                    private
                    pure
                    returns (mapping(string => OfferItem[]) storage offerItemMap)
                {
                    bytes32 position = OFFER_ITEMS_MAP_POSITION;
                    assembly {
                        offerItemMap.slot := position
                    }
                }
                // methods for configuring a single of each of an OfferItem's fields, which modifies the OfferItem in-place and
                // returns it
                /**
                 * @notice sets the item type
                 * @param item the OfferItem to modify
                 * @param itemType the item type to set
                 * @return the modified OfferItem
                 */
                function withItemType(
                    OfferItem memory item,
                    ItemType itemType
                ) internal pure returns (OfferItem memory) {
                    item.itemType = itemType;
                    return item;
                }
                /**
                 * @notice sets the token address
                 * @param item the OfferItem to modify
                 * @param token the token address to set
                 * @return the modified OfferItem
                 */
                function withToken(
                    OfferItem memory item,
                    address token
                ) internal pure returns (OfferItem memory) {
                    item.token = token;
                    return item;
                }
                /**
                 * @notice sets the identifier or criteria
                 * @param item the OfferItem to modify
                 * @param identifierOrCriteria the identifier or criteria to set
                 * @return the modified OfferItem
                 */
                function withIdentifierOrCriteria(
                    OfferItem memory item,
                    uint256 identifierOrCriteria
                ) internal pure returns (OfferItem memory) {
                    item.identifierOrCriteria = identifierOrCriteria;
                    return item;
                }
                /**
                 * @notice sets the start amount
                 * @param item the OfferItem to modify
                 * @param startAmount the start amount to set
                 * @return the modified OfferItem
                 */
                function withStartAmount(
                    OfferItem memory item,
                    uint256 startAmount
                ) internal pure returns (OfferItem memory) {
                    item.startAmount = startAmount;
                    return item;
                }
                /**
                 * @notice sets the end amount
                 * @param item the OfferItem to modify
                 * @param endAmount the end amount to set
                 * @return the modified OfferItem
                 */
                function withEndAmount(
                    OfferItem memory item,
                    uint256 endAmount
                ) internal pure returns (OfferItem memory) {
                    item.endAmount = endAmount;
                    return item;
                }
                function toSpentItem(
                    OfferItem memory item
                ) internal pure returns (SpentItem memory) {
                    return
                        SpentItem({
                            itemType: item.itemType,
                            token: item.token,
                            identifier: item.identifierOrCriteria,
                            amount: item.startAmount
                        });
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.17;
            import {
                BasicOrderParameters,
                OrderComponents,
                ConsiderationItem,
                OrderParameters,
                OfferItem,
                AdditionalRecipient
            } from "../../../lib/ConsiderationStructs.sol";
            import {
                OrderType,
                ItemType,
                BasicOrderType
            } from "../../../lib/ConsiderationEnums.sol";
            import { StructCopier } from "./StructCopier.sol";
            import { OfferItemLib } from "./OfferItemLib.sol";
            import { ConsiderationItemLib } from "./ConsiderationItemLib.sol";
            library OrderComponentsLib {
                using OrderComponentsLib for OrderComponents;
                using OfferItemLib for OfferItem[];
                using ConsiderationItemLib for ConsiderationItem[];
                bytes32 private constant ORDER_COMPONENTS_MAP_POSITION =
                    keccak256("seaport.OrderComponentsDefaults");
                bytes32 private constant ORDER_COMPONENTS_ARRAY_MAP_POSITION =
                    keccak256("seaport.OrderComponentsArrayDefaults");
                function clear(OrderComponents storage components) internal {
                    // uninitialized pointers take up no new memory (versus one word for initializing length-0)
                    OfferItem[] memory offer;
                    ConsiderationItem[] memory consideration;
                    // clear all fields
                    components.offerer = address(0);
                    components.zone = address(0);
                    StructCopier.setOfferItems(components.offer, offer);
                    StructCopier.setConsiderationItems(
                        components.consideration,
                        consideration
                    );
                    components.orderType = OrderType(0);
                    components.startTime = 0;
                    components.endTime = 0;
                    components.zoneHash = bytes32(0);
                    components.salt = 0;
                    components.conduitKey = bytes32(0);
                    components.counter = 0;
                }
                function clear(OrderComponents[] storage components) internal {
                    while (components.length > 0) {
                        clear(components[components.length - 1]);
                        components.pop();
                    }
                }
                /**
                 * @notice clears a default OrderComponents from storage
                 * @param defaultName the name of the default to clear
                 */
                function clear(string memory defaultName) internal {
                    mapping(string => OrderComponents)
                        storage orderComponentsMap = _orderComponentsMap();
                    OrderComponents storage components = orderComponentsMap[defaultName];
                    components.clear();
                }
                function empty() internal pure returns (OrderComponents memory item) {
                    OfferItem[] memory offer;
                    ConsiderationItem[] memory consideration;
                    item = OrderComponents({
                        offerer: address(0),
                        zone: address(0),
                        offer: offer,
                        consideration: consideration,
                        orderType: OrderType(0),
                        startTime: 0,
                        endTime: 0,
                        zoneHash: bytes32(0),
                        salt: 0,
                        conduitKey: bytes32(0),
                        counter: 0
                    });
                }
                /**
                 * @notice gets a default OrderComponents from storage
                 * @param defaultName the name of the default for retrieval
                 */
                function fromDefault(
                    string memory defaultName
                ) internal view returns (OrderComponents memory item) {
                    mapping(string => OrderComponents)
                        storage orderComponentsMap = _orderComponentsMap();
                    item = orderComponentsMap[defaultName];
                }
                function fromDefaultMany(
                    string memory defaultName
                ) internal view returns (OrderComponents[] memory items) {
                    mapping(string => OrderComponents[])
                        storage orderComponentsArrayMap = _orderComponentsArrayMap();
                    items = orderComponentsArrayMap[defaultName];
                }
                /**
                 * @notice saves an OrderComponents as a named default
                 * @param orderComponents the OrderComponents to save as a default
                 * @param defaultName the name of the default for retrieval
                 */
                function saveDefault(
                    OrderComponents memory orderComponents,
                    string memory defaultName
                ) internal returns (OrderComponents memory _orderComponents) {
                    mapping(string => OrderComponents)
                        storage orderComponentsMap = _orderComponentsMap();
                    OrderComponents storage destination = orderComponentsMap[defaultName];
                    StructCopier.setOrderComponents(destination, orderComponents);
                    return orderComponents;
                }
                function saveDefaultMany(
                    OrderComponents[] memory orderComponents,
                    string memory defaultName
                ) internal returns (OrderComponents[] memory _orderComponents) {
                    mapping(string => OrderComponents[])
                        storage orderComponentsArrayMap = _orderComponentsArrayMap();
                    OrderComponents[] storage destination = orderComponentsArrayMap[
                        defaultName
                    ];
                    StructCopier.setOrderComponents(destination, orderComponents);
                    return orderComponents;
                }
                /**
                 * @notice makes a copy of an OrderComponents in-memory
                 * @param item the OrderComponents to make a copy of in-memory
                 */
                function copy(
                    OrderComponents memory item
                ) internal pure returns (OrderComponents memory) {
                    return
                        OrderComponents({
                            offerer: item.offerer,
                            zone: item.zone,
                            offer: item.offer.copy(),
                            consideration: item.consideration.copy(),
                            orderType: item.orderType,
                            startTime: item.startTime,
                            endTime: item.endTime,
                            zoneHash: item.zoneHash,
                            salt: item.salt,
                            conduitKey: item.conduitKey,
                            counter: item.counter
                        });
                }
                /**
                 * @notice gets the storage position of the default OrderComponents map
                 */
                function _orderComponentsMap()
                    private
                    pure
                    returns (mapping(string => OrderComponents) storage orderComponentsMap)
                {
                    bytes32 position = ORDER_COMPONENTS_MAP_POSITION;
                    assembly {
                        orderComponentsMap.slot := position
                    }
                }
                function _orderComponentsArrayMap()
                    private
                    pure
                    returns (
                        mapping(string => OrderComponents[]) storage orderComponentsArrayMap
                    )
                {
                    bytes32 position = ORDER_COMPONENTS_ARRAY_MAP_POSITION;
                    assembly {
                        orderComponentsArrayMap.slot := position
                    }
                }
                // methods for configuring a single of each of an in-memory OrderComponents's fields, which modifies the
                // OrderComponents in-memory and returns it
                function withOfferer(
                    OrderComponents memory components,
                    address offerer
                ) internal pure returns (OrderComponents memory) {
                    components.offerer = offerer;
                    return components;
                }
                function withZone(
                    OrderComponents memory components,
                    address zone
                ) internal pure returns (OrderComponents memory) {
                    components.zone = zone;
                    return components;
                }
                function withOffer(
                    OrderComponents memory components,
                    OfferItem[] memory offer
                ) internal pure returns (OrderComponents memory) {
                    components.offer = offer;
                    return components;
                }
                function withConsideration(
                    OrderComponents memory components,
                    ConsiderationItem[] memory consideration
                ) internal pure returns (OrderComponents memory) {
                    components.consideration = consideration;
                    return components;
                }
                function withOrderType(
                    OrderComponents memory components,
                    OrderType orderType
                ) internal pure returns (OrderComponents memory) {
                    components.orderType = orderType;
                    return components;
                }
                function withStartTime(
                    OrderComponents memory components,
                    uint256 startTime
                ) internal pure returns (OrderComponents memory) {
                    components.startTime = startTime;
                    return components;
                }
                function withEndTime(
                    OrderComponents memory components,
                    uint256 endTime
                ) internal pure returns (OrderComponents memory) {
                    components.endTime = endTime;
                    return components;
                }
                function withZoneHash(
                    OrderComponents memory components,
                    bytes32 zoneHash
                ) internal pure returns (OrderComponents memory) {
                    components.zoneHash = zoneHash;
                    return components;
                }
                function withSalt(
                    OrderComponents memory components,
                    uint256 salt
                ) internal pure returns (OrderComponents memory) {
                    components.salt = salt;
                    return components;
                }
                function withConduitKey(
                    OrderComponents memory components,
                    bytes32 conduitKey
                ) internal pure returns (OrderComponents memory) {
                    components.conduitKey = conduitKey;
                    return components;
                }
                function withCounter(
                    OrderComponents memory components,
                    uint256 counter
                ) internal pure returns (OrderComponents memory) {
                    components.counter = counter;
                    return components;
                }
                function toOrderParameters(
                    OrderComponents memory components
                ) internal pure returns (OrderParameters memory parameters) {
                    parameters.offerer = components.offerer;
                    parameters.zone = components.zone;
                    parameters.offer = components.offer.copy();
                    parameters.consideration = components.consideration.copy();
                    parameters.orderType = components.orderType;
                    parameters.startTime = components.startTime;
                    parameters.endTime = components.endTime;
                    parameters.zoneHash = components.zoneHash;
                    parameters.salt = components.salt;
                    parameters.conduitKey = components.conduitKey;
                    parameters.totalOriginalConsiderationItems = components
                        .consideration
                        .length;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.17;
            import {
                Order,
                AdvancedOrder,
                OrderParameters
            } from "../../../lib/ConsiderationStructs.sol";
            import { OrderParametersLib } from "./OrderParametersLib.sol";
            import { StructCopier } from "./StructCopier.sol";
            library OrderLib {
                bytes32 private constant ORDER_MAP_POSITION =
                    keccak256("seaport.OrderDefaults");
                bytes32 private constant ORDERS_MAP_POSITION =
                    keccak256("seaport.OrdersDefaults");
                using OrderParametersLib for OrderParameters;
                /**
                 * @notice clears a default Order from storage
                 * @param defaultName the name of the default to clear
                 */
                function clear(string memory defaultName) internal {
                    mapping(string => Order) storage orderMap = _orderMap();
                    Order storage item = orderMap[defaultName];
                    clear(item);
                }
                function clear(Order storage order) internal {
                    // clear all fields
                    order.parameters.clear();
                    order.signature = "";
                }
                function clear(Order[] storage order) internal {
                    while (order.length > 0) {
                        clear(order[order.length - 1]);
                        order.pop();
                    }
                }
                /**
                 * @notice gets a default Order from storage
                 * @param defaultName the name of the default for retrieval
                 */
                function fromDefault(
                    string memory defaultName
                ) internal view returns (Order memory item) {
                    mapping(string => Order) storage orderMap = _orderMap();
                    item = orderMap[defaultName];
                }
                function fromDefaultMany(
                    string memory defaultName
                ) internal view returns (Order[] memory) {
                    mapping(string => Order[]) storage ordersMap = _ordersMap();
                    Order[] memory items = ordersMap[defaultName];
                    return items;
                }
                /**
                 * @notice saves an Order as a named default
                 * @param order the Order to save as a default
                 * @param defaultName the name of the default for retrieval
                 */
                function saveDefault(
                    Order memory order,
                    string memory defaultName
                ) internal returns (Order memory _order) {
                    mapping(string => Order) storage orderMap = _orderMap();
                    StructCopier.setOrder(orderMap[defaultName], order);
                    return order;
                }
                function saveDefaultMany(
                    Order[] memory orders,
                    string memory defaultName
                ) internal returns (Order[] memory _orders) {
                    mapping(string => Order[]) storage ordersMap = _ordersMap();
                    StructCopier.setOrders(ordersMap[defaultName], orders);
                    return orders;
                }
                /**
                 * @notice makes a copy of an Order in-memory
                 * @param item the Order to make a copy of in-memory
                 */
                function copy(Order memory item) internal pure returns (Order memory) {
                    return
                        Order({
                            parameters: item.parameters.copy(),
                            signature: item.signature
                        });
                }
                function copy(Order[] memory items) internal pure returns (Order[] memory) {
                    Order[] memory copiedItems = new Order[](items.length);
                    for (uint256 i = 0; i < items.length; i++) {
                        copiedItems[i] = copy(items[i]);
                    }
                    return copiedItems;
                }
                function empty() internal pure returns (Order memory) {
                    return Order({ parameters: OrderParametersLib.empty(), signature: "" });
                }
                /**
                 * @notice gets the storage position of the default Order map
                 */
                function _orderMap()
                    private
                    pure
                    returns (mapping(string => Order) storage orderMap)
                {
                    bytes32 position = ORDER_MAP_POSITION;
                    assembly {
                        orderMap.slot := position
                    }
                }
                function _ordersMap()
                    private
                    pure
                    returns (mapping(string => Order[]) storage ordersMap)
                {
                    bytes32 position = ORDERS_MAP_POSITION;
                    assembly {
                        ordersMap.slot := position
                    }
                }
                // methods for configuring a single of each of an Order's fields, which modifies the Order in-place and
                // returns it
                function withParameters(
                    Order memory order,
                    OrderParameters memory parameters
                ) internal pure returns (Order memory) {
                    order.parameters = parameters.copy();
                    return order;
                }
                function withSignature(
                    Order memory order,
                    bytes memory signature
                ) internal pure returns (Order memory) {
                    order.signature = signature;
                    return order;
                }
                function toAdvancedOrder(
                    Order memory order,
                    uint120 numerator,
                    uint120 denominator,
                    bytes memory extraData
                ) internal pure returns (AdvancedOrder memory advancedOrder) {
                    advancedOrder.parameters = order.parameters.copy();
                    advancedOrder.numerator = numerator;
                    advancedOrder.denominator = denominator;
                    advancedOrder.signature = order.signature;
                    advancedOrder.extraData = extraData;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.17;
            import {
                BasicOrderParameters,
                OrderComponents,
                ConsiderationItem,
                OrderParameters,
                OfferItem,
                AdditionalRecipient
            } from "../../../lib/ConsiderationStructs.sol";
            import {
                OrderType,
                ItemType,
                BasicOrderType
            } from "../../../lib/ConsiderationEnums.sol";
            import { StructCopier } from "./StructCopier.sol";
            import { OfferItemLib } from "./OfferItemLib.sol";
            import { ConsiderationItemLib } from "./ConsiderationItemLib.sol";
            library OrderParametersLib {
                using OrderParametersLib for OrderParameters;
                using OfferItemLib for OfferItem[];
                using ConsiderationItemLib for ConsiderationItem[];
                using ConsiderationItemLib for ConsiderationItem;
                using OfferItemLib for OfferItem;
                bytes32 private constant ORDER_PARAMETERS_MAP_POSITION =
                    keccak256("seaport.OrderParametersDefaults");
                bytes32 private constant ORDER_PARAMETERS_ARRAY_MAP_POSITION =
                    keccak256("seaport.OrderParametersArrayDefaults");
                function clear(OrderParameters storage parameters) internal {
                    // uninitialized pointers take up no new memory (versus one word for initializing length-0)
                    OfferItem[] memory offer;
                    ConsiderationItem[] memory consideration;
                    // clear all fields
                    parameters.offerer = address(0);
                    parameters.zone = address(0);
                    StructCopier.setOfferItems(parameters.offer, offer);
                    StructCopier.setConsiderationItems(
                        parameters.consideration,
                        consideration
                    );
                    parameters.orderType = OrderType(0);
                    parameters.startTime = 0;
                    parameters.endTime = 0;
                    parameters.zoneHash = bytes32(0);
                    parameters.salt = 0;
                    parameters.conduitKey = bytes32(0);
                    parameters.totalOriginalConsiderationItems = 0;
                }
                function clear(OrderParameters[] storage parameters) internal {
                    while (parameters.length > 0) {
                        clear(parameters[parameters.length - 1]);
                        parameters.pop();
                    }
                }
                /**
                 * @notice clears a default OrderParameters from storage
                 * @param defaultName the name of the default to clear
                 */
                function clear(string memory defaultName) internal {
                    mapping(string => OrderParameters)
                        storage orderParametersMap = _orderParametersMap();
                    OrderParameters storage parameters = orderParametersMap[defaultName];
                    parameters.clear();
                }
                function empty() internal pure returns (OrderParameters memory item) {
                    OfferItem[] memory offer;
                    ConsiderationItem[] memory consideration;
                    item = OrderParameters({
                        offerer: address(0),
                        zone: address(0),
                        offer: offer,
                        consideration: consideration,
                        orderType: OrderType(0),
                        startTime: 0,
                        endTime: 0,
                        zoneHash: bytes32(0),
                        salt: 0,
                        conduitKey: bytes32(0),
                        totalOriginalConsiderationItems: 0
                    });
                }
                /**
                 * @notice gets a default OrderParameters from storage
                 * @param defaultName the name of the default for retrieval
                 */
                function fromDefault(
                    string memory defaultName
                ) internal view returns (OrderParameters memory item) {
                    mapping(string => OrderParameters)
                        storage orderParametersMap = _orderParametersMap();
                    item = orderParametersMap[defaultName];
                }
                function fromDefaultMany(
                    string memory defaultName
                ) internal view returns (OrderParameters[] memory items) {
                    mapping(string => OrderParameters[])
                        storage orderParametersArrayMap = _orderParametersArrayMap();
                    items = orderParametersArrayMap[defaultName];
                }
                /**
                 * @notice saves an OrderParameters as a named default
                 * @param orderParameters the OrderParameters to save as a default
                 * @param defaultName the name of the default for retrieval
                 */
                function saveDefault(
                    OrderParameters memory orderParameters,
                    string memory defaultName
                ) internal returns (OrderParameters memory _orderParameters) {
                    mapping(string => OrderParameters)
                        storage orderParametersMap = _orderParametersMap();
                    OrderParameters storage destination = orderParametersMap[defaultName];
                    StructCopier.setOrderParameters(destination, orderParameters);
                    return orderParameters;
                }
                function saveDefaultMany(
                    OrderParameters[] memory orderParameters,
                    string memory defaultName
                ) internal returns (OrderParameters[] memory _orderParameters) {
                    mapping(string => OrderParameters[])
                        storage orderParametersArrayMap = _orderParametersArrayMap();
                    OrderParameters[] storage destination = orderParametersArrayMap[
                        defaultName
                    ];
                    StructCopier.setOrderParameters(destination, orderParameters);
                    return orderParameters;
                }
                /**
                 * @notice makes a copy of an OrderParameters in-memory
                 * @param item the OrderParameters to make a copy of in-memory
                 */
                function copy(
                    OrderParameters memory item
                ) internal pure returns (OrderParameters memory) {
                    return
                        OrderParameters({
                            offerer: item.offerer,
                            zone: item.zone,
                            offer: item.offer.copy(),
                            consideration: item.consideration.copy(),
                            orderType: item.orderType,
                            startTime: item.startTime,
                            endTime: item.endTime,
                            zoneHash: item.zoneHash,
                            salt: item.salt,
                            conduitKey: item.conduitKey,
                            totalOriginalConsiderationItems: item
                                .totalOriginalConsiderationItems
                        });
                }
                /**
                 * @notice gets the storage position of the default OrderParameters map
                 */
                function _orderParametersMap()
                    private
                    pure
                    returns (mapping(string => OrderParameters) storage orderParametersMap)
                {
                    bytes32 position = ORDER_PARAMETERS_MAP_POSITION;
                    assembly {
                        orderParametersMap.slot := position
                    }
                }
                function _orderParametersArrayMap()
                    private
                    pure
                    returns (
                        mapping(string => OrderParameters[]) storage orderParametersArrayMap
                    )
                {
                    bytes32 position = ORDER_PARAMETERS_ARRAY_MAP_POSITION;
                    assembly {
                        orderParametersArrayMap.slot := position
                    }
                }
                // methods for configuring a single of each of an in-memory OrderParameters's fields, which modifies the
                // OrderParameters in-memory and returns it
                function withOfferer(
                    OrderParameters memory parameters,
                    address offerer
                ) internal pure returns (OrderParameters memory) {
                    parameters.offerer = offerer;
                    return parameters;
                }
                function withZone(
                    OrderParameters memory parameters,
                    address zone
                ) internal pure returns (OrderParameters memory) {
                    parameters.zone = zone;
                    return parameters;
                }
                function withOffer(
                    OrderParameters memory parameters,
                    OfferItem[] memory offer
                ) internal pure returns (OrderParameters memory) {
                    parameters.offer = offer;
                    return parameters;
                }
                function withConsideration(
                    OrderParameters memory parameters,
                    ConsiderationItem[] memory consideration
                ) internal pure returns (OrderParameters memory) {
                    parameters.consideration = consideration;
                    return parameters;
                }
                function withOrderType(
                    OrderParameters memory parameters,
                    OrderType orderType
                ) internal pure returns (OrderParameters memory) {
                    parameters.orderType = orderType;
                    return parameters;
                }
                function withStartTime(
                    OrderParameters memory parameters,
                    uint256 startTime
                ) internal pure returns (OrderParameters memory) {
                    parameters.startTime = startTime;
                    return parameters;
                }
                function withEndTime(
                    OrderParameters memory parameters,
                    uint256 endTime
                ) internal pure returns (OrderParameters memory) {
                    parameters.endTime = endTime;
                    return parameters;
                }
                function withZoneHash(
                    OrderParameters memory parameters,
                    bytes32 zoneHash
                ) internal pure returns (OrderParameters memory) {
                    parameters.zoneHash = zoneHash;
                    return parameters;
                }
                function withSalt(
                    OrderParameters memory parameters,
                    uint256 salt
                ) internal pure returns (OrderParameters memory) {
                    parameters.salt = salt;
                    return parameters;
                }
                function withConduitKey(
                    OrderParameters memory parameters,
                    bytes32 conduitKey
                ) internal pure returns (OrderParameters memory) {
                    parameters.conduitKey = conduitKey;
                    return parameters;
                }
                function withTotalOriginalConsiderationItems(
                    OrderParameters memory parameters,
                    uint256 totalOriginalConsiderationItems
                ) internal pure returns (OrderParameters memory) {
                    parameters
                        .totalOriginalConsiderationItems = totalOriginalConsiderationItems;
                    return parameters;
                }
                function toOrderComponents(
                    OrderParameters memory parameters,
                    uint256 counter
                ) internal pure returns (OrderComponents memory components) {
                    components.offerer = parameters.offerer;
                    components.zone = parameters.zone;
                    components.offer = parameters.offer.copy();
                    components.consideration = parameters.consideration.copy();
                    components.orderType = parameters.orderType;
                    components.startTime = parameters.startTime;
                    components.endTime = parameters.endTime;
                    components.zoneHash = parameters.zoneHash;
                    components.salt = parameters.salt;
                    components.conduitKey = parameters.conduitKey;
                    components.counter = counter;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.17;
            import {
                ReceivedItem,
                ConsiderationItem
            } from "../../../lib/ConsiderationStructs.sol";
            import { ItemType } from "../../../lib/ConsiderationEnums.sol";
            import { StructCopier } from "./StructCopier.sol";
            library ReceivedItemLib {
                bytes32 private constant RECEIVED_ITEM_MAP_POSITION =
                    keccak256("seaport.ReceivedItemDefaults");
                bytes32 private constant RECEIVED_ITEMS_MAP_POSITION =
                    keccak256("seaport.ReceivedItemsDefaults");
                /**
                 * @notice clears a default ReceivedItem from storage
                 * @param defaultName the name of the default to clear
                 */
                function clear(string memory defaultName) internal {
                    mapping(string => ReceivedItem)
                        storage receivedItemMap = _receivedItemMap();
                    ReceivedItem storage item = receivedItemMap[defaultName];
                    clear(item);
                }
                function clear(ReceivedItem storage item) internal {
                    // clear all fields
                    item.itemType = ItemType.NATIVE;
                    item.token = address(0);
                    item.identifier = 0;
                    item.amount = 0;
                    item.recipient = payable(address(0));
                }
                function clearMany(string memory defaultsName) internal {
                    mapping(string => ReceivedItem[])
                        storage receivedItemsMap = _receivedItemsMap();
                    ReceivedItem[] storage items = receivedItemsMap[defaultsName];
                    clearMany(items);
                }
                function clearMany(ReceivedItem[] storage items) internal {
                    while (items.length > 0) {
                        clear(items[items.length - 1]);
                        items.pop();
                    }
                }
                function empty() internal pure returns (ReceivedItem memory) {
                    return
                        ReceivedItem({
                            itemType: ItemType(0),
                            token: address(0),
                            identifier: 0,
                            amount: 0,
                            recipient: payable(address(0))
                        });
                }
                /**
                 * @notice gets a default ReceivedItem from storage
                 * @param defaultName the name of the default for retrieval
                 */
                function fromDefault(
                    string memory defaultName
                ) internal view returns (ReceivedItem memory item) {
                    mapping(string => ReceivedItem)
                        storage receivedItemMap = _receivedItemMap();
                    item = receivedItemMap[defaultName];
                }
                function fromDefaultMany(
                    string memory defaultsName
                ) internal view returns (ReceivedItem[] memory items) {
                    mapping(string => ReceivedItem[])
                        storage receivedItemsMap = _receivedItemsMap();
                    items = receivedItemsMap[defaultsName];
                }
                /**
                 * @notice saves an ReceivedItem as a named default
                 * @param receivedItem the ReceivedItem to save as a default
                 * @param defaultName the name of the default for retrieval
                 */
                function saveDefault(
                    ReceivedItem memory receivedItem,
                    string memory defaultName
                ) internal returns (ReceivedItem memory _receivedItem) {
                    mapping(string => ReceivedItem)
                        storage receivedItemMap = _receivedItemMap();
                    receivedItemMap[defaultName] = receivedItem;
                    return receivedItem;
                }
                function saveDefaultMany(
                    ReceivedItem[] memory receivedItems,
                    string memory defaultsName
                ) internal returns (ReceivedItem[] memory _receivedItems) {
                    mapping(string => ReceivedItem[])
                        storage receivedItemsMap = _receivedItemsMap();
                    ReceivedItem[] storage items = receivedItemsMap[defaultsName];
                    setReceivedItems(items, receivedItems);
                    return receivedItems;
                }
                function setReceivedItems(
                    ReceivedItem[] storage items,
                    ReceivedItem[] memory newItems
                ) internal {
                    clearMany(items);
                    for (uint256 i = 0; i < newItems.length; i++) {
                        items.push(newItems[i]);
                    }
                }
                /**
                 * @notice makes a copy of an ReceivedItem in-memory
                 * @param item the ReceivedItem to make a copy of in-memory
                 */
                function copy(
                    ReceivedItem memory item
                ) internal pure returns (ReceivedItem memory) {
                    return
                        ReceivedItem({
                            itemType: item.itemType,
                            token: item.token,
                            identifier: item.identifier,
                            amount: item.amount,
                            recipient: item.recipient
                        });
                }
                function copy(
                    ReceivedItem[] memory item
                ) internal pure returns (ReceivedItem[] memory) {
                    ReceivedItem[] memory copies = new ReceivedItem[](item.length);
                    for (uint256 i = 0; i < item.length; i++) {
                        copies[i] = ReceivedItemLib.copy(item[i]);
                    }
                    return copies;
                }
                /**
                 * @notice gets the storage position of the default ReceivedItem map
                 */
                function _receivedItemMap()
                    private
                    pure
                    returns (mapping(string => ReceivedItem) storage receivedItemMap)
                {
                    bytes32 position = RECEIVED_ITEM_MAP_POSITION;
                    assembly {
                        receivedItemMap.slot := position
                    }
                }
                /**
                 * @notice gets the storage position of the default ReceivedItem map
                 */
                function _receivedItemsMap()
                    private
                    pure
                    returns (mapping(string => ReceivedItem[]) storage receivedItemsMap)
                {
                    bytes32 position = RECEIVED_ITEMS_MAP_POSITION;
                    assembly {
                        receivedItemsMap.slot := position
                    }
                }
                // methods for configuring a single of each of an ReceivedItem's fields, which modifies the ReceivedItem
                // in-place and
                // returns it
                /**
                 * @notice sets the item type
                 * @param item the ReceivedItem to modify
                 * @param itemType the item type to set
                 * @return the modified ReceivedItem
                 */
                function withItemType(
                    ReceivedItem memory item,
                    ItemType itemType
                ) internal pure returns (ReceivedItem memory) {
                    item.itemType = itemType;
                    return item;
                }
                /**
                 * @notice sets the token address
                 * @param item the ReceivedItem to modify
                 * @param token the token address to set
                 * @return the modified ReceivedItem
                 */
                function withToken(
                    ReceivedItem memory item,
                    address token
                ) internal pure returns (ReceivedItem memory) {
                    item.token = token;
                    return item;
                }
                /**
                 * @notice sets the identifier or criteria
                 * @param item the ReceivedItem to modify
                 * @param identifier the identifier or criteria to set
                 * @return the modified ReceivedItem
                 */
                function withIdentifier(
                    ReceivedItem memory item,
                    uint256 identifier
                ) internal pure returns (ReceivedItem memory) {
                    item.identifier = identifier;
                    return item;
                }
                /**
                 * @notice sets the start amount
                 * @param item the ReceivedItem to modify
                 * @param amount the start amount to set
                 * @return the modified ReceivedItem
                 */
                function withAmount(
                    ReceivedItem memory item,
                    uint256 amount
                ) internal pure returns (ReceivedItem memory) {
                    item.amount = amount;
                    return item;
                }
                /**
                 * @notice sets the recipient
                 * @param item the ReceivedItem to modify
                 * @param recipient the recipient to set
                 * @return the modified ReceivedItem
                 */
                function withRecipient(
                    ReceivedItem memory item,
                    address recipient
                ) internal pure returns (ReceivedItem memory) {
                    item.recipient = payable(recipient);
                    return item;
                }
                function toConsiderationItem(
                    ReceivedItem memory item
                ) internal pure returns (ConsiderationItem memory) {
                    return
                        ConsiderationItem({
                            itemType: item.itemType,
                            token: item.token,
                            identifierOrCriteria: item.identifier,
                            startAmount: item.amount,
                            endAmount: item.amount,
                            recipient: item.recipient
                        });
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.17;
            import {
                OrderComponents,
                OfferItem,
                ConsiderationItem,
                SpentItem,
                ReceivedItem,
                BasicOrderParameters,
                AdditionalRecipient,
                OrderParameters,
                Order,
                AdvancedOrder,
                CriteriaResolver,
                Fulfillment,
                FulfillmentComponent
            } from "../../../lib/ConsiderationStructs.sol";
            library SeaportArrays {
                function Orders(Order memory a) internal pure returns (Order[] memory) {
                    Order[] memory arr = new Order[](1);
                    arr[0] = a;
                    return arr;
                }
                function Orders(
                    Order memory a,
                    Order memory b
                ) internal pure returns (Order[] memory) {
                    Order[] memory arr = new Order[](2);
                    arr[0] = a;
                    arr[1] = b;
                    return arr;
                }
                function Orders(
                    Order memory a,
                    Order memory b,
                    Order memory c
                ) internal pure returns (Order[] memory) {
                    Order[] memory arr = new Order[](3);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    return arr;
                }
                function Orders(
                    Order memory a,
                    Order memory b,
                    Order memory c,
                    Order memory d
                ) internal pure returns (Order[] memory) {
                    Order[] memory arr = new Order[](4);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    return arr;
                }
                function Orders(
                    Order memory a,
                    Order memory b,
                    Order memory c,
                    Order memory d,
                    Order memory e
                ) internal pure returns (Order[] memory) {
                    Order[] memory arr = new Order[](5);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    return arr;
                }
                function Orders(
                    Order memory a,
                    Order memory b,
                    Order memory c,
                    Order memory d,
                    Order memory e,
                    Order memory f
                ) internal pure returns (Order[] memory) {
                    Order[] memory arr = new Order[](6);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    return arr;
                }
                function Orders(
                    Order memory a,
                    Order memory b,
                    Order memory c,
                    Order memory d,
                    Order memory e,
                    Order memory f,
                    Order memory g
                ) internal pure returns (Order[] memory) {
                    Order[] memory arr = new Order[](7);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    arr[6] = g;
                    return arr;
                }
                function AdvancedOrders(
                    AdvancedOrder memory a
                ) internal pure returns (AdvancedOrder[] memory) {
                    AdvancedOrder[] memory arr = new AdvancedOrder[](1);
                    arr[0] = a;
                    return arr;
                }
                function AdvancedOrders(
                    AdvancedOrder memory a,
                    AdvancedOrder memory b
                ) internal pure returns (AdvancedOrder[] memory) {
                    AdvancedOrder[] memory arr = new AdvancedOrder[](2);
                    arr[0] = a;
                    arr[1] = b;
                    return arr;
                }
                function AdvancedOrders(
                    AdvancedOrder memory a,
                    AdvancedOrder memory b,
                    AdvancedOrder memory c
                ) internal pure returns (AdvancedOrder[] memory) {
                    AdvancedOrder[] memory arr = new AdvancedOrder[](3);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    return arr;
                }
                function AdvancedOrders(
                    AdvancedOrder memory a,
                    AdvancedOrder memory b,
                    AdvancedOrder memory c,
                    AdvancedOrder memory d
                ) internal pure returns (AdvancedOrder[] memory) {
                    AdvancedOrder[] memory arr = new AdvancedOrder[](4);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    return arr;
                }
                function AdvancedOrders(
                    AdvancedOrder memory a,
                    AdvancedOrder memory b,
                    AdvancedOrder memory c,
                    AdvancedOrder memory d,
                    AdvancedOrder memory e
                ) internal pure returns (AdvancedOrder[] memory) {
                    AdvancedOrder[] memory arr = new AdvancedOrder[](5);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    return arr;
                }
                function AdvancedOrders(
                    AdvancedOrder memory a,
                    AdvancedOrder memory b,
                    AdvancedOrder memory c,
                    AdvancedOrder memory d,
                    AdvancedOrder memory e,
                    AdvancedOrder memory f
                ) internal pure returns (AdvancedOrder[] memory) {
                    AdvancedOrder[] memory arr = new AdvancedOrder[](6);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    return arr;
                }
                function AdvancedOrders(
                    AdvancedOrder memory a,
                    AdvancedOrder memory b,
                    AdvancedOrder memory c,
                    AdvancedOrder memory d,
                    AdvancedOrder memory e,
                    AdvancedOrder memory f,
                    AdvancedOrder memory g
                ) internal pure returns (AdvancedOrder[] memory) {
                    AdvancedOrder[] memory arr = new AdvancedOrder[](7);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    arr[6] = g;
                    return arr;
                }
                function OrderComponentsArray(
                    OrderComponents memory a
                ) internal pure returns (OrderComponents[] memory) {
                    OrderComponents[] memory arr = new OrderComponents[](1);
                    arr[0] = a;
                    return arr;
                }
                function OrderComponentsArray(
                    OrderComponents memory a,
                    OrderComponents memory b
                ) internal pure returns (OrderComponents[] memory) {
                    OrderComponents[] memory arr = new OrderComponents[](2);
                    arr[0] = a;
                    arr[1] = b;
                    return arr;
                }
                function OrderComponentsArray(
                    OrderComponents memory a,
                    OrderComponents memory b,
                    OrderComponents memory c
                ) internal pure returns (OrderComponents[] memory) {
                    OrderComponents[] memory arr = new OrderComponents[](3);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    return arr;
                }
                function OrderComponentsArray(
                    OrderComponents memory a,
                    OrderComponents memory b,
                    OrderComponents memory c,
                    OrderComponents memory d
                ) internal pure returns (OrderComponents[] memory) {
                    OrderComponents[] memory arr = new OrderComponents[](4);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    return arr;
                }
                function OrderComponentsArray(
                    OrderComponents memory a,
                    OrderComponents memory b,
                    OrderComponents memory c,
                    OrderComponents memory d,
                    OrderComponents memory e
                ) internal pure returns (OrderComponents[] memory) {
                    OrderComponents[] memory arr = new OrderComponents[](5);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    return arr;
                }
                function OrderComponentsArray(
                    OrderComponents memory a,
                    OrderComponents memory b,
                    OrderComponents memory c,
                    OrderComponents memory d,
                    OrderComponents memory e,
                    OrderComponents memory f
                ) internal pure returns (OrderComponents[] memory) {
                    OrderComponents[] memory arr = new OrderComponents[](6);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    return arr;
                }
                function OrderComponentsArray(
                    OrderComponents memory a,
                    OrderComponents memory b,
                    OrderComponents memory c,
                    OrderComponents memory d,
                    OrderComponents memory e,
                    OrderComponents memory f,
                    OrderComponents memory g
                ) internal pure returns (OrderComponents[] memory) {
                    OrderComponents[] memory arr = new OrderComponents[](7);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    arr[6] = g;
                    return arr;
                }
                function OrderParametersArray(
                    OrderParameters memory a
                ) internal pure returns (OrderParameters[] memory) {
                    OrderParameters[] memory arr = new OrderParameters[](1);
                    arr[0] = a;
                    return arr;
                }
                function OrderParametersArray(
                    OrderParameters memory a,
                    OrderParameters memory b
                ) internal pure returns (OrderParameters[] memory) {
                    OrderParameters[] memory arr = new OrderParameters[](2);
                    arr[0] = a;
                    arr[1] = b;
                    return arr;
                }
                function OrderParametersArray(
                    OrderParameters memory a,
                    OrderParameters memory b,
                    OrderParameters memory c
                ) internal pure returns (OrderParameters[] memory) {
                    OrderParameters[] memory arr = new OrderParameters[](3);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    return arr;
                }
                function OrderParametersArray(
                    OrderParameters memory a,
                    OrderParameters memory b,
                    OrderParameters memory c,
                    OrderParameters memory d
                ) internal pure returns (OrderParameters[] memory) {
                    OrderParameters[] memory arr = new OrderParameters[](4);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    return arr;
                }
                function OrderParametersArray(
                    OrderParameters memory a,
                    OrderParameters memory b,
                    OrderParameters memory c,
                    OrderParameters memory d,
                    OrderParameters memory e
                ) internal pure returns (OrderParameters[] memory) {
                    OrderParameters[] memory arr = new OrderParameters[](5);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    return arr;
                }
                function OrderParametersArray(
                    OrderParameters memory a,
                    OrderParameters memory b,
                    OrderParameters memory c,
                    OrderParameters memory d,
                    OrderParameters memory e,
                    OrderParameters memory f
                ) internal pure returns (OrderParameters[] memory) {
                    OrderParameters[] memory arr = new OrderParameters[](6);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    return arr;
                }
                function OrderParametersArray(
                    OrderParameters memory a,
                    OrderParameters memory b,
                    OrderParameters memory c,
                    OrderParameters memory d,
                    OrderParameters memory e,
                    OrderParameters memory f,
                    OrderParameters memory g
                ) internal pure returns (OrderParameters[] memory) {
                    OrderParameters[] memory arr = new OrderParameters[](7);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    arr[6] = g;
                    return arr;
                }
                function OfferItems(
                    OfferItem memory a
                ) internal pure returns (OfferItem[] memory) {
                    OfferItem[] memory arr = new OfferItem[](1);
                    arr[0] = a;
                    return arr;
                }
                function OfferItems(
                    OfferItem memory a,
                    OfferItem memory b
                ) internal pure returns (OfferItem[] memory) {
                    OfferItem[] memory arr = new OfferItem[](2);
                    arr[0] = a;
                    arr[1] = b;
                    return arr;
                }
                function OfferItems(
                    OfferItem memory a,
                    OfferItem memory b,
                    OfferItem memory c
                ) internal pure returns (OfferItem[] memory) {
                    OfferItem[] memory arr = new OfferItem[](3);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    return arr;
                }
                function OfferItems(
                    OfferItem memory a,
                    OfferItem memory b,
                    OfferItem memory c,
                    OfferItem memory d
                ) internal pure returns (OfferItem[] memory) {
                    OfferItem[] memory arr = new OfferItem[](4);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    return arr;
                }
                function OfferItems(
                    OfferItem memory a,
                    OfferItem memory b,
                    OfferItem memory c,
                    OfferItem memory d,
                    OfferItem memory e
                ) internal pure returns (OfferItem[] memory) {
                    OfferItem[] memory arr = new OfferItem[](5);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    return arr;
                }
                function OfferItems(
                    OfferItem memory a,
                    OfferItem memory b,
                    OfferItem memory c,
                    OfferItem memory d,
                    OfferItem memory e,
                    OfferItem memory f
                ) internal pure returns (OfferItem[] memory) {
                    OfferItem[] memory arr = new OfferItem[](6);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    return arr;
                }
                function OfferItems(
                    OfferItem memory a,
                    OfferItem memory b,
                    OfferItem memory c,
                    OfferItem memory d,
                    OfferItem memory e,
                    OfferItem memory f,
                    OfferItem memory g
                ) internal pure returns (OfferItem[] memory) {
                    OfferItem[] memory arr = new OfferItem[](7);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    arr[6] = g;
                    return arr;
                }
                function ConsiderationItems(
                    ConsiderationItem memory a
                ) internal pure returns (ConsiderationItem[] memory) {
                    ConsiderationItem[] memory arr = new ConsiderationItem[](1);
                    arr[0] = a;
                    return arr;
                }
                function ConsiderationItems(
                    ConsiderationItem memory a,
                    ConsiderationItem memory b
                ) internal pure returns (ConsiderationItem[] memory) {
                    ConsiderationItem[] memory arr = new ConsiderationItem[](2);
                    arr[0] = a;
                    arr[1] = b;
                    return arr;
                }
                function ConsiderationItems(
                    ConsiderationItem memory a,
                    ConsiderationItem memory b,
                    ConsiderationItem memory c
                ) internal pure returns (ConsiderationItem[] memory) {
                    ConsiderationItem[] memory arr = new ConsiderationItem[](3);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    return arr;
                }
                function ConsiderationItems(
                    ConsiderationItem memory a,
                    ConsiderationItem memory b,
                    ConsiderationItem memory c,
                    ConsiderationItem memory d
                ) internal pure returns (ConsiderationItem[] memory) {
                    ConsiderationItem[] memory arr = new ConsiderationItem[](4);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    return arr;
                }
                function ConsiderationItems(
                    ConsiderationItem memory a,
                    ConsiderationItem memory b,
                    ConsiderationItem memory c,
                    ConsiderationItem memory d,
                    ConsiderationItem memory e
                ) internal pure returns (ConsiderationItem[] memory) {
                    ConsiderationItem[] memory arr = new ConsiderationItem[](5);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    return arr;
                }
                function ConsiderationItems(
                    ConsiderationItem memory a,
                    ConsiderationItem memory b,
                    ConsiderationItem memory c,
                    ConsiderationItem memory d,
                    ConsiderationItem memory e,
                    ConsiderationItem memory f
                ) internal pure returns (ConsiderationItem[] memory) {
                    ConsiderationItem[] memory arr = new ConsiderationItem[](6);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    return arr;
                }
                function ConsiderationItems(
                    ConsiderationItem memory a,
                    ConsiderationItem memory b,
                    ConsiderationItem memory c,
                    ConsiderationItem memory d,
                    ConsiderationItem memory e,
                    ConsiderationItem memory f,
                    ConsiderationItem memory g
                ) internal pure returns (ConsiderationItem[] memory) {
                    ConsiderationItem[] memory arr = new ConsiderationItem[](7);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    arr[6] = g;
                    return arr;
                }
                function SpentItems(
                    SpentItem memory a
                ) internal pure returns (SpentItem[] memory) {
                    SpentItem[] memory arr = new SpentItem[](1);
                    arr[0] = a;
                    return arr;
                }
                function SpentItems(
                    SpentItem memory a,
                    SpentItem memory b
                ) internal pure returns (SpentItem[] memory) {
                    SpentItem[] memory arr = new SpentItem[](2);
                    arr[0] = a;
                    arr[1] = b;
                    return arr;
                }
                function SpentItems(
                    SpentItem memory a,
                    SpentItem memory b,
                    SpentItem memory c
                ) internal pure returns (SpentItem[] memory) {
                    SpentItem[] memory arr = new SpentItem[](3);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    return arr;
                }
                function SpentItems(
                    SpentItem memory a,
                    SpentItem memory b,
                    SpentItem memory c,
                    SpentItem memory d
                ) internal pure returns (SpentItem[] memory) {
                    SpentItem[] memory arr = new SpentItem[](4);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    return arr;
                }
                function SpentItems(
                    SpentItem memory a,
                    SpentItem memory b,
                    SpentItem memory c,
                    SpentItem memory d,
                    SpentItem memory e
                ) internal pure returns (SpentItem[] memory) {
                    SpentItem[] memory arr = new SpentItem[](5);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    return arr;
                }
                function SpentItems(
                    SpentItem memory a,
                    SpentItem memory b,
                    SpentItem memory c,
                    SpentItem memory d,
                    SpentItem memory e,
                    SpentItem memory f
                ) internal pure returns (SpentItem[] memory) {
                    SpentItem[] memory arr = new SpentItem[](6);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    return arr;
                }
                function SpentItems(
                    SpentItem memory a,
                    SpentItem memory b,
                    SpentItem memory c,
                    SpentItem memory d,
                    SpentItem memory e,
                    SpentItem memory f,
                    SpentItem memory g
                ) internal pure returns (SpentItem[] memory) {
                    SpentItem[] memory arr = new SpentItem[](7);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    arr[6] = g;
                    return arr;
                }
                function ReceivedItems(
                    ReceivedItem memory a
                ) internal pure returns (ReceivedItem[] memory) {
                    ReceivedItem[] memory arr = new ReceivedItem[](1);
                    arr[0] = a;
                    return arr;
                }
                function ReceivedItems(
                    ReceivedItem memory a,
                    ReceivedItem memory b
                ) internal pure returns (ReceivedItem[] memory) {
                    ReceivedItem[] memory arr = new ReceivedItem[](2);
                    arr[0] = a;
                    arr[1] = b;
                    return arr;
                }
                function ReceivedItems(
                    ReceivedItem memory a,
                    ReceivedItem memory b,
                    ReceivedItem memory c
                ) internal pure returns (ReceivedItem[] memory) {
                    ReceivedItem[] memory arr = new ReceivedItem[](3);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    return arr;
                }
                function ReceivedItems(
                    ReceivedItem memory a,
                    ReceivedItem memory b,
                    ReceivedItem memory c,
                    ReceivedItem memory d
                ) internal pure returns (ReceivedItem[] memory) {
                    ReceivedItem[] memory arr = new ReceivedItem[](4);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    return arr;
                }
                function ReceivedItems(
                    ReceivedItem memory a,
                    ReceivedItem memory b,
                    ReceivedItem memory c,
                    ReceivedItem memory d,
                    ReceivedItem memory e
                ) internal pure returns (ReceivedItem[] memory) {
                    ReceivedItem[] memory arr = new ReceivedItem[](5);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    return arr;
                }
                function ReceivedItems(
                    ReceivedItem memory a,
                    ReceivedItem memory b,
                    ReceivedItem memory c,
                    ReceivedItem memory d,
                    ReceivedItem memory e,
                    ReceivedItem memory f
                ) internal pure returns (ReceivedItem[] memory) {
                    ReceivedItem[] memory arr = new ReceivedItem[](6);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    return arr;
                }
                function ReceivedItems(
                    ReceivedItem memory a,
                    ReceivedItem memory b,
                    ReceivedItem memory c,
                    ReceivedItem memory d,
                    ReceivedItem memory e,
                    ReceivedItem memory f,
                    ReceivedItem memory g
                ) internal pure returns (ReceivedItem[] memory) {
                    ReceivedItem[] memory arr = new ReceivedItem[](7);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    arr[6] = g;
                    return arr;
                }
                function FulfillmentComponents(
                    FulfillmentComponent memory a
                ) internal pure returns (FulfillmentComponent[] memory) {
                    FulfillmentComponent[] memory arr = new FulfillmentComponent[](1);
                    arr[0] = a;
                    return arr;
                }
                function FulfillmentComponents(
                    FulfillmentComponent memory a,
                    FulfillmentComponent memory b
                ) internal pure returns (FulfillmentComponent[] memory) {
                    FulfillmentComponent[] memory arr = new FulfillmentComponent[](2);
                    arr[0] = a;
                    arr[1] = b;
                    return arr;
                }
                function FulfillmentComponents(
                    FulfillmentComponent memory a,
                    FulfillmentComponent memory b,
                    FulfillmentComponent memory c
                ) internal pure returns (FulfillmentComponent[] memory) {
                    FulfillmentComponent[] memory arr = new FulfillmentComponent[](3);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    return arr;
                }
                function FulfillmentComponents(
                    FulfillmentComponent memory a,
                    FulfillmentComponent memory b,
                    FulfillmentComponent memory c,
                    FulfillmentComponent memory d
                ) internal pure returns (FulfillmentComponent[] memory) {
                    FulfillmentComponent[] memory arr = new FulfillmentComponent[](4);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    return arr;
                }
                function FulfillmentComponents(
                    FulfillmentComponent memory a,
                    FulfillmentComponent memory b,
                    FulfillmentComponent memory c,
                    FulfillmentComponent memory d,
                    FulfillmentComponent memory e
                ) internal pure returns (FulfillmentComponent[] memory) {
                    FulfillmentComponent[] memory arr = new FulfillmentComponent[](5);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    return arr;
                }
                function FulfillmentComponents(
                    FulfillmentComponent memory a,
                    FulfillmentComponent memory b,
                    FulfillmentComponent memory c,
                    FulfillmentComponent memory d,
                    FulfillmentComponent memory e,
                    FulfillmentComponent memory f
                ) internal pure returns (FulfillmentComponent[] memory) {
                    FulfillmentComponent[] memory arr = new FulfillmentComponent[](6);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    return arr;
                }
                function FulfillmentComponents(
                    FulfillmentComponent memory a,
                    FulfillmentComponent memory b,
                    FulfillmentComponent memory c,
                    FulfillmentComponent memory d,
                    FulfillmentComponent memory e,
                    FulfillmentComponent memory f,
                    FulfillmentComponent memory g
                ) internal pure returns (FulfillmentComponent[] memory) {
                    FulfillmentComponent[] memory arr = new FulfillmentComponent[](7);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    arr[6] = g;
                    return arr;
                }
                function FulfillmentComponentArrays(
                    FulfillmentComponent[] memory a
                ) internal pure returns (FulfillmentComponent[][] memory) {
                    FulfillmentComponent[][] memory arr = new FulfillmentComponent[][](1);
                    arr[0] = a;
                    return arr;
                }
                function FulfillmentComponentArrays(
                    FulfillmentComponent[] memory a,
                    FulfillmentComponent[] memory b
                ) internal pure returns (FulfillmentComponent[][] memory) {
                    FulfillmentComponent[][] memory arr = new FulfillmentComponent[][](2);
                    arr[0] = a;
                    arr[1] = b;
                    return arr;
                }
                function FulfillmentComponentArrays(
                    FulfillmentComponent[] memory a,
                    FulfillmentComponent[] memory b,
                    FulfillmentComponent[] memory c
                ) internal pure returns (FulfillmentComponent[][] memory) {
                    FulfillmentComponent[][] memory arr = new FulfillmentComponent[][](3);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    return arr;
                }
                function FulfillmentComponentArrays(
                    FulfillmentComponent[] memory a,
                    FulfillmentComponent[] memory b,
                    FulfillmentComponent[] memory c,
                    FulfillmentComponent[] memory d
                ) internal pure returns (FulfillmentComponent[][] memory) {
                    FulfillmentComponent[][] memory arr = new FulfillmentComponent[][](4);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    return arr;
                }
                function FulfillmentComponentArrays(
                    FulfillmentComponent[] memory a,
                    FulfillmentComponent[] memory b,
                    FulfillmentComponent[] memory c,
                    FulfillmentComponent[] memory d,
                    FulfillmentComponent[] memory e
                ) internal pure returns (FulfillmentComponent[][] memory) {
                    FulfillmentComponent[][] memory arr = new FulfillmentComponent[][](5);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    return arr;
                }
                function FulfillmentComponentArrays(
                    FulfillmentComponent[] memory a,
                    FulfillmentComponent[] memory b,
                    FulfillmentComponent[] memory c,
                    FulfillmentComponent[] memory d,
                    FulfillmentComponent[] memory e,
                    FulfillmentComponent[] memory f
                ) internal pure returns (FulfillmentComponent[][] memory) {
                    FulfillmentComponent[][] memory arr = new FulfillmentComponent[][](6);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    return arr;
                }
                function FulfillmentComponentArrays(
                    FulfillmentComponent[] memory a,
                    FulfillmentComponent[] memory b,
                    FulfillmentComponent[] memory c,
                    FulfillmentComponent[] memory d,
                    FulfillmentComponent[] memory e,
                    FulfillmentComponent[] memory f,
                    FulfillmentComponent[] memory g
                ) internal pure returns (FulfillmentComponent[][] memory) {
                    FulfillmentComponent[][] memory arr = new FulfillmentComponent[][](7);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    arr[6] = g;
                    return arr;
                }
                function CriteriaResolvers(
                    CriteriaResolver memory a
                ) internal pure returns (CriteriaResolver[] memory) {
                    CriteriaResolver[] memory arr = new CriteriaResolver[](1);
                    arr[0] = a;
                    return arr;
                }
                function CriteriaResolvers(
                    CriteriaResolver memory a,
                    CriteriaResolver memory b
                ) internal pure returns (CriteriaResolver[] memory) {
                    CriteriaResolver[] memory arr = new CriteriaResolver[](2);
                    arr[0] = a;
                    arr[1] = b;
                    return arr;
                }
                function CriteriaResolvers(
                    CriteriaResolver memory a,
                    CriteriaResolver memory b,
                    CriteriaResolver memory c
                ) internal pure returns (CriteriaResolver[] memory) {
                    CriteriaResolver[] memory arr = new CriteriaResolver[](3);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    return arr;
                }
                function CriteriaResolvers(
                    CriteriaResolver memory a,
                    CriteriaResolver memory b,
                    CriteriaResolver memory c,
                    CriteriaResolver memory d
                ) internal pure returns (CriteriaResolver[] memory) {
                    CriteriaResolver[] memory arr = new CriteriaResolver[](4);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    return arr;
                }
                function CriteriaResolvers(
                    CriteriaResolver memory a,
                    CriteriaResolver memory b,
                    CriteriaResolver memory c,
                    CriteriaResolver memory d,
                    CriteriaResolver memory e
                ) internal pure returns (CriteriaResolver[] memory) {
                    CriteriaResolver[] memory arr = new CriteriaResolver[](5);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    return arr;
                }
                function CriteriaResolvers(
                    CriteriaResolver memory a,
                    CriteriaResolver memory b,
                    CriteriaResolver memory c,
                    CriteriaResolver memory d,
                    CriteriaResolver memory e,
                    CriteriaResolver memory f
                ) internal pure returns (CriteriaResolver[] memory) {
                    CriteriaResolver[] memory arr = new CriteriaResolver[](6);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    return arr;
                }
                function CriteriaResolvers(
                    CriteriaResolver memory a,
                    CriteriaResolver memory b,
                    CriteriaResolver memory c,
                    CriteriaResolver memory d,
                    CriteriaResolver memory e,
                    CriteriaResolver memory f,
                    CriteriaResolver memory g
                ) internal pure returns (CriteriaResolver[] memory) {
                    CriteriaResolver[] memory arr = new CriteriaResolver[](7);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    arr[6] = g;
                    return arr;
                }
                function AdditionalRecipients(
                    AdditionalRecipient memory a
                ) internal pure returns (AdditionalRecipient[] memory) {
                    AdditionalRecipient[] memory arr = new AdditionalRecipient[](1);
                    arr[0] = a;
                    return arr;
                }
                function AdditionalRecipients(
                    AdditionalRecipient memory a,
                    AdditionalRecipient memory b
                ) internal pure returns (AdditionalRecipient[] memory) {
                    AdditionalRecipient[] memory arr = new AdditionalRecipient[](2);
                    arr[0] = a;
                    arr[1] = b;
                    return arr;
                }
                function AdditionalRecipients(
                    AdditionalRecipient memory a,
                    AdditionalRecipient memory b,
                    AdditionalRecipient memory c
                ) internal pure returns (AdditionalRecipient[] memory) {
                    AdditionalRecipient[] memory arr = new AdditionalRecipient[](3);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    return arr;
                }
                function AdditionalRecipients(
                    AdditionalRecipient memory a,
                    AdditionalRecipient memory b,
                    AdditionalRecipient memory c,
                    AdditionalRecipient memory d
                ) internal pure returns (AdditionalRecipient[] memory) {
                    AdditionalRecipient[] memory arr = new AdditionalRecipient[](4);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    return arr;
                }
                function AdditionalRecipients(
                    AdditionalRecipient memory a,
                    AdditionalRecipient memory b,
                    AdditionalRecipient memory c,
                    AdditionalRecipient memory d,
                    AdditionalRecipient memory e
                ) internal pure returns (AdditionalRecipient[] memory) {
                    AdditionalRecipient[] memory arr = new AdditionalRecipient[](5);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    return arr;
                }
                function AdditionalRecipients(
                    AdditionalRecipient memory a,
                    AdditionalRecipient memory b,
                    AdditionalRecipient memory c,
                    AdditionalRecipient memory d,
                    AdditionalRecipient memory e,
                    AdditionalRecipient memory f
                ) internal pure returns (AdditionalRecipient[] memory) {
                    AdditionalRecipient[] memory arr = new AdditionalRecipient[](6);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    return arr;
                }
                function AdditionalRecipients(
                    AdditionalRecipient memory a,
                    AdditionalRecipient memory b,
                    AdditionalRecipient memory c,
                    AdditionalRecipient memory d,
                    AdditionalRecipient memory e,
                    AdditionalRecipient memory f,
                    AdditionalRecipient memory g
                ) internal pure returns (AdditionalRecipient[] memory) {
                    AdditionalRecipient[] memory arr = new AdditionalRecipient[](7);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    arr[6] = g;
                    return arr;
                }
                function BasicOrderParametersArray(
                    BasicOrderParameters memory a
                ) internal pure returns (BasicOrderParameters[] memory) {
                    BasicOrderParameters[] memory arr = new BasicOrderParameters[](1);
                    arr[0] = a;
                    return arr;
                }
                function BasicOrderParametersArray(
                    BasicOrderParameters memory a,
                    BasicOrderParameters memory b
                ) internal pure returns (BasicOrderParameters[] memory) {
                    BasicOrderParameters[] memory arr = new BasicOrderParameters[](2);
                    arr[0] = a;
                    arr[1] = b;
                    return arr;
                }
                function BasicOrderParametersArray(
                    BasicOrderParameters memory a,
                    BasicOrderParameters memory b,
                    BasicOrderParameters memory c
                ) internal pure returns (BasicOrderParameters[] memory) {
                    BasicOrderParameters[] memory arr = new BasicOrderParameters[](3);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    return arr;
                }
                function BasicOrderParametersArray(
                    BasicOrderParameters memory a,
                    BasicOrderParameters memory b,
                    BasicOrderParameters memory c,
                    BasicOrderParameters memory d
                ) internal pure returns (BasicOrderParameters[] memory) {
                    BasicOrderParameters[] memory arr = new BasicOrderParameters[](4);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    return arr;
                }
                function BasicOrderParametersArray(
                    BasicOrderParameters memory a,
                    BasicOrderParameters memory b,
                    BasicOrderParameters memory c,
                    BasicOrderParameters memory d,
                    BasicOrderParameters memory e
                ) internal pure returns (BasicOrderParameters[] memory) {
                    BasicOrderParameters[] memory arr = new BasicOrderParameters[](5);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    return arr;
                }
                function BasicOrderParametersArray(
                    BasicOrderParameters memory a,
                    BasicOrderParameters memory b,
                    BasicOrderParameters memory c,
                    BasicOrderParameters memory d,
                    BasicOrderParameters memory e,
                    BasicOrderParameters memory f
                ) internal pure returns (BasicOrderParameters[] memory) {
                    BasicOrderParameters[] memory arr = new BasicOrderParameters[](6);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    return arr;
                }
                function BasicOrderParametersArray(
                    BasicOrderParameters memory a,
                    BasicOrderParameters memory b,
                    BasicOrderParameters memory c,
                    BasicOrderParameters memory d,
                    BasicOrderParameters memory e,
                    BasicOrderParameters memory f,
                    BasicOrderParameters memory g
                ) internal pure returns (BasicOrderParameters[] memory) {
                    BasicOrderParameters[] memory arr = new BasicOrderParameters[](7);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    arr[6] = g;
                    return arr;
                }
                function Fulfillments(
                    Fulfillment memory a
                ) internal pure returns (Fulfillment[] memory) {
                    Fulfillment[] memory arr = new Fulfillment[](1);
                    arr[0] = a;
                    return arr;
                }
                function Fulfillments(
                    Fulfillment memory a,
                    Fulfillment memory b
                ) internal pure returns (Fulfillment[] memory) {
                    Fulfillment[] memory arr = new Fulfillment[](2);
                    arr[0] = a;
                    arr[1] = b;
                    return arr;
                }
                function Fulfillments(
                    Fulfillment memory a,
                    Fulfillment memory b,
                    Fulfillment memory c
                ) internal pure returns (Fulfillment[] memory) {
                    Fulfillment[] memory arr = new Fulfillment[](3);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    return arr;
                }
                function Fulfillments(
                    Fulfillment memory a,
                    Fulfillment memory b,
                    Fulfillment memory c,
                    Fulfillment memory d
                ) internal pure returns (Fulfillment[] memory) {
                    Fulfillment[] memory arr = new Fulfillment[](4);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    return arr;
                }
                function Fulfillments(
                    Fulfillment memory a,
                    Fulfillment memory b,
                    Fulfillment memory c,
                    Fulfillment memory d,
                    Fulfillment memory e
                ) internal pure returns (Fulfillment[] memory) {
                    Fulfillment[] memory arr = new Fulfillment[](5);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    return arr;
                }
                function Fulfillments(
                    Fulfillment memory a,
                    Fulfillment memory b,
                    Fulfillment memory c,
                    Fulfillment memory d,
                    Fulfillment memory e,
                    Fulfillment memory f
                ) internal pure returns (Fulfillment[] memory) {
                    Fulfillment[] memory arr = new Fulfillment[](6);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    return arr;
                }
                function Fulfillments(
                    Fulfillment memory a,
                    Fulfillment memory b,
                    Fulfillment memory c,
                    Fulfillment memory d,
                    Fulfillment memory e,
                    Fulfillment memory f,
                    Fulfillment memory g
                ) internal pure returns (Fulfillment[] memory) {
                    Fulfillment[] memory arr = new Fulfillment[](7);
                    arr[0] = a;
                    arr[1] = b;
                    arr[2] = c;
                    arr[3] = d;
                    arr[4] = e;
                    arr[5] = f;
                    arr[6] = g;
                    return arr;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.17;
            import {
                BasicOrderParameters,
                OrderParameters
            } from "../../../lib/ConsiderationStructs.sol";
            import {
                OrderType,
                BasicOrderType,
                ItemType,
                BasicOrderRouteType
            } from "../../../lib/ConsiderationEnums.sol";
            library SeaportEnumsLib {
                function parseBasicOrderType(
                    BasicOrderType basicOrderType
                )
                    internal
                    pure
                    returns (
                        OrderType orderType,
                        ItemType offerType,
                        ItemType considerationType,
                        ItemType additionalRecipientsType,
                        bool offerTypeIsAdditionalRecipientsType
                    )
                {
                    assembly {
                        // Mask all but 2 least-significant bits to derive the order type.
                        orderType := and(basicOrderType, 3)
                        // Divide basicOrderType by four to derive the route.
                        let route := shr(2, basicOrderType)
                        offerTypeIsAdditionalRecipientsType := gt(route, 3)
                        // If route > 1 additionalRecipient items are ERC20 (1) else Eth (0)
                        additionalRecipientsType := gt(route, 1)
                        // If route > 2, receivedItemType is route - 2. If route is 2,
                        // the receivedItemType is ERC20 (1). Otherwise, it is Eth (0).
                        considerationType := 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.
                        offerType := add(route, mul(iszero(additionalRecipientsType), 2))
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import {
                SeaportRouterInterface
            } from "../interfaces/SeaportRouterInterface.sol";
            import { SeaportInterface } from "../interfaces/SeaportInterface.sol";
            import { ReentrancyGuard } from "../lib/ReentrancyGuard.sol";
            import {
                Execution,
                AdvancedOrder,
                CriteriaResolver,
                FulfillmentComponent
            } from "../lib/ConsiderationStructs.sol";
            /**
             * @title  SeaportRouter
             * @author Ryan Ghods (ralxz.eth), 0age (0age.eth), James Wenzel (emo.eth)
             * @notice A utility contract for fulfilling orders with multiple
             *         Seaport versions. DISCLAIMER: This contract only works when
             *         all consideration items across all listings are native tokens.
             */
            contract SeaportRouter is SeaportRouterInterface, ReentrancyGuard {
                /// @dev The allowed v1.1 contract usable through this router.
                address private immutable _SEAPORT_V1_1;
                /// @dev The allowed v1.2 contract usable through this router.
                address private immutable _SEAPORT_V1_2;
                /**
                 * @dev Deploy contract with the supported Seaport contracts.
                 *
                 * @param seaportV1point1 The address of the Seaport v1.1 contract.
                 * @param seaportV1point2 The address of the Seaport v1.2 contract.
                 */
                constructor(address seaportV1point1, address seaportV1point2) {
                    _SEAPORT_V1_1 = seaportV1point1;
                    _SEAPORT_V1_2 = seaportV1point2;
                }
                /**
                 * @dev Fallback function to receive excess ether, in case total amount of
                 *      ether sent is more than the amount required to fulfill the order.
                 */
                receive() external payable override {
                    // Ensure we only receive ether from Seaport.
                    _assertSeaportAllowed(msg.sender);
                }
                /**
                 * @notice Fulfill available advanced orders through multiple Seaport
                 *         versions.
                 *         See {SeaportInterface-fulfillAvailableAdvancedOrders}
                 *
                 * @param params The parameters for fulfilling available advanced orders.
                 */
                function fulfillAvailableAdvancedOrders(
                    FulfillAvailableAdvancedOrdersParams calldata params
                )
                    external
                    payable
                    override
                    returns (
                        bool[][] memory availableOrders,
                        Execution[][] memory executions
                    )
                {
                    // Ensure this function cannot be triggered during a reentrant call.
                    _setReentrancyGuard(true);
                    // Put the number of Seaport contracts on the stack.
                    uint256 seaportContractsLength = params.seaportContracts.length;
                    // Set the availableOrders and executions arrays to the correct length.
                    availableOrders = new bool[][](seaportContractsLength);
                    executions = new Execution[][](seaportContractsLength);
                    // Track the number of order fulfillments left.
                    uint256 fulfillmentsLeft = params.maximumFulfilled;
                    // To help avoid stack too deep errors, we format the calldata
                    // params in a struct and put it on the stack.
                    AdvancedOrder[] memory emptyAdvancedOrders;
                    CriteriaResolver[] memory emptyCriteriaResolvers;
                    FulfillmentComponent[][] memory emptyFulfillmentComponents;
                    CalldataParams memory calldataParams = CalldataParams({
                        advancedOrders: emptyAdvancedOrders,
                        criteriaResolvers: emptyCriteriaResolvers,
                        offerFulfillments: emptyFulfillmentComponents,
                        considerationFulfillments: emptyFulfillmentComponents,
                        fulfillerConduitKey: params.fulfillerConduitKey,
                        recipient: params.recipient,
                        maximumFulfilled: fulfillmentsLeft
                    });
                    // Iterate through the provided Seaport contracts.
                    for (uint256 i = 0; i < params.seaportContracts.length; ) {
                        // Ensure the provided Seaport contract is allowed.
                        _assertSeaportAllowed(params.seaportContracts[i]);
                        // Put the order params on the stack.
                        AdvancedOrderParams calldata orderParams = params
                            .advancedOrderParams[i];
                        // Assign the variables to the calldata params.
                        calldataParams.advancedOrders = orderParams.advancedOrders;
                        calldataParams.criteriaResolvers = orderParams.criteriaResolvers;
                        calldataParams.offerFulfillments = orderParams.offerFulfillments;
                        calldataParams.considerationFulfillments = orderParams
                            .considerationFulfillments;
                        // Execute the orders, collecting availableOrders and executions.
                        // This is wrapped in a try/catch in case a single order is
                        // executed that is no longer available, leading to a revert
                        // with `NoSpecifiedOrdersAvailable()`.
                        try
                            SeaportInterface(params.seaportContracts[i])
                                .fulfillAvailableAdvancedOrders{
                                value: orderParams.etherValue
                            }(
                                calldataParams.advancedOrders,
                                calldataParams.criteriaResolvers,
                                calldataParams.offerFulfillments,
                                calldataParams.considerationFulfillments,
                                calldataParams.fulfillerConduitKey,
                                calldataParams.recipient,
                                calldataParams.maximumFulfilled
                            )
                        returns (
                            bool[] memory newAvailableOrders,
                            Execution[] memory newExecutions
                        ) {
                            availableOrders[i] = newAvailableOrders;
                            executions[i] = newExecutions;
                            // Subtract the number of orders fulfilled.
                            uint256 newAvailableOrdersLength = newAvailableOrders.length;
                            for (uint256 j = 0; j < newAvailableOrdersLength; ) {
                                if (newAvailableOrders[j]) {
                                    unchecked {
                                        --fulfillmentsLeft;
                                        ++j;
                                    }
                                }
                            }
                            // Break if the maximum number of executions has been reached.
                            if (fulfillmentsLeft == 0) {
                                break;
                            }
                        } catch {}
                        // Update fulfillments left.
                        calldataParams.maximumFulfilled = fulfillmentsLeft;
                        unchecked {
                            ++i;
                        }
                    }
                    // Return excess ether that may not have been used or was sent back.
                    if (address(this).balance > 0) {
                        _returnExcessEther();
                    }
                    // Clear the reentrancy guard.
                    _clearReentrancyGuard();
                }
                /**
                 * @notice Returns the Seaport contracts allowed to be used through this
                 *         router.
                 */
                function getAllowedSeaportContracts()
                    external
                    view
                    override
                    returns (address[] memory seaportContracts)
                {
                    seaportContracts = new address[](2);
                    seaportContracts[0] = _SEAPORT_V1_1;
                    seaportContracts[1] = _SEAPORT_V1_2;
                }
                /**
                 * @dev Reverts if the provided Seaport contract is not allowed.
                 */
                function _assertSeaportAllowed(address seaport) internal view {
                    if (
                        _cast(seaport == _SEAPORT_V1_1) | _cast(seaport == _SEAPORT_V1_2) ==
                        0
                    ) {
                        revert SeaportNotAllowed(seaport);
                    }
                }
                /**
                 * @dev Function to return excess ether, in case total amount of
                 *      ether sent is more than the amount required to fulfill the order.
                 */
                function _returnExcessEther() private {
                    // Send received funds back to msg.sender.
                    (bool success, bytes memory data) = payable(msg.sender).call{
                        value: address(this).balance
                    }("");
                    // Revert with an error if the ether transfer failed.
                    if (!success) {
                        revert EtherReturnTransferFailed(
                            msg.sender,
                            address(this).balance,
                            data
                        );
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import {
                AdvancedOrder,
                CriteriaResolver,
                FulfillmentComponent
            } from "../lib/ConsiderationStructs.sol";
            import { Execution } from "../lib/ConsiderationStructs.sol";
            /**
             * @title  SeaportRouterInterface
             * @author Ryan Ghods (ralxz.eth), 0age (0age.eth), James Wenzel (emo.eth)
             * @notice A utility contract for fulfilling orders with multiple
             *         Seaport versions. DISCLAIMER: This contract only works when
             *         all consideration items across all listings are native tokens.
             */
            interface SeaportRouterInterface {
                /**
                 * @dev Advanced order parameters for use through the
                 *      FulfillAvailableAdvancedOrdersParams struct.
                 */
                struct AdvancedOrderParams {
                    AdvancedOrder[] advancedOrders;
                    CriteriaResolver[] criteriaResolvers;
                    FulfillmentComponent[][] offerFulfillments;
                    FulfillmentComponent[][] considerationFulfillments;
                    uint256 etherValue; /// The ether value to send with the set of orders.
                }
                /**
                 * @dev Parameters for using fulfillAvailableAdvancedOrders
                 *      through SeaportRouter.
                 */
                struct FulfillAvailableAdvancedOrdersParams {
                    address[] seaportContracts;
                    AdvancedOrderParams[] advancedOrderParams;
                    bytes32 fulfillerConduitKey;
                    address recipient;
                    uint256 maximumFulfilled;
                }
                /**
                 * @dev Calldata params for calling FulfillAvailableAdvancedOrders.
                 */
                struct CalldataParams {
                    AdvancedOrder[] advancedOrders;
                    CriteriaResolver[] criteriaResolvers;
                    FulfillmentComponent[][] offerFulfillments;
                    FulfillmentComponent[][] considerationFulfillments;
                    bytes32 fulfillerConduitKey;
                    address recipient;
                    uint256 maximumFulfilled;
                }
                /**
                 * @dev Revert with an error if a provided Seaport contract is not allowed
                 *      to be used in the router.
                 */
                error SeaportNotAllowed(address seaport);
                /**
                 * @dev Revert with an error if an ether transfer back to the fulfiller
                 *      fails.
                 */
                error EtherReturnTransferFailed(
                    address recipient,
                    uint256 amount,
                    bytes returnData
                );
                /**
                 * @dev Fallback function to receive excess ether, in case total amount of
                 *      ether sent is more than the amount required to fulfill the order.
                 */
                receive() external payable;
                /**
                 * @notice Fulfill available advanced orders through multiple Seaport
                 *         versions.
                 *         See {SeaportInterface-fulfillAvailableAdvancedOrders}
                 *
                 * @param params The parameters for fulfilling available advanced orders.
                 */
                function fulfillAvailableAdvancedOrders(
                    FulfillAvailableAdvancedOrdersParams calldata params
                )
                    external
                    payable
                    returns (
                        bool[][] memory availableOrders,
                        Execution[][] memory executions
                    );
                /**
                 * @notice Returns the Seaport contracts allowed to be used through this
                 *         router.
                 */
                function getAllowedSeaportContracts()
                    external
                    view
                    returns (address[] memory);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.7;
            import {
                AdvancedOrder,
                CriteriaResolver
            } from "../../lib/ConsiderationStructs.sol";
            /**
             * @title ZoneInterface1.1
             * @author 0age
             * @custom:version 1.1
             *
             * @dev This is the legacy ZoneInterface from Seaport 1.1
             */
            interface ZoneInterface1_1 {
                // 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;
            import {
                BasicOrderParameters,
                OrderComponents,
                Fulfillment,
                FulfillmentComponent,
                Execution,
                Order,
                AdvancedOrder,
                OrderStatus,
                CriteriaResolver
            } from "../../lib/ConsiderationStructs.sol";
            /**
             * @title ConsiderationInterface1.1
             * @author 0age
             * @custom:version 1.1
             * *
             * @dev This is the legacy ConsiderationInterface from Seaport 1.1
             */
            interface ConsiderationInterface1_1 {
                /**
                 * @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);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            /**
             * @title EIP1271Interface
             * @notice Interface for the EIP-1271 standard signature validation method for
             *         contracts.
             */
            interface EIP1271Interface {
                /**
                 * @dev Validates a smart contract signature
                 *
                 * @param digest    bytes32 The digest of the data to be signed.
                 * @param signature bytes The signature of the data to be validated.
                 *
                 * @return bytes4 The magic value, if the signature is valid.
                 */
                function isValidSignature(
                    bytes32 digest,
                    bytes calldata signature
                ) external view returns (bytes4);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            /**
             * @title ImmutableCreate2FactoryInterface
             * @author 0age
             * @notice This contract provides a safeCreate2 function that takes a salt value
             *         and a block of initialization code as arguments and passes them into
             *         inline assembly. The contract prevents redeploys by maintaining a
             *         mapping of all contracts that have already been deployed, and
             *         prevents frontrunning or other collisions by requiring that the first
             *         20 bytes of the salt are equal to the address of the caller (this can
             *         be bypassed by setting the first 20 bytes to the null address). There
             *         is also a view function that computes the address of the contract
             *         that will be created when submitting a given salt or nonce along with
             *         a given block of initialization code.
             */
            interface ImmutableCreate2FactoryInterface {
                /**
                 * @dev Create a contract using CREATE2 by submitting a given salt or nonce
                 *      along with the initialization code for the contract. Note that the
                 *      first 20 bytes of the salt must match those of the calling address,
                 *      which prevents contract creation events from being submitted by
                 *      unintended parties.
                 *
                 * @param salt               The nonce that will be passed into the CREATE2
                 *                           call.
                 * @param initializationCode The initialization code that will be passed
                 *                           into the CREATE2 call.
                 *
                 * @return deploymentAddress Address of the contract that will be created.
                 */
                function safeCreate2(
                    bytes32 salt,
                    bytes calldata initializationCode
                ) external payable returns (address deploymentAddress);
                /**
                 * @dev Compute the address of the contract that will be created when
                 *      submitting a given salt or nonce to the contract along with the
                 *      contract's initialization code. The CREATE2 address is computed in
                 *      accordance with EIP-1014, and adheres to the formula therein of
                 *      `keccak256( 0xff ++ address ++ salt ++ keccak256(init_code)))[12:]`
                 *      when performing the computation. The computed address is then
                 *      checked for any existing contract code - if so, the null address
                 *      will be returned instead.
                 *
                 * @param salt     The nonce passed into the CREATE2 address calculation.
                 * @param initCode The contract initialization code to be used that will be
                 *                 passed into the CREATE2 address calculation.
                 *
                 * @return deploymentAddress Address of the contract that will be created,
                 *                           or the null address if a contract already
                 *                           exists at that address.
                 */
                function findCreate2Address(
                    bytes32 salt,
                    bytes calldata initCode
                ) external view returns (address deploymentAddress);
                /**
                 * @dev Compute the address of the contract that will be created when
                 *      submitting a given salt or nonce to the contract along with the
                 *      keccak256 hash of the contract's initialization code. The CREATE2
                 *      address is computed in accordance with EIP-1014, and adheres to the
                 *      `keccak256( 0xff ++ address ++ salt ++ keccak256(init_code)))[12:]`
                 *      formula when performing the computation. The computed address is
                 *      then checked for any existing contract code - if so, the null
                 *      address will be returned instead.
                 *
                 * @param salt         The nonce passed into the CREATE2 address
                 *                     calculation.
                 * @param initCodeHash The keccak256 hash of the initialization code that
                 *                     will be passed into the CREATE2 address calculation.
                 *
                 * @return deploymentAddress Address of the contract that will be created,
                 *                           or the null address if a contract already
                 *                           exists at that address.
                 */
                function findCreate2AddressViaHash(
                    bytes32 salt,
                    bytes32 initCodeHash
                ) external view returns (address deploymentAddress);
                /**
                 * @dev Determine if a contract has already been deployed by the factory to
                 *      a given address.
                 *
                 * @param deploymentAddress The contract address to check.
                 *
                 * @return True if the contract has been deployed, false otherwise.
                 */
                function hasBeenDeployed(
                    address deploymentAddress
                ) external view returns (bool);
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            interface ERC20ApprovalInterface {
                function approve(address, uint256) external returns (bool);
            }
            interface NFTApprovalInterface {
                function setApprovalForAll(address, bool) external;
            }
            contract EIP1271Wallet {
                bytes4 private constant _EIP_1271_MAGIC_VALUE = 0x1626ba7e;
                address public immutable owner;
                bool public showRevertMessage;
                mapping(bytes32 => bool) public digestApproved;
                bool public isValid;
                constructor(address _owner) {
                    owner = _owner;
                    showRevertMessage = true;
                    isValid = true;
                }
                function setValid(bool valid) external {
                    isValid = valid;
                }
                function revertWithMessage(bool showMessage) external {
                    showRevertMessage = showMessage;
                }
                function registerDigest(bytes32 digest, bool approved) external {
                    digestApproved[digest] = approved;
                }
                function approveERC20(
                    ERC20ApprovalInterface token,
                    address operator,
                    uint256 amount
                ) external {
                    if (msg.sender != owner) {
                        revert("Only owner");
                    }
                    token.approve(operator, amount);
                }
                function approveNFT(NFTApprovalInterface token, address operator) external {
                    if (msg.sender != owner) {
                        revert("Only owner");
                    }
                    token.setApprovalForAll(operator, true);
                }
                function isValidSignature(
                    bytes32 digest,
                    bytes memory signature
                ) external view returns (bytes4) {
                    if (digestApproved[digest]) {
                        return _EIP_1271_MAGIC_VALUE;
                    }
                    // NOTE: this is obviously not secure, do not use outside of testing.
                    if (signature.length == 64) {
                        // All signatures of length 64 are OK as long as valid is true
                        return isValid ? _EIP_1271_MAGIC_VALUE : bytes4(0xffffffff);
                    }
                    if (signature.length != 65) {
                        revert();
                    }
                    bytes32 r;
                    bytes32 s;
                    uint8 v;
                    assembly {
                        r := mload(add(signature, 0x20))
                        s := mload(add(signature, 0x40))
                        v := byte(0, mload(add(signature, 0x60)))
                    }
                    if (
                        uint256(s) >
                        0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0
                    ) {
                        revert();
                    }
                    if (v != 27 && v != 28) {
                        revert();
                    }
                    address signer = ecrecover(digest, v, r, s);
                    if (signer == address(0)) {
                        revert();
                    }
                    if (signer != owner) {
                        if (showRevertMessage) {
                            revert("BAD SIGNER");
                        }
                        revert();
                    }
                    return isValid ? _EIP_1271_MAGIC_VALUE : bytes4(0xffffffff);
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            contract ERC1155BatchRecipient {
                error UnexpectedBatchData();
                function onERC1155BatchReceived(
                    address,
                    address,
                    uint256[] calldata,
                    uint256[] calldata,
                    bytes memory data
                ) external pure returns (bytes4) {
                    if (data.length != 0) {
                        revert UnexpectedBatchData();
                    }
                    return ERC1155BatchRecipient.onERC1155BatchReceived.selector;
                }
            }
            // SPDX-License-Identifier: Unlicense
            pragma solidity ^0.8.13;
            contract ExcessReturnDataRecipient {
                uint256 private revertDataSize;
                function setRevertDataSize(uint256 size) external {
                    revertDataSize = size;
                }
                // Code created with the help of Stack Exchange question
                // https://ethereum.stackexchange.com/questions/8086
                // Question by Doug King:
                // https://ethereum.stackexchange.com/users/2041/doug-king
                // Answer by Tjaden Hess:
                // https://ethereum.stackexchange.com/users/131/tjaden-hess
                // Modified to use Yul instead of Solidity and added change of
                // base to convert to natural logarithm
                function ln(uint256 x) internal pure returns (uint256 y) {
                    assembly {
                        let arg := x
                        x := sub(x, 1)
                        x := or(x, div(x, 0x02))
                        x := or(x, div(x, 0x04))
                        x := or(x, div(x, 0x10))
                        x := or(x, div(x, 0x100))
                        x := or(x, div(x, 0x10000))
                        x := or(x, div(x, 0x100000000))
                        x := or(x, div(x, 0x10000000000000000))
                        x := or(x, div(x, 0x100000000000000000000000000000000))
                        x := add(x, 1)
                        let m := mload(0x40)
                        mstore(
                            m,
                            0xf8f9cbfae6cc78fbefe7cdc3a1793dfcf4f0e8bbd8cec470b6a28a7a5a3e1efd
                        )
                        mstore(
                            add(m, 0x20),
                            0xf5ecf1b3e9debc68e1d9cfabc5997135bfb7a7a3938b7b606b5b4b3f2f1f0ffe
                        )
                        mstore(
                            add(m, 0x40),
                            0xf6e4ed9ff2d6b458eadcdf97bd91692de2d4da8fd2d0ac50c6ae9a8272523616
                        )
                        mstore(
                            add(m, 0x60),
                            0xc8c0b887b0a8a4489c948c7f847c6125746c645c544c444038302820181008ff
                        )
                        mstore(
                            add(m, 0x80),
                            0xf7cae577eec2a03cf3bad76fb589591debb2dd67e0aa9834bea6925f6a4a2e0e
                        )
                        mstore(
                            add(m, 0xa0),
                            0xe39ed557db96902cd38ed14fad815115c786af479b7e83247363534337271707
                        )
                        mstore(
                            add(m, 0xc0),
                            0xc976c13bb96e881cb166a933a55e490d9d56952b8d4e801485467d2362422606
                        )
                        mstore(
                            add(m, 0xe0),
                            0x753a6d1b65325d0c552a4d1345224105391a310b29122104190a110309020100
                        )
                        mstore(0x40, add(m, 0x100))
                        let
                            magic
                        := 0x818283848586878898a8b8c8d8e8f929395969799a9b9d9e9faaeb6bedeeff
                        let
                            shift
                        := 0x100000000000000000000000000000000000000000000000000000000000000
                        let a := div(mul(x, magic), shift)
                        y := div(mload(add(m, sub(255, a))), shift)
                        y := add(
                            y,
                            mul(
                                256,
                                gt(
                                    arg,
                                    0x8000000000000000000000000000000000000000000000000000000000000000
                                )
                            )
                        )
                        y := mul(y, 10000000000000000)
                        y := div(y, 14426950408889632)
                    }
                }
                function sqrt(uint256 y) internal pure returns (uint256 z) {
                    assembly {
                        switch gt(y, 3)
                        case 1 {
                            z := y
                            let x := div(add(y, 1), 2)
                            for {
                            } lt(x, z) {
                            } {
                                z := x
                                x := div(add(div(y, x), x), 2)
                            }
                        }
                        case 0 {
                            z := 1
                        }
                    }
                }
                function onERC1155Received(
                    address,
                    address,
                    uint256,
                    uint256,
                    bytes calldata
                ) external view returns (bytes4 magic) {
                    magic = this.onERC1155Received.selector;
                    if (revertDataSize > 0) {
                        uint256 gasToCalculateSqrt = (54 * ln(gasleft())) + 1200;
                        uint256 w = (sqrt(
                            2048 * (gasleft() - gasToCalculateSqrt) + 9431040
                        ) - 3072) / 4;
                        assembly {
                            let size := mul(w, 32)
                            calldatacopy(0, 0, mul(w, 32))
                            revert(0, size)
                        }
                    }
                }
                receive() external payable {
                    if (revertDataSize > 0) {
                        uint256 gasToCalculateSqrt = (54 * ln(gasleft())) + 1200;
                        uint256 w = (sqrt(
                            2048 * (gasleft() - gasToCalculateSqrt) + 9431040
                        ) - 3072) / 2;
                        assembly {
                            let size := mul(w, 32)
                            calldatacopy(0, 0, mul(w, 32))
                            revert(0, size)
                        }
                    }
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            interface IERC721Receiver {
                function onERC721Received(
                    address,
                    address,
                    uint256,
                    bytes calldata
                ) external returns (bytes4);
            }
            contract InvalidERC721Recipient is IERC721Receiver {
                function onERC721Received(
                    address /* operator */,
                    address /* from */,
                    uint256 /* tokenId */,
                    bytes calldata /* data */
                ) external pure override returns (bytes4) {
                    return 0xabcd0000;
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            contract InvalidEthRecipient {
                receive() external payable {
                    revert(
                        "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
                    );
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            contract Reenterer {
                bool public isPrepared;
                address public target;
                uint256 public msgValue;
                bytes public callData;
                event Reentered(bytes returnData);
                function prepare(
                    address targetToUse,
                    uint256 msgValueToUse,
                    bytes calldata callDataToUse
                ) external {
                    target = targetToUse;
                    msgValue = msgValueToUse;
                    callData = callDataToUse;
                    isPrepared = true;
                }
                receive() external payable {
                    if (isPrepared) {
                        (bool success, bytes memory returnData) = target.call{
                            value: msgValue
                        }(callData);
                        if (!success) {
                            assembly {
                                returndatacopy(0, 0, returndatasize())
                                revert(0, returndatasize())
                            }
                        }
                        emit Reentered(returnData);
                        isPrepared = false;
                    }
                }
                function execute(address to, uint256 value, bytes memory data) external {
                    (bool success, ) = payable(to).call{ value: value }(data);
                    if (!success) {
                        assembly {
                            returndatacopy(0, 0, returndatasize())
                            revert(0, returndatasize())
                        }
                    }
                }
            }
            // SPDX-License-Identifier: Unlicense
            pragma solidity ^0.8.13;
            import { ERC1155 } from "@rari-capital/solmate/src/tokens/ERC1155.sol";
            // Used for minting test ERC1155s in our tests
            contract TestERC1155 is ERC1155 {
                function mint(
                    address to,
                    uint256 tokenId,
                    uint256 amount
                ) public returns (bool) {
                    _mint(to, tokenId, amount, "");
                    return true;
                }
                function uri(uint256) public pure override returns (string memory) {
                    return "uri";
                }
            }
            // SPDX-License-Identifier: AGPL-3.0-only
            pragma solidity >=0.8.0;
            /// @notice Minimalist and gas efficient standard ERC1155 implementation.
            /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC1155.sol)
            abstract contract ERC1155 {
                /*//////////////////////////////////////////////////////////////
                                             EVENTS
                //////////////////////////////////////////////////////////////*/
                event TransferSingle(
                    address indexed operator,
                    address indexed from,
                    address indexed to,
                    uint256 id,
                    uint256 amount
                );
                event TransferBatch(
                    address indexed operator,
                    address indexed from,
                    address indexed to,
                    uint256[] ids,
                    uint256[] amounts
                );
                event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
                event URI(string value, uint256 indexed id);
                /*//////////////////////////////////////////////////////////////
                                         ERC1155 STORAGE
                //////////////////////////////////////////////////////////////*/
                mapping(address => mapping(uint256 => uint256)) public balanceOf;
                mapping(address => mapping(address => bool)) public isApprovedForAll;
                /*//////////////////////////////////////////////////////////////
                                         METADATA LOGIC
                //////////////////////////////////////////////////////////////*/
                function uri(uint256 id) public view virtual returns (string memory);
                /*//////////////////////////////////////////////////////////////
                                          ERC1155 LOGIC
                //////////////////////////////////////////////////////////////*/
                function setApprovalForAll(address operator, bool approved) public virtual {
                    isApprovedForAll[msg.sender][operator] = approved;
                    emit ApprovalForAll(msg.sender, operator, approved);
                }
                function safeTransferFrom(
                    address from,
                    address to,
                    uint256 id,
                    uint256 amount,
                    bytes calldata data
                ) public virtual {
                    require(msg.sender == from || isApprovedForAll[from][msg.sender], "NOT_AUTHORIZED");
                    balanceOf[from][id] -= amount;
                    balanceOf[to][id] += amount;
                    emit TransferSingle(msg.sender, from, to, id, amount);
                    require(
                        to.code.length == 0
                            ? to != address(0)
                            : ERC1155TokenReceiver(to).onERC1155Received(msg.sender, from, id, amount, data) ==
                                ERC1155TokenReceiver.onERC1155Received.selector,
                        "UNSAFE_RECIPIENT"
                    );
                }
                function safeBatchTransferFrom(
                    address from,
                    address to,
                    uint256[] calldata ids,
                    uint256[] calldata amounts,
                    bytes calldata data
                ) public virtual {
                    require(ids.length == amounts.length, "LENGTH_MISMATCH");
                    require(msg.sender == from || isApprovedForAll[from][msg.sender], "NOT_AUTHORIZED");
                    // Storing these outside the loop saves ~15 gas per iteration.
                    uint256 id;
                    uint256 amount;
                    for (uint256 i = 0; i < ids.length; ) {
                        id = ids[i];
                        amount = amounts[i];
                        balanceOf[from][id] -= amount;
                        balanceOf[to][id] += amount;
                        // An array can't have a total length
                        // larger than the max uint256 value.
                        unchecked {
                            ++i;
                        }
                    }
                    emit TransferBatch(msg.sender, from, to, ids, amounts);
                    require(
                        to.code.length == 0
                            ? to != address(0)
                            : ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, from, ids, amounts, data) ==
                                ERC1155TokenReceiver.onERC1155BatchReceived.selector,
                        "UNSAFE_RECIPIENT"
                    );
                }
                function balanceOfBatch(address[] calldata owners, uint256[] calldata ids)
                    public
                    view
                    virtual
                    returns (uint256[] memory balances)
                {
                    require(owners.length == ids.length, "LENGTH_MISMATCH");
                    balances = new uint256[](owners.length);
                    // Unchecked because the only math done is incrementing
                    // the array index counter which cannot possibly overflow.
                    unchecked {
                        for (uint256 i = 0; i < owners.length; ++i) {
                            balances[i] = balanceOf[owners[i]][ids[i]];
                        }
                    }
                }
                /*//////////////////////////////////////////////////////////////
                                          ERC165 LOGIC
                //////////////////////////////////////////////////////////////*/
                function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
                    return
                        interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
                        interfaceId == 0xd9b67a26 || // ERC165 Interface ID for ERC1155
                        interfaceId == 0x0e89341c; // ERC165 Interface ID for ERC1155MetadataURI
                }
                /*//////////////////////////////////////////////////////////////
                                    INTERNAL MINT/BURN LOGIC
                //////////////////////////////////////////////////////////////*/
                function _mint(
                    address to,
                    uint256 id,
                    uint256 amount,
                    bytes memory data
                ) internal virtual {
                    balanceOf[to][id] += amount;
                    emit TransferSingle(msg.sender, address(0), to, id, amount);
                    require(
                        to.code.length == 0
                            ? to != address(0)
                            : ERC1155TokenReceiver(to).onERC1155Received(msg.sender, address(0), id, amount, data) ==
                                ERC1155TokenReceiver.onERC1155Received.selector,
                        "UNSAFE_RECIPIENT"
                    );
                }
                function _batchMint(
                    address to,
                    uint256[] memory ids,
                    uint256[] memory amounts,
                    bytes memory data
                ) internal virtual {
                    uint256 idsLength = ids.length; // Saves MLOADs.
                    require(idsLength == amounts.length, "LENGTH_MISMATCH");
                    for (uint256 i = 0; i < idsLength; ) {
                        balanceOf[to][ids[i]] += amounts[i];
                        // An array can't have a total length
                        // larger than the max uint256 value.
                        unchecked {
                            ++i;
                        }
                    }
                    emit TransferBatch(msg.sender, address(0), to, ids, amounts);
                    require(
                        to.code.length == 0
                            ? to != address(0)
                            : ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, address(0), ids, amounts, data) ==
                                ERC1155TokenReceiver.onERC1155BatchReceived.selector,
                        "UNSAFE_RECIPIENT"
                    );
                }
                function _batchBurn(
                    address from,
                    uint256[] memory ids,
                    uint256[] memory amounts
                ) internal virtual {
                    uint256 idsLength = ids.length; // Saves MLOADs.
                    require(idsLength == amounts.length, "LENGTH_MISMATCH");
                    for (uint256 i = 0; i < idsLength; ) {
                        balanceOf[from][ids[i]] -= amounts[i];
                        // An array can't have a total length
                        // larger than the max uint256 value.
                        unchecked {
                            ++i;
                        }
                    }
                    emit TransferBatch(msg.sender, from, address(0), ids, amounts);
                }
                function _burn(
                    address from,
                    uint256 id,
                    uint256 amount
                ) internal virtual {
                    balanceOf[from][id] -= amount;
                    emit TransferSingle(msg.sender, from, address(0), id, amount);
                }
            }
            /// @notice A generic interface for a contract which properly accepts ERC1155 tokens.
            /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC1155.sol)
            abstract contract ERC1155TokenReceiver {
                function onERC1155Received(
                    address,
                    address,
                    uint256,
                    uint256,
                    bytes calldata
                ) external virtual returns (bytes4) {
                    return ERC1155TokenReceiver.onERC1155Received.selector;
                }
                function onERC1155BatchReceived(
                    address,
                    address,
                    uint256[] calldata,
                    uint256[] calldata,
                    bytes calldata
                ) external virtual returns (bytes4) {
                    return ERC1155TokenReceiver.onERC1155BatchReceived.selector;
                }
            }
            // SPDX-License-Identifier: Unlicense
            pragma solidity ^0.8.0;
            contract TestERC1155Revert {
                function safeTransferFrom(
                    address /* from */,
                    address /* to */,
                    uint256 /* id */,
                    uint256 /* amount */,
                    bytes calldata /* data */
                ) public pure {
                    revert(
                        "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
                    );
                }
                function safeBatchTransferFrom(
                    address /* from */,
                    address /* to */,
                    uint256[] memory /* ids */,
                    uint256[] memory /* values */,
                    bytes memory /* data */
                ) public pure {
                    revert("Some ERC1155 revert message for batch transfers");
                }
                function getRevertData() public pure returns (bytes memory) {
                    assembly {
                        mstore(0x40, 0)
                        mstore(0, shl(20, 1))
                        mstore(add(0x20, shl(20, 1)), 1)
                        return(0, add(0x20, shl(20, 1)))
                    }
                }
            }
            // SPDX-License-Identifier: Unlicense
            pragma solidity ^0.8.13;
            import { ERC20 } from "@rari-capital/solmate/src/tokens/ERC20.sol";
            // Used for minting test ERC20s in our tests
            contract TestERC20 is ERC20("Test20", "TST20", 18) {
                bool public blocked;
                bool public noReturnData;
                constructor() {
                    blocked = false;
                    noReturnData = false;
                }
                function blockTransfer(bool blocking) external {
                    blocked = blocking;
                }
                function setNoReturnData(bool noReturn) external {
                    noReturnData = noReturn;
                }
                function mint(address to, uint256 amount) external returns (bool) {
                    _mint(to, amount);
                    return true;
                }
                function transferFrom(
                    address from,
                    address to,
                    uint256 amount
                ) public override returns (bool ok) {
                    if (blocked) {
                        return false;
                    }
                    super.transferFrom(from, to, amount);
                    if (noReturnData) {
                        assembly {
                            return(0, 0)
                        }
                    }
                    ok = true;
                }
            }
            // SPDX-License-Identifier: AGPL-3.0-only
            pragma solidity >=0.8.0;
            /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
            /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol)
            /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
            /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
            abstract contract ERC20 {
                /*//////////////////////////////////////////////////////////////
                                             EVENTS
                //////////////////////////////////////////////////////////////*/
                event Transfer(address indexed from, address indexed to, uint256 amount);
                event Approval(address indexed owner, address indexed spender, uint256 amount);
                /*//////////////////////////////////////////////////////////////
                                        METADATA STORAGE
                //////////////////////////////////////////////////////////////*/
                string public name;
                string public symbol;
                uint8 public immutable decimals;
                /*//////////////////////////////////////////////////////////////
                                          ERC20 STORAGE
                //////////////////////////////////////////////////////////////*/
                uint256 public totalSupply;
                mapping(address => uint256) public balanceOf;
                mapping(address => mapping(address => uint256)) public allowance;
                /*//////////////////////////////////////////////////////////////
                                        EIP-2612 STORAGE
                //////////////////////////////////////////////////////////////*/
                uint256 internal immutable INITIAL_CHAIN_ID;
                bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
                mapping(address => uint256) public nonces;
                /*//////////////////////////////////////////////////////////////
                                           CONSTRUCTOR
                //////////////////////////////////////////////////////////////*/
                constructor(
                    string memory _name,
                    string memory _symbol,
                    uint8 _decimals
                ) {
                    name = _name;
                    symbol = _symbol;
                    decimals = _decimals;
                    INITIAL_CHAIN_ID = block.chainid;
                    INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
                }
                /*//////////////////////////////////////////////////////////////
                                           ERC20 LOGIC
                //////////////////////////////////////////////////////////////*/
                function approve(address spender, uint256 amount) public virtual returns (bool) {
                    allowance[msg.sender][spender] = amount;
                    emit Approval(msg.sender, spender, amount);
                    return true;
                }
                function transfer(address to, uint256 amount) public virtual returns (bool) {
                    balanceOf[msg.sender] -= amount;
                    // Cannot overflow because the sum of all user
                    // balances can't exceed the max uint256 value.
                    unchecked {
                        balanceOf[to] += amount;
                    }
                    emit Transfer(msg.sender, to, amount);
                    return true;
                }
                function transferFrom(
                    address from,
                    address to,
                    uint256 amount
                ) public virtual returns (bool) {
                    uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
                    if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
                    balanceOf[from] -= amount;
                    // Cannot overflow because the sum of all user
                    // balances can't exceed the max uint256 value.
                    unchecked {
                        balanceOf[to] += amount;
                    }
                    emit Transfer(from, to, amount);
                    return true;
                }
                /*//////////////////////////////////////////////////////////////
                                         EIP-2612 LOGIC
                //////////////////////////////////////////////////////////////*/
                function permit(
                    address owner,
                    address spender,
                    uint256 value,
                    uint256 deadline,
                    uint8 v,
                    bytes32 r,
                    bytes32 s
                ) public virtual {
                    require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
                    // Unchecked because the only math done is incrementing
                    // the owner's nonce which cannot realistically overflow.
                    unchecked {
                        address recoveredAddress = ecrecover(
                            keccak256(
                                abi.encodePacked(
                                    "\\x19\\x01",
                                    DOMAIN_SEPARATOR(),
                                    keccak256(
                                        abi.encode(
                                            keccak256(
                                                "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                            ),
                                            owner,
                                            spender,
                                            value,
                                            nonces[owner]++,
                                            deadline
                                        )
                                    )
                                )
                            ),
                            v,
                            r,
                            s
                        );
                        require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
                        allowance[recoveredAddress][spender] = value;
                    }
                    emit Approval(owner, spender, value);
                }
                function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
                    return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
                }
                function computeDomainSeparator() internal view virtual returns (bytes32) {
                    return
                        keccak256(
                            abi.encode(
                                keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                                keccak256(bytes(name)),
                                keccak256("1"),
                                block.chainid,
                                address(this)
                            )
                        );
                }
                /*//////////////////////////////////////////////////////////////
                                    INTERNAL MINT/BURN LOGIC
                //////////////////////////////////////////////////////////////*/
                function _mint(address to, uint256 amount) internal virtual {
                    totalSupply += amount;
                    // Cannot overflow because the sum of all user
                    // balances can't exceed the max uint256 value.
                    unchecked {
                        balanceOf[to] += amount;
                    }
                    emit Transfer(address(0), to, amount);
                }
                function _burn(address from, uint256 amount) internal virtual {
                    balanceOf[from] -= amount;
                    // Cannot underflow because a user's balance
                    // will never be larger than the total supply.
                    unchecked {
                        totalSupply -= amount;
                    }
                    emit Transfer(from, address(0), amount);
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import { ERC20 } from "@rari-capital/solmate/src/tokens/ERC20.sol";
            contract TestERC20Revert is ERC20("TestRevert", "REVERT", 18) {
                function mint(address to, uint256 amount) external {
                    _mint(to, amount);
                }
                function transferFrom(
                    address /* from */,
                    address /* to */,
                    uint256 /* amount */
                ) public pure override returns (bool) {
                    revert(
                        "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
                    );
                }
            }
            // SPDX-License-Identifier: MIT
            pragma solidity ^0.8.13;
            import { ERC20 } from "@rari-capital/solmate/src/tokens/ERC20.sol";
            contract TestERC20Panic is ERC20("TestPanic", "PANIC", 18) {
                function mint(address to, uint256 amount) external returns (bool) {
                    _mint(to, amount);
                    return true;
                }
                function transferFrom(
                    address /* from */,
                    address /* to */,
                    uint256 /* amount */
                ) public pure override returns (bool) {
                    uint256 a = uint256(0) / uint256(0);
                    a;
                    return true;
                }
            }
            // SPDX-License-Identifier: Unlicense
            pragma solidity ^0.8.13;
            import { ERC20 } from "@rari-capital/solmate/src/tokens/ERC20.sol";
            // Used for minting test ERC20s in our tests.
            contract TestERC20NotOk is ERC20("Test20NotOk", "TST20NO", 18) {
                bool public notOk;
                function mint(address to, uint256 amount) external returns (bool) {
                    _mint(to, amount);
                    return true;
                }
                function transferFrom(
                    address /* from */,
                    address /* to */,
                    uint256 /* amount */
                ) public pure override returns (bool) {
                    return false;
                }
            }
            // SPDX-License-Identifier: Unlicense
            pragma solidity ^0.8.13;
            import { ERC721 } from "@rari-capital/solmate/src/tokens/ERC721.sol";
            // Used for minting test ERC721s in our tests
            contract TestERC721 is ERC721("Test721", "TST721") {
                function mint(address to, uint256 tokenId) public returns (bool) {
                    _mint(to, tokenId);
                    return true;
                }
                function tokenURI(uint256) public pure override returns (string memory) {
                    return "tokenURI";
                }
            }
            // SPDX-License-Identifier: AGPL-3.0-only
            pragma solidity >=0.8.0;
            /// @notice Modern, minimalist, and gas efficient ERC-721 implementation.
            /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)
            abstract contract ERC721 {
                /*//////////////////////////////////////////////////////////////
                                             EVENTS
                //////////////////////////////////////////////////////////////*/
                event Transfer(address indexed from, address indexed to, uint256 indexed id);
                event Approval(address indexed owner, address indexed spender, uint256 indexed id);
                event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
                /*//////////////////////////////////////////////////////////////
                                     METADATA STORAGE/LOGIC
                //////////////////////////////////////////////////////////////*/
                string public name;
                string public symbol;
                function tokenURI(uint256 id) public view virtual returns (string memory);
                /*//////////////////////////////////////////////////////////////
                                  ERC721 BALANCE/OWNER STORAGE
                //////////////////////////////////////////////////////////////*/
                mapping(uint256 => address) internal _ownerOf;
                mapping(address => uint256) internal _balanceOf;
                function ownerOf(uint256 id) public view virtual returns (address owner) {
                    require((owner = _ownerOf[id]) != address(0), "NOT_MINTED");
                }
                function balanceOf(address owner) public view virtual returns (uint256) {
                    require(owner != address(0), "ZERO_ADDRESS");
                    return _balanceOf[owner];
                }
                /*//////////////////////////////////////////////////////////////
                                     ERC721 APPROVAL STORAGE
                //////////////////////////////////////////////////////////////*/
                mapping(uint256 => address) public getApproved;
                mapping(address => mapping(address => bool)) public isApprovedForAll;
                /*//////////////////////////////////////////////////////////////
                                           CONSTRUCTOR
                //////////////////////////////////////////////////////////////*/
                constructor(string memory _name, string memory _symbol) {
                    name = _name;
                    symbol = _symbol;
                }
                /*//////////////////////////////////////////////////////////////
                                          ERC721 LOGIC
                //////////////////////////////////////////////////////////////*/
                function approve(address spender, uint256 id) public virtual {
                    address owner = _ownerOf[id];
                    require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "NOT_AUTHORIZED");
                    getApproved[id] = spender;
                    emit Approval(owner, spender, id);
                }
                function setApprovalForAll(address operator, bool approved) public virtual {
                    isApprovedForAll[msg.sender][operator] = approved;
                    emit ApprovalForAll(msg.sender, operator, approved);
                }
                function transferFrom(
                    address from,
                    address to,
                    uint256 id
                ) public virtual {
                    require(from == _ownerOf[id], "WRONG_FROM");
                    require(to != address(0), "INVALID_RECIPIENT");
                    require(
                        msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],
                        "NOT_AUTHORIZED"
                    );
                    // Underflow of the sender's balance is impossible because we check for
                    // ownership above and the recipient's balance can't realistically overflow.
                    unchecked {
                        _balanceOf[from]--;
                        _balanceOf[to]++;
                    }
                    _ownerOf[id] = to;
                    delete getApproved[id];
                    emit Transfer(from, to, id);
                }
                function safeTransferFrom(
                    address from,
                    address to,
                    uint256 id
                ) public virtual {
                    transferFrom(from, to, id);
                    require(
                        to.code.length == 0 ||
                            ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") ==
                            ERC721TokenReceiver.onERC721Received.selector,
                        "UNSAFE_RECIPIENT"
                    );
                }
                function safeTransferFrom(
                    address from,
                    address to,
                    uint256 id,
                    bytes calldata data
                ) public virtual {
                    transferFrom(from, to, id);
                    require(
                        to.code.length == 0 ||
                            ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==
                            ERC721TokenReceiver.onERC721Received.selector,
                        "UNSAFE_RECIPIENT"
                    );
                }
                /*//////////////////////////////////////////////////////////////
                                          ERC165 LOGIC
                //////////////////////////////////////////////////////////////*/
                function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
                    return
                        interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
                        interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721
                        interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata
                }
                /*//////////////////////////////////////////////////////////////
                                    INTERNAL MINT/BURN LOGIC
                //////////////////////////////////////////////////////////////*/
                function _mint(address to, uint256 id) internal virtual {
                    require(to != address(0), "INVALID_RECIPIENT");
                    require(_ownerOf[id] == address(0), "ALREADY_MINTED");
                    // Counter overflow is incredibly unrealistic.
                    unchecked {
                        _balanceOf[to]++;
                    }
                    _ownerOf[id] = to;
                    emit Transfer(address(0), to, id);
                }
                function _burn(uint256 id) internal virtual {
                    address owner = _ownerOf[id];
                    require(owner != address(0), "NOT_MINTED");
                    // Ownership check above ensures no underflow.
                    unchecked {
                        _balanceOf[owner]--;
                    }
                    delete _ownerOf[id];
                    delete getApproved[id];
                    emit Transfer(owner, address(0), id);
                }
                /*//////////////////////////////////////////////////////////////
                                    INTERNAL SAFE MINT LOGIC
                //////////////////////////////////////////////////////////////*/
                function _safeMint(address to, uint256 id) internal virtual {
                    _mint(to, id);
                    require(
                        to.code.length == 0 ||
                            ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") ==
                            ERC721TokenReceiver.onERC721Received.selector,
                        "UNSAFE_RECIPIENT"
                    );
                }
                function _safeMint(
                    address to,
                    uint256 id,
                    bytes memory data
                ) internal virtual {
                    _mint(to, id);
                    require(
                        to.code.length == 0 ||
                            ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==
                            ERC721TokenReceiver.onERC721Received.selector,
                        "UNSAFE_RECIPIENT"
                    );
                }
            }
            /// @notice A generic interface for a contract which properly accepts ERC721 tokens.
            /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)
            abstract contract ERC721TokenReceiver {
                function onERC721Received(
                    address,
                    address,
                    uint256,
                    bytes calldata
                ) external virtual returns (bytes4) {
                    return ERC721TokenReceiver.onERC721Received.selector;
                }
            }
            // SPDX-License-Identifier: Unlicense
            pragma solidity ^0.8.0;
            contract TestERC721Revert {
                function transferFrom(
                    address /* from */,
                    address /* to */,
                    uint256 /* amount */
                ) public pure {
                    revert(
                        "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
                    );
                }
            }
            

            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 - <stefan@gnosis.io>
            /// @author Richard Meissner - <richard@gnosis.io>
            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 - <richard@gnosis.pm>
            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 - <richard@gnosis.pm>
            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 - <richard@gnosis.pm>
            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 - <stefan@gnosis.pm>
            /// @author Richard Meissner - <richard@gnosis.pm>
            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 - <stefan@gnosis.pm>
            /// @author Richard Meissner - <richard@gnosis.pm>
            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 - <richard@gnosis.pm>
            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 - <richard@gnosis.pm>
            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 - <richard@gnosis.pm>
            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 - <richard@gnosis.pm>
            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 - <richard@gnosis.pm>
            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 - <richard@gnosis.io>
            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);
            }