Contract 0x00e5F120f500006757E984F1DED400fc00370000 15

 

Txn Hash Method
Block
From
To
Value [Txn Fee]
Latest 1 internal transaction
Parent Txn Hash Block From To Value
0x8578e4902ae3f4bf653d9e6a1ab736d344f192ce111c36d34fc2c06e7bee860e1018698912023-06-16 20:48:47259 days 7 hrs ago 0x0000000000ffe8b47b3e2130213b802212439497  Contract Creation0 ETH
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
SeaportValidator

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 99999999 runs

Other Settings:
default evmVersion, MIT license
File 1 of 53 : ArrayHelpers.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import "seaport-types/src/helpers/PointerLibraries.sol";

/**
 * @author d1ll0n
 * @custom:coauthor Most of the natspec is cribbed from the TypeScript
 *                  documentation
 */
library ArrayHelpers {
    // Has to be out of place to silence a linter warning
    function reduceWithArg(
        MemoryPointer array,
        /* function (uint256 currentResult, uint256 element, uint256 arg) */
        /* returns (uint256 newResult) */
        function(uint256, uint256, MemoryPointer) internal returns (uint256) fn,
        uint256 initialValue,
        MemoryPointer arg
    ) internal returns (uint256 result) {
        unchecked {
            uint256 length = array.readUint256();

            MemoryPointer srcPosition = array.next();
            MemoryPointer srcEnd = srcPosition.offset(length * 0x20);

            result = initialValue;
            while (srcPosition.lt(srcEnd)) {
                result = fn(result, srcPosition.readUint256(), arg);
                srcPosition = srcPosition.next();
            }
        }
    }

    function flatten(
        MemoryPointer array1,
        MemoryPointer array2
    ) internal view returns (MemoryPointer newArray) {
        unchecked {
            uint256 arrayLength1 = array1.readUint256();
            uint256 arrayLength2 = array2.readUint256();
            uint256 array1HeadSize = arrayLength1 * 32;
            uint256 array2HeadSize = arrayLength2 * 32;

            newArray = malloc(array1HeadSize + array2HeadSize + 32);
            newArray.write(arrayLength1 + arrayLength2);

            MemoryPointer dst = newArray.next();
            if (arrayLength1 > 0) {
                array1.next().copy(dst, array1HeadSize);
            }
            if (arrayLength2 > 0) {
                array2.next().copy(dst.offset(array1HeadSize), array2HeadSize);
            }
        }
    }

    function flattenThree(
        MemoryPointer array1,
        MemoryPointer array2,
        MemoryPointer array3
    ) internal view returns (MemoryPointer newArray) {
        unchecked {
            uint256 arrayLength1 = array1.readUint256();
            uint256 arrayLength2 = array2.readUint256();
            uint256 arrayLength3 = array3.readUint256();
            uint256 array1HeadSize = arrayLength1 * 32;
            uint256 array2HeadSize = arrayLength2 * 32;
            uint256 array3HeadSize = arrayLength3 * 32;

            newArray = malloc(
                array1HeadSize + array2HeadSize + array3HeadSize + 32
            );
            newArray.write(arrayLength1 + arrayLength2 + arrayLength3);

            MemoryPointer dst = newArray.next();
            if (arrayLength1 > 0) {
                array1.next().copy(dst, array1HeadSize);
            }
            if (arrayLength2 > 0) {
                array2.next().copy(dst.offset(array1HeadSize), array2HeadSize);
            }
            if (arrayLength3 > 0) {
                array3.next().copy(
                    dst.offset(array1HeadSize + array2HeadSize),
                    array3HeadSize
                );
            }
        }
    }

    // =====================================================================//
    //            map with (element) => (newElement) callback               //
    // =====================================================================//

    /**
     * @dev map calls a defined callback function on each element of an array
     *      and returns an array that contains the results
     *
     * @param array   the array to map
     * @param fn      a function that accepts each element in the array and
     *                returns a new value to put in its place in the new array
     *
     * @return newArray the new array created with the results from calling
     *         fn with each element
     */
    function map(
        MemoryPointer array,
        /* function (uint256 value) returns (uint256 newValue) */
        function(uint256) internal pure returns (uint256) fn
    ) internal pure returns (MemoryPointer newArray) {
        unchecked {
            uint256 length = array.readUint256();

            newArray = malloc((length + 1) * 32);
            newArray.write(length);

            MemoryPointer srcPosition = array.next();
            MemoryPointer srcEnd = srcPosition.offset(length * 0x20);
            MemoryPointer dstPosition = newArray.next();

            while (srcPosition.lt(srcEnd)) {
                dstPosition.write(fn(srcPosition.readUint256()));
                srcPosition = srcPosition.next();
                dstPosition = dstPosition.next();
            }
        }
    }

    // =====================================================================//
    //         filterMap with (element) => (newElement) callback            //
    // =====================================================================//

    /**
     * @dev filterMap calls a defined callback function on each element of an
     *      array and returns an array that contains only the non-zero results
     *
     * @param array   the array to map
     * @param fn      a function that accepts each element in the array and
     *                returns a new value to put in its place in the new array
     *                or a zero value to indicate that the element should not
     *                be included in the new array
     *
     * @return newArray the new array created with the results from calling
     *                  fn with each element
     */
    function filterMap(
        MemoryPointer array,
        /* function (uint256 value) returns (uint256 newValue) */
        function(MemoryPointer) internal pure returns (MemoryPointer) fn
    ) internal pure returns (MemoryPointer newArray) {
        unchecked {
            uint256 length = array.readUint256();

            newArray = malloc((length + 1) * 32);

            MemoryPointer srcPosition = array.next();
            MemoryPointer srcEnd = srcPosition.offset(length * 0x20);
            MemoryPointer dstPosition = newArray.next();

            length = 0;

            while (srcPosition.lt(srcEnd)) {
                MemoryPointer result = fn(srcPosition.readMemoryPointer());
                if (!result.isNull()) {
                    dstPosition.write(result);
                    dstPosition = dstPosition.next();
                    length += 1;
                }
                srcPosition = srcPosition.next();
            }
            newArray.write(length);
        }
    }

    // =====================================================================//
    //      filterMap with (element, arg) => (newElement) callback          //
    // =====================================================================//

    /**
     * @dev filterMap calls a defined callback function on each element of an
     *      array and returns an array that contains only the non-zero results
     *
     *        filterMapWithArg = (arr, callback, arg) => arr.map(
     *          (element) => callback(element, arg)
     *        ).filter(result => result != 0)
     *
     * @param array   the array to map
     * @param fn      a function that accepts each element in the array and
     *                returns a new value to put in its place in the new array
     *                or a zero value to indicate that the element should not
     *                be included in the new array
     * @param arg     an arbitrary value provided in each call to fn
     *
     * @return newArray the new array created with the results from calling
     *                  fn with each element
     */
    function filterMapWithArg(
        MemoryPointer array,
        /* function (MemoryPointer element, MemoryPointer arg) */
        /* returns (uint256 newValue) */
        function(MemoryPointer, MemoryPointer)
            internal
            pure
            returns (MemoryPointer) fn,
        MemoryPointer arg
    ) internal pure returns (MemoryPointer newArray) {
        unchecked {
            uint256 length = array.readUint256();

            newArray = malloc((length + 1) * 32);

            MemoryPointer srcPosition = array.next();
            MemoryPointer srcEnd = srcPosition.offset(length * 0x20);
            MemoryPointer dstPosition = newArray.next();

            length = 0;

            while (srcPosition.lt(srcEnd)) {
                MemoryPointer result = fn(srcPosition.readMemoryPointer(), arg);
                if (!result.isNull()) {
                    dstPosition.write(result);
                    dstPosition = dstPosition.next();
                    length += 1;
                }
                srcPosition = srcPosition.next();
            }
            newArray.write(length);
        }
    }

    // ====================================================================//
    //         filter  with (element, arg) => (bool) predicate             //
    // ====================================================================//

    /**
     * @dev filter calls a defined callback function on each element of an array
     *      and returns an array that contains only the elements which the
     *      callback returned true for
     *
     * @param array   the array to map
     * @param fn      a function that accepts each element in the array and
     *                returns a boolean that indicates whether the element
     *                should be included in the new array
     * @param arg     an arbitrary value provided in each call to fn
     *
     * @return newArray the new array created with the elements which the
     *                  callback returned true for
     */
    function filterWithArg(
        MemoryPointer array,
        /* function (uint256 value, uint256 arg) returns (bool) */
        function(MemoryPointer, MemoryPointer) internal pure returns (bool) fn,
        MemoryPointer arg
    ) internal pure returns (MemoryPointer newArray) {
        unchecked {
            uint256 length = array.readUint256();

            newArray = malloc((length + 1) * 32);

            MemoryPointer srcPosition = array.next();
            MemoryPointer srcEnd = srcPosition.offset(length * 0x20);
            MemoryPointer dstPosition = newArray.next();

            length = 0;

            while (srcPosition.lt(srcEnd)) {
                MemoryPointer element = srcPosition.readMemoryPointer();
                if (fn(element, arg)) {
                    dstPosition.write(element);
                    dstPosition = dstPosition.next();
                    length += 1;
                }
                srcPosition = srcPosition.next();
            }
            newArray.write(length);
        }
    }

    // ====================================================================//
    //            filter  with (element) => (bool) predicate               //
    // ====================================================================//

    /**
     * @dev filter calls a defined callback function on each element of an array
     *      and returns an array that contains only the elements which the
     *      callback returned true for
     *
     * @param array   the array to map
     * @param fn      a function that accepts each element in the array and
     *                returns a boolean that indicates whether the element
     *                should be included in the new array
     *
     * @return newArray the new array created with the elements which the
     *                  callback returned true for
     */
    function filter(
        MemoryPointer array,
        /* function (uint256 value) returns (bool) */
        function(MemoryPointer) internal pure returns (bool) fn
    ) internal pure returns (MemoryPointer newArray) {
        unchecked {
            uint256 length = array.readUint256();

            newArray = malloc((length + 1) * 32);

            MemoryPointer srcPosition = array.next();
            MemoryPointer srcEnd = srcPosition.offset(length * 0x20);
            MemoryPointer dstPosition = newArray.next();

            length = 0;

            while (srcPosition.lt(srcEnd)) {
                MemoryPointer element = srcPosition.readMemoryPointer();
                if (fn(element)) {
                    dstPosition.write(element);
                    dstPosition = dstPosition.next();
                    length += 1;
                }
                srcPosition = srcPosition.next();
            }
            newArray.write(length);
        }
    }

    /**
     * @dev mapWithIndex calls a defined callback function with each element of
     *      an array and its index and returns an array that contains the
     *      results
     *
     * @param array   the array to map
     * @param fn      a function that accepts each element in the array and
     *                its index and returns a new value to put in its place
     *                in the new array
     *
     * @return newArray the new array created with the results from calling
     *         fn with each element
     */
    function mapWithIndex(
        MemoryPointer array,
        /* function (uint256 value, uint256 index) returns (uint256 newValue) */
        function(uint256, uint256) internal pure returns (uint256) fn
    ) internal pure returns (MemoryPointer newArray) {
        unchecked {
            uint256 length = array.readUint256();

            newArray = malloc((length + 1) * 32);
            newArray.write(length);

            MemoryPointer srcPosition = array.next();
            MemoryPointer srcEnd = srcPosition.offset(length * 0x20);
            MemoryPointer dstPosition = newArray.next();

            uint256 index;
            while (srcPosition.lt(srcEnd)) {
                dstPosition.write(fn(srcPosition.readUint256(), index++));
                srcPosition = srcPosition.next();
                dstPosition = dstPosition.next();
            }
        }
    }

    /**
     * @dev map calls a defined callback function on each element of an array
     *      and returns an array that contains the results
     *
     * @param array   the array to map
     * @param fn      a function that accepts each element in the array and
     *                the `arg` value provided in the call to map and returns
     *                a new value to put in its place in the new array
     * @param arg     an arbitrary value provided in each call to fn
     *
     * @return newArray the new array created with the results from calling
     *         fn with each element
     */
    function mapWithArg(
        MemoryPointer array,
        /* function (uint256 value, uint256 arg) returns (uint256 newValue) */
        function(MemoryPointer, MemoryPointer)
            internal
            pure
            returns (MemoryPointer) fn,
        MemoryPointer arg
    ) internal pure returns (MemoryPointer newArray) {
        unchecked {
            uint256 length = array.readUint256();

            newArray = malloc((length + 1) * 32);
            newArray.write(length);

            MemoryPointer srcPosition = array.next();
            MemoryPointer srcEnd = srcPosition.offset(length * 0x20);
            MemoryPointer dstPosition = newArray.next();

            while (srcPosition.lt(srcEnd)) {
                dstPosition.write(fn(srcPosition.readMemoryPointer(), arg));
                srcPosition = srcPosition.next();
                dstPosition = dstPosition.next();
            }
        }
    }

    function mapWithIndex(
        MemoryPointer array,
        /* function (uint256 value, uint256 index, uint256 arg) */
        /* returns (uint256 newValue) */
        function(uint256, uint256, uint256) internal pure returns (uint256) fn,
        uint256 arg
    ) internal pure returns (MemoryPointer newArray) {
        unchecked {
            uint256 length = array.readUint256();

            newArray = malloc((length + 1) * 32);
            newArray.write(length);

            MemoryPointer srcPosition = array.next();
            MemoryPointer srcEnd = srcPosition.offset(length * 0x20);
            MemoryPointer dstPosition = newArray.next();

            uint256 index;
            while (srcPosition.lt(srcEnd)) {
                dstPosition.write(fn(srcPosition.readUint256(), index++, arg));
                srcPosition = srcPosition.next();
                dstPosition = dstPosition.next();
            }
        }
    }

    function reduce(
        MemoryPointer array,
        /* function (uint256 currentResult, uint256 element) */
        /* returns (uint256 newResult) */
        function(uint256, uint256) internal pure returns (uint256) fn,
        uint256 initialValue
    ) internal pure returns (uint256 result) {
        unchecked {
            uint256 length = array.readUint256();

            MemoryPointer srcPosition = array.next();
            MemoryPointer srcEnd = srcPosition.offset(length * 0x20);

            result = initialValue;
            while (srcPosition.lt(srcEnd)) {
                result = fn(result, srcPosition.readUint256());
                srcPosition = srcPosition.next();
            }
        }
    }

    // This was the previous home of `reduceWithArg`. It can now be found near
    // the top of this file.

    function forEach(
        MemoryPointer array,
        /* function (MemoryPointer element, MemoryPointer arg) */
        function(MemoryPointer, MemoryPointer) internal pure fn,
        MemoryPointer arg
    ) internal pure {
        unchecked {
            uint256 length = array.readUint256();

            MemoryPointer srcPosition = array.next();
            MemoryPointer srcEnd = srcPosition.offset(length * 0x20);

            while (srcPosition.lt(srcEnd)) {
                fn(srcPosition.readMemoryPointer(), arg);
                srcPosition = srcPosition.next();
            }
        }
    }

    function forEach(
        MemoryPointer array,
        /* function (MemoryPointer element) */
        function(MemoryPointer) internal pure fn
    ) internal pure {
        unchecked {
            uint256 length = array.readUint256();

            MemoryPointer srcPosition = array.next();
            MemoryPointer srcEnd = srcPosition.offset(length * 0x20);

            while (srcPosition.lt(srcEnd)) {
                fn(srcPosition.readMemoryPointer());
                srcPosition = srcPosition.next();
            }
        }
    }

    // =====================================================================//
    //     find with function(uint256 element, uint256 arg) predicate       //
    // =====================================================================//

    /**
     * @dev calls `predicate` once for each element of the array, in ascending
     *      order, until it finds one where predicate returns true. If such an
     *      element is found, find immediately returns that element value.
     *      Otherwise, find returns 0.
     *
     * @param array     array to search
     * @param predicate function that checks whether each element meets the
     *                  search filter.
     * @param arg       second input to `predicate`
     *
     * @return          the value of the first element in the array where
     *                  predicate is true and 0 otherwise.
     */
    function find(
        MemoryPointer array,
        function(uint256, uint256) internal pure returns (bool) predicate,
        uint256 arg
    ) internal pure returns (uint256) {
        unchecked {
            uint256 length = array.readUint256();
            MemoryPointer srcPosition = array.next();
            MemoryPointer srcEnd = srcPosition.offset(length * 0x20);
            while (srcPosition.lt(srcEnd)) {
                uint256 value = srcPosition.readUint256();
                if (predicate(value, arg)) return value;
                srcPosition = srcPosition.next();
            }
            return 0;
        }
    }

    // =====================================================================//
    //            find with function(uint256 element) predicate             //
    // =====================================================================//

    /**
     * @dev calls `predicate` once for each element of the array, in ascending
     *      order, until it finds one where predicate returns true. If such an
     *      element is found, find immediately returns that element value.
     *      Otherwise, find returns 0.
     *
     * @param array     array to search
     * @param predicate function that checks whether each element meets the
     *                  search filter.
     * @param fromIndex index to start search at
     *
     * @custom:return   the value of the first element in the array where
     *                  predicate is trueand 0 otherwise.
     */
    function find(
        MemoryPointer array,
        function(uint256) internal pure returns (bool) predicate,
        uint256 fromIndex
    ) internal pure returns (uint256) {
        unchecked {
            uint256 length = array.readUint256();
            MemoryPointer srcPosition = array.next().offset(fromIndex * 0x20);
            MemoryPointer srcEnd = srcPosition.offset(length * 0x20);
            while (srcPosition.lt(srcEnd)) {
                uint256 value = srcPosition.readUint256();
                if (predicate(value)) return value;
                srcPosition = srcPosition.next();
            }
            return 0;
        }
    }

    // =====================================================================//
    //            find with function(uint256 element) predicate             //
    // =====================================================================//

    /**
     * @dev calls `predicate` once for each element of the array, in ascending
     *      order, until it finds one where predicate returns true. If such an
     *      element is found, find immediately returns that element value.
     *      Otherwise, find returns 0.
     *
     * @param array     array to search
     * @param predicate function that checks whether each element meets the
     *                  search filter.
     *
     * @return          the value of the first element in the array where
     *                  predicate is true and 0 otherwise.
     */
    function find(
        MemoryPointer array,
        function(uint256) internal pure returns (bool) predicate
    ) internal pure returns (uint256) {
        unchecked {
            uint256 length = array.readUint256();
            MemoryPointer srcPosition = array.next();
            MemoryPointer srcEnd = srcPosition.offset(length * 0x20);
            while (srcPosition.lt(srcEnd)) {
                uint256 value = srcPosition.readUint256();
                if (predicate(value)) return value;
                srcPosition = srcPosition.next();
            }
            return 0;
        }
    }

    // =====================================================================//
    //                               indexOf                                //
    // =====================================================================//

    /**
     * @dev Returns the index of the first occurrence of a value in an array,
     *      or -1 if it is not present.
     *
     * @param array         array to search
     * @param searchElement the value to locate in the array.
     */
    function indexOf(
        MemoryPointer array,
        uint256 searchElement
    ) internal pure returns (int256 index) {
        unchecked {
            int256 length = array.readInt256();
            MemoryPointer src = array;
            int256 reachedEnd;
            while (
                ((reachedEnd = toInt(index == length)) |
                    toInt((src = src.next()).readUint256() == searchElement)) ==
                0
            ) {
                index += 1;
            }
            return (reachedEnd * -1) | index;
        }
    }

    function toInt(bool a) internal pure returns (int256 b) {
        assembly {
            b := a
        }
    }

    // =====================================================================//
    //                     findIndex with one argument                      //
    // =====================================================================//

    function findIndexWithArg(
        MemoryPointer array,
        function(uint256, uint256) internal pure returns (bool) predicate,
        uint256 arg
    ) internal pure returns (int256 index) {
        unchecked {
            int256 length = array.readInt256();
            MemoryPointer src = array;
            while (index < length) {
                if (predicate((src = src.next()).readUint256(), arg)) {
                    return index;
                }
                index += 1;
            }
            return -1;
        }
    }

    // =====================================================================//
    //                     findIndex from start index                       //
    // =====================================================================//

    function findIndexFrom(
        MemoryPointer array,
        function(MemoryPointer) internal pure returns (bool) predicate,
        uint256 fromIndex
    ) internal pure returns (int256 index) {
        unchecked {
            index = int256(fromIndex);
            int256 length = array.readInt256();
            MemoryPointer src = array.offset(fromIndex * 0x20);
            while (index < length) {
                if (predicate((src = src.next()).readMemoryPointer())) {
                    return index;
                }
                index += 1;
            }
            return -1;
        }
    }

    function countFrom(
        MemoryPointer array,
        function(MemoryPointer) internal pure returns (bool) predicate,
        uint256 fromIndex
    ) internal pure returns (int256 count) {
        unchecked {
            uint256 index = fromIndex;
            uint256 length = array.readUint256();
            MemoryPointer src = array.offset(fromIndex * 0x20);
            while (index < length) {
                if (predicate((src = src.next()).readMemoryPointer())) {
                    count += 1;
                }
                index += 1;
            }
        }
    }

    // =====================================================================//
    //                      includes with one argument                      //
    // =====================================================================//

    function includes(
        MemoryPointer array,
        uint256 value
    ) internal pure returns (bool) {
        return indexOf(array, value) != -1;
    }
}

File 2 of 53 : PointerLibraries.sol
// 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)
        }
    }

    function isNull(CalldataPointer a) internal pure returns (bool b) {
        assembly {
            b := iszero(a)
        }
    }

    /// @dev Resolves an offset stored at `cdPtr + headOffset` to a calldata.
    ///      pointer `cdPtr` must point to some parent object with a dynamic
    ///      type's head stored at `cdPtr + headOffset`.
    function 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)
        }
    }

    function isNull(ReturndataPointer a) internal pure returns (bool b) {
        assembly {
            b := iszero(a)
        }
    }

    /// @dev Resolves an offset stored at `rdPtr + headOffset` to a returndata
    ///      pointer. `rdPtr` must point to some parent object with a dynamic
    ///      type's head stored at `rdPtr + headOffset`.
    function 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)
        }
    }

    function isNull(MemoryPointer a) internal pure returns (bool b) {
        assembly {
            b := iszero(a)
        }
    }

    function hash(
        MemoryPointer ptr,
        uint256 length
    ) internal pure returns (bytes32 _hash) {
        assembly {
            _hash := keccak256(ptr, length)
        }
    }

    /// @dev Returns the memory pointer one word after `mPtr`.
    function next(
        MemoryPointer mPtr
    ) internal pure returns (MemoryPointer mPtrNext) {
        assembly {
            mPtrNext := add(mPtr, _OneWord)
        }
    }

    /// @dev Returns the memory pointer `_offset` bytes after `mPtr`.
    function offset(
        MemoryPointer mPtr,
        uint256 _offset
    ) internal pure returns (MemoryPointer mPtrNext) {
        assembly {
            mPtrNext := add(mPtr, _offset)
        }
    }

    /// @dev Resolves a pointer at `mPtr + headOffset` to a memory
    ///    pointer. `mPtr` must point to some parent object with a dynamic
    ///    type's pointer stored at `mPtr + headOffset`.
    function pptr(
        MemoryPointer mPtr,
        uint256 headOffset
    ) internal pure returns (MemoryPointer mPtrChild) {
        mPtrChild = mPtr.offset(headOffset).readMemoryPointer();
    }

    /// @dev Resolves a pointer stored at `mPtr` to a memory pointer.
    ///    `mPtr` must point to some parent object with a dynamic type as its
    ///    first member, e.g. `struct { bytes data; }`
    function pptr(
        MemoryPointer mPtr
    ) internal pure returns (MemoryPointer mPtrChild) {
        mPtrChild = mPtr.readMemoryPointer();
    }
}

library CalldataReaders {
    /// @dev Reads the value at `cdPtr` and applies a mask to return only the
    ///    last 4 bytes.
    function readMaskedUint256(
        CalldataPointer cdPtr
    ) internal pure returns (uint256 value) {
        value = cdPtr.readUint256() & OffsetOrLengthMask;
    }

    /// @dev Reads the bool at `cdPtr` in calldata.
    function readBool(
        CalldataPointer cdPtr
    ) internal pure returns (bool value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the address at `cdPtr` in calldata.
    function readAddress(
        CalldataPointer cdPtr
    ) internal pure returns (address value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes1 at `cdPtr` in calldata.
    function readBytes1(
        CalldataPointer cdPtr
    ) internal pure returns (bytes1 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes2 at `cdPtr` in calldata.
    function readBytes2(
        CalldataPointer cdPtr
    ) internal pure returns (bytes2 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes3 at `cdPtr` in calldata.
    function readBytes3(
        CalldataPointer cdPtr
    ) internal pure returns (bytes3 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes4 at `cdPtr` in calldata.
    function readBytes4(
        CalldataPointer cdPtr
    ) internal pure returns (bytes4 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes5 at `cdPtr` in calldata.
    function readBytes5(
        CalldataPointer cdPtr
    ) internal pure returns (bytes5 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes6 at `cdPtr` in calldata.
    function readBytes6(
        CalldataPointer cdPtr
    ) internal pure returns (bytes6 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes7 at `cdPtr` in calldata.
    function readBytes7(
        CalldataPointer cdPtr
    ) internal pure returns (bytes7 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes8 at `cdPtr` in calldata.
    function readBytes8(
        CalldataPointer cdPtr
    ) internal pure returns (bytes8 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes9 at `cdPtr` in calldata.
    function readBytes9(
        CalldataPointer cdPtr
    ) internal pure returns (bytes9 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes10 at `cdPtr` in calldata.
    function readBytes10(
        CalldataPointer cdPtr
    ) internal pure returns (bytes10 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes11 at `cdPtr` in calldata.
    function readBytes11(
        CalldataPointer cdPtr
    ) internal pure returns (bytes11 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes12 at `cdPtr` in calldata.
    function readBytes12(
        CalldataPointer cdPtr
    ) internal pure returns (bytes12 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes13 at `cdPtr` in calldata.
    function readBytes13(
        CalldataPointer cdPtr
    ) internal pure returns (bytes13 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes14 at `cdPtr` in calldata.
    function readBytes14(
        CalldataPointer cdPtr
    ) internal pure returns (bytes14 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes15 at `cdPtr` in calldata.
    function readBytes15(
        CalldataPointer cdPtr
    ) internal pure returns (bytes15 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes16 at `cdPtr` in calldata.
    function readBytes16(
        CalldataPointer cdPtr
    ) internal pure returns (bytes16 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes17 at `cdPtr` in calldata.
    function readBytes17(
        CalldataPointer cdPtr
    ) internal pure returns (bytes17 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes18 at `cdPtr` in calldata.
    function readBytes18(
        CalldataPointer cdPtr
    ) internal pure returns (bytes18 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes19 at `cdPtr` in calldata.
    function readBytes19(
        CalldataPointer cdPtr
    ) internal pure returns (bytes19 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes20 at `cdPtr` in calldata.
    function readBytes20(
        CalldataPointer cdPtr
    ) internal pure returns (bytes20 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes21 at `cdPtr` in calldata.
    function readBytes21(
        CalldataPointer cdPtr
    ) internal pure returns (bytes21 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes22 at `cdPtr` in calldata.
    function readBytes22(
        CalldataPointer cdPtr
    ) internal pure returns (bytes22 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes23 at `cdPtr` in calldata.
    function readBytes23(
        CalldataPointer cdPtr
    ) internal pure returns (bytes23 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes24 at `cdPtr` in calldata.
    function readBytes24(
        CalldataPointer cdPtr
    ) internal pure returns (bytes24 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes25 at `cdPtr` in calldata.
    function readBytes25(
        CalldataPointer cdPtr
    ) internal pure returns (bytes25 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes26 at `cdPtr` in calldata.
    function readBytes26(
        CalldataPointer cdPtr
    ) internal pure returns (bytes26 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes27 at `cdPtr` in calldata.
    function readBytes27(
        CalldataPointer cdPtr
    ) internal pure returns (bytes27 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes28 at `cdPtr` in calldata.
    function readBytes28(
        CalldataPointer cdPtr
    ) internal pure returns (bytes28 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes29 at `cdPtr` in calldata.
    function readBytes29(
        CalldataPointer cdPtr
    ) internal pure returns (bytes29 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes30 at `cdPtr` in calldata.
    function readBytes30(
        CalldataPointer cdPtr
    ) internal pure returns (bytes30 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes31 at `cdPtr` in calldata.
    function readBytes31(
        CalldataPointer cdPtr
    ) internal pure returns (bytes31 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the bytes32 at `cdPtr` in calldata.
    function readBytes32(
        CalldataPointer cdPtr
    ) internal pure returns (bytes32 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint8 at `cdPtr` in calldata.
    function readUint8(
        CalldataPointer cdPtr
    ) internal pure returns (uint8 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint16 at `cdPtr` in calldata.
    function readUint16(
        CalldataPointer cdPtr
    ) internal pure returns (uint16 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint24 at `cdPtr` in calldata.
    function readUint24(
        CalldataPointer cdPtr
    ) internal pure returns (uint24 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint32 at `cdPtr` in calldata.
    function readUint32(
        CalldataPointer cdPtr
    ) internal pure returns (uint32 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint40 at `cdPtr` in calldata.
    function readUint40(
        CalldataPointer cdPtr
    ) internal pure returns (uint40 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint48 at `cdPtr` in calldata.
    function readUint48(
        CalldataPointer cdPtr
    ) internal pure returns (uint48 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint56 at `cdPtr` in calldata.
    function readUint56(
        CalldataPointer cdPtr
    ) internal pure returns (uint56 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint64 at `cdPtr` in calldata.
    function readUint64(
        CalldataPointer cdPtr
    ) internal pure returns (uint64 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint72 at `cdPtr` in calldata.
    function readUint72(
        CalldataPointer cdPtr
    ) internal pure returns (uint72 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint80 at `cdPtr` in calldata.
    function readUint80(
        CalldataPointer cdPtr
    ) internal pure returns (uint80 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint88 at `cdPtr` in calldata.
    function readUint88(
        CalldataPointer cdPtr
    ) internal pure returns (uint88 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint96 at `cdPtr` in calldata.
    function readUint96(
        CalldataPointer cdPtr
    ) internal pure returns (uint96 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint104 at `cdPtr` in calldata.
    function readUint104(
        CalldataPointer cdPtr
    ) internal pure returns (uint104 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint112 at `cdPtr` in calldata.
    function readUint112(
        CalldataPointer cdPtr
    ) internal pure returns (uint112 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint120 at `cdPtr` in calldata.
    function readUint120(
        CalldataPointer cdPtr
    ) internal pure returns (uint120 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint128 at `cdPtr` in calldata.
    function readUint128(
        CalldataPointer cdPtr
    ) internal pure returns (uint128 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint136 at `cdPtr` in calldata.
    function readUint136(
        CalldataPointer cdPtr
    ) internal pure returns (uint136 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint144 at `cdPtr` in calldata.
    function readUint144(
        CalldataPointer cdPtr
    ) internal pure returns (uint144 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint152 at `cdPtr` in calldata.
    function readUint152(
        CalldataPointer cdPtr
    ) internal pure returns (uint152 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint160 at `cdPtr` in calldata.
    function readUint160(
        CalldataPointer cdPtr
    ) internal pure returns (uint160 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint168 at `cdPtr` in calldata.
    function readUint168(
        CalldataPointer cdPtr
    ) internal pure returns (uint168 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint176 at `cdPtr` in calldata.
    function readUint176(
        CalldataPointer cdPtr
    ) internal pure returns (uint176 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint184 at `cdPtr` in calldata.
    function readUint184(
        CalldataPointer cdPtr
    ) internal pure returns (uint184 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint192 at `cdPtr` in calldata.
    function readUint192(
        CalldataPointer cdPtr
    ) internal pure returns (uint192 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint200 at `cdPtr` in calldata.
    function readUint200(
        CalldataPointer cdPtr
    ) internal pure returns (uint200 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint208 at `cdPtr` in calldata.
    function readUint208(
        CalldataPointer cdPtr
    ) internal pure returns (uint208 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint216 at `cdPtr` in calldata.
    function readUint216(
        CalldataPointer cdPtr
    ) internal pure returns (uint216 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint224 at `cdPtr` in calldata.
    function readUint224(
        CalldataPointer cdPtr
    ) internal pure returns (uint224 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint232 at `cdPtr` in calldata.
    function readUint232(
        CalldataPointer cdPtr
    ) internal pure returns (uint232 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint240 at `cdPtr` in calldata.
    function readUint240(
        CalldataPointer cdPtr
    ) internal pure returns (uint240 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint248 at `cdPtr` in calldata.
    function readUint248(
        CalldataPointer cdPtr
    ) internal pure returns (uint248 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the uint256 at `cdPtr` in calldata.
    function readUint256(
        CalldataPointer cdPtr
    ) internal pure returns (uint256 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int8 at `cdPtr` in calldata.
    function readInt8(
        CalldataPointer cdPtr
    ) internal pure returns (int8 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int16 at `cdPtr` in calldata.
    function readInt16(
        CalldataPointer cdPtr
    ) internal pure returns (int16 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int24 at `cdPtr` in calldata.
    function readInt24(
        CalldataPointer cdPtr
    ) internal pure returns (int24 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int32 at `cdPtr` in calldata.
    function readInt32(
        CalldataPointer cdPtr
    ) internal pure returns (int32 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int40 at `cdPtr` in calldata.
    function readInt40(
        CalldataPointer cdPtr
    ) internal pure returns (int40 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int48 at `cdPtr` in calldata.
    function readInt48(
        CalldataPointer cdPtr
    ) internal pure returns (int48 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int56 at `cdPtr` in calldata.
    function readInt56(
        CalldataPointer cdPtr
    ) internal pure returns (int56 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int64 at `cdPtr` in calldata.
    function readInt64(
        CalldataPointer cdPtr
    ) internal pure returns (int64 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int72 at `cdPtr` in calldata.
    function readInt72(
        CalldataPointer cdPtr
    ) internal pure returns (int72 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int80 at `cdPtr` in calldata.
    function readInt80(
        CalldataPointer cdPtr
    ) internal pure returns (int80 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int88 at `cdPtr` in calldata.
    function readInt88(
        CalldataPointer cdPtr
    ) internal pure returns (int88 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int96 at `cdPtr` in calldata.
    function readInt96(
        CalldataPointer cdPtr
    ) internal pure returns (int96 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int104 at `cdPtr` in calldata.
    function readInt104(
        CalldataPointer cdPtr
    ) internal pure returns (int104 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int112 at `cdPtr` in calldata.
    function readInt112(
        CalldataPointer cdPtr
    ) internal pure returns (int112 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int120 at `cdPtr` in calldata.
    function readInt120(
        CalldataPointer cdPtr
    ) internal pure returns (int120 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int128 at `cdPtr` in calldata.
    function readInt128(
        CalldataPointer cdPtr
    ) internal pure returns (int128 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int136 at `cdPtr` in calldata.
    function readInt136(
        CalldataPointer cdPtr
    ) internal pure returns (int136 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int144 at `cdPtr` in calldata.
    function readInt144(
        CalldataPointer cdPtr
    ) internal pure returns (int144 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int152 at `cdPtr` in calldata.
    function readInt152(
        CalldataPointer cdPtr
    ) internal pure returns (int152 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int160 at `cdPtr` in calldata.
    function readInt160(
        CalldataPointer cdPtr
    ) internal pure returns (int160 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int168 at `cdPtr` in calldata.
    function readInt168(
        CalldataPointer cdPtr
    ) internal pure returns (int168 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int176 at `cdPtr` in calldata.
    function readInt176(
        CalldataPointer cdPtr
    ) internal pure returns (int176 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int184 at `cdPtr` in calldata.
    function readInt184(
        CalldataPointer cdPtr
    ) internal pure returns (int184 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int192 at `cdPtr` in calldata.
    function readInt192(
        CalldataPointer cdPtr
    ) internal pure returns (int192 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int200 at `cdPtr` in calldata.
    function readInt200(
        CalldataPointer cdPtr
    ) internal pure returns (int200 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int208 at `cdPtr` in calldata.
    function readInt208(
        CalldataPointer cdPtr
    ) internal pure returns (int208 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int216 at `cdPtr` in calldata.
    function readInt216(
        CalldataPointer cdPtr
    ) internal pure returns (int216 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int224 at `cdPtr` in calldata.
    function readInt224(
        CalldataPointer cdPtr
    ) internal pure returns (int224 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int232 at `cdPtr` in calldata.
    function readInt232(
        CalldataPointer cdPtr
    ) internal pure returns (int232 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int240 at `cdPtr` in calldata.
    function readInt240(
        CalldataPointer cdPtr
    ) internal pure returns (int240 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int248 at `cdPtr` in calldata.
    function readInt248(
        CalldataPointer cdPtr
    ) internal pure returns (int248 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }

    /// @dev Reads the int256 at `cdPtr` in calldata.
    function readInt256(
        CalldataPointer cdPtr
    ) internal pure returns (int256 value) {
        assembly {
            value := calldataload(cdPtr)
        }
    }
}

library ReturndataReaders {
    /// @dev Reads value at `rdPtr` & applies a mask to return only last 4 bytes
    function readMaskedUint256(
        ReturndataPointer rdPtr
    ) internal pure returns (uint256 value) {
        value = rdPtr.readUint256() & OffsetOrLengthMask;
    }

    /// @dev Reads the bool at `rdPtr` in returndata.
    function readBool(
        ReturndataPointer rdPtr
    ) internal pure returns (bool value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the address at `rdPtr` in returndata.
    function readAddress(
        ReturndataPointer rdPtr
    ) internal pure returns (address value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes1 at `rdPtr` in returndata.
    function readBytes1(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes1 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes2 at `rdPtr` in returndata.
    function readBytes2(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes2 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes3 at `rdPtr` in returndata.
    function readBytes3(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes3 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes4 at `rdPtr` in returndata.
    function readBytes4(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes4 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes5 at `rdPtr` in returndata.
    function readBytes5(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes5 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes6 at `rdPtr` in returndata.
    function readBytes6(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes6 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes7 at `rdPtr` in returndata.
    function readBytes7(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes7 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes8 at `rdPtr` in returndata.
    function readBytes8(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes8 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes9 at `rdPtr` in returndata.
    function readBytes9(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes9 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes10 at `rdPtr` in returndata.
    function readBytes10(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes10 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes11 at `rdPtr` in returndata.
    function readBytes11(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes11 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes12 at `rdPtr` in returndata.
    function readBytes12(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes12 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes13 at `rdPtr` in returndata.
    function readBytes13(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes13 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes14 at `rdPtr` in returndata.
    function readBytes14(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes14 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes15 at `rdPtr` in returndata.
    function readBytes15(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes15 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes16 at `rdPtr` in returndata.
    function readBytes16(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes16 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes17 at `rdPtr` in returndata.
    function readBytes17(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes17 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes18 at `rdPtr` in returndata.
    function readBytes18(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes18 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes19 at `rdPtr` in returndata.
    function readBytes19(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes19 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes20 at `rdPtr` in returndata.
    function readBytes20(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes20 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes21 at `rdPtr` in returndata.
    function readBytes21(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes21 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes22 at `rdPtr` in returndata.
    function readBytes22(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes22 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes23 at `rdPtr` in returndata.
    function readBytes23(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes23 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes24 at `rdPtr` in returndata.
    function readBytes24(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes24 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes25 at `rdPtr` in returndata.
    function readBytes25(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes25 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes26 at `rdPtr` in returndata.
    function readBytes26(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes26 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes27 at `rdPtr` in returndata.
    function readBytes27(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes27 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes28 at `rdPtr` in returndata.
    function readBytes28(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes28 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes29 at `rdPtr` in returndata.
    function readBytes29(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes29 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes30 at `rdPtr` in returndata.
    function readBytes30(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes30 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes31 at `rdPtr` in returndata.
    function readBytes31(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes31 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the bytes32 at `rdPtr` in returndata.
    function readBytes32(
        ReturndataPointer rdPtr
    ) internal pure returns (bytes32 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint8 at `rdPtr` in returndata.
    function readUint8(
        ReturndataPointer rdPtr
    ) internal pure returns (uint8 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint16 at `rdPtr` in returndata.
    function readUint16(
        ReturndataPointer rdPtr
    ) internal pure returns (uint16 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint24 at `rdPtr` in returndata.
    function readUint24(
        ReturndataPointer rdPtr
    ) internal pure returns (uint24 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint32 at `rdPtr` in returndata.
    function readUint32(
        ReturndataPointer rdPtr
    ) internal pure returns (uint32 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint40 at `rdPtr` in returndata.
    function readUint40(
        ReturndataPointer rdPtr
    ) internal pure returns (uint40 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint48 at `rdPtr` in returndata.
    function readUint48(
        ReturndataPointer rdPtr
    ) internal pure returns (uint48 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint56 at `rdPtr` in returndata.
    function readUint56(
        ReturndataPointer rdPtr
    ) internal pure returns (uint56 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint64 at `rdPtr` in returndata.
    function readUint64(
        ReturndataPointer rdPtr
    ) internal pure returns (uint64 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint72 at `rdPtr` in returndata.
    function readUint72(
        ReturndataPointer rdPtr
    ) internal pure returns (uint72 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint80 at `rdPtr` in returndata.
    function readUint80(
        ReturndataPointer rdPtr
    ) internal pure returns (uint80 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint88 at `rdPtr` in returndata.
    function readUint88(
        ReturndataPointer rdPtr
    ) internal pure returns (uint88 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint96 at `rdPtr` in returndata.
    function readUint96(
        ReturndataPointer rdPtr
    ) internal pure returns (uint96 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint104 at `rdPtr` in returndata.
    function readUint104(
        ReturndataPointer rdPtr
    ) internal pure returns (uint104 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint112 at `rdPtr` in returndata.
    function readUint112(
        ReturndataPointer rdPtr
    ) internal pure returns (uint112 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint120 at `rdPtr` in returndata.
    function readUint120(
        ReturndataPointer rdPtr
    ) internal pure returns (uint120 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint128 at `rdPtr` in returndata.
    function readUint128(
        ReturndataPointer rdPtr
    ) internal pure returns (uint128 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint136 at `rdPtr` in returndata.
    function readUint136(
        ReturndataPointer rdPtr
    ) internal pure returns (uint136 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint144 at `rdPtr` in returndata.
    function readUint144(
        ReturndataPointer rdPtr
    ) internal pure returns (uint144 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint152 at `rdPtr` in returndata.
    function readUint152(
        ReturndataPointer rdPtr
    ) internal pure returns (uint152 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint160 at `rdPtr` in returndata.
    function readUint160(
        ReturndataPointer rdPtr
    ) internal pure returns (uint160 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint168 at `rdPtr` in returndata.
    function readUint168(
        ReturndataPointer rdPtr
    ) internal pure returns (uint168 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint176 at `rdPtr` in returndata.
    function readUint176(
        ReturndataPointer rdPtr
    ) internal pure returns (uint176 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint184 at `rdPtr` in returndata.
    function readUint184(
        ReturndataPointer rdPtr
    ) internal pure returns (uint184 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint192 at `rdPtr` in returndata.
    function readUint192(
        ReturndataPointer rdPtr
    ) internal pure returns (uint192 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint200 at `rdPtr` in returndata.
    function readUint200(
        ReturndataPointer rdPtr
    ) internal pure returns (uint200 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint208 at `rdPtr` in returndata.
    function readUint208(
        ReturndataPointer rdPtr
    ) internal pure returns (uint208 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint216 at `rdPtr` in returndata.
    function readUint216(
        ReturndataPointer rdPtr
    ) internal pure returns (uint216 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint224 at `rdPtr` in returndata.
    function readUint224(
        ReturndataPointer rdPtr
    ) internal pure returns (uint224 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint232 at `rdPtr` in returndata.
    function readUint232(
        ReturndataPointer rdPtr
    ) internal pure returns (uint232 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint240 at `rdPtr` in returndata.
    function readUint240(
        ReturndataPointer rdPtr
    ) internal pure returns (uint240 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint248 at `rdPtr` in returndata.
    function readUint248(
        ReturndataPointer rdPtr
    ) internal pure returns (uint248 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the uint256 at `rdPtr` in returndata.
    function readUint256(
        ReturndataPointer rdPtr
    ) internal pure returns (uint256 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int8 at `rdPtr` in returndata.
    function readInt8(
        ReturndataPointer rdPtr
    ) internal pure returns (int8 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int16 at `rdPtr` in returndata.
    function readInt16(
        ReturndataPointer rdPtr
    ) internal pure returns (int16 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int24 at `rdPtr` in returndata.
    function readInt24(
        ReturndataPointer rdPtr
    ) internal pure returns (int24 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int32 at `rdPtr` in returndata.
    function readInt32(
        ReturndataPointer rdPtr
    ) internal pure returns (int32 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int40 at `rdPtr` in returndata.
    function readInt40(
        ReturndataPointer rdPtr
    ) internal pure returns (int40 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int48 at `rdPtr` in returndata.
    function readInt48(
        ReturndataPointer rdPtr
    ) internal pure returns (int48 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int56 at `rdPtr` in returndata.
    function readInt56(
        ReturndataPointer rdPtr
    ) internal pure returns (int56 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int64 at `rdPtr` in returndata.
    function readInt64(
        ReturndataPointer rdPtr
    ) internal pure returns (int64 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int72 at `rdPtr` in returndata.
    function readInt72(
        ReturndataPointer rdPtr
    ) internal pure returns (int72 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int80 at `rdPtr` in returndata.
    function readInt80(
        ReturndataPointer rdPtr
    ) internal pure returns (int80 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int88 at `rdPtr` in returndata.
    function readInt88(
        ReturndataPointer rdPtr
    ) internal pure returns (int88 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int96 at `rdPtr` in returndata.
    function readInt96(
        ReturndataPointer rdPtr
    ) internal pure returns (int96 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int104 at `rdPtr` in returndata.
    function readInt104(
        ReturndataPointer rdPtr
    ) internal pure returns (int104 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int112 at `rdPtr` in returndata.
    function readInt112(
        ReturndataPointer rdPtr
    ) internal pure returns (int112 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int120 at `rdPtr` in returndata.
    function readInt120(
        ReturndataPointer rdPtr
    ) internal pure returns (int120 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int128 at `rdPtr` in returndata.
    function readInt128(
        ReturndataPointer rdPtr
    ) internal pure returns (int128 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int136 at `rdPtr` in returndata.
    function readInt136(
        ReturndataPointer rdPtr
    ) internal pure returns (int136 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int144 at `rdPtr` in returndata.
    function readInt144(
        ReturndataPointer rdPtr
    ) internal pure returns (int144 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int152 at `rdPtr` in returndata.
    function readInt152(
        ReturndataPointer rdPtr
    ) internal pure returns (int152 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int160 at `rdPtr` in returndata.
    function readInt160(
        ReturndataPointer rdPtr
    ) internal pure returns (int160 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int168 at `rdPtr` in returndata.
    function readInt168(
        ReturndataPointer rdPtr
    ) internal pure returns (int168 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int176 at `rdPtr` in returndata.
    function readInt176(
        ReturndataPointer rdPtr
    ) internal pure returns (int176 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int184 at `rdPtr` in returndata.
    function readInt184(
        ReturndataPointer rdPtr
    ) internal pure returns (int184 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int192 at `rdPtr` in returndata.
    function readInt192(
        ReturndataPointer rdPtr
    ) internal pure returns (int192 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int200 at `rdPtr` in returndata.
    function readInt200(
        ReturndataPointer rdPtr
    ) internal pure returns (int200 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int208 at `rdPtr` in returndata.
    function readInt208(
        ReturndataPointer rdPtr
    ) internal pure returns (int208 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int216 at `rdPtr` in returndata.
    function readInt216(
        ReturndataPointer rdPtr
    ) internal pure returns (int216 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int224 at `rdPtr` in returndata.
    function readInt224(
        ReturndataPointer rdPtr
    ) internal pure returns (int224 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int232 at `rdPtr` in returndata.
    function readInt232(
        ReturndataPointer rdPtr
    ) internal pure returns (int232 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int240 at `rdPtr` in returndata.
    function readInt240(
        ReturndataPointer rdPtr
    ) internal pure returns (int240 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int248 at `rdPtr` in returndata.
    function readInt248(
        ReturndataPointer rdPtr
    ) internal pure returns (int248 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }

    /// @dev Reads the int256 at `rdPtr` in returndata.
    function readInt256(
        ReturndataPointer rdPtr
    ) internal pure returns (int256 value) {
        assembly {
            returndatacopy(0, rdPtr, _OneWord)
            value := mload(0)
        }
    }
}

library MemoryReaders {
    /// @dev Reads the memory pointer at `mPtr` in memory.
    function readMemoryPointer(
        MemoryPointer mPtr
    ) internal pure returns (MemoryPointer value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads value at `mPtr` & applies a mask to return only last 4 bytes
    function readMaskedUint256(
        MemoryPointer mPtr
    ) internal pure returns (uint256 value) {
        value = mPtr.readUint256() & OffsetOrLengthMask;
    }

    /// @dev Reads the bool at `mPtr` in memory.
    function readBool(MemoryPointer mPtr) internal pure returns (bool value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the address at `mPtr` in memory.
    function readAddress(
        MemoryPointer mPtr
    ) internal pure returns (address value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes1 at `mPtr` in memory.
    function readBytes1(
        MemoryPointer mPtr
    ) internal pure returns (bytes1 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes2 at `mPtr` in memory.
    function readBytes2(
        MemoryPointer mPtr
    ) internal pure returns (bytes2 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes3 at `mPtr` in memory.
    function readBytes3(
        MemoryPointer mPtr
    ) internal pure returns (bytes3 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes4 at `mPtr` in memory.
    function readBytes4(
        MemoryPointer mPtr
    ) internal pure returns (bytes4 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes5 at `mPtr` in memory.
    function readBytes5(
        MemoryPointer mPtr
    ) internal pure returns (bytes5 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes6 at `mPtr` in memory.
    function readBytes6(
        MemoryPointer mPtr
    ) internal pure returns (bytes6 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes7 at `mPtr` in memory.
    function readBytes7(
        MemoryPointer mPtr
    ) internal pure returns (bytes7 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes8 at `mPtr` in memory.
    function readBytes8(
        MemoryPointer mPtr
    ) internal pure returns (bytes8 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes9 at `mPtr` in memory.
    function readBytes9(
        MemoryPointer mPtr
    ) internal pure returns (bytes9 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes10 at `mPtr` in memory.
    function readBytes10(
        MemoryPointer mPtr
    ) internal pure returns (bytes10 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes11 at `mPtr` in memory.
    function readBytes11(
        MemoryPointer mPtr
    ) internal pure returns (bytes11 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes12 at `mPtr` in memory.
    function readBytes12(
        MemoryPointer mPtr
    ) internal pure returns (bytes12 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes13 at `mPtr` in memory.
    function readBytes13(
        MemoryPointer mPtr
    ) internal pure returns (bytes13 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes14 at `mPtr` in memory.
    function readBytes14(
        MemoryPointer mPtr
    ) internal pure returns (bytes14 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes15 at `mPtr` in memory.
    function readBytes15(
        MemoryPointer mPtr
    ) internal pure returns (bytes15 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes16 at `mPtr` in memory.
    function readBytes16(
        MemoryPointer mPtr
    ) internal pure returns (bytes16 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes17 at `mPtr` in memory.
    function readBytes17(
        MemoryPointer mPtr
    ) internal pure returns (bytes17 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes18 at `mPtr` in memory.
    function readBytes18(
        MemoryPointer mPtr
    ) internal pure returns (bytes18 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes19 at `mPtr` in memory.
    function readBytes19(
        MemoryPointer mPtr
    ) internal pure returns (bytes19 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes20 at `mPtr` in memory.
    function readBytes20(
        MemoryPointer mPtr
    ) internal pure returns (bytes20 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes21 at `mPtr` in memory.
    function readBytes21(
        MemoryPointer mPtr
    ) internal pure returns (bytes21 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes22 at `mPtr` in memory.
    function readBytes22(
        MemoryPointer mPtr
    ) internal pure returns (bytes22 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes23 at `mPtr` in memory.
    function readBytes23(
        MemoryPointer mPtr
    ) internal pure returns (bytes23 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes24 at `mPtr` in memory.
    function readBytes24(
        MemoryPointer mPtr
    ) internal pure returns (bytes24 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes25 at `mPtr` in memory.
    function readBytes25(
        MemoryPointer mPtr
    ) internal pure returns (bytes25 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes26 at `mPtr` in memory.
    function readBytes26(
        MemoryPointer mPtr
    ) internal pure returns (bytes26 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes27 at `mPtr` in memory.
    function readBytes27(
        MemoryPointer mPtr
    ) internal pure returns (bytes27 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes28 at `mPtr` in memory.
    function readBytes28(
        MemoryPointer mPtr
    ) internal pure returns (bytes28 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes29 at `mPtr` in memory.
    function readBytes29(
        MemoryPointer mPtr
    ) internal pure returns (bytes29 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes30 at `mPtr` in memory.
    function readBytes30(
        MemoryPointer mPtr
    ) internal pure returns (bytes30 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes31 at `mPtr` in memory.
    function readBytes31(
        MemoryPointer mPtr
    ) internal pure returns (bytes31 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the bytes32 at `mPtr` in memory.
    function readBytes32(
        MemoryPointer mPtr
    ) internal pure returns (bytes32 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint8 at `mPtr` in memory.
    function readUint8(MemoryPointer mPtr) internal pure returns (uint8 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint16 at `mPtr` in memory.
    function readUint16(
        MemoryPointer mPtr
    ) internal pure returns (uint16 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint24 at `mPtr` in memory.
    function readUint24(
        MemoryPointer mPtr
    ) internal pure returns (uint24 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint32 at `mPtr` in memory.
    function readUint32(
        MemoryPointer mPtr
    ) internal pure returns (uint32 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint40 at `mPtr` in memory.
    function readUint40(
        MemoryPointer mPtr
    ) internal pure returns (uint40 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint48 at `mPtr` in memory.
    function readUint48(
        MemoryPointer mPtr
    ) internal pure returns (uint48 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint56 at `mPtr` in memory.
    function readUint56(
        MemoryPointer mPtr
    ) internal pure returns (uint56 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint64 at `mPtr` in memory.
    function readUint64(
        MemoryPointer mPtr
    ) internal pure returns (uint64 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint72 at `mPtr` in memory.
    function readUint72(
        MemoryPointer mPtr
    ) internal pure returns (uint72 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint80 at `mPtr` in memory.
    function readUint80(
        MemoryPointer mPtr
    ) internal pure returns (uint80 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint88 at `mPtr` in memory.
    function readUint88(
        MemoryPointer mPtr
    ) internal pure returns (uint88 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint96 at `mPtr` in memory.
    function readUint96(
        MemoryPointer mPtr
    ) internal pure returns (uint96 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint104 at `mPtr` in memory.
    function readUint104(
        MemoryPointer mPtr
    ) internal pure returns (uint104 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint112 at `mPtr` in memory.
    function readUint112(
        MemoryPointer mPtr
    ) internal pure returns (uint112 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint120 at `mPtr` in memory.
    function readUint120(
        MemoryPointer mPtr
    ) internal pure returns (uint120 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint128 at `mPtr` in memory.
    function readUint128(
        MemoryPointer mPtr
    ) internal pure returns (uint128 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint136 at `mPtr` in memory.
    function readUint136(
        MemoryPointer mPtr
    ) internal pure returns (uint136 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint144 at `mPtr` in memory.
    function readUint144(
        MemoryPointer mPtr
    ) internal pure returns (uint144 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint152 at `mPtr` in memory.
    function readUint152(
        MemoryPointer mPtr
    ) internal pure returns (uint152 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint160 at `mPtr` in memory.
    function readUint160(
        MemoryPointer mPtr
    ) internal pure returns (uint160 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint168 at `mPtr` in memory.
    function readUint168(
        MemoryPointer mPtr
    ) internal pure returns (uint168 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint176 at `mPtr` in memory.
    function readUint176(
        MemoryPointer mPtr
    ) internal pure returns (uint176 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint184 at `mPtr` in memory.
    function readUint184(
        MemoryPointer mPtr
    ) internal pure returns (uint184 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint192 at `mPtr` in memory.
    function readUint192(
        MemoryPointer mPtr
    ) internal pure returns (uint192 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint200 at `mPtr` in memory.
    function readUint200(
        MemoryPointer mPtr
    ) internal pure returns (uint200 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint208 at `mPtr` in memory.
    function readUint208(
        MemoryPointer mPtr
    ) internal pure returns (uint208 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint216 at `mPtr` in memory.
    function readUint216(
        MemoryPointer mPtr
    ) internal pure returns (uint216 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint224 at `mPtr` in memory.
    function readUint224(
        MemoryPointer mPtr
    ) internal pure returns (uint224 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint232 at `mPtr` in memory.
    function readUint232(
        MemoryPointer mPtr
    ) internal pure returns (uint232 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint240 at `mPtr` in memory.
    function readUint240(
        MemoryPointer mPtr
    ) internal pure returns (uint240 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint248 at `mPtr` in memory.
    function readUint248(
        MemoryPointer mPtr
    ) internal pure returns (uint248 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the uint256 at `mPtr` in memory.
    function readUint256(
        MemoryPointer mPtr
    ) internal pure returns (uint256 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int8 at `mPtr` in memory.
    function readInt8(MemoryPointer mPtr) internal pure returns (int8 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int16 at `mPtr` in memory.
    function readInt16(MemoryPointer mPtr) internal pure returns (int16 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int24 at `mPtr` in memory.
    function readInt24(MemoryPointer mPtr) internal pure returns (int24 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int32 at `mPtr` in memory.
    function readInt32(MemoryPointer mPtr) internal pure returns (int32 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int40 at `mPtr` in memory.
    function readInt40(MemoryPointer mPtr) internal pure returns (int40 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int48 at `mPtr` in memory.
    function readInt48(MemoryPointer mPtr) internal pure returns (int48 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int56 at `mPtr` in memory.
    function readInt56(MemoryPointer mPtr) internal pure returns (int56 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int64 at `mPtr` in memory.
    function readInt64(MemoryPointer mPtr) internal pure returns (int64 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int72 at `mPtr` in memory.
    function readInt72(MemoryPointer mPtr) internal pure returns (int72 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int80 at `mPtr` in memory.
    function readInt80(MemoryPointer mPtr) internal pure returns (int80 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int88 at `mPtr` in memory.
    function readInt88(MemoryPointer mPtr) internal pure returns (int88 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int96 at `mPtr` in memory.
    function readInt96(MemoryPointer mPtr) internal pure returns (int96 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int104 at `mPtr` in memory.
    function readInt104(
        MemoryPointer mPtr
    ) internal pure returns (int104 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int112 at `mPtr` in memory.
    function readInt112(
        MemoryPointer mPtr
    ) internal pure returns (int112 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int120 at `mPtr` in memory.
    function readInt120(
        MemoryPointer mPtr
    ) internal pure returns (int120 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int128 at `mPtr` in memory.
    function readInt128(
        MemoryPointer mPtr
    ) internal pure returns (int128 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int136 at `mPtr` in memory.
    function readInt136(
        MemoryPointer mPtr
    ) internal pure returns (int136 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int144 at `mPtr` in memory.
    function readInt144(
        MemoryPointer mPtr
    ) internal pure returns (int144 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int152 at `mPtr` in memory.
    function readInt152(
        MemoryPointer mPtr
    ) internal pure returns (int152 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int160 at `mPtr` in memory.
    function readInt160(
        MemoryPointer mPtr
    ) internal pure returns (int160 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int168 at `mPtr` in memory.
    function readInt168(
        MemoryPointer mPtr
    ) internal pure returns (int168 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int176 at `mPtr` in memory.
    function readInt176(
        MemoryPointer mPtr
    ) internal pure returns (int176 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int184 at `mPtr` in memory.
    function readInt184(
        MemoryPointer mPtr
    ) internal pure returns (int184 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int192 at `mPtr` in memory.
    function readInt192(
        MemoryPointer mPtr
    ) internal pure returns (int192 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int200 at `mPtr` in memory.
    function readInt200(
        MemoryPointer mPtr
    ) internal pure returns (int200 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int208 at `mPtr` in memory.
    function readInt208(
        MemoryPointer mPtr
    ) internal pure returns (int208 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int216 at `mPtr` in memory.
    function readInt216(
        MemoryPointer mPtr
    ) internal pure returns (int216 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int224 at `mPtr` in memory.
    function readInt224(
        MemoryPointer mPtr
    ) internal pure returns (int224 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int232 at `mPtr` in memory.
    function readInt232(
        MemoryPointer mPtr
    ) internal pure returns (int232 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int240 at `mPtr` in memory.
    function readInt240(
        MemoryPointer mPtr
    ) internal pure returns (int240 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int248 at `mPtr` in memory.
    function readInt248(
        MemoryPointer mPtr
    ) internal pure returns (int248 value) {
        assembly {
            value := mload(mPtr)
        }
    }

    /// @dev Reads the int256 at `mPtr` in memory.
    function readInt256(
        MemoryPointer mPtr
    ) internal pure returns (int256 value) {
        assembly {
            value := mload(mPtr)
        }
    }
}

library MemoryWriters {
    /// @dev Writes `valuePtr` to memory at `mPtr`.
    function write(MemoryPointer mPtr, MemoryPointer valuePtr) internal pure {
        assembly {
            mstore(mPtr, valuePtr)
        }
    }

    /// @dev Writes a boolean `value` to `mPtr` in memory.
    function write(MemoryPointer mPtr, bool value) internal pure {
        assembly {
            mstore(mPtr, value)
        }
    }

    /// @dev Writes an address `value` to `mPtr` in memory.
    function write(MemoryPointer mPtr, address value) internal pure {
        assembly {
            mstore(mPtr, value)
        }
    }

    /// @dev Writes a bytes32 `value` to `mPtr` in memory.
    /// Separate name to disambiguate literal write parameters.
    function writeBytes32(MemoryPointer mPtr, bytes32 value) internal pure {
        assembly {
            mstore(mPtr, value)
        }
    }

    /// @dev Writes a uint256 `value` to `mPtr` in memory.
    function write(MemoryPointer mPtr, uint256 value) internal pure {
        assembly {
            mstore(mPtr, value)
        }
    }

    /// @dev Writes an int256 `value` to `mPtr` in memory.
    /// Separate name to disambiguate literal write parameters.
    function writeInt(MemoryPointer mPtr, int256 value) internal pure {
        assembly {
            mstore(mPtr, value)
        }
    }
}

File 3 of 53 : ConsiderationEncoder.sol
// 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 "seaport-types/src/lib/ConsiderationConstants.sol";

import {BasicOrderParameters, OrderParameters} from "seaport-types/src/lib/ConsiderationStructs.sol";

import {CalldataPointer, getFreeMemoryPointer, MemoryPointer} from "seaport-types/src/helpers/PointerLibraries.sol";

contract ConsiderationEncoder {
    /**
     * @dev Takes a bytes array and casts it to a memory pointer.
     *
     * @param obj A bytes array in memory.
     *
     * @return ptr A memory pointer to the start of the bytes array in memory.
     */
    function toMemoryPointer(bytes memory obj) internal pure returns (MemoryPointer ptr) {
        assembly {
            ptr := obj
        }
    }

    /**
     * @dev Takes an array of bytes32 types and casts it to a memory pointer.
     *
     * @param obj An array of bytes32 types in memory.
     *
     * @return ptr A memory pointer to the start of the array of bytes32 types
     *             in memory.
     */
    function toMemoryPointer(bytes32[] memory obj) internal pure returns (MemoryPointer ptr) {
        assembly {
            ptr := obj
        }
    }

    /**
     * @dev Takes a bytes array in memory and copies it to a new location in
     *      memory.
     *
     * @param src A memory pointer referencing the bytes array to be copied (and
     *            pointing to the length of the bytes array).
     * @param src A memory pointer referencing the location in memory to copy
     *            the bytes array to (and pointing to the length of the copied
     *            bytes array).
     *
     * @return size The size of the bytes array.
     */
    function _encodeBytes(MemoryPointer src, MemoryPointer dst) internal view returns (uint256 size) {
        unchecked {
            // Mask the length of the bytes array to protect against overflow
            // and round up to the nearest word.
            // Note: `size` also includes the 1 word that stores the length.
            size = (src.readUint256() + SixtyThreeBytes) & OnlyFullWordMask;

            // Copy the bytes array to the new memory location.
            src.copy(dst, size);
        }
    }

    /**
     * @dev Takes an OrderParameters struct and a context bytes array in memory
     *      and encodes it as `generateOrder` calldata.
     *
     * @param orderParameters The OrderParameters struct used to construct the
     *                        encoded `generateOrder` calldata.
     * @param context         The context bytes array used to construct the
     *                        encoded `generateOrder` calldata.
     *
     * @return dst  A memory pointer referencing the encoded `generateOrder`
     *              calldata.
     * @return size The size of the bytes array.
     */
    function _encodeGenerateOrder(OrderParameters memory orderParameters, bytes memory context)
        internal
        view
        returns (MemoryPointer dst, uint256 size)
    {
        // Get the memory pointer for the OrderParameters struct.
        MemoryPointer src = orderParameters.toMemoryPointer();

        // Get free memory pointer to write calldata to.
        dst = getFreeMemoryPointer();

        // Write generateOrder selector and get pointer to start of calldata.
        dst.write(generateOrder_selector);
        dst = dst.offset(generateOrder_selector_offset);

        // Get pointer to the beginning of the encoded data.
        MemoryPointer dstHead = dst.offset(generateOrder_head_offset);

        // Write `fulfiller` to calldata.
        dstHead.write(msg.sender);

        // Initialize tail offset, used to populate the minimumReceived array.
        uint256 tailOffset = generateOrder_base_tail_offset;

        // Write offset to minimumReceived.
        dstHead.offset(generateOrder_minimumReceived_head_offset).write(tailOffset);

        // Get memory pointer to `orderParameters.offer.length`.
        MemoryPointer srcOfferPointer = src.offset(OrderParameters_offer_head_offset).readMemoryPointer();

        // Encode the offer array as a `SpentItem[]`.
        uint256 minimumReceivedSize = _encodeSpentItems(srcOfferPointer, dstHead.offset(tailOffset));

        unchecked {
            // Increment tail offset, now used to populate maximumSpent array.
            tailOffset += minimumReceivedSize;
        }

        // Write offset to maximumSpent.
        dstHead.offset(generateOrder_maximumSpent_head_offset).write(tailOffset);

        // Get memory pointer to `orderParameters.consideration.length`.
        MemoryPointer srcConsiderationPointer =
            src.offset(OrderParameters_consideration_head_offset).readMemoryPointer();

        // Encode the consideration array as a `SpentItem[]`.
        uint256 maximumSpentSize = _encodeSpentItems(srcConsiderationPointer, dstHead.offset(tailOffset));

        unchecked {
            // Increment tail offset, now used to populate context array.
            tailOffset += maximumSpentSize;
        }

        // Write offset to context.
        dstHead.offset(generateOrder_context_head_offset).write(tailOffset);

        // Get memory pointer to context.
        MemoryPointer srcContext = toMemoryPointer(context);

        // Encode context as a bytes array.
        uint256 contextSize = _encodeBytes(srcContext, dstHead.offset(tailOffset));

        unchecked {
            // Increment the tail offset, now used to determine final size.
            tailOffset += contextSize;

            // Derive the final size by including the selector.
            size = Selector_length + tailOffset;
        }
    }

    /**
     * @dev Takes an order hash (e.g. offerer shifted 96 bits to the left XOR'd
     *      with the contract nonce in the case of contract orders), an
     *      OrderParameters struct, context bytes array, and an array of order
     *      hashes for each order included as part of the current fulfillment
     *      and encodes it as `ratifyOrder` calldata.
     *
     * @param orderHash       The order hash (e.g. shl(0x60, offerer) ^ nonce).
     * @param orderParameters The OrderParameters struct used to construct the
     *                        encoded `ratifyOrder` calldata.
     * @param context         The context bytes array used to construct the
     *                        encoded `ratifyOrder` calldata.
     * @param orderHashes     An array of bytes32 values representing the order
     *                        hashes of all orders included as part of the
     *                        current fulfillment.
     * @param shiftedOfferer  The offerer for the order, shifted 96 bits to the
     *                        left.
     *
     * @return dst  A memory pointer referencing the encoded `ratifyOrder`
     *              calldata.
     * @return size The size of the bytes array.
     */
    function _encodeRatifyOrder(
        bytes32 orderHash, // e.g. shl(0x60, offerer) ^ contract nonce
        OrderParameters memory orderParameters,
        bytes memory context, // encoded based on the schemaID
        bytes32[] memory orderHashes,
        uint256 shiftedOfferer
    ) internal view returns (MemoryPointer dst, uint256 size) {
        // Get free memory pointer to write calldata to. This isn't allocated as
        // it is only used for a single function call.
        dst = getFreeMemoryPointer();

        // Write ratifyOrder selector and get pointer to start of calldata.
        dst.write(ratifyOrder_selector);
        dst = dst.offset(ratifyOrder_selector_offset);

        // Get pointer to the beginning of the encoded data.
        MemoryPointer dstHead = dst.offset(ratifyOrder_head_offset);

        // Write contractNonce to calldata via xor(orderHash, shiftedOfferer).
        dstHead.offset(ratifyOrder_contractNonce_offset).write(uint256(orderHash) ^ shiftedOfferer);

        // Initialize tail offset, used to populate the offer array.
        uint256 tailOffset = ratifyOrder_base_tail_offset;
        MemoryPointer src = orderParameters.toMemoryPointer();

        // Write offset to `offer`.
        dstHead.write(tailOffset);

        // Get memory pointer to `orderParameters.offer.length`.
        MemoryPointer srcOfferPointer = src.offset(OrderParameters_offer_head_offset).readMemoryPointer();

        // Encode the offer array as a `SpentItem[]`.
        uint256 offerSize = _encodeSpentItems(srcOfferPointer, dstHead.offset(tailOffset));

        unchecked {
            // Increment tail offset, now used to populate consideration array.
            tailOffset += offerSize;
        }

        // Write offset to consideration.
        dstHead.offset(ratifyOrder_consideration_head_offset).write(tailOffset);

        // Get pointer to `orderParameters.consideration.length`.
        MemoryPointer srcConsiderationPointer =
            src.offset(OrderParameters_consideration_head_offset).readMemoryPointer();

        // Encode the consideration array as a `ReceivedItem[]`.
        uint256 considerationSize =
            _encodeConsiderationAsReceivedItems(srcConsiderationPointer, dstHead.offset(tailOffset));

        unchecked {
            // Increment tail offset, now used to populate context array.
            tailOffset += considerationSize;
        }

        // Write offset to context.
        dstHead.offset(ratifyOrder_context_head_offset).write(tailOffset);

        // Encode context.
        uint256 contextSize = _encodeBytes(toMemoryPointer(context), dstHead.offset(tailOffset));

        unchecked {
            // Increment tail offset, now used to populate orderHashes array.
            tailOffset += contextSize;
        }

        // Write offset to orderHashes.
        dstHead.offset(ratifyOrder_orderHashes_head_offset).write(tailOffset);

        // Encode orderHashes.
        uint256 orderHashesSize = _encodeOrderHashes(toMemoryPointer(orderHashes), dstHead.offset(tailOffset));

        unchecked {
            // Increment the tail offset, now used to determine final size.
            tailOffset += orderHashesSize;

            // Derive the final size by including the selector.
            size = Selector_length + tailOffset;
        }
    }

    /**
     * @dev Takes an order hash, OrderParameters struct, extraData bytes array,
     *      and array of order hashes for each order included as part of the
     *      current fulfillment and encodes it as `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);
        }
    }
}

File 4 of 53 : ConsiderationConstants.sol
// 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 = 0x03312e35; // 1.5
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;

File 5 of 53 : ConsiderationStructs.sol
// 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
        }
    }
}

File 6 of 53 : ConsiderationEnums.sol
// 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
}

File 7 of 53 : ConsiderationDecoder.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {
    AdvancedOrder,
    ConsiderationItem,
    CriteriaResolver,
    Fulfillment,
    FulfillmentComponent,
    OfferItem,
    Order,
    OrderParameters,
    ReceivedItem
} from "seaport-types/src/lib/ConsiderationStructs.sol";

import {
    AdvancedOrder_denominator_offset,
    AdvancedOrder_extraData_offset,
    AdvancedOrder_fixed_segment_0,
    AdvancedOrder_head_size,
    AdvancedOrder_numerator_offset,
    AdvancedOrder_signature_offset,
    AdvancedOrderPlusOrderParameters_head_size,
    Common_amount_offset,
    Common_endAmount_offset,
    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 "seaport-types/src/lib/ConsiderationConstants.sol";

import {CalldataPointer, malloc, MemoryPointer, OffsetOrLengthMask} from "seaport-types/src/helpers/PointerLibraries.sol";

contract ConsiderationDecoder {
    /**
     * @dev Takes a bytes array from calldata and copies it into memory.
     *
     * @param cdPtrLength A calldata pointer to the start of the bytes array in
     *                    calldata which contains the length of the array.
     *
     * @return mPtrLength A memory pointer to the start of the bytes array in
     *                    memory which contains the length of the array.
     */
    function _decodeBytes(CalldataPointer cdPtrLength) internal pure returns (MemoryPointer mPtrLength) {
        assembly {
            // Get the current free memory pointer.
            mPtrLength := mload(FreeMemoryPointerSlot)

            // Derive the size of the bytes array, rounding up to nearest word
            // and adding a word for the length field. Note: masking
            // `calldataload(cdPtrLength)` is redundant here.
            let size := add(and(add(calldataload(cdPtrLength), ThirtyOneBytes), OnlyFullWordMask), OneWord)

            // Copy bytes from calldata into memory based on pointers and size.
            calldatacopy(mPtrLength, cdPtrLength, size)

            // Store the masked value in memory. Note: the value of `size` is at
            // least 32, meaning the calldatacopy above will at least write to
            // `[mPtrLength, mPtrLength + 32)`.
            mstore(mPtrLength, and(calldataload(cdPtrLength), OffsetOrLengthMask))

            // Update free memory pointer based on the size of the bytes array.
            mstore(FreeMemoryPointerSlot, add(mPtrLength, size))
        }
    }

    /**
     * @dev Takes an offer array from calldata and copies it into memory.
     *
     * @param cdPtrLength A calldata pointer to the start of the offer array
     *                    in calldata which contains the length of the array.
     *
     * @return mPtrLength A memory pointer to the start of the offer array in
     *                    memory which contains the length of the array.
     */
    function _decodeOffer(CalldataPointer cdPtrLength) internal pure returns (MemoryPointer mPtrLength) {
        assembly {
            // Retrieve length of array, masking to prevent potential overflow.
            let arrLength := and(calldataload(cdPtrLength), OffsetOrLengthMask)

            // Get the current free memory pointer.
            mPtrLength := mload(FreeMemoryPointerSlot)

            // Write the array length to memory.
            mstore(mPtrLength, arrLength)

            // Derive the head by adding one word to the length pointer.
            let mPtrHead := add(mPtrLength, OneWord)

            // Derive the tail by adding one word per element (note that structs
            // are written to memory with an offset per struct element).
            let mPtrTail := add(mPtrHead, shl(OneWordShift, arrLength))

            // Track the next tail, beginning with the initial tail value.
            let mPtrTailNext := mPtrTail

            // Copy all offer array data into memory at the tail pointer.
            calldatacopy(mPtrTail, add(cdPtrLength, OneWord), mul(arrLength, OfferItem_size))

            // Track the next head pointer, starting with initial head value.
            let mPtrHeadNext := mPtrHead

            // Iterate over each head pointer until it reaches the tail.
            for {} lt(mPtrHeadNext, mPtrTail) {} {
                // Write the next tail pointer to next head pointer in memory.
                mstore(mPtrHeadNext, mPtrTailNext)

                // Increment the next head pointer by one word.
                mPtrHeadNext := add(mPtrHeadNext, OneWord)

                // Increment the next tail pointer by the size of an offer item.
                mPtrTailNext := add(mPtrTailNext, OfferItem_size)
            }

            // Update free memory pointer to allocate memory up to end of tail.
            mstore(FreeMemoryPointerSlot, mPtrTailNext)
        }
    }

    /**
     * @dev Takes a consideration array from calldata and copies it into memory.
     *
     * @param cdPtrLength A calldata pointer to the start of the consideration
     *                    array in calldata which contains the length of the
     *                    array.
     *
     * @return mPtrLength A memory pointer to the start of the consideration
     *                    array in memory which contains the length of the
     *                    array.
     */
    function _decodeConsideration(CalldataPointer cdPtrLength) internal pure returns (MemoryPointer mPtrLength) {
        assembly {
            // Retrieve length of array, masking to prevent potential overflow.
            let arrLength := and(calldataload(cdPtrLength), OffsetOrLengthMask)

            // Get the current free memory pointer.
            mPtrLength := mload(FreeMemoryPointerSlot)

            // Write the array length to memory.
            mstore(mPtrLength, arrLength)

            // Derive the head by adding one word to the length pointer.
            let mPtrHead := add(mPtrLength, OneWord)

            // Derive the tail by adding one word per element (note that structs
            // are written to memory with an offset per struct element).
            let mPtrTail := add(mPtrHead, shl(OneWordShift, arrLength))

            // Track the next tail, beginning with the initial tail value.
            let mPtrTailNext := mPtrTail

            // Copy all consideration array data into memory at tail pointer.
            calldatacopy(mPtrTail, add(cdPtrLength, OneWord), mul(arrLength, ConsiderationItem_size))

            // Track the next head pointer, starting with initial head value.
            let mPtrHeadNext := mPtrHead

            // Iterate over each head pointer until it reaches the tail.
            for {} lt(mPtrHeadNext, mPtrTail) {} {
                // Write the next tail pointer to next head pointer in memory.
                mstore(mPtrHeadNext, mPtrTailNext)

                // Increment the next head pointer by one word.
                mPtrHeadNext := add(mPtrHeadNext, OneWord)

                // Increment next tail pointer by size of a consideration item.
                mPtrTailNext := add(mPtrTailNext, ConsiderationItem_size)
            }

            // Update free memory pointer to allocate memory up to end of tail.
            mstore(FreeMemoryPointerSlot, mPtrTailNext)
        }
    }

    /**
     * @dev Takes a calldata pointer and memory pointer and copies a referenced
     *      OrderParameters struct and associated offer and consideration data
     *      to memory.
     *
     * @param cdPtr A calldata pointer for the OrderParameters struct.
     * @param mPtr A memory pointer to the OrderParameters struct head.
     */
    function _decodeOrderParametersTo(CalldataPointer cdPtr, MemoryPointer mPtr) internal pure {
        // Copy the full OrderParameters head from calldata to memory.
        cdPtr.copy(mPtr, OrderParameters_head_size);

        // Resolve the offer calldata offset, use that to decode and copy offer
        // from calldata, and write resultant memory offset to head in memory.
        mPtr.offset(OrderParameters_offer_head_offset).write(
            _decodeOffer(cdPtr.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 Caches the endAmount in an offer item and replaces it with
     * a given recipient so that its memory may be reused as a temporary
     * ReceivedItem.
     *
     * @param offerItem The offer item.
     * @param recipient The recipient.
     *
     * @return originalEndAmount The original end amount.
     */
    function _replaceEndAmountWithRecipient(OfferItem memory offerItem, address recipient)
        internal
        pure
        returns (uint256 originalEndAmount)
    {
        assembly {
            // Derive the pointer to the end amount on the offer item.
            let endAmountPtr := add(offerItem, ReceivedItem_recipient_offset)

            // Retrieve the value of the end amount on the offer item.
            originalEndAmount := mload(endAmountPtr)

            // Write recipient to received item at the offer end amount pointer.
            mstore(endAmountPtr, recipient)
        }
    }
}

File 8 of 53 : CounterManager.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {ConsiderationEventsAndErrors} from "seaport-types/src/interfaces/ConsiderationEventsAndErrors.sol";

import {ReentrancyGuard} from "./ReentrancyGuard.sol";

import {Counter_blockhash_shift, OneWord, TwoWords} from "seaport-types/src/lib/ConsiderationConstants.sol";

/**
 * @title CounterManager
 * @author 0age
 * @notice CounterManager contains a storage mapping and related functionality
 *         for retrieving and incrementing a per-offerer counter.
 */
contract CounterManager is ConsiderationEventsAndErrors, ReentrancyGuard {
    // Only orders signed using an offerer's current counter are fulfillable.
    mapping(address => uint256) private _counters;

    /**
     * @dev Internal function to cancel all orders from a given offerer in bulk
     *      by incrementing a counter by a large, quasi-random interval. Note
     *      that only the offerer may increment the counter. Note that the
     *      counter is incremented by a large, quasi-random interval, which
     *      makes it infeasible to "activate" signed orders by incrementing the
     *      counter.  This activation functionality can be achieved instead with
     *      restricted orders or contract orders.
     *
     * @return newCounter The new counter.
     */
    function _incrementCounter() internal returns (uint256 newCounter) {
        // Ensure that the reentrancy guard is not currently set.
        _assertNonReentrant();

        // Utilize assembly to access counters storage mapping directly. Skip
        // overflow check as counter cannot be incremented that far.
        assembly {
            // Use second half of previous block hash as a quasi-random number.
            let quasiRandomNumber := shr(Counter_blockhash_shift, blockhash(sub(number(), 1)))

            // Write the caller to scratch space.
            mstore(0, caller())

            // Write the storage slot for _counters to scratch space.
            mstore(OneWord, _counters.slot)

            // Derive the storage pointer for the counter value.
            let storagePointer := keccak256(0, TwoWords)

            // Derive new counter value using random number and original value.
            newCounter := add(quasiRandomNumber, sload(storagePointer))

            // Store the updated counter value.
            sstore(storagePointer, newCounter)
        }

        // Emit an event containing the new counter.
        emit CounterIncremented(newCounter, msg.sender);
    }

    /**
     * @dev Internal view function to retrieve the current counter for a given
     *      offerer.
     *
     * @param offerer The offerer in question.
     *
     * @return currentCounter The current counter.
     */
    function _getCounter(address offerer) internal view returns (uint256 currentCounter) {
        // Return the counter for the supplied offerer.
        currentCounter = _counters[offerer];
    }
}

File 9 of 53 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {ReentrancyErrors} from "seaport-types/src/interfaces/ReentrancyErrors.sol";

import {LowLevelHelpers} from "./LowLevelHelpers.sol";

import {_revertInvalidMsgValue, _revertNoReentrantCalls} from "seaport-types/src/lib/ConsiderationErrors.sol";

import {
    _ENTERED_AND_ACCEPTING_NATIVE_TOKENS, _ENTERED, _NOT_ENTERED
} from "seaport-types/src/lib/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);
        }
    }
}

File 10 of 53 : ConsiderationEventsAndErrors.sol
// 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();
}

File 11 of 53 : ConsiderationErrors.sol
// 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
        )
    }
}

File 12 of 53 : ReentrancyErrors.sol
// 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();
}

File 13 of 53 : LowLevelHelpers.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {
    CostPerWord,
    ExtraGasBuffer,
    FreeMemoryPointerSlot,
    MemoryExpansionCoefficientShift,
    OneWord,
    OneWordShift,
    ThirtyOneBytes
} from "seaport-types/src/lib/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
        }
    }
}

File 14 of 53 : ConsiderationErrorConstants.sol
// 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;

File 15 of 53 : ConsiderationBase.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {ConduitControllerInterface} from "seaport-types/src/interfaces/ConduitControllerInterface.sol";

import {ConsiderationEventsAndErrors} from "seaport-types/src/interfaces/ConsiderationEventsAndErrors.sol";

import {
    BulkOrder_Typehash_Height_One,
    BulkOrder_Typehash_Height_Two,
    BulkOrder_Typehash_Height_Three,
    BulkOrder_Typehash_Height_Four,
    BulkOrder_Typehash_Height_Five,
    BulkOrder_Typehash_Height_Six,
    BulkOrder_Typehash_Height_Seven,
    BulkOrder_Typehash_Height_Eight,
    BulkOrder_Typehash_Height_Nine,
    BulkOrder_Typehash_Height_Ten,
    BulkOrder_Typehash_Height_Eleven,
    BulkOrder_Typehash_Height_Twelve,
    BulkOrder_Typehash_Height_Thirteen,
    BulkOrder_Typehash_Height_Fourteen,
    BulkOrder_Typehash_Height_Fifteen,
    BulkOrder_Typehash_Height_Sixteen,
    BulkOrder_Typehash_Height_Seventeen,
    BulkOrder_Typehash_Height_Eighteen,
    BulkOrder_Typehash_Height_Nineteen,
    BulkOrder_Typehash_Height_Twenty,
    BulkOrder_Typehash_Height_TwentyOne,
    BulkOrder_Typehash_Height_TwentyTwo,
    BulkOrder_Typehash_Height_TwentyThree,
    BulkOrder_Typehash_Height_TwentyFour,
    EIP712_domainData_chainId_offset,
    EIP712_domainData_nameHash_offset,
    EIP712_domainData_size,
    EIP712_domainData_verifyingContract_offset,
    EIP712_domainData_versionHash_offset,
    FreeMemoryPointerSlot,
    NameLengthPtr,
    NameWithLength,
    OneWord,
    Slot0x80,
    ThreeWords,
    ZeroSlot
} from "seaport-types/src/lib/ConsiderationConstants.sol";

import {ConsiderationDecoder} from "./ConsiderationDecoder.sol";

import {ConsiderationEncoder} from "./ConsiderationEncoder.sol";

/**
 * @title ConsiderationBase
 * @author 0age
 * @notice ConsiderationBase contains immutable constants and constructor logic.
 */
contract ConsiderationBase is ConsiderationDecoder, ConsiderationEncoder, ConsiderationEventsAndErrors {
    // Precompute hashes, original chainId, and domain separator on deployment.
    bytes32 internal immutable _NAME_HASH;
    bytes32 internal immutable _VERSION_HASH;
    bytes32 internal immutable _EIP_712_DOMAIN_TYPEHASH;
    bytes32 internal immutable _OFFER_ITEM_TYPEHASH;
    bytes32 internal immutable _CONSIDERATION_ITEM_TYPEHASH;
    bytes32 internal immutable _ORDER_TYPEHASH;
    uint256 internal immutable _CHAIN_ID;
    bytes32 internal immutable _DOMAIN_SEPARATOR;

    // Allow for interaction with the conduit controller.
    ConduitControllerInterface internal immutable _CONDUIT_CONTROLLER;

    // Cache the conduit creation code hash used by the conduit controller.
    bytes32 internal immutable _CONDUIT_CREATION_CODE_HASH;

    /**
     * @dev Derive and set hashes, reference chainId, and associated domain
     *      separator during deployment.
     *
     * @param conduitController A contract that deploys conduits, or proxies
     *                          that may optionally be used to transfer approved
     *                          ERC20/721/1155 tokens.
     */
    constructor(address conduitController) {
        // Derive name and version hashes alongside required EIP-712 typehashes.
        (
            _NAME_HASH,
            _VERSION_HASH,
            _EIP_712_DOMAIN_TYPEHASH,
            _OFFER_ITEM_TYPEHASH,
            _CONSIDERATION_ITEM_TYPEHASH,
            _ORDER_TYPEHASH
        ) = _deriveTypehashes();

        // Store the current chainId and derive the current domain separator.
        _CHAIN_ID = block.chainid;
        _DOMAIN_SEPARATOR = _deriveDomainSeparator();

        // Set the supplied conduit controller.
        _CONDUIT_CONTROLLER = ConduitControllerInterface(conduitController);

        // Retrieve the conduit creation code hash from the supplied controller.
        (_CONDUIT_CREATION_CODE_HASH,) = (_CONDUIT_CONTROLLER.getConduitCodeHashes());
    }

    /**
     * @dev Internal view function to derive the EIP-712 domain separator.
     *
     * @return domainSeparator The derived domain separator.
     */
    function _deriveDomainSeparator() internal view returns (bytes32 domainSeparator) {
        bytes32 typehash = _EIP_712_DOMAIN_TYPEHASH;
        bytes32 nameHash = _NAME_HASH;
        bytes32 versionHash = _VERSION_HASH;

        // Leverage scratch space and other memory to perform an efficient hash.
        assembly {
            // Retrieve the free memory pointer; it will be replaced afterwards.
            let freeMemoryPointer := mload(FreeMemoryPointerSlot)

            // Retrieve value at 0x80; it will also be replaced afterwards.
            let slot0x80 := mload(Slot0x80)

            // Place typehash, name hash, and version hash at start of memory.
            mstore(0, typehash)
            mstore(EIP712_domainData_nameHash_offset, nameHash)
            mstore(EIP712_domainData_versionHash_offset, versionHash)

            // Place chainId in the next memory location.
            mstore(EIP712_domainData_chainId_offset, chainid())

            // Place the address of this contract in the next memory location.
            mstore(EIP712_domainData_verifyingContract_offset, address())

            // Hash relevant region of memory to derive the domain separator.
            domainSeparator := keccak256(0, EIP712_domainData_size)

            // Restore the free memory pointer.
            mstore(FreeMemoryPointerSlot, freeMemoryPointer)

            // Restore the zero slot to zero.
            mstore(ZeroSlot, 0)

            // Restore the value at 0x80.
            mstore(Slot0x80, slot0x80)
        }
    }

    /**
     * @dev Internal pure function to retrieve the default name of this
     *      contract and return.
     *
     * @return The name of this contract.
     */
    function _name() internal pure virtual returns (string memory) {
        // Return the name of the contract.
        assembly {
            // First element is the offset for the returned string. Offset the
            // value in memory by one word so that the free memory pointer will
            // be overwritten by the next write.
            mstore(OneWord, OneWord)

            // Name is right padded, so it touches the length which is left
            // padded. This enables writing both values at once. The free memory
            // pointer will be overwritten in the process.
            mstore(NameLengthPtr, NameWithLength)

            // Standard ABI encoding pads returned data to the nearest word. Use
            // the already empty zero slot memory region for this purpose and
            // return the final name string, offset by the original single word.
            return(OneWord, ThreeWords)
        }
    }

    /**
     * @dev Internal pure function to retrieve the default name of this contract
     *      as a string that can be used internally.
     *
     * @return The name of this contract.
     */
    function _nameString() internal pure virtual returns (string memory) {
        // Return the name of the contract.
        return "Consideration";
    }

    /**
     * @dev Internal pure function to derive required EIP-712 typehashes and
     *      other hashes during contract creation.
     *
     * @return nameHash                  The hash of the name of the contract.
     * @return versionHash               The hash of the version string of the
     *                                   contract.
     * @return eip712DomainTypehash      The primary EIP-712 domain typehash.
     * @return offerItemTypehash         The EIP-712 typehash for OfferItem
     *                                   types.
     * @return considerationItemTypehash The EIP-712 typehash for
     *                                   ConsiderationItem types.
     * @return orderTypehash             The EIP-712 typehash for Order types.
     */
    function _deriveTypehashes()
        internal
        pure
        returns (
            bytes32 nameHash,
            bytes32 versionHash,
            bytes32 eip712DomainTypehash,
            bytes32 offerItemTypehash,
            bytes32 considerationItemTypehash,
            bytes32 orderTypehash
        )
    {
        // Derive hash of the name of the contract.
        nameHash = keccak256(bytes(_nameString()));

        // Derive hash of the version string of the contract.
        versionHash = keccak256(bytes("1.5"));

        // 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)
        }
    }
}

File 16 of 53 : ConduitControllerInterface.sol
// 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);
}

File 17 of 53 : SeaportValidatorHelper.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import { ItemType } from "seaport-types/src/lib/ConsiderationEnums.sol";
import {
    Order,
    OrderParameters,
    BasicOrderParameters,
    OfferItem,
    ConsiderationItem,
    Schema,
    ZoneParameters
} from "seaport-types/src/lib/ConsiderationStructs.sol";
import { ConsiderationTypeHashes } from "./ConsiderationTypeHashes.sol";
import {
    ConsiderationInterface
} from "seaport-types/src/interfaces/ConsiderationInterface.sol";
import {
    ConduitControllerInterface
} from "seaport-types/src/interfaces/ConduitControllerInterface.sol";
import {
    ContractOffererInterface
} from "seaport-types/src/interfaces/ContractOffererInterface.sol";
import { ZoneInterface } from "seaport-types/src/interfaces/ZoneInterface.sol";
import {
    GettersAndDerivers
} from "seaport-core/src/lib/GettersAndDerivers.sol";
import {
    SeaportValidatorInterface
} from "../lib/SeaportValidatorInterface.sol";
import { ZoneInterface } from "seaport-types/src/interfaces/ZoneInterface.sol";
import {
    ERC20Interface,
    ERC721Interface,
    ERC1155Interface
} from "seaport-types/src/interfaces/AbridgedTokenInterfaces.sol";
import { IERC165 } from "@openzeppelin/contracts/interfaces/IERC165.sol";
import { IERC2981 } from "@openzeppelin/contracts/interfaces/IERC2981.sol";
import {
    ErrorsAndWarnings,
    ErrorsAndWarningsLib
} from "../lib/ErrorsAndWarnings.sol";
import { SafeStaticCall } from "../lib/SafeStaticCall.sol";
import { Murky } from "../lib/Murky.sol";
import {
    IssueParser,
    ValidationConfiguration,
    TimeIssue,
    StatusIssue,
    OfferIssue,
    ContractOffererIssue,
    ConsiderationIssue,
    PrimaryFeeIssue,
    ERC721Issue,
    ERC1155Issue,
    ERC20Issue,
    NativeIssue,
    ZoneIssue,
    ConduitIssue,
    CreatorFeeIssue,
    SignatureIssue,
    GenericIssue,
    ConsiderationItemConfiguration
} from "./SeaportValidatorTypes.sol";
import { Verifiers } from "seaport-core/src/lib/Verifiers.sol";

/**
 * @title SeaportValidator
 * @author OpenSea Protocol Team
 * @notice SeaportValidatorHelper assists in advanced validation to seaport orders.
 */
contract SeaportValidatorHelper is Murky {
    using ErrorsAndWarningsLib for ErrorsAndWarnings;
    using SafeStaticCall for address;
    using IssueParser for *;

    /// @notice Ethereum creator fee engine address
    CreatorFeeEngineInterface public immutable creatorFeeEngine;

    bytes4 public constant ERC20_INTERFACE_ID = 0x36372b07;

    bytes4 public constant ERC721_INTERFACE_ID = 0x80ac58cd;

    bytes4 public constant ERC1155_INTERFACE_ID = 0xd9b67a26;

    constructor() {
        address creatorFeeEngineAddress;
        if (block.chainid == 1 || block.chainid == 31337) {
            creatorFeeEngineAddress = 0x0385603ab55642cb4Dd5De3aE9e306809991804f;
        } else if (block.chainid == 3) {
            // Ropsten
            creatorFeeEngineAddress = 0xFf5A6F7f36764aAD301B7C9E85A5277614Df5E26;
        } else if (block.chainid == 4) {
            // Rinkeby
            creatorFeeEngineAddress = 0x8d17687ea9a6bb6efA24ec11DcFab01661b2ddcd;
        } else if (block.chainid == 5) {
            // Goerli
            creatorFeeEngineAddress = 0xe7c9Cb6D966f76f3B5142167088927Bf34966a1f;
        } else if (block.chainid == 42) {
            // Kovan
            creatorFeeEngineAddress = 0x54D88324cBedfFe1e62c9A59eBb310A11C295198;
        } else if (block.chainid == 137) {
            // Polygon
            creatorFeeEngineAddress = 0x28EdFcF0Be7E86b07493466e7631a213bDe8eEF2;
        } else if (block.chainid == 80001) {
            // Mumbai
            creatorFeeEngineAddress = 0x0a01E11887f727D1b1Cd81251eeEE9BEE4262D07;
        } else {
            // No creator fee engine for this chain
            creatorFeeEngineAddress = address(0);
        }

        creatorFeeEngine = CreatorFeeEngineInterface(creatorFeeEngineAddress);
    }

    /**
     * @notice Strict validation operates under tight assumptions. It validates primary
     *    fee, creator fee, private sale consideration, and overall order format.
     * @dev Only checks first fee recipient provided by CreatorFeeEngine.
     *    Order of consideration items must be as follows:
     *    1. Primary consideration
     *    2. Primary fee
     *    3. Creator fee
     *    4. Private sale consideration
     * @param orderParameters The parameters for the order to validate.
     * @param primaryFeeRecipient The primary fee recipient. Set to null address for no primary fee.
     * @param primaryFeeBips The primary fee in BIPs.
     * @param checkCreatorFee Should check for creator fee. If true, creator fee must be present as
     *    according to creator fee engine. If false, must not have creator fee.
     * @return errorsAndWarnings The errors and warnings.
     */
    function validateStrictLogic(
        OrderParameters memory orderParameters,
        address primaryFeeRecipient,
        uint256 primaryFeeBips,
        bool checkCreatorFee
    ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) {
        errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0));

        // Check that order matches the required format (listing or offer)
        {
            bool canCheckFee = true;
            // Single offer item and at least one consideration
            if (
                orderParameters.offer.length != 1 ||
                orderParameters.consideration.length == 0
            ) {
                // Not listing or offer, can't check fees
                canCheckFee = false;
            } else if (
                // Can't have both items be fungible
                isPaymentToken(orderParameters.offer[0].itemType) &&
                isPaymentToken(orderParameters.consideration[0].itemType)
            ) {
                // Not listing or offer, can't check fees
                canCheckFee = false;
            } else if (
                // Can't have both items be non-fungible
                !isPaymentToken(orderParameters.offer[0].itemType) &&
                !isPaymentToken(orderParameters.consideration[0].itemType)
            ) {
                // Not listing or offer, can't check fees
                canCheckFee = false;
            }
            if (!canCheckFee) {
                // Does not match required format
                errorsAndWarnings.addError(
                    GenericIssue.InvalidOrderFormat.parseInt()
                );
                return errorsAndWarnings;
            }
        }

        // Validate secondary consideration items (fees)
        (
            uint256 tertiaryConsiderationIndex,
            ErrorsAndWarnings memory errorsAndWarningsLocal
        ) = _validateSecondaryConsiderationItems(
                orderParameters,
                ConsiderationItemConfiguration({
                    primaryFeeRecipient: primaryFeeRecipient,
                    primaryFeeBips: primaryFeeBips,
                    checkCreatorFee: checkCreatorFee
                })
            );

        errorsAndWarnings.concat(errorsAndWarningsLocal);

        // Validate tertiary consideration items if not 0 (0 indicates error).
        // Only if no prior errors
        if (tertiaryConsiderationIndex != 0) {
            errorsAndWarnings.concat(
                _validateTertiaryConsiderationItems(
                    orderParameters,
                    tertiaryConsiderationIndex
                )
            );
        }
    }

    /**
     * @notice Validate all consideration items for an order
     * @param orderParameters The parameters for the order to validate
     * @return errorsAndWarnings  The errors and warnings
     */
    function validateConsiderationItems(
        OrderParameters memory orderParameters,
        address seaportAddress
    ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) {
        errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0));

        // You must have a consideration item
        if (orderParameters.consideration.length == 0) {
            errorsAndWarnings.addWarning(
                ConsiderationIssue.ZeroItems.parseInt()
            );
            return errorsAndWarnings;
        }

        // Declare a boolean to check if offerer is receiving at least
        // one consideration item
        bool offererReceivingAtLeastOneItem = false;

        // Iterate over each consideration item
        for (uint256 i = 0; i < orderParameters.consideration.length; i++) {
            // Validate consideration item
            errorsAndWarnings.concat(
                validateConsiderationItem(orderParameters, i, seaportAddress)
            );

            ConsiderationItem memory considerationItem1 = orderParameters
                .consideration[i];

            // Check if the offerer is the recipient
            if (!offererReceivingAtLeastOneItem) {
                if (considerationItem1.recipient == orderParameters.offerer) {
                    offererReceivingAtLeastOneItem = true;
                }
            }

            // Check for duplicate consideration items
            for (
                uint256 j = i + 1;
                j < orderParameters.consideration.length;
                j++
            ) {
                // Iterate over each remaining consideration item
                // (previous items already check with this item)
                ConsiderationItem memory considerationItem2 = orderParameters
                    .consideration[j];

                // Check if itemType, token, id, and recipient are the same
                if (
                    considerationItem2.itemType ==
                    considerationItem1.itemType &&
                    considerationItem2.token == considerationItem1.token &&
                    considerationItem2.identifierOrCriteria ==
                    considerationItem1.identifierOrCriteria &&
                    considerationItem2.recipient == considerationItem1.recipient
                ) {
                    errorsAndWarnings.addWarning(
                        // Duplicate consideration item, warning
                        ConsiderationIssue.DuplicateItem.parseInt()
                    );
                }
            }
        }

        if (!offererReceivingAtLeastOneItem) {
            // Offerer is not receiving at least one consideration item
            errorsAndWarnings.addWarning(
                ConsiderationIssue.OffererNotReceivingAtLeastOneItem.parseInt()
            );
        }
    }

    /**
     * @notice Validate a consideration item
     * @param orderParameters The parameters for the order to validate
     * @param considerationItemIndex The index of the consideration item to validate
     * @return errorsAndWarnings  The errors and warnings
     */
    function validateConsiderationItem(
        OrderParameters memory orderParameters,
        uint256 considerationItemIndex,
        address seaportAddress
    ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) {
        errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0));

        // Validate the consideration item at considerationItemIndex
        errorsAndWarnings.concat(
            validateConsiderationItemParameters(
                orderParameters,
                considerationItemIndex,
                seaportAddress
            )
        );
    }

    /**
     * @notice Validates the parameters of a consideration item including contract validation
     * @param orderParameters The parameters for the order to validate
     * @param considerationItemIndex The index of the consideration item to validate
     * @return errorsAndWarnings  The errors and warnings
     */
    function validateConsiderationItemParameters(
        OrderParameters memory orderParameters,
        uint256 considerationItemIndex,
        address seaportAddress
    ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) {
        errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0));

        ConsiderationItem memory considerationItem = orderParameters
            .consideration[considerationItemIndex];

        // Check if startAmount and endAmount are zero
        if (
            considerationItem.startAmount == 0 &&
            considerationItem.endAmount == 0
        ) {
            errorsAndWarnings.addError(
                ConsiderationIssue.AmountZero.parseInt()
            );
            return errorsAndWarnings;
        }

        // Check if the recipient is the null address
        if (considerationItem.recipient == address(0)) {
            errorsAndWarnings.addError(
                ConsiderationIssue.NullRecipient.parseInt()
            );
        }

        if (
            considerationItem.startAmount != considerationItem.endAmount &&
            orderParameters.endTime > orderParameters.startTime
        ) {
            // Check that amount velocity is not too high.
            // Assign larger and smaller amount values
            (uint256 maxAmount, uint256 minAmount) = considerationItem
                .startAmount > considerationItem.endAmount
                ? (considerationItem.startAmount, considerationItem.endAmount)
                : (considerationItem.endAmount, considerationItem.startAmount);

            uint256 amountDelta = maxAmount - minAmount;
            // delta of time that order exists for
            uint256 timeDelta = orderParameters.endTime -
                orderParameters.startTime;

            // Velocity scaled by 1e10 for precision
            uint256 velocity = (amountDelta * 1e10) / timeDelta;
            // gives velocity percentage in hundredth of a basis points per second in terms of larger value
            uint256 velocityPercentage = velocity / (maxAmount * 1e4);

            // 278 * 60 * 30 ~= 500,000
            if (velocityPercentage > 278) {
                // Over 50% change per 30 min
                errorsAndWarnings.addError(
                    ConsiderationIssue.AmountVelocityHigh.parseInt()
                );
            }
            // 28 * 60 * 30 ~= 50,000
            else if (velocityPercentage > 28) {
                // Over 5% change per 30 min
                errorsAndWarnings.addWarning(
                    ConsiderationIssue.AmountVelocityHigh.parseInt()
                );
            }

            // Check for large amount steps
            if (minAmount <= 1e15) {
                errorsAndWarnings.addWarning(
                    ConsiderationIssue.AmountStepLarge.parseInt()
                );
            }
        }

        if (considerationItem.itemType == ItemType.ERC721) {
            // ERC721 type requires amounts to be 1
            if (
                considerationItem.startAmount != 1 ||
                considerationItem.endAmount != 1
            ) {
                errorsAndWarnings.addError(ERC721Issue.AmountNotOne.parseInt());
            }

            // Check EIP165 interface
            if (!checkInterface(considerationItem.token, ERC721_INTERFACE_ID)) {
                errorsAndWarnings.addError(ERC721Issue.InvalidToken.parseInt());
                return errorsAndWarnings;
            }

            // Check that token exists
            if (
                !considerationItem.token.safeStaticCallUint256(
                    abi.encodeWithSelector(
                        ERC721Interface.ownerOf.selector,
                        considerationItem.identifierOrCriteria
                    ),
                    1
                )
            ) {
                // Token does not exist
                errorsAndWarnings.addError(
                    ERC721Issue.IdentifierDNE.parseInt()
                );
            }
        } else if (
            considerationItem.itemType == ItemType.ERC721_WITH_CRITERIA
        ) {
            // Check EIP165 interface
            if (!checkInterface(considerationItem.token, ERC721_INTERFACE_ID)) {
                // Does not implement required interface
                errorsAndWarnings.addError(ERC721Issue.InvalidToken.parseInt());
            }
        } else if (
            considerationItem.itemType == ItemType.ERC1155 ||
            considerationItem.itemType == ItemType.ERC1155_WITH_CRITERIA
        ) {
            // Check EIP165 interface
            if (
                !checkInterface(considerationItem.token, ERC1155_INTERFACE_ID)
            ) {
                // Does not implement required interface
                errorsAndWarnings.addError(
                    ERC1155Issue.InvalidToken.parseInt()
                );
            }
        } else if (considerationItem.itemType == ItemType.ERC20) {
            // ERC20 must have `identifierOrCriteria` be zero
            if (considerationItem.identifierOrCriteria != 0) {
                errorsAndWarnings.addError(
                    ERC20Issue.IdentifierNonZero.parseInt()
                );
            }

            // Check that it is an ERC20 token. ERC20 will return a uint256
            if (
                !considerationItem.token.safeStaticCallUint256(
                    abi.encodeWithSelector(
                        ERC20Interface.allowance.selector,
                        seaportAddress,
                        seaportAddress
                    ),
                    0
                )
            ) {
                // Not an ERC20 token
                errorsAndWarnings.addError(ERC20Issue.InvalidToken.parseInt());
            }
        } else {
            // Must be native
            // NATIVE must have `token` be zero address
            if (considerationItem.token != address(0)) {
                errorsAndWarnings.addError(NativeIssue.TokenAddress.parseInt());
            }
            // NATIVE must have `identifierOrCriteria` be zero
            if (considerationItem.identifierOrCriteria != 0) {
                errorsAndWarnings.addError(
                    NativeIssue.IdentifierNonZero.parseInt()
                );
            }
        }
    }

    function _validateSecondaryConsiderationItems(
        OrderParameters memory orderParameters,
        ConsiderationItemConfiguration memory config
    )
        internal
        view
        returns (
            uint256 /* tertiaryConsiderationIndex */,
            ErrorsAndWarnings memory /* errorsAndWarnings */
        )
    {
        ErrorsAndWarnings memory errorsAndWarnings = ErrorsAndWarnings(
            new uint16[](0),
            new uint16[](0)
        );

        // Consideration item to hold expected creator fee info
        ConsiderationItem memory creatorFeeConsideration;

        bool primaryFeePresent;

        {
            // non-fungible item address
            address itemAddress;
            // non-fungible item identifier
            uint256 itemIdentifier;
            // fungible item start amount
            uint256 transactionAmountStart;
            // fungible item end amount
            uint256 transactionAmountEnd;

            if (isPaymentToken(orderParameters.offer[0].itemType)) {
                // Offer is an offer. Offer item is fungible and used for fees
                creatorFeeConsideration.itemType = orderParameters
                    .offer[0]
                    .itemType;
                creatorFeeConsideration.token = orderParameters.offer[0].token;
                transactionAmountStart = orderParameters.offer[0].startAmount;
                transactionAmountEnd = orderParameters.offer[0].endAmount;

                // Set non-fungible information for calculating creator fee
                itemAddress = orderParameters.consideration[0].token;
                itemIdentifier = orderParameters
                    .consideration[0]
                    .identifierOrCriteria;
            } else {
                // Offer is an offer. Consideration item is fungible and used for fees
                creatorFeeConsideration.itemType = orderParameters
                    .consideration[0]
                    .itemType;
                creatorFeeConsideration.token = orderParameters
                    .consideration[0]
                    .token;
                transactionAmountStart = orderParameters
                    .consideration[0]
                    .startAmount;
                transactionAmountEnd = orderParameters
                    .consideration[0]
                    .endAmount;

                // Set non-fungible information for calculating creator fees
                itemAddress = orderParameters.offer[0].token;
                itemIdentifier = orderParameters.offer[0].identifierOrCriteria;
            }

            // Store flag if primary fee is present
            primaryFeePresent = false;
            {
                // Calculate primary fee start and end amounts
                uint256 primaryFeeStartAmount = (transactionAmountStart *
                    config.primaryFeeBips) / 10000;
                uint256 primaryFeeEndAmount = (transactionAmountEnd *
                    config.primaryFeeBips) / 10000;

                // Check if primary fee check is desired. Skip if calculated amount is zero.
                if (
                    config.primaryFeeRecipient != address(0) &&
                    (primaryFeeStartAmount > 0 || primaryFeeEndAmount > 0)
                ) {
                    // Ensure primary fee is present
                    if (orderParameters.consideration.length < 2) {
                        errorsAndWarnings.addError(
                            PrimaryFeeIssue.Missing.parseInt()
                        );
                        return (0, errorsAndWarnings);
                    }
                    primaryFeePresent = true;

                    ConsiderationItem memory primaryFeeItem = orderParameters
                        .consideration[1];

                    // Check item type
                    if (
                        primaryFeeItem.itemType !=
                        creatorFeeConsideration.itemType
                    ) {
                        errorsAndWarnings.addError(
                            PrimaryFeeIssue.ItemType.parseInt()
                        );
                        return (0, errorsAndWarnings);
                    }
                    // Check token
                    if (primaryFeeItem.token != creatorFeeConsideration.token) {
                        errorsAndWarnings.addError(
                            PrimaryFeeIssue.Token.parseInt()
                        );
                    }
                    // Check start amount
                    if (primaryFeeItem.startAmount < primaryFeeStartAmount) {
                        errorsAndWarnings.addError(
                            PrimaryFeeIssue.StartAmount.parseInt()
                        );
                    }
                    // Check end amount
                    if (primaryFeeItem.endAmount < primaryFeeEndAmount) {
                        errorsAndWarnings.addError(
                            PrimaryFeeIssue.EndAmount.parseInt()
                        );
                    }
                    // Check recipient
                    if (
                        primaryFeeItem.recipient != config.primaryFeeRecipient
                    ) {
                        errorsAndWarnings.addError(
                            PrimaryFeeIssue.Recipient.parseInt()
                        );
                    }
                }
            }

            // Check creator fee
            (
                creatorFeeConsideration.recipient,
                creatorFeeConsideration.startAmount,
                creatorFeeConsideration.endAmount
            ) = getCreatorFeeInfo(
                itemAddress,
                itemIdentifier,
                transactionAmountStart,
                transactionAmountEnd
            );
        }

        // Flag indicating if creator fee is present in considerations
        bool creatorFeePresent = false;

        // Determine if should check for creator fee
        if (
            creatorFeeConsideration.recipient != address(0) &&
            config.checkCreatorFee &&
            (creatorFeeConsideration.startAmount > 0 ||
                creatorFeeConsideration.endAmount > 0)
        ) {
            // Calculate index of creator fee consideration item
            uint16 creatorFeeConsiderationIndex = primaryFeePresent ? 2 : 1; // 2 if primary fee, ow 1

            // Check that creator fee consideration item exists
            if (
                orderParameters.consideration.length - 1 <
                creatorFeeConsiderationIndex
            ) {
                errorsAndWarnings.addError(CreatorFeeIssue.Missing.parseInt());
                return (0, errorsAndWarnings);
            }

            ConsiderationItem memory creatorFeeItem = orderParameters
                .consideration[creatorFeeConsiderationIndex];

            creatorFeePresent = true;

            // Check type
            if (creatorFeeItem.itemType != creatorFeeConsideration.itemType) {
                errorsAndWarnings.addError(CreatorFeeIssue.ItemType.parseInt());
                return (0, errorsAndWarnings);
            }
            // Check token
            if (creatorFeeItem.token != creatorFeeConsideration.token) {
                errorsAndWarnings.addError(CreatorFeeIssue.Token.parseInt());
            }
            // Check start amount
            if (
                creatorFeeItem.startAmount < creatorFeeConsideration.startAmount
            ) {
                errorsAndWarnings.addError(
                    CreatorFeeIssue.StartAmount.parseInt()
                );
            }
            // Check end amount
            if (creatorFeeItem.endAmount < creatorFeeConsideration.endAmount) {
                errorsAndWarnings.addError(
                    CreatorFeeIssue.EndAmount.parseInt()
                );
            }
            // Check recipient
            if (creatorFeeItem.recipient != creatorFeeConsideration.recipient) {
                errorsAndWarnings.addError(
                    CreatorFeeIssue.Recipient.parseInt()
                );
            }
        }

        // Calculate index of first tertiary consideration item
        uint256 tertiaryConsiderationIndex = 1 +
            (primaryFeePresent ? 1 : 0) +
            (creatorFeePresent ? 1 : 0);

        return (tertiaryConsiderationIndex, errorsAndWarnings);
    }

    /**
     * @notice Internal function for validating all consideration items after the fee items.
     *    Only additional acceptable consideration is private sale.
     */
    function _validateTertiaryConsiderationItems(
        OrderParameters memory orderParameters,
        uint256 considerationItemIndex
    ) internal pure returns (ErrorsAndWarnings memory errorsAndWarnings) {
        errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0));

        if (orderParameters.consideration.length <= considerationItemIndex) {
            // No more consideration items
            return errorsAndWarnings;
        }

        ConsiderationItem memory privateSaleConsideration = orderParameters
            .consideration[considerationItemIndex];

        // Check if offer is payment token. Private sale not possible if so.
        if (isPaymentToken(orderParameters.offer[0].itemType)) {
            errorsAndWarnings.addError(
                ConsiderationIssue.ExtraItems.parseInt()
            );
            return errorsAndWarnings;
        }

        // Check if private sale to self
        if (privateSaleConsideration.recipient == orderParameters.offerer) {
            errorsAndWarnings.addError(
                ConsiderationIssue.PrivateSaleToSelf.parseInt()
            );
            return errorsAndWarnings;
        }

        // Ensure that private sale parameters match offer item.
        if (
            privateSaleConsideration.itemType !=
            orderParameters.offer[0].itemType ||
            privateSaleConsideration.token != orderParameters.offer[0].token ||
            orderParameters.offer[0].startAmount !=
            privateSaleConsideration.startAmount ||
            orderParameters.offer[0].endAmount !=
            privateSaleConsideration.endAmount ||
            orderParameters.offer[0].identifierOrCriteria !=
            privateSaleConsideration.identifierOrCriteria
        ) {
            // Invalid private sale, say extra consideration item
            errorsAndWarnings.addError(
                ConsiderationIssue.ExtraItems.parseInt()
            );
            return errorsAndWarnings;
        }

        errorsAndWarnings.addWarning(ConsiderationIssue.PrivateSale.parseInt());

        // Should not be any additional consideration items
        if (orderParameters.consideration.length - 1 > considerationItemIndex) {
            // Extra consideration items
            errorsAndWarnings.addError(
                ConsiderationIssue.ExtraItems.parseInt()
            );
            return errorsAndWarnings;
        }
    }

    /**
     * @notice Fetches the on chain creator fees.
     * @dev Uses the creatorFeeEngine when available, otherwise fallback to `IERC2981`.
     * @param token The token address
     * @param tokenId The token identifier
     * @param transactionAmountStart The transaction start amount
     * @param transactionAmountEnd The transaction end amount
     * @return recipient creator fee recipient
     * @return creatorFeeAmountStart creator fee start amount
     * @return creatorFeeAmountEnd creator fee end amount
     */
    function getCreatorFeeInfo(
        address token,
        uint256 tokenId,
        uint256 transactionAmountStart,
        uint256 transactionAmountEnd
    )
        public
        view
        returns (
            address payable recipient,
            uint256 creatorFeeAmountStart,
            uint256 creatorFeeAmountEnd
        )
    {
        // Check if creator fee engine is on this chain
        if (address(creatorFeeEngine) != address(0)) {
            // Creator fee engine may revert if no creator fees are present.
            try
                creatorFeeEngine.getRoyaltyView(
                    token,
                    tokenId,
                    transactionAmountStart
                )
            returns (
                address payable[] memory creatorFeeRecipients,
                uint256[] memory creatorFeeAmountsStart
            ) {
                if (creatorFeeRecipients.length != 0) {
                    // Use first recipient and amount
                    recipient = creatorFeeRecipients[0];
                    creatorFeeAmountStart = creatorFeeAmountsStart[0];
                }
            } catch {
                // Creator fee not found
            }

            // If fees found for start amount, check end amount
            if (recipient != address(0)) {
                // Creator fee engine may revert if no creator fees are present.
                try
                    creatorFeeEngine.getRoyaltyView(
                        token,
                        tokenId,
                        transactionAmountEnd
                    )
                returns (
                    address payable[] memory,
                    uint256[] memory creatorFeeAmountsEnd
                ) {
                    creatorFeeAmountEnd = creatorFeeAmountsEnd[0];
                } catch {}
            }
        } else {
            // Fallback to ERC2981
            {
                // Static call to token using ERC2981
                (bool success, bytes memory res) = token.staticcall(
                    abi.encodeWithSelector(
                        IERC2981.royaltyInfo.selector,
                        tokenId,
                        transactionAmountStart
                    )
                );
                // Check if call succeeded
                if (success) {
                    // Ensure 64 bytes returned
                    if (res.length == 64) {
                        // Decode result and assign recipient and start amount
                        (recipient, creatorFeeAmountStart) = abi.decode(
                            res,
                            (address, uint256)
                        );
                    }
                }
            }

            // Only check end amount if start amount found
            if (recipient != address(0)) {
                // Static call to token using ERC2981
                (bool success, bytes memory res) = token.staticcall(
                    abi.encodeWithSelector(
                        IERC2981.royaltyInfo.selector,
                        tokenId,
                        transactionAmountEnd
                    )
                );
                // Check if call succeeded
                if (success) {
                    // Ensure 64 bytes returned
                    if (res.length == 64) {
                        // Decode result and assign end amount
                        (, creatorFeeAmountEnd) = abi.decode(
                            res,
                            (address, uint256)
                        );
                    }
                }
            }
        }
    }

    /**
     * @notice Safely check that a contract implements an interface
     * @param token The token address to check
     * @param interfaceHash The interface hash to check
     */
    function checkInterface(
        address token,
        bytes4 interfaceHash
    ) public view returns (bool) {
        return
            token.safeStaticCallBool(
                abi.encodeWithSelector(
                    IERC165.supportsInterface.selector,
                    interfaceHash
                ),
                true
            );
    }

    /*//////////////////////////////////////////////////////////////
                        Merkle Helpers
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice Sorts an array of token ids by the keccak256 hash of the id. Required ordering of ids
     *    for other merkle operations.
     * @param includedTokens An array of included token ids.
     * @return sortedTokens The sorted `includedTokens` array.
     */
    function sortMerkleTokens(
        uint256[] memory includedTokens
    ) public pure returns (uint256[] memory sortedTokens) {
        // Sort token ids by the keccak256 hash of the id
        return _sortUint256ByHash(includedTokens);
    }

    /**
     * @notice Creates a merkle root for includedTokens.
     * @dev `includedTokens` must be sorting in strictly ascending order according to the keccak256 hash of the value.
     * @return merkleRoot The merkle root
     * @return errorsAndWarnings Errors and warnings from the operation
     */
    function getMerkleRoot(
        uint256[] memory includedTokens
    )
        public
        pure
        returns (bytes32 merkleRoot, ErrorsAndWarnings memory errorsAndWarnings)
    {
        (merkleRoot, errorsAndWarnings) = _getRoot(includedTokens);
    }

    /**
     * @notice Creates a merkle proof for the the targetIndex contained in includedTokens.
     * @dev `targetIndex` is referring to the index of an element in `includedTokens`.
     *    `includedTokens` must be sorting in ascending order according to the keccak256 hash of the value.
     * @return merkleProof The merkle proof
     * @return errorsAndWarnings Errors and warnings from the operation
     */
    function getMerkleProof(
        uint256[] memory includedTokens,
        uint256 targetIndex
    )
        public
        pure
        returns (
            bytes32[] memory merkleProof,
            ErrorsAndWarnings memory errorsAndWarnings
        )
    {
        (merkleProof, errorsAndWarnings) = _getProof(
            includedTokens,
            targetIndex
        );
    }

    /**
     * @notice Verifies a merkle proof for the value to prove and given root and proof.
     * @dev The `valueToProve` is hashed prior to executing the proof verification.
     * @param merkleRoot The root of the merkle tree
     * @param merkleProof The merkle proof
     * @param valueToProve The value to prove
     * @return whether proof is valid
     */
    function verifyMerkleProof(
        bytes32 merkleRoot,
        bytes32[] memory merkleProof,
        uint256 valueToProve
    ) public pure returns (bool) {
        bytes32 hashedValue = keccak256(abi.encode(valueToProve));

        return _verifyProof(merkleRoot, merkleProof, hashedValue);
    }

    function isPaymentToken(ItemType itemType) public pure returns (bool) {
        return itemType == ItemType.NATIVE || itemType == ItemType.ERC20;
    }
}

interface CreatorFeeEngineInterface {
    function getRoyaltyView(
        address tokenAddress,
        uint256 tokenId,
        uint256 value
    )
        external
        view
        returns (address payable[] memory recipients, uint256[] memory amounts);
}

File 18 of 53 : ConsiderationTypeHashes.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

import "seaport-types/src/lib/ConsiderationStructs.sol";

uint256 constant EIP712_Order_size = 0x180;
uint256 constant EIP712_OfferItem_size = 0xc0;
uint256 constant EIP712_ConsiderationItem_size = 0xe0;
uint256 constant EIP712_DomainSeparator_offset = 0x02;
uint256 constant EIP712_OrderHash_offset = 0x22;
uint256 constant EIP712_DigestPayload_size = 0x42;
uint256 constant EIP_712_PREFIX = (
    0x1901000000000000000000000000000000000000000000000000000000000000
);

contract ConsiderationTypeHashes {
    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;
    bytes32 internal immutable _DOMAIN_SEPARATOR;
    address internal constant seaportAddress =
        address(0x00000000000006c7676171937C444f6BDe3D6282);

    constructor() {
        // Derive hash of the name of the contract.
        _NAME_HASH = keccak256(bytes("Seaport"));

        // Derive hash of the version string of the contract.
        _VERSION_HASH = keccak256(bytes("1.2"));

        bytes memory offerItemTypeString = abi.encodePacked(
            "OfferItem(",
            "uint8 itemType,",
            "address token,",
            "uint256 identifierOrCriteria,",
            "uint256 startAmount,",
            "uint256 endAmount",
            ")"
        );

        // Construct the ConsiderationItem type string.
        // prettier-ignore
        bytes memory considerationItemTypeString = abi.encodePacked(
            "ConsiderationItem(",
                "uint8 itemType,",
                "address token,",
                "uint256 identifierOrCriteria,",
                "uint256 startAmount,",
                "uint256 endAmount,",
                "address recipient",
            ")"
        );

        // Construct the OrderComponents type string, not including the above.
        // prettier-ignore
        bytes memory orderComponentsPartialTypeString = abi.encodePacked(
            "OrderComponents(",
                "address offerer,",
                "address zone,",
                "OfferItem[] offer,",
                "ConsiderationItem[] consideration,",
                "uint8 orderType,",
                "uint256 startTime,",
                "uint256 endTime,",
                "bytes32 zoneHash,",
                "uint256 salt,",
                "bytes32 conduitKey,",
                "uint256 counter",
            ")"
        );
        // Derive the OfferItem type hash using the corresponding type string.
        bytes32 offerItemTypehash = keccak256(offerItemTypeString);

        // Derive ConsiderationItem type hash using corresponding type string.
        bytes32 considerationItemTypehash = keccak256(
            considerationItemTypeString
        );

        // Construct the primary EIP-712 domain type string.
        // prettier-ignore
        _EIP_712_DOMAIN_TYPEHASH = keccak256(
            abi.encodePacked(
                "EIP712Domain(",
                    "string name,",
                    "string version,",
                    "uint256 chainId,",
                    "address verifyingContract",
                ")"
            )
        );

        _OFFER_ITEM_TYPEHASH = offerItemTypehash;
        _CONSIDERATION_ITEM_TYPEHASH = considerationItemTypehash;

        // Derive OrderItem type hash via combination of relevant type strings.
        _ORDER_TYPEHASH = keccak256(
            abi.encodePacked(
                orderComponentsPartialTypeString,
                considerationItemTypeString,
                offerItemTypeString
            )
        );

        _DOMAIN_SEPARATOR = _deriveDomainSeparator();
    }

    /**
     * @dev Internal view function to derive the EIP-712 domain separator.
     *
     * @return The derived domain separator.
     */
    function _deriveDomainSeparator() internal view returns (bytes32) {
        // prettier-ignore
        return keccak256(
            abi.encode(
                _EIP_712_DOMAIN_TYPEHASH,
                _NAME_HASH,
                _VERSION_HASH,
                block.chainid,
                seaportAddress
            )
        );
    }

    /**
     * @dev Internal pure function to efficiently derive an digest to sign for
     *      an order in accordance with EIP-712.
     *
     * @param orderHash       The order hash.
     *
     * @return value The hash.
     */
    function _deriveEIP712Digest(
        bytes32 orderHash
    ) internal view returns (bytes32 value) {
        bytes32 domainSeparator = _DOMAIN_SEPARATOR;
        // 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)
        }
    }

    /**
     * @dev Internal view function to derive the EIP-712 hash for an offer item.
     *
     * @param offerItem The offered item to hash.
     *
     * @return The hash.
     */
    function _hashOfferItem(
        OfferItem memory offerItem
    ) internal view returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    _OFFER_ITEM_TYPEHASH,
                    offerItem.itemType,
                    offerItem.token,
                    offerItem.identifierOrCriteria,
                    offerItem.startAmount,
                    offerItem.endAmount
                )
            );
    }

    /**
     * @dev Internal view function to derive the EIP-712 hash for a consideration item.
     *
     * @param considerationItem The consideration item to hash.
     *
     * @return The hash.
     */
    function _hashConsiderationItem(
        ConsiderationItem memory considerationItem
    ) internal view returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    _CONSIDERATION_ITEM_TYPEHASH,
                    considerationItem.itemType,
                    considerationItem.token,
                    considerationItem.identifierOrCriteria,
                    considerationItem.startAmount,
                    considerationItem.endAmount,
                    considerationItem.recipient
                )
            );
    }

    /**
     * @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) {
        // Designate new memory regions for offer and consideration item hashes.
        bytes32[] memory offerHashes = new bytes32[](
            orderParameters.offer.length
        );
        bytes32[] memory considerationHashes = new bytes32[](
            orderParameters.totalOriginalConsiderationItems
        );

        // Iterate over each offer on the order.
        for (uint256 i = 0; i < orderParameters.offer.length; ++i) {
            // Hash the offer and place the result into memory.
            offerHashes[i] = _hashOfferItem(orderParameters.offer[i]);
        }

        // Iterate over each consideration on the order.
        for (
            uint256 i = 0;
            i < orderParameters.totalOriginalConsiderationItems;
            ++i
        ) {
            // Hash the consideration and place the result into memory.
            considerationHashes[i] = _hashConsiderationItem(
                orderParameters.consideration[i]
            );
        }

        // Derive and return the order hash as specified by EIP-712.

        return
            keccak256(
                abi.encode(
                    _ORDER_TYPEHASH,
                    orderParameters.offerer,
                    orderParameters.zone,
                    keccak256(abi.encodePacked(offerHashes)),
                    keccak256(abi.encodePacked(considerationHashes)),
                    orderParameters.orderType,
                    orderParameters.startTime,
                    orderParameters.endTime,
                    orderParameters.zoneHash,
                    orderParameters.salt,
                    orderParameters.conduitKey,
                    counter
                )
            );
    }
}

File 19 of 53 : SeaportValidatorInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

import { ItemType } from "seaport-types/src/lib/ConsiderationEnums.sol";
import {
    Order,
    OrderParameters,
    ZoneParameters
} from "seaport-types/src/lib/ConsiderationStructs.sol";
import { ErrorsAndWarnings } from "./ErrorsAndWarnings.sol";
import { ValidationConfiguration } from "./SeaportValidatorTypes.sol";

/**
 * @title SeaportValidator
 * @notice SeaportValidator validates simple orders that adhere to a set of rules defined below:
 *    - The order is either a listing or an offer order (one NFT to buy or one NFT to sell).
 *    - The first consideration is the primary consideration.
 *    - The order pays up to two fees in the fungible token currency. First fee is primary fee, second is creator fee.
 *    - In private orders, the last consideration specifies a recipient for the offer item.
 *    - Offer items must be owned and properly approved by the offerer.
 *    - Consideration items must exist.
 */
interface SeaportValidatorInterface {
    /**
     * @notice Conduct a comprehensive validation of the given order.
     * @param order The order to validate.
     * @return errorsAndWarnings The errors and warnings found in the order.
     */
    function isValidOrder(
        Order calldata order,
        address seaportAddress
    ) external view returns (ErrorsAndWarnings memory errorsAndWarnings);

    /**
     * @notice Same as `isValidOrder` but allows for more configuration related to fee validation.
     */
    function isValidOrderWithConfiguration(
        ValidationConfiguration memory validationConfiguration,
        Order memory order
    ) external view returns (ErrorsAndWarnings memory errorsAndWarnings);

    /**
     * @notice Checks if a conduit key is valid.
     * @param conduitKey The conduit key to check.
     * @return errorsAndWarnings The errors and warnings
     */
    function isValidConduit(
        bytes32 conduitKey,
        address seaportAddress
    ) external view returns (ErrorsAndWarnings memory errorsAndWarnings);

    // TODO: Need to add support for order with extra data
    /**
     * @notice Checks that the zone of an order implements the required interface
     * @param orderParameters The parameters for the order to validate
     * @return errorsAndWarnings An ErrorsAndWarnings structs with results
     */
    function isValidZone(
        OrderParameters memory orderParameters
    ) external view returns (ErrorsAndWarnings memory errorsAndWarnings);

    function validateSignature(
        Order memory order,
        address seaportAddress
    ) external returns (ErrorsAndWarnings memory errorsAndWarnings);

    function validateSignatureWithCounter(
        Order memory order,
        uint256 counter,
        address seaportAddress
    ) external returns (ErrorsAndWarnings memory errorsAndWarnings);

    /**
     * @notice Check the time validity of an order
     * @param orderParameters The parameters for the order to validate
     * @param shortOrderDuration The duration of which an order is considered short
     * @param distantOrderExpiration Distant order expiration delta in seconds.
     * @return errorsAndWarnings The Issues and warnings
     */
    function validateTime(
        OrderParameters memory orderParameters,
        uint256 shortOrderDuration,
        uint256 distantOrderExpiration
    ) external view returns (ErrorsAndWarnings memory errorsAndWarnings);

    /**
     * @notice Validate the status of an order
     * @param orderParameters The parameters for the order to validate
     * @return errorsAndWarnings  The errors and warnings
     */
    function validateOrderStatus(
        OrderParameters memory orderParameters,
        address seaportAddress
    ) external view returns (ErrorsAndWarnings memory errorsAndWarnings);

    /**
     * @notice Validate all offer items for an order
     * @param orderParameters The parameters for the order to validate
     * @return errorsAndWarnings  The errors and warnings
     */
    function validateOfferItems(
        OrderParameters memory orderParameters,
        address seaportAddress
    ) external view returns (ErrorsAndWarnings memory errorsAndWarnings);

    /**
     * @notice Validate all consideration items for an order
     * @param orderParameters The parameters for the order to validate
     * @return errorsAndWarnings  The errors and warnings
     */
    function validateConsiderationItems(
        OrderParameters memory orderParameters,
        address seaportAddress
    ) external view returns (ErrorsAndWarnings memory errorsAndWarnings);

    /**
     * @notice Strict validation operates under tight assumptions. It validates primary
     *    fee, creator fee, private sale consideration, and overall order format.
     * @dev Only checks first fee recipient provided by CreatorFeeRegistry.
     *    Order of consideration items must be as follows:
     *    1. Primary consideration
     *    2. Primary fee
     *    3. Creator Fee
     *    4. Private sale consideration
     * @param orderParameters The parameters for the order to validate.
     * @param primaryFeeRecipient The primary fee recipient. Set to null address for no primary fee.
     * @param primaryFeeBips The primary fee in BIPs.
     * @param checkCreatorFee Should check for creator fee. If true, creator fee must be present as
     *    according to creator fee engine. If false, must not have creator fee.
     * @return errorsAndWarnings The errors and warnings.
     */
    function validateStrictLogic(
        OrderParameters memory orderParameters,
        address primaryFeeRecipient,
        uint256 primaryFeeBips,
        bool checkCreatorFee
    ) external view returns (ErrorsAndWarnings memory errorsAndWarnings);

    /**
     * @notice Validate a consideration item
     * @param orderParameters The parameters for the order to validate
     * @param considerationItemIndex The index of the consideration item to validate
     * @return errorsAndWarnings  The errors and warnings
     */
    function validateConsiderationItem(
        OrderParameters memory orderParameters,
        uint256 considerationItemIndex,
        address seaportAddress
    ) external view returns (ErrorsAndWarnings memory errorsAndWarnings);

    /**
     * @notice Validates the parameters of a consideration item including contract validation
     * @param orderParameters The parameters for the order to validate
     * @param considerationItemIndex The index of the consideration item to validate
     * @return errorsAndWarnings  The errors and warnings
     */
    function validateConsiderationItemParameters(
        OrderParameters memory orderParameters,
        uint256 considerationItemIndex,
        address seaportAddress
    ) external view returns (ErrorsAndWarnings memory errorsAndWarnings);

    /**
     * @notice Validates an offer item
     * @param orderParameters The parameters for the order to validate
     * @param offerItemIndex The index of the offerItem in offer array to validate
     * @return errorsAndWarnings An ErrorsAndWarnings structs with results
     */
    function validateOfferItem(
        OrderParameters memory orderParameters,
        uint256 offerItemIndex,
        address seaportAddress
    ) external view returns (ErrorsAndWarnings memory errorsAndWarnings);

    /**
     * @notice Validates the OfferItem parameters. This includes token contract validation
     * @dev OfferItems with criteria are currently not allowed
     * @param orderParameters The parameters for the order to validate
     * @param offerItemIndex The index of the offerItem in offer array to validate
     * @return errorsAndWarnings An ErrorsAndWarnings structs with results
     */
    function validateOfferItemParameters(
        OrderParameters memory orderParameters,
        uint256 offerItemIndex,
        address seaportAddress
    ) external view returns (ErrorsAndWarnings memory errorsAndWarnings);

    /**
     * @notice Validates the OfferItem approvals and balances
     * @param orderParameters The parameters for the order to validate
     * @param offerItemIndex The index of the offerItem in offer array to validate
     * @return errorsAndWarnings An ErrorsAndWarnings structs with results
     */
    function validateOfferItemApprovalAndBalance(
        OrderParameters memory orderParameters,
        uint256 offerItemIndex,
        address seaportAddress
    ) external view returns (ErrorsAndWarnings memory errorsAndWarnings);

    /**
     * @notice Calls validateOrder on the order's zone with the given zoneParameters
     * @param orderParameters The parameters for the order to validate
     * @param zoneParameters The parameters for the zone to validate
     * @return errorsAndWarnings An ErrorsAndWarnings structs with results
     */
    function validateOrderWithZone(
        OrderParameters memory orderParameters,
        ZoneParameters memory zoneParameters
    ) external view returns (ErrorsAndWarnings memory errorsAndWarnings);

    /**
     * @notice Gets the approval address for the given conduit key
     * @param conduitKey Conduit key to get approval address for
     * @return errorsAndWarnings An ErrorsAndWarnings structs with results
     */
    function getApprovalAddress(
        bytes32 conduitKey,
        address seaportAddress
    )
        external
        view
        returns (address, ErrorsAndWarnings memory errorsAndWarnings);

    /**
     * @notice Safely check that a contract implements an interface
     * @param token The token address to check
     * @param interfaceHash The interface hash to check
     */
    function checkInterface(
        address token,
        bytes4 interfaceHash
    ) external view returns (bool);

    function isPaymentToken(ItemType itemType) external pure returns (bool);

    /*//////////////////////////////////////////////////////////////
                        Merkle Helpers
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice Sorts an array of token ids by the keccak256 hash of the id. Required ordering of ids
     *    for other merkle operations.
     * @param includedTokens An array of included token ids.
     * @return sortedTokens The sorted `includedTokens` array.
     */
    function sortMerkleTokens(
        uint256[] memory includedTokens
    ) external view returns (uint256[] memory sortedTokens);

    /**
     * @notice Creates a merkle root for includedTokens.
     * @dev `includedTokens` must be sorting in strictly ascending order according to the keccak256 hash of the value.
     * @return merkleRoot The merkle root
     * @return errorsAndWarnings Errors and warnings from the operation
     */
    function getMerkleRoot(
        uint256[] memory includedTokens
    )
        external
        view
        returns (
            bytes32 merkleRoot,
            ErrorsAndWarnings memory errorsAndWarnings
        );

    /**
     * @notice Creates a merkle proof for the the targetIndex contained in includedTokens.
     * @dev `targetIndex` is referring to the index of an element in `includedTokens`.
     *    `includedTokens` must be sorting in ascending order according to the keccak256 hash of the value.
     * @return merkleProof The merkle proof
     * @return errorsAndWarnings Errors and warnings from the operation
     */
    function getMerkleProof(
        uint256[] memory includedTokens,
        uint256 targetIndex
    )
        external
        view
        returns (
            bytes32[] memory merkleProof,
            ErrorsAndWarnings memory errorsAndWarnings
        );

    function verifyMerkleProof(
        bytes32 merkleRoot,
        bytes32[] memory merkleProof,
        uint256 valueToProve
    ) external view returns (bool);
}

File 20 of 53 : ErrorsAndWarnings.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

import {
    ConduitIssue,
    ConsiderationIssue,
    ERC20Issue,
    ERC721Issue,
    ERC1155Issue,
    GenericIssue,
    OfferIssue,
    SignatureIssue,
    StatusIssue,
    TimeIssue,
    NativeIssue,
    IssueParser
} from "./SeaportValidatorTypes.sol";

struct ErrorsAndWarnings {
    uint16[] errors;
    uint16[] warnings;
}

library ErrorsAndWarningsLib {
    using IssueParser for ConduitIssue;
    using IssueParser for ConsiderationIssue;
    using IssueParser for ERC20Issue;
    using IssueParser for ERC721Issue;
    using IssueParser for ERC1155Issue;
    using IssueParser for GenericIssue;
    using IssueParser for OfferIssue;
    using IssueParser for SignatureIssue;
    using IssueParser for StatusIssue;
    using IssueParser for TimeIssue;
    using IssueParser for NativeIssue;

    function concat(
        ErrorsAndWarnings memory ew1,
        ErrorsAndWarnings memory ew2
    ) internal pure {
        ew1.errors = concatMemory(ew1.errors, ew2.errors);
        ew1.warnings = concatMemory(ew1.warnings, ew2.warnings);
    }

    function empty() internal pure returns (ErrorsAndWarnings memory) {
        return ErrorsAndWarnings(new uint16[](0), new uint16[](0));
    }

    function addError(
        uint16 err
    ) internal pure returns (ErrorsAndWarnings memory) {
        ErrorsAndWarnings memory ew = ErrorsAndWarnings(
            new uint16[](0),
            new uint16[](0)
        );
        ew.errors = pushMemory(ew.errors, err);
        return ew;
    }

    function addError(
        ErrorsAndWarnings memory ew,
        uint16 err
    ) internal pure returns (ErrorsAndWarnings memory) {
        ew.errors = pushMemory(ew.errors, err);
        return ew;
    }

    function addError(
        ErrorsAndWarnings memory ew,
        GenericIssue err
    ) internal pure returns (ErrorsAndWarnings memory) {
        return addError(ew, err.parseInt());
    }

    function addError(
        ErrorsAndWarnings memory ew,
        ERC20Issue err
    ) internal pure returns (ErrorsAndWarnings memory) {
        return addError(ew, err.parseInt());
    }

    function addError(
        ErrorsAndWarnings memory ew,
        ERC721Issue err
    ) internal pure returns (ErrorsAndWarnings memory) {
        return addError(ew, err.parseInt());
    }

    function addError(
        ErrorsAndWarnings memory ew,
        ERC1155Issue err
    ) internal pure returns (ErrorsAndWarnings memory) {
        return addError(ew, err.parseInt());
    }

    function addError(
        ErrorsAndWarnings memory ew,
        ConsiderationIssue err
    ) internal pure returns (ErrorsAndWarnings memory) {
        return addError(ew, err.parseInt());
    }

    function addError(
        ErrorsAndWarnings memory ew,
        OfferIssue err
    ) internal pure returns (ErrorsAndWarnings memory) {
        return addError(ew, err.parseInt());
    }

    function addError(
        ErrorsAndWarnings memory ew,
        SignatureIssue err
    ) internal pure returns (ErrorsAndWarnings memory) {
        return addError(ew, err.parseInt());
    }

    function addError(
        ErrorsAndWarnings memory ew,
        TimeIssue err
    ) internal pure returns (ErrorsAndWarnings memory) {
        return addError(ew, err.parseInt());
    }

    function addError(
        ErrorsAndWarnings memory ew,
        ConduitIssue err
    ) internal pure returns (ErrorsAndWarnings memory) {
        return addError(ew, err.parseInt());
    }

    function addError(
        ErrorsAndWarnings memory ew,
        StatusIssue err
    ) internal pure returns (ErrorsAndWarnings memory) {
        return addError(ew, err.parseInt());
    }

    function addWarning(
        uint16 warn
    ) internal pure returns (ErrorsAndWarnings memory) {
        ErrorsAndWarnings memory ew = ErrorsAndWarnings(
            new uint16[](0),
            new uint16[](0)
        );
        ew.warnings = pushMemory(ew.warnings, warn);
        return ew;
    }

    function addWarning(
        ErrorsAndWarnings memory ew,
        uint16 warn
    ) internal pure returns (ErrorsAndWarnings memory) {
        ew.warnings = pushMemory(ew.warnings, warn);
        return ew;
    }

    function addWarning(
        ErrorsAndWarnings memory ew,
        GenericIssue warn
    ) internal pure returns (ErrorsAndWarnings memory) {
        return addWarning(ew, warn.parseInt());
    }

    function addWarning(
        ErrorsAndWarnings memory ew,
        ERC20Issue warn
    ) internal pure returns (ErrorsAndWarnings memory) {
        return addWarning(ew, warn.parseInt());
    }

    function addWarning(
        ErrorsAndWarnings memory ew,
        ERC721Issue warn
    ) internal pure returns (ErrorsAndWarnings memory) {
        return addWarning(ew, warn.parseInt());
    }

    function addWarning(
        ErrorsAndWarnings memory ew,
        ERC1155Issue warn
    ) internal pure returns (ErrorsAndWarnings memory) {
        return addWarning(ew, warn.parseInt());
    }

    function addWarning(
        ErrorsAndWarnings memory ew,
        OfferIssue warn
    ) internal pure returns (ErrorsAndWarnings memory) {
        return addWarning(ew, warn.parseInt());
    }

    function addWarning(
        ErrorsAndWarnings memory ew,
        ConsiderationIssue warn
    ) internal pure returns (ErrorsAndWarnings memory) {
        return addWarning(ew, warn.parseInt());
    }

    function addWarning(
        ErrorsAndWarnings memory ew,
        SignatureIssue warn
    ) internal pure returns (ErrorsAndWarnings memory) {
        return addWarning(ew, warn.parseInt());
    }

    function addWarning(
        ErrorsAndWarnings memory ew,
        TimeIssue warn
    ) internal pure returns (ErrorsAndWarnings memory) {
        return addWarning(ew, warn.parseInt());
    }

    function addWarning(
        ErrorsAndWarnings memory ew,
        ConduitIssue warn
    ) internal pure returns (ErrorsAndWarnings memory) {
        return addWarning(ew, warn.parseInt());
    }

    function addWarning(
        ErrorsAndWarnings memory ew,
        StatusIssue warn
    ) internal pure returns (ErrorsAndWarnings memory) {
        return addWarning(ew, warn.parseInt());
    }

    function addWarning(
        ErrorsAndWarnings memory ew,
        NativeIssue warn
    ) internal pure returns (ErrorsAndWarnings memory) {
        return addWarning(ew, warn.parseInt());
    }

    function hasErrors(
        ErrorsAndWarnings memory ew
    ) internal pure returns (bool) {
        return ew.errors.length != 0;
    }

    function hasWarnings(
        ErrorsAndWarnings memory ew
    ) internal pure returns (bool) {
        return ew.warnings.length != 0;
    }

    // Helper Functions
    function concatMemory(
        uint16[] memory array1,
        uint16[] memory array2
    ) private pure returns (uint16[] memory) {
        if (array1.length == 0) {
            return array2;
        } else if (array2.length == 0) {
            return array1;
        }

        uint16[] memory returnValue = new uint16[](
            array1.length + array2.length
        );

        for (uint256 i = 0; i < array1.length; i++) {
            returnValue[i] = array1[i];
        }
        for (uint256 i = 0; i < array2.length; i++) {
            returnValue[i + array1.length] = array2[i];
        }

        return returnValue;
    }

    function pushMemory(
        uint16[] memory uint16Array,
        uint16 newValue
    ) internal pure returns (uint16[] memory) {
        uint16[] memory returnValue = new uint16[](uint16Array.length + 1);

        for (uint256 i = 0; i < uint16Array.length; i++) {
            returnValue[i] = uint16Array[i];
        }
        returnValue[uint16Array.length] = newValue;

        return returnValue;
    }
}

File 21 of 53 : SafeStaticCall.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

library SafeStaticCall {
    function safeStaticCallBool(
        address target,
        bytes memory callData,
        bool expectedReturn
    ) internal view returns (bool) {
        (bool success, bytes memory res) = target.staticcall(callData);
        if (!success) return false;
        if (res.length != 32) return false;

        if (
            bytes32(res) &
                0x0000000000000000000000000000000000000000000000000000000000000001 !=
            bytes32(res)
        ) {
            return false;
        }

        return expectedReturn ? res[31] == 0x01 : res[31] == 0;
    }

    function safeStaticCallAddress(
        address target,
        bytes memory callData,
        address expectedReturn
    ) internal view returns (bool) {
        (bool success, bytes memory res) = target.staticcall(callData);
        if (!success) return false;
        if (res.length != 32) return false;

        if (
            bytes32(res) &
                0x000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF !=
            bytes32(res)
        ) {
            // Ensure only 20 bytes used
            return false;
        }

        return abi.decode(res, (address)) == expectedReturn;
    }

    function safeStaticCallUint256(
        address target,
        bytes memory callData,
        uint256 minExpectedReturn
    ) internal view returns (bool) {
        (bool success, bytes memory res) = target.staticcall(callData);
        if (!success) return false;
        if (res.length != 32) return false;

        return abi.decode(res, (uint256)) >= minExpectedReturn;
    }

    function safeStaticCallBytes4(
        address target,
        bytes memory callData,
        bytes4 expectedReturn
    ) internal view returns (bool) {
        (bool success, bytes memory res) = target.staticcall(callData);
        if (!success) return false;
        if (res.length != 32) return false;
        if (
            bytes32(res) &
                0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 !=
            bytes32(res)
        ) {
            // Ensure only 4 bytes used
            return false;
        }

        return abi.decode(res, (bytes4)) == expectedReturn;
    }
}

File 22 of 53 : Murky.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

import {
    ErrorsAndWarnings,
    ErrorsAndWarningsLib
} from "./ErrorsAndWarnings.sol";

import { IssueParser, MerkleIssue } from "./SeaportValidatorTypes.sol";

contract Murky {
    using ErrorsAndWarningsLib for ErrorsAndWarnings;
    using IssueParser for MerkleIssue;

    bool internal constant HASH_ODD_WITH_ZERO = false;

    function _verifyProof(
        bytes32 root,
        bytes32[] memory proof,
        bytes32 valueToProve
    ) internal pure returns (bool) {
        // proof length must be less than max array size
        bytes32 rollingHash = valueToProve;
        uint256 length = proof.length;
        unchecked {
            for (uint256 i = 0; i < length; ++i) {
                rollingHash = _hashLeafPairs(rollingHash, proof[i]);
            }
        }
        return root == rollingHash;
    }

    /********************
     * HASHING FUNCTION *
     ********************/

    /// ascending sort and concat prior to hashing
    function _hashLeafPairs(
        bytes32 left,
        bytes32 right
    ) internal pure returns (bytes32 _hash) {
        assembly {
            switch lt(left, right)
            case 0 {
                mstore(0x0, right)
                mstore(0x20, left)
            }
            default {
                mstore(0x0, left)
                mstore(0x20, right)
            }
            _hash := keccak256(0x0, 0x40)
        }
    }

    /********************
     * PROOF GENERATION *
     ********************/

    function _getRoot(
        uint256[] memory data
    )
        internal
        pure
        returns (bytes32 result, ErrorsAndWarnings memory errorsAndWarnings)
    {
        errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0));

        if (data.length < 2) {
            errorsAndWarnings.addError(MerkleIssue.SingleLeaf.parseInt());
            return (0, errorsAndWarnings);
        }

        bool hashOddWithZero = HASH_ODD_WITH_ZERO;

        if (!_processInput(data)) {
            errorsAndWarnings.addError(MerkleIssue.Unsorted.parseInt());
            return (0, errorsAndWarnings);
        }

        assembly {
            function hashLeafPairs(left, right) -> _hash {
                switch lt(left, right)
                case 0 {
                    mstore(0x0, right)
                    mstore(0x20, left)
                }
                default {
                    mstore(0x0, left)
                    mstore(0x20, right)
                }
                _hash := keccak256(0x0, 0x40)
            }
            function hashLevel(_data, length, _hashOddWithZero) -> newLength {
                // we will be modifying data in-place, so set result pointer to data pointer
                let _result := _data
                // get length of original data array
                // let length := mload(_data)
                // bool to track if we need to hash the last element of an odd-length array with zero
                let oddLength

                // if length is odd, we need to hash the last element with zero
                switch and(length, 1)
                case 1 {
                    // if length is odd, add 1 so division by 2 will round up
                    newLength := add(1, div(length, 2))
                    oddLength := 1
                }
                default {
                    newLength := div(length, 2)
                }
                // todo: necessary?
                // mstore(_data, newLength)
                let resultIndexPointer := add(0x20, _data)
                let dataIndexPointer := resultIndexPointer

                // stop iterating over for loop at length-1
                let stopIteration := add(_data, mul(length, 0x20))
                // write result array in-place over data array
                for {

                } lt(dataIndexPointer, stopIteration) {

                } {
                    // get next two elements from data, hash them together
                    let data1 := mload(dataIndexPointer)
                    let data2 := mload(add(dataIndexPointer, 0x20))
                    let hashedPair := hashLeafPairs(data1, data2)
                    // overwrite an element of data array with
                    mstore(resultIndexPointer, hashedPair)
                    // increment result pointer by 1 slot
                    resultIndexPointer := add(0x20, resultIndexPointer)
                    // increment data pointer by 2 slot
                    dataIndexPointer := add(0x40, dataIndexPointer)
                }
                // we did not yet hash last index if odd-length
                if oddLength {
                    let data1 := mload(dataIndexPointer)
                    let nextValue
                    switch _hashOddWithZero
                    case 0 {
                        nextValue := data1
                    }
                    default {
                        nextValue := hashLeafPairs(data1, 0)
                    }
                    mstore(resultIndexPointer, nextValue)
                }
            }

            let dataLength := mload(data)
            for {

            } gt(dataLength, 1) {

            } {
                dataLength := hashLevel(data, dataLength, hashOddWithZero)
            }
            result := mload(add(0x20, data))
        }
    }

    function _getProof(
        uint256[] memory data,
        uint256 node
    )
        internal
        pure
        returns (
            bytes32[] memory result,
            ErrorsAndWarnings memory errorsAndWarnings
        )
    {
        errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0));

        if (data.length < 2) {
            errorsAndWarnings.addError(MerkleIssue.SingleLeaf.parseInt());
            return (new bytes32[](0), errorsAndWarnings);
        }

        bool hashOddWithZero = HASH_ODD_WITH_ZERO;

        if (!_processInput(data)) {
            errorsAndWarnings.addError(MerkleIssue.Unsorted.parseInt());
            return (new bytes32[](0), errorsAndWarnings);
        }

        // The size of the proof is equal to the ceiling of log2(numLeaves)
        // Two overflow risks: node, pos
        // node: max array size is 2**256-1. Largest index in the array will be 1 less than that. Also,
        // for dynamic arrays, size is limited to 2**64-1
        // pos: pos is bounded by log2(data.length), which should be less than type(uint256).max
        assembly {
            function hashLeafPairs(left, right) -> _hash {
                switch lt(left, right)
                case 0 {
                    mstore(0x0, right)
                    mstore(0x20, left)
                }
                default {
                    mstore(0x0, left)
                    mstore(0x20, right)
                }
                _hash := keccak256(0x0, 0x40)
            }
            function hashLevel(_data, length, _hashOddWithZero) -> newLength {
                // we will be modifying data in-place, so set result pointer to data pointer
                let _result := _data
                // get length of original data array
                // let length := mload(_data)
                // bool to track if we need to hash the last element of an odd-length array with zero
                let oddLength

                // if length is odd, we'll need to hash the last element with zero
                switch and(length, 1)
                case 1 {
                    // if length is odd, add 1 so division by 2 will round up
                    newLength := add(1, div(length, 2))
                    oddLength := 1
                }
                default {
                    newLength := div(length, 2)
                }
                // todo: necessary?
                // mstore(_data, newLength)
                let resultIndexPointer := add(0x20, _data)
                let dataIndexPointer := resultIndexPointer

                // stop iterating over for loop at length-1
                let stopIteration := add(_data, mul(length, 0x20))
                // write result array in-place over data array
                for {

                } lt(dataIndexPointer, stopIteration) {

                } {
                    // get next two elements from data, hash them together
                    let data1 := mload(dataIndexPointer)
                    let data2 := mload(add(dataIndexPointer, 0x20))
                    let hashedPair := hashLeafPairs(data1, data2)
                    // overwrite an element of data array with
                    mstore(resultIndexPointer, hashedPair)
                    // increment result pointer by 1 slot
                    resultIndexPointer := add(0x20, resultIndexPointer)
                    // increment data pointer by 2 slot
                    dataIndexPointer := add(0x40, dataIndexPointer)
                }
                // we did not yet hash last index if odd-length
                if oddLength {
                    let data1 := mload(dataIndexPointer)
                    let nextValue
                    switch _hashOddWithZero
                    case 0 {
                        nextValue := data1
                    }
                    default {
                        nextValue := hashLeafPairs(data1, 0)
                    }
                    mstore(resultIndexPointer, nextValue)
                }
            }

            // set result pointer to free memory
            result := mload(0x40)
            // get pointer to first index of result
            let resultIndexPtr := add(0x20, result)
            // declare so we can use later
            let newLength
            // put length of data onto stack
            let dataLength := mload(data)
            for {
                // repeat until only one element is left
            } gt(dataLength, 1) {

            } {
                // bool if node is odd
                let oddNodeIndex := and(node, 1)
                // bool if node is last
                let lastNodeIndex := eq(dataLength, add(1, node))
                // store both bools in one value so we can switch on it
                let switchVal := or(shl(1, lastNodeIndex), oddNodeIndex)
                switch switchVal
                // 00 - neither odd nor last
                case 0 {
                    // store data[node+1] at result[i]
                    // get pointer to result[node+1] by adding 2 to node and multiplying by 0x20
                    // to account for the fact that result points to array length, not first index
                    mstore(
                        resultIndexPtr,
                        mload(add(data, mul(0x20, add(2, node))))
                    )
                }
                // 10 - node is last
                case 2 {
                    // store 0 at result[i]
                    mstore(resultIndexPtr, 0)
                }
                // 01 or 11 - node is odd (and possibly also last)
                default {
                    // store data[node-1] at result[i]
                    mstore(resultIndexPtr, mload(add(data, mul(0x20, node))))
                }
                // increment result index
                resultIndexPtr := add(0x20, resultIndexPtr)

                // get new node index
                node := div(node, 2)
                // keep track of how long result array is
                newLength := add(1, newLength)
                // compute the next hash level, overwriting data, and get the new length
                dataLength := hashLevel(data, dataLength, hashOddWithZero)
            }
            // store length of result array at pointer
            mstore(result, newLength)
            // set free mem pointer to word after end of result array
            mstore(0x40, resultIndexPtr)
        }
    }

    /**
     * Hashes each element of the input array in place using keccak256
     */
    function _processInput(
        uint256[] memory data
    ) private pure returns (bool sorted) {
        sorted = true;

        // Hash inputs with keccak256
        for (uint256 i = 0; i < data.length; ++i) {
            assembly {
                mstore(
                    add(data, mul(0x20, add(1, i))),
                    keccak256(add(data, mul(0x20, add(1, i))), 0x20)
                )
                // for every element after the first, hashed value must be greater than the last one
                if and(
                    gt(i, 0),
                    iszero(
                        gt(
                            mload(add(data, mul(0x20, add(1, i)))),
                            mload(add(data, mul(0x20, add(1, sub(i, 1)))))
                        )
                    )
                ) {
                    sorted := 0 // Elements not ordered by hash
                }
            }
        }
    }

    // Sort uint256 in order of the keccak256 hashes
    struct HashAndIntTuple {
        uint256 num;
        bytes32 hash;
    }

    function _sortUint256ByHash(
        uint256[] memory values
    ) internal pure returns (uint256[] memory sortedValues) {
        HashAndIntTuple[] memory toSort = new HashAndIntTuple[](values.length);
        for (uint256 i = 0; i < values.length; i++) {
            toSort[i] = HashAndIntTuple(
                values[i],
                keccak256(abi.encode(values[i]))
            );
        }

        _quickSort(toSort, 0, int256(toSort.length - 1));

        sortedValues = new uint256[](values.length);
        for (uint256 i = 0; i < values.length; i++) {
            sortedValues[i] = toSort[i].num;
        }
    }

    function _quickSort(
        HashAndIntTuple[] memory arr,
        int256 left,
        int256 right
    ) internal pure {
        int256 i = left;
        int256 j = right;
        if (i == j) return;
        bytes32 pivot = arr[uint256(left + (right - left) / 2)].hash;
        while (i <= j) {
            while (arr[uint256(i)].hash < pivot) i++;
            while (pivot < arr[uint256(j)].hash) j--;
            if (i <= j) {
                (arr[uint256(i)], arr[uint256(j)]) = (
                    arr[uint256(j)],
                    arr[uint256(i)]
                );
                i++;
                j--;
            }
        }
        if (left < j) _quickSort(arr, left, j);
        if (i < right) _quickSort(arr, i, right);
    }
}

File 23 of 53 : SeaportValidatorTypes.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;

struct ValidationConfiguration {
    /// @notice The seaport address.
    address seaport;
    /// @notice Recipient for primary fee payments.
    address primaryFeeRecipient;
    /// @notice Bips for primary fee payments.
    uint256 primaryFeeBips;
    /// @notice Should creator fees be checked?
    bool checkCreatorFee;
    /// @notice Should strict validation be skipped?
    bool skipStrictValidation;
    /// @notice Short order duration in seconds
    uint256 shortOrderDuration;
    /// @notice Distant order expiration delta in seconds. Warning if order expires in longer than this.
    uint256 distantOrderExpiration;
}

struct ConsiderationItemConfiguration {
    address primaryFeeRecipient;
    uint256 primaryFeeBips;
    bool checkCreatorFee;
}

enum GenericIssue {
    InvalidOrderFormat // 100
}

enum ERC20Issue {
    IdentifierNonZero, // 200
    InvalidToken, // 201
    InsufficientAllowance, // 202
    InsufficientBalance // 203
}

enum ERC721Issue {
    AmountNotOne, // 300
    InvalidToken, // 301
    IdentifierDNE, // 302
    NotOwner, // 303
    NotApproved, // 304
    CriteriaNotPartialFill // 305
}

enum ERC1155Issue {
    InvalidToken, // 400
    NotApproved, // 401
    InsufficientBalance // 402
}

enum ConsiderationIssue {
    AmountZero, // 500
    NullRecipient, // 501
    ExtraItems, // 502
    PrivateSaleToSelf, // 503
    ZeroItems, // 504
    DuplicateItem, // 505
    OffererNotReceivingAtLeastOneItem, // 506
    PrivateSale, // 507
    AmountVelocityHigh, // 508
    AmountStepLarge // 509
}

enum OfferIssue {
    ZeroItems, // 600
    AmountZero, // 601
    MoreThanOneItem, // 602
    NativeItem, // 603
    DuplicateItem, // 604
    AmountVelocityHigh, // 605
    AmountStepLarge // 606
}

enum PrimaryFeeIssue {
    Missing, // 700
    ItemType, // 701
    Token, // 702
    StartAmount, // 703
    EndAmount, // 704
    Recipient // 705
}

enum StatusIssue {
    Cancelled, // 800
    FullyFilled, // 801
    ContractOrder // 802
}

enum TimeIssue {
    EndTimeBeforeStartTime, // 900
    Expired, // 901
    DistantExpiration, // 902
    NotActive, // 903
    ShortOrder // 904
}

enum ConduitIssue {
    KeyInvalid, // 1000
    MissingSeaportChannel // 1001
}

enum SignatureIssue {
    Invalid, // 1100
    ContractOrder, // 1101
    LowCounter, // 1102
    HighCounter, // 1103
    OriginalConsiderationItems // 1104
}

enum CreatorFeeIssue {
    Missing, // 1200
    ItemType, // 1201
    Token, // 1202
    StartAmount, // 1203
    EndAmount, // 1204
    Recipient // 1205
}

enum NativeIssue {
    TokenAddress, // 1300
    IdentifierNonZero, // 1301
    InsufficientBalance // 1302
}

enum ZoneIssue {
    InvalidZone, // 1400
    RejectedOrder, // 1401
    NotSet, // 1402
    EOAZone // 1403
}

enum MerkleIssue {
    SingleLeaf, // 1500
    Unsorted // 1501
}

enum ContractOffererIssue {
    InvalidContractOfferer // 1600
}

/**
 * @title IssueParser - parse issues into integers
 * @notice Implements a `parseInt` function for each issue type.
 *    offsets the enum value to place within the issue range.
 */
library IssueParser {
    function parseInt(GenericIssue err) internal pure returns (uint16) {
        return uint16(err) + 100;
    }

    function parseInt(ERC20Issue err) internal pure returns (uint16) {
        return uint16(err) + 200;
    }

    function parseInt(ERC721Issue err) internal pure returns (uint16) {
        return uint16(err) + 300;
    }

    function parseInt(ERC1155Issue err) internal pure returns (uint16) {
        return uint16(err) + 400;
    }

    function parseInt(ConsiderationIssue err) internal pure returns (uint16) {
        return uint16(err) + 500;
    }

    function parseInt(OfferIssue err) internal pure returns (uint16) {
        return uint16(err) + 600;
    }

    function parseInt(PrimaryFeeIssue err) internal pure returns (uint16) {
        return uint16(err) + 700;
    }

    function parseInt(StatusIssue err) internal pure returns (uint16) {
        return uint16(err) + 800;
    }

    function parseInt(TimeIssue err) internal pure returns (uint16) {
        return uint16(err) + 900;
    }

    function parseInt(ConduitIssue err) internal pure returns (uint16) {
        return uint16(err) + 1000;
    }

    function parseInt(SignatureIssue err) internal pure returns (uint16) {
        return uint16(err) + 1100;
    }

    function parseInt(CreatorFeeIssue err) internal pure returns (uint16) {
        return uint16(err) + 1200;
    }

    function parseInt(NativeIssue err) internal pure returns (uint16) {
        return uint16(err) + 1300;
    }

    function parseInt(ZoneIssue err) internal pure returns (uint16) {
        return uint16(err) + 1400;
    }

    function parseInt(MerkleIssue err) internal pure returns (uint16) {
        return uint16(err) + 1500;
    }

    function parseInt(ContractOffererIssue err) internal pure returns (uint16) {
        return uint16(err) + 1600;
    }
}

library IssueStringHelpers {
    function toString(GenericIssue id) internal pure returns (string memory) {
        string memory code;
        if (id == GenericIssue.InvalidOrderFormat) {
            code = "InvalidOrderFormat";
        }
        return string.concat("GenericIssue: ", code);
    }

    function toString(ERC20Issue id) internal pure returns (string memory) {
        string memory code;
        if (id == ERC20Issue.IdentifierNonZero) {
            code = "IdentifierNonZero";
        } else if (id == ERC20Issue.InvalidToken) {
            code = "InvalidToken";
        } else if (id == ERC20Issue.InsufficientAllowance) {
            code = "InsufficientAllowance";
        } else if (id == ERC20Issue.InsufficientBalance) {
            code = "InsufficientBalance";
        }
        return string.concat("ERC20Issue: ", code);
    }

    function toString(ERC721Issue id) internal pure returns (string memory) {
        string memory code;
        if (id == ERC721Issue.AmountNotOne) {
            code = "AmountNotOne";
        } else if (id == ERC721Issue.InvalidToken) {
            code = "InvalidToken";
        } else if (id == ERC721Issue.IdentifierDNE) {
            code = "IdentifierDNE";
        } else if (id == ERC721Issue.NotOwner) {
            code = "NotOwner";
        } else if (id == ERC721Issue.NotApproved) {
            code = "NotApproved";
        } else if (id == ERC721Issue.CriteriaNotPartialFill) {
            code = "CriteriaNotPartialFill";
        }
        return string.concat("ERC721Issue: ", code);
    }

    function toString(ERC1155Issue id) internal pure returns (string memory) {
        string memory code;
        if (id == ERC1155Issue.InvalidToken) {
            code = "InvalidToken";
        } else if (id == ERC1155Issue.NotApproved) {
            code = "NotApproved";
        } else if (id == ERC1155Issue.InsufficientBalance) {
            code = "InsufficientBalance";
        }
        return string.concat("ERC1155Issue: ", code);
    }

    function toString(
        ConsiderationIssue id
    ) internal pure returns (string memory) {
        string memory code;
        if (id == ConsiderationIssue.AmountZero) {
            code = "AmountZero";
        } else if (id == ConsiderationIssue.NullRecipient) {
            code = "NullRecipient";
        } else if (id == ConsiderationIssue.ExtraItems) {
            code = "ExtraItems";
        } else if (id == ConsiderationIssue.PrivateSaleToSelf) {
            code = "PrivateSaleToSelf";
        } else if (id == ConsiderationIssue.ZeroItems) {
            code = "ZeroItems";
        } else if (id == ConsiderationIssue.DuplicateItem) {
            code = "DuplicateItem";
        } else if (id == ConsiderationIssue.OffererNotReceivingAtLeastOneItem) {
            code = "OffererNotReceivingAtLeastOneItem";
        } else if (id == ConsiderationIssue.PrivateSale) {
            code = "PrivateSale";
        } else if (id == ConsiderationIssue.AmountVelocityHigh) {
            code = "AmountVelocityHigh";
        } else if (id == ConsiderationIssue.AmountStepLarge) {
            code = "AmountStepLarge";
        }
        return string.concat("ConsiderationIssue: ", code);
    }

    function toString(OfferIssue id) internal pure returns (string memory) {
        string memory code;
        if (id == OfferIssue.ZeroItems) {
            code = "ZeroItems";
        } else if (id == OfferIssue.AmountZero) {
            code = "AmountZero";
        } else if (id == OfferIssue.MoreThanOneItem) {
            code = "MoreThanOneItem";
        } else if (id == OfferIssue.NativeItem) {
            code = "NativeItem";
        } else if (id == OfferIssue.DuplicateItem) {
            code = "DuplicateItem";
        } else if (id == OfferIssue.AmountVelocityHigh) {
            code = "AmountVelocityHigh";
        } else if (id == OfferIssue.AmountStepLarge) {
            code = "AmountStepLarge";
        }
        return string.concat("OfferIssue: ", code);
    }

    function toString(
        PrimaryFeeIssue id
    ) internal pure returns (string memory) {
        string memory code;
        if (id == PrimaryFeeIssue.Missing) {
            code = "Missing";
        } else if (id == PrimaryFeeIssue.ItemType) {
            code = "ItemType";
        } else if (id == PrimaryFeeIssue.Token) {
            code = "Token";
        } else if (id == PrimaryFeeIssue.StartAmount) {
            code = "StartAmount";
        } else if (id == PrimaryFeeIssue.EndAmount) {
            code = "EndAmount";
        } else if (id == PrimaryFeeIssue.Recipient) {
            code = "Recipient";
        }
        return string.concat("PrimaryFeeIssue: ", code);
    }

    function toString(StatusIssue id) internal pure returns (string memory) {
        string memory code;
        if (id == StatusIssue.Cancelled) {
            code = "Cancelled";
        } else if (id == StatusIssue.FullyFilled) {
            code = "FullyFilled";
        } else if (id == StatusIssue.ContractOrder) {
            code = "ContractOrder";
        }
        return string.concat("StatusIssue: ", code);
    }

    function toString(TimeIssue id) internal pure returns (string memory) {
        string memory code;
        if (id == TimeIssue.EndTimeBeforeStartTime) {
            code = "EndTimeBeforeStartTime";
        } else if (id == TimeIssue.Expired) {
            code = "Expired";
        } else if (id == TimeIssue.DistantExpiration) {
            code = "DistantExpiration";
        } else if (id == TimeIssue.NotActive) {
            code = "NotActive";
        } else if (id == TimeIssue.ShortOrder) {
            code = "ShortOrder";
        }
        return string.concat("TimeIssue: ", code);
    }

    function toString(ConduitIssue id) internal pure returns (string memory) {
        string memory code;
        if (id == ConduitIssue.KeyInvalid) {
            code = "KeyInvalid";
        } else if (id == ConduitIssue.MissingSeaportChannel) {
            code = "MissingSeaportChannel";
        }
        return string.concat("ConduitIssue: ", code);
    }

    function toString(SignatureIssue id) internal pure returns (string memory) {
        string memory code;
        if (id == SignatureIssue.Invalid) {
            code = "Invalid";
        } else if (id == SignatureIssue.ContractOrder) {
            code = "ContractOrder";
        } else if (id == SignatureIssue.LowCounter) {
            code = "LowCounter";
        } else if (id == SignatureIssue.HighCounter) {
            code = "HighCounter";
        } else if (id == SignatureIssue.OriginalConsiderationItems) {
            code = "OriginalConsiderationItems";
        }
        return string.concat("SignatureIssue: ", code);
    }

    function toString(
        CreatorFeeIssue id
    ) internal pure returns (string memory) {
        string memory code;
        if (id == CreatorFeeIssue.Missing) {
            code = "Missing";
        } else if (id == CreatorFeeIssue.ItemType) {
            code = "ItemType";
        } else if (id == CreatorFeeIssue.Token) {
            code = "Token";
        } else if (id == CreatorFeeIssue.StartAmount) {
            code = "StartAmount";
        } else if (id == CreatorFeeIssue.EndAmount) {
            code = "EndAmount";
        } else if (id == CreatorFeeIssue.Recipient) {
            code = "Recipient";
        }
        return string.concat("CreatorFeeIssue: ", code);
    }

    function toString(NativeIssue id) internal pure returns (string memory) {
        string memory code;
        if (id == NativeIssue.TokenAddress) {
            code = "TokenAddress";
        } else if (id == NativeIssue.IdentifierNonZero) {
            code = "IdentifierNonZero";
        } else if (id == NativeIssue.InsufficientBalance) {
            code = "InsufficientBalance";
        }
        return string.concat("NativeIssue: ", code);
    }

    function toString(ZoneIssue id) internal pure returns (string memory) {
        string memory code;
        if (id == ZoneIssue.InvalidZone) {
            code = "InvalidZone";
        } else if (id == ZoneIssue.RejectedOrder) {
            code = "RejectedOrder";
        } else if (id == ZoneIssue.NotSet) {
            code = "NotSet";
        } else if (id == ZoneIssue.EOAZone) {
            code = "EOAZone";
        }
        return string.concat("ZoneIssue: ", code);
    }

    function toString(MerkleIssue id) internal pure returns (string memory) {
        string memory code;
        if (id == MerkleIssue.SingleLeaf) {
            code = "SingleLeaf";
        } else if (id == MerkleIssue.Unsorted) {
            code = "Unsorted";
        }
        return string.concat("MerkleIssue: ", code);
    }

    function toString(
        ContractOffererIssue id
    ) internal pure returns (string memory) {
        string memory code;
        if (id == ContractOffererIssue.InvalidContractOfferer) {
            code = "InvalidContractOfferer";
        }
        return string.concat("ContractOffererIssue: ", code);
    }

    function toIssueString(
        uint16 issueCode
    ) internal pure returns (string memory issueString) {
        uint16 issue = (issueCode / 100) * 100;
        uint8 id = uint8(issueCode % 100);
        if (issue == 100) {
            return toString(GenericIssue(id));
        } else if (issue == 200) {
            return toString(ERC20Issue(id));
        } else if (issue == 300) {
            return toString(ERC721Issue(id));
        } else if (issue == 400) {
            return toString(ERC1155Issue(id));
        } else if (issue == 500) {
            return toString(ConsiderationIssue(id));
        } else if (issue == 600) {
            return toString(OfferIssue(id));
        } else if (issue == 700) {
            return toString(PrimaryFeeIssue(id));
        } else if (issue == 800) {
            return toString(StatusIssue(id));
        } else if (issue == 900) {
            return toString(TimeIssue(id));
        } else if (issue == 1000) {
            return toString(ConduitIssue(id));
        } else if (issue == 1100) {
            return toString(SignatureIssue(id));
        } else if (issue == 1200) {
            return toString(CreatorFeeIssue(id));
        } else if (issue == 1300) {
            return toString(NativeIssue(id));
        } else if (issue == 1400) {
            return toString(ZoneIssue(id));
        } else if (issue == 1500) {
            return toString(MerkleIssue(id));
        } else if (issue == 1600) {
            return toString(ContractOffererIssue(id));
        } else {
            revert("IssueStringHelpers: Unknown issue code");
        }
    }

    function toIssueString(
        uint16[] memory issueCodes
    ) internal pure returns (string memory issueString) {
        for (uint256 i; i < issueCodes.length; i++) {
            issueString = string.concat(
                issueString,
                "\n    ",
                toIssueString(issueCodes[i])
            );
        }
    }
}

File 24 of 53 : ContractOffererInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import {ReceivedItem, Schema, SpentItem} from "../lib/ConsiderationStructs.sol";
import {IERC165} from "../interfaces/IERC165.sol";

/**
 * @title ContractOffererInterface
 * @notice Contains the minimum interfaces needed to interact with a contract
 *         offerer.
 */
interface ContractOffererInterface is IERC165 {
    /**
     * @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

    function supportsInterface(bytes4 interfaceId) external view override returns (bool);

    // Additional functions and/or events based on implemented schemaIDs
}

File 25 of 53 : GettersAndDerivers.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {OrderParameters} from "seaport-types/src/lib/ConsiderationStructs.sol";

import {ConsiderationBase} from "./ConsiderationBase.sol";

import {
    Create2AddressDerivation_length,
    Create2AddressDerivation_ptr,
    EIP_712_PREFIX,
    EIP712_ConsiderationItem_size,
    EIP712_DigestPayload_size,
    EIP712_DomainSeparator_offset,
    EIP712_OfferItem_size,
    EIP712_Order_size,
    EIP712_OrderHash_offset,
    FreeMemoryPointerSlot,
    information_conduitController_offset,
    information_domainSeparator_offset,
    information_length,
    information_version_cd_offset,
    information_version_offset,
    information_versionLengthPtr,
    information_versionWithLength,
    MaskOverByteTwelve,
    MaskOverLastTwentyBytes,
    OneWord,
    OneWordShift,
    OrderParameters_consideration_head_offset,
    OrderParameters_counter_offset,
    OrderParameters_offer_head_offset,
    TwoWords
} from "seaport-types/src/lib/ConsiderationConstants.sol";

/**
 * @title GettersAndDerivers
 * @author 0age
 * @notice ConsiderationInternal contains pure and internal view functions
 *         related to getting or deriving various values.
 */
contract GettersAndDerivers is ConsiderationBase {
    /**
     * @dev Derive and set hashes, reference chainId, and associated domain
     *      separator during deployment.
     *
     * @param conduitController A contract that deploys conduits, or proxies
     *                          that may optionally be used to transfer approved
     *                          ERC20/721/1155 tokens.
     */
    constructor(address conduitController) ConsiderationBase(conduitController) {}

    /**
     * @dev Internal view function to derive the order hash for a given order.
     *      Note that only the original consideration items are included in the
     *      order hash, as additional consideration items may be supplied by the
     *      caller.
     *
     * @param orderParameters The parameters of the order to hash.
     * @param counter         The counter of the order to hash.
     *
     * @return orderHash The hash.
     */
    function _deriveOrderHash(OrderParameters memory orderParameters, uint256 counter)
        internal
        view
        returns (bytes32 orderHash)
    {
        // Get length of original consideration array and place it on the stack.
        uint256 originalConsiderationLength = (orderParameters.totalOriginalConsiderationItems);

        /*
         * Memory layout for an array of structs (dynamic or not) is similar
         * to ABI encoding of dynamic types, with a head segment followed by
         * a data segment. The main difference is that the head of an element
         * is a memory pointer rather than an offset.
         */

        // Declare a variable for the derived hash of the offer array.
        bytes32 offerHash;

        // Read offer item EIP-712 typehash from runtime code & place on stack.
        bytes32 typeHash = _OFFER_ITEM_TYPEHASH;

        // Utilize assembly so that memory regions can be reused across hashes.
        assembly {
            // Retrieve the free memory pointer and place on the stack.
            let hashArrPtr := mload(FreeMemoryPointerSlot)

            // Get the pointer to the offers array.
            let offerArrPtr := mload(add(orderParameters, OrderParameters_offer_head_offset))

            // Load the length.
            let offerLength := mload(offerArrPtr)

            // Set the pointer to the first offer's head.
            offerArrPtr := add(offerArrPtr, OneWord)

            // Iterate over the offer items.
            for { let i := 0 } lt(i, offerLength) { i := add(i, 1) } {
                // Read the pointer to the offer data and subtract one word
                // to get typeHash pointer.
                let ptr := sub(mload(offerArrPtr), OneWord)

                // Read the current value before the offer data.
                let value := mload(ptr)

                // Write the type hash to the previous word.
                mstore(ptr, typeHash)

                // Take the EIP712 hash and store it in the hash array.
                mstore(hashArrPtr, keccak256(ptr, EIP712_OfferItem_size))

                // Restore the previous word.
                mstore(ptr, value)

                // Increment the array pointers by one word.
                offerArrPtr := add(offerArrPtr, OneWord)
                hashArrPtr := add(hashArrPtr, OneWord)
            }

            // Derive the offer hash using the hashes of each item.
            offerHash := keccak256(mload(FreeMemoryPointerSlot), shl(OneWordShift, offerLength))
        }

        // Declare a variable for the derived hash of the consideration array.
        bytes32 considerationHash;

        // Read consideration item typehash from runtime code & place on stack.
        typeHash = _CONSIDERATION_ITEM_TYPEHASH;

        // Utilize assembly so that memory regions can be reused across hashes.
        assembly {
            // Retrieve the free memory pointer and place on the stack.
            let hashArrPtr := mload(FreeMemoryPointerSlot)

            // Get the pointer to the consideration array.
            let considerationArrPtr :=
                add(mload(add(orderParameters, OrderParameters_consideration_head_offset)), OneWord)

            // Iterate over the consideration items (not including tips).
            for { let i := 0 } lt(i, originalConsiderationLength) { i := add(i, 1) } {
                // Read the pointer to the consideration data and subtract one
                // word to get typeHash pointer.
                let ptr := sub(mload(considerationArrPtr), OneWord)

                // Read the current value before the consideration data.
                let value := mload(ptr)

                // Write the type hash to the previous word.
                mstore(ptr, typeHash)

                // Take the EIP712 hash and store it in the hash array.
                mstore(hashArrPtr, keccak256(ptr, EIP712_ConsiderationItem_size))

                // Restore the previous word.
                mstore(ptr, value)

                // Increment the array pointers by one word.
                considerationArrPtr := add(considerationArrPtr, OneWord)
                hashArrPtr := add(hashArrPtr, OneWord)
            }

            // Derive the consideration hash using the hashes of each item.
            considerationHash := keccak256(mload(FreeMemoryPointerSlot), shl(OneWordShift, originalConsiderationLength))
        }

        // Read order item EIP-712 typehash from runtime code & place on stack.
        typeHash = _ORDER_TYPEHASH;

        // Utilize assembly to access derived hashes & other arguments directly.
        assembly {
            // Retrieve pointer to the region located just behind parameters.
            let typeHashPtr := sub(orderParameters, OneWord)

            // Store the value at that pointer location to restore later.
            let previousValue := mload(typeHashPtr)

            // Store the order item EIP-712 typehash at the typehash location.
            mstore(typeHashPtr, typeHash)

            // Retrieve the pointer for the offer array head.
            let offerHeadPtr := add(orderParameters, OrderParameters_offer_head_offset)

            // Retrieve the data pointer referenced by the offer head.
            let offerDataPtr := mload(offerHeadPtr)

            // Store the offer hash at the retrieved memory location.
            mstore(offerHeadPtr, offerHash)

            // Retrieve the pointer for the consideration array head.
            let considerationHeadPtr := add(orderParameters, OrderParameters_consideration_head_offset)

            // Retrieve the data pointer referenced by the consideration head.
            let considerationDataPtr := mload(considerationHeadPtr)

            // Store the consideration hash at the retrieved memory location.
            mstore(considerationHeadPtr, considerationHash)

            // Retrieve the pointer for the counter.
            let counterPtr := add(orderParameters, OrderParameters_counter_offset)

            // Store the counter at the retrieved memory location.
            mstore(counterPtr, counter)

            // Derive the order hash using the full range of order parameters.
            orderHash := keccak256(typeHashPtr, EIP712_Order_size)

            // Restore the value previously held at typehash pointer location.
            mstore(typeHashPtr, previousValue)

            // Restore offer data pointer at the offer head pointer location.
            mstore(offerHeadPtr, offerDataPtr)

            // Restore consideration data pointer at the consideration head ptr.
            mstore(considerationHeadPtr, considerationDataPtr)

            // Restore consideration item length at the counter pointer.
            mstore(counterPtr, originalConsiderationLength)
        }
    }

    /**
     * @dev Internal view function to derive the address of a given conduit
     *      using a corresponding conduit key.
     *
     * @param conduitKey A bytes32 value indicating what corresponding conduit,
     *                   if any, to source token approvals from. This value is
     *                   the "salt" parameter supplied by the deployer (i.e. the
     *                   conduit controller) when deploying the given conduit.
     *
     * @return conduit The address of the conduit associated with the given
     *                 conduit key.
     */
    function _deriveConduit(bytes32 conduitKey) internal view returns (address conduit) {
        // Read conduit controller address from runtime and place on the stack.
        address conduitController = address(_CONDUIT_CONTROLLER);

        // Read conduit creation code hash from runtime and place on the stack.
        bytes32 conduitCreationCodeHash = _CONDUIT_CREATION_CODE_HASH;

        // Leverage scratch space to perform an efficient hash.
        assembly {
            // Retrieve the free memory pointer; it will be replaced afterwards.
            let freeMemoryPointer := mload(FreeMemoryPointerSlot)

            // Place the control character and the conduit controller in scratch
            // space; note that eleven bytes at the beginning are left unused.
            mstore(0, or(MaskOverByteTwelve, conduitController))

            // Place the conduit key in the next region of scratch space.
            mstore(OneWord, conduitKey)

            // Place conduit creation code hash in free memory pointer location.
            mstore(TwoWords, conduitCreationCodeHash)

            // Derive conduit by hashing and applying a mask over last 20 bytes.
            conduit :=
                and(
                    // Hash the relevant region.
                    keccak256(
                        // The region starts at memory pointer 11.
                        Create2AddressDerivation_ptr,
                        // The region is 85 bytes long (1 + 20 + 32 + 32).
                        Create2AddressDerivation_length
                    ),
                    // The address equals the last twenty bytes of the hash.
                    MaskOverLastTwentyBytes
                )

            // Restore the free memory pointer.
            mstore(FreeMemoryPointerSlot, freeMemoryPointer)
        }
    }

    /**
     * @dev Internal view function to get the EIP-712 domain separator. If the
     *      chainId matches the chainId set on deployment, the cached domain
     *      separator will be returned; otherwise, it will be derived from
     *      scratch.
     *
     * @return The domain separator.
     */
    function _domainSeparator() internal view returns (bytes32) {
        return block.chainid == _CHAIN_ID ? _DOMAIN_SEPARATOR : _deriveDomainSeparator();
    }

    /**
     * @dev Internal view function to retrieve configuration information for
     *      this contract.
     *
     * @return The contract version.
     * @return The domain separator for this contract.
     * @return The conduit Controller set for this contract.
     */
    function _information()
        internal
        view
        returns (string memory, /* version */ bytes32, /* domainSeparator */ address /* conduitController */ )
    {
        // Derive the domain separator.
        bytes32 domainSeparator = _domainSeparator();

        // Declare variable as immutables cannot be accessed within assembly.
        address conduitController = address(_CONDUIT_CONTROLLER);

        // Return the version, domain separator, and conduit controller.
        assembly {
            mstore(information_version_offset, information_version_cd_offset)
            mstore(information_domainSeparator_offset, domainSeparator)
            mstore(information_conduitController_offset, conduitController)
            mstore(information_versionLengthPtr, information_versionWithLength)
            return(information_version_offset, information_length)
        }
    }

    /**
     * @dev Internal pure function to efficiently derive an digest to sign for
     *      an order in accordance with EIP-712.
     *
     * @param domainSeparator The domain separator.
     * @param orderHash       The order hash.
     *
     * @return value The hash.
     */
    function _deriveEIP712Digest(bytes32 domainSeparator, bytes32 orderHash) internal pure returns (bytes32 value) {
        // Leverage scratch space to perform an efficient hash.
        assembly {
            // Place the EIP-712 prefix at the start of scratch space.
            mstore(0, EIP_712_PREFIX)

            // Place the domain separator in the next region of scratch space.
            mstore(EIP712_DomainSeparator_offset, domainSeparator)

            // Place the order hash in scratch space, spilling into the first
            // two bytes of the free memory pointer — this should never be set
            // as memory cannot be expanded to that size, and will be zeroed out
            // after the hash is performed.
            mstore(EIP712_OrderHash_offset, orderHash)

            // Hash the relevant region (65 bytes).
            value := keccak256(0, EIP712_DigestPayload_size)

            // Clear out the dirtied bits in the memory pointer.
            mstore(EIP712_OrderHash_offset, 0)
        }
    }
}

File 26 of 53 : ZoneInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import {ZoneParameters, Schema} from "../lib/ConsiderationStructs.sol";

import {IERC165} from "./IERC165.sol";

/**
 * @title  ZoneInterface
 * @notice Contains functions exposed by a zone.
 */
interface ZoneInterface is IERC165 {
    /**
     * @dev 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

    function supportsInterface(bytes4 interfaceId) external view override returns (bool);
}

File 27 of 53 : ConsiderationInterface.sol
// 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.5
 * @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);
}

File 28 of 53 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol)

pragma solidity ^0.8.0;

import "../utils/introspection/IERC165.sol";

File 29 of 53 : IERC2981.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC2981.sol)

pragma solidity ^0.8.0;

import "../utils/introspection/IERC165.sol";

/**
 * @dev Interface for the NFT Royalty Standard.
 *
 * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal
 * support for royalty payments across all NFT marketplaces and ecosystem participants.
 *
 * _Available since v4.5._
 */
interface IERC2981 is IERC165 {
    /**
     * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of
     * exchange. The royalty amount is denominated and should be paid in that same unit of exchange.
     */
    function royaltyInfo(
        uint256 tokenId,
        uint256 salePrice
    ) external view returns (address receiver, uint256 royaltyAmount);
}

File 30 of 53 : Verifiers.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {OrderStatus} from "seaport-types/src/lib/ConsiderationStructs.sol";

import {Assertions} from "./Assertions.sol";

import {SignatureVerification} from "./SignatureVerification.sol";

import {
    _revertInvalidTime,
    _revertOrderAlreadyFilled,
    _revertOrderIsCancelled,
    _revertOrderPartiallyFilled
} from "seaport-types/src/lib/ConsiderationErrors.sol";

import {
    BulkOrderProof_keyShift,
    BulkOrderProof_keySize,
    BulkOrderProof_lengthAdjustmentBeforeMask,
    BulkOrderProof_lengthRangeAfterMask,
    BulkOrderProof_minSize,
    BulkOrderProof_rangeSize,
    ECDSA_MaxLength,
    OneWord,
    OneWordShift,
    ThirtyOneBytes,
    TwoWords
} from "seaport-types/src/lib/ConsiderationConstants.sol";

/**
 * @title Verifiers
 * @author 0age
 * @notice Verifiers contains functions for performing verifications.
 */
contract Verifiers is Assertions, SignatureVerification {
    /**
     * @dev Derive and set hashes, reference chainId, and associated domain
     *      separator during deployment.
     *
     * @param conduitController A contract that deploys conduits, or proxies
     *                          that may optionally be used to transfer approved
     *                          ERC20/721/1155 tokens.
     */
    constructor(address conduitController) Assertions(conduitController) {}

    /**
     * @dev Internal view function to ensure that the current time falls within
     *      an order's valid timespan.
     *
     * @param startTime       The time at which the order becomes active.
     * @param endTime         The time at which the order becomes inactive.
     * @param revertOnInvalid A boolean indicating whether to revert if the
     *                        order is not active.
     *
     * @return valid A boolean indicating whether the order is active.
     */
    function _verifyTime(uint256 startTime, uint256 endTime, bool revertOnInvalid) internal view returns (bool valid) {
        // Mark as valid if order has started and has not already ended.
        assembly {
            valid := and(iszero(gt(startTime, timestamp())), gt(endTime, timestamp()))
        }

        // Only revert on invalid if revertOnInvalid has been supplied as true.
        if (revertOnInvalid && !valid) {
            _revertInvalidTime(startTime, endTime);
        }
    }

    /**
     * @dev Internal view function to verify the signature of an order. An
     *      ERC-1271 fallback will be attempted if either the signature length
     *      is not 64 or 65 bytes or if the recovered signer does not match the
     *      supplied offerer. Note that in cases where a 64 or 65 byte signature
     *      is supplied, only standard ECDSA signatures that recover to a
     *      non-zero address are supported.
     *
     * @param offerer   The offerer for the order.
     * @param orderHash The order hash.
     * @param signature A signature from the offerer indicating that the order
     *                  has been approved.
     */
    function _verifySignature(address offerer, bytes32 orderHash, bytes memory signature) internal view {
        // Determine whether the offerer is the caller.
        bool offererIsCaller;
        assembly {
            offererIsCaller := eq(offerer, caller())
        }

        // Skip signature verification if the offerer is the caller.
        if (offererIsCaller) {
            return;
        }

        // Derive the EIP-712 domain separator.
        bytes32 domainSeparator = _domainSeparator();

        // Derive original EIP-712 digest using domain separator and order hash.
        bytes32 originalDigest = _deriveEIP712Digest(domainSeparator, orderHash);

        // Read the length of the signature from memory and place on the stack.
        uint256 originalSignatureLength = signature.length;

        // Determine effective digest if signature has a valid bulk order size.
        bytes32 digest;
        if (_isValidBulkOrderSize(originalSignatureLength)) {
            // Rederive order hash and digest using bulk order proof.
            (orderHash) = _computeBulkOrderProof(signature, orderHash);
            digest = _deriveEIP712Digest(domainSeparator, orderHash);
        } else {
            // Supply the original digest as the effective digest.
            digest = originalDigest;
        }

        // Ensure that the signature for the digest is valid for the offerer.
        _assertValidSignature(offerer, digest, originalDigest, originalSignatureLength, signature);
    }

    /**
     * @dev Determines whether the specified bulk order size is valid.
     *
     * @param signatureLength The signature length of the bulk order to check.
     *
     * @return validLength True if bulk order size is valid, false otherwise.
     */
    function _isValidBulkOrderSize(uint256 signatureLength) internal pure returns (bool validLength) {
        // Utilize assembly to validate the length; the equivalent logic is
        // (64 + x) + 3 + 32y where (0 <= x <= 1) and (1 <= y <= 24).
        assembly {
            validLength :=
                and(
                    lt(sub(signatureLength, BulkOrderProof_minSize), BulkOrderProof_rangeSize),
                    lt(
                        and(add(signatureLength, BulkOrderProof_lengthAdjustmentBeforeMask), ThirtyOneBytes),
                        BulkOrderProof_lengthRangeAfterMask
                    )
                )
        }
    }

    /**
     * @dev Computes the bulk order hash for the specified proof and leaf. Note
     *      that if an index that exceeds the number of orders in the bulk order
     *      payload will instead "wrap around" and refer to an earlier index.
     *
     * @param proofAndSignature The proof and signature of the bulk order.
     * @param leaf              The leaf of the bulk order tree.
     *
     * @return bulkOrderHash The bulk order hash.
     */
    function _computeBulkOrderProof(bytes memory proofAndSignature, bytes32 leaf)
        internal
        pure
        returns (bytes32 bulkOrderHash)
    {
        // Declare arguments for the root hash and the height of the proof.
        bytes32 root;
        uint256 height;

        // Utilize assembly to efficiently derive the root hash using the proof.
        assembly {
            // Retrieve the length of the proof, key, and signature combined.
            let fullLength := mload(proofAndSignature)

            // If proofAndSignature has odd length, it is a compact signature
            // with 64 bytes.
            let signatureLength := sub(ECDSA_MaxLength, and(fullLength, 1))

            // Derive height (or depth of tree) with signature and proof length.
            height := shr(OneWordShift, sub(fullLength, signatureLength))

            // Update the length in memory to only include the signature.
            mstore(proofAndSignature, signatureLength)

            // Derive the pointer for the key using the signature length.
            let keyPtr := add(proofAndSignature, add(OneWord, signatureLength))

            // Retrieve the three-byte key using the derived pointer.
            let key := shr(BulkOrderProof_keyShift, mload(keyPtr))

            /// Retrieve pointer to first proof element by applying a constant
            // for the key size to the derived key pointer.
            let proof := add(keyPtr, BulkOrderProof_keySize)

            // Compute level 1.
            let scratchPtr1 := shl(OneWordShift, and(key, 1))
            mstore(scratchPtr1, leaf)
            mstore(xor(scratchPtr1, OneWord), mload(proof))

            // Compute remaining proofs.
            for { let i := 1 } lt(i, height) { i := add(i, 1) } {
                proof := add(proof, OneWord)
                let scratchPtr := shl(OneWordShift, and(shr(i, key), 1))
                mstore(scratchPtr, keccak256(0, TwoWords))
                mstore(xor(scratchPtr, OneWord), mload(proof))
            }

            // Compute root hash.
            root := keccak256(0, TwoWords)
        }

        // Retrieve appropriate typehash constant based on height.
        bytes32 rootTypeHash = _lookupBulkOrderTypehash(height);

        // Use the typehash and the root hash to derive final bulk order hash.
        assembly {
            mstore(0, rootTypeHash)
            mstore(OneWord, root)
            bulkOrderHash := keccak256(0, TwoWords)
        }
    }

    /**
     * @dev Internal view function to validate that a given order is fillable
     *      and not cancelled based on the order status.
     *
     * @param orderHash       The order hash.
     * @param orderStatus     The status of the order, including whether it has
     *                        been cancelled and the fraction filled.
     * @param onlyAllowUnused A boolean flag indicating whether partial fills
     *                        are supported by the calling function.
     * @param revertOnInvalid A boolean indicating whether to revert if the
     *                        order has been cancelled or filled beyond the
     *                        allowable amount.
     *
     * @return valid A boolean indicating whether the order is valid.
     */
    function _verifyOrderStatus(
        bytes32 orderHash,
        OrderStatus storage orderStatus,
        bool onlyAllowUnused,
        bool revertOnInvalid
    ) internal view returns (bool valid) {
        // Ensure that the order has not been cancelled.
        if (orderStatus.isCancelled) {
            // Only revert if revertOnInvalid has been supplied as true.
            if (revertOnInvalid) {
                _revertOrderIsCancelled(orderHash);
            }

            // Return false as the order status is invalid.
            return false;
        }

        // Read order status numerator from storage and place on stack.
        uint256 orderStatusNumerator = orderStatus.numerator;

        // If the order is not entirely unused...
        if (orderStatusNumerator != 0) {
            // ensure the order has not been partially filled when not allowed.
            if (onlyAllowUnused) {
                // Always revert on partial fills when onlyAllowUnused is true.
                _revertOrderPartiallyFilled(orderHash);
            }
            // Otherwise, ensure that order has not been entirely filled.
            else if (orderStatusNumerator >= orderStatus.denominator) {
                // Only revert if revertOnInvalid has been supplied as true.
                if (revertOnInvalid) {
                    _revertOrderAlreadyFilled(orderHash);
                }

                // Return false as the order status is invalid.
                return false;
            }
        }

        // Return true as the order status is valid.
        valid = true;
    }
}

File 31 of 53 : AbridgedTokenInterfaces.sol
// 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 balance of a user.
     *
     * @param account The address of the user.
     *
     * @return balance The balance of the user.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Returns the amount which spender is still allowed to withdraw
     *      from owner.
     *
     * @param owner   The address of the owner.
     * @param spender The address of the spender.
     *
     * @return remaining The amount of tokens that the spender is allowed to
     *                   transfer on behalf of the owner.
     */
    function allowance(address owner, address spender) external view returns (uint256 remaining);
}

/**
 * @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 account approved for tokenId token
     *
     * @param tokenId The tokenId to query the approval of.
     *
     * @return operator The approved account of the tokenId.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns whether an operator is allowed to manage all of
     *      the assets of owner.
     *
     * @param owner    The address of the owner.
     * @param operator The address of the operator.
     *
     * @return approved True if the operator is approved by the owner.
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);

    /**
     * @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 amount of token type id owned by account.
     *
     * @param account The address of the account.
     * @param id      The id of the token.
     *
     * @return balance The amount of tokens of type id owned by account.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev Returns true if operator is approved to transfer account's tokens.
     *
     * @param account  The address of the account.
     * @param operator The address of the operator.
     *
     * @return approved True if the operator is approved to transfer account's
     *                  tokens.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);
}

File 32 of 53 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.7;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 33 of 53 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 34 of 53 : SignatureVerification.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {SignatureVerificationErrors} from "seaport-types/src/interfaces/SignatureVerificationErrors.sol";

import {LowLevelHelpers} from "./LowLevelHelpers.sol";

import {
    ECDSA_MaxLength,
    ECDSA_signature_s_offset,
    ECDSA_signature_v_offset,
    ECDSA_twentySeventhAndTwentyEighthBytesSet,
    Ecrecover_args_size,
    Ecrecover_precompile,
    EIP1271_isValidSignature_calldata_baseLength,
    EIP1271_isValidSignature_digest_negativeOffset,
    EIP1271_isValidSignature_selector_negativeOffset,
    EIP1271_isValidSignature_selector,
    EIP1271_isValidSignature_signature_head_offset,
    EIP2098_allButHighestBitMask,
    MaxUint8,
    OneWord,
    Signature_lower_v
} from "seaport-types/src/lib/ConsiderationConstants.sol";

import {
    BadContractSignature_error_length,
    BadContractSignature_error_selector,
    BadSignatureV_error_length,
    BadSignatureV_error_selector,
    BadSignatureV_error_v_ptr,
    Error_selector_offset,
    InvalidSignature_error_length,
    InvalidSignature_error_selector,
    InvalidSigner_error_length,
    InvalidSigner_error_selector
} from "seaport-types/src/lib/ConsiderationErrorConstants.sol";

/**
 * @title SignatureVerification
 * @author 0age
 * @notice SignatureVerification contains logic for verifying signatures.
 */
contract SignatureVerification is SignatureVerificationErrors, LowLevelHelpers {
    /**
     * @dev Internal view function to verify the signature of an order. An
     *      ERC-1271 fallback will be attempted if either the signature length
     *      is not 64 or 65 bytes or if the recovered signer does not match the
     *      supplied signer.
     *
     * @param signer                  The signer for the order.
     * @param digest                  The digest to verify signature against.
     * @param originalDigest          The original digest to verify signature
     *                                against.
     * @param originalSignatureLength The original signature length.
     * @param signature               A signature from the signer indicating
     *                                that the order has been approved.
     */
    function _assertValidSignature(
        address signer,
        bytes32 digest,
        bytes32 originalDigest,
        uint256 originalSignatureLength,
        bytes memory signature
    ) internal view {
        // Declare value for ecrecover equality or 1271 call success status.
        bool success;

        // Utilize assembly to perform optimized signature verification check.
        assembly {
            // Ensure that first word of scratch space is empty.
            mstore(0, 0)

            // Get the length of the signature.
            let signatureLength := mload(signature)

            // Get the pointer to the value preceding the signature length.
            // This will be used for temporary memory overrides - either the
            // signature head for isValidSignature or the digest for ecrecover.
            let wordBeforeSignaturePtr := sub(signature, OneWord)

            // Cache the current value behind the signature to restore it later.
            let cachedWordBeforeSignature := mload(wordBeforeSignaturePtr)

            // Declare lenDiff + recoveredSigner scope to manage stack pressure.
            {
                // Take the difference between the max ECDSA signature length
                // and the actual signature length. Overflow desired for any
                // values > 65. If the diff is not 0 or 1, it is not a valid
                // ECDSA signature - move on to EIP1271 check.
                let lenDiff := sub(ECDSA_MaxLength, signatureLength)

                // Declare variable for recovered signer.
                let recoveredSigner

                // If diff is 0 or 1, it may be an ECDSA signature.
                // Try to recover signer.
                if iszero(gt(lenDiff, 1)) {
                    // Read the signature `s` value.
                    let originalSignatureS := mload(add(signature, ECDSA_signature_s_offset))

                    // Read the first byte of the word after `s`. If the
                    // signature is 65 bytes, this will be the real `v` value.
                    // If not, it will need to be modified - doing it this way
                    // saves an extra condition.
                    let v := byte(0, mload(add(signature, ECDSA_signature_v_offset)))

                    // If lenDiff is 1, parse 64-byte signature as ECDSA.
                    if lenDiff {
                        // Extract yParity from highest bit of vs and add 27 to
                        // get v.
                        v := add(shr(MaxUint8, originalSignatureS), Signature_lower_v)

                        // Extract canonical s from vs, all but the highest bit.
                        // Temporarily overwrite the original `s` value in the
                        // signature.
                        mstore(
                            add(signature, ECDSA_signature_s_offset),
                            and(originalSignatureS, EIP2098_allButHighestBitMask)
                        )
                    }
                    // Temporarily overwrite the signature length with `v` to
                    // conform to the expected input for ecrecover.
                    mstore(signature, v)

                    // Temporarily overwrite the word before the length with
                    // `digest` to conform to the expected input for ecrecover.
                    mstore(wordBeforeSignaturePtr, digest)

                    // Attempt to recover the signer for the given signature. Do
                    // not check the call status as ecrecover will return a null
                    // address if the signature is invalid.
                    pop(
                        staticcall(
                            gas(),
                            Ecrecover_precompile, // Call ecrecover precompile.
                            wordBeforeSignaturePtr, // Use data memory location.
                            Ecrecover_args_size, // Size of digest, v, r, and s.
                            0, // Write result to scratch space.
                            OneWord // Provide size of returned result.
                        )
                    )

                    // Restore cached word before signature.
                    mstore(wordBeforeSignaturePtr, cachedWordBeforeSignature)

                    // Restore cached signature length.
                    mstore(signature, signatureLength)

                    // Restore cached signature `s` value.
                    mstore(add(signature, ECDSA_signature_s_offset), originalSignatureS)

                    // Read the recovered signer from the buffer given as return
                    // space for ecrecover.
                    recoveredSigner := mload(0)
                }

                // Set success to true if the signature provided was a valid
                // ECDSA signature and the signer is not the null address. Use
                // gt instead of direct as success is used outside of assembly.
                success := and(eq(signer, recoveredSigner), gt(signer, 0))
            }

            // If the signature was not verified with ecrecover, try EIP1271.
            if iszero(success) {
                // Reset the original signature length.
                mstore(signature, originalSignatureLength)

                // Temporarily overwrite the word before the signature length
                // and use it as the head of the signature input to
                // `isValidSignature`, which has a value of 64.
                mstore(wordBeforeSignaturePtr, EIP1271_isValidSignature_signature_head_offset)

                // Get pointer to use for the selector of `isValidSignature`.
                let selectorPtr := sub(signature, EIP1271_isValidSignature_selector_negativeOffset)

                // Cache the value currently stored at the selector pointer.
                let cachedWordOverwrittenBySelector := mload(selectorPtr)

                // Cache the value currently stored at the digest pointer.
                let cachedWordOverwrittenByDigest :=
                    mload(sub(signature, EIP1271_isValidSignature_digest_negativeOffset))

                // Write the selector first, since it overlaps the digest.
                mstore(selectorPtr, EIP1271_isValidSignature_selector)

                // Next, write the original digest.
                mstore(sub(signature, EIP1271_isValidSignature_digest_negativeOffset), originalDigest)

                // Call signer with `isValidSignature` to validate signature.
                success :=
                    staticcall(
                        gas(),
                        signer,
                        selectorPtr,
                        add(originalSignatureLength, EIP1271_isValidSignature_calldata_baseLength),
                        0,
                        OneWord
                    )

                // Determine if the signature is valid on successful calls.
                if success {
                    // If first word of scratch space does not contain EIP-1271
                    // signature selector, revert.
                    if iszero(eq(mload(0), EIP1271_isValidSignature_selector)) {
                        // Revert with bad 1271 signature if signer has code.
                        if extcodesize(signer) {
                            // Bad contract signature.
                            // Store left-padded selector with push4, mem[28:32]
                            mstore(0, BadContractSignature_error_selector)

                            // revert(abi.encodeWithSignature(
                            //     "BadContractSignature()"
                            // ))
                            revert(Error_selector_offset, BadContractSignature_error_length)
                        }

                        // Check if signature length was invalid.
                        if gt(sub(ECDSA_MaxLength, signatureLength), 1) {
                            // Revert with generic invalid signature error.
                            // Store left-padded selector with push4, mem[28:32]
                            mstore(0, InvalidSignature_error_selector)

                            // revert(abi.encodeWithSignature(
                            //     "InvalidSignature()"
                            // ))
                            revert(Error_selector_offset, InvalidSignature_error_length)
                        }

                        // Check if v was invalid.
                        if and(
                            eq(signatureLength, ECDSA_MaxLength),
                            iszero(
                                byte(
                                    byte(0, mload(add(signature, ECDSA_signature_v_offset))),
                                    ECDSA_twentySeventhAndTwentyEighthBytesSet
                                )
                            )
                        ) {
                            // Revert with invalid v value.
                            // Store left-padded selector with push4, mem[28:32]
                            mstore(0, BadSignatureV_error_selector)
                            mstore(BadSignatureV_error_v_ptr, byte(0, mload(add(signature, ECDSA_signature_v_offset))))

                            // revert(abi.encodeWithSignature(
                            //     "BadSignatureV(uint8)", v
                            // ))
                            revert(Error_selector_offset, BadSignatureV_error_length)
                        }

                        // Revert with generic invalid signer error message.
                        // Store left-padded selector with push4, mem[28:32]
                        mstore(0, InvalidSigner_error_selector)

                        // revert(abi.encodeWithSignature("InvalidSigner()"))
                        revert(Error_selector_offset, InvalidSigner_error_length)
                    }
                }

                // Restore the cached values overwritten by selector, digest and
                // signature head.
                mstore(wordBeforeSignaturePtr, cachedWordBeforeSignature)
                mstore(selectorPtr, cachedWordOverwrittenBySelector)
                mstore(sub(signature, EIP1271_isValidSignature_digest_negativeOffset), cachedWordOverwrittenByDigest)
            }
        }

        // If the call failed...
        if (!success) {
            // Revert and pass reason along if one was returned.
            _revertWithReasonIfOneIsReturned();

            // Otherwise, revert with error indicating bad contract signature.
            assembly {
                // Store left-padded selector with push4, mem[28:32] = selector
                mstore(0, BadContractSignature_error_selector)
                // revert(abi.encodeWithSignature("BadContractSignature()"))
                revert(Error_selector_offset, BadContractSignature_error_length)
            }
        }
    }
}

File 35 of 53 : Assertions.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {OrderParameters} from "seaport-types/src/lib/ConsiderationStructs.sol";

import {GettersAndDerivers} from "./GettersAndDerivers.sol";

import {TokenTransferrerErrors} from "seaport-types/src/interfaces/TokenTransferrerErrors.sol";

import {CounterManager} from "./CounterManager.sol";

import {
    AdditionalRecipient_size_shift,
    AddressDirtyUpperBitThreshold,
    BasicOrder_additionalRecipients_head_cdPtr,
    BasicOrder_additionalRecipients_head_ptr,
    BasicOrder_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 "seaport-types/src/lib/ConsiderationConstants.sol";

import {
    Error_selector_offset,
    MissingItemAmount_error_length,
    MissingItemAmount_error_selector
} from "seaport-types/src/lib/ConsiderationErrorConstants.sol";

import {
    _revertInvalidBasicOrderParameterEncoding,
    _revertMissingOriginalConsiderationItems
} from "seaport-types/src/lib/ConsiderationErrors.sol";

/**
 * @title Assertions
 * @author 0age
 * @notice Assertions contains logic for making various assertions that do not
 *         fit neatly within a dedicated semantic scope.
 */
contract Assertions is GettersAndDerivers, CounterManager, TokenTransferrerErrors {
    /**
     * @dev Derive and set hashes, reference chainId, and associated domain
     *      separator during deployment.
     *
     * @param conduitController A contract that deploys conduits, or proxies
     *                          that may optionally be used to transfer approved
     *                          ERC20/721/1155 tokens.
     */
    constructor(address conduitController) GettersAndDerivers(conduitController) {}

    /**
     * @dev Internal view function to ensure that the supplied consideration
     *      array length on a given set of order parameters is not less than the
     *      original consideration array length for that order and to retrieve
     *      the current counter for a given order's offerer and zone and use it
     *      to derive the order hash.
     *
     * @param orderParameters The parameters of the order to hash.
     *
     * @return The hash.
     */
    function _assertConsiderationLengthAndGetOrderHash(OrderParameters memory orderParameters)
        internal
        view
        returns (bytes32)
    {
        // Ensure supplied consideration array length is not less than original.
        _assertConsiderationLengthIsNotLessThanOriginalConsiderationLength(
            orderParameters.consideration.length, orderParameters.totalOriginalConsiderationItems
        );

        // Derive and return order hash using current counter for the offerer.
        return _deriveOrderHash(orderParameters, _getCounter(orderParameters.offerer));
    }

    /**
     * @dev Internal pure function to ensure that the supplied consideration
     *      array length for an order to be fulfilled is not less than the
     *      original consideration array length for that order.
     *
     * @param suppliedConsiderationItemTotal The number of consideration items
     *                                       supplied when fulfilling the order.
     * @param originalConsiderationItemTotal The number of consideration items
     *                                       supplied on initial order creation.
     */
    function _assertConsiderationLengthIsNotLessThanOriginalConsiderationLength(
        uint256 suppliedConsiderationItemTotal,
        uint256 originalConsiderationItemTotal
    ) internal pure {
        // Ensure supplied consideration array length is not less than original.
        if (suppliedConsiderationItemTotal < originalConsiderationItemTotal) {
            _revertMissingOriginalConsiderationItems();
        }
    }

    /**
     * @dev Internal pure function to ensure that a given item amount is not
     *      zero.
     *
     * @param amount The amount to check.
     */
    function _assertNonZeroAmount(uint256 amount) internal pure {
        assembly {
            if iszero(amount) {
                // Store left-padded selector with push4, mem[28:32] = selector
                mstore(0, MissingItemAmount_error_selector)

                // revert(abi.encodeWithSignature("MissingItemAmount()"))
                revert(Error_selector_offset, MissingItemAmount_error_length)
            }
        }
    }

    /**
     * @dev Internal pure function to validate calldata offsets for dynamic
     *      types in BasicOrderParameters and other parameters. This ensures
     *      that functions using the calldata object normally will be using the
     *      same data as the assembly functions and that values that are bound
     *      to a given range are within that range. Note that no parameters are
     *      supplied as all basic order functions use the same calldata
     *      encoding.
     */
    function _assertValidBasicOrderParameters() internal pure {
        // Declare a boolean designating basic order parameter offset validity.
        bool validOffsets;

        // Utilize assembly in order to read offset data directly from calldata.
        assembly {
            /*
             * Checks:
             * 1. Order parameters struct offset == 0x20
             * 2. Additional recipients arr offset == 0x240
             * 3. Signature offset == 0x260 + (recipients.length * 0x40)
             * 4. BasicOrderType between 0 and 23 (i.e. < 24)
             * 5. Offerer, zone, offer token, and consideration token have no
             *    upper dirty bits — each argument is type(uint160).max or less
             */
            validOffsets :=
                and(
                    and(
                        and(
                            // Order parameters at cd 0x04 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();
        }
    }
}

File 36 of 53 : SignatureVerificationErrors.sol
// 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();
}

File 37 of 53 : TokenTransferrerErrors.sol
// 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();
}

File 38 of 53 : SeaportValidator.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import { ItemType } from "seaport-types/src/lib/ConsiderationEnums.sol";
import {
    Order,
    OrderParameters,
    BasicOrderParameters,
    OfferItem,
    ConsiderationItem,
    Schema,
    ZoneParameters
} from "seaport-types/src/lib/ConsiderationStructs.sol";
import { ConsiderationTypeHashes } from "./lib/ConsiderationTypeHashes.sol";
import {
    ConsiderationInterface
} from "seaport-types/src/interfaces/ConsiderationInterface.sol";
import {
    ConduitControllerInterface
} from "seaport-types/src/interfaces/ConduitControllerInterface.sol";
import {
    ContractOffererInterface
} from "seaport-types/src/interfaces/ContractOffererInterface.sol";
import { ZoneInterface } from "seaport-types/src/interfaces/ZoneInterface.sol";
import {
    GettersAndDerivers
} from "seaport-core/src/lib/GettersAndDerivers.sol";
import { SeaportValidatorInterface } from "./lib/SeaportValidatorInterface.sol";
import { ZoneInterface } from "seaport-types/src/interfaces/ZoneInterface.sol";
import {
    ERC20Interface,
    ERC721Interface,
    ERC1155Interface
} from "seaport-types/src/interfaces/AbridgedTokenInterfaces.sol";
import { IERC165 } from "@openzeppelin/contracts/interfaces/IERC165.sol";
import { IERC2981 } from "@openzeppelin/contracts/interfaces/IERC2981.sol";
import {
    ErrorsAndWarnings,
    ErrorsAndWarningsLib
} from "./lib/ErrorsAndWarnings.sol";
import { SafeStaticCall } from "./lib/SafeStaticCall.sol";
import {
    IssueParser,
    ValidationConfiguration,
    TimeIssue,
    StatusIssue,
    OfferIssue,
    ContractOffererIssue,
    ConsiderationIssue,
    PrimaryFeeIssue,
    ERC721Issue,
    ERC1155Issue,
    ERC20Issue,
    NativeIssue,
    ZoneIssue,
    ConduitIssue,
    CreatorFeeIssue,
    SignatureIssue,
    GenericIssue,
    ConsiderationItemConfiguration
} from "./lib/SeaportValidatorTypes.sol";
import { Verifiers } from "seaport-core/src/lib/Verifiers.sol";
import { ReadOnlyOrderValidator } from "./lib/ReadOnlyOrderValidator.sol";
import { SeaportValidatorHelper } from "./lib/SeaportValidatorHelper.sol";

/**
 * @title SeaportValidator
 * @author OpenSea Protocol Team
 * @notice SeaportValidator provides advanced validation to seaport orders.
 */
contract SeaportValidator is
    SeaportValidatorInterface,
    ConsiderationTypeHashes
{
    using ErrorsAndWarningsLib for ErrorsAndWarnings;
    using SafeStaticCall for address;
    using IssueParser for *;

    /// @notice Cross-chain conduit controller Address
    ConduitControllerInterface private immutable _conduitController;

    SeaportValidatorHelper private immutable _helper;

    ReadOnlyOrderValidator private immutable _readOnlyOrderValidator;

    bytes4 public constant ERC20_INTERFACE_ID = 0x36372b07;

    bytes4 public constant ERC721_INTERFACE_ID = 0x80ac58cd;

    bytes4 public constant ERC1155_INTERFACE_ID = 0xd9b67a26;

    bytes4 public constant CONTRACT_OFFERER_INTERFACE_ID = 0x1be900b1;

    bytes4 public constant ZONE_INTERFACE_ID = 0x3839be19;

    constructor(
        address readOnlyOrderValidatorAddress,
        address seaportValidatorHelperAddress,
        address conduitControllerAddress
    ) {
        _readOnlyOrderValidator = ReadOnlyOrderValidator(
            readOnlyOrderValidatorAddress
        );
        _helper = SeaportValidatorHelper(seaportValidatorHelperAddress);
        _conduitController = ConduitControllerInterface(
            conduitControllerAddress
        );
    }

    /**
     * @notice Conduct a comprehensive validation of the given order.
     *    `isValidOrder` validates simple orders that adhere to a set of rules defined below:
     *    - The order is either a listing or an offer order (one NFT to buy or one NFT to sell).
     *    - The first consideration is the primary consideration.
     *    - The order pays up to two fees in the fungible token currency. First fee is primary fee, second is creator fee.
     *    - In private orders, the last consideration specifies a recipient for the offer item.
     *    - Offer items must be owned and properly approved by the offerer.
     *    - There must be one offer item
     *    - Consideration items must exist.
     *    - The signature must be valid, or the order must be already validated on chain
     * @param order The order to validate.
     * @return errorsAndWarnings The errors and warnings found in the order.
     */
    function isValidOrder(
        Order calldata order,
        address seaportAddress
    ) external view returns (ErrorsAndWarnings memory errorsAndWarnings) {
        return
            isValidOrderWithConfiguration(
                ValidationConfiguration(
                    seaportAddress,
                    address(0),
                    0,
                    false,
                    false,
                    30 minutes,
                    26 weeks
                ),
                order
            );
    }

    /**
     * @notice Same as `isValidOrder` but allows for more configuration related to fee validation.
     *    If `skipStrictValidation` is set order logic validation is not carried out: fees are not
     *       checked and there may be more than one offer item as well as any number of consideration items.
     */
    function isValidOrderWithConfiguration(
        ValidationConfiguration memory validationConfiguration,
        Order memory order
    ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) {
        errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0));

        // Concatenates errorsAndWarnings with the returned errorsAndWarnings
        errorsAndWarnings.concat(
            validateTime(
                order.parameters,
                validationConfiguration.shortOrderDuration,
                validationConfiguration.distantOrderExpiration
            )
        );
        errorsAndWarnings.concat(
            validateOrderStatus(
                order.parameters,
                validationConfiguration.seaport
            )
        );
        errorsAndWarnings.concat(
            validateOfferItems(
                order.parameters,
                validationConfiguration.seaport
            )
        );
        errorsAndWarnings.concat(
            validateConsiderationItems(
                order.parameters,
                validationConfiguration.seaport
            )
        );
        errorsAndWarnings.concat(isValidZone(order.parameters));
        errorsAndWarnings.concat(
            validateSignature(order, validationConfiguration.seaport)
        );

        // Skip strict validation if requested
        if (!validationConfiguration.skipStrictValidation) {
            errorsAndWarnings.concat(
                validateStrictLogic(
                    order.parameters,
                    validationConfiguration.primaryFeeRecipient,
                    validationConfiguration.primaryFeeBips,
                    validationConfiguration.checkCreatorFee
                )
            );
        }
    }

    /**
     * @notice Strict validation operates under tight assumptions. It validates primary
     *    fee, creator fee, private sale consideration, and overall order format.
     * @dev Only checks first fee recipient provided by CreatorFeeEngine.
     *    Order of consideration items must be as follows:
     *    1. Primary consideration
     *    2. Primary fee
     *    3. Creator fee
     *    4. Private sale consideration
     * @param orderParameters The parameters for the order to validate.
     * @param primaryFeeRecipient The primary fee recipient. Set to null address for no primary fee.
     * @param primaryFeeBips The primary fee in BIPs.
     * @param checkCreatorFee Should check for creator fee. If true, creator fee must be present as
     *    according to creator fee engine. If false, must not have creator fee.
     * @return errorsAndWarnings The errors and warnings.
     */
    function validateStrictLogic(
        OrderParameters memory orderParameters,
        address primaryFeeRecipient,
        uint256 primaryFeeBips,
        bool checkCreatorFee
    ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) {
        return
            _helper.validateStrictLogic(
                orderParameters,
                primaryFeeRecipient,
                primaryFeeBips,
                checkCreatorFee
            );
    }

    /**
     * @notice Checks if a conduit key is valid.
     * @param conduitKey The conduit key to check.
     * @return errorsAndWarnings The errors and warnings
     */
    function isValidConduit(
        bytes32 conduitKey,
        address seaportAddress
    ) external view returns (ErrorsAndWarnings memory errorsAndWarnings) {
        (, errorsAndWarnings) = getApprovalAddress(conduitKey, seaportAddress);
    }

    /**
     * @notice Checks if the zone of an order is set and implements the EIP165
     *         zone interface
     * @dev To validate the zone call for an order, see validateOrderWithZone
     * @param orderParameters The order parameters to check.
     * @return errorsAndWarnings The errors and warnings
     */
    function isValidZone(
        OrderParameters memory orderParameters
    ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) {
        errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0));

        // If not restricted, zone isn't checked
        if (
            uint8(orderParameters.orderType) < 2 ||
            uint8(orderParameters.orderType) == 4
        ) {
            return errorsAndWarnings;
        }

        if (orderParameters.zone == address(0)) {
            // Zone is not set
            errorsAndWarnings.addError(ZoneIssue.NotSet.parseInt());
            return errorsAndWarnings;
        }

        // Warn if zone is an EOA
        if (address(orderParameters.zone).code.length == 0) {
            errorsAndWarnings.addWarning(ZoneIssue.EOAZone.parseInt());
            return errorsAndWarnings;
        }

        // Check the EIP165 zone interface
        if (!checkInterface(orderParameters.zone, ZONE_INTERFACE_ID)) {
            errorsAndWarnings.addWarning(ZoneIssue.InvalidZone.parseInt());
            return errorsAndWarnings;
        }

        // Check if the zone implements SIP-5
        try ZoneInterface(orderParameters.zone).getSeaportMetadata() {} catch {
            errorsAndWarnings.addWarning(ZoneIssue.InvalidZone.parseInt());
        }
    }

    /**
     * @notice Gets the approval address for the given conduit key
     * @param conduitKey Conduit key to get approval address for
     * @param seaportAddress The Seaport address
     * @return approvalAddress The address to use for approvals
     * @return errorsAndWarnings An ErrorsAndWarnings structs with results
     */
    function getApprovalAddress(
        bytes32 conduitKey,
        address seaportAddress
    )
        public
        view
        returns (address, ErrorsAndWarnings memory errorsAndWarnings)
    {
        errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0));

        // Zero conduit key corresponds to seaport
        if (conduitKey == 0) return (seaportAddress, errorsAndWarnings);

        // Pull conduit info from conduitController
        (address conduitAddress, bool exists) = _conduitController.getConduit(
            conduitKey
        );

        // Conduit does not exist
        if (!exists) {
            errorsAndWarnings.addError(ConduitIssue.KeyInvalid.parseInt());
            conduitAddress = address(0); // Don't return invalid conduit
        }

        // Approval address does not have Seaport added as a channel
        if (
            exists &&
            !_conduitController.getChannelStatus(conduitAddress, seaportAddress)
        ) {
            errorsAndWarnings.addError(
                ConduitIssue.MissingSeaportChannel.parseInt()
            );
        }

        return (conduitAddress, errorsAndWarnings);
    }

    /**
     * @notice Validates the signature for the order using the offerer's current counter
     * @dev Will also check if order is validated on chain.
     */
    function validateSignature(
        Order memory order,
        address seaportAddress
    ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) {
        // Pull current counter from seaport
        uint256 currentCounter = ConsiderationInterface(seaportAddress)
            .getCounter(order.parameters.offerer);

        return
            validateSignatureWithCounter(order, currentCounter, seaportAddress);
    }

    /**
     * @notice Validates the signature for the order using the given counter
     * @dev Will also check if order is validated on chain.
     */
    function validateSignatureWithCounter(
        Order memory order,
        uint256 counter,
        address seaportAddress
    ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) {
        errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0));

        // Typecast Seaport address to ConsiderationInterface
        ConsiderationInterface seaport = ConsiderationInterface(seaportAddress);

        // Contract orders do not have signatures
        if (uint8(order.parameters.orderType) == 4) {
            errorsAndWarnings.addWarning(
                SignatureIssue.ContractOrder.parseInt()
            );
        }

        // Get current counter for context
        uint256 currentCounter = seaport.getCounter(order.parameters.offerer);

        if (currentCounter > counter) {
            // Counter strictly increases
            errorsAndWarnings.addError(SignatureIssue.LowCounter.parseInt());
            return errorsAndWarnings;
        } else if (currentCounter < counter) {
            // Counter is incremented by random large number
            errorsAndWarnings.addError(SignatureIssue.HighCounter.parseInt());
            return errorsAndWarnings;
        }

        bytes32 orderHash = _deriveOrderHash(order.parameters, counter);

        // Check if order is validated on chain
        (bool isValid, , , ) = seaport.getOrderStatus(orderHash);

        if (isValid) {
            // Shortcut success, valid on chain
            return errorsAndWarnings;
        }

        // Create memory array to pass into validate
        Order[] memory orderArray = new Order[](1);

        // Store order in array
        orderArray[0] = order;

        try
            // Call validate on Seaport
            _readOnlyOrderValidator.canValidate(seaportAddress, orderArray)
        returns (bool success) {
            if (!success) {
                // Call was unsuccessful, so signature is invalid
                errorsAndWarnings.addError(SignatureIssue.Invalid.parseInt());
            }
        } catch {
            if (
                order.parameters.consideration.length !=
                order.parameters.totalOriginalConsiderationItems
            ) {
                // May help diagnose signature issues
                errorsAndWarnings.addWarning(
                    SignatureIssue.OriginalConsiderationItems.parseInt()
                );
            }
            // Call reverted, so signature is invalid
            errorsAndWarnings.addError(SignatureIssue.Invalid.parseInt());
        }
    }

    /**
     * @notice Check that a contract offerer implements the EIP165
     *         contract offerer interface
     * @param contractOfferer The address of the contract offerer
     * @return errorsAndWarnings The errors and warnings
     */
    function validateContractOfferer(
        address contractOfferer
    ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) {
        errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0));

        // Check the EIP165 contract offerer interface
        if (!checkInterface(contractOfferer, CONTRACT_OFFERER_INTERFACE_ID)) {
            errorsAndWarnings.addWarning(
                ContractOffererIssue.InvalidContractOfferer.parseInt()
            );
        }

        // Check if the contract offerer implements SIP-5
        try
            ContractOffererInterface(contractOfferer).getSeaportMetadata()
        {} catch {
            errorsAndWarnings.addWarning(
                ContractOffererIssue.InvalidContractOfferer.parseInt()
            );
        }

        return errorsAndWarnings;
    }

    /**
     * @notice Check the time validity of an order
     * @param orderParameters The parameters for the order to validate
     * @param shortOrderDuration The duration of which an order is considered short
     * @param distantOrderExpiration Distant order expiration delta in seconds.
     * @return errorsAndWarnings The errors and warnings
     */
    function validateTime(
        OrderParameters memory orderParameters,
        uint256 shortOrderDuration,
        uint256 distantOrderExpiration
    ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) {
        errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0));

        if (orderParameters.endTime <= orderParameters.startTime) {
            // Order duration is zero
            errorsAndWarnings.addError(
                TimeIssue.EndTimeBeforeStartTime.parseInt()
            );
            return errorsAndWarnings;
        }

        if (orderParameters.endTime < block.timestamp) {
            // Order is expired
            errorsAndWarnings.addError(TimeIssue.Expired.parseInt());
            return errorsAndWarnings;
        } else if (
            orderParameters.endTime > block.timestamp + distantOrderExpiration
        ) {
            // Order expires in a long time
            errorsAndWarnings.addWarning(
                TimeIssue.DistantExpiration.parseInt()
            );
        }

        if (orderParameters.startTime > block.timestamp) {
            // Order is not active
            errorsAndWarnings.addWarning(TimeIssue.NotActive.parseInt());
        }

        if (
            orderParameters.endTime -
                (
                    orderParameters.startTime > block.timestamp
                        ? orderParameters.startTime
                        : block.timestamp
                ) <
            shortOrderDuration
        ) {
            // Order has a short duration
            errorsAndWarnings.addWarning(TimeIssue.ShortOrder.parseInt());
        }
    }

    /**
     * @notice Validate the status of an order
     * @param orderParameters The parameters for the order to validate
     * @return errorsAndWarnings  The errors and warnings
     */
    function validateOrderStatus(
        OrderParameters memory orderParameters,
        address seaportAddress
    ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) {
        errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0));

        // Typecast Seaport address to ConsiderationInterface
        ConsiderationInterface seaport = ConsiderationInterface(seaportAddress);

        // Cannot validate status of contract order
        if (uint8(orderParameters.orderType) == 4) {
            errorsAndWarnings.addWarning(StatusIssue.ContractOrder.parseInt());
        }

        // Pull current counter from seaport
        uint256 currentOffererCounter = seaport.getCounter(
            orderParameters.offerer
        );
        // Derive order hash using orderParameters and currentOffererCounter
        bytes32 orderHash = _deriveOrderHash(
            orderParameters,
            currentOffererCounter
        );
        // Get order status from seaport
        (, bool isCancelled, uint256 totalFilled, uint256 totalSize) = seaport
            .getOrderStatus(orderHash);

        if (isCancelled) {
            // Order is cancelled
            errorsAndWarnings.addError(StatusIssue.Cancelled.parseInt());
        }

        if (totalSize > 0 && totalFilled == totalSize) {
            // Order is fully filled
            errorsAndWarnings.addError(StatusIssue.FullyFilled.parseInt());
        }
    }

    /**
     * @notice Validate all offer items for an order. Ensures that
     *         offerer has sufficient balance and approval for each item.
     * @dev Amounts are not summed and verified, just the individual amounts.
     * @param orderParameters The parameters for the order to validate
     * @return errorsAndWarnings  The errors and warnings
     */
    function validateOfferItems(
        OrderParameters memory orderParameters,
        address seaportAddress
    ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) {
        errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0));

        // Iterate over each offer item and validate it
        for (uint256 i = 0; i < orderParameters.offer.length; i++) {
            errorsAndWarnings.concat(
                validateOfferItem(orderParameters, i, seaportAddress)
            );

            // Check for duplicate offer item
            OfferItem memory offerItem1 = orderParameters.offer[i];

            for (uint256 j = i + 1; j < orderParameters.offer.length; j++) {
                // Iterate over each remaining offer item
                // (previous items already check with this item)
                OfferItem memory offerItem2 = orderParameters.offer[j];

                // Check if token and id are the same
                if (
                    offerItem1.token == offerItem2.token &&
                    offerItem1.identifierOrCriteria ==
                    offerItem2.identifierOrCriteria
                ) {
                    errorsAndWarnings.addError(
                        OfferIssue.DuplicateItem.parseInt()
                    );
                }
            }
        }

        // You must have an offer item
        if (orderParameters.offer.length == 0) {
            errorsAndWarnings.addWarning(OfferIssue.ZeroItems.parseInt());
        }

        // Warning if there is more than one offer item
        if (orderParameters.offer.length > 1) {
            errorsAndWarnings.addWarning(OfferIssue.MoreThanOneItem.parseInt());
        }
    }

    /**
     * @notice Validates an offer item
     * @param orderParameters The parameters for the order to validate
     * @param offerItemIndex The index of the offerItem in offer array to validate
     * @return errorsAndWarnings An ErrorsAndWarnings structs with results
     */
    function validateOfferItem(
        OrderParameters memory orderParameters,
        uint256 offerItemIndex,
        address seaportAddress
    ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) {
        // First validate the parameters (correct amount, contract, etc)
        errorsAndWarnings = validateOfferItemParameters(
            orderParameters,
            offerItemIndex,
            seaportAddress
        );
        if (errorsAndWarnings.hasErrors()) {
            // Only validate approvals and balances if parameters are valid
            return errorsAndWarnings;
        }

        // Validate approvals and balances for the offer item
        errorsAndWarnings.concat(
            validateOfferItemApprovalAndBalance(
                orderParameters,
                offerItemIndex,
                seaportAddress
            )
        );
    }

    /**
     * @notice Validates the OfferItem parameters. This includes token contract validation
     * @dev OfferItems with criteria are currently not allowed
     * @param orderParameters The parameters for the order to validate
     * @param offerItemIndex The index of the offerItem in offer array to validate
     * @return errorsAndWarnings An ErrorsAndWarnings structs with results
     */
    function validateOfferItemParameters(
        OrderParameters memory orderParameters,
        uint256 offerItemIndex,
        address seaportAddress
    ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) {
        errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0));

        // Get the offer item at offerItemIndex
        OfferItem memory offerItem = orderParameters.offer[offerItemIndex];

        // Check if start amount and end amount are zero
        if (offerItem.startAmount == 0 && offerItem.endAmount == 0) {
            errorsAndWarnings.addError(OfferIssue.AmountZero.parseInt());
            return errorsAndWarnings;
        }

        // Check that amount velocity is not too high.
        if (
            offerItem.startAmount != offerItem.endAmount &&
            orderParameters.endTime > orderParameters.startTime
        ) {
            // Assign larger and smaller amount values
            (uint256 maxAmount, uint256 minAmount) = offerItem.startAmount >
                offerItem.endAmount
                ? (offerItem.startAmount, offerItem.endAmount)
                : (offerItem.endAmount, offerItem.startAmount);

            uint256 amountDelta = maxAmount - minAmount;
            // delta of time that order exists for
            uint256 timeDelta = orderParameters.endTime -
                orderParameters.startTime;

            // Velocity scaled by 1e10 for precision
            uint256 velocity = (amountDelta * 1e10) / timeDelta;
            // gives velocity percentage in hundredth of a basis points per second in terms of larger value
            uint256 velocityPercentage = velocity / (maxAmount * 1e4);

            // 278 * 60 * 30 ~= 500,000
            if (velocityPercentage > 278) {
                // Over 50% change per 30 min
                errorsAndWarnings.addError(
                    OfferIssue.AmountVelocityHigh.parseInt()
                );
            }
            // Over 50% change per 30 min
            else if (velocityPercentage > 28) {
                // Over 5% change per 30 min
                errorsAndWarnings.addWarning(
                    OfferIssue.AmountVelocityHigh.parseInt()
                );
            }

            // Check for large amount steps
            if (minAmount <= 1e15) {
                errorsAndWarnings.addWarning(
                    OfferIssue.AmountStepLarge.parseInt()
                );
            }
        }

        if (offerItem.itemType == ItemType.ERC721) {
            // ERC721 type requires amounts to be 1
            if (offerItem.startAmount != 1 || offerItem.endAmount != 1) {
                errorsAndWarnings.addError(ERC721Issue.AmountNotOne.parseInt());
            }

            // Check the EIP165 token interface
            if (!checkInterface(offerItem.token, ERC721_INTERFACE_ID)) {
                errorsAndWarnings.addError(ERC721Issue.InvalidToken.parseInt());
            }
        } else if (offerItem.itemType == ItemType.ERC721_WITH_CRITERIA) {
            // Check the EIP165 token interface
            if (!checkInterface(offerItem.token, ERC721_INTERFACE_ID)) {
                errorsAndWarnings.addError(ERC721Issue.InvalidToken.parseInt());
            }

            if (offerItem.startAmount > 1 || offerItem.endAmount > 1) {
                // Require partial fill enabled. Even orderTypes are full
                if (uint8(orderParameters.orderType) % 2 == 0) {
                    errorsAndWarnings.addError(
                        ERC721Issue.CriteriaNotPartialFill.parseInt()
                    );
                }
            }
        } else if (
            offerItem.itemType == ItemType.ERC1155 ||
            offerItem.itemType == ItemType.ERC1155_WITH_CRITERIA
        ) {
            // Check the EIP165 token interface
            if (!checkInterface(offerItem.token, ERC1155_INTERFACE_ID)) {
                errorsAndWarnings.addError(
                    ERC1155Issue.InvalidToken.parseInt()
                );
            }
        } else if (offerItem.itemType == ItemType.ERC20) {
            // ERC20 must have `identifierOrCriteria` be zero
            if (offerItem.identifierOrCriteria != 0) {
                errorsAndWarnings.addError(
                    ERC20Issue.IdentifierNonZero.parseInt()
                );
            }

            // Validate contract, should return an uint256 if its an ERC20
            if (
                !offerItem.token.safeStaticCallUint256(
                    abi.encodeWithSelector(
                        ERC20Interface.allowance.selector,
                        seaportAddress,
                        seaportAddress
                    ),
                    0
                )
            ) {
                errorsAndWarnings.addError(ERC20Issue.InvalidToken.parseInt());
            }
        } else {
            // Must be native
            // NATIVE must have `token` be zero address
            if (offerItem.token != address(0)) {
                errorsAndWarnings.addError(NativeIssue.TokenAddress.parseInt());
            }

            // NATIVE must have `identifierOrCriteria` be zero
            if (offerItem.identifierOrCriteria != 0) {
                errorsAndWarnings.addError(
                    NativeIssue.IdentifierNonZero.parseInt()
                );
            }
        }
    }

    /**
     * @notice Validates the OfferItem approvals and balances
     * @param orderParameters The parameters for the order to validate
     * @param offerItemIndex The index of the offerItem in offer array to validate
     * @return errorsAndWarnings An ErrorsAndWarnings structs with results
     */
    function validateOfferItemApprovalAndBalance(
        OrderParameters memory orderParameters,
        uint256 offerItemIndex,
        address seaportAddress
    ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) {
        // Note: If multiple items are of the same token, token amounts are not summed for validation

        errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0));

        // Get the approval address for the given conduit key
        (
            address approvalAddress,
            ErrorsAndWarnings memory ew
        ) = getApprovalAddress(orderParameters.conduitKey, seaportAddress);
        errorsAndWarnings.concat(ew);

        if (ew.hasErrors()) {
            // Approval address is invalid
            return errorsAndWarnings;
        }

        // Get the offer item at offerItemIndex
        OfferItem memory offerItem = orderParameters.offer[offerItemIndex];

        if (offerItem.itemType == ItemType.ERC721) {
            ERC721Interface token = ERC721Interface(offerItem.token);

            // Check that offerer owns token
            if (
                !address(token).safeStaticCallAddress(
                    abi.encodeWithSelector(
                        ERC721Interface.ownerOf.selector,
                        offerItem.identifierOrCriteria
                    ),
                    orderParameters.offerer
                )
            ) {
                errorsAndWarnings.addError(ERC721Issue.NotOwner.parseInt());
            }

            // Check for approval via `getApproved`
            if (
                !address(token).safeStaticCallAddress(
                    abi.encodeWithSelector(
                        ERC721Interface.getApproved.selector,
                        offerItem.identifierOrCriteria
                    ),
                    approvalAddress
                )
            ) {
                // Fallback to `isApprovalForAll`
                if (
                    !address(token).safeStaticCallBool(
                        abi.encodeWithSelector(
                            ERC721Interface.isApprovedForAll.selector,
                            orderParameters.offerer,
                            approvalAddress
                        ),
                        true
                    )
                ) {
                    // Not approved
                    errorsAndWarnings.addError(
                        ERC721Issue.NotApproved.parseInt()
                    );
                }
            }
        } else if (offerItem.itemType == ItemType.ERC721_WITH_CRITERIA) {
            ERC721Interface token = ERC721Interface(offerItem.token);

            // Check for approval
            if (
                !address(token).safeStaticCallBool(
                    abi.encodeWithSelector(
                        ERC721Interface.isApprovedForAll.selector,
                        orderParameters.offerer,
                        approvalAddress
                    ),
                    true
                )
            ) {
                // Not approved
                errorsAndWarnings.addError(ERC721Issue.NotApproved.parseInt());
            }
        } else if (offerItem.itemType == ItemType.ERC1155) {
            ERC1155Interface token = ERC1155Interface(offerItem.token);

            // Check for approval
            if (
                !address(token).safeStaticCallBool(
                    abi.encodeWithSelector(
                        ERC1155Interface.isApprovedForAll.selector,
                        orderParameters.offerer,
                        approvalAddress
                    ),
                    true
                )
            ) {
                errorsAndWarnings.addError(ERC1155Issue.NotApproved.parseInt());
            }

            // Get min required balance (max(startAmount, endAmount))
            uint256 minBalance = offerItem.startAmount < offerItem.endAmount
                ? offerItem.startAmount
                : offerItem.endAmount;

            // Check for sufficient balance
            if (
                !address(token).safeStaticCallUint256(
                    abi.encodeWithSelector(
                        ERC1155Interface.balanceOf.selector,
                        orderParameters.offerer,
                        offerItem.identifierOrCriteria
                    ),
                    minBalance
                )
            ) {
                // Insufficient balance
                errorsAndWarnings.addError(
                    ERC1155Issue.InsufficientBalance.parseInt()
                );
            }
        } else if (offerItem.itemType == ItemType.ERC1155_WITH_CRITERIA) {
            ERC1155Interface token = ERC1155Interface(offerItem.token);

            // Check for approval
            if (
                !address(token).safeStaticCallBool(
                    abi.encodeWithSelector(
                        ERC1155Interface.isApprovedForAll.selector,
                        orderParameters.offerer,
                        approvalAddress
                    ),
                    true
                )
            ) {
                errorsAndWarnings.addError(ERC1155Issue.NotApproved.parseInt());
            }
        } else if (offerItem.itemType == ItemType.ERC20) {
            ERC20Interface token = ERC20Interface(offerItem.token);

            // Get min required balance and approval (max(startAmount, endAmount))
            uint256 minBalanceAndAllowance = offerItem.startAmount <
                offerItem.endAmount
                ? offerItem.startAmount
                : offerItem.endAmount;

            // Check allowance
            if (
                !address(token).safeStaticCallUint256(
                    abi.encodeWithSelector(
                        ERC20Interface.allowance.selector,
                        orderParameters.offerer,
                        approvalAddress
                    ),
                    minBalanceAndAllowance
                )
            ) {
                errorsAndWarnings.addError(
                    ERC20Issue.InsufficientAllowance.parseInt()
                );
            }

            // Check balance
            if (
                !address(token).safeStaticCallUint256(
                    abi.encodeWithSelector(
                        ERC20Interface.balanceOf.selector,
                        orderParameters.offerer
                    ),
                    minBalanceAndAllowance
                )
            ) {
                errorsAndWarnings.addError(
                    ERC20Issue.InsufficientBalance.parseInt()
                );
            }
        } else {
            // Must be native
            // Get min required balance (max(startAmount, endAmount))
            uint256 minBalance = offerItem.startAmount < offerItem.endAmount
                ? offerItem.startAmount
                : offerItem.endAmount;

            // Check for sufficient balance
            if (orderParameters.offerer.balance < minBalance) {
                errorsAndWarnings.addError(
                    NativeIssue.InsufficientBalance.parseInt()
                );
            }

            // Native items can not be pulled so warn
            errorsAndWarnings.addWarning(OfferIssue.NativeItem.parseInt());
        }
    }

    /**
     * @notice Validate all consideration items for an order
     * @param orderParameters The parameters for the order to validate
     * @return errorsAndWarnings  The errors and warnings
     */
    function validateConsiderationItems(
        OrderParameters memory orderParameters,
        address seaportAddress
    ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) {
        return
            _helper.validateConsiderationItems(orderParameters, seaportAddress);
    }

    /**
     * @notice Validate a consideration item
     * @param orderParameters The parameters for the order to validate
     * @param considerationItemIndex The index of the consideration item to validate
     * @return errorsAndWarnings  The errors and warnings
     */
    function validateConsiderationItem(
        OrderParameters memory orderParameters,
        uint256 considerationItemIndex,
        address seaportAddress
    ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) {
        return
            _helper.validateConsiderationItem(
                orderParameters,
                considerationItemIndex,
                seaportAddress
            );
    }

    /**
     * @notice Validates the parameters of a consideration item including contract validation
     * @param orderParameters The parameters for the order to validate
     * @param considerationItemIndex The index of the consideration item to validate
     * @return errorsAndWarnings  The errors and warnings
     */
    function validateConsiderationItemParameters(
        OrderParameters memory orderParameters,
        uint256 considerationItemIndex,
        address seaportAddress
    ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) {
        return
            _helper.validateConsiderationItemParameters(
                orderParameters,
                considerationItemIndex,
                seaportAddress
            );
    }

    /**
     * @notice Validates the zone call for an order
     * @param orderParameters The order parameters for the order to validate
     * @param zoneParameters The zone parameters for the order to validate
     * @return errorsAndWarnings An ErrorsAndWarnings structs with results
     */
    function validateOrderWithZone(
        OrderParameters memory orderParameters,
        ZoneParameters memory zoneParameters
    ) public view returns (ErrorsAndWarnings memory errorsAndWarnings) {
        errorsAndWarnings = ErrorsAndWarnings(new uint16[](0), new uint16[](0));

        // Call isValidZone to check if zone is set and implements EIP165
        errorsAndWarnings.concat(isValidZone(orderParameters));

        // Call zone function `validateOrder` with the supplied ZoneParameters
        if (
            !orderParameters.zone.safeStaticCallBytes4(
                abi.encodeWithSelector(
                    ZoneInterface.validateOrder.selector,
                    zoneParameters
                ),
                ZoneInterface.validateOrder.selector
            )
        ) {
            // Call to validateOrder reverted or returned invalid magic value
            errorsAndWarnings.addWarning(ZoneIssue.RejectedOrder.parseInt());
        }
    }

    /**
     * @notice Safely check that a contract implements an interface
     * @param token The token address to check
     * @param interfaceHash The interface hash to check
     */
    function checkInterface(
        address token,
        bytes4 interfaceHash
    ) public view returns (bool) {
        return
            token.safeStaticCallBool(
                abi.encodeWithSelector(
                    IERC165.supportsInterface.selector,
                    interfaceHash
                ),
                true
            );
    }

    function isPaymentToken(ItemType itemType) public pure returns (bool) {
        return itemType == ItemType.NATIVE || itemType == ItemType.ERC20;
    }

    /*//////////////////////////////////////////////////////////////
                        Merkle Helpers
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice Sorts an array of token ids by the keccak256 hash of the id. Required ordering of ids
     *    for other merkle operations.
     * @param includedTokens An array of included token ids.
     * @return sortedTokens The sorted `includedTokens` array.
     */
    function sortMerkleTokens(
        uint256[] memory includedTokens
    ) public view returns (uint256[] memory sortedTokens) {
        // Sort token ids by the keccak256 hash of the id
        return _helper.sortMerkleTokens(includedTokens);
    }

    /**
     * @notice Creates a merkle root for includedTokens.
     * @dev `includedTokens` must be sorting in strictly ascending order according to the keccak256 hash of the value.
     * @return merkleRoot The merkle root
     * @return errorsAndWarnings Errors and warnings from the operation
     */
    function getMerkleRoot(
        uint256[] memory includedTokens
    )
        public
        view
        returns (bytes32 merkleRoot, ErrorsAndWarnings memory errorsAndWarnings)
    {
        return _helper.getMerkleRoot(includedTokens);
    }

    /**
     * @notice Creates a merkle proof for the the targetIndex contained in includedTokens.
     * @dev `targetIndex` is referring to the index of an element in `includedTokens`.
     *    `includedTokens` must be sorting in ascending order according to the keccak256 hash of the value.
     * @return merkleProof The merkle proof
     * @return errorsAndWarnings Errors and warnings from the operation
     */
    function getMerkleProof(
        uint256[] memory includedTokens,
        uint256 targetIndex
    )
        public
        view
        returns (
            bytes32[] memory merkleProof,
            ErrorsAndWarnings memory errorsAndWarnings
        )
    {
        return _helper.getMerkleProof(includedTokens, targetIndex);
    }

    /**
     * @notice Verifies a merkle proof for the value to prove and given root and proof.
     * @dev The `valueToProve` is hashed prior to executing the proof verification.
     * @param merkleRoot The root of the merkle tree
     * @param merkleProof The merkle proof
     * @param valueToProve The value to prove
     * @return whether proof is valid
     */
    function verifyMerkleProof(
        bytes32 merkleRoot,
        bytes32[] memory merkleProof,
        uint256 valueToProve
    ) public view returns (bool) {
        return _helper.verifyMerkleProof(merkleRoot, merkleProof, valueToProve);
    }
}

File 39 of 53 : ReadOnlyOrderValidator.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import { OrderType } from "seaport-types/src/lib/ConsiderationEnums.sol";

import {
    Order,
    OrderComponents,
    OrderParameters,
    OrderStatus
} from "seaport-types/src/lib/ConsiderationStructs.sol";

import {
    _revertConsiderationLengthNotEqualToTotalOriginal,
    _revertMissingOriginalConsiderationItems
} from "seaport-types/src/lib/ConsiderationErrors.sol";

import {
    SignatureVerification
} from "seaport-core/src/lib/SignatureVerification.sol";

import {
    _revertOrderAlreadyFilled,
    _revertOrderIsCancelled,
    _revertOrderPartiallyFilled
} from "seaport-types/src/lib/ConsiderationErrors.sol";

import { SeaportInterface } from "seaport-sol/src/SeaportInterface.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,
    BulkOrderProof_keyShift,
    BulkOrderProof_keySize,
    BulkOrderProof_lengthAdjustmentBeforeMask,
    BulkOrderProof_lengthRangeAfterMask,
    BulkOrderProof_minSize,
    BulkOrderProof_rangeSize,
    ECDSA_MaxLength,
    EIP_712_PREFIX,
    EIP712_DigestPayload_size,
    EIP712_DomainSeparator_offset,
    EIP712_OrderHash_offset,
    OneWord,
    OneWordShift,
    ThirtyOneBytes,
    TwoWords
} from "seaport-types/src/lib/ConsiderationConstants.sol";

contract ReadOnlyOrderValidator is SignatureVerification {
    function canValidate(
        address seaport,
        Order[] memory orders
    ) external view returns (bool) {
        return _validate(orders, SeaportInterface(seaport));
    }

    /**
     * @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,
        SeaportInterface seaport
    ) internal view returns (bool validated) {
        (, bytes32 domainSeparator, ) = seaport.information();

        // Declare variables outside of the loop.
        OrderStatus memory 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,
                    seaport
                );

                {
                    // Retrieve the order status using the derived order hash.
                    (
                        bool isValidated,
                        bool isCancelled,
                        uint256 totalFilled,
                        uint256 totalSize
                    ) = seaport.getOrderStatus(orderHash);
                    orderStatus = OrderStatus(
                        isValidated,
                        isCancelled,
                        uint120(totalFilled),
                        uint120(totalSize)
                    );
                }

                // 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,
                        domainSeparator
                    );

                    // 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 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 memory orderStatus,
        bool onlyAllowUnused,
        bool revertOnInvalid
    ) internal pure 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 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;
    }

    /**
     * @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,
        bytes32 domainSeparator
    ) 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 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 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)
        }
    }

    /**
     * @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,
        SeaportInterface seaport
    ) 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(seaport, orderParameters.offerer),
                seaport
            );
    }

    function _getCounter(
        SeaportInterface seaport,
        address offerer
    ) internal view returns (uint256) {
        return seaport.getCounter(offerer);
    }

    function _deriveOrderHash(
        OrderParameters memory orderParameters,
        uint256 counter,
        SeaportInterface seaport
    ) internal view returns (bytes32 orderHash) {
        return
            seaport.getOrderHash(_toOrderComponents(orderParameters, counter));
    }

    /**
     * @dev Converts an OrderParameters struct into an OrderComponents struct.
     *
     * @param parameters the OrderParameters struct to convert
     * @param counter    the counter to use for the OrderComponents struct
     *
     * @return components the OrderComponents struct
     */
    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;
        components.consideration = parameters.consideration;
        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;
    }

    /**
     * @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)
        }
    }

    /**
     * @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();
        }
    }
}

File 40 of 53 : SeaportInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import {ConsiderationInterface as SeaportInterface} from "seaport-types/src/interfaces/ConsiderationInterface.sol";

File 41 of 53 : SeaportRouter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import {
    SeaportRouterInterface
} from "seaport-types/src/interfaces/SeaportRouterInterface.sol";

import {
    SeaportInterface
} from "seaport-types/src/interfaces/SeaportInterface.sol";

import { ReentrancyGuard } from "seaport-core/src/lib/ReentrancyGuard.sol";

import {
    AdvancedOrder,
    CriteriaResolver,
    Execution,
    FulfillmentComponent
} from "seaport-types/src/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.4 contract usable through this router.
    address private immutable _SEAPORT_V1_4;
    /// @dev The allowed v1.5 contract usable through this router.
    address private immutable _SEAPORT_V1_5;

    /**
     * @dev Deploy contract with the supported Seaport contracts.
     *
     * @param seaportV1point4 The address of the Seaport v1.4 contract.
     * @param seaportV1point5 The address of the Seaport v1.5 contract.
     */
    constructor(address seaportV1point4, address seaportV1point5) {
        _SEAPORT_V1_4 = seaportV1point4;
        _SEAPORT_V1_5 = seaportV1point5;
    }

    /**
     * @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
        });

        // If recipient is not provided assign to msg.sender.
        if (calldataParams.recipient == address(0)) {
            calldataParams.recipient = msg.sender;
        }

        // 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()` that can be ignored.
            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 (bytes memory data) {
                // 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(
                        // Data begins after length offset.
                        mload(add(data, 0x20)),
                        customErrorSelector
                    )
                }

                // Pass through the custom error if the error is
                // not NoSpecifiedOrdersAvailable()
                if (
                    customErrorSelector != NoSpecifiedOrdersAvailable.selector
                ) {
                    assembly {
                        revert(add(data, 32), mload(data))
                    }
                }
            }

            // Update fulfillments left.
            calldataParams.maximumFulfilled = fulfillmentsLeft;

            unchecked {
                ++i;
            }
        }

        // Throw an error if no orders were fulfilled.
        if (fulfillmentsLeft == params.maximumFulfilled) {
            revert NoSpecifiedOrdersAvailable();
        }

        // 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_4;
        seaportContracts[1] = _SEAPORT_V1_5;
    }

    /**
     * @dev Reverts if the provided Seaport contract is not allowed.
     */
    function _assertSeaportAllowed(address seaport) internal view {
        if (
            _cast(seaport == _SEAPORT_V1_4) | _cast(seaport == _SEAPORT_V1_5) ==
            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
            );
        }
    }
}

File 42 of 53 : SeaportRouterInterface.sol
// 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 Revert with an error when attempting to fulfill any number of
     *      available orders when none are fulfillable.
     */
    error NoSpecifiedOrdersAvailable();

    /**
     * @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);
}

File 43 of 53 : SeaportInterface.sol
// 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.5
 * @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);
}

File 44 of 53 : ZoneInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import {
    ZoneParameters,
    Schema
} from "seaport-types/src/lib/ConsiderationStructs.sol";

import { IERC165 } from "seaport-types/src/interfaces/IERC165.sol";

/**
 * @title  ZoneInterface
 * @notice Contains functions exposed by a zone.
 */
interface ZoneInterface is IERC165 {
    /**
     * @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
        );

    function supportsInterface(
        bytes4 interfaceId
    ) external view override returns (bool);
}

File 45 of 53 : ConduitStructs.sol
// 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;
}

File 46 of 53 : ConduitEnums.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

enum ConduitItemType {
    NATIVE, // unused
    ERC20,
    ERC721,
    ERC1155
}

File 47 of 53 : TransferHelperStructs.sol
// 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;
}

File 48 of 53 : TransferHelperInterface.sol
// 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);
}

File 49 of 53 : ConduitInterface.sol
// 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;
}

File 50 of 53 : TransferHelperErrors.sol
// 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
    );
}

File 51 of 53 : IERC721Receiver.sol
// 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);
}

File 52 of 53 : ImmutableCreate2FactoryInterface.sol
// 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);
}

File 53 of 53 : ZoneInteractionErrors.sol
// 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);
}

Settings
{
  "viaIR": true,
  "optimizer": {
    "enabled": true,
    "runs": 99999999
  },
  "metadata": {
    "bytecodeHash": "none"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract ABI

[{"inputs":[{"internalType":"address","name":"readOnlyOrderValidatorAddress","type":"address"},{"internalType":"address","name":"seaportValidatorHelperAddress","type":"address"},{"internalType":"address","name":"conduitControllerAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CONTRACT_OFFERER_INTERFACE_ID","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ERC1155_INTERFACE_ID","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ERC20_INTERFACE_ID","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ERC721_INTERFACE_ID","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ZONE_INTERFACE_ID","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bytes4","name":"interfaceHash","type":"bytes4"}],"name":"checkInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"address","name":"seaportAddress","type":"address"}],"name":"getApprovalAddress","outputs":[{"internalType":"address","name":"","type":"address"},{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"includedTokens","type":"uint256[]"},{"internalType":"uint256","name":"targetIndex","type":"uint256"}],"name":"getMerkleProof","outputs":[{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"},{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"includedTokens","type":"uint256[]"}],"name":"getMerkleRoot","outputs":[{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"}],"name":"isPaymentToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"address","name":"seaportAddress","type":"address"}],"name":"isValidConduit","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"parameters","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Order","name":"order","type":"tuple"},{"internalType":"address","name":"seaportAddress","type":"address"}],"name":"isValidOrder","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"seaport","type":"address"},{"internalType":"address","name":"primaryFeeRecipient","type":"address"},{"internalType":"uint256","name":"primaryFeeBips","type":"uint256"},{"internalType":"bool","name":"checkCreatorFee","type":"bool"},{"internalType":"bool","name":"skipStrictValidation","type":"bool"},{"internalType":"uint256","name":"shortOrderDuration","type":"uint256"},{"internalType":"uint256","name":"distantOrderExpiration","type":"uint256"}],"internalType":"struct ValidationConfiguration","name":"validationConfiguration","type":"tuple"},{"components":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"parameters","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Order","name":"order","type":"tuple"}],"name":"isValidOrderWithConfiguration","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"orderParameters","type":"tuple"}],"name":"isValidZone","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"includedTokens","type":"uint256[]"}],"name":"sortMerkleTokens","outputs":[{"internalType":"uint256[]","name":"sortedTokens","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"orderParameters","type":"tuple"},{"internalType":"uint256","name":"considerationItemIndex","type":"uint256"},{"internalType":"address","name":"seaportAddress","type":"address"}],"name":"validateConsiderationItem","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"orderParameters","type":"tuple"},{"internalType":"uint256","name":"considerationItemIndex","type":"uint256"},{"internalType":"address","name":"seaportAddress","type":"address"}],"name":"validateConsiderationItemParameters","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"orderParameters","type":"tuple"},{"internalType":"address","name":"seaportAddress","type":"address"}],"name":"validateConsiderationItems","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contractOfferer","type":"address"}],"name":"validateContractOfferer","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"orderParameters","type":"tuple"},{"internalType":"uint256","name":"offerItemIndex","type":"uint256"},{"internalType":"address","name":"seaportAddress","type":"address"}],"name":"validateOfferItem","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"orderParameters","type":"tuple"},{"internalType":"uint256","name":"offerItemIndex","type":"uint256"},{"internalType":"address","name":"seaportAddress","type":"address"}],"name":"validateOfferItemApprovalAndBalance","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"orderParameters","type":"tuple"},{"internalType":"uint256","name":"offerItemIndex","type":"uint256"},{"internalType":"address","name":"seaportAddress","type":"address"}],"name":"validateOfferItemParameters","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"orderParameters","type":"tuple"},{"internalType":"address","name":"seaportAddress","type":"address"}],"name":"validateOfferItems","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"orderParameters","type":"tuple"},{"internalType":"address","name":"seaportAddress","type":"address"}],"name":"validateOrderStatus","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"orderParameters","type":"tuple"},{"components":[{"internalType":"bytes32","name":"orderHash","type":"bytes32"},{"internalType":"address","name":"fulfiller","type":"address"},{"internalType":"address","name":"offerer","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct SpentItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifier","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ReceivedItem[]","name":"consideration","type":"tuple[]"},{"internalType":"bytes","name":"extraData","type":"bytes"},{"internalType":"bytes32[]","name":"orderHashes","type":"bytes32[]"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"}],"internalType":"struct ZoneParameters","name":"zoneParameters","type":"tuple"}],"name":"validateOrderWithZone","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"parameters","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Order","name":"order","type":"tuple"},{"internalType":"address","name":"seaportAddress","type":"address"}],"name":"validateSignature","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"parameters","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct Order","name":"order","type":"tuple"},{"internalType":"uint256","name":"counter","type":"uint256"},{"internalType":"address","name":"seaportAddress","type":"address"}],"name":"validateSignatureWithCounter","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"orderParameters","type":"tuple"},{"internalType":"address","name":"primaryFeeRecipient","type":"address"},{"internalType":"uint256","name":"primaryFeeBips","type":"uint256"},{"internalType":"bool","name":"checkCreatorFee","type":"bool"}],"name":"validateStrictLogic","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"offerer","type":"address"},{"internalType":"address","name":"zone","type":"address"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"}],"internalType":"struct OfferItem[]","name":"offer","type":"tuple[]"},{"components":[{"internalType":"enum ItemType","name":"itemType","type":"uint8"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"identifierOrCriteria","type":"uint256"},{"internalType":"uint256","name":"startAmount","type":"uint256"},{"internalType":"uint256","name":"endAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ConsiderationItem[]","name":"consideration","type":"tuple[]"},{"internalType":"enum OrderType","name":"orderType","type":"uint8"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"bytes32","name":"zoneHash","type":"bytes32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"bytes32","name":"conduitKey","type":"bytes32"},{"internalType":"uint256","name":"totalOriginalConsiderationItems","type":"uint256"}],"internalType":"struct OrderParameters","name":"orderParameters","type":"tuple"},{"internalType":"uint256","name":"shortOrderDuration","type":"uint256"},{"internalType":"uint256","name":"distantOrderExpiration","type":"uint256"}],"name":"validateTime","outputs":[{"components":[{"internalType":"uint16[]","name":"errors","type":"uint16[]"},{"internalType":"uint16[]","name":"warnings","type":"uint16[]"}],"internalType":"struct ErrorsAndWarnings","name":"errorsAndWarnings","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"},{"internalType":"uint256","name":"valueToProve","type":"uint256"}],"name":"verifyMerkleProof","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]

6101c06040818152346200056557606082620061538038038091620000258285620005a2565b83398101031262000565576200003b82620005c6565b916020620000588362000050838501620005c6565b9301620005c6565b600782855162000068816200056a565b828152016614d9585c1bdc9d60ca1b81522060805260038285516200008d816200056a565b828152016218971960e91b8152209460a0958652845192808401956909ecccccae492e8cada560b31b87526e1d5a5b9d0e081a5d195b551e5c194b608a1b9586602a8701526d1859191c995cdcc81d1bdad95b8b60921b928360398801527f75696e74323536206964656e7469666965724f7243726974657269612c0000008060478901527f75696e74323536207374617274416d6f756e742c000000000000000000000000948560648a0152701d5a5b9d0c8d4d88195b99105b5bdd5b9d607a1b60788a0152602960f81b958660898b0152606a8a528c8a019260018060401b03928b8510848611176200054f5771086dedce6d2c8cae4c2e8d2dedc92e8cada560731b9c85895260c08d019d8e5260d28d015260e18c015260ef8b015261010c8a015261012095711d5a5b9d0c8d4d88195b99105b5bdd5b9d0b60721b878b0152701859191c995cdcc81c9958da5c1a595b9d607a1b6101328b0152806101438b015260848352620002018362000586565b85516f09ee4c8cae486dedae0dedccadce8e6560831b858201526f1859191c995cdcc81bd999995c995c8b60821b60308201526c1859191c995cdcc81e9bdb994b609a1b878201527113d999995c925d195b56d7481bd999995c8b60721b604d8201527f436f6e73696465726174696f6e4974656d5b5d20636f6e73696465726174696f605f820152611b8b60f21b607f8201526f1d5a5b9d0e081bdc99195c951e5c194b60821b6081820152711d5a5b9d0c8d4d881cdd185c9d151a5b594b60721b60918201526f1d5a5b9d0c8d4d88195b99151a5b594b60821b60a382015270189e5d195ccccc881e9bdb9952185cda0b607a1b60b38201526c1d5a5b9d0c8d4d881cd85b1d0b609a1b60c48201527f6279746573333220636f6e647569744b65792c0000000000000000000000000060d18201526e3ab4b73a191a9b1031b7bab73a32b960891b60e48201528160f382015260d481526101009c8d820190828210858311176200054f578189528c5190209c855190209b898301936c08a92a06e626488dedac2d2dc5609b1b85526b1cdd1c9a5b99c81b985b594b60a21b61012d8501526e1cdd1c9a5b99c81d995c9cda5bdb8b608a1b6101398501526f1d5a5b9d0c8d4d8818da185a5b92590b60821b6101488501527f6164647265737320766572696679696e67436f6e747261637400000000000000610158850152610171840152605282526101809c8d840195838710908711176200054f578f620004519f6200046d966200045895898e5251902060c05260e052526101a09d8e840196620004518886620005db565b90620005db565b0361019f198101835261017f190182620005a2565b519020845260c051906080518b519085519283019384528583015260608201524660808201526d06c7676171937c444f6bde3d62828b8201528a8152620004b48162000586565b5190209361014094855260018060a01b0391828092168952168652610160941684525195615b4a97886200060989396080518850505187505060c05187505060e05187615211015251866152e201525185615491015251845050518361297a015251828181610b6101528181610f530152818161107901528181611376015281816115c70152818161243601526150f101525181612fee0152f35b634e487b7160e01b600052604160045260246000fd5b600080fd5b604081019081106001600160401b038211176200054f57604052565b60c081019081106001600160401b038211176200054f57604052565b601f909101601f19168101906001600160401b038211908210176200054f57604052565b51906001600160a01b03821682036200056557565b9081519160005b838110620005f4575050016000815290565b8060208092840101518185015201620005e256fe608080604052600436101561001357600080fd5b60003560e01c9081630234cb0b146118da575080630f27ba8c14611738578063157b7e1714611671578063198380d01461165757806320c35eca1461163d57806326affb001461150f57806326fa0f89146114f5578063272b2ec1146114a35780632ca069a51461144a5780632f5d94d7146112cc578063377d77ac1461124b5780633b33d7e6146111e85780633d1c8a23146111845780634710042e14610fbf57806350b613bf14610ee857806350f9cb6314610e8657806359f4a90714610e2d57806361af055d14610d77578063638430f014610d1e578063666eff3814610d045780636bb89fc314610cea57806373d8ab3014610c91578063772fc56c14610c1a5780637e74774114610c0057806383f4127a14610aaf57806386250b331461037e578063b0517ff21461030e578063b0cedcb4146102b4578063cfec3dff146101f65763de6fe0901461016957600080fd5b346101f15760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15760043567ffffffffffffffff81116101f1576101d96101be6101ed923690600401611ae2565b6101c6611954565b906101cf611f84565b91604435916123b8565b6040519182916020835260208301906119d0565b0390f35b600080fd5b346101f1577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360161010081126101f15760e0136101f15760405161023a81611a19565b610242611931565b815261024c611954565b60208201526044356040820152610261611f84565b606082015260843580151581036101f157608082015260a43560a082015260c43560c082015260e43567ffffffffffffffff81116101f1576101ed916102ae6101d9923690600401611f29565b90611ffb565b346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15760043567ffffffffffffffff81116101f1576101d96103096101ed923690600401611ae2565b6125fb565b346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15760043560068110156101f157806103556020926121f1565b801590811561036a575b506040519015158152f35b60019150610377816121f1565b148261035f565b346101f1577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6040813601126101f15760043567ffffffffffffffff81116101f1576103ce903690600401611ae2565b9067ffffffffffffffff602435116101f15761014090602435360301126101f15760405190610140820182811067ffffffffffffffff821117610a80576040526024356004013582526104246024803501611977565b6020830152610437604460243501611977565b60408301526064602435013567ffffffffffffffff81116101f15760243501366023820112156101f15760048101359061047082611aca565b9161047e6040519384611a89565b80835260208301913660248360071b830101116101f1579160248301925b60248360071b8201018410610a0e575050505060608301526084602435013567ffffffffffffffff81116101f15736602382602435010112156101f1576104ea600482602435010135611aca565b906104f86040519283611a89565b6004602480358301918201358085526020850193923660a090920201909101116101f15760248181350101915b602480358301600481013560a002010183106109a057505050608083015260a4602435013567ffffffffffffffff81116101f15761056b90600436916024350101611ee2565b60a083015267ffffffffffffffff60c46024350135116101f15761059a3660243560c481013501600401611e16565b60c083015260243560e481013560e084015261010481013561010084015261012401356101208301526105cb611f93565b5073ffffffffffffffffffffffffffffffffffffffff6020604051926105f084611a51565b6000845260405161060081611a51565b6000815260405194610611866119fd565b855282850152610629610623826125fb565b85615523565b015116604051907f17b1f9420000000000000000000000000000000000000000000000000000000060208301526020602483015261018482018451604484015273ffffffffffffffffffffffffffffffffffffffff602086015116606484015273ffffffffffffffffffffffffffffffffffffffff604086015116608484015260608501519061014060a4850152815180915260206101a4850192019060005b81811061094b5750505060808501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc8483030160c48501526020808251938481520191019160005b8181106108e8575050610754915060a08601517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc8583030160e4860152612d45565b9360c0810151947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc848203016101048501526020808751928381520196019060005b8181106108d257505050826107fd94956101208360e06107f89501516101248501526101008101516101448501520151610164830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101845283611a89565b615a91565b1561081b575b6101ed906040519182916020835260208301906119d0565b610823611f93565b5060208101519081516001908181018091116108a35761084290611fac565b906000815b61086c575b505061057961085f6101ed945183612d31565b5260208201529050610803565b845181101561089e578061ffff6108866108989388612d31565b51166108928286612d31565b52613a29565b81610847565b61084c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8251885260209788019790920191600101610796565b9091602060a060019273ffffffffffffffffffffffffffffffffffffffff608088518051610915816121f1565b84528286820151168685015260408101516040850152606081015160608501520151166080820152019401910192919092610712565b90919260206080600192606087518051610964816121f1565b83528085015173ffffffffffffffffffffffffffffffffffffffff168584015260408082015190840152015160608201520194019291016106c9565b60a0833603126101f157604051906109b782611a35565b6006843510156101f157602060a091602493863581526109d8838801611977565b83820152604087013560408201526060870135606082015260806109fd818901611977565b908201528152019301929050610525565b60809182853603126101f15760405192838181011067ffffffffffffffff8286011117610a805783016040526006853510156101f157602060809160249487358152610a5b838901611977565b838201526040880135604082015260608089013590820152815201940193915061049c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15767ffffffffffffffff6004358181116101f1576000610b04610b48923690600401611e16565b610b0c611f93565b50604051809381927f83f4127a000000000000000000000000000000000000000000000000000000008352602060048401526024830190611e74565b038173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa918215610bf457600091600093610bb3575b50506101ed60405192839283526040602084015260408301906119d0565b915091503d806000833e610bc78183611a89565b81016040828203126101f15781519260208301519081116101f157610bec9201612175565b908280610b95565b6040513d6000823e3d90fd5b346101f1576101ed6101d9610c1436611d38565b906136c1565b346101f15760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15773ffffffffffffffffffffffffffffffffffffffff6101ed610c74610c6c611954565b600435612916565b6040929192519384931683526040602084015260408301906119d0565b346101f15760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15760206040517f1be900b1000000000000000000000000000000000000000000000000000000008152f35b346101f1576101ed6101d9610cfe36611d38565b90615084565b346101f1576101ed6101d9610d1836611da5565b91614718565b346101f15760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15760206040517f3839be19000000000000000000000000000000000000000000000000000000008152f35b346101f15760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f157610dae611931565b602435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036101f157602091610e2391604051917f01ffc9a70000000000000000000000000000000000000000000000000000000085840152602483015260248252610e1e82611a6d565b6158aa565b6040519015158152f35b346101f15760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15760206040517f80ac58cd000000000000000000000000000000000000000000000000000000008152f35b346101f15760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15760043567ffffffffffffffff81116101f1576101d9610edb6101ed923690600401611ae2565b6044359060243590613401565b346101f1576000610ef836611da5565b9291610f02611f93565b50610f3a60405194859384937f50b613bf00000000000000000000000000000000000000000000000000000000855260048501615125565b038173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa8015610bf4576101ed91600091610f9c575b506040519182916020835260208301906119d0565b610fb991503d806000833e610fb18183611a89565b8101906121cb565b82610f87565b346101f15760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15767ffffffffffffffff6004358181116101f1576000611014611058923690600401611e16565b61101c611f93565b50604051809381927f4710042e000000000000000000000000000000000000000000000000000000008352604060048401526044830190611e74565b6024356024830152038173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa918215610bf4576000916000936110d7575b6110c9836101ed86604051938493604085526040850190611e74565b9083820360208501526119d0565b915091503d806000833e6110eb8183611a89565b8101916040828403126101f15781518181116101f15782019183601f840112156101f157825161111a81611aca565b936111286040519586611a89565b818552602091828087019160051b830101918783116101f15783809101915b83831061117457505050508101519182116101f1576110c9936101ed9261116e9201612175565b926110ad565b8251815291810191849101611147565b346101f15760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f1576101ed6111d26111c1611954565b6111c9611f93565b50600435612916565b90506040519182916020835260208301906119d0565b346101f15760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15760043567ffffffffffffffff81116101f1576101d961123d6101ed923690600401611f29565b611245611954565b90612c16565b346101f15760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15760043567ffffffffffffffff81116101f15761129a903690600401611f29565b6044359073ffffffffffffffffffffffffffffffffffffffff821682036101f1576101ed916101d99160243590612d88565b346101f1576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15767ffffffffffffffff906004358281116101f157600061132361135d923690600401611e16565b604051809381927f2f5d94d70000000000000000000000000000000000000000000000000000000083528660048401526024830190611e74565b038173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa928315610bf4576000936113bd575b50506101ed604051928284938452830190611e74565b909192503d806000843e6113d18184611a89565b82019183818403126101f15780519182116101f157019080601f830112156101f1578151916113ff83611aca565b9261140d6040519485611a89565b808452848085019160051b8301019283116101f15784809201905b83821061143b57505050509082806113a7565b81518152908201908201611428565b346101f15760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15760206040517fd9b67a26000000000000000000000000000000000000000000000000000000008152f35b346101f15760006114b336611da5565b92916114bd611f93565b50610f3a60405194859384937f272b2ec100000000000000000000000000000000000000000000000000000000855260048501615125565b346101f1576101ed6101d961150936611da5565b91613dd9565b346101f15760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15760243567ffffffffffffffff81116101f15760206115636115a6923690600401611e16565b604051809381927f26affb000000000000000000000000000000000000000000000000000000000083526004356004840152606060248401526064830190611e74565b6044356044830152038173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa8015610bf457600090611604575b6020906040519015158152f35b506020813d8211611635575b8161161d60209383611a89565b810103126101f157611630602091612909565b6115f7565b3d9150611610565b346101f1576101ed6101d961165136611da5565b91613d6e565b346101f1576101ed6101d961166b36611d38565b90613a56565b346101f1577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6040813601126101f1576004359067ffffffffffffffff82116101f15760409082360301126101f1576101d96101ed916102ae6116d2611954565b916116db611f93565b5073ffffffffffffffffffffffffffffffffffffffff604051936116fe85611a19565b1683526000602084015260006040840152600060608401526000608084015261070860a084015262eff10060c08401523690600401611f29565b346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f1576101ed611772611931565b61177a611f93565b506040519061178882611a51565b6000825273ffffffffffffffffffffffffffffffffffffffff6000604051926117b084611a51565b818452604051946117c0866119fd565b85526020850193845261182e6040517f01ffc9a70000000000000000000000000000000000000000000000000000000060208201527f1be900b10000000000000000000000000000000000000000000000000000000060248201526024815261182881611a6d565b826158aa565b156118c0575b6004604051809481937f2e778efc000000000000000000000000000000000000000000000000000000008352165afa908161189e575b5061189857611877611f93565b5061188281516155cd565b90526040519182916020835260208301906119d0565b506101d9565b6118ba903d806000833e6118b28183611a89565b8101906124d7565b5061186a565b6118c8611f93565b506118d384516155cd565b8452611834565b346101f15760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f157807f36372b070000000000000000000000000000000000000000000000000000000060209252f35b6004359073ffffffffffffffffffffffffffffffffffffffff821682036101f157565b6024359073ffffffffffffffffffffffffffffffffffffffff821682036101f157565b359073ffffffffffffffffffffffffffffffffffffffff821682036101f157565b90815180825260208080930193019160005b8281106119b8575050505090565b835161ffff16855293810193928101926001016119aa565b6119fa9160206119e98351604084526040840190611998565b920151906020818403910152611998565b90565b6040810190811067ffffffffffffffff821117610a8057604052565b60e0810190811067ffffffffffffffff821117610a8057604052565b60a0810190811067ffffffffffffffff821117610a8057604052565b6020810190811067ffffffffffffffff821117610a8057604052565b6060810190811067ffffffffffffffff821117610a8057604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610a8057604052565b67ffffffffffffffff8111610a805760051b60200190565b9190916101609081818503126101f15760409384519283019067ffffffffffffffff9184811083821117610a805786528395611b1d84611977565b85526020611b2c818601611977565b81870152818501358481116101f15785019280601f850112156101f157833593611b5585611aca565b90611b6285519283611a89565b8582528382018460a0809802830101918483116101f1578501905b828210611cdb5750505083880152606091828701358681116101f15787019180601f840112156101f157823596611bb388611aca565b95611bc081519788611a89565b888752838701928460c0809b02870101958187116101f1578501935b868510611c3c5750505050505050850152608083013560058110156101f15760808501528083013590840152808201359083015260e081013560e08301526101008082013590830152610120808201359083015261014080910135910152565b8a858303126101f1578251908b820182811086821117611cad57845285359060068210156101f1578288928e9452611c75838901611977565b8382015285880135868201528a8801358b82015260808089013590820152611c9e8d8901611977565b8d820152815201940193611bdc565b602460007f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b87828603126101f157865190611cf082611a35565b82359060068210156101f1578288928b9452611d0d838601611977565b83820152898501358a8201526060808601359082015260808086013590820152815201910190611b7d565b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8201126101f1576004359067ffffffffffffffff82116101f157611d8191600401611ae2565b9060243573ffffffffffffffffffffffffffffffffffffffff811681036101f15790565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8201126101f1576004359067ffffffffffffffff82116101f157611dee91600401611ae2565b906024359060443573ffffffffffffffffffffffffffffffffffffffff811681036101f15790565b81601f820112156101f157803591611e2d83611aca565b92611e3b6040519485611a89565b808452602092838086019260051b8201019283116101f1578301905b828210611e65575050505090565b81358152908301908301611e57565b90815180825260208080930193019160005b828110611e94575050505090565b835185529381019392810192600101611e86565b67ffffffffffffffff8111610a8057601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b81601f820112156101f157803590611ef982611ea8565b92611f076040519485611a89565b828452602083830101116101f157816000926020809301838601378301015290565b91906040838203126101f15760405190611f42826119fd565b819380359167ffffffffffffffff928381116101f15781611f64918401611ae2565b845260208201359283116101f157602092611f7f9201611ee2565b910152565b6064359081151582036101f157565b60405190611fa0826119fd565b60606020838281520152565b90611fb682611aca565b611fc36040519182611a89565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0611ff18294611aca565b0190602036910137565b919091612006611f93565b5060405161201381611a51565b6000815260405161202381611a51565b6000815260405191612034836119fd565b82526020820152809361205b612055825160a086015160c087015191613401565b83615523565b805161208961208373ffffffffffffffffffffffffffffffffffffffff9283875116906136c1565b84615523565b61209b61208383518387511690613a56565b6120ad61208383518387511690615084565b6120ba61208383516125fb565b6120ca6120838286511684612c16565b6080840151156120db575b50505050565b612103936120fd925191602082015116606060408301519201511515926123b8565b90615523565b388080806120d5565b81601f820112156101f15780519161212383611aca565b926121316040519485611a89565b808452602092838086019260051b8201019283116101f1578301905b82821061215b575050505090565b815161ffff811681036101f157815290830190830161214d565b91906040838203126101f1576040519061218e826119fd565b819380519167ffffffffffffffff928381116101f157816121b091840161210c565b845260208201519283116101f157602092611f7f920161210c565b906020828203126101f157815167ffffffffffffffff81116101f1576119fa9201612175565b600611156121fb57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600511156121fb57565b90610160918282019273ffffffffffffffffffffffffffffffffffffffff90818351168452602082818501511681860152604095868501519287870152825180915281610180870193019060005b8181106123675750505060608085015196868403828801528280895195868152019801946000925b85841061230c575050505050505060808101516122c68161222a565b608083015260a081015160a083015260c081015160c083015260e081015160e0830152610100808201519083015261012080820151908301526101408091015191015290565b909192939495988560c06001928c518051612326816121f1565b825280840151871684830152878101518883015285810151868301526080808201519083015260a090810151871690820152019a01969594019291906122aa565b9091949792938460a060019288518051612380816121f1565b8252808401518d168483015287810151888301526060808201519083015260809081015190820152959a979501959401929101612282565b9061240860009394926123c9611f93565b50604051958694859384937fde6fe090000000000000000000000000000000000000000000000000000000008552608060048601526084850190612234565b9173ffffffffffffffffffffffffffffffffffffffff809616602485015260448401521515606483015203917f0000000000000000000000000000000000000000000000000000000000000000165afa908115610bf45760009161246a575090565b6119fa913d8091833e610fb18183611a89565b60005b8381106124905750506000910152565b8181015183820152602001612480565b909291926124ad81611ea8565b916124bb6040519384611a89565b8294828452828201116101f15760206124d593019061247d565b565b919060409081848203126101f157835167ffffffffffffffff908181116101f15785019180601f840112156101f15761251681845160208096016124a0565b9583810151908382116101f157019181601f840112156101f15782519061253c82611aca565b9561254981519788611a89565b828752858088019360051b860101948486116101f157868101935b86851061257657505050505050505090565b84518481116101f157820190837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe083890301126101f1578351916125b9836119fd565b89810151835284810151908682116101f157019087603f830112156101f15789926125ec898488878097015191016124a0565b83820152815201940193612564565b90612604611f93565b506040519161261283611a51565b60008084526040519161262483611a51565b81835260405194612634866119fd565b8552602092838601528460808201600260ff82516126518161222a565b61265a8161222a565b16109081156128e7575b506128e05750820173ffffffffffffffffffffffffffffffffffffffff90818151161561283957818151163b15612792576126f882825116604051907f01ffc9a700000000000000000000000000000000000000000000000000000000878301527f3839be1900000000000000000000000000000000000000000000000000000000602483015260248252610e1e82611a6d565b15612772579180916004935116604051938480927f2e778efc0000000000000000000000000000000000000000000000000000000082525afa918261275a575b505061275757612746611f93565b5082016127538151615629565b9052565b50565b61276d913d8091833e6118b28183611a89565b612738565b505050612780929192611f93565b50810161278d8151615629565b905290565b5050906127a0939293611f93565b5082018051805160019081810180911161280c576127be8291611fac565b94905b6127db575b50506127d661057b915184612d31565b525290565b8251811015612807578061ffff6127f56128019386612d31565b51166108928288612d31565b816127c1565b6127c6565b6024857f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b50509050612848929192611f93565b50815180516001908181018091116128b3576128648291611fac565b93905b612882575b505061287c61057a915183612d31565b52815290565b82518110156128ae578061ffff61289c6128a89386612d31565b51166108928287612d31565b81612867565b61286c565b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b9450505050565b6004915060ff90516128f88161222a565b6129018161222a565b161438612664565b519081151582036101f157565b919091612921611f93565b50604080519361293085611a51565b600091828652805161294181611a51565b838152815196612950886119fd565b875260209081880152868515612c0b575073ffffffffffffffffffffffffffffffffffffffff92837f000000000000000000000000000000000000000000000000000000000000000016958351907f6e9bfd9f000000000000000000000000000000000000000000000000000000008252600482015283816024818a5afa948515612c015786918796612bb6575b5050958415612b1b575b84612a63575b505050506129fb57509190565b612a03611f93565b50835180516001908181018091116128b357612a1f8291611fac565b93905b612a3e575b5050612a376103e9915183612d31565b5283529190565b8251811015612a5e578061ffff61289c612a589386612d31565b81612a22565b612a27565b83517f33bc857200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8881166004830152929092166024830152929350918190839060449082905afa928315612b1257508392612ad8575b505015388080806129ee565b90809250813d8311612b0b575b612aef8183611a89565b81010312612b0757612b0090612909565b3880612acc565b5080fd5b503d612ae5565b513d85823e3d90fd5b9550612b25611f93565b508751805190600191828101809111612b8957612b4190611fac565b9187815b612b64575b5050612b5a6103e8915183612d31565b52885284956129e8565b8251811015612b84578061ffff61289c612b7e9386612d31565b81612b45565b612b4a565b6024887f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b85809297508193503d8311612bfa575b612bd08183611a89565b81010312612bf65780519485168503612bf65782612bee9101612909565b9338806129de565b8580fd5b503d612bc6565b84513d88823e3d90fd5b965050509150509190565b9190612c20611f93565b5073ffffffffffffffffffffffffffffffffffffffff92602084825151166024604051809781937ff07ec373000000000000000000000000000000000000000000000000000000008352600483015286165afa938415610bf457600094612c8e575b50926119fa9293612d88565b6020813d8211612cbd575b81612ca660209383611a89565b81010312612cb9575193506119fa612c82565b8480fd5b3d9150612c99565b91908260809103126101f157612cda82612909565b91612ce760208201612909565b916060604083015192015190565b805115612d025760200190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8051821015612d025760209160051b010190565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602093612d818151809281875287808801910161247d565b0116010190565b9091612d92611f93565b5060ff6040805192612da384611a51565b600094858552825192612db584611a51565b868452805195612dc4876119fd565b8652602092838701948552869873ffffffffffffffffffffffffffffffffffffffff809216906080968786510151612dfb8161222a565b612e048161222a565b60049916891461334e575b508285515116988451997ff07ec373000000000000000000000000000000000000000000000000000000008b52898b015260249987818c81875afa908115613344578c91613313575b5082811115612ef957505050505050505050612e72611f93565b50835191825190600192838301809311612ecf575050612e928291611fac565b93905b612eaa575b505061287c61044e915183612d31565b8251811015612eca578061ffff61289c612ec49386612d31565b81612e95565b612e9a565b601186917f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b82909d9c9d9a999a106132a35750612f129085516151ec565b8351907f46423aa70000000000000000000000000000000000000000000000000000000082528982015286818981855afa908115613299578a91613269575b5061325e579184918151612f64816119fd565b6001978882528b5b8581106131a557505085612f7f82612cf5565b52612f8981612cf5565b508a83519586947f7509063800000000000000000000000000000000000000000000000000000000865260448601918d870152808c8701528351809252606486018760648460051b890101950193915b8c8484106131395750505050505082809103917f0000000000000000000000000000000000000000000000000000000000000000165afa8791816130fe575b506130e85750516101406060820151519101510361304d575b505050505061303e611f93565b506130498251615681565b8252565b613055611f93565b508601928351928351918383018093116130be5750506130758291611fac565b94905b613099575b505061308d610450915184612d31565b52523880808080613031565b82518110156130b9578061ffff6127f56130b39386612d31565b81613078565b61307d565b601187917f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b95505050505050156130f657565b61303e611f93565b9091508381813d8311613132575b6131168183611a89565b8101031261312e5761312790612909565b9038613018565b8780fd5b503d61310c565b9295807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c8b94979a613193939c94979a9c0301875289519083613183835189845289840190612234565b9201519084818403910152612d45565b9701930193018795938a979592612fd9565b9091938096939550516131b7816119fd565b8651610160810181811067ffffffffffffffff821117613232578a9392918f918a528181528185820152606091828b830152828083015280878301528060a08301528060c08301528060e083015280610100830152806101208301526101408201528252838201528282870101520190879492959391612f6c565b508b8e60418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b505050505050505050565b6132899150873d8911613292575b6132818183611a89565b810190612cc5565b50505038612f51565b503d613277565b84513d8c823e3d90fd5b9a9b5050505050505050906132b6611f93565b50835191825190600192838301809311612ecf5750506132d68291611fac565b93905b6132ee575b505061287c61044f915183612d31565b825181101561330e578061ffff61289c6133089386612d31565b816132d9565b6132de565b90508781813d831161333d575b61332a8183611a89565b81010312613339575138612e58565b8b80fd5b503d613320565b86513d8e823e3d90fd5b613356611f93565b508051908151916001928381018091116133bb5792806133768f95611fac565b94905b613396575b505061338e61044d915184612d31565b525238612e0f565b82518110156133b6578061ffff6127f56133b09386612d31565b81613379565b61337e565b60248e60118e7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b919082018092116108a357565b919082039182116108a357565b9061340a611f93565b506040519161341883611a51565b60009283815260405161342a81611a51565b8481526040519161343a836119fd565b82526020820152809460c083019160a083519401938451101561365a5750815190428210156134c9575050505050613470611f93565b50815180516001908181018091116128b35761348c8291611fac565b93905b6134a4575b505061287c610385915183612d31565b82518110156134c4578061ffff61289c6134be9386612d31565b8161348f565b613494565b6134d690979697426133e7565b106135ec575b42825111613574575b5190516134fb91904281111561356c57906133f4565b106135035750565b61350b611f93565b50602083018051805160019081810180911161280c5761352b8291611fac565b94905b613547575b5050613543610388915184612d31565b5252565b8251811015613567578061ffff6127f56135619386612d31565b8161352e565b613533565b5042906133f4565b61357c611f93565b5060208601805190815191600192838101809111612b895761359d90611fac565b9287815b6135c7575b5050906103876135bd6134fb969594935184612d31565b52529091506134e5565b82518110156135e7578061ffff6127f56135e19386612d31565b816135a1565b6135a6565b6135f4611f93565b5060208601805190815191600192838101809111612b895761361590611fac565b9287815b613635575b505061362e610386915184612d31565b52526134dc565b8251811015613655578061ffff6127f561364f9386612d31565b81613619565b61361e565b955050505050613668611f93565b50815180516001908181018091116128b3576136848291611fac565b93905b61369c575b505061287c610384915183612d31565b82518110156136bc578061ffff61289c6136b69386612d31565b81613687565b61368c565b9190916136cc611f93565b5060409060ff8251916136de83611a51565b6000938484528051916136f083611a51565b8583528151946136ff866119fd565b855260208501928352849773ffffffffffffffffffffffffffffffffffffffff8091169360808301516137318161222a565b61373a8161222a565b600496168614613992575b508151168251907ff07ec37300000000000000000000000000000000000000000000000000000000825285820152602081602481875afa908115613988578791613952575b50613797906080926151ec565b60248351809581937f46423aa7000000000000000000000000000000000000000000000000000000008352888301525afa90811561394957508485928692613924575b5061388e575b8015159182613884575b50506137f557505050565b6137fd611f93565b508151908151600191828201809211613858575061381b8291611fac565b94905b613833575b5050613543610321915184612d31565b8251811015613853578061ffff6127f561384d9386612d31565b8161381e565b613823565b8560116024927f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b14905038806137ea565b613896611f93565b5083518051906001918281018091116138f8576138b290611fac565b9187815b6138d3575b50506138cb610320915183612d31565b5284526137e0565b82518110156138f3578061ffff61289c6138ed9386612d31565b816138b6565b6138bb565b6024886011887f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b91505061393f915060803d8111613292576132818183611a89565b92509190386137da565b513d86823e3d90fd5b90506020813d8211613980575b8161396c60209383611a89565b8101031261397c5751608061378a565b8680fd5b3d915061395f565b83513d89823e3d90fd5b61399a611f93565b508051908151916001928381018091116139fd576139b790611fac565b928a815b6139d8575b50506139d0610322915184612d31565b525238613745565b82518110156139f8578061ffff6127f56139f29386612d31565b816139bb565b6139c0565b60248b60118b7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146108a35760010190565b9190613a60611f93565b5060408051613a6e81611a51565b600091828252805193613a8085611a51565b838552815192613a8f846119fd565b835260209687840195865283855b848301805151821015613c5357613abe613ab8868487613d6e565b88615523565b613ac9828251612d31565b51600191828401808511613c26578d9493929185830191845b613afb575b5050505050613af69150613a29565b613a9d565b8151968751821015613c1f57613b1382879899612d31565b519073ffffffffffffffffffffffffffffffffffffffff808651169183015116149081613c0e575b50613b52575b613b4a90613a29565b8f9695613ae2565b9091929350613b5f611f93565b508a518051868101809111613be157869594939291868f92613b8090611fac565b92905b613ba6575b509061025c613b9c613b4a94935183612d31565b528d529050613b41565b819293949596979151811015613bd4578061ffff61289c613bc79386612d31565b8197969594939291613b83565b9695949392919096613b88565b60248e7f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b90508b808601519101511438613b3b565b9650613ae7565b60248b7f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b50509750919250509291920180515115613cd7575b60018091515111613c7857505050565b613c80611f93565b50815190815181810180911161280c57613c9a8291611fac565b94905b613cb2575b505061354361025a915184612d31565b8251811015613cd2578061ffff6127f5613ccc9386612d31565b81613c9d565b613ca2565b613cdf611f93565b508151805190600191828101809111613d4157613cfb90611fac565b9185815b613d1c575b5050613d14610258915183612d31565b528252613c68565b8251811015613d3c578061ffff61289c613d369386612d31565b81613cff565b613d04565b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b929190613d79611f93565b50613d85828286613dd9565b93845151613d9b5791612055916124d593614718565b505050565b8115613daa570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b92919092613de5611f93565b5060408051613df381611a51565b600091828252805194613e0586611a51565b838652815192613e14846119fd565b835260209586840152613e2b839883870151612d31565b519460608601938451158061470c575b6146a1575083519260808701938451908181141580614690575b614500575b505060028751613e69816121f1565b613e72816121f1565b03613f60575050506001808093511491821592613f54575b5050613ece575b50500151613eb49073ffffffffffffffffffffffffffffffffffffffff1661515e565b15613ebb57565b613ec3611f93565b506130498251615731565b613ed6611f93565b5085519081518181018091116128b357613ef08291611fac565b93905b613f2f575b505091613eb4939161012c613f2373ffffffffffffffffffffffffffffffffffffffff955183612d31565b52865291819350613e91565b8251811015613f4f578061ffff61289c613f499386612d31565b81613ef3565b613ef8565b51141590508138613e8a565b869194959792965196613f72886121f1565b613f7b886121f1565b60049788036140aa5750500151613fa79073ffffffffffffffffffffffffffffffffffffffff1661515e565b15614090575b60018080945111918215614085575b5050613fc85750505050565b608082910151613fd78161222a565b613fe08161222a565b1615613fed575b806120d5565b613ff5611f93565b5084519182519082820180921161405957506140118291611fac565b93905b614034575b5050614029610131915183612d31565b528252388080613fe7565b8251811015614054578061ffff61289c61404e9386612d31565b81614014565b614019565b8460116024927f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b511190508238613fbc565b614098611f93565b506140a38751615731565b8752613fad565b92945092509350600384516140be816121f1565b6140c7816121f1565b1480156144e3575b156141bd57507f01ffc9a70000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff8361414c950151169151928301527fd9b67a2600000000000000000000000000000000000000000000000000000000602483015260248252610e1e82611a6d565b15614155575050565b61415d611f93565b508351908151600191828201809211614059575061417b8291611fac565b93905b614198575b5050614193610190915183612d31565b528252565b82518110156141b8578061ffff61289c6141b29386612d31565b8161417e565b614183565b8392919251936141cc856121f1565b6141d5856121f1565b60019485036143c357838101516142e1575b82015192517fdd62ed3e000000000000000000000000000000000000000000000000000000009281019290925273ffffffffffffffffffffffffffffffffffffffff908116602483018190526044830152614277921661427282606481015b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101845283611a89565b615a07565b1561428157505050565b614289611f93565b5084519182519082820180921161405957506142a58291611fac565b93905b6142bc575b505061419360c9915183612d31565b82518110156142dc578061ffff61289c6142d69386612d31565b816142a8565b6142ad565b6142e9611f93565b5088518051868101809111614397576143028b91611fac565b91878a815b614372575b50509373ffffffffffffffffffffffffffffffffffffffff86614272957fdd62ed3e0000000000000000000000000000000000000000000000000000000098956142469560c86143616142779d9b5184612d31565b5252955050509395505092506141e7565b8251811015614392578061ffff6127f561438c9386612d31565b81614307565b61430c565b60248960118a7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b9173ffffffffffffffffffffffffffffffffffffffff915082015116614450575b01516143ef57505050565b6143f7611f93565b5084519182519082820180921161405957506144138291611fac565b93905b61442b575b5050614193610515915183612d31565b825181101561444b578061ffff61289c6144459386612d31565b81614416565b61441b565b614458611f93565b50865180518481018091116144b75761447090611fac565b908487815b614492575b505061448a610514915183612d31565b5287526143e4565b82518110156144b2578061ffff61289c6144ac9386612d31565b81614475565b61447a565b6024876011887f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b50600584516144f1816121f1565b6144fa816121f1565b146140cf565b8181111561468a575b61451382826133f4565b61452660c086015160a0870151906133f4565b906402540be4009081810291818304149015171561460b579061454891613da0565b6127109182810292818404149015171561465d5766038d7ea4c68000929161456f91613da0565b6101168111156146385750614582611f93565b5061458d8c516156d9565b8c525b111561459e575b3880613e5a565b6145a6611f93565b50878a0180519081519160019283810180911161460b576145c690611fac565b9289815b6145e6575b50506145df61025e915184612d31565b5252614597565b8251811015614606578061ffff6127f56146009386612d31565b816145ca565b6145cf565b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b601c101561459057614648611f93565b50898c0161465681516156d9565b9052614590565b6024897f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b90614509565b5060c084015160a085015110613e55565b979850505050509150506146b3611f93565b50815180516001908181018091116128b3576146cf8291611fac565b93905b6146e7575b505061287c610259915183612d31565b8251811015614707578061ffff61289c6147019386612d31565b816146d2565b6146d7565b50608087015115613e3b565b90929192614724611f93565b50604091825161473381611a51565b60009283825284519061474582611a51565b848252855192614754846119fd565b83526020918284015261476d8398610120860151612916565b61477981869396615523565b515161507a575061478d9086850151612d31565b51926002845161479c816121f1565b6147a5816121f1565b036149b25773ffffffffffffffffffffffffffffffffffffffff92868484870151169501818151976148158a517f6352211e000000000000000000000000000000000000000000000000000000008882015260249a8b8201528a815261480a81611a6d565b88875116908a615973565b15614900575b5061485f91518951907f081812fc00000000000000000000000000000000000000000000000000000000878301528982015288815261485981611a6d565b87615973565b1561486e575b50505050505050565b6148d4967fe985e9c50000000000000000000000000000000000000000000000000000000096610e1e956142469451169151978895860152840190602090939293604083019473ffffffffffffffffffffffffffffffffffffffff809216845216910152565b156148e6575b38808080808080614865565b6148ee611f93565b506148f982516157e1565b82526148da565b905061490a611f93565b508a51805160019081810180911161498657918161492b8795939694611fac565b92955b614950575b5061485f945061494761012f915183612d31565b528c529161481b565b9193819395915182101561497b57508061ffff61289c6149709386612d31565b93918186949261492e565b939185939150614933565b8a847f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b949192909381516149c2816121f1565b6149cb816121f1565b6004908103614a56575050830151935190517fe985e9c5000000000000000000000000000000000000000000000000000000009381019390935273ffffffffffffffffffffffffffffffffffffffff90811660248401529081166044830152614a3c9216610e1e8260648101614246565b15614a4357565b614a4b611f93565b5061304982516157e1565b94929095939160038151614a69816121f1565b614a72816121f1565b03614c425780840151855183517fe985e9c5000000000000000000000000000000000000000000000000000000008188015273ffffffffffffffffffffffffffffffffffffffff9182166024820152948116604486015290811693839190614b0f90614b0981606481015b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611a89565b866158aa565b15614c28575b6060830151608084015180821015614c205750965b5116910151907efdd58e000000000000000000000000000000000000000000000000000000008351958601526024850152604484015260448352608083019083821067ffffffffffffffff831117614bf45752614b88929190615a45565b15614b91575050565b614b99611f93565b5083519081516001918282018092116140595750614bb78291611fac565b93905b614bcf575b5050614193610192915183612d31565b8251811015614bef578061ffff61289c614be99386612d31565b81614bba565b614bbf565b6024876041887f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b905096614b2a565b614c30611f93565b50614c3b8b51615789565b8b52614b15565b91929394600583999897929951614c58816121f1565b614c61816121f1565b03614ced575050820151925195517fe985e9c5000000000000000000000000000000000000000000000000000000009281019290925273ffffffffffffffffffffffffffffffffffffffff95861660248301528516604482015292939192614cd392909116610e1e8260648101614246565b15614cda57565b614ce2611f93565b506130498251615789565b9391909497815193614cfe856121f1565b614d07856121f1565b6001948503614f3c579089939291614db273ffffffffffffffffffffffffffffffffffffffff958692614dac8488880151169660806060820151910151808210600014614f3257509889935b5187517fdd62ed3e000000000000000000000000000000000000000000000000000000008b82015273ffffffffffffffffffffffffffffffffffffffff9290911682166024820152921660448301528160648101614add565b85615a45565b15614e6c575b7f70a082310000000000000000000000000000000000000000000000000000000090614e02969798999a9b5116915193840152602483015260248252614dfd82611a6d565b615a45565b15614e0c57505050565b614e14611f93565b508451918251908282018092116140595750614e308291611fac565b93905b614e47575b505061419360cb915183612d31565b8251811015614e67578061ffff61289c614e619386612d31565b81614e33565b614e38565b614e74611f93565b5089518051878101809111614f0657614e8c90611fac565b9089885b614ee0575b509b7f70a0823100000000000000000000000000000000000000000000000000000000929160ca614ecf614e029a9b9c9d9e9f5183612d31565b528d529b9a99989796509050614db8565b8151811015614f0157614efb8161ffff61289c8c9486612d31565b90614e90565b614e95565b60248a60118b7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b9050988993614d53565b5050806080606073ffffffffffffffffffffffffffffffffffffffff939a94959798999a01519101518082106000146150725750915b51163110614fdf575b614f83611f93565b508501918251918251908282018092116138585750614fa28291611fac565b94905b614fba575b505061354361025b915184612d31565b8251811015614fda578061ffff6127f5614fd49386612d31565b81614fa5565b614faa565b614fe7611f93565b508551805184810180911161504657614fff90611fac565b908486815b615021575b5050615019610516915183612d31565b528652614f7b565b8251811015615041578061ffff61289c61503b9386612d31565b81615004565b615009565b6024866011867f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b905091614f72565b9750505050505050565b6000906150d092615093611f93565b5060405180809581947f6bb89fc3000000000000000000000000000000000000000000000000000000008352604060048401526044830190612234565b73ffffffffffffffffffffffffffffffffffffffff809416602483015203917f0000000000000000000000000000000000000000000000000000000000000000165afa908115610bf45760009161246a575090565b91939273ffffffffffffffffffffffffffffffffffffffff90615152604093606086526060860190612234565b95602085015216910152565b6119fa90604051907f01ffc9a70000000000000000000000000000000000000000000000000000000060208301527f80ac58cd00000000000000000000000000000000000000000000000000000000602483015260248252610e1e82611a6d565b805160208092019160005b8281106151d8575050505090565b8351855293810193928101926001016151ca565b919060408301916151fe835151611fac565b9161014085019061520f8251611fac565b7f00000000000000000000000000000000000000000000000000000000000000009660005b875180518210156152d357908961524e826152ce94612d31565b51805161525a816121f1565b60209173ffffffffffffffffffffffffffffffffffffffff83820151169060408101519060609283820151936080809301519560405197880198895261529f816121f1565b604088015286015284015260a083015260c0908183015281526152c181611a19565b519020610892828a612d31565b615234565b505093929550939095506000957f0000000000000000000000000000000000000000000000000000000000000000965b86518110156153c6576060908861531d8284890151612d31565b519283519061532b826121f1565b73ffffffffffffffffffffffffffffffffffffffff90602095828782015116916040820151908083015193608091828501519660a08096015116976040519b8c01998a52615378816121f1565b60408c01528a015288015286015260c085015260e09081850152835261010083019280841067ffffffffffffffff851117610a80576153c1936040525190206108928289612d31565b615303565b509392919550935073ffffffffffffffffffffffffffffffffffffffff9384825116946020830151169260405191826154036020820180936151bf565b03926154357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe094858101835282611a89565b5190209161545b604051918261544f6020820180966151bf565b03908101835282611a89565b519020608083015161546c8161222a565b60a08401519060c08501519260e086015194610120610100880151970151976040519a7f000000000000000000000000000000000000000000000000000000000000000060208d015260408c015260608b015260808a015260a08901526154d28161222a565b60c088015260e0870152610100860152610120850152610140840152610160830152610180908183015281526101a0810181811067ffffffffffffffff821117610a80576040526020815191012090565b6020612753916155368151855190615543565b8152019160208351910151905b80518061554f57505090565b8251156155c75761556561556a918451906133e7565b611fac565b9260005b825181101561558d578061ffff6127f56155889386612d31565b61556e565b509160005b8151811015613d9b578061ffff6155ac6155c29385612d31565b51166108926155bc8651846133e7565b88612d31565b615592565b50905090565b8051906001918281018091116108a3576155e690611fac565b916000815b615604575b5050615600610640915183612d31565b5290565b8251811015615624578061ffff61289c61561e9386612d31565b816155eb565b6155f0565b8051906001918281018091116108a35761564290611fac565b916000815b61565c575b5050615600610578915183612d31565b825181101561567c578061ffff61289c6156769386612d31565b81615647565b61564c565b8051906001918281018091116108a35761569a90611fac565b916000815b6156b4575b505061560061044c915183612d31565b82518110156156d4578061ffff61289c6156ce9386612d31565b8161569f565b6156a4565b8051906001918281018091116108a3576156f290611fac565b916000815b61570c575b505061560061025d915183612d31565b825181101561572c578061ffff61289c6157269386612d31565b816156f7565b6156fc565b8051906001918281018091116108a35761574a90611fac565b916000815b615764575b505061560061012d915183612d31565b8251811015615784578061ffff61289c61577e9386612d31565b8161574f565b615754565b8051906001918281018091116108a3576157a290611fac565b916000815b6157bc575b5050615600610191915183612d31565b82518110156157dc578061ffff61289c6157d69386612d31565b816157a7565b6157ac565b8051906001918281018091116108a3576157fa90611fac565b916000815b615814575b5050615600610130915183612d31565b8251811015615834578061ffff61289c61582e9386612d31565b816157ff565b615804565b3d15615864573d9061584a82611ea8565b916158586040519384611a89565b82523d6000602084013e565b606090565b60208151910151906020811061587d575090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9060200360031b1b1690565b60008281939260208394519201905afa906158c3615839565b911561596e578151602081036155c75760016158de84615869565b166158e884615869565b036155c757601f10156159415750603f01517fff00000000000000000000000000000000000000000000000000000000000000167f01000000000000000000000000000000000000000000000000000000000000001490565b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526032600452fd5b905090565b8151600093928492839291602001905afa9061598d615839565b9115615a0257815191602083036159fc5773ffffffffffffffffffffffffffffffffffffffff92836159be83615869565b166159c883615869565b036159f55781602091810103126159f15760200151928284168094036159ee5750161490565b80fd5b8380fd5b5050505090565b50505090565b505090565b60008281939260208394519201905afa615a1f615839565b9015615a415780519060208203615a0257602091810103126159ee5750600190565b5090565b60008281939260208394519201905afa90615a5e615839565b9115615a8b57815160208103615a845782602091810103126159ee575060200151101590565b5091505090565b91505090565b60008281939260208394519201905afa90615aaa615839565b911561596e57815191602083036155c7577fffffffff000000000000000000000000000000000000000000000000000000009283615ae783615869565b16615af183615869565b03615b36578160209181010312612b0757602001519182168092036159ee57507f17b1f942000000000000000000000000000000000000000000000000000000001490565b505090509056fea164736f6c6343000811000a0000000000000000000000005345fc1b72e68c88e14132374dd104cbf103e1a9000000000000000000000000b9e372e572a152d905ade5c19bea45ad640460aa00000000000000000000000000000000f9490004c11cef243f5400493c00ad63

Deployed Bytecode

0x608080604052600436101561001357600080fd5b60003560e01c9081630234cb0b146118da575080630f27ba8c14611738578063157b7e1714611671578063198380d01461165757806320c35eca1461163d57806326affb001461150f57806326fa0f89146114f5578063272b2ec1146114a35780632ca069a51461144a5780632f5d94d7146112cc578063377d77ac1461124b5780633b33d7e6146111e85780633d1c8a23146111845780634710042e14610fbf57806350b613bf14610ee857806350f9cb6314610e8657806359f4a90714610e2d57806361af055d14610d77578063638430f014610d1e578063666eff3814610d045780636bb89fc314610cea57806373d8ab3014610c91578063772fc56c14610c1a5780637e74774114610c0057806383f4127a14610aaf57806386250b331461037e578063b0517ff21461030e578063b0cedcb4146102b4578063cfec3dff146101f65763de6fe0901461016957600080fd5b346101f15760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15760043567ffffffffffffffff81116101f1576101d96101be6101ed923690600401611ae2565b6101c6611954565b906101cf611f84565b91604435916123b8565b6040519182916020835260208301906119d0565b0390f35b600080fd5b346101f1577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360161010081126101f15760e0136101f15760405161023a81611a19565b610242611931565b815261024c611954565b60208201526044356040820152610261611f84565b606082015260843580151581036101f157608082015260a43560a082015260c43560c082015260e43567ffffffffffffffff81116101f1576101ed916102ae6101d9923690600401611f29565b90611ffb565b346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15760043567ffffffffffffffff81116101f1576101d96103096101ed923690600401611ae2565b6125fb565b346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15760043560068110156101f157806103556020926121f1565b801590811561036a575b506040519015158152f35b60019150610377816121f1565b148261035f565b346101f1577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6040813601126101f15760043567ffffffffffffffff81116101f1576103ce903690600401611ae2565b9067ffffffffffffffff602435116101f15761014090602435360301126101f15760405190610140820182811067ffffffffffffffff821117610a80576040526024356004013582526104246024803501611977565b6020830152610437604460243501611977565b60408301526064602435013567ffffffffffffffff81116101f15760243501366023820112156101f15760048101359061047082611aca565b9161047e6040519384611a89565b80835260208301913660248360071b830101116101f1579160248301925b60248360071b8201018410610a0e575050505060608301526084602435013567ffffffffffffffff81116101f15736602382602435010112156101f1576104ea600482602435010135611aca565b906104f86040519283611a89565b6004602480358301918201358085526020850193923660a090920201909101116101f15760248181350101915b602480358301600481013560a002010183106109a057505050608083015260a4602435013567ffffffffffffffff81116101f15761056b90600436916024350101611ee2565b60a083015267ffffffffffffffff60c46024350135116101f15761059a3660243560c481013501600401611e16565b60c083015260243560e481013560e084015261010481013561010084015261012401356101208301526105cb611f93565b5073ffffffffffffffffffffffffffffffffffffffff6020604051926105f084611a51565b6000845260405161060081611a51565b6000815260405194610611866119fd565b855282850152610629610623826125fb565b85615523565b015116604051907f17b1f9420000000000000000000000000000000000000000000000000000000060208301526020602483015261018482018451604484015273ffffffffffffffffffffffffffffffffffffffff602086015116606484015273ffffffffffffffffffffffffffffffffffffffff604086015116608484015260608501519061014060a4850152815180915260206101a4850192019060005b81811061094b5750505060808501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc8483030160c48501526020808251938481520191019160005b8181106108e8575050610754915060a08601517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc8583030160e4860152612d45565b9360c0810151947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc848203016101048501526020808751928381520196019060005b8181106108d257505050826107fd94956101208360e06107f89501516101248501526101008101516101448501520151610164830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101845283611a89565b615a91565b1561081b575b6101ed906040519182916020835260208301906119d0565b610823611f93565b5060208101519081516001908181018091116108a35761084290611fac565b906000815b61086c575b505061057961085f6101ed945183612d31565b5260208201529050610803565b845181101561089e578061ffff6108866108989388612d31565b51166108928286612d31565b52613a29565b81610847565b61084c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8251885260209788019790920191600101610796565b9091602060a060019273ffffffffffffffffffffffffffffffffffffffff608088518051610915816121f1565b84528286820151168685015260408101516040850152606081015160608501520151166080820152019401910192919092610712565b90919260206080600192606087518051610964816121f1565b83528085015173ffffffffffffffffffffffffffffffffffffffff168584015260408082015190840152015160608201520194019291016106c9565b60a0833603126101f157604051906109b782611a35565b6006843510156101f157602060a091602493863581526109d8838801611977565b83820152604087013560408201526060870135606082015260806109fd818901611977565b908201528152019301929050610525565b60809182853603126101f15760405192838181011067ffffffffffffffff8286011117610a805783016040526006853510156101f157602060809160249487358152610a5b838901611977565b838201526040880135604082015260608089013590820152815201940193915061049c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15767ffffffffffffffff6004358181116101f1576000610b04610b48923690600401611e16565b610b0c611f93565b50604051809381927f83f4127a000000000000000000000000000000000000000000000000000000008352602060048401526024830190611e74565b038173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000b9e372e572a152d905ade5c19bea45ad640460aa165afa918215610bf457600091600093610bb3575b50506101ed60405192839283526040602084015260408301906119d0565b915091503d806000833e610bc78183611a89565b81016040828203126101f15781519260208301519081116101f157610bec9201612175565b908280610b95565b6040513d6000823e3d90fd5b346101f1576101ed6101d9610c1436611d38565b906136c1565b346101f15760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15773ffffffffffffffffffffffffffffffffffffffff6101ed610c74610c6c611954565b600435612916565b6040929192519384931683526040602084015260408301906119d0565b346101f15760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15760206040517f1be900b1000000000000000000000000000000000000000000000000000000008152f35b346101f1576101ed6101d9610cfe36611d38565b90615084565b346101f1576101ed6101d9610d1836611da5565b91614718565b346101f15760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15760206040517f3839be19000000000000000000000000000000000000000000000000000000008152f35b346101f15760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f157610dae611931565b602435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036101f157602091610e2391604051917f01ffc9a70000000000000000000000000000000000000000000000000000000085840152602483015260248252610e1e82611a6d565b6158aa565b6040519015158152f35b346101f15760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15760206040517f80ac58cd000000000000000000000000000000000000000000000000000000008152f35b346101f15760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15760043567ffffffffffffffff81116101f1576101d9610edb6101ed923690600401611ae2565b6044359060243590613401565b346101f1576000610ef836611da5565b9291610f02611f93565b50610f3a60405194859384937f50b613bf00000000000000000000000000000000000000000000000000000000855260048501615125565b038173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000b9e372e572a152d905ade5c19bea45ad640460aa165afa8015610bf4576101ed91600091610f9c575b506040519182916020835260208301906119d0565b610fb991503d806000833e610fb18183611a89565b8101906121cb565b82610f87565b346101f15760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15767ffffffffffffffff6004358181116101f1576000611014611058923690600401611e16565b61101c611f93565b50604051809381927f4710042e000000000000000000000000000000000000000000000000000000008352604060048401526044830190611e74565b6024356024830152038173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000b9e372e572a152d905ade5c19bea45ad640460aa165afa918215610bf4576000916000936110d7575b6110c9836101ed86604051938493604085526040850190611e74565b9083820360208501526119d0565b915091503d806000833e6110eb8183611a89565b8101916040828403126101f15781518181116101f15782019183601f840112156101f157825161111a81611aca565b936111286040519586611a89565b818552602091828087019160051b830101918783116101f15783809101915b83831061117457505050508101519182116101f1576110c9936101ed9261116e9201612175565b926110ad565b8251815291810191849101611147565b346101f15760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f1576101ed6111d26111c1611954565b6111c9611f93565b50600435612916565b90506040519182916020835260208301906119d0565b346101f15760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15760043567ffffffffffffffff81116101f1576101d961123d6101ed923690600401611f29565b611245611954565b90612c16565b346101f15760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15760043567ffffffffffffffff81116101f15761129a903690600401611f29565b6044359073ffffffffffffffffffffffffffffffffffffffff821682036101f1576101ed916101d99160243590612d88565b346101f1576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15767ffffffffffffffff906004358281116101f157600061132361135d923690600401611e16565b604051809381927f2f5d94d70000000000000000000000000000000000000000000000000000000083528660048401526024830190611e74565b038173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000b9e372e572a152d905ade5c19bea45ad640460aa165afa928315610bf4576000936113bd575b50506101ed604051928284938452830190611e74565b909192503d806000843e6113d18184611a89565b82019183818403126101f15780519182116101f157019080601f830112156101f1578151916113ff83611aca565b9261140d6040519485611a89565b808452848085019160051b8301019283116101f15784809201905b83821061143b57505050509082806113a7565b81518152908201908201611428565b346101f15760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15760206040517fd9b67a26000000000000000000000000000000000000000000000000000000008152f35b346101f15760006114b336611da5565b92916114bd611f93565b50610f3a60405194859384937f272b2ec100000000000000000000000000000000000000000000000000000000855260048501615125565b346101f1576101ed6101d961150936611da5565b91613dd9565b346101f15760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f15760243567ffffffffffffffff81116101f15760206115636115a6923690600401611e16565b604051809381927f26affb000000000000000000000000000000000000000000000000000000000083526004356004840152606060248401526064830190611e74565b6044356044830152038173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000b9e372e572a152d905ade5c19bea45ad640460aa165afa8015610bf457600090611604575b6020906040519015158152f35b506020813d8211611635575b8161161d60209383611a89565b810103126101f157611630602091612909565b6115f7565b3d9150611610565b346101f1576101ed6101d961165136611da5565b91613d6e565b346101f1576101ed6101d961166b36611d38565b90613a56565b346101f1577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6040813601126101f1576004359067ffffffffffffffff82116101f15760409082360301126101f1576101d96101ed916102ae6116d2611954565b916116db611f93565b5073ffffffffffffffffffffffffffffffffffffffff604051936116fe85611a19565b1683526000602084015260006040840152600060608401526000608084015261070860a084015262eff10060c08401523690600401611f29565b346101f15760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f1576101ed611772611931565b61177a611f93565b506040519061178882611a51565b6000825273ffffffffffffffffffffffffffffffffffffffff6000604051926117b084611a51565b818452604051946117c0866119fd565b85526020850193845261182e6040517f01ffc9a70000000000000000000000000000000000000000000000000000000060208201527f1be900b10000000000000000000000000000000000000000000000000000000060248201526024815261182881611a6d565b826158aa565b156118c0575b6004604051809481937f2e778efc000000000000000000000000000000000000000000000000000000008352165afa908161189e575b5061189857611877611f93565b5061188281516155cd565b90526040519182916020835260208301906119d0565b506101d9565b6118ba903d806000833e6118b28183611a89565b8101906124d7565b5061186a565b6118c8611f93565b506118d384516155cd565b8452611834565b346101f15760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101f157807f36372b070000000000000000000000000000000000000000000000000000000060209252f35b6004359073ffffffffffffffffffffffffffffffffffffffff821682036101f157565b6024359073ffffffffffffffffffffffffffffffffffffffff821682036101f157565b359073ffffffffffffffffffffffffffffffffffffffff821682036101f157565b90815180825260208080930193019160005b8281106119b8575050505090565b835161ffff16855293810193928101926001016119aa565b6119fa9160206119e98351604084526040840190611998565b920151906020818403910152611998565b90565b6040810190811067ffffffffffffffff821117610a8057604052565b60e0810190811067ffffffffffffffff821117610a8057604052565b60a0810190811067ffffffffffffffff821117610a8057604052565b6020810190811067ffffffffffffffff821117610a8057604052565b6060810190811067ffffffffffffffff821117610a8057604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610a8057604052565b67ffffffffffffffff8111610a805760051b60200190565b9190916101609081818503126101f15760409384519283019067ffffffffffffffff9184811083821117610a805786528395611b1d84611977565b85526020611b2c818601611977565b81870152818501358481116101f15785019280601f850112156101f157833593611b5585611aca565b90611b6285519283611a89565b8582528382018460a0809802830101918483116101f1578501905b828210611cdb5750505083880152606091828701358681116101f15787019180601f840112156101f157823596611bb388611aca565b95611bc081519788611a89565b888752838701928460c0809b02870101958187116101f1578501935b868510611c3c5750505050505050850152608083013560058110156101f15760808501528083013590840152808201359083015260e081013560e08301526101008082013590830152610120808201359083015261014080910135910152565b8a858303126101f1578251908b820182811086821117611cad57845285359060068210156101f1578288928e9452611c75838901611977565b8382015285880135868201528a8801358b82015260808089013590820152611c9e8d8901611977565b8d820152815201940193611bdc565b602460007f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b87828603126101f157865190611cf082611a35565b82359060068210156101f1578288928b9452611d0d838601611977565b83820152898501358a8201526060808601359082015260808086013590820152815201910190611b7d565b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8201126101f1576004359067ffffffffffffffff82116101f157611d8191600401611ae2565b9060243573ffffffffffffffffffffffffffffffffffffffff811681036101f15790565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8201126101f1576004359067ffffffffffffffff82116101f157611dee91600401611ae2565b906024359060443573ffffffffffffffffffffffffffffffffffffffff811681036101f15790565b81601f820112156101f157803591611e2d83611aca565b92611e3b6040519485611a89565b808452602092838086019260051b8201019283116101f1578301905b828210611e65575050505090565b81358152908301908301611e57565b90815180825260208080930193019160005b828110611e94575050505090565b835185529381019392810192600101611e86565b67ffffffffffffffff8111610a8057601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b81601f820112156101f157803590611ef982611ea8565b92611f076040519485611a89565b828452602083830101116101f157816000926020809301838601378301015290565b91906040838203126101f15760405190611f42826119fd565b819380359167ffffffffffffffff928381116101f15781611f64918401611ae2565b845260208201359283116101f157602092611f7f9201611ee2565b910152565b6064359081151582036101f157565b60405190611fa0826119fd565b60606020838281520152565b90611fb682611aca565b611fc36040519182611a89565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0611ff18294611aca565b0190602036910137565b919091612006611f93565b5060405161201381611a51565b6000815260405161202381611a51565b6000815260405191612034836119fd565b82526020820152809361205b612055825160a086015160c087015191613401565b83615523565b805161208961208373ffffffffffffffffffffffffffffffffffffffff9283875116906136c1565b84615523565b61209b61208383518387511690613a56565b6120ad61208383518387511690615084565b6120ba61208383516125fb565b6120ca6120838286511684612c16565b6080840151156120db575b50505050565b612103936120fd925191602082015116606060408301519201511515926123b8565b90615523565b388080806120d5565b81601f820112156101f15780519161212383611aca565b926121316040519485611a89565b808452602092838086019260051b8201019283116101f1578301905b82821061215b575050505090565b815161ffff811681036101f157815290830190830161214d565b91906040838203126101f1576040519061218e826119fd565b819380519167ffffffffffffffff928381116101f157816121b091840161210c565b845260208201519283116101f157602092611f7f920161210c565b906020828203126101f157815167ffffffffffffffff81116101f1576119fa9201612175565b600611156121fb57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600511156121fb57565b90610160918282019273ffffffffffffffffffffffffffffffffffffffff90818351168452602082818501511681860152604095868501519287870152825180915281610180870193019060005b8181106123675750505060608085015196868403828801528280895195868152019801946000925b85841061230c575050505050505060808101516122c68161222a565b608083015260a081015160a083015260c081015160c083015260e081015160e0830152610100808201519083015261012080820151908301526101408091015191015290565b909192939495988560c06001928c518051612326816121f1565b825280840151871684830152878101518883015285810151868301526080808201519083015260a090810151871690820152019a01969594019291906122aa565b9091949792938460a060019288518051612380816121f1565b8252808401518d168483015287810151888301526060808201519083015260809081015190820152959a979501959401929101612282565b9061240860009394926123c9611f93565b50604051958694859384937fde6fe090000000000000000000000000000000000000000000000000000000008552608060048601526084850190612234565b9173ffffffffffffffffffffffffffffffffffffffff809616602485015260448401521515606483015203917f000000000000000000000000b9e372e572a152d905ade5c19bea45ad640460aa165afa908115610bf45760009161246a575090565b6119fa913d8091833e610fb18183611a89565b60005b8381106124905750506000910152565b8181015183820152602001612480565b909291926124ad81611ea8565b916124bb6040519384611a89565b8294828452828201116101f15760206124d593019061247d565b565b919060409081848203126101f157835167ffffffffffffffff908181116101f15785019180601f840112156101f15761251681845160208096016124a0565b9583810151908382116101f157019181601f840112156101f15782519061253c82611aca565b9561254981519788611a89565b828752858088019360051b860101948486116101f157868101935b86851061257657505050505050505090565b84518481116101f157820190837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe083890301126101f1578351916125b9836119fd565b89810151835284810151908682116101f157019087603f830112156101f15789926125ec898488878097015191016124a0565b83820152815201940193612564565b90612604611f93565b506040519161261283611a51565b60008084526040519161262483611a51565b81835260405194612634866119fd565b8552602092838601528460808201600260ff82516126518161222a565b61265a8161222a565b16109081156128e7575b506128e05750820173ffffffffffffffffffffffffffffffffffffffff90818151161561283957818151163b15612792576126f882825116604051907f01ffc9a700000000000000000000000000000000000000000000000000000000878301527f3839be1900000000000000000000000000000000000000000000000000000000602483015260248252610e1e82611a6d565b15612772579180916004935116604051938480927f2e778efc0000000000000000000000000000000000000000000000000000000082525afa918261275a575b505061275757612746611f93565b5082016127538151615629565b9052565b50565b61276d913d8091833e6118b28183611a89565b612738565b505050612780929192611f93565b50810161278d8151615629565b905290565b5050906127a0939293611f93565b5082018051805160019081810180911161280c576127be8291611fac565b94905b6127db575b50506127d661057b915184612d31565b525290565b8251811015612807578061ffff6127f56128019386612d31565b51166108928288612d31565b816127c1565b6127c6565b6024857f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b50509050612848929192611f93565b50815180516001908181018091116128b3576128648291611fac565b93905b612882575b505061287c61057a915183612d31565b52815290565b82518110156128ae578061ffff61289c6128a89386612d31565b51166108928287612d31565b81612867565b61286c565b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b9450505050565b6004915060ff90516128f88161222a565b6129018161222a565b161438612664565b519081151582036101f157565b919091612921611f93565b50604080519361293085611a51565b600091828652805161294181611a51565b838152815196612950886119fd565b875260209081880152868515612c0b575073ffffffffffffffffffffffffffffffffffffffff92837f00000000000000000000000000000000f9490004c11cef243f5400493c00ad6316958351907f6e9bfd9f000000000000000000000000000000000000000000000000000000008252600482015283816024818a5afa948515612c015786918796612bb6575b5050958415612b1b575b84612a63575b505050506129fb57509190565b612a03611f93565b50835180516001908181018091116128b357612a1f8291611fac565b93905b612a3e575b5050612a376103e9915183612d31565b5283529190565b8251811015612a5e578061ffff61289c612a589386612d31565b81612a22565b612a27565b83517f33bc857200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8881166004830152929092166024830152929350918190839060449082905afa928315612b1257508392612ad8575b505015388080806129ee565b90809250813d8311612b0b575b612aef8183611a89565b81010312612b0757612b0090612909565b3880612acc565b5080fd5b503d612ae5565b513d85823e3d90fd5b9550612b25611f93565b508751805190600191828101809111612b8957612b4190611fac565b9187815b612b64575b5050612b5a6103e8915183612d31565b52885284956129e8565b8251811015612b84578061ffff61289c612b7e9386612d31565b81612b45565b612b4a565b6024887f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b85809297508193503d8311612bfa575b612bd08183611a89565b81010312612bf65780519485168503612bf65782612bee9101612909565b9338806129de565b8580fd5b503d612bc6565b84513d88823e3d90fd5b965050509150509190565b9190612c20611f93565b5073ffffffffffffffffffffffffffffffffffffffff92602084825151166024604051809781937ff07ec373000000000000000000000000000000000000000000000000000000008352600483015286165afa938415610bf457600094612c8e575b50926119fa9293612d88565b6020813d8211612cbd575b81612ca660209383611a89565b81010312612cb9575193506119fa612c82565b8480fd5b3d9150612c99565b91908260809103126101f157612cda82612909565b91612ce760208201612909565b916060604083015192015190565b805115612d025760200190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8051821015612d025760209160051b010190565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602093612d818151809281875287808801910161247d565b0116010190565b9091612d92611f93565b5060ff6040805192612da384611a51565b600094858552825192612db584611a51565b868452805195612dc4876119fd565b8652602092838701948552869873ffffffffffffffffffffffffffffffffffffffff809216906080968786510151612dfb8161222a565b612e048161222a565b60049916891461334e575b508285515116988451997ff07ec373000000000000000000000000000000000000000000000000000000008b52898b015260249987818c81875afa908115613344578c91613313575b5082811115612ef957505050505050505050612e72611f93565b50835191825190600192838301809311612ecf575050612e928291611fac565b93905b612eaa575b505061287c61044e915183612d31565b8251811015612eca578061ffff61289c612ec49386612d31565b81612e95565b612e9a565b601186917f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b82909d9c9d9a999a106132a35750612f129085516151ec565b8351907f46423aa70000000000000000000000000000000000000000000000000000000082528982015286818981855afa908115613299578a91613269575b5061325e579184918151612f64816119fd565b6001978882528b5b8581106131a557505085612f7f82612cf5565b52612f8981612cf5565b508a83519586947f7509063800000000000000000000000000000000000000000000000000000000865260448601918d870152808c8701528351809252606486018760648460051b890101950193915b8c8484106131395750505050505082809103917f0000000000000000000000005345fc1b72e68c88e14132374dd104cbf103e1a9165afa8791816130fe575b506130e85750516101406060820151519101510361304d575b505050505061303e611f93565b506130498251615681565b8252565b613055611f93565b508601928351928351918383018093116130be5750506130758291611fac565b94905b613099575b505061308d610450915184612d31565b52523880808080613031565b82518110156130b9578061ffff6127f56130b39386612d31565b81613078565b61307d565b601187917f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b95505050505050156130f657565b61303e611f93565b9091508381813d8311613132575b6131168183611a89565b8101031261312e5761312790612909565b9038613018565b8780fd5b503d61310c565b9295807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c8b94979a613193939c94979a9c0301875289519083613183835189845289840190612234565b9201519084818403910152612d45565b9701930193018795938a979592612fd9565b9091938096939550516131b7816119fd565b8651610160810181811067ffffffffffffffff821117613232578a9392918f918a528181528185820152606091828b830152828083015280878301528060a08301528060c08301528060e083015280610100830152806101208301526101408201528252838201528282870101520190879492959391612f6c565b508b8e60418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b505050505050505050565b6132899150873d8911613292575b6132818183611a89565b810190612cc5565b50505038612f51565b503d613277565b84513d8c823e3d90fd5b9a9b5050505050505050906132b6611f93565b50835191825190600192838301809311612ecf5750506132d68291611fac565b93905b6132ee575b505061287c61044f915183612d31565b825181101561330e578061ffff61289c6133089386612d31565b816132d9565b6132de565b90508781813d831161333d575b61332a8183611a89565b81010312613339575138612e58565b8b80fd5b503d613320565b86513d8e823e3d90fd5b613356611f93565b508051908151916001928381018091116133bb5792806133768f95611fac565b94905b613396575b505061338e61044d915184612d31565b525238612e0f565b82518110156133b6578061ffff6127f56133b09386612d31565b81613379565b61337e565b60248e60118e7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b919082018092116108a357565b919082039182116108a357565b9061340a611f93565b506040519161341883611a51565b60009283815260405161342a81611a51565b8481526040519161343a836119fd565b82526020820152809460c083019160a083519401938451101561365a5750815190428210156134c9575050505050613470611f93565b50815180516001908181018091116128b35761348c8291611fac565b93905b6134a4575b505061287c610385915183612d31565b82518110156134c4578061ffff61289c6134be9386612d31565b8161348f565b613494565b6134d690979697426133e7565b106135ec575b42825111613574575b5190516134fb91904281111561356c57906133f4565b106135035750565b61350b611f93565b50602083018051805160019081810180911161280c5761352b8291611fac565b94905b613547575b5050613543610388915184612d31565b5252565b8251811015613567578061ffff6127f56135619386612d31565b8161352e565b613533565b5042906133f4565b61357c611f93565b5060208601805190815191600192838101809111612b895761359d90611fac565b9287815b6135c7575b5050906103876135bd6134fb969594935184612d31565b52529091506134e5565b82518110156135e7578061ffff6127f56135e19386612d31565b816135a1565b6135a6565b6135f4611f93565b5060208601805190815191600192838101809111612b895761361590611fac565b9287815b613635575b505061362e610386915184612d31565b52526134dc565b8251811015613655578061ffff6127f561364f9386612d31565b81613619565b61361e565b955050505050613668611f93565b50815180516001908181018091116128b3576136848291611fac565b93905b61369c575b505061287c610384915183612d31565b82518110156136bc578061ffff61289c6136b69386612d31565b81613687565b61368c565b9190916136cc611f93565b5060409060ff8251916136de83611a51565b6000938484528051916136f083611a51565b8583528151946136ff866119fd565b855260208501928352849773ffffffffffffffffffffffffffffffffffffffff8091169360808301516137318161222a565b61373a8161222a565b600496168614613992575b508151168251907ff07ec37300000000000000000000000000000000000000000000000000000000825285820152602081602481875afa908115613988578791613952575b50613797906080926151ec565b60248351809581937f46423aa7000000000000000000000000000000000000000000000000000000008352888301525afa90811561394957508485928692613924575b5061388e575b8015159182613884575b50506137f557505050565b6137fd611f93565b508151908151600191828201809211613858575061381b8291611fac565b94905b613833575b5050613543610321915184612d31565b8251811015613853578061ffff6127f561384d9386612d31565b8161381e565b613823565b8560116024927f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b14905038806137ea565b613896611f93565b5083518051906001918281018091116138f8576138b290611fac565b9187815b6138d3575b50506138cb610320915183612d31565b5284526137e0565b82518110156138f3578061ffff61289c6138ed9386612d31565b816138b6565b6138bb565b6024886011887f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b91505061393f915060803d8111613292576132818183611a89565b92509190386137da565b513d86823e3d90fd5b90506020813d8211613980575b8161396c60209383611a89565b8101031261397c5751608061378a565b8680fd5b3d915061395f565b83513d89823e3d90fd5b61399a611f93565b508051908151916001928381018091116139fd576139b790611fac565b928a815b6139d8575b50506139d0610322915184612d31565b525238613745565b82518110156139f8578061ffff6127f56139f29386612d31565b816139bb565b6139c0565b60248b60118b7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146108a35760010190565b9190613a60611f93565b5060408051613a6e81611a51565b600091828252805193613a8085611a51565b838552815192613a8f846119fd565b835260209687840195865283855b848301805151821015613c5357613abe613ab8868487613d6e565b88615523565b613ac9828251612d31565b51600191828401808511613c26578d9493929185830191845b613afb575b5050505050613af69150613a29565b613a9d565b8151968751821015613c1f57613b1382879899612d31565b519073ffffffffffffffffffffffffffffffffffffffff808651169183015116149081613c0e575b50613b52575b613b4a90613a29565b8f9695613ae2565b9091929350613b5f611f93565b508a518051868101809111613be157869594939291868f92613b8090611fac565b92905b613ba6575b509061025c613b9c613b4a94935183612d31565b528d529050613b41565b819293949596979151811015613bd4578061ffff61289c613bc79386612d31565b8197969594939291613b83565b9695949392919096613b88565b60248e7f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b90508b808601519101511438613b3b565b9650613ae7565b60248b7f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b50509750919250509291920180515115613cd7575b60018091515111613c7857505050565b613c80611f93565b50815190815181810180911161280c57613c9a8291611fac565b94905b613cb2575b505061354361025a915184612d31565b8251811015613cd2578061ffff6127f5613ccc9386612d31565b81613c9d565b613ca2565b613cdf611f93565b508151805190600191828101809111613d4157613cfb90611fac565b9185815b613d1c575b5050613d14610258915183612d31565b528252613c68565b8251811015613d3c578061ffff61289c613d369386612d31565b81613cff565b613d04565b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b929190613d79611f93565b50613d85828286613dd9565b93845151613d9b5791612055916124d593614718565b505050565b8115613daa570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b92919092613de5611f93565b5060408051613df381611a51565b600091828252805194613e0586611a51565b838652815192613e14846119fd565b835260209586840152613e2b839883870151612d31565b519460608601938451158061470c575b6146a1575083519260808701938451908181141580614690575b614500575b505060028751613e69816121f1565b613e72816121f1565b03613f60575050506001808093511491821592613f54575b5050613ece575b50500151613eb49073ffffffffffffffffffffffffffffffffffffffff1661515e565b15613ebb57565b613ec3611f93565b506130498251615731565b613ed6611f93565b5085519081518181018091116128b357613ef08291611fac565b93905b613f2f575b505091613eb4939161012c613f2373ffffffffffffffffffffffffffffffffffffffff955183612d31565b52865291819350613e91565b8251811015613f4f578061ffff61289c613f499386612d31565b81613ef3565b613ef8565b51141590508138613e8a565b869194959792965196613f72886121f1565b613f7b886121f1565b60049788036140aa5750500151613fa79073ffffffffffffffffffffffffffffffffffffffff1661515e565b15614090575b60018080945111918215614085575b5050613fc85750505050565b608082910151613fd78161222a565b613fe08161222a565b1615613fed575b806120d5565b613ff5611f93565b5084519182519082820180921161405957506140118291611fac565b93905b614034575b5050614029610131915183612d31565b528252388080613fe7565b8251811015614054578061ffff61289c61404e9386612d31565b81614014565b614019565b8460116024927f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b511190508238613fbc565b614098611f93565b506140a38751615731565b8752613fad565b92945092509350600384516140be816121f1565b6140c7816121f1565b1480156144e3575b156141bd57507f01ffc9a70000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff8361414c950151169151928301527fd9b67a2600000000000000000000000000000000000000000000000000000000602483015260248252610e1e82611a6d565b15614155575050565b61415d611f93565b508351908151600191828201809211614059575061417b8291611fac565b93905b614198575b5050614193610190915183612d31565b528252565b82518110156141b8578061ffff61289c6141b29386612d31565b8161417e565b614183565b8392919251936141cc856121f1565b6141d5856121f1565b60019485036143c357838101516142e1575b82015192517fdd62ed3e000000000000000000000000000000000000000000000000000000009281019290925273ffffffffffffffffffffffffffffffffffffffff908116602483018190526044830152614277921661427282606481015b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101845283611a89565b615a07565b1561428157505050565b614289611f93565b5084519182519082820180921161405957506142a58291611fac565b93905b6142bc575b505061419360c9915183612d31565b82518110156142dc578061ffff61289c6142d69386612d31565b816142a8565b6142ad565b6142e9611f93565b5088518051868101809111614397576143028b91611fac565b91878a815b614372575b50509373ffffffffffffffffffffffffffffffffffffffff86614272957fdd62ed3e0000000000000000000000000000000000000000000000000000000098956142469560c86143616142779d9b5184612d31565b5252955050509395505092506141e7565b8251811015614392578061ffff6127f561438c9386612d31565b81614307565b61430c565b60248960118a7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b9173ffffffffffffffffffffffffffffffffffffffff915082015116614450575b01516143ef57505050565b6143f7611f93565b5084519182519082820180921161405957506144138291611fac565b93905b61442b575b5050614193610515915183612d31565b825181101561444b578061ffff61289c6144459386612d31565b81614416565b61441b565b614458611f93565b50865180518481018091116144b75761447090611fac565b908487815b614492575b505061448a610514915183612d31565b5287526143e4565b82518110156144b2578061ffff61289c6144ac9386612d31565b81614475565b61447a565b6024876011887f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b50600584516144f1816121f1565b6144fa816121f1565b146140cf565b8181111561468a575b61451382826133f4565b61452660c086015160a0870151906133f4565b906402540be4009081810291818304149015171561460b579061454891613da0565b6127109182810292818404149015171561465d5766038d7ea4c68000929161456f91613da0565b6101168111156146385750614582611f93565b5061458d8c516156d9565b8c525b111561459e575b3880613e5a565b6145a6611f93565b50878a0180519081519160019283810180911161460b576145c690611fac565b9289815b6145e6575b50506145df61025e915184612d31565b5252614597565b8251811015614606578061ffff6127f56146009386612d31565b816145ca565b6145cf565b60248a7f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b601c101561459057614648611f93565b50898c0161465681516156d9565b9052614590565b6024897f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b90614509565b5060c084015160a085015110613e55565b979850505050509150506146b3611f93565b50815180516001908181018091116128b3576146cf8291611fac565b93905b6146e7575b505061287c610259915183612d31565b8251811015614707578061ffff61289c6147019386612d31565b816146d2565b6146d7565b50608087015115613e3b565b90929192614724611f93565b50604091825161473381611a51565b60009283825284519061474582611a51565b848252855192614754846119fd565b83526020918284015261476d8398610120860151612916565b61477981869396615523565b515161507a575061478d9086850151612d31565b51926002845161479c816121f1565b6147a5816121f1565b036149b25773ffffffffffffffffffffffffffffffffffffffff92868484870151169501818151976148158a517f6352211e000000000000000000000000000000000000000000000000000000008882015260249a8b8201528a815261480a81611a6d565b88875116908a615973565b15614900575b5061485f91518951907f081812fc00000000000000000000000000000000000000000000000000000000878301528982015288815261485981611a6d565b87615973565b1561486e575b50505050505050565b6148d4967fe985e9c50000000000000000000000000000000000000000000000000000000096610e1e956142469451169151978895860152840190602090939293604083019473ffffffffffffffffffffffffffffffffffffffff809216845216910152565b156148e6575b38808080808080614865565b6148ee611f93565b506148f982516157e1565b82526148da565b905061490a611f93565b508a51805160019081810180911161498657918161492b8795939694611fac565b92955b614950575b5061485f945061494761012f915183612d31565b528c529161481b565b9193819395915182101561497b57508061ffff61289c6149709386612d31565b93918186949261492e565b939185939150614933565b8a847f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b949192909381516149c2816121f1565b6149cb816121f1565b6004908103614a56575050830151935190517fe985e9c5000000000000000000000000000000000000000000000000000000009381019390935273ffffffffffffffffffffffffffffffffffffffff90811660248401529081166044830152614a3c9216610e1e8260648101614246565b15614a4357565b614a4b611f93565b5061304982516157e1565b94929095939160038151614a69816121f1565b614a72816121f1565b03614c425780840151855183517fe985e9c5000000000000000000000000000000000000000000000000000000008188015273ffffffffffffffffffffffffffffffffffffffff9182166024820152948116604486015290811693839190614b0f90614b0981606481015b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611a89565b866158aa565b15614c28575b6060830151608084015180821015614c205750965b5116910151907efdd58e000000000000000000000000000000000000000000000000000000008351958601526024850152604484015260448352608083019083821067ffffffffffffffff831117614bf45752614b88929190615a45565b15614b91575050565b614b99611f93565b5083519081516001918282018092116140595750614bb78291611fac565b93905b614bcf575b5050614193610192915183612d31565b8251811015614bef578061ffff61289c614be99386612d31565b81614bba565b614bbf565b6024876041887f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b905096614b2a565b614c30611f93565b50614c3b8b51615789565b8b52614b15565b91929394600583999897929951614c58816121f1565b614c61816121f1565b03614ced575050820151925195517fe985e9c5000000000000000000000000000000000000000000000000000000009281019290925273ffffffffffffffffffffffffffffffffffffffff95861660248301528516604482015292939192614cd392909116610e1e8260648101614246565b15614cda57565b614ce2611f93565b506130498251615789565b9391909497815193614cfe856121f1565b614d07856121f1565b6001948503614f3c579089939291614db273ffffffffffffffffffffffffffffffffffffffff958692614dac8488880151169660806060820151910151808210600014614f3257509889935b5187517fdd62ed3e000000000000000000000000000000000000000000000000000000008b82015273ffffffffffffffffffffffffffffffffffffffff9290911682166024820152921660448301528160648101614add565b85615a45565b15614e6c575b7f70a082310000000000000000000000000000000000000000000000000000000090614e02969798999a9b5116915193840152602483015260248252614dfd82611a6d565b615a45565b15614e0c57505050565b614e14611f93565b508451918251908282018092116140595750614e308291611fac565b93905b614e47575b505061419360cb915183612d31565b8251811015614e67578061ffff61289c614e619386612d31565b81614e33565b614e38565b614e74611f93565b5089518051878101809111614f0657614e8c90611fac565b9089885b614ee0575b509b7f70a0823100000000000000000000000000000000000000000000000000000000929160ca614ecf614e029a9b9c9d9e9f5183612d31565b528d529b9a99989796509050614db8565b8151811015614f0157614efb8161ffff61289c8c9486612d31565b90614e90565b614e95565b60248a60118b7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b9050988993614d53565b5050806080606073ffffffffffffffffffffffffffffffffffffffff939a94959798999a01519101518082106000146150725750915b51163110614fdf575b614f83611f93565b508501918251918251908282018092116138585750614fa28291611fac565b94905b614fba575b505061354361025b915184612d31565b8251811015614fda578061ffff6127f5614fd49386612d31565b81614fa5565b614faa565b614fe7611f93565b508551805184810180911161504657614fff90611fac565b908486815b615021575b5050615019610516915183612d31565b528652614f7b565b8251811015615041578061ffff61289c61503b9386612d31565b81615004565b615009565b6024866011867f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b905091614f72565b9750505050505050565b6000906150d092615093611f93565b5060405180809581947f6bb89fc3000000000000000000000000000000000000000000000000000000008352604060048401526044830190612234565b73ffffffffffffffffffffffffffffffffffffffff809416602483015203917f000000000000000000000000b9e372e572a152d905ade5c19bea45ad640460aa165afa908115610bf45760009161246a575090565b91939273ffffffffffffffffffffffffffffffffffffffff90615152604093606086526060860190612234565b95602085015216910152565b6119fa90604051907f01ffc9a70000000000000000000000000000000000000000000000000000000060208301527f80ac58cd00000000000000000000000000000000000000000000000000000000602483015260248252610e1e82611a6d565b805160208092019160005b8281106151d8575050505090565b8351855293810193928101926001016151ca565b919060408301916151fe835151611fac565b9161014085019061520f8251611fac565b7fa66999307ad1bb4fde44d13a5d710bd7718e0c87c1eef68a571629fbf5b93d029660005b875180518210156152d357908961524e826152ce94612d31565b51805161525a816121f1565b60209173ffffffffffffffffffffffffffffffffffffffff83820151169060408101519060609283820151936080809301519560405197880198895261529f816121f1565b604088015286015284015260a083015260c0908183015281526152c181611a19565b519020610892828a612d31565b615234565b505093929550939095506000957f42d81c6929ffdc4eb27a0808e40e82516ad42296c166065de7f812492304ff6e965b86518110156153c6576060908861531d8284890151612d31565b519283519061532b826121f1565b73ffffffffffffffffffffffffffffffffffffffff90602095828782015116916040820151908083015193608091828501519660a08096015116976040519b8c01998a52615378816121f1565b60408c01528a015288015286015260c085015260e09081850152835261010083019280841067ffffffffffffffff851117610a80576153c1936040525190206108928289612d31565b615303565b509392919550935073ffffffffffffffffffffffffffffffffffffffff9384825116946020830151169260405191826154036020820180936151bf565b03926154357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe094858101835282611a89565b5190209161545b604051918261544f6020820180966151bf565b03908101835282611a89565b519020608083015161546c8161222a565b60a08401519060c08501519260e086015194610120610100880151970151976040519a7ffa445660b7e21515a59617fcd68910b487aa5808b8abda3d78bc85df364b2c2f60208d015260408c015260608b015260808a015260a08901526154d28161222a565b60c088015260e0870152610100860152610120850152610140840152610160830152610180908183015281526101a0810181811067ffffffffffffffff821117610a80576040526020815191012090565b6020612753916155368151855190615543565b8152019160208351910151905b80518061554f57505090565b8251156155c75761556561556a918451906133e7565b611fac565b9260005b825181101561558d578061ffff6127f56155889386612d31565b61556e565b509160005b8151811015613d9b578061ffff6155ac6155c29385612d31565b51166108926155bc8651846133e7565b88612d31565b615592565b50905090565b8051906001918281018091116108a3576155e690611fac565b916000815b615604575b5050615600610640915183612d31565b5290565b8251811015615624578061ffff61289c61561e9386612d31565b816155eb565b6155f0565b8051906001918281018091116108a35761564290611fac565b916000815b61565c575b5050615600610578915183612d31565b825181101561567c578061ffff61289c6156769386612d31565b81615647565b61564c565b8051906001918281018091116108a35761569a90611fac565b916000815b6156b4575b505061560061044c915183612d31565b82518110156156d4578061ffff61289c6156ce9386612d31565b8161569f565b6156a4565b8051906001918281018091116108a3576156f290611fac565b916000815b61570c575b505061560061025d915183612d31565b825181101561572c578061ffff61289c6157269386612d31565b816156f7565b6156fc565b8051906001918281018091116108a35761574a90611fac565b916000815b615764575b505061560061012d915183612d31565b8251811015615784578061ffff61289c61577e9386612d31565b8161574f565b615754565b8051906001918281018091116108a3576157a290611fac565b916000815b6157bc575b5050615600610191915183612d31565b82518110156157dc578061ffff61289c6157d69386612d31565b816157a7565b6157ac565b8051906001918281018091116108a3576157fa90611fac565b916000815b615814575b5050615600610130915183612d31565b8251811015615834578061ffff61289c61582e9386612d31565b816157ff565b615804565b3d15615864573d9061584a82611ea8565b916158586040519384611a89565b82523d6000602084013e565b606090565b60208151910151906020811061587d575090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9060200360031b1b1690565b60008281939260208394519201905afa906158c3615839565b911561596e578151602081036155c75760016158de84615869565b166158e884615869565b036155c757601f10156159415750603f01517fff00000000000000000000000000000000000000000000000000000000000000167f01000000000000000000000000000000000000000000000000000000000000001490565b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526032600452fd5b905090565b8151600093928492839291602001905afa9061598d615839565b9115615a0257815191602083036159fc5773ffffffffffffffffffffffffffffffffffffffff92836159be83615869565b166159c883615869565b036159f55781602091810103126159f15760200151928284168094036159ee5750161490565b80fd5b8380fd5b5050505090565b50505090565b505090565b60008281939260208394519201905afa615a1f615839565b9015615a415780519060208203615a0257602091810103126159ee5750600190565b5090565b60008281939260208394519201905afa90615a5e615839565b9115615a8b57815160208103615a845782602091810103126159ee575060200151101590565b5091505090565b91505090565b60008281939260208394519201905afa90615aaa615839565b911561596e57815191602083036155c7577fffffffff000000000000000000000000000000000000000000000000000000009283615ae783615869565b16615af183615869565b03615b36578160209181010312612b0757602001519182168092036159ee57507f17b1f942000000000000000000000000000000000000000000000000000000001490565b505090509056fea164736f6c6343000811000a

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000005345fc1b72e68c88e14132374dd104cbf103e1a9000000000000000000000000b9e372e572a152d905ade5c19bea45ad640460aa00000000000000000000000000000000f9490004c11cef243f5400493c00ad63

-----Decoded View---------------
Arg [0] : readOnlyOrderValidatorAddress (address): 0x5345fc1b72e68c88E14132374dd104Cbf103e1a9
Arg [1] : seaportValidatorHelperAddress (address): 0xb9E372e572A152D905aDe5c19BEA45ad640460Aa
Arg [2] : conduitControllerAddress (address): 0x00000000F9490004C11Cef243f5400493c00Ad63

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000005345fc1b72e68c88e14132374dd104cbf103e1a9
Arg [1] : 000000000000000000000000b9e372e572a152d905ade5c19bea45ad640460aa
Arg [2] : 00000000000000000000000000000000f9490004c11cef243f5400493c00ad63


Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.