{
  "language": "Solidity",
  "sources": {
    "contracts/BNPL.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.13;\n\nimport {\n    Consideration\n} from \"./lib/Consideration.sol\";\n\ncontract BNPL is Consideration {\n\n    constructor(address conduitController, address shadowToken) Consideration(conduitController, shadowToken) {}\n\n    function _nameString() internal pure override returns (string memory) {\n        return \"BNPL\";\n    }\n}"
    },
    "contracts/lib/Consideration.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport {\n    OrderParameters,\n    OrderComponents,\n    OrderStatus,\n    Order\n} from \"./ConsiderationStructs.sol\";\n\nimport {\n    OrderFulfiller\n} from \"./OrderFulfiller.sol\";\n\ncontract Consideration is OrderFulfiller {\n\n    mapping(bytes32 => OrderStatus) private _orderStatus;\n\n    constructor(address conduitController, address shadowToken) OrderFulfiller(conduitController, shadowToken) {}\n\n    function fulfillOrder(Order calldata order, bytes32 fulfillerConduitKey)\n        external\n        payable\n        returns (bool fulfilled)\n    {\n        fulfilled = _validateAndFulfillOrder(order, fulfillerConduitKey);\n    }\n\n    function repayOrder(OrderParameters calldata parameters, bytes32 fulfillerConduitKey, uint256 payTimes)\n        external\n        payable\n        returns (bool repaid)\n    {\n        repaid = _validateAndRepayOrder(parameters, fulfillerConduitKey, payTimes);\n    }\n\n    function breakOrder(OrderParameters calldata parameters)\n        external\n        returns (bool broken)\n    {\n        broken = _validateAndBreakOrder(parameters);\n    }\n\n    function cancel(OrderComponents[] calldata orders)\n        external\n        returns (bool cancelled)\n    {\n        cancelled = _cancel(orders);\n    }\n\n    function validate(Order[] calldata orders)\n        external\n        returns (bool validated)\n    {\n        validated = _validate(orders);\n    }\n\n    function incrementCounter() external returns (uint256 newCounter) {\n        newCounter = _incrementCounter();\n    }\n\n    function getOrderHash(OrderComponents calldata order)\n        external\n        view\n        returns (bytes32 orderHash)\n    {\n        orderHash = _deriveOrderHash(\n            OrderParameters(\n                order.offerer,\n                order.token,\n                order.identifier,\n                order.currency,\n                order.artist,\n                order.platform,\n                order.startTime,\n                order.endTime,\n                order.duration,\n                order.periods,\n                order.amount,\n                order.ratio,\n                order.royalty,\n                order.fee,\n                order.withdrawFee,\n                order.salt,\n                order.conduitKey\n            ),\n            order.counter\n        );\n    }\n\n    function getOrderStatus(bytes32 orderHash)\n        external\n        view\n        returns (\n            bool isValidated,\n            bool isCancelled,\n            bool isFinalized,\n            bool isBroken,\n            address fulfiller,\n            uint256 startedAt,\n            uint256 shadowId,\n            uint256 paidTimes\n        )\n    {\n        return _getOrderStatus(orderHash);\n    }\n\n    function getCounter(address offerer)\n        external\n        view\n        returns (uint256 counter)\n    {\n        counter = _getCounter(offerer);\n    }\n\n    function information()\n        external\n        view\n        returns (\n            string memory version,\n            bytes32 domainSeparator,\n            address conduitController\n        )\n    {\n        return _information();\n    }\n}"
    },
    "contracts/lib/ConsiderationStructs.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.7;\n\nstruct OrderComponents {\n    address offerer;\n    address token;\n    uint256 identifier;\n    address currency;\n    address artist;\n    address platform;\n    uint256 startTime;\n    uint256 endTime;\n    uint256 duration;\n    uint256 periods;\n    uint256 amount;\n    uint256 ratio;\n    uint256 royalty;\n    uint256 fee;\n    uint256 withdrawFee;\n    uint256 salt;\n    bytes32 conduitKey;\n    uint256 counter;\n}\n\nstruct OrderParameters {\n    address offerer;    // 0x00\n    address token;      // 0x20\n    uint256 identifier; // 0x40\n    address currency;   // 0x60\n    address artist;     // 0x80\n    address platform;   // 0xa0\n    uint256 startTime;  // 0xc0\n    uint256 endTime;    // 0xe0\n    uint256 duration;   // 0x100\n    uint256 periods;    // 0x120\n    uint256 amount;     // 0x140\n    uint256 ratio;      // 0x160\n    uint256 royalty;    // 0x180\n    uint256 fee;        // 0x1a0\n    uint256 withdrawFee;// 0x1c0\n    uint256 salt;       // 0x1e0\n    bytes32 conduitKey; // 0x200\n}\n\nstruct Order {\n    OrderParameters parameters;\n    bytes signature;\n}\n\nstruct OrderStatus {\n    bool isValidated;\n    bool isCancelled;\n    bool isFinalized;\n    bool isBroken;\n    address fulfiller;\n    uint256 startedAt;\n    uint256 shadowId;\n    uint256 paidTimes;\n}"
    },
    "contracts/lib/OrderFulfiller.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport { ConduitInterface } from \"../interfaces/ConduitInterface.sol\";\n\nimport {\n    ItemType\n} from \"./ConsiderationEnums.sol\";\n\nimport {\n    Order,\n    OrderParameters\n} from \"./ConsiderationStructs.sol\";\n\nimport { OrderValidator } from \"./OrderValidator.sol\";\n\nimport \"./ConsiderationConstants.sol\";\n\ncontract OrderFulfiller is OrderValidator {\n\n    struct Dispatch {\n        uint256 payment;\n        uint256 toOfferer;\n        uint256 toPlatform;\n        uint256 toArtist;\n    }\n\n    constructor(address conduitController, address shadowToken) OrderValidator(conduitController, shadowToken) {}\n\n    function _calculateDispatch(\n        OrderParameters calldata params,\n        uint256 payTimes,\n        bool isFirst,\n        bool isFinalize\n    )\n        internal\n        pure\n        returns (Dispatch memory ret)\n    {\n        uint256 royalty;\n        uint256 paidTimes = params.periods - payTimes;\n\n        ret.toPlatform = params.withdrawFee;\n        if (isFinalize) {\n            royalty = params.royalty - paidTimes * (params.royalty / params.periods);\n            ret.payment = params.amount - paidTimes* (params.amount / params.periods);\n            ret.toOfferer = params.amount - (params.amount / params.periods) * params.ratio / 10000 * paidTimes - ret.toPlatform - royalty;\n            ret.toArtist = params.royalty;\n        } else {\n            royalty = payTimes * (params.royalty / params.periods);\n            ret.payment = payTimes * (params.amount / params.periods);            \n            ret.toOfferer = ret.payment * params.ratio / 10000 - ret.toPlatform - royalty;\n            if (isFirst) {\n                ret.payment += params.fee;\n                ret.toPlatform += params.fee;\n            }\n        }\n    }\n\n    function _validateAndFulfillOrder(Order calldata order, bytes32 fulfillerConduitKey)\n        internal\n        returns (bool)\n    {\n        (\n            bytes32 orderHash,\n            bool valid,\n            uint256 shadowId\n        ) = _validateOrderAndUpdateStatus(\n            order,\n            true\n        );\n\n        if (!valid) {\n            return false;\n        }\n\n        OrderParameters calldata orderParameters = order.parameters;\n        Dispatch memory dispatch = _calculateDispatch(orderParameters, 1, true, false);\n\n        if (orderParameters.currency == address(0)) {\n            _transferIndividual721Or1155Item(\n                ItemType.ERC721,\n                orderParameters.token,\n                orderParameters.offerer,\n                address(this),\n                orderParameters.identifier,\n                1,\n                orderParameters.conduitKey\n            );\n\n            _transferEthAndFinalize(orderParameters, dispatch);\n        } else {\n            bytes memory accumulator = new bytes(AccumulatorDisarmed);\n            _transferERC721(\n                orderParameters.token,\n                orderParameters.offerer,\n                address(this),\n                orderParameters.identifier,\n                1,\n                orderParameters.conduitKey,\n                accumulator\n            );\n\n            _transferERC20AndFinalize(\n                orderParameters,\n                dispatch,\n                fulfillerConduitKey,\n                accumulator\n            );\n        }\n\n        emit OrderFulfilled(\n            orderHash,\n            orderParameters.offerer,\n            shadowId\n        );\n\n        return true;\n    }\n\n    function _validateAndRepayOrder(OrderParameters calldata parameters, bytes32 fulfillerConduitKey, uint256 payTimes)\n        internal\n        returns (bool)\n    {\n        bytes32 orderHash;\n        address fulfiller;\n        bool isFinalized;\n        {\n            bool valid;\n            (\n                orderHash,\n                fulfiller,\n                valid,\n                isFinalized\n            ) = _validateOrderAndUpdateRepayStatus(\n                parameters,\n                payTimes,\n                true\n            );\n\n            if (!valid) {\n                return false;\n            }\n        }\n\n        Dispatch memory dispatch = _calculateDispatch(parameters, payTimes, false, isFinalized);\n\n        if (parameters.currency == address(0)) {\n            _transferEthAndFinalize(parameters, dispatch);\n        } else {\n            bytes memory accumulator = new bytes(AccumulatorDisarmed);\n            _transferERC20AndFinalize(\n                parameters,\n                dispatch,\n                fulfillerConduitKey,\n                accumulator\n            );\n        }\n\n        if (isFinalized) {\n            _transferIndividual721Or1155Item(\n                ItemType.ERC721,\n                parameters.token,\n                address(this),\n                fulfiller,\n                parameters.identifier,\n                1,\n                bytes32(0)\n            );\n        }\n\n        emit OrderRepaid(\n            orderHash,\n            payTimes,\n            isFinalized\n        );\n\n        return true;\n    }\n\n    function _validateAndBreakOrder(OrderParameters calldata parameters)\n        internal\n        returns (bool)\n    {\n        (\n            bytes32 orderHash,\n            uint256 paidTimes,\n            bool valid\n        ) = _validateOrderAndUpdateBreakStatus(\n            parameters,\n            true\n        );\n\n        if (!valid) {\n            return false;\n        }\n\n        _transferIndividual721Or1155Item(\n            ItemType.ERC721,\n            parameters.token,\n            address(this),\n            parameters.offerer,\n            parameters.identifier,\n            1,\n            bytes32(0)\n        );\n\n        if (parameters.currency == address(0)) {\n            _transferEthBroken(parameters, paidTimes);\n        } else {\n            _transferERC20Broken(\n                parameters,\n                paidTimes\n            );\n        }\n\n        emit OrderBroken(\n            orderHash,\n            parameters.offerer\n        );\n\n        return true;\n    }\n\n    function _transferEthBroken(\n        OrderParameters calldata orderParameters,\n        uint256 paidTimes\n    ) internal {\n        _transferEth(\n            payable(orderParameters.offerer),\n            orderParameters.royalty / orderParameters.periods * paidTimes\n        );\n        uint256 toPlatform = orderParameters.amount / orderParameters.periods * paidTimes;\n        toPlatform = toPlatform - toPlatform * orderParameters.ratio / 10000;\n        _transferEth(\n            payable(orderParameters.platform),\n            toPlatform\n        );\n    }\n\n    function _transferERC20Broken(\n        OrderParameters calldata parameters,\n        uint256 paidTimes\n    ) internal {\n        _performSelfERC20Transfer(parameters.currency, parameters.offerer, parameters.royalty / parameters.periods * paidTimes);\n\n        uint256 toPlatform = parameters.amount / parameters.periods * paidTimes;\n        toPlatform = toPlatform - toPlatform * parameters.ratio / 10000;\n        _performSelfERC20Transfer(parameters.currency, parameters.platform, toPlatform);\n    }\n\n    function _transferEthAndFinalize(\n        OrderParameters calldata orderParameters,\n        Dispatch memory dispatch\n    ) internal {\n        uint256 etherRemaining = msg.value;\n\n        if (dispatch.payment > etherRemaining) {\n            revert InsufficientEtherSupplied();\n        }\n\n        _transferEth(\n            payable(orderParameters.offerer),\n            dispatch.toOfferer\n        );\n\n        _transferEth(\n            payable(orderParameters.platform),\n            dispatch.toPlatform\n        );\n\n        if (dispatch.toArtist > 0) {\n            _transferEth(\n                payable(orderParameters.artist),\n                dispatch.toArtist\n            );\n        }\n\n        etherRemaining -= dispatch.payment;\n\n        if (etherRemaining > 0) {\n            unchecked {\n                _transferEth(payable(msg.sender), etherRemaining);\n            }\n        }\n    }\n\n    function _transferERC20AndFinalize(\n        OrderParameters calldata parameters,\n        Dispatch memory dispatch,\n        bytes32 conduitKey,\n        bytes memory accumulator\n    ) internal {\n        address from = msg.sender;\n        address token = parameters.currency;\n\n        _transferERC20(\n            token,\n            from,\n            parameters.platform,\n            dispatch.toPlatform,\n            conduitKey,\n            accumulator\n        );\n\n        if (dispatch.toArtist > 0) {\n            _transferERC20(\n                token,\n                from,\n                parameters.artist,\n                dispatch.toArtist,\n                conduitKey,\n                accumulator\n            );\n        }\n\n        uint256 left = dispatch.payment - dispatch.toPlatform - dispatch.toArtist;\n        if (left >= dispatch.toOfferer) {\n            _transferERC20(\n                token,\n                from,\n                parameters.offerer,\n                dispatch.toOfferer,\n                conduitKey,\n                accumulator\n            );\n            left -= dispatch.toOfferer;\n            if (left > 0) {\n                _transferERC20(\n                    token,\n                    from,\n                    address(this),\n                    left,\n                    conduitKey,\n                    accumulator\n                );\n            }\n            _triggerIfArmed(accumulator);\n        } else {\n            _transferERC20(\n                token,\n                from,\n                parameters.offerer,\n                left,\n                conduitKey,\n                accumulator\n            );\n            _triggerIfArmed(accumulator);\n\n            _performSelfERC20Transfer(token, parameters.offerer, dispatch.toOfferer - left);\n        }\n    }\n}\n"
    },
    "contracts/interfaces/ConduitInterface.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.7;\n\nimport {\n    ConduitTransfer,\n    ConduitBatch1155Transfer\n} from \"../conduit/lib/ConduitStructs.sol\";\n\n/**\n * @title ConduitInterface\n * @author 0age\n * @notice ConduitInterface contains all external function interfaces, events,\n *         and errors for conduit contracts.\n */\ninterface ConduitInterface {\n    /**\n     * @dev Revert with an error when attempting to execute transfers using a\n     *      caller that does not have an open channel.\n     */\n    error ChannelClosed(address channel);\n\n    /**\n     * @dev Revert with an error when attempting to update a channel to the\n     *      current status of that channel.\n     */\n    error ChannelStatusAlreadySet(address channel, bool isOpen);\n\n    /**\n     * @dev Revert with an error when attempting to execute a transfer for an\n     *      item that does not have an ERC20/721/1155 item type.\n     */\n    error InvalidItemType();\n\n    /**\n     * @dev Revert with an error when attempting to update the status of a\n     *      channel from a caller that is not the conduit controller.\n     */\n    error InvalidController();\n\n    /**\n     * @dev Emit an event whenever a channel is opened or closed.\n     *\n     * @param channel The channel that has been updated.\n     * @param open    A boolean indicating whether the conduit is open or not.\n     */\n    event ChannelUpdated(address indexed channel, bool open);\n\n    /**\n     * @notice Execute a sequence of ERC20/721/1155 transfers. Only a caller\n     *         with an open channel can call this function.\n     *\n     * @param transfers The ERC20/721/1155 transfers to perform.\n     *\n     * @return magicValue A magic value indicating that the transfers were\n     *                    performed successfully.\n     */\n    function execute(ConduitTransfer[] calldata transfers)\n        external\n        returns (bytes4 magicValue);\n\n    /**\n     * @notice Execute a sequence of batch 1155 transfers. Only a caller with an\n     *         open channel can call this function.\n     *\n     * @param batch1155Transfers The 1155 batch transfers to perform.\n     *\n     * @return magicValue A magic value indicating that the transfers were\n     *                    performed successfully.\n     */\n    function executeBatch1155(\n        ConduitBatch1155Transfer[] calldata batch1155Transfers\n    ) external returns (bytes4 magicValue);\n\n    /**\n     * @notice Execute a sequence of transfers, both single and batch 1155. Only\n     *         a caller with an open channel can call this function.\n     *\n     * @param standardTransfers  The ERC20/721/1155 transfers to perform.\n     * @param batch1155Transfers The 1155 batch transfers to perform.\n     *\n     * @return magicValue A magic value indicating that the transfers were\n     *                    performed successfully.\n     */\n    function executeWithBatch1155(\n        ConduitTransfer[] calldata standardTransfers,\n        ConduitBatch1155Transfer[] calldata batch1155Transfers\n    ) external returns (bytes4 magicValue);\n\n    /**\n     * @notice Open or close a given channel. Only callable by the controller.\n     *\n     * @param channel The channel to open or close.\n     * @param isOpen  The status of the channel (either open or closed).\n     */\n    function updateChannel(address channel, bool isOpen) external;\n}\n"
    },
    "contracts/lib/ConsiderationEnums.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.7;\n\nenum ItemType {\n    NATIVE,\n    ERC20,\n    ERC721,\n    ERC1155\n}"
    },
    "contracts/lib/OrderValidator.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport {\n    OrderParameters,\n    Order,\n    OrderComponents,\n    OrderStatus\n} from \"./ConsiderationStructs.sol\";\n\nimport \"./ConsiderationConstants.sol\";\n\nimport { Executor } from \"./Executor.sol\";\nimport { Shadow } from \"./Shadow.sol\";\n\ncontract OrderValidator is Executor, Shadow {\n\n    mapping(bytes32 => OrderStatus) private _orderStatus;\n\n    constructor(address conduitController, address shadowToken) Executor(conduitController) Shadow(shadowToken) {}\n\n    function _validateOrderAndUpdateStatus(\n        Order calldata order,\n        bool revertOnInvalid\n    )\n        internal\n        returns (\n            bytes32 orderHash,\n            bool valid,\n            uint256 shadowId\n        )\n    {\n        OrderParameters calldata orderParameters = order.parameters;\n        if (\n            !_verifyTime(\n                orderParameters.startTime,\n                orderParameters.endTime,\n                revertOnInvalid\n            )\n        ) {\n            return (bytes32(0), false, 0);\n        }\n\n        if (orderParameters.periods < 2) {\n            if (revertOnInvalid) {\n                revert InvalidOrderParameters();\n            }\n            return (bytes32(0), false, 0);\n        }\n\n        orderHash = _deriveOrderHash(\n            orderParameters,\n            _getCounter(orderParameters.offerer)\n        );\n\n        OrderStatus storage orderStatus = _orderStatus[orderHash];\n\n        if (\n            !_verifyOrderStatus(\n                orderHash,\n                orderStatus,\n                true,\n                revertOnInvalid\n            )\n        ) {\n            return (orderHash, false, 0);\n        }\n\n        if (!orderStatus.isValidated) {\n            _verifySignature(\n                orderParameters.offerer,\n                orderHash,\n                order.signature\n            );\n        }\n\n        shadowId = _mintToken(\n            msg.sender,\n            orderParameters.token,\n            orderParameters.identifier,\n            orderParameters.duration\n        );\n\n        orderStatus.isValidated = true;\n        orderStatus.isCancelled = false;\n        orderStatus.isBroken = false;\n        orderStatus.fulfiller = msg.sender;\n        orderStatus.startedAt = block.timestamp;\n        orderStatus.shadowId = shadowId;\n        orderStatus.paidTimes = 1;\n\n        valid = true;\n    }\n\n    function _validateOrderAndUpdateRepayStatus(\n        OrderParameters calldata parameters,\n        uint256 payTimes,\n        bool revertOnInvalid\n    )\n        internal\n        returns (\n            bytes32 orderHash,\n            address fulfiller,\n            bool valid,\n            bool isFinalized\n        )\n    {\n        orderHash = _deriveOrderHash(\n            parameters,\n            _getCounter(parameters.offerer)\n        );\n\n        OrderStatus storage orderStatus = _orderStatus[orderHash];\n        if (!orderStatus.isValidated) {\n            if (revertOnInvalid) {\n                revert OrderNotValidated(orderHash);\n            }\n            return (orderHash, address(0), false, false);\n        }\n\n        if (\n            !_verifyOrderStatus(\n                orderHash,\n                orderStatus,\n                false,\n                revertOnInvalid\n            )\n        ) {\n            return (orderHash, address(0), false, false);\n        }\n\n        if (orderStatus.paidTimes + payTimes > parameters.periods || payTimes < 1) {\n            if (revertOnInvalid) {\n                revert OrderInvalidRepayParameters(orderHash);\n            }\n            return (orderHash, address(0), false, false);\n        }\n\n        if (orderStatus.startedAt + orderStatus.paidTimes * parameters.duration < block.timestamp) {\n            if (revertOnInvalid) {\n                revert OrderExpired(orderHash);\n            }\n            return (orderHash, address(0), false, false);\n        }\n\n        orderStatus.paidTimes += payTimes;\n        if (orderStatus.paidTimes == parameters.periods) {\n            orderStatus.isFinalized = true;\n            isFinalized = true;\n            _burnToken(orderStatus.shadowId);\n        } else {\n            _extendToken(\n                orderStatus.fulfiller,\n                orderStatus.shadowId,\n                orderStatus.startedAt + orderStatus.paidTimes * parameters.duration\n            );\n        }\n\n        valid = true;\n        fulfiller = orderStatus.fulfiller;\n    }\n\n    function _validateOrderAndUpdateBreakStatus(\n        OrderParameters calldata parameters,\n        bool revertOnInvalid\n    )\n        internal\n        returns (\n            bytes32 orderHash,\n            uint256 paidTimes,\n            bool valid\n        )\n    {\n        orderHash = _deriveOrderHash(\n            parameters,\n            _getCounter(parameters.offerer)\n        );\n\n        OrderStatus storage orderStatus = _orderStatus[orderHash];\n        if (!orderStatus.isValidated) {\n            if (revertOnInvalid) {\n                revert OrderNotValidated(orderHash);\n            }\n            return (orderHash, paidTimes, false);\n        }\n\n        paidTimes = orderStatus.paidTimes;\n\n        if (\n            !_verifyOrderStatus(\n                orderHash,\n                orderStatus,\n                false,\n                revertOnInvalid\n            )\n        ) {\n            return (orderHash, paidTimes, false);\n        }\n\n        if (orderStatus.startedAt + paidTimes * parameters.duration > block.timestamp) {\n            if (revertOnInvalid) {\n                revert OrderNotExpired(orderHash);\n            }\n            return (orderHash, paidTimes, false);\n        }\n\n        _burnToken(orderStatus.shadowId);\n\n        orderStatus.isFinalized = true;\n        orderStatus.isBroken = true;\n        valid = true;\n    }\n\n    function _cancel(OrderComponents[] calldata orders)\n        internal\n        returns (bool cancelled)\n    {\n        // Ensure that the reentrancy guard is not currently set.\n        _assertNonReentrant();\n\n        // Declare variables outside of the loop.\n        OrderStatus storage orderStatus;\n        address offerer;\n\n        // Skip overflow check as for loop is indexed starting at zero.\n        unchecked {\n            // Read length of the orders array from memory and place on stack.\n            uint256 totalOrders = orders.length;\n\n            // Iterate over each order.\n            for (uint256 i = 0; i < totalOrders; ) {\n                // Retrieve the order.\n                OrderComponents calldata order = orders[i];\n\n                offerer = order.offerer;\n\n                if (msg.sender != offerer) {\n                    revert InvalidCanceller();\n                }\n\n                // Derive order hash using the order parameters and the counter.\n                bytes32 orderHash = _deriveOrderHash(\n                    OrderParameters(\n                        offerer,\n                        order.token,\n                        order.identifier,\n                        order.currency,\n                        order.artist,\n                        order.platform,\n                        order.startTime,\n                        order.endTime,\n                        order.duration,\n                        order.periods,\n                        order.amount,\n                        order.ratio,\n                        order.royalty,\n                        order.fee,\n                        order.withdrawFee,\n                        order.salt,\n                        order.conduitKey\n                    ),\n                    order.counter\n                );\n\n                // Retrieve the order status using the derived order hash.\n                orderStatus = _orderStatus[orderHash];\n\n                if (orderStatus.startedAt > 0) {\n                    revert OrderAlreadyStarted(orderHash);\n                }\n\n                // Update the order status as not valid and cancelled.\n                orderStatus.isValidated = false;\n                orderStatus.isCancelled = true;\n\n                // Emit an event signifying that the order has been cancelled.\n                emit OrderCancelled(orderHash, offerer);\n\n                // Increment counter inside body of loop for gas efficiency.\n                ++i;\n            }\n        }\n\n        // Return a boolean indicating that orders were successfully cancelled.\n        cancelled = true;\n    }\n\n    function _validate(Order[] calldata orders)\n        internal\n        returns (bool validated)\n    {\n        // Ensure that the reentrancy guard is not currently set.\n        _assertNonReentrant();\n\n        // Declare variables outside of the loop.\n        OrderStatus storage orderStatus;\n        bytes32 orderHash;\n        address offerer;\n\n        // Skip overflow check as for loop is indexed starting at zero.\n        unchecked {\n            // Read length of the orders array from memory and place on stack.\n            uint256 totalOrders = orders.length;\n\n            // Iterate over each order.\n            for (uint256 i = 0; i < totalOrders; ) {\n                // Retrieve the order.\n                Order calldata order = orders[i];\n\n                // Retrieve the order parameters.\n                OrderParameters calldata orderParameters = order.parameters;\n\n                // Move offerer from memory to the stack.\n                offerer = orderParameters.offerer;\n\n                // Get current counter & use it w/ params to derive order hash.\n                orderHash = _deriveOrderHash(\n                    OrderParameters(\n                        offerer,\n                        orderParameters.token,\n                        orderParameters.identifier,\n                        orderParameters.currency,\n                        orderParameters.artist,\n                        orderParameters.platform,\n                        orderParameters.startTime,\n                        orderParameters.endTime,\n                        orderParameters.duration,\n                        orderParameters.periods,\n                        orderParameters.amount,\n                        orderParameters.ratio,\n                        orderParameters.royalty,\n                        orderParameters.fee,\n                        orderParameters.withdrawFee,\n                        orderParameters.salt,\n                        orderParameters.conduitKey\n                    ),\n                    _getCounter(orderParameters.offerer)\n                );\n\n                // Retrieve the order status using the derived order hash.\n                orderStatus = _orderStatus[orderHash];\n\n                // Ensure order is fillable and retrieve the filled amount.\n                _verifyOrderStatus(\n                    orderHash,\n                    orderStatus,\n                    true, // Signifies that partially filled orders are valid.\n                    true // Signifies to revert if the order is invalid.\n                );\n\n                // If the order has not already been validated...\n                if (!orderStatus.isValidated) {\n                    // Verify the supplied signature.\n                    _verifySignature(offerer, orderHash, order.signature);\n\n                    // Update order status to mark the order as valid.\n                    orderStatus.isValidated = true;\n\n                    // Emit an event signifying the order has been validated.\n                    emit OrderValidated(\n                        orderHash,\n                        offerer\n                    );\n                }\n\n                // Increment counter inside body of the loop for gas efficiency.\n                ++i;\n            }\n        }\n\n        // Return a boolean indicating that orders were successfully validated.\n        validated = true;\n    }\n\n    function _getOrderStatus(bytes32 orderHash)\n        internal\n        view\n        returns (\n            bool isValidated,\n            bool isCancelled,\n            bool isFinalized,\n            bool isBroken,\n            address fulfiller,\n            uint256 startedAt,\n            uint256 shadowId,\n            uint256 paidTimes\n        )\n    {\n        OrderStatus storage orderStatus = _orderStatus[orderHash];\n        return (\n            orderStatus.isValidated,\n            orderStatus.isCancelled,\n            orderStatus.isFinalized,\n            orderStatus.isBroken,\n            orderStatus.fulfiller,\n            orderStatus.startedAt,\n            orderStatus.shadowId,\n            orderStatus.paidTimes\n        );\n    }\n}\n"
    },
    "contracts/lib/ConsiderationConstants.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.7;\n\n/*\n * -------------------------- Disambiguation & Other Notes ---------------------\n *    - The term \"head\" is used as it is in the documentation for ABI encoding,\n *      but only in reference to dynamic types, i.e. it always refers to the\n *      offset or pointer to the body of a dynamic type. In calldata, the head\n *      is always an offset (relative to the parent object), while in memory,\n *      the head is always the pointer to the body. More information found here:\n *      https://docs.soliditylang.org/en/v0.8.14/abi-spec.html#argument-encoding\n *        - Note that the length of an array is separate from and precedes the\n *          head of the array.\n *\n *    - The term \"body\" is used in place of the term \"head\" used in the ABI\n *      documentation. It refers to the start of the data for a dynamic type,\n *      e.g. the first word of a struct or the first word of the first element\n *      in an array.\n *\n *    - The term \"pointer\" is used to describe the absolute position of a value\n *      and never an offset relative to another value.\n *        - The suffix \"_ptr\" refers to a memory pointer.\n *        - The suffix \"_cdPtr\" refers to a calldata pointer.\n *\n *    - The term \"offset\" is used to describe the position of a value relative\n *      to some parent value. For example, OrderParameters_conduit_offset is the\n *      offset to the \"conduit\" value in the OrderParameters struct relative to\n *      the start of the body.\n *        - Note: Offsets are used to derive pointers.\n *\n *    - Some structs have pointers defined for all of their fields in this file.\n *      Lines which are commented out are fields that are not used in the\n *      codebase but have been left in for readability.\n */\n\n// Declare constants for name, version, and reentrancy sentinel values.\n\n// Name is right padded, so it touches the length which is left padded. This\n// enables writing both values at once. Length goes at byte 95 in memory, and\n// name fills bytes 96-109, so both values can be written left-padded to 77.\nuint256 constant NameLengthPtr = 77;\nuint256 constant NameWithLength = 0x0d436F6E73696465726174696F6E;\n\nuint256 constant Version = 0x312e31;\nuint256 constant Version_length = 3;\nuint256 constant Version_shift = 0xe8;\n\nuint256 constant _NOT_ENTERED = 1;\nuint256 constant _ENTERED = 2;\n\n// Common Offsets\n// Offsets for identically positioned fields shared by:\n// OfferItem, ConsiderationItem, SpentItem, ReceivedItem\n\nuint256 constant Common_token_offset = 0x20;\nuint256 constant Common_identifier_offset = 0x40;\nuint256 constant Common_amount_offset = 0x60;\n\nuint256 constant ReceivedItem_size = 0xa0;\nuint256 constant ReceivedItem_amount_offset = 0x60;\nuint256 constant ReceivedItem_recipient_offset = 0x80;\n\nuint256 constant ReceivedItem_CommonParams_size = 0x60;\n\nuint256 constant ConsiderationItem_recipient_offset = 0xa0;\n// Store the same constant in an abbreviated format for a line length fix.\nuint256 constant ConsiderItem_recipient_offset = 0xa0;\n\nuint256 constant Execution_offerer_offset = 0x20;\nuint256 constant Execution_conduit_offset = 0x40;\n\nuint256 constant InvalidFulfillmentComponentData_error_signature = (\n    0x7fda727900000000000000000000000000000000000000000000000000000000\n);\nuint256 constant InvalidFulfillmentComponentData_error_len = 0x04;\n\nuint256 constant Panic_error_signature = (\n    0x4e487b7100000000000000000000000000000000000000000000000000000000\n);\nuint256 constant Panic_error_offset = 0x04;\nuint256 constant Panic_error_length = 0x24;\nuint256 constant Panic_arithmetic = 0x11;\n\nuint256 constant MissingItemAmount_error_signature = (\n    0x91b3e51400000000000000000000000000000000000000000000000000000000\n);\nuint256 constant MissingItemAmount_error_len = 0x04;\n\nuint256 constant OrderParameters_offer_head_offset = 0x20;\nuint256 constant OrderParameters_consideration_head_offset = 0x40;\nuint256 constant OrderParameters_conduit_offset = 0x200;\nuint256 constant OrderParameters_counter_offset = 0x220;\n\nuint256 constant Fulfillment_itemIndex_offset = 0x20;\n\nuint256 constant AdvancedOrder_numerator_offset = 0x20;\n\nuint256 constant AlmostOneWord = 0x1f;\nuint256 constant OneWord = 0x20;\nuint256 constant TwoWords = 0x40;\nuint256 constant ThreeWords = 0x60;\nuint256 constant FourWords = 0x80;\nuint256 constant FiveWords = 0xa0;\n\nuint256 constant FreeMemoryPointerSlot = 0x40;\nuint256 constant ZeroSlot = 0x60;\nuint256 constant DefaultFreeMemoryPointer = 0x80;\n\nuint256 constant Slot0x80 = 0x80;\nuint256 constant Slot0xA0 = 0xa0;\n\nuint256 constant BasicOrder_endAmount_cdPtr = 0x104;\nuint256 constant BasicOrder_common_params_size = 0xa0;\nuint256 constant BasicOrder_considerationHashesArray_ptr = 0x160;\n\nuint256 constant EIP712_Order_size = 0x260;\nuint256 constant AdditionalRecipients_size = 0x40;\n\nuint256 constant EIP712_DomainSeparator_offset = 0x02;\nuint256 constant EIP712_OrderHash_offset = 0x22;\nuint256 constant EIP712_DigestPayload_size = 0x42;\n\nuint256 constant receivedItemsHash_ptr = 0x60;\n\n/*\n *  Memory layout in _prepareBasicFulfillmentFromCalldata of\n *  data for OrderFulfilled\n *\n *   event OrderFulfilled(\n *     bytes32 orderHash,\n *     address indexed offerer,\n *     address indexed zone,\n *     address fulfiller,\n *     SpentItem[] offer,\n *       > (itemType, token, id, amount)\n *     ReceivedItem[] consideration\n *       > (itemType, token, id, amount, recipient)\n *   )\n *\n *  - 0x00: orderHash\n *  - 0x20: fulfiller\n *  - 0x40: offer offset (0x80)\n *  - 0x60: consideration offset (0x120)\n *  - 0x80: offer.length (1)\n *  - 0xa0: offerItemType\n *  - 0xc0: offerToken\n *  - 0xe0: offerIdentifier\n *  - 0x100: offerAmount\n *  - 0x120: consideration.length (1 + additionalRecipients.length)\n *  - 0x140: considerationItemType\n *  - 0x160: considerationToken\n *  - 0x180: considerationIdentifier\n *  - 0x1a0: considerationAmount\n *  - 0x1c0: considerationRecipient\n *  - ...\n */\n\n// Minimum length of the OrderFulfilled event data.\n// Must be added to the size of the ReceivedItem array for additionalRecipients\n// (0xa0 * additionalRecipients.length) to calculate full size of the buffer.\nuint256 constant OrderFulfilled_baseSize = 0x1e0;\nuint256 constant OrderFulfilled_selector = (\n    0x9d9af8e38d66c62e2c12f0225249fd9d721c54b83f48d9352c97c6cacdcb6f31\n);\n\n// Minimum offset in memory to OrderFulfilled event data.\n// Must be added to the size of the EIP712 hash array for additionalRecipients\n// (32 * additionalRecipients.length) to calculate the pointer to event data.\nuint256 constant OrderFulfilled_baseOffset = 0x180;\nuint256 constant OrderFulfilled_consideration_length_baseOffset = 0x2a0;\nuint256 constant OrderFulfilled_offer_length_baseOffset = 0x200;\n\n// uint256 constant OrderFulfilled_orderHash_offset = 0x00;\nuint256 constant OrderFulfilled_fulfiller_offset = 0x20;\nuint256 constant OrderFulfilled_offer_head_offset = 0x40;\nuint256 constant OrderFulfilled_offer_body_offset = 0x80;\nuint256 constant OrderFulfilled_consideration_head_offset = 0x60;\nuint256 constant OrderFulfilled_consideration_body_offset = 0x120;\n\n// BasicOrderParameters\nuint256 constant BasicOrder_parameters_cdPtr = 0x04;\nuint256 constant BasicOrder_considerationToken_cdPtr = 0x24;\n// uint256 constant BasicOrder_considerationIdentifier_cdPtr = 0x44;\nuint256 constant BasicOrder_considerationAmount_cdPtr = 0x64;\nuint256 constant BasicOrder_offerer_cdPtr = 0x84;\nuint256 constant BasicOrder_zone_cdPtr = 0xa4;\nuint256 constant BasicOrder_offerToken_cdPtr = 0xc4;\n// uint256 constant BasicOrder_offerIdentifier_cdPtr = 0xe4;\nuint256 constant BasicOrder_offerAmount_cdPtr = 0x104;\nuint256 constant BasicOrder_basicOrderType_cdPtr = 0x124;\nuint256 constant BasicOrder_startTime_cdPtr = 0x144;\n// uint256 constant BasicOrder_endTime_cdPtr = 0x164;\n// uint256 constant BasicOrder_zoneHash_cdPtr = 0x184;\n// uint256 constant BasicOrder_salt_cdPtr = 0x1a4;\nuint256 constant BasicOrder_offererConduit_cdPtr = 0x1c4;\nuint256 constant BasicOrder_fulfillerConduit_cdPtr = 0x1e4;\nuint256 constant BasicOrder_totalOriginalAdditionalRecipients_cdPtr = 0x204;\nuint256 constant BasicOrder_additionalRecipients_head_cdPtr = 0x224;\nuint256 constant BasicOrder_signature_cdPtr = 0x244;\nuint256 constant BasicOrder_additionalRecipients_length_cdPtr = 0x264;\nuint256 constant BasicOrder_additionalRecipients_data_cdPtr = 0x284;\n\nuint256 constant BasicOrder_parameters_ptr = 0x20;\n\nuint256 constant BasicOrder_basicOrderType_range = 0x18; // 24 values\n\n/*\n *  Memory layout in _prepareBasicFulfillmentFromCalldata of\n *  EIP712 data for ConsiderationItem\n *   - 0x80: ConsiderationItem EIP-712 typehash (constant)\n *   - 0xa0: itemType\n *   - 0xc0: token\n *   - 0xe0: identifier\n *   - 0x100: startAmount\n *   - 0x120: endAmount\n *   - 0x140: recipient\n */\nuint256 constant BasicOrder_considerationItem_typeHash_ptr = 0x80; // memoryPtr\nuint256 constant BasicOrder_considerationItem_itemType_ptr = 0xa0;\nuint256 constant BasicOrder_considerationItem_token_ptr = 0xc0;\nuint256 constant BasicOrder_considerationItem_identifier_ptr = 0xe0;\nuint256 constant BasicOrder_considerationItem_startAmount_ptr = 0x100;\nuint256 constant BasicOrder_considerationItem_endAmount_ptr = 0x120;\n// uint256 constant BasicOrder_considerationItem_recipient_ptr = 0x140;\n\n/*\n *  Memory layout in _prepareBasicFulfillmentFromCalldata of\n *  EIP712 data for OfferItem\n *   - 0x80:  OfferItem EIP-712 typehash (constant)\n *   - 0xa0:  itemType\n *   - 0xc0:  token\n *   - 0xe0:  identifier (reused for offeredItemsHash)\n *   - 0x100: startAmount\n *   - 0x120: endAmount\n */\nuint256 constant BasicOrder_offerItem_typeHash_ptr = DefaultFreeMemoryPointer;\nuint256 constant BasicOrder_offerItem_itemType_ptr = 0xa0;\nuint256 constant BasicOrder_offerItem_token_ptr = 0xc0;\n// uint256 constant BasicOrder_offerItem_identifier_ptr = 0xe0;\n// uint256 constant BasicOrder_offerItem_startAmount_ptr = 0x100;\nuint256 constant BasicOrder_offerItem_endAmount_ptr = 0x120;\n\n/*\n *  Memory layout in _prepareBasicFulfillmentFromCalldata of\n *  EIP712 data for Order\n *   - 0x80:   Order EIP-712 typehash (constant)\n *   - 0xa0:   orderParameters.offerer\n *   - 0xc0:   orderParameters.zone\n *   - 0xe0:   keccak256(abi.encodePacked(offerHashes))\n *   - 0x100:  keccak256(abi.encodePacked(considerationHashes))\n *   - 0x120:  orderType\n *   - 0x140:  startTime\n *   - 0x160:  endTime\n *   - 0x180:  zoneHash\n *   - 0x1a0:  salt\n *   - 0x1c0:  conduit\n *   - 0x1e0:  _counters[orderParameters.offerer] (from storage)\n */\nuint256 constant BasicOrder_order_typeHash_ptr = 0x80;\nuint256 constant BasicOrder_order_offerer_ptr = 0xa0;\n// uint256 constant BasicOrder_order_zone_ptr = 0xc0;\nuint256 constant BasicOrder_order_offerHashes_ptr = 0xe0;\nuint256 constant BasicOrder_order_considerationHashes_ptr = 0x100;\nuint256 constant BasicOrder_order_orderType_ptr = 0x120;\nuint256 constant BasicOrder_order_startTime_ptr = 0x140;\n// uint256 constant BasicOrder_order_endTime_ptr = 0x160;\n// uint256 constant BasicOrder_order_zoneHash_ptr = 0x180;\n// uint256 constant BasicOrder_order_salt_ptr = 0x1a0;\n// uint256 constant BasicOrder_order_conduitKey_ptr = 0x1c0;\nuint256 constant BasicOrder_order_counter_ptr = 0x1e0;\nuint256 constant BasicOrder_additionalRecipients_head_ptr = 0x240;\nuint256 constant BasicOrder_signature_ptr = 0x260;\n\n// Signature-related\nbytes32 constant EIP2098_allButHighestBitMask = (\n    0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\n);\nbytes32 constant ECDSA_twentySeventhAndTwentyEighthBytesSet = (\n    0x0000000000000000000000000000000000000000000000000000000101000000\n);\nuint256 constant ECDSA_MaxLength = 65;\nuint256 constant ECDSA_signature_s_offset = 0x40;\nuint256 constant ECDSA_signature_v_offset = 0x60;\n\nbytes32 constant EIP1271_isValidSignature_selector = (\n    0x1626ba7e00000000000000000000000000000000000000000000000000000000\n);\nuint256 constant EIP1271_isValidSignature_signatureHead_negativeOffset = 0x20;\nuint256 constant EIP1271_isValidSignature_digest_negativeOffset = 0x40;\nuint256 constant EIP1271_isValidSignature_selector_negativeOffset = 0x44;\nuint256 constant EIP1271_isValidSignature_calldata_baseLength = 0x64;\n\nuint256 constant EIP1271_isValidSignature_signature_head_offset = 0x40;\n\n// abi.encodeWithSignature(\"NoContract(address)\")\nuint256 constant NoContract_error_signature = (\n    0x5f15d67200000000000000000000000000000000000000000000000000000000\n);\nuint256 constant NoContract_error_sig_ptr = 0x0;\nuint256 constant NoContract_error_token_ptr = 0x4;\nuint256 constant NoContract_error_length = 0x24; // 4 + 32 == 36\n\nuint256 constant EIP_712_PREFIX = (\n    0x1901000000000000000000000000000000000000000000000000000000000000\n);\n\nuint256 constant ExtraGasBuffer = 0x20;\nuint256 constant CostPerWord = 3;\nuint256 constant MemoryExpansionCoefficient = 0x200; // 512\n\nuint256 constant Create2AddressDerivation_ptr = 0x0b;\nuint256 constant Create2AddressDerivation_length = 0x55;\n\nuint256 constant MaskOverByteTwelve = (\n    0x0000000000000000000000ff0000000000000000000000000000000000000000\n);\n\nuint256 constant MaskOverLastTwentyBytes = (\n    0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff\n);\n\nuint256 constant MaskOverFirstFourBytes = (\n    0xffffffff00000000000000000000000000000000000000000000000000000000\n);\n\nuint256 constant Conduit_execute_signature = (\n    0x4ce34aa200000000000000000000000000000000000000000000000000000000\n);\n\nuint256 constant MaxUint8 = 0xff;\nuint256 constant MaxUint120 = 0xffffffffffffffffffffffffffffff;\n\nuint256 constant Conduit_execute_ConduitTransfer_ptr = 0x20;\nuint256 constant Conduit_execute_ConduitTransfer_length = 0x01;\n\nuint256 constant Conduit_execute_ConduitTransfer_offset_ptr = 0x04;\nuint256 constant Conduit_execute_ConduitTransfer_length_ptr = 0x24;\nuint256 constant Conduit_execute_transferItemType_ptr = 0x44;\nuint256 constant Conduit_execute_transferToken_ptr = 0x64;\nuint256 constant Conduit_execute_transferFrom_ptr = 0x84;\nuint256 constant Conduit_execute_transferTo_ptr = 0xa4;\nuint256 constant Conduit_execute_transferIdentifier_ptr = 0xc4;\nuint256 constant Conduit_execute_transferAmount_ptr = 0xe4;\n\nuint256 constant OneConduitExecute_size = 0x104;\n\n// Sentinel value to indicate that the conduit accumulator is not armed.\nuint256 constant AccumulatorDisarmed = 0x20;\nuint256 constant AccumulatorArmed = 0x40;\nuint256 constant Accumulator_conduitKey_ptr = 0x20;\nuint256 constant Accumulator_selector_ptr = 0x40;\nuint256 constant Accumulator_array_offset_ptr = 0x44;\nuint256 constant Accumulator_array_length_ptr = 0x64;\n\nuint256 constant Accumulator_itemSizeOffsetDifference = 0x3c;\n\nuint256 constant Accumulator_array_offset = 0x20;\nuint256 constant Conduit_transferItem_size = 0xc0;\nuint256 constant Conduit_transferItem_token_ptr = 0x20;\nuint256 constant Conduit_transferItem_from_ptr = 0x40;\nuint256 constant Conduit_transferItem_to_ptr = 0x60;\nuint256 constant Conduit_transferItem_identifier_ptr = 0x80;\nuint256 constant Conduit_transferItem_amount_ptr = 0xa0;\n\n// Declare constant for errors related to amount derivation.\n// error InexactFraction() @ AmountDerivationErrors.sol\nuint256 constant InexactFraction_error_signature = (\n    0xc63cf08900000000000000000000000000000000000000000000000000000000\n);\nuint256 constant InexactFraction_error_len = 0x04;\n\n// Declare constant for errors related to signature verification.\nuint256 constant Ecrecover_precompile = 1;\nuint256 constant Ecrecover_args_size = 0x80;\nuint256 constant Signature_lower_v = 27;\n\n// error BadSignatureV(uint8) @ SignatureVerificationErrors.sol\nuint256 constant BadSignatureV_error_signature = (\n    0x1f003d0a00000000000000000000000000000000000000000000000000000000\n);\nuint256 constant BadSignatureV_error_offset = 0x04;\nuint256 constant BadSignatureV_error_length = 0x24;\n\n// error InvalidSigner() @ SignatureVerificationErrors.sol\nuint256 constant InvalidSigner_error_signature = (\n    0x815e1d6400000000000000000000000000000000000000000000000000000000\n);\nuint256 constant InvalidSigner_error_length = 0x04;\n\n// error InvalidSignature() @ SignatureVerificationErrors.sol\nuint256 constant InvalidSignature_error_signature = (\n    0x8baa579f00000000000000000000000000000000000000000000000000000000\n);\nuint256 constant InvalidSignature_error_length = 0x04;\n\n// error BadContractSignature() @ SignatureVerificationErrors.sol\nuint256 constant BadContractSignature_error_signature = (\n    0x4f7fb80d00000000000000000000000000000000000000000000000000000000\n);\nuint256 constant BadContractSignature_error_length = 0x04;\n\nuint256 constant NumBitsAfterSelector = 0xe0;\n\n// 69 is the lowest modulus for which the remainder\n// of every selector other than the two match functions\n// is greater than those of the match functions.\nuint256 constant NonMatchSelector_MagicModulus = 69;\n// Of the two match function selectors, the highest\n// remainder modulo 69 is 29.\nuint256 constant NonMatchSelector_MagicRemainder = 0x1d;\n"
    },
    "contracts/conduit/lib/ConduitStructs.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.7;\n\nimport { ConduitItemType } from \"./ConduitEnums.sol\";\n\nstruct ConduitTransfer {\n    ConduitItemType itemType;\n    address token;\n    address from;\n    address to;\n    uint256 identifier;\n    uint256 amount;\n}\n\nstruct ConduitBatch1155Transfer {\n    address token;\n    address from;\n    address to;\n    uint256[] ids;\n    uint256[] amounts;\n}\n"
    },
    "contracts/conduit/lib/ConduitEnums.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.7;\n\nenum ConduitItemType {\n    NATIVE, // unused\n    ERC20,\n    ERC721,\n    ERC1155\n}\n"
    },
    "contracts/lib/Executor.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport { ConduitInterface } from \"../interfaces/ConduitInterface.sol\";\n\nimport { ConduitItemType } from \"../conduit/lib/ConduitEnums.sol\";\n\nimport { ItemType } from \"./ConsiderationEnums.sol\";\n\nimport { Verifiers } from \"./Verifiers.sol\";\n\nimport { TokenTransferrer } from \"./TokenTransferrer.sol\";\n\nimport \"./ConsiderationConstants.sol\";\n\n/**\n * @title Executor\n * @author 0age\n * @notice Executor contains functions related to processing executions (i.e.\n *         transferring items, either directly or via conduits).\n */\ncontract Executor is Verifiers, TokenTransferrer {\n    /**\n     * @dev Derive and set hashes, reference chainId, and associated domain\n     *      separator during deployment.\n     *\n     * @param conduitController A contract that deploys conduits, or proxies\n     *                          that may optionally be used to transfer approved\n     *                          ERC20/721/1155 tokens.\n     */\n    constructor(address conduitController) Verifiers(conduitController) {}\n\n    /**\n     * @dev Internal function to transfer an individual ERC721 or ERC1155 item\n     *      from a given originator to a given recipient. The accumulator will\n     *      be bypassed, meaning that this function should be utilized in cases\n     *      where multiple item transfers can be accumulated into a single\n     *      conduit call. Sufficient approvals must be set, either on the\n     *      respective conduit or on this contract itself.\n     *\n     * @param itemType   The type of item to transfer, either ERC721 or ERC1155.\n     * @param token      The token to transfer.\n     * @param from       The originator of the transfer.\n     * @param to         The recipient of the transfer.\n     * @param identifier The tokenId to transfer.\n     * @param amount     The amount to transfer.\n     * @param conduitKey A bytes32 value indicating what corresponding conduit,\n     *                   if any, to source token approvals from. The zero hash\n     *                   signifies that no conduit should be used, with direct\n     *                   approvals set on this contract.\n     */\n    function _transferIndividual721Or1155Item(\n        ItemType itemType,\n        address token,\n        address from,\n        address to,\n        uint256 identifier,\n        uint256 amount,\n        bytes32 conduitKey\n    ) internal {\n        // Determine if the transfer is to be performed via a conduit.\n        if (conduitKey != bytes32(0)) {\n            // Use free memory pointer as calldata offset for the conduit call.\n            uint256 callDataOffset;\n\n            // Utilize assembly to place each argument in free memory.\n            assembly {\n                // Retrieve the free memory pointer and use it as the offset.\n                callDataOffset := mload(FreeMemoryPointerSlot)\n\n                // Write ConduitInterface.execute.selector to memory.\n                mstore(callDataOffset, Conduit_execute_signature)\n\n                // Write the offset to the ConduitTransfer array in memory.\n                mstore(\n                    add(\n                        callDataOffset,\n                        Conduit_execute_ConduitTransfer_offset_ptr\n                    ),\n                    Conduit_execute_ConduitTransfer_ptr\n                )\n\n                // Write the length of the ConduitTransfer array to memory.\n                mstore(\n                    add(\n                        callDataOffset,\n                        Conduit_execute_ConduitTransfer_length_ptr\n                    ),\n                    Conduit_execute_ConduitTransfer_length\n                )\n\n                // Write the item type to memory.\n                mstore(\n                    add(callDataOffset, Conduit_execute_transferItemType_ptr),\n                    itemType\n                )\n\n                // Write the token to memory.\n                mstore(\n                    add(callDataOffset, Conduit_execute_transferToken_ptr),\n                    token\n                )\n\n                // Write the transfer source to memory.\n                mstore(\n                    add(callDataOffset, Conduit_execute_transferFrom_ptr),\n                    from\n                )\n\n                // Write the transfer recipient to memory.\n                mstore(add(callDataOffset, Conduit_execute_transferTo_ptr), to)\n\n                // Write the token identifier to memory.\n                mstore(\n                    add(callDataOffset, Conduit_execute_transferIdentifier_ptr),\n                    identifier\n                )\n\n                // Write the transfer amount to memory.\n                mstore(\n                    add(callDataOffset, Conduit_execute_transferAmount_ptr),\n                    amount\n                )\n            }\n\n            // Perform the call to the conduit.\n            _callConduitUsingOffsets(\n                conduitKey,\n                callDataOffset,\n                OneConduitExecute_size\n            );\n        } else {\n            // Otherwise, determine whether it is an ERC721 or ERC1155 item.\n            if (itemType == ItemType.ERC721) {\n                // Ensure that exactly one 721 item is being transferred.\n                if (amount != 1) {\n                    revert InvalidERC721TransferAmount();\n                }\n\n                // Perform transfer via the token contract directly.\n                _performERC721Transfer(token, from, to, identifier);\n            } else {\n                // Perform transfer via the token contract directly.\n                _performERC1155Transfer(token, from, to, identifier, amount);\n            }\n        }\n    }\n\n    /**\n     * @dev Internal function to transfer Ether or other native tokens to a\n     *      given recipient.\n     *\n     * @param to     The recipient of the transfer.\n     * @param amount The amount to transfer.\n     */\n    function _transferEth(address payable to, uint256 amount) internal {\n        // Ensure that the supplied amount is non-zero.\n        _assertNonZeroAmount(amount);\n\n        // Declare a variable indicating whether the call was successful or not.\n        bool success;\n\n        assembly {\n            // Transfer the ETH and store if it succeeded or not.\n            success := call(gas(), to, amount, 0, 0, 0, 0)\n        }\n\n        // If the call fails...\n        if (!success) {\n            // Revert and pass the revert reason along if one was returned.\n            _revertWithReasonIfOneIsReturned();\n\n            // Otherwise, revert with a generic error message.\n            revert EtherTransferGenericFailure(to, amount);\n        }\n    }\n\n    /**\n     * @dev Internal function to transfer ERC20 tokens from a given originator\n     *      to a given recipient using a given conduit if applicable. Sufficient\n     *      approvals must be set on this contract or on a respective conduit.\n     *\n     * @param token       The ERC20 token to transfer.\n     * @param from        The originator of the transfer.\n     * @param to          The recipient of the transfer.\n     * @param amount      The amount to transfer.\n     * @param conduitKey  A bytes32 value indicating what corresponding conduit,\n     *                    if any, to source token approvals from. The zero hash\n     *                    signifies that no conduit should be used, with direct\n     *                    approvals set on this contract.\n     * @param accumulator An open-ended array that collects transfers to execute\n     *                    against a given conduit in a single call.\n     */\n    function _transferERC20(\n        address token,\n        address from,\n        address to,\n        uint256 amount,\n        bytes32 conduitKey,\n        bytes memory accumulator\n    ) internal {\n        // Ensure that the supplied amount is non-zero.\n        _assertNonZeroAmount(amount);\n\n        // Trigger accumulated transfers if the conduits differ.\n        _triggerIfArmedAndNotAccumulatable(accumulator, conduitKey);\n\n        // If no conduit has been specified...\n        if (conduitKey == bytes32(0)) {\n            // Perform the token transfer directly.\n            _performERC20Transfer(token, from, to, amount);\n        } else {\n            // Insert the call to the conduit into the accumulator.\n            _insert(\n                conduitKey,\n                accumulator,\n                ConduitItemType.ERC20,\n                token,\n                from,\n                to,\n                uint256(0),\n                amount\n            );\n        }\n    }\n\n    /**\n     * @dev Internal function to transfer a single ERC721 token from a given\n     *      originator to a given recipient. Sufficient approvals must be set,\n     *      either on the respective conduit or on this contract itself.\n     *\n     * @param token       The ERC721 token to transfer.\n     * @param from        The originator of the transfer.\n     * @param to          The recipient of the transfer.\n     * @param identifier  The tokenId to transfer (must be 1 for ERC721).\n     * @param amount      The amount to transfer.\n     * @param conduitKey  A bytes32 value indicating what corresponding conduit,\n     *                    if any, to source token approvals from. The zero hash\n     *                    signifies that no conduit should be used, with direct\n     *                    approvals set on this contract.\n     * @param accumulator An open-ended array that collects transfers to execute\n     *                    against a given conduit in a single call.\n     */\n    function _transferERC721(\n        address token,\n        address from,\n        address to,\n        uint256 identifier,\n        uint256 amount,\n        bytes32 conduitKey,\n        bytes memory accumulator\n    ) internal {\n        // Trigger accumulated transfers if the conduits differ.\n        _triggerIfArmedAndNotAccumulatable(accumulator, conduitKey);\n\n        // If no conduit has been specified...\n        if (conduitKey == bytes32(0)) {\n            // Ensure that exactly one 721 item is being transferred.\n            if (amount != 1) {\n                revert InvalidERC721TransferAmount();\n            }\n\n            // Perform transfer via the token contract directly.\n            _performERC721Transfer(token, from, to, identifier);\n        } else {\n            // Insert the call to the conduit into the accumulator.\n            _insert(\n                conduitKey,\n                accumulator,\n                ConduitItemType.ERC721,\n                token,\n                from,\n                to,\n                identifier,\n                amount\n            );\n        }\n    }\n\n    /**\n     * @dev Internal function to transfer ERC1155 tokens from a given originator\n     *      to a given recipient. Sufficient approvals must be set, either on\n     *      the respective conduit or on this contract itself.\n     *\n     * @param token       The ERC1155 token to transfer.\n     * @param from        The originator of the transfer.\n     * @param to          The recipient of the transfer.\n     * @param identifier  The id to transfer.\n     * @param amount      The amount to transfer.\n     * @param conduitKey  A bytes32 value indicating what corresponding conduit,\n     *                    if any, to source token approvals from. The zero hash\n     *                    signifies that no conduit should be used, with direct\n     *                    approvals set on this contract.\n     * @param accumulator An open-ended array that collects transfers to execute\n     *                    against a given conduit in a single call.\n     */\n    function _transferERC1155(\n        address token,\n        address from,\n        address to,\n        uint256 identifier,\n        uint256 amount,\n        bytes32 conduitKey,\n        bytes memory accumulator\n    ) internal {\n        // Ensure that the supplied amount is non-zero.\n        _assertNonZeroAmount(amount);\n\n        // Trigger accumulated transfers if the conduits differ.\n        _triggerIfArmedAndNotAccumulatable(accumulator, conduitKey);\n\n        // If no conduit has been specified...\n        if (conduitKey == bytes32(0)) {\n            // Perform transfer via the token contract directly.\n            _performERC1155Transfer(token, from, to, identifier, amount);\n        } else {\n            // Insert the call to the conduit into the accumulator.\n            _insert(\n                conduitKey,\n                accumulator,\n                ConduitItemType.ERC1155,\n                token,\n                from,\n                to,\n                identifier,\n                amount\n            );\n        }\n    }\n\n    /**\n     * @dev Internal function to trigger a call to the conduit currently held by\n     *      the accumulator if the accumulator contains item transfers (i.e. it\n     *      is \"armed\") and the supplied conduit key does not match the key held\n     *      by the accumulator.\n     *\n     * @param accumulator An open-ended array that collects transfers to execute\n     *                    against a given conduit in a single call.\n     * @param conduitKey  A bytes32 value indicating what corresponding conduit,\n     *                    if any, to source token approvals from. The zero hash\n     *                    signifies that no conduit should be used, with direct\n     *                    approvals set on this contract.\n     */\n    function _triggerIfArmedAndNotAccumulatable(\n        bytes memory accumulator,\n        bytes32 conduitKey\n    ) internal {\n        // Retrieve the current conduit key from the accumulator.\n        bytes32 accumulatorConduitKey = _getAccumulatorConduitKey(accumulator);\n\n        // Perform conduit call if the set key does not match the supplied key.\n        if (accumulatorConduitKey != conduitKey) {\n            _triggerIfArmed(accumulator);\n        }\n    }\n\n    /**\n     * @dev Internal function to trigger a call to the conduit currently held by\n     *      the accumulator if the accumulator contains item transfers (i.e. it\n     *      is \"armed\").\n     *\n     * @param accumulator An open-ended array that collects transfers to execute\n     *                    against a given conduit in a single call.\n     */\n    function _triggerIfArmed(bytes memory accumulator) internal {\n        // Exit if the accumulator is not \"armed\".\n        if (accumulator.length != AccumulatorArmed) {\n            return;\n        }\n\n        // Retrieve the current conduit key from the accumulator.\n        bytes32 accumulatorConduitKey = _getAccumulatorConduitKey(accumulator);\n\n        // Perform conduit call.\n        _trigger(accumulatorConduitKey, accumulator);\n    }\n\n    /**\n     * @dev Internal function to trigger a call to the conduit corresponding to\n     *      a given conduit key, supplying all accumulated item transfers. The\n     *      accumulator will be \"disarmed\" and reset in the process.\n     *\n     * @param conduitKey  A bytes32 value indicating what corresponding conduit,\n     *                    if any, to source token approvals from. The zero hash\n     *                    signifies that no conduit should be used, with direct\n     *                    approvals set on this contract.\n     * @param accumulator An open-ended array that collects transfers to execute\n     *                    against a given conduit in a single call.\n     */\n    function _trigger(bytes32 conduitKey, bytes memory accumulator) internal {\n        // Declare variables for offset in memory & size of calldata to conduit.\n        uint256 callDataOffset;\n        uint256 callDataSize;\n\n        // Call the conduit with all the accumulated transfers.\n        assembly {\n            // Call begins at third word; the first is length or \"armed\" status,\n            // and the second is the current conduit key.\n            callDataOffset := add(accumulator, TwoWords)\n\n            // 68 + items * 192\n            callDataSize := add(\n                Accumulator_array_offset_ptr,\n                mul(\n                    mload(add(accumulator, Accumulator_array_length_ptr)),\n                    Conduit_transferItem_size\n                )\n            )\n        }\n\n        // Call conduit derived from conduit key & supply accumulated transfers.\n        _callConduitUsingOffsets(conduitKey, callDataOffset, callDataSize);\n\n        // Reset accumulator length to signal that it is now \"disarmed\".\n        assembly {\n            mstore(accumulator, AccumulatorDisarmed)\n        }\n    }\n\n    /**\n     * @dev Internal function to perform a call to the conduit corresponding to\n     *      a given conduit key based on the offset and size of the calldata in\n     *      question in memory.\n     *\n     * @param conduitKey     A bytes32 value indicating what corresponding\n     *                       conduit, if any, to source token approvals from.\n     *                       The zero hash signifies that no conduit should be\n     *                       used, with direct approvals set on this contract.\n     * @param callDataOffset The memory pointer where calldata is contained.\n     * @param callDataSize   The size of calldata in memory.\n     */\n    function _callConduitUsingOffsets(\n        bytes32 conduitKey,\n        uint256 callDataOffset,\n        uint256 callDataSize\n    ) internal {\n        // Derive the address of the conduit using the conduit key.\n        address conduit = _deriveConduit(conduitKey);\n\n        bool success;\n        bytes4 result;\n\n        // call the conduit.\n        assembly {\n            // Ensure first word of scratch space is empty.\n            mstore(0, 0)\n\n            // Perform call, placing first word of return data in scratch space.\n            success := call(\n                gas(),\n                conduit,\n                0,\n                callDataOffset,\n                callDataSize,\n                0,\n                OneWord\n            )\n\n            // Take value from scratch space and place it on the stack.\n            result := mload(0)\n        }\n\n        // If the call failed...\n        if (!success) {\n            // Pass along whatever revert reason was given by the conduit.\n            _revertWithReasonIfOneIsReturned();\n\n            // Otherwise, revert with a generic error.\n            revert InvalidCallToConduit(conduit);\n        }\n\n        // Ensure result was extracted and matches EIP-1271 magic value.\n        if (result != ConduitInterface.execute.selector) {\n            revert InvalidConduit(conduitKey, conduit);\n        }\n    }\n\n    /**\n     * @dev Internal pure function to retrieve the current conduit key set for\n     *      the accumulator.\n     *\n     * @param accumulator An open-ended array that collects transfers to execute\n     *                    against a given conduit in a single call.\n     *\n     * @return accumulatorConduitKey The conduit key currently set for the\n     *                               accumulator.\n     */\n    function _getAccumulatorConduitKey(bytes memory accumulator)\n        internal\n        pure\n        returns (bytes32 accumulatorConduitKey)\n    {\n        // Retrieve the current conduit key from the accumulator.\n        assembly {\n            accumulatorConduitKey := mload(\n                add(accumulator, Accumulator_conduitKey_ptr)\n            )\n        }\n    }\n\n    /**\n     * @dev Internal pure function to place an item transfer into an accumulator\n     *      that collects a series of transfers to execute against a given\n     *      conduit in a single call.\n     *\n     * @param conduitKey  A bytes32 value indicating what corresponding conduit,\n     *                    if any, to source token approvals from. The zero hash\n     *                    signifies that no conduit should be used, with direct\n     *                    approvals set on this contract.\n     * @param accumulator An open-ended array that collects transfers to execute\n     *                    against a given conduit in a single call.\n     * @param itemType    The type of the item to transfer.\n     * @param token       The token to transfer.\n     * @param from        The originator of the transfer.\n     * @param to          The recipient of the transfer.\n     * @param identifier  The tokenId to transfer.\n     * @param amount      The amount to transfer.\n     */\n    function _insert(\n        bytes32 conduitKey,\n        bytes memory accumulator,\n        ConduitItemType itemType,\n        address token,\n        address from,\n        address to,\n        uint256 identifier,\n        uint256 amount\n    ) internal pure {\n        uint256 elements;\n        // \"Arm\" and prime accumulator if it's not already armed. The sentinel\n        // value is held in the length of the accumulator array.\n        if (accumulator.length == AccumulatorDisarmed) {\n            elements = 1;\n            bytes4 selector = ConduitInterface.execute.selector;\n            assembly {\n                mstore(accumulator, AccumulatorArmed) // \"arm\" the accumulator.\n                mstore(add(accumulator, Accumulator_conduitKey_ptr), conduitKey)\n                mstore(add(accumulator, Accumulator_selector_ptr), selector)\n                mstore(\n                    add(accumulator, Accumulator_array_offset_ptr),\n                    Accumulator_array_offset\n                )\n                mstore(add(accumulator, Accumulator_array_length_ptr), elements)\n            }\n        } else {\n            // Otherwise, increase the number of elements by one.\n            assembly {\n                elements := add(\n                    mload(add(accumulator, Accumulator_array_length_ptr)),\n                    1\n                )\n                mstore(add(accumulator, Accumulator_array_length_ptr), elements)\n            }\n        }\n\n        // Insert the item.\n        assembly {\n            let itemPointer := sub(\n                add(accumulator, mul(elements, Conduit_transferItem_size)),\n                Accumulator_itemSizeOffsetDifference\n            )\n            mstore(itemPointer, itemType)\n            mstore(add(itemPointer, Conduit_transferItem_token_ptr), token)\n            mstore(add(itemPointer, Conduit_transferItem_from_ptr), from)\n            mstore(add(itemPointer, Conduit_transferItem_to_ptr), to)\n            mstore(\n                add(itemPointer, Conduit_transferItem_identifier_ptr),\n                identifier\n            )\n            mstore(add(itemPointer, Conduit_transferItem_amount_ptr), amount)\n        }\n    }\n}\n"
    },
    "contracts/lib/Shadow.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport { IERC4907A } from \"erc721a/contracts/extensions/IERC4907A.sol\";\n\ninterface IMintBurnableERC4907 {\n    function mint(address to, address tokenAddress, uint256 tokenId) external returns (uint256);\n    function burn(uint256 tokenId) external;\n}\n\ncontract Shadow {\n    \n    address public immutable shadowToken;\n\n    constructor(address _token) {\n        shadowToken = _token;\n    }\n\n    function _mintToken(\n        address to,\n        address token,\n        uint256 identifier,\n        uint256 duration\n    ) internal returns (uint256) {\n        uint256 tid = IMintBurnableERC4907(shadowToken).mint(address(this), token, identifier);\n        IERC4907A(shadowToken).setUser(tid, to, uint64(duration + block.timestamp));\n        return tid;\n    }\n\n    function _extendToken(address to, uint256 tokenId, uint256 expires) internal {\n        IERC4907A(shadowToken).setUser(tokenId, to, uint64(expires));\n    }\n\n    function _burnToken(uint256 tokenId) internal {\n        IMintBurnableERC4907(shadowToken).burn(tokenId);\n    }\n}"
    },
    "contracts/lib/Verifiers.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport { OrderStatus } from \"./ConsiderationStructs.sol\";\n\nimport { Assertions } from \"./Assertions.sol\";\n\nimport { SignatureVerification } from \"./SignatureVerification.sol\";\n\n/**\n * @title Verifiers\n * @author 0age\n * @notice Verifiers contains functions for performing verifications.\n */\ncontract Verifiers is Assertions, SignatureVerification {\n    /**\n     * @dev Derive and set hashes, reference chainId, and associated domain\n     *      separator during deployment.\n     *\n     * @param conduitController A contract that deploys conduits, or proxies\n     *                          that may optionally be used to transfer approved\n     *                          ERC20/721/1155 tokens.\n     */\n    constructor(address conduitController) Assertions(conduitController) {}\n\n    /**\n     * @dev Internal view function to ensure that the current time falls within\n     *      an order's valid timespan.\n     *\n     * @param startTime       The time at which the order becomes active.\n     * @param endTime         The time at which the order becomes inactive.\n     * @param revertOnInvalid A boolean indicating whether to revert if the\n     *                        order is not active.\n     *\n     * @return valid A boolean indicating whether the order is active.\n     */\n    function _verifyTime(\n        uint256 startTime,\n        uint256 endTime,\n        bool revertOnInvalid\n    ) internal view returns (bool valid) {\n        // Revert if order's timespan hasn't started yet or has already ended.\n        if (startTime > block.timestamp || endTime <= block.timestamp) {\n            // Only revert if revertOnInvalid has been supplied as true.\n            if (revertOnInvalid) {\n                revert InvalidTime();\n            }\n\n            // Return false as the order is invalid.\n            return false;\n        }\n\n        // Return true as the order time is valid.\n        valid = true;\n    }\n\n    /**\n     * @dev Internal view function to verify the signature of an order. An\n     *      ERC-1271 fallback will be attempted if either the signature length\n     *      is not 64 or 65 bytes or if the recovered signer does not match the\n     *      supplied offerer. Note that in cases where a 64 or 65 byte signature\n     *      is supplied, only standard ECDSA signatures that recover to a\n     *      non-zero address are supported.\n     *\n     * @param offerer   The offerer for the order.\n     * @param orderHash The order hash.\n     * @param signature A signature from the offerer indicating that the order\n     *                  has been approved.\n     */\n    function _verifySignature(\n        address offerer,\n        bytes32 orderHash,\n        bytes memory signature\n    ) internal view {\n        // Skip signature verification if the offerer is the caller.\n        if (offerer == msg.sender) {\n            return;\n        }\n\n        // Derive EIP-712 digest using the domain separator and the order hash.\n        bytes32 digest = _deriveEIP712Digest(_domainSeparator(), orderHash);\n\n        // Ensure that the signature for the digest is valid for the offerer.\n        _assertValidSignature(offerer, digest, signature);\n    }\n\n    function _verifyOrderStatus(\n        bytes32 orderHash,\n        OrderStatus storage orderStatus,\n        bool firstPay,\n        bool revertOnInvalid\n    ) internal view returns (bool valid) {\n        if (orderStatus.isCancelled) {\n            if (revertOnInvalid) {\n                revert OrderIsCancelled(orderHash);\n            }\n\n            return false;\n        }\n\n        if (orderStatus.isFinalized) {\n            if (revertOnInvalid) {\n                revert OrderAlreadyFinalized(orderHash);\n            }\n\n            return false;\n        }\n\n        if (firstPay) {\n            if (orderStatus.paidTimes > 0) {\n                if (revertOnInvalid) {\n                    revert OrderAlreadyStarted(orderHash);\n                }\n                return false;\n            }\n        } else {\n            if (orderStatus.paidTimes == 0) {\n                if (revertOnInvalid) {\n                    revert OrderNotStarted(orderHash);\n                }\n                return false;\n            }\n        }\n\n        valid = true;\n    }\n}\n"
    },
    "contracts/lib/TokenTransferrer.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.7;\n\nimport \"./TokenTransferrerConstants.sol\";\n\nimport {\n    TokenTransferrerErrors\n} from \"../interfaces/TokenTransferrerErrors.sol\";\n\nimport { ConduitBatch1155Transfer } from \"../conduit/lib/ConduitStructs.sol\";\n\n/**\n * @title TokenTransferrer\n * @author 0age\n * @custom:coauthor d1ll0n\n * @custom:coauthor transmissions11\n * @notice TokenTransferrer is a library for performing optimized ERC20, ERC721,\n *         ERC1155, and batch ERC1155 transfers, used by both Seaport as well as\n *         by conduits deployed by the ConduitController. Use great caution when\n *         considering these functions for use in other codebases, as there are\n *         significant side effects and edge cases that need to be thoroughly\n *         understood and carefully addressed.\n */\ncontract TokenTransferrer is TokenTransferrerErrors {\n    /**\n     * @dev Internal function to transfer ERC20 tokens from a given originator\n     *      to a given recipient. Sufficient approvals must be set on the\n     *      contract performing the transfer.\n     *\n     * @param token      The ERC20 token to transfer.\n     * @param from       The originator of the transfer.\n     * @param to         The recipient of the transfer.\n     * @param amount     The amount to transfer.\n     */\n    function _performERC20Transfer(\n        address token,\n        address from,\n        address to,\n        uint256 amount\n    ) internal {\n        // Utilize assembly to perform an optimized ERC20 token transfer.\n        assembly {\n            // The free memory pointer memory slot will be used when populating\n            // call data for the transfer; read the value and restore it later.\n            let memPointer := mload(FreeMemoryPointerSlot)\n\n            // Write call data into memory, starting with function selector.\n            mstore(ERC20_transferFrom_sig_ptr, ERC20_transferFrom_signature)\n            mstore(ERC20_transferFrom_from_ptr, from)\n            mstore(ERC20_transferFrom_to_ptr, to)\n            mstore(ERC20_transferFrom_amount_ptr, amount)\n\n            // Make call & copy up to 32 bytes of return data to scratch space.\n            // Scratch space does not need to be cleared ahead of time, as the\n            // subsequent check will ensure that either at least a full word of\n            // return data is received (in which case it will be overwritten) or\n            // that no data is received (in which case scratch space will be\n            // ignored) on a successful call to the given token.\n            let callStatus := call(\n                gas(),\n                token,\n                0,\n                ERC20_transferFrom_sig_ptr,\n                ERC20_transferFrom_length,\n                0,\n                OneWord\n            )\n\n            // Determine whether transfer was successful using status & result.\n            let success := and(\n                // Set success to whether the call reverted, if not check it\n                // either returned exactly 1 (can't just be non-zero data), or\n                // had no return data.\n                or(\n                    and(eq(mload(0), 1), gt(returndatasize(), 31)),\n                    iszero(returndatasize())\n                ),\n                callStatus\n            )\n\n            // Handle cases where either the transfer failed or no data was\n            // returned. Group these, as most transfers will succeed with data.\n            // Equivalent to `or(iszero(success), iszero(returndatasize()))`\n            // but after it's inverted for JUMPI this expression is cheaper.\n            if iszero(and(success, iszero(iszero(returndatasize())))) {\n                // If the token has no code or the transfer failed: Equivalent\n                // to `or(iszero(success), iszero(extcodesize(token)))` but\n                // after it's inverted for JUMPI this expression is cheaper.\n                if iszero(and(iszero(iszero(extcodesize(token))), success)) {\n                    // If the transfer failed:\n                    if iszero(success) {\n                        // If it was due to a revert:\n                        if iszero(callStatus) {\n                            // If it returned a message, bubble it up as long as\n                            // sufficient gas remains to do so:\n                            if returndatasize() {\n                                // Ensure that sufficient gas is available to\n                                // copy returndata while expanding memory where\n                                // necessary. Start by computing the word size\n                                // of returndata and allocated memory. Round up\n                                // to the nearest full word.\n                                let returnDataWords := div(\n                                    add(returndatasize(), AlmostOneWord),\n                                    OneWord\n                                )\n\n                                // Note: use the free memory pointer in place of\n                                // msize() to work around a Yul warning that\n                                // prevents accessing msize directly when the IR\n                                // pipeline is activated.\n                                let msizeWords := div(memPointer, OneWord)\n\n                                // Next, compute the cost of the returndatacopy.\n                                let cost := mul(CostPerWord, returnDataWords)\n\n                                // Then, compute cost of new memory allocation.\n                                if gt(returnDataWords, msizeWords) {\n                                    cost := add(\n                                        cost,\n                                        add(\n                                            mul(\n                                                sub(\n                                                    returnDataWords,\n                                                    msizeWords\n                                                ),\n                                                CostPerWord\n                                            ),\n                                            div(\n                                                sub(\n                                                    mul(\n                                                        returnDataWords,\n                                                        returnDataWords\n                                                    ),\n                                                    mul(msizeWords, msizeWords)\n                                                ),\n                                                MemoryExpansionCoefficient\n                                            )\n                                        )\n                                    )\n                                }\n\n                                // Finally, add a small constant and compare to\n                                // gas remaining; bubble up the revert data if\n                                // enough gas is still available.\n                                if lt(add(cost, ExtraGasBuffer), gas()) {\n                                    // Copy returndata to memory; overwrite\n                                    // existing memory.\n                                    returndatacopy(0, 0, returndatasize())\n\n                                    // Revert, specifying memory region with\n                                    // copied returndata.\n                                    revert(0, returndatasize())\n                                }\n                            }\n\n                            // Otherwise revert with a generic error message.\n                            mstore(\n                                TokenTransferGenericFailure_error_sig_ptr,\n                                TokenTransferGenericFailure_error_signature\n                            )\n                            mstore(\n                                TokenTransferGenericFailure_error_token_ptr,\n                                token\n                            )\n                            mstore(\n                                TokenTransferGenericFailure_error_from_ptr,\n                                from\n                            )\n                            mstore(TokenTransferGenericFailure_error_to_ptr, to)\n                            mstore(TokenTransferGenericFailure_error_id_ptr, 0)\n                            mstore(\n                                TokenTransferGenericFailure_error_amount_ptr,\n                                amount\n                            )\n                            revert(\n                                TokenTransferGenericFailure_error_sig_ptr,\n                                TokenTransferGenericFailure_error_length\n                            )\n                        }\n\n                        // Otherwise revert with a message about the token\n                        // returning false or non-compliant return values.\n                        mstore(\n                            BadReturnValueFromERC20OnTransfer_error_sig_ptr,\n                            BadReturnValueFromERC20OnTransfer_error_signature\n                        )\n                        mstore(\n                            BadReturnValueFromERC20OnTransfer_error_token_ptr,\n                            token\n                        )\n                        mstore(\n                            BadReturnValueFromERC20OnTransfer_error_from_ptr,\n                            from\n                        )\n                        mstore(\n                            BadReturnValueFromERC20OnTransfer_error_to_ptr,\n                            to\n                        )\n                        mstore(\n                            BadReturnValueFromERC20OnTransfer_error_amount_ptr,\n                            amount\n                        )\n                        revert(\n                            BadReturnValueFromERC20OnTransfer_error_sig_ptr,\n                            BadReturnValueFromERC20OnTransfer_error_length\n                        )\n                    }\n\n                    // Otherwise, revert with error about token not having code:\n                    mstore(NoContract_error_sig_ptr, NoContract_error_signature)\n                    mstore(NoContract_error_token_ptr, token)\n                    revert(NoContract_error_sig_ptr, NoContract_error_length)\n                }\n\n                // Otherwise, the token just returned no data despite the call\n                // having succeeded; no need to optimize for this as it's not\n                // technically ERC20 compliant.\n            }\n\n            // Restore the original free memory pointer.\n            mstore(FreeMemoryPointerSlot, memPointer)\n\n            // Restore the zero slot to zero.\n            mstore(ZeroSlot, 0)\n        }\n    }\n\n    function _performSelfERC20Transfer(\n        address token,\n        address to,\n        uint256 amount\n    ) internal {\n        // Utilize assembly to perform an optimized ERC20 token transfer.\n        assembly {\n            // The free memory pointer memory slot will be used when populating\n            // call data for the transfer; read the value and restore it later.\n            let memPointer := mload(FreeMemoryPointerSlot)\n\n            // Write call data into memory, starting with function selector.\n            mstore(ERC20_transfer_sig_ptr, ERC20_transfer_signature)\n            mstore(ERC20_transfer_to_ptr, to)\n            mstore(ERC20_transfer_amount_ptr, amount)\n\n            // Make call & copy up to 32 bytes of return data to scratch space.\n            // Scratch space does not need to be cleared ahead of time, as the\n            // subsequent check will ensure that either at least a full word of\n            // return data is received (in which case it will be overwritten) or\n            // that no data is received (in which case scratch space will be\n            // ignored) on a successful call to the given token.\n            let callStatus := call(\n                gas(),\n                token,\n                0,\n                ERC20_transfer_sig_ptr,\n                ERC20_transfer_length,\n                0,\n                OneWord\n            )\n\n            // Determine whether transfer was successful using status & result.\n            let success := and(\n                // Set success to whether the call reverted, if not check it\n                // either returned exactly 1 (can't just be non-zero data), or\n                // had no return data.\n                or(\n                    and(eq(mload(0), 1), gt(returndatasize(), 31)),\n                    iszero(returndatasize())\n                ),\n                callStatus\n            )\n\n            // Handle cases where either the transfer failed or no data was\n            // returned. Group these, as most transfers will succeed with data.\n            // Equivalent to `or(iszero(success), iszero(returndatasize()))`\n            // but after it's inverted for JUMPI this expression is cheaper.\n            if iszero(and(success, iszero(iszero(returndatasize())))) {\n                // If the token has no code or the transfer failed: Equivalent\n                // to `or(iszero(success), iszero(extcodesize(token)))` but\n                // after it's inverted for JUMPI this expression is cheaper.\n                if iszero(and(iszero(iszero(extcodesize(token))), success)) {\n                    // If the transfer failed:\n                    if iszero(success) {\n                        // If it was due to a revert:\n                        if iszero(callStatus) {\n                            // If it returned a message, bubble it up as long as\n                            // sufficient gas remains to do so:\n                            if returndatasize() {\n                                // Ensure that sufficient gas is available to\n                                // copy returndata while expanding memory where\n                                // necessary. Start by computing the word size\n                                // of returndata and allocated memory. Round up\n                                // to the nearest full word.\n                                let returnDataWords := div(\n                                    add(returndatasize(), AlmostOneWord),\n                                    OneWord\n                                )\n\n                                // Note: use the free memory pointer in place of\n                                // msize() to work around a Yul warning that\n                                // prevents accessing msize directly when the IR\n                                // pipeline is activated.\n                                let msizeWords := div(memPointer, OneWord)\n\n                                // Next, compute the cost of the returndatacopy.\n                                let cost := mul(CostPerWord, returnDataWords)\n\n                                // Then, compute cost of new memory allocation.\n                                if gt(returnDataWords, msizeWords) {\n                                    cost := add(\n                                        cost,\n                                        add(\n                                            mul(\n                                                sub(\n                                                    returnDataWords,\n                                                    msizeWords\n                                                ),\n                                                CostPerWord\n                                            ),\n                                            div(\n                                                sub(\n                                                    mul(\n                                                        returnDataWords,\n                                                        returnDataWords\n                                                    ),\n                                                    mul(msizeWords, msizeWords)\n                                                ),\n                                                MemoryExpansionCoefficient\n                                            )\n                                        )\n                                    )\n                                }\n\n                                // Finally, add a small constant and compare to\n                                // gas remaining; bubble up the revert data if\n                                // enough gas is still available.\n                                if lt(add(cost, ExtraGasBuffer), gas()) {\n                                    // Copy returndata to memory; overwrite\n                                    // existing memory.\n                                    returndatacopy(0, 0, returndatasize())\n\n                                    // Revert, specifying memory region with\n                                    // copied returndata.\n                                    revert(0, returndatasize())\n                                }\n                            }\n\n                            // Otherwise revert with a generic error message.\n                            mstore(\n                                TokenTransferGenericFailure_error_sig_ptr,\n                                TokenTransferGenericFailure_error_signature\n                            )\n                            mstore(\n                                TokenTransferGenericFailure_error_token_ptr,\n                                token\n                            )\n                            mstore(\n                                TokenTransferGenericFailure_error_from_ptr,\n                                address()\n                            )\n                            mstore(TokenTransferGenericFailure_error_to_ptr, to)\n                            mstore(TokenTransferGenericFailure_error_id_ptr, 0)\n                            mstore(\n                                TokenTransferGenericFailure_error_amount_ptr,\n                                amount\n                            )\n                            revert(\n                                TokenTransferGenericFailure_error_sig_ptr,\n                                TokenTransferGenericFailure_error_length\n                            )\n                        }\n\n                        // Otherwise revert with a message about the token\n                        // returning false or non-compliant return values.\n                        mstore(\n                            BadReturnValueFromERC20OnTransfer_error_sig_ptr,\n                            BadReturnValueFromERC20OnTransfer_error_signature\n                        )\n                        mstore(\n                            BadReturnValueFromERC20OnTransfer_error_token_ptr,\n                            token\n                        )\n                        mstore(\n                            BadReturnValueFromERC20OnTransfer_error_from_ptr,\n                            address()\n                        )\n                        mstore(\n                            BadReturnValueFromERC20OnTransfer_error_to_ptr,\n                            to\n                        )\n                        mstore(\n                            BadReturnValueFromERC20OnTransfer_error_amount_ptr,\n                            amount\n                        )\n                        revert(\n                            BadReturnValueFromERC20OnTransfer_error_sig_ptr,\n                            BadReturnValueFromERC20OnTransfer_error_length\n                        )\n                    }\n\n                    // Otherwise, revert with error about token not having code:\n                    mstore(NoContract_error_sig_ptr, NoContract_error_signature)\n                    mstore(NoContract_error_token_ptr, token)\n                    revert(NoContract_error_sig_ptr, NoContract_error_length)\n                }\n\n                // Otherwise, the token just returned no data despite the call\n                // having succeeded; no need to optimize for this as it's not\n                // technically ERC20 compliant.\n            }\n\n            // Restore the original free memory pointer.\n            mstore(FreeMemoryPointerSlot, memPointer)\n\n            // Restore the zero slot to zero.\n            mstore(ZeroSlot, 0)\n        }\n    }\n\n    /**\n     * @dev Internal function to transfer an ERC721 token from a given\n     *      originator to a given recipient. Sufficient approvals must be set on\n     *      the contract performing the transfer. Note that this function does\n     *      not check whether the receiver can accept the ERC721 token (i.e. it\n     *      does not use `safeTransferFrom`).\n     *\n     * @param token      The ERC721 token to transfer.\n     * @param from       The originator of the transfer.\n     * @param to         The recipient of the transfer.\n     * @param identifier The tokenId to transfer.\n     */\n    function _performERC721Transfer(\n        address token,\n        address from,\n        address to,\n        uint256 identifier\n    ) internal {\n        // Utilize assembly to perform an optimized ERC721 token transfer.\n        assembly {\n            // If the token has no code, revert.\n            if iszero(extcodesize(token)) {\n                mstore(NoContract_error_sig_ptr, NoContract_error_signature)\n                mstore(NoContract_error_token_ptr, token)\n                revert(NoContract_error_sig_ptr, NoContract_error_length)\n            }\n\n            // The free memory pointer memory slot will be used when populating\n            // call data for the transfer; read the value and restore it later.\n            let memPointer := mload(FreeMemoryPointerSlot)\n\n            // Write call data to memory starting with function selector.\n            mstore(ERC721_transferFrom_sig_ptr, ERC721_transferFrom_signature)\n            mstore(ERC721_transferFrom_from_ptr, from)\n            mstore(ERC721_transferFrom_to_ptr, to)\n            mstore(ERC721_transferFrom_id_ptr, identifier)\n\n            // Perform the call, ignoring return data.\n            let success := call(\n                gas(),\n                token,\n                0,\n                ERC721_transferFrom_sig_ptr,\n                ERC721_transferFrom_length,\n                0,\n                0\n            )\n\n            // If the transfer reverted:\n            if iszero(success) {\n                // If it returned a message, bubble it up as long as sufficient\n                // gas remains to do so:\n                if returndatasize() {\n                    // Ensure that sufficient gas is available to copy\n                    // returndata while expanding memory where necessary. Start\n                    // by computing word size of returndata & allocated memory.\n                    // Round up to the nearest full word.\n                    let returnDataWords := div(\n                        add(returndatasize(), AlmostOneWord),\n                        OneWord\n                    )\n\n                    // Note: use the free memory pointer in place of msize() to\n                    // work around a Yul warning that prevents accessing msize\n                    // directly when the IR pipeline is activated.\n                    let msizeWords := div(memPointer, OneWord)\n\n                    // Next, compute the cost of the returndatacopy.\n                    let cost := mul(CostPerWord, returnDataWords)\n\n                    // Then, compute cost of new memory allocation.\n                    if gt(returnDataWords, msizeWords) {\n                        cost := add(\n                            cost,\n                            add(\n                                mul(\n                                    sub(returnDataWords, msizeWords),\n                                    CostPerWord\n                                ),\n                                div(\n                                    sub(\n                                        mul(returnDataWords, returnDataWords),\n                                        mul(msizeWords, msizeWords)\n                                    ),\n                                    MemoryExpansionCoefficient\n                                )\n                            )\n                        )\n                    }\n\n                    // Finally, add a small constant and compare to gas\n                    // remaining; bubble up the revert data if enough gas is\n                    // still available.\n                    if lt(add(cost, ExtraGasBuffer), gas()) {\n                        // Copy returndata to memory; overwrite existing memory.\n                        returndatacopy(0, 0, returndatasize())\n\n                        // Revert, giving memory region with copied returndata.\n                        revert(0, returndatasize())\n                    }\n                }\n\n                // Otherwise revert with a generic error message.\n                mstore(\n                    TokenTransferGenericFailure_error_sig_ptr,\n                    TokenTransferGenericFailure_error_signature\n                )\n                mstore(TokenTransferGenericFailure_error_token_ptr, token)\n                mstore(TokenTransferGenericFailure_error_from_ptr, from)\n                mstore(TokenTransferGenericFailure_error_to_ptr, to)\n                mstore(TokenTransferGenericFailure_error_id_ptr, identifier)\n                mstore(TokenTransferGenericFailure_error_amount_ptr, 1)\n                revert(\n                    TokenTransferGenericFailure_error_sig_ptr,\n                    TokenTransferGenericFailure_error_length\n                )\n            }\n\n            // Restore the original free memory pointer.\n            mstore(FreeMemoryPointerSlot, memPointer)\n\n            // Restore the zero slot to zero.\n            mstore(ZeroSlot, 0)\n        }\n    }\n\n    /**\n     * @dev Internal function to transfer ERC1155 tokens from a given\n     *      originator to a given recipient. Sufficient approvals must be set on\n     *      the contract performing the transfer and contract recipients must\n     *      implement the ERC1155TokenReceiver interface to indicate that they\n     *      are willing to accept the transfer.\n     *\n     * @param token      The ERC1155 token to transfer.\n     * @param from       The originator of the transfer.\n     * @param to         The recipient of the transfer.\n     * @param identifier The id to transfer.\n     * @param amount     The amount to transfer.\n     */\n    function _performERC1155Transfer(\n        address token,\n        address from,\n        address to,\n        uint256 identifier,\n        uint256 amount\n    ) internal {\n        // Utilize assembly to perform an optimized ERC1155 token transfer.\n        assembly {\n            // If the token has no code, revert.\n            if iszero(extcodesize(token)) {\n                mstore(NoContract_error_sig_ptr, NoContract_error_signature)\n                mstore(NoContract_error_token_ptr, token)\n                revert(NoContract_error_sig_ptr, NoContract_error_length)\n            }\n\n            // The following memory slots will be used when populating call data\n            // for the transfer; read the values and restore them later.\n            let memPointer := mload(FreeMemoryPointerSlot)\n            let slot0x80 := mload(Slot0x80)\n            let slot0xA0 := mload(Slot0xA0)\n            let slot0xC0 := mload(Slot0xC0)\n\n            // Write call data into memory, beginning with function selector.\n            mstore(\n                ERC1155_safeTransferFrom_sig_ptr,\n                ERC1155_safeTransferFrom_signature\n            )\n            mstore(ERC1155_safeTransferFrom_from_ptr, from)\n            mstore(ERC1155_safeTransferFrom_to_ptr, to)\n            mstore(ERC1155_safeTransferFrom_id_ptr, identifier)\n            mstore(ERC1155_safeTransferFrom_amount_ptr, amount)\n            mstore(\n                ERC1155_safeTransferFrom_data_offset_ptr,\n                ERC1155_safeTransferFrom_data_length_offset\n            )\n            mstore(ERC1155_safeTransferFrom_data_length_ptr, 0)\n\n            // Perform the call, ignoring return data.\n            let success := call(\n                gas(),\n                token,\n                0,\n                ERC1155_safeTransferFrom_sig_ptr,\n                ERC1155_safeTransferFrom_length,\n                0,\n                0\n            )\n\n            // If the transfer reverted:\n            if iszero(success) {\n                // If it returned a message, bubble it up as long as sufficient\n                // gas remains to do so:\n                if returndatasize() {\n                    // Ensure that sufficient gas is available to copy\n                    // returndata while expanding memory where necessary. Start\n                    // by computing word size of returndata & allocated memory.\n                    // Round up to the nearest full word.\n                    let returnDataWords := div(\n                        add(returndatasize(), AlmostOneWord),\n                        OneWord\n                    )\n\n                    // Note: use the free memory pointer in place of msize() to\n                    // work around a Yul warning that prevents accessing msize\n                    // directly when the IR pipeline is activated.\n                    let msizeWords := div(memPointer, OneWord)\n\n                    // Next, compute the cost of the returndatacopy.\n                    let cost := mul(CostPerWord, returnDataWords)\n\n                    // Then, compute cost of new memory allocation.\n                    if gt(returnDataWords, msizeWords) {\n                        cost := add(\n                            cost,\n                            add(\n                                mul(\n                                    sub(returnDataWords, msizeWords),\n                                    CostPerWord\n                                ),\n                                div(\n                                    sub(\n                                        mul(returnDataWords, returnDataWords),\n                                        mul(msizeWords, msizeWords)\n                                    ),\n                                    MemoryExpansionCoefficient\n                                )\n                            )\n                        )\n                    }\n\n                    // Finally, add a small constant and compare to gas\n                    // remaining; bubble up the revert data if enough gas is\n                    // still available.\n                    if lt(add(cost, ExtraGasBuffer), gas()) {\n                        // Copy returndata to memory; overwrite existing memory.\n                        returndatacopy(0, 0, returndatasize())\n\n                        // Revert, giving memory region with copied returndata.\n                        revert(0, returndatasize())\n                    }\n                }\n\n                // Otherwise revert with a generic error message.\n                mstore(\n                    TokenTransferGenericFailure_error_sig_ptr,\n                    TokenTransferGenericFailure_error_signature\n                )\n                mstore(TokenTransferGenericFailure_error_token_ptr, token)\n                mstore(TokenTransferGenericFailure_error_from_ptr, from)\n                mstore(TokenTransferGenericFailure_error_to_ptr, to)\n                mstore(TokenTransferGenericFailure_error_id_ptr, identifier)\n                mstore(TokenTransferGenericFailure_error_amount_ptr, amount)\n                revert(\n                    TokenTransferGenericFailure_error_sig_ptr,\n                    TokenTransferGenericFailure_error_length\n                )\n            }\n\n            mstore(Slot0x80, slot0x80) // Restore slot 0x80.\n            mstore(Slot0xA0, slot0xA0) // Restore slot 0xA0.\n            mstore(Slot0xC0, slot0xC0) // Restore slot 0xC0.\n\n            // Restore the original free memory pointer.\n            mstore(FreeMemoryPointerSlot, memPointer)\n\n            // Restore the zero slot to zero.\n            mstore(ZeroSlot, 0)\n        }\n    }\n\n    /**\n     * @dev Internal function to transfer ERC1155 tokens from a given\n     *      originator to a given recipient. Sufficient approvals must be set on\n     *      the contract performing the transfer and contract recipients must\n     *      implement the ERC1155TokenReceiver interface to indicate that they\n     *      are willing to accept the transfer. NOTE: this function is not\n     *      memory-safe; it will overwrite existing memory, restore the free\n     *      memory pointer to the default value, and overwrite the zero slot.\n     *      This function should only be called once memory is no longer\n     *      required and when uninitialized arrays are not utilized, and memory\n     *      should be considered fully corrupted (aside from the existence of a\n     *      default-value free memory pointer) after calling this function.\n     *\n     * @param batchTransfers The group of 1155 batch transfers to perform.\n     */\n    function _performERC1155BatchTransfers(\n        ConduitBatch1155Transfer[] calldata batchTransfers\n    ) internal {\n        // Utilize assembly to perform optimized batch 1155 transfers.\n        assembly {\n            let len := batchTransfers.length\n            // Pointer to first head in the array, which is offset to the struct\n            // at each index. This gets incremented after each loop to avoid\n            // multiplying by 32 to get the offset for each element.\n            let nextElementHeadPtr := batchTransfers.offset\n\n            // Pointer to beginning of the head of the array. This is the\n            // reference position each offset references. It's held static to\n            // let each loop calculate the data position for an element.\n            let arrayHeadPtr := nextElementHeadPtr\n\n            // Write the function selector, which will be reused for each call:\n            // safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)\n            mstore(\n                ConduitBatch1155Transfer_from_offset,\n                ERC1155_safeBatchTransferFrom_signature\n            )\n\n            // Iterate over each batch transfer.\n            for {\n                let i := 0\n            } lt(i, len) {\n                i := add(i, 1)\n            } {\n                // Read the offset to the beginning of the element and add\n                // it to pointer to the beginning of the array head to get\n                // the absolute position of the element in calldata.\n                let elementPtr := add(\n                    arrayHeadPtr,\n                    calldataload(nextElementHeadPtr)\n                )\n\n                // Retrieve the token from calldata.\n                let token := calldataload(elementPtr)\n\n                // If the token has no code, revert.\n                if iszero(extcodesize(token)) {\n                    mstore(NoContract_error_sig_ptr, NoContract_error_signature)\n                    mstore(NoContract_error_token_ptr, token)\n                    revert(NoContract_error_sig_ptr, NoContract_error_length)\n                }\n\n                // Get the total number of supplied ids.\n                let idsLength := calldataload(\n                    add(elementPtr, ConduitBatch1155Transfer_ids_length_offset)\n                )\n\n                // Determine the expected offset for the amounts array.\n                let expectedAmountsOffset := add(\n                    ConduitBatch1155Transfer_amounts_length_baseOffset,\n                    mul(idsLength, OneWord)\n                )\n\n                // Validate struct encoding.\n                let invalidEncoding := iszero(\n                    and(\n                        // ids.length == amounts.length\n                        eq(\n                            idsLength,\n                            calldataload(add(elementPtr, expectedAmountsOffset))\n                        ),\n                        and(\n                            // ids_offset == 0xa0\n                            eq(\n                                calldataload(\n                                    add(\n                                        elementPtr,\n                                        ConduitBatch1155Transfer_ids_head_offset\n                                    )\n                                ),\n                                ConduitBatch1155Transfer_ids_length_offset\n                            ),\n                            // amounts_offset == 0xc0 + ids.length*32\n                            eq(\n                                calldataload(\n                                    add(\n                                        elementPtr,\n                                        ConduitBatchTransfer_amounts_head_offset\n                                    )\n                                ),\n                                expectedAmountsOffset\n                            )\n                        )\n                    )\n                )\n\n                // Revert with an error if the encoding is not valid.\n                if invalidEncoding {\n                    mstore(\n                        Invalid1155BatchTransferEncoding_ptr,\n                        Invalid1155BatchTransferEncoding_selector\n                    )\n                    revert(\n                        Invalid1155BatchTransferEncoding_ptr,\n                        Invalid1155BatchTransferEncoding_length\n                    )\n                }\n\n                // Update the offset position for the next loop\n                nextElementHeadPtr := add(nextElementHeadPtr, OneWord)\n\n                // Copy the first section of calldata (before dynamic values).\n                calldatacopy(\n                    BatchTransfer1155Params_ptr,\n                    add(elementPtr, ConduitBatch1155Transfer_from_offset),\n                    ConduitBatch1155Transfer_usable_head_size\n                )\n\n                // Determine size of calldata required for ids and amounts. Note\n                // that the size includes both lengths as well as the data.\n                let idsAndAmountsSize := add(TwoWords, mul(idsLength, TwoWords))\n\n                // Update the offset for the data array in memory.\n                mstore(\n                    BatchTransfer1155Params_data_head_ptr,\n                    add(\n                        BatchTransfer1155Params_ids_length_offset,\n                        idsAndAmountsSize\n                    )\n                )\n\n                // Set the length of the data array in memory to zero.\n                mstore(\n                    add(\n                        BatchTransfer1155Params_data_length_basePtr,\n                        idsAndAmountsSize\n                    ),\n                    0\n                )\n\n                // Determine the total calldata size for the call to transfer.\n                let transferDataSize := add(\n                    BatchTransfer1155Params_calldata_baseSize,\n                    idsAndAmountsSize\n                )\n\n                // Copy second section of calldata (including dynamic values).\n                calldatacopy(\n                    BatchTransfer1155Params_ids_length_ptr,\n                    add(elementPtr, ConduitBatch1155Transfer_ids_length_offset),\n                    idsAndAmountsSize\n                )\n\n                // Perform the call to transfer 1155 tokens.\n                let success := call(\n                    gas(),\n                    token,\n                    0,\n                    ConduitBatch1155Transfer_from_offset, // Data portion start.\n                    transferDataSize, // Location of the length of callData.\n                    0,\n                    0\n                )\n\n                // If the transfer reverted:\n                if iszero(success) {\n                    // If it returned a message, bubble it up as long as\n                    // sufficient gas remains to do so:\n                    if returndatasize() {\n                        // Ensure that sufficient gas is available to copy\n                        // returndata while expanding memory where necessary.\n                        // Start by computing word size of returndata and\n                        // allocated memory. Round up to the nearest full word.\n                        let returnDataWords := div(\n                            add(returndatasize(), AlmostOneWord),\n                            OneWord\n                        )\n\n                        // Note: use transferDataSize in place of msize() to\n                        // work around a Yul warning that prevents accessing\n                        // msize directly when the IR pipeline is activated.\n                        // The free memory pointer is not used here because\n                        // this function does almost all memory management\n                        // manually and does not update it, and transferDataSize\n                        // should be the largest memory value used (unless a\n                        // previous batch was larger).\n                        let msizeWords := div(transferDataSize, OneWord)\n\n                        // Next, compute the cost of the returndatacopy.\n                        let cost := mul(CostPerWord, returnDataWords)\n\n                        // Then, compute cost of new memory allocation.\n                        if gt(returnDataWords, msizeWords) {\n                            cost := add(\n                                cost,\n                                add(\n                                    mul(\n                                        sub(returnDataWords, msizeWords),\n                                        CostPerWord\n                                    ),\n                                    div(\n                                        sub(\n                                            mul(\n                                                returnDataWords,\n                                                returnDataWords\n                                            ),\n                                            mul(msizeWords, msizeWords)\n                                        ),\n                                        MemoryExpansionCoefficient\n                                    )\n                                )\n                            )\n                        }\n\n                        // Finally, add a small constant and compare to gas\n                        // remaining; bubble up the revert data if enough gas is\n                        // still available.\n                        if lt(add(cost, ExtraGasBuffer), gas()) {\n                            // Copy returndata to memory; overwrite existing.\n                            returndatacopy(0, 0, returndatasize())\n\n                            // Revert with memory region containing returndata.\n                            revert(0, returndatasize())\n                        }\n                    }\n\n                    // Set the error signature.\n                    mstore(\n                        0,\n                        ERC1155BatchTransferGenericFailure_error_signature\n                    )\n\n                    // Write the token.\n                    mstore(ERC1155BatchTransferGenericFailure_token_ptr, token)\n\n                    // Increase the offset to ids by 32.\n                    mstore(\n                        BatchTransfer1155Params_ids_head_ptr,\n                        ERC1155BatchTransferGenericFailure_ids_offset\n                    )\n\n                    // Increase the offset to amounts by 32.\n                    mstore(\n                        BatchTransfer1155Params_amounts_head_ptr,\n                        add(\n                            OneWord,\n                            mload(BatchTransfer1155Params_amounts_head_ptr)\n                        )\n                    )\n\n                    // Return modified region. The total size stays the same as\n                    // `token` uses the same number of bytes as `data.length`.\n                    revert(0, transferDataSize)\n                }\n            }\n\n            // Reset the free memory pointer to the default value; memory must\n            // be assumed to be dirtied and not reused from this point forward.\n            // Also note that the zero slot is not reset to zero, meaning empty\n            // arrays cannot be safely created or utilized until it is restored.\n            mstore(FreeMemoryPointerSlot, DefaultFreeMemoryPointer)\n        }\n    }\n}\n"
    },
    "contracts/lib/Assertions.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport { GettersAndDerivers } from \"./GettersAndDerivers.sol\";\n\nimport {\n    TokenTransferrerErrors\n} from \"../interfaces/TokenTransferrerErrors.sol\";\n\nimport { CounterManager } from \"./CounterManager.sol\";\n\ncontract Assertions is\n    GettersAndDerivers,\n    CounterManager,\n    TokenTransferrerErrors\n{\n    constructor(address conduitController)\n        GettersAndDerivers(conduitController)\n    {}\n\n    function _assertNonZeroAmount(uint256 amount) internal pure {\n        // Revert if the supplied amount is equal to zero.\n        if (amount == 0) {\n            revert MissingItemAmount();\n        }\n    }\n}\n"
    },
    "contracts/lib/SignatureVerification.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport { EIP1271Interface } from \"../interfaces/EIP1271Interface.sol\";\n\nimport {\n    SignatureVerificationErrors\n} from \"../interfaces/SignatureVerificationErrors.sol\";\n\nimport { LowLevelHelpers } from \"./LowLevelHelpers.sol\";\n\nimport \"./ConsiderationConstants.sol\";\n\n/**\n * @title SignatureVerification\n * @author 0age\n * @notice SignatureVerification contains logic for verifying signatures.\n */\ncontract SignatureVerification is SignatureVerificationErrors, LowLevelHelpers {\n    /**\n     * @dev Internal view function to verify the signature of an order. An\n     *      ERC-1271 fallback will be attempted if either the signature length\n     *      is not 64 or 65 bytes or if the recovered signer does not match the\n     *      supplied signer.\n     *\n     * @param signer    The signer for the order.\n     * @param digest    The digest to verify the signature against.\n     * @param signature A signature from the signer indicating that the order\n     *                  has been approved.\n     */\n    function _assertValidSignature(\n        address signer,\n        bytes32 digest,\n        bytes memory signature\n    ) internal view {\n        // Declare value for ecrecover equality or 1271 call success status.\n        bool success;\n\n        // Utilize assembly to perform optimized signature verification check.\n        assembly {\n            // Ensure that first word of scratch space is empty.\n            mstore(0, 0)\n\n            // Declare value for v signature parameter.\n            let v\n\n            // Get the length of the signature.\n            let signatureLength := mload(signature)\n\n            // Get the pointer to the value preceding the signature length.\n            // This will be used for temporary memory overrides - either the\n            // signature head for isValidSignature or the digest for ecrecover.\n            let wordBeforeSignaturePtr := sub(signature, OneWord)\n\n            // Cache the current value behind the signature to restore it later.\n            let cachedWordBeforeSignature := mload(wordBeforeSignaturePtr)\n\n            // Declare lenDiff + recoveredSigner scope to manage stack pressure.\n            {\n                // Take the difference between the max ECDSA signature length\n                // and the actual signature length. Overflow desired for any\n                // values > 65. If the diff is not 0 or 1, it is not a valid\n                // ECDSA signature - move on to EIP1271 check.\n                let lenDiff := sub(ECDSA_MaxLength, signatureLength)\n\n                // Declare variable for recovered signer.\n                let recoveredSigner\n\n                // If diff is 0 or 1, it may be an ECDSA signature.\n                // Try to recover signer.\n                if iszero(gt(lenDiff, 1)) {\n                    // Read the signature `s` value.\n                    let originalSignatureS := mload(\n                        add(signature, ECDSA_signature_s_offset)\n                    )\n\n                    // Read the first byte of the word after `s`. If the\n                    // signature is 65 bytes, this will be the real `v` value.\n                    // If not, it will need to be modified - doing it this way\n                    // saves an extra condition.\n                    v := byte(\n                        0,\n                        mload(add(signature, ECDSA_signature_v_offset))\n                    )\n\n                    // If lenDiff is 1, parse 64-byte signature as ECDSA.\n                    if lenDiff {\n                        // Extract yParity from highest bit of vs and add 27 to\n                        // get v.\n                        v := add(\n                            shr(MaxUint8, originalSignatureS),\n                            Signature_lower_v\n                        )\n\n                        // Extract canonical s from vs, all but the highest bit.\n                        // Temporarily overwrite the original `s` value in the\n                        // signature.\n                        mstore(\n                            add(signature, ECDSA_signature_s_offset),\n                            and(\n                                originalSignatureS,\n                                EIP2098_allButHighestBitMask\n                            )\n                        )\n                    }\n                    // Temporarily overwrite the signature length with `v` to\n                    // conform to the expected input for ecrecover.\n                    mstore(signature, v)\n\n                    // Temporarily overwrite the word before the length with\n                    // `digest` to conform to the expected input for ecrecover.\n                    mstore(wordBeforeSignaturePtr, digest)\n\n                    // Attempt to recover the signer for the given signature. Do\n                    // not check the call status as ecrecover will return a null\n                    // address if the signature is invalid.\n                    pop(\n                        staticcall(\n                            gas(),\n                            Ecrecover_precompile, // Call ecrecover precompile.\n                            wordBeforeSignaturePtr, // Use data memory location.\n                            Ecrecover_args_size, // Size of digest, v, r, and s.\n                            0, // Write result to scratch space.\n                            OneWord // Provide size of returned result.\n                        )\n                    )\n\n                    // Restore cached word before signature.\n                    mstore(wordBeforeSignaturePtr, cachedWordBeforeSignature)\n\n                    // Restore cached signature length.\n                    mstore(signature, signatureLength)\n\n                    // Restore cached signature `s` value.\n                    mstore(\n                        add(signature, ECDSA_signature_s_offset),\n                        originalSignatureS\n                    )\n\n                    // Read the recovered signer from the buffer given as return\n                    // space for ecrecover.\n                    recoveredSigner := mload(0)\n                }\n\n                // Set success to true if the signature provided was a valid\n                // ECDSA signature and the signer is not the null address. Use\n                // gt instead of direct as success is used outside of assembly.\n                success := and(eq(signer, recoveredSigner), gt(signer, 0))\n            }\n\n            // If the signature was not verified with ecrecover, try EIP1271.\n            if iszero(success) {\n                // Temporarily overwrite the word before the signature length\n                // and use it as the head of the signature input to\n                // `isValidSignature`, which has a value of 64.\n                mstore(\n                    wordBeforeSignaturePtr,\n                    EIP1271_isValidSignature_signature_head_offset\n                )\n\n                // Get pointer to use for the selector of `isValidSignature`.\n                let selectorPtr := sub(\n                    signature,\n                    EIP1271_isValidSignature_selector_negativeOffset\n                )\n\n                // Cache the value currently stored at the selector pointer.\n                let cachedWordOverwrittenBySelector := mload(selectorPtr)\n\n                // Get pointer to use for `digest` input to `isValidSignature`.\n                let digestPtr := sub(\n                    signature,\n                    EIP1271_isValidSignature_digest_negativeOffset\n                )\n\n                // Cache the value currently stored at the digest pointer.\n                let cachedWordOverwrittenByDigest := mload(digestPtr)\n\n                // Write the selector first, since it overlaps the digest.\n                mstore(selectorPtr, EIP1271_isValidSignature_selector)\n\n                // Next, write the digest.\n                mstore(digestPtr, digest)\n\n                // Call signer with `isValidSignature` to validate signature.\n                success := staticcall(\n                    gas(),\n                    signer,\n                    selectorPtr,\n                    add(\n                        signatureLength,\n                        EIP1271_isValidSignature_calldata_baseLength\n                    ),\n                    0,\n                    OneWord\n                )\n\n                // Determine if the signature is valid on successful calls.\n                if success {\n                    // If first word of scratch space does not contain EIP-1271\n                    // signature selector, revert.\n                    if iszero(eq(mload(0), EIP1271_isValidSignature_selector)) {\n                        // Revert with bad 1271 signature if signer has code.\n                        if extcodesize(signer) {\n                            // Bad contract signature.\n                            mstore(0, BadContractSignature_error_signature)\n                            revert(0, BadContractSignature_error_length)\n                        }\n\n                        // Check if signature length was invalid.\n                        if gt(sub(ECDSA_MaxLength, signatureLength), 1) {\n                            // Revert with generic invalid signature error.\n                            mstore(0, InvalidSignature_error_signature)\n                            revert(0, InvalidSignature_error_length)\n                        }\n\n                        // Check if v was invalid.\n                        if iszero(\n                            byte(v, ECDSA_twentySeventhAndTwentyEighthBytesSet)\n                        ) {\n                            // Revert with invalid v value.\n                            mstore(0, BadSignatureV_error_signature)\n                            mstore(BadSignatureV_error_offset, v)\n                            revert(0, BadSignatureV_error_length)\n                        }\n\n                        // Revert with generic invalid signer error message.\n                        mstore(0, InvalidSigner_error_signature)\n                        revert(0, InvalidSigner_error_length)\n                    }\n                }\n\n                // Restore the cached values overwritten by selector, digest and\n                // signature head.\n                mstore(wordBeforeSignaturePtr, cachedWordBeforeSignature)\n                mstore(selectorPtr, cachedWordOverwrittenBySelector)\n                mstore(digestPtr, cachedWordOverwrittenByDigest)\n            }\n        }\n\n        // If the call failed...\n        if (!success) {\n            // Revert and pass reason along if one was returned.\n            _revertWithReasonIfOneIsReturned();\n\n            // Otherwise, revert with error indicating bad contract signature.\n            assembly {\n                mstore(0, BadContractSignature_error_signature)\n                revert(0, BadContractSignature_error_length)\n            }\n        }\n    }\n}\n"
    },
    "contracts/lib/GettersAndDerivers.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport { OrderParameters } from \"./ConsiderationStructs.sol\";\n\nimport { ConsiderationBase } from \"./ConsiderationBase.sol\";\n\nimport \"./ConsiderationConstants.sol\";\n\ncontract GettersAndDerivers is ConsiderationBase {\n\n    constructor(address conduitController)\n        ConsiderationBase(conduitController)\n    {}\n\n    function _deriveOrderHash(\n        OrderParameters memory orderParameters,\n        uint256 counter\n    ) internal view returns (bytes32 orderHash) {\n        bytes32 typeHash = _ORDER_TYPEHASH;\n\n        assembly {\n            let typeHashPtr := sub(orderParameters, OneWord)\n\n            let previousValue := mload(typeHashPtr)\n\n            mstore(typeHashPtr, typeHash)\n\n            let counterPtr := add(\n                orderParameters,\n                OrderParameters_counter_offset\n            )\n\n            let counterDataPtr := mload(counterPtr)\n\n            mstore(counterPtr, counter)\n\n            orderHash := keccak256(typeHashPtr, EIP712_Order_size)\n\n            mstore(typeHashPtr, previousValue)\n\n            mstore(counterPtr, counterDataPtr)\n        }\n    }\n\n    function _deriveConduit(bytes32 conduitKey)\n        internal\n        view\n        returns (address conduit)\n    {\n        // Read conduit controller address from runtime and place on the stack.\n        address conduitController = address(_CONDUIT_CONTROLLER);\n\n        // Read conduit creation code hash from runtime and place on the stack.\n        bytes32 conduitCreationCodeHash = _CONDUIT_CREATION_CODE_HASH;\n\n        // Leverage scratch space to perform an efficient hash.\n        assembly {\n            // Retrieve the free memory pointer; it will be replaced afterwards.\n            let freeMemoryPointer := mload(FreeMemoryPointerSlot)\n\n            // Place the control character and the conduit controller in scratch\n            // space; note that eleven bytes at the beginning are left unused.\n            mstore(0, or(MaskOverByteTwelve, conduitController))\n\n            // Place the conduit key in the next region of scratch space.\n            mstore(OneWord, conduitKey)\n\n            // Place conduit creation code hash in free memory pointer location.\n            mstore(TwoWords, conduitCreationCodeHash)\n\n            // Derive conduit by hashing and applying a mask over last 20 bytes.\n            conduit := and(\n                // Hash the relevant region.\n                keccak256(\n                    // The region starts at memory pointer 11.\n                    Create2AddressDerivation_ptr,\n                    // The region is 85 bytes long (1 + 20 + 32 + 32).\n                    Create2AddressDerivation_length\n                ),\n                // The address equals the last twenty bytes of the hash.\n                MaskOverLastTwentyBytes\n            )\n\n            // Restore the free memory pointer.\n            mstore(FreeMemoryPointerSlot, freeMemoryPointer)\n        }\n    }\n\n    /**\n     * @dev Internal view function to get the EIP-712 domain separator. If the\n     *      chainId matches the chainId set on deployment, the cached domain\n     *      separator will be returned; otherwise, it will be derived from\n     *      scratch.\n     *\n     * @return The domain separator.\n     */\n    function _domainSeparator() internal view returns (bytes32) {\n        // prettier-ignore\n        return block.chainid == _CHAIN_ID\n            ? _DOMAIN_SEPARATOR\n            : _deriveDomainSeparator();\n    }\n\n    /**\n     * @dev Internal view function to retrieve configuration information for\n     *      this contract.\n     *\n     * @return version           The contract version.\n     * @return domainSeparator   The domain separator for this contract.\n     * @return conduitController The conduit Controller set for this contract.\n     */\n    function _information()\n        internal\n        view\n        returns (\n            string memory version,\n            bytes32 domainSeparator,\n            address conduitController\n        )\n    {\n        // Derive the domain separator.\n        domainSeparator = _domainSeparator();\n\n        // Declare variable as immutables cannot be accessed within assembly.\n        conduitController = address(_CONDUIT_CONTROLLER);\n\n        // Allocate a string with the intended length.\n        version = new string(Version_length);\n\n        // Set the version as data on the newly allocated string.\n        assembly {\n            mstore(add(version, OneWord), shl(Version_shift, Version))\n        }\n    }\n\n    /**\n     * @dev Internal pure function to efficiently derive an digest to sign for\n     *      an order in accordance with EIP-712.\n     *\n     * @param domainSeparator The domain separator.\n     * @param orderHash       The order hash.\n     *\n     * @return value The hash.\n     */\n    function _deriveEIP712Digest(bytes32 domainSeparator, bytes32 orderHash)\n        internal\n        pure\n        returns (bytes32 value)\n    {\n        // Leverage scratch space to perform an efficient hash.\n        assembly {\n            // Place the EIP-712 prefix at the start of scratch space.\n            mstore(0, EIP_712_PREFIX)\n\n            // Place the domain separator in the next region of scratch space.\n            mstore(EIP712_DomainSeparator_offset, domainSeparator)\n\n            // Place the order hash in scratch space, spilling into the first\n            // two bytes of the free memory pointer — this should never be set\n            // as memory cannot be expanded to that size, and will be zeroed out\n            // after the hash is performed.\n            mstore(EIP712_OrderHash_offset, orderHash)\n\n            // Hash the relevant region (65 bytes).\n            value := keccak256(0, EIP712_DigestPayload_size)\n\n            // Clear out the dirtied bits in the memory pointer.\n            mstore(EIP712_OrderHash_offset, 0)\n        }\n    }\n}\n"
    },
    "contracts/interfaces/TokenTransferrerErrors.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.7;\n\n/**\n * @title TokenTransferrerErrors\n */\ninterface TokenTransferrerErrors {\n    /**\n     * @dev Revert with an error when an ERC721 transfer with amount other than\n     *      one is attempted.\n     */\n    error InvalidERC721TransferAmount();\n\n    /**\n     * @dev Revert with an error when attempting to fulfill an order where an\n     *      item has an amount of zero.\n     */\n    error MissingItemAmount();\n\n    /**\n     * @dev Revert with an error when attempting to fulfill an order where an\n     *      item has unused parameters. This includes both the token and the\n     *      identifier parameters for native transfers as well as the identifier\n     *      parameter for ERC20 transfers. Note that the conduit does not\n     *      perform this check, leaving it up to the calling channel to enforce\n     *      when desired.\n     */\n    error UnusedItemParameters();\n\n    /**\n     * @dev Revert with an error when an ERC20, ERC721, or ERC1155 token\n     *      transfer reverts.\n     *\n     * @param token      The token for which the transfer was attempted.\n     * @param from       The source of the attempted transfer.\n     * @param to         The recipient of the attempted transfer.\n     * @param identifier The identifier for the attempted transfer.\n     * @param amount     The amount for the attempted transfer.\n     */\n    error TokenTransferGenericFailure(\n        address token,\n        address from,\n        address to,\n        uint256 identifier,\n        uint256 amount\n    );\n\n    /**\n     * @dev Revert with an error when a batch ERC1155 token transfer reverts.\n     *\n     * @param token       The token for which the transfer was attempted.\n     * @param from        The source of the attempted transfer.\n     * @param to          The recipient of the attempted transfer.\n     * @param identifiers The identifiers for the attempted transfer.\n     * @param amounts     The amounts for the attempted transfer.\n     */\n    error ERC1155BatchTransferGenericFailure(\n        address token,\n        address from,\n        address to,\n        uint256[] identifiers,\n        uint256[] amounts\n    );\n\n    /**\n     * @dev Revert with an error when an ERC20 token transfer returns a falsey\n     *      value.\n     *\n     * @param token      The token for which the ERC20 transfer was attempted.\n     * @param from       The source of the attempted ERC20 transfer.\n     * @param to         The recipient of the attempted ERC20 transfer.\n     * @param amount     The amount for the attempted ERC20 transfer.\n     */\n    error BadReturnValueFromERC20OnTransfer(\n        address token,\n        address from,\n        address to,\n        uint256 amount\n    );\n\n    /**\n     * @dev Revert with an error when an account being called as an assumed\n     *      contract does not have code and returns no data.\n     *\n     * @param account The account that should contain code.\n     */\n    error NoContract(address account);\n\n    /**\n     * @dev Revert with an error when attempting to execute an 1155 batch\n     *      transfer using calldata not produced by default ABI encoding or with\n     *      different lengths for ids and amounts arrays.\n     */\n    error Invalid1155BatchTransferEncoding();\n}\n"
    },
    "contracts/lib/CounterManager.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport {\n    ConsiderationEventsAndErrors\n} from \"../interfaces/ConsiderationEventsAndErrors.sol\";\n\nimport { ReentrancyGuard } from \"./ReentrancyGuard.sol\";\n\ncontract CounterManager is ConsiderationEventsAndErrors, ReentrancyGuard {\n\n    mapping(address => uint256) private _counters;\n\n    function _incrementCounter() internal returns (uint256 newCounter) {\n        _assertNonReentrant();\n\n        unchecked {\n            newCounter = ++_counters[msg.sender];\n        }\n\n        emit CounterIncremented(newCounter, msg.sender);\n    }\n\n    function _getCounter(address offerer)\n        internal\n        view\n        returns (uint256 currentCounter)\n    {\n        currentCounter = _counters[offerer];\n    }\n}\n"
    },
    "contracts/lib/ConsiderationBase.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport {\n    ConduitControllerInterface\n} from \"../interfaces/ConduitControllerInterface.sol\";\n\ncontract ConsiderationBase {\n    bytes32 internal immutable _NAME_HASH;\n    bytes32 internal immutable _VERSION_HASH;\n    bytes32 internal immutable _EIP_712_DOMAIN_TYPEHASH;\n    bytes32 internal immutable _ORDER_TYPEHASH;\n    uint256 internal immutable _CHAIN_ID;\n    bytes32 internal immutable _DOMAIN_SEPARATOR;\n\n    ConduitControllerInterface internal immutable _CONDUIT_CONTROLLER;\n    bytes32 internal immutable _CONDUIT_CREATION_CODE_HASH;\n\n    constructor(address conduitController) {\n        (\n            _NAME_HASH,\n            _VERSION_HASH,\n            _EIP_712_DOMAIN_TYPEHASH,\n            _ORDER_TYPEHASH\n        ) = _deriveTypehashes();\n\n        _CHAIN_ID = block.chainid;\n        _DOMAIN_SEPARATOR = _deriveDomainSeparator();\n\n        _CONDUIT_CONTROLLER = ConduitControllerInterface(conduitController);\n\n        (_CONDUIT_CREATION_CODE_HASH, ) = (\n            _CONDUIT_CONTROLLER.getConduitCodeHashes()\n        );\n    }\n\n    function _deriveDomainSeparator() internal view returns (bytes32) {\n        return keccak256(\n            abi.encode(\n                _EIP_712_DOMAIN_TYPEHASH,\n                _NAME_HASH,\n                _VERSION_HASH,\n                block.chainid,\n                address(this)\n            )\n        );\n    }\n\n    function _nameString() internal pure virtual returns (string memory) {\n        return \"Consideration\";\n    }\n\n    function _deriveTypehashes()\n        internal\n        pure\n        returns (\n            bytes32 nameHash,\n            bytes32 versionHash,\n            bytes32 eip712DomainTypehash,\n            bytes32 orderTypehash\n        )\n    {\n        nameHash = keccak256(bytes(_nameString()));\n\n        versionHash = keccak256(bytes(\"1.0\"));\n\n        bytes memory orderComponentsTypeString = abi.encodePacked(\n            \"OrderComponents(\",\n                \"address offerer,\",\n                \"address token,\",\n                \"uint256 identifier,\",\n                \"address currency,\",\n                \"address artist,\",\n                \"address platform,\",\n                \"uint256 startTime,\",\n                \"uint256 endTime,\",\n                \"uint256 duration,\",\n                \"uint256 periods,\",\n                \"uint256 amount,\",\n                \"uint256 ratio,\",\n                \"uint256 royalty,\",\n                \"uint256 fee,\",\n                \"uint256 withdrawFee,\",\n                \"uint256 salt,\",\n                \"bytes32 conduitKey,\",\n                \"uint256 counter\",\n            \")\"\n        );\n\n        eip712DomainTypehash = keccak256(\n            abi.encodePacked(\n                \"EIP712Domain(\",\n                    \"string name,\",\n                    \"string version,\",\n                    \"uint256 chainId,\",\n                    \"address verifyingContract\",\n                \")\"\n            )\n        );\n\n        orderTypehash = keccak256(orderComponentsTypeString);\n    }\n}"
    },
    "contracts/interfaces/ConduitControllerInterface.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.7;\n\n/**\n * @title ConduitControllerInterface\n * @author 0age\n * @notice ConduitControllerInterface contains all external function interfaces,\n *         structs, events, and errors for the conduit controller.\n */\ninterface ConduitControllerInterface {\n    /**\n     * @dev Track the conduit key, current owner, new potential owner, and open\n     *      channels for each deployed conduit.\n     */\n    struct ConduitProperties {\n        bytes32 key;\n        address owner;\n        address potentialOwner;\n        address[] channels;\n        mapping(address => uint256) channelIndexesPlusOne;\n    }\n\n    /**\n     * @dev Emit an event whenever a new conduit is created.\n     *\n     * @param conduit    The newly created conduit.\n     * @param conduitKey The conduit key used to create the new conduit.\n     */\n    event NewConduit(address conduit, bytes32 conduitKey);\n\n    /**\n     * @dev Emit an event whenever conduit ownership is transferred.\n     *\n     * @param conduit       The conduit for which ownership has been\n     *                      transferred.\n     * @param previousOwner The previous owner of the conduit.\n     * @param newOwner      The new owner of the conduit.\n     */\n    event OwnershipTransferred(\n        address indexed conduit,\n        address indexed previousOwner,\n        address indexed newOwner\n    );\n\n    /**\n     * @dev Emit an event whenever a conduit owner registers a new potential\n     *      owner for that conduit.\n     *\n     * @param newPotentialOwner The new potential owner of the conduit.\n     */\n    event PotentialOwnerUpdated(address indexed newPotentialOwner);\n\n    /**\n     * @dev Revert with an error when attempting to create a new conduit using a\n     *      conduit key where the first twenty bytes of the key do not match the\n     *      address of the caller.\n     */\n    error InvalidCreator();\n\n    /**\n     * @dev Revert with an error when attempting to create a new conduit when no\n     *      initial owner address is supplied.\n     */\n    error InvalidInitialOwner();\n\n    /**\n     * @dev Revert with an error when attempting to set a new potential owner\n     *      that is already set.\n     */\n    error NewPotentialOwnerAlreadySet(\n        address conduit,\n        address newPotentialOwner\n    );\n\n    /**\n     * @dev Revert with an error when attempting to cancel ownership transfer\n     *      when no new potential owner is currently set.\n     */\n    error NoPotentialOwnerCurrentlySet(address conduit);\n\n    /**\n     * @dev Revert with an error when attempting to interact with a conduit that\n     *      does not yet exist.\n     */\n    error NoConduit();\n\n    /**\n     * @dev Revert with an error when attempting to create a conduit that\n     *      already exists.\n     */\n    error ConduitAlreadyExists(address conduit);\n\n    /**\n     * @dev Revert with an error when attempting to update channels or transfer\n     *      ownership of a conduit when the caller is not the owner of the\n     *      conduit in question.\n     */\n    error CallerIsNotOwner(address conduit);\n\n    /**\n     * @dev Revert with an error when attempting to register a new potential\n     *      owner and supplying the null address.\n     */\n    error NewPotentialOwnerIsZeroAddress(address conduit);\n\n    /**\n     * @dev Revert with an error when attempting to claim ownership of a conduit\n     *      with a caller that is not the current potential owner for the\n     *      conduit in question.\n     */\n    error CallerIsNotNewPotentialOwner(address conduit);\n\n    /**\n     * @dev Revert with an error when attempting to retrieve a channel using an\n     *      index that is out of range.\n     */\n    error ChannelOutOfRange(address conduit);\n\n    /**\n     * @notice Deploy a new conduit using a supplied conduit key and assigning\n     *         an initial owner for the deployed conduit. Note that the first\n     *         twenty bytes of the supplied conduit key must match the caller\n     *         and that a new conduit cannot be created if one has already been\n     *         deployed using the same conduit key.\n     *\n     * @param conduitKey   The conduit key used to deploy the conduit. Note that\n     *                     the first twenty bytes of the conduit key must match\n     *                     the caller of this contract.\n     * @param initialOwner The initial owner to set for the new conduit.\n     *\n     * @return conduit The address of the newly deployed conduit.\n     */\n    function createConduit(bytes32 conduitKey, address initialOwner)\n        external\n        returns (address conduit);\n\n    /**\n     * @notice Open or close a channel on a given conduit, thereby allowing the\n     *         specified account to execute transfers against that conduit.\n     *         Extreme care must be taken when updating channels, as malicious\n     *         or vulnerable channels can transfer any ERC20, ERC721 and ERC1155\n     *         tokens where the token holder has granted the conduit approval.\n     *         Only the owner of the conduit in question may call this function.\n     *\n     * @param conduit The conduit for which to open or close the channel.\n     * @param channel The channel to open or close on the conduit.\n     * @param isOpen  A boolean indicating whether to open or close the channel.\n     */\n    function updateChannel(\n        address conduit,\n        address channel,\n        bool isOpen\n    ) external;\n\n    /**\n     * @notice Initiate conduit ownership transfer by assigning a new potential\n     *         owner for the given conduit. Once set, the new potential owner\n     *         may call `acceptOwnership` to claim ownership of the conduit.\n     *         Only the owner of the conduit in question may call this function.\n     *\n     * @param conduit The conduit for which to initiate ownership transfer.\n     * @param newPotentialOwner The new potential owner of the conduit.\n     */\n    function transferOwnership(address conduit, address newPotentialOwner)\n        external;\n\n    /**\n     * @notice Clear the currently set potential owner, if any, from a conduit.\n     *         Only the owner of the conduit in question may call this function.\n     *\n     * @param conduit The conduit for which to cancel ownership transfer.\n     */\n    function cancelOwnershipTransfer(address conduit) external;\n\n    /**\n     * @notice Accept ownership of a supplied conduit. Only accounts that the\n     *         current owner has set as the new potential owner may call this\n     *         function.\n     *\n     * @param conduit The conduit for which to accept ownership.\n     */\n    function acceptOwnership(address conduit) external;\n\n    /**\n     * @notice Retrieve the current owner of a deployed conduit.\n     *\n     * @param conduit The conduit for which to retrieve the associated owner.\n     *\n     * @return owner The owner of the supplied conduit.\n     */\n    function ownerOf(address conduit) external view returns (address owner);\n\n    /**\n     * @notice Retrieve the conduit key for a deployed conduit via reverse\n     *         lookup.\n     *\n     * @param conduit The conduit for which to retrieve the associated conduit\n     *                key.\n     *\n     * @return conduitKey The conduit key used to deploy the supplied conduit.\n     */\n    function getKey(address conduit) external view returns (bytes32 conduitKey);\n\n    /**\n     * @notice Derive the conduit associated with a given conduit key and\n     *         determine whether that conduit exists (i.e. whether it has been\n     *         deployed).\n     *\n     * @param conduitKey The conduit key used to derive the conduit.\n     *\n     * @return conduit The derived address of the conduit.\n     * @return exists  A boolean indicating whether the derived conduit has been\n     *                 deployed or not.\n     */\n    function getConduit(bytes32 conduitKey)\n        external\n        view\n        returns (address conduit, bool exists);\n\n    /**\n     * @notice Retrieve the potential owner, if any, for a given conduit. The\n     *         current owner may set a new potential owner via\n     *         `transferOwnership` and that owner may then accept ownership of\n     *         the conduit in question via `acceptOwnership`.\n     *\n     * @param conduit The conduit for which to retrieve the potential owner.\n     *\n     * @return potentialOwner The potential owner, if any, for the conduit.\n     */\n    function getPotentialOwner(address conduit)\n        external\n        view\n        returns (address potentialOwner);\n\n    /**\n     * @notice Retrieve the status (either open or closed) of a given channel on\n     *         a conduit.\n     *\n     * @param conduit The conduit for which to retrieve the channel status.\n     * @param channel The channel for which to retrieve the status.\n     *\n     * @return isOpen The status of the channel on the given conduit.\n     */\n    function getChannelStatus(address conduit, address channel)\n        external\n        view\n        returns (bool isOpen);\n\n    /**\n     * @notice Retrieve the total number of open channels for a given conduit.\n     *\n     * @param conduit The conduit for which to retrieve the total channel count.\n     *\n     * @return totalChannels The total number of open channels for the conduit.\n     */\n    function getTotalChannels(address conduit)\n        external\n        view\n        returns (uint256 totalChannels);\n\n    /**\n     * @notice Retrieve an open channel at a specific index for a given conduit.\n     *         Note that the index of a channel can change as a result of other\n     *         channels being closed on the conduit.\n     *\n     * @param conduit      The conduit for which to retrieve the open channel.\n     * @param channelIndex The index of the channel in question.\n     *\n     * @return channel The open channel, if any, at the specified channel index.\n     */\n    function getChannel(address conduit, uint256 channelIndex)\n        external\n        view\n        returns (address channel);\n\n    /**\n     * @notice Retrieve all open channels for a given conduit. Note that calling\n     *         this function for a conduit with many channels will revert with\n     *         an out-of-gas error.\n     *\n     * @param conduit The conduit for which to retrieve open channels.\n     *\n     * @return channels An array of open channels on the given conduit.\n     */\n    function getChannels(address conduit)\n        external\n        view\n        returns (address[] memory channels);\n\n    /**\n     * @dev Retrieve the conduit creation code and runtime code hashes.\n     */\n    function getConduitCodeHashes()\n        external\n        view\n        returns (bytes32 creationCodeHash, bytes32 runtimeCodeHash);\n}\n"
    },
    "contracts/interfaces/ConsiderationEventsAndErrors.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.7;\n\n/**\n * @title ConsiderationEventsAndErrors\n * @author 0age\n * @notice ConsiderationEventsAndErrors contains all events and errors.\n */\ninterface ConsiderationEventsAndErrors {\n\n    event OrderFulfilled(\n        bytes32 orderHash,\n        address indexed offerer,\n        uint256 shadowId\n    );\n\n    event OrderRepaid(\n        bytes32 orderHash,\n        uint256 payTimes,\n        bool finalized\n    );\n\n    event OrderBroken(\n        bytes32 orderHash,\n        address indexed offerer\n    );\n\n    /**\n     * @dev Emit an event whenever an order is successfully cancelled.\n     *\n     * @param orderHash The hash of the cancelled order.\n     * @param offerer   The offerer of the cancelled order.\n     */\n    event OrderCancelled(\n        bytes32 orderHash,\n        address indexed offerer\n    );\n\n    /**\n     * @dev Emit an event whenever an order is explicitly validated. Note that\n     *      this event will not be emitted on partial fills even though they do\n     *      validate the order as part of partial fulfillment.\n     *\n     * @param orderHash The hash of the validated order.\n     * @param offerer   The offerer of the validated order.\n     */\n    event OrderValidated(\n        bytes32 orderHash,\n        address indexed offerer\n    );\n\n    /**\n     * @dev Emit an event whenever a counter for a given offerer is incremented.\n     *\n     * @param newCounter The new counter for the offerer.\n     * @param offerer  The offerer in question.\n     */\n    event CounterIncremented(uint256 newCounter, address indexed offerer);\n\n    /**\n     * @dev Revert with an error when attempting to fill an order that has\n     *      already been fully filled.\n     *\n     * @param orderHash The order hash on which a fill was attempted.\n     */\n    error OrderAlreadyFilled(bytes32 orderHash);\n\n    error OrderAlreadyFinalized(bytes32 orderHash);\n\n    error OrderAlreadyStarted(bytes32 orderHash);\n\n    error OrderNotStarted(bytes32 orderHash);\n\n    /**\n     * @dev Revert with an error when attempting to fill an order outside the\n     *      specified start time and end time.\n     */\n    error InvalidTime();\n\n    /**\n     * @dev Revert with an error when attempting to fill an order referencing an\n     *      invalid conduit (i.e. one that has not been deployed).\n     */\n    error InvalidConduit(bytes32 conduitKey, address conduit);\n\n    /**\n     * @dev Revert with an error when an order is supplied for fulfillment with\n     *      a consideration array that is shorter than the original array.\n     */\n    error MissingOriginalConsiderationItems();\n\n    /**\n     * @dev Revert with an error when a call to a conduit fails with revert data\n     *      that is too expensive to return.\n     */\n    error InvalidCallToConduit(address conduit);\n\n    /**\n     * @dev Revert with an error if a consideration amount has not been fully\n     *      zeroed out after applying all fulfillments.\n     *\n     * @param orderIndex         The index of the order with the consideration\n     *                           item with a shortfall.\n     * @param considerationIndex The index of the consideration item on the\n     *                           order.\n     * @param shortfallAmount    The unfulfilled consideration amount.\n     */\n    error ConsiderationNotMet(\n        uint256 orderIndex,\n        uint256 considerationIndex,\n        uint256 shortfallAmount\n    );\n\n    /**\n     * @dev Revert with an error when insufficient ether is supplied as part of\n     *      msg.value when fulfilling orders.\n     */\n    error InsufficientEtherSupplied();\n\n    /**\n     * @dev Revert with an error when an ether transfer reverts.\n     */\n    error EtherTransferGenericFailure(address account, uint256 amount);\n\n    /**\n     * @dev Revert with an error when a partial fill is attempted on an order\n     *      that does not specify partial fill support in its order type.\n     */\n    error PartialFillsNotEnabledForOrder();\n\n    /**\n     * @dev Revert with an error when attempting to fill an order that has been\n     *      cancelled.\n     *\n     * @param orderHash The hash of the cancelled order.\n     */\n    error OrderIsCancelled(bytes32 orderHash);\n\n    /**\n     * @dev Revert with an error when attempting to fill a basic order that has\n     *      been partially filled.\n     *\n     * @param orderHash The hash of the partially used order.\n     */\n    error OrderPartiallyFilled(bytes32 orderHash);\n\n    /**\n     * @dev Revert with an error when attempting to cancel an order as a caller\n     *      other than the indicated offerer or zone.\n     */\n    error InvalidCanceller();\n\n    /**\n     * @dev Revert with an error when supplying a fraction with a value of zero\n     *      for the numerator or denominator, or one where the numerator exceeds\n     *      the denominator.\n     */\n    error BadFraction();\n\n    /**\n     * @dev Revert with an error when a caller attempts to supply callvalue to a\n     *      non-payable basic order route or does not supply any callvalue to a\n     *      payable basic order route.\n     */\n    error InvalidMsgValue(uint256 value);\n\n    /**\n     * @dev Revert with an error when attempting to fill a basic order using\n     *      calldata not produced by default ABI encoding.\n     */\n    error InvalidBasicOrderParameterEncoding();\n\n    /**\n     * @dev Revert with an error when attempting to fulfill any number of\n     *      available orders when none are fulfillable.\n     */\n    error NoSpecifiedOrdersAvailable();\n\n    /**\n     * @dev Revert with an error when attempting to fulfill an order with an\n     *      offer for ETH outside of matching orders.\n     */\n    error InvalidNativeOfferItem();\n\n    error OrderNotValidated(bytes32 orderHash);\n\n    error OrderExpired(bytes32 orderHash);\n\n    error OrderNotExpired(bytes32 orderHash);\n\n    error OrderInvalidRepayParameters(bytes32 orderHash);\n\n    error InvalidOrderParameters();\n}\n"
    },
    "contracts/lib/ReentrancyGuard.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport { ReentrancyErrors } from \"../interfaces/ReentrancyErrors.sol\";\n\nimport \"./ConsiderationConstants.sol\";\n\n/**\n * @title ReentrancyGuard\n * @author 0age\n * @notice ReentrancyGuard contains a storage variable and related functionality\n *         for protecting against reentrancy.\n */\ncontract ReentrancyGuard is ReentrancyErrors {\n    // Prevent reentrant calls on protected functions.\n    uint256 private _reentrancyGuard;\n\n    /**\n     * @dev Initialize the reentrancy guard during deployment.\n     */\n    constructor() {\n        // Initialize the reentrancy guard in a cleared state.\n        _reentrancyGuard = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Internal function to ensure that the sentinel value for the\n     *      reentrancy guard is not currently set and, if not, to set the\n     *      sentinel value for the reentrancy guard.\n     */\n    function _setReentrancyGuard() internal {\n        // Ensure that the reentrancy guard is not already set.\n        _assertNonReentrant();\n\n        // Set the reentrancy guard.\n        _reentrancyGuard = _ENTERED;\n    }\n\n    /**\n     * @dev Internal function to unset the reentrancy guard sentinel value.\n     */\n    function _clearReentrancyGuard() internal {\n        // Clear the reentrancy guard.\n        _reentrancyGuard = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Internal view function to ensure that the sentinel value for the\n            reentrancy guard is not currently set.\n     */\n    function _assertNonReentrant() internal view {\n        // Ensure that the reentrancy guard is not currently set.\n        if (_reentrancyGuard != _NOT_ENTERED) {\n            revert NoReentrantCalls();\n        }\n    }\n}\n"
    },
    "contracts/interfaces/ReentrancyErrors.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.7;\n\n/**\n * @title ReentrancyErrors\n * @author 0age\n * @notice ReentrancyErrors contains errors related to reentrancy.\n */\ninterface ReentrancyErrors {\n    /**\n     * @dev Revert with an error when a caller attempts to reenter a protected\n     *      function.\n     */\n    error NoReentrantCalls();\n}\n"
    },
    "contracts/interfaces/EIP1271Interface.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.7;\n\ninterface EIP1271Interface {\n    function isValidSignature(bytes32 digest, bytes calldata signature)\n        external\n        view\n        returns (bytes4);\n}"
    },
    "contracts/interfaces/SignatureVerificationErrors.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.7;\n\n/**\n * @title SignatureVerificationErrors\n * @author 0age\n * @notice SignatureVerificationErrors contains all errors related to signature\n *         verification.\n */\ninterface SignatureVerificationErrors {\n    /**\n     * @dev Revert with an error when a signature that does not contain a v\n     *      value of 27 or 28 has been supplied.\n     *\n     * @param v The invalid v value.\n     */\n    error BadSignatureV(uint8 v);\n\n    /**\n     * @dev Revert with an error when the signer recovered by the supplied\n     *      signature does not match the offerer or an allowed EIP-1271 signer\n     *      as specified by the offerer in the event they are a contract.\n     */\n    error InvalidSigner();\n\n    /**\n     * @dev Revert with an error when a signer cannot be recovered from the\n     *      supplied signature.\n     */\n    error InvalidSignature();\n\n    /**\n     * @dev Revert with an error when an EIP-1271 call to an account fails.\n     */\n    error BadContractSignature();\n}\n"
    },
    "contracts/lib/LowLevelHelpers.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport \"./ConsiderationConstants.sol\";\n\n/**\n * @title LowLevelHelpers\n * @author 0age\n * @notice LowLevelHelpers contains logic for performing various low-level\n *         operations.\n */\ncontract LowLevelHelpers {\n    /**\n     * @dev Internal view function to staticcall an arbitrary target with given\n     *      calldata. Note that no data is written to memory and no contract\n     *      size check is performed.\n     *\n     * @param target   The account to staticcall.\n     * @param callData The calldata to supply when staticcalling the target.\n     *\n     * @return success The status of the staticcall to the target.\n     */\n    function _staticcall(address target, bytes memory callData)\n        internal\n        view\n        returns (bool success)\n    {\n        assembly {\n            // Perform the staticcall.\n            success := staticcall(\n                gas(),\n                target,\n                add(callData, OneWord),\n                mload(callData),\n                0,\n                0\n            )\n        }\n    }\n\n    /**\n     * @dev Internal view function to revert and pass along the revert reason if\n     *      data was returned by the last call and that the size of that data\n     *      does not exceed the currently allocated memory size.\n     */\n    function _revertWithReasonIfOneIsReturned() internal view {\n        assembly {\n            // If it returned a message, bubble it up as long as sufficient gas\n            // remains to do so:\n            if returndatasize() {\n                // Ensure that sufficient gas is available to copy returndata\n                // while expanding memory where necessary. Start by computing\n                // the word size of returndata and allocated memory.\n                let returnDataWords := div(\n                    add(returndatasize(), AlmostOneWord),\n                    OneWord\n                )\n\n                // Note: use the free memory pointer in place of msize() to work\n                // around a Yul warning that prevents accessing msize directly\n                // when the IR pipeline is activated.\n                let msizeWords := div(mload(FreeMemoryPointerSlot), OneWord)\n\n                // Next, compute the cost of the returndatacopy.\n                let cost := mul(CostPerWord, returnDataWords)\n\n                // Then, compute cost of new memory allocation.\n                if gt(returnDataWords, msizeWords) {\n                    cost := add(\n                        cost,\n                        add(\n                            mul(sub(returnDataWords, msizeWords), CostPerWord),\n                            div(\n                                sub(\n                                    mul(returnDataWords, returnDataWords),\n                                    mul(msizeWords, msizeWords)\n                                ),\n                                MemoryExpansionCoefficient\n                            )\n                        )\n                    )\n                }\n\n                // Finally, add a small constant and compare to gas remaining;\n                // bubble up the revert data if enough gas is still available.\n                if lt(add(cost, ExtraGasBuffer), gas()) {\n                    // Copy returndata to memory; overwrite existing memory.\n                    returndatacopy(0, 0, returndatasize())\n\n                    // Revert, specifying memory region with copied returndata.\n                    revert(0, returndatasize())\n                }\n            }\n        }\n    }\n\n    /**\n     * @dev Internal pure function to determine if the first word of returndata\n     *      matches an expected magic value.\n     *\n     * @param expected The expected magic value.\n     *\n     * @return A boolean indicating whether the expected value matches the one\n     *         located in the first word of returndata.\n     */\n    function _doesNotMatchMagic(bytes4 expected) internal pure returns (bool) {\n        // Declare a variable for the value held by the return data buffer.\n        bytes4 result;\n\n        // Utilize assembly in order to read directly from returndata buffer.\n        assembly {\n            // Only put result on stack if return data is exactly one word.\n            if eq(returndatasize(), OneWord) {\n                // Copy the word directly from return data into scratch space.\n                returndatacopy(0, 0, OneWord)\n\n                // Take value from scratch space and place it on the stack.\n                result := mload(0)\n            }\n        }\n\n        // Return a boolean indicating whether expected and located value match.\n        return result != expected;\n    }\n}\n"
    },
    "contracts/lib/TokenTransferrerConstants.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.7;\n\n/*\n * -------------------------- Disambiguation & Other Notes ---------------------\n *    - The term \"head\" is used as it is in the documentation for ABI encoding,\n *      but only in reference to dynamic types, i.e. it always refers to the\n *      offset or pointer to the body of a dynamic type. In calldata, the head\n *      is always an offset (relative to the parent object), while in memory,\n *      the head is always the pointer to the body. More information found here:\n *      https://docs.soliditylang.org/en/v0.8.14/abi-spec.html#argument-encoding\n *        - Note that the length of an array is separate from and precedes the\n *          head of the array.\n *\n *    - The term \"body\" is used in place of the term \"head\" used in the ABI\n *      documentation. It refers to the start of the data for a dynamic type,\n *      e.g. the first word of a struct or the first word of the first element\n *      in an array.\n *\n *    - The term \"pointer\" is used to describe the absolute position of a value\n *      and never an offset relative to another value.\n *        - The suffix \"_ptr\" refers to a memory pointer.\n *        - The suffix \"_cdPtr\" refers to a calldata pointer.\n *\n *    - The term \"offset\" is used to describe the position of a value relative\n *      to some parent value. For example, OrderParameters_conduit_offset is the\n *      offset to the \"conduit\" value in the OrderParameters struct relative to\n *      the start of the body.\n *        - Note: Offsets are used to derive pointers.\n *\n *    - Some structs have pointers defined for all of their fields in this file.\n *      Lines which are commented out are fields that are not used in the\n *      codebase but have been left in for readability.\n */\n\nuint256 constant AlmostOneWord = 0x1f;\nuint256 constant OneWord = 0x20;\nuint256 constant TwoWords = 0x40;\nuint256 constant ThreeWords = 0x60;\n\nuint256 constant FreeMemoryPointerSlot = 0x40;\nuint256 constant ZeroSlot = 0x60;\nuint256 constant DefaultFreeMemoryPointer = 0x80;\n\nuint256 constant Slot0x80 = 0x80;\nuint256 constant Slot0xA0 = 0xa0;\nuint256 constant Slot0xC0 = 0xc0;\n\n// abi.encodeWithSignature(\"transferFrom(address,address,uint256)\")\nuint256 constant ERC20_transferFrom_signature = (\n    0x23b872dd00000000000000000000000000000000000000000000000000000000\n);\nuint256 constant ERC20_transferFrom_sig_ptr = 0x0;\nuint256 constant ERC20_transferFrom_from_ptr = 0x04;\nuint256 constant ERC20_transferFrom_to_ptr = 0x24;\nuint256 constant ERC20_transferFrom_amount_ptr = 0x44;\nuint256 constant ERC20_transferFrom_length = 0x64; // 4 + 32 * 3 == 100\n\n// abi.encodeWithSignature(\"transfer(address,uint256)\")\nuint256 constant ERC20_transfer_signature = (\n    0xa9059cbb00000000000000000000000000000000000000000000000000000000\n);\nuint256 constant ERC20_transfer_sig_ptr = 0x0;\nuint256 constant ERC20_transfer_to_ptr = 0x04;\nuint256 constant ERC20_transfer_amount_ptr = 0x24;\nuint256 constant ERC20_transfer_length = 0x44; // 4 + 32 * 2 == 68\n\n// abi.encodeWithSignature(\n//     \"safeTransferFrom(address,address,uint256,uint256,bytes)\"\n// )\nuint256 constant ERC1155_safeTransferFrom_signature = (\n    0xf242432a00000000000000000000000000000000000000000000000000000000\n);\nuint256 constant ERC1155_safeTransferFrom_sig_ptr = 0x0;\nuint256 constant ERC1155_safeTransferFrom_from_ptr = 0x04;\nuint256 constant ERC1155_safeTransferFrom_to_ptr = 0x24;\nuint256 constant ERC1155_safeTransferFrom_id_ptr = 0x44;\nuint256 constant ERC1155_safeTransferFrom_amount_ptr = 0x64;\nuint256 constant ERC1155_safeTransferFrom_data_offset_ptr = 0x84;\nuint256 constant ERC1155_safeTransferFrom_data_length_ptr = 0xa4;\nuint256 constant ERC1155_safeTransferFrom_length = 0xc4; // 4 + 32 * 6 == 196\nuint256 constant ERC1155_safeTransferFrom_data_length_offset = 0xa0;\n\n// abi.encodeWithSignature(\n//     \"safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)\"\n// )\nuint256 constant ERC1155_safeBatchTransferFrom_signature = (\n    0x2eb2c2d600000000000000000000000000000000000000000000000000000000\n);\n\nbytes4 constant ERC1155_safeBatchTransferFrom_selector = bytes4(\n    bytes32(ERC1155_safeBatchTransferFrom_signature)\n);\n\nuint256 constant ERC721_transferFrom_signature = ERC20_transferFrom_signature;\nuint256 constant ERC721_transferFrom_sig_ptr = 0x0;\nuint256 constant ERC721_transferFrom_from_ptr = 0x04;\nuint256 constant ERC721_transferFrom_to_ptr = 0x24;\nuint256 constant ERC721_transferFrom_id_ptr = 0x44;\nuint256 constant ERC721_transferFrom_length = 0x64; // 4 + 32 * 3 == 100\n\n// abi.encodeWithSignature(\"NoContract(address)\")\nuint256 constant NoContract_error_signature = (\n    0x5f15d67200000000000000000000000000000000000000000000000000000000\n);\nuint256 constant NoContract_error_sig_ptr = 0x0;\nuint256 constant NoContract_error_token_ptr = 0x4;\nuint256 constant NoContract_error_length = 0x24; // 4 + 32 == 36\n\n// abi.encodeWithSignature(\n//     \"TokenTransferGenericFailure(address,address,address,uint256,uint256)\"\n// )\nuint256 constant TokenTransferGenericFailure_error_signature = (\n    0xf486bc8700000000000000000000000000000000000000000000000000000000\n);\nuint256 constant TokenTransferGenericFailure_error_sig_ptr = 0x0;\nuint256 constant TokenTransferGenericFailure_error_token_ptr = 0x4;\nuint256 constant TokenTransferGenericFailure_error_from_ptr = 0x24;\nuint256 constant TokenTransferGenericFailure_error_to_ptr = 0x44;\nuint256 constant TokenTransferGenericFailure_error_id_ptr = 0x64;\nuint256 constant TokenTransferGenericFailure_error_amount_ptr = 0x84;\n\n// 4 + 32 * 5 == 164\nuint256 constant TokenTransferGenericFailure_error_length = 0xa4;\n\n// abi.encodeWithSignature(\n//     \"BadReturnValueFromERC20OnTransfer(address,address,address,uint256)\"\n// )\nuint256 constant BadReturnValueFromERC20OnTransfer_error_signature = (\n    0x9889192300000000000000000000000000000000000000000000000000000000\n);\nuint256 constant BadReturnValueFromERC20OnTransfer_error_sig_ptr = 0x0;\nuint256 constant BadReturnValueFromERC20OnTransfer_error_token_ptr = 0x4;\nuint256 constant BadReturnValueFromERC20OnTransfer_error_from_ptr = 0x24;\nuint256 constant BadReturnValueFromERC20OnTransfer_error_to_ptr = 0x44;\nuint256 constant BadReturnValueFromERC20OnTransfer_error_amount_ptr = 0x64;\n\n// 4 + 32 * 4 == 132\nuint256 constant BadReturnValueFromERC20OnTransfer_error_length = 0x84;\n\nuint256 constant ExtraGasBuffer = 0x20;\nuint256 constant CostPerWord = 3;\nuint256 constant MemoryExpansionCoefficient = 0x200;\n\n// Values are offset by 32 bytes in order to write the token to the beginning\n// in the event of a revert\nuint256 constant BatchTransfer1155Params_ptr = 0x24;\nuint256 constant BatchTransfer1155Params_ids_head_ptr = 0x64;\nuint256 constant BatchTransfer1155Params_amounts_head_ptr = 0x84;\nuint256 constant BatchTransfer1155Params_data_head_ptr = 0xa4;\nuint256 constant BatchTransfer1155Params_data_length_basePtr = 0xc4;\nuint256 constant BatchTransfer1155Params_calldata_baseSize = 0xc4;\n\nuint256 constant BatchTransfer1155Params_ids_length_ptr = 0xc4;\n\nuint256 constant BatchTransfer1155Params_ids_length_offset = 0xa0;\nuint256 constant BatchTransfer1155Params_amounts_length_baseOffset = 0xc0;\nuint256 constant BatchTransfer1155Params_data_length_baseOffset = 0xe0;\n\nuint256 constant ConduitBatch1155Transfer_usable_head_size = 0x80;\n\nuint256 constant ConduitBatch1155Transfer_from_offset = 0x20;\nuint256 constant ConduitBatch1155Transfer_ids_head_offset = 0x60;\nuint256 constant ConduitBatch1155Transfer_amounts_head_offset = 0x80;\nuint256 constant ConduitBatch1155Transfer_ids_length_offset = 0xa0;\nuint256 constant ConduitBatch1155Transfer_amounts_length_baseOffset = 0xc0;\nuint256 constant ConduitBatch1155Transfer_calldata_baseSize = 0xc0;\n\n// Note: abbreviated version of above constant to adhere to line length limit.\nuint256 constant ConduitBatchTransfer_amounts_head_offset = 0x80;\n\nuint256 constant Invalid1155BatchTransferEncoding_ptr = 0x00;\nuint256 constant Invalid1155BatchTransferEncoding_length = 0x04;\nuint256 constant Invalid1155BatchTransferEncoding_selector = (\n    0xeba2084c00000000000000000000000000000000000000000000000000000000\n);\n\nuint256 constant ERC1155BatchTransferGenericFailure_error_signature = (\n    0xafc445e200000000000000000000000000000000000000000000000000000000\n);\nuint256 constant ERC1155BatchTransferGenericFailure_token_ptr = 0x04;\nuint256 constant ERC1155BatchTransferGenericFailure_ids_offset = 0xc0;\n"
    },
    "erc721a/contracts/extensions/IERC4907A.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// ERC721A Contracts v4.2.3\n// Creator: Chiru Labs\n\npragma solidity ^0.8.4;\n\nimport '../IERC721A.sol';\n\n/**\n * @dev Interface of ERC4907A.\n */\ninterface IERC4907A is IERC721A {\n    /**\n     * The caller must own the token or be an approved operator.\n     */\n    error SetUserCallerNotOwnerNorApproved();\n\n    /**\n     * @dev Emitted when the `user` of an NFT or the `expires` of the `user` is changed.\n     * The zero address for user indicates that there is no user address.\n     */\n    event UpdateUser(uint256 indexed tokenId, address indexed user, uint64 expires);\n\n    /**\n     * @dev Sets the `user` and `expires` for `tokenId`.\n     * The zero address indicates there is no user.\n     *\n     * Requirements:\n     *\n     * - The caller must own `tokenId` or be an approved operator.\n     */\n    function setUser(\n        uint256 tokenId,\n        address user,\n        uint64 expires\n    ) external;\n\n    /**\n     * @dev Returns the user address for `tokenId`.\n     * The zero address indicates that there is no user or if the user is expired.\n     */\n    function userOf(uint256 tokenId) external view returns (address);\n\n    /**\n     * @dev Returns the user's expires of `tokenId`.\n     */\n    function userExpires(uint256 tokenId) external view returns (uint256);\n}\n"
    },
    "erc721a/contracts/IERC721A.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// ERC721A Contracts v4.2.3\n// Creator: Chiru Labs\n\npragma solidity ^0.8.4;\n\n/**\n * @dev Interface of ERC721A.\n */\ninterface IERC721A {\n    /**\n     * The caller must own the token or be an approved operator.\n     */\n    error ApprovalCallerNotOwnerNorApproved();\n\n    /**\n     * The token does not exist.\n     */\n    error ApprovalQueryForNonexistentToken();\n\n    /**\n     * Cannot query the balance for the zero address.\n     */\n    error BalanceQueryForZeroAddress();\n\n    /**\n     * Cannot mint to the zero address.\n     */\n    error MintToZeroAddress();\n\n    /**\n     * The quantity of tokens minted must be more than zero.\n     */\n    error MintZeroQuantity();\n\n    /**\n     * The token does not exist.\n     */\n    error OwnerQueryForNonexistentToken();\n\n    /**\n     * The caller must own the token or be an approved operator.\n     */\n    error TransferCallerNotOwnerNorApproved();\n\n    /**\n     * The token must be owned by `from`.\n     */\n    error TransferFromIncorrectOwner();\n\n    /**\n     * Cannot safely transfer to a contract that does not implement the\n     * ERC721Receiver interface.\n     */\n    error TransferToNonERC721ReceiverImplementer();\n\n    /**\n     * Cannot transfer to the zero address.\n     */\n    error TransferToZeroAddress();\n\n    /**\n     * The token does not exist.\n     */\n    error URIQueryForNonexistentToken();\n\n    /**\n     * The `quantity` minted with ERC2309 exceeds the safety limit.\n     */\n    error MintERC2309QuantityExceedsLimit();\n\n    /**\n     * The `extraData` cannot be set on an unintialized ownership slot.\n     */\n    error OwnershipNotInitializedForExtraData();\n\n    // =============================================================\n    //                            STRUCTS\n    // =============================================================\n\n    struct TokenOwnership {\n        // The address of the owner.\n        address addr;\n        // Stores the start time of ownership with minimal overhead for tokenomics.\n        uint64 startTimestamp;\n        // Whether the token has been burned.\n        bool burned;\n        // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}.\n        uint24 extraData;\n    }\n\n    // =============================================================\n    //                         TOKEN COUNTERS\n    // =============================================================\n\n    /**\n     * @dev Returns the total number of tokens in existence.\n     * Burned tokens will reduce the count.\n     * To get the total number of tokens minted, please see {_totalMinted}.\n     */\n    function totalSupply() external view returns (uint256);\n\n    // =============================================================\n    //                            IERC165\n    // =============================================================\n\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n\n    // =============================================================\n    //                            IERC721\n    // =============================================================\n\n    /**\n     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n     */\n    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables or disables\n     * (`approved`) `operator` to manage all of its assets.\n     */\n    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n    /**\n     * @dev Returns the number of tokens in `owner`'s account.\n     */\n    function balanceOf(address owner) external view returns (uint256 balance);\n\n    /**\n     * @dev Returns the owner of the `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function ownerOf(uint256 tokenId) external view returns (address owner);\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`,\n     * checking first that contract recipients are aware of the ERC721 protocol\n     * to prevent tokens from being forever locked.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must be have been allowed to move\n     * this token by either {approve} or {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement\n     * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId,\n        bytes calldata data\n    ) external payable;\n\n    /**\n     * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) external payable;\n\n    /**\n     * @dev Transfers `tokenId` from `from` to `to`.\n     *\n     * WARNING: Usage of this method is discouraged, use {safeTransferFrom}\n     * whenever possible.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token\n     * by either {approve} or {setApprovalForAll}.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) external payable;\n\n    /**\n     * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n     * The approval is cleared when the token is transferred.\n     *\n     * Only a single account can be approved at a time, so approving the\n     * zero address clears previous approvals.\n     *\n     * Requirements:\n     *\n     * - The caller must own the token or be an approved operator.\n     * - `tokenId` must exist.\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address to, uint256 tokenId) external payable;\n\n    /**\n     * @dev Approve or remove `operator` as an operator for the caller.\n     * Operators can call {transferFrom} or {safeTransferFrom}\n     * for any token owned by the caller.\n     *\n     * Requirements:\n     *\n     * - The `operator` cannot be the caller.\n     *\n     * Emits an {ApprovalForAll} event.\n     */\n    function setApprovalForAll(address operator, bool _approved) external;\n\n    /**\n     * @dev Returns the account approved for `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function getApproved(uint256 tokenId) external view returns (address operator);\n\n    /**\n     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n     *\n     * See {setApprovalForAll}.\n     */\n    function isApprovedForAll(address owner, address operator) external view returns (bool);\n\n    // =============================================================\n    //                        IERC721Metadata\n    // =============================================================\n\n    /**\n     * @dev Returns the token collection name.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the token collection symbol.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n     */\n    function tokenURI(uint256 tokenId) external view returns (string memory);\n\n    // =============================================================\n    //                           IERC2309\n    // =============================================================\n\n    /**\n     * @dev Emitted when tokens in `fromTokenId` to `toTokenId`\n     * (inclusive) is transferred from `from` to `to`, as defined in the\n     * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard.\n     *\n     * See {_mintERC2309} for more details.\n     */\n    event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to);\n}\n"
    },
    "erc721a/contracts/ERC721A.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// ERC721A Contracts v4.2.3\n// Creator: Chiru Labs\n\npragma solidity ^0.8.4;\n\nimport './IERC721A.sol';\n\n/**\n * @dev Interface of ERC721 token receiver.\n */\ninterface ERC721A__IERC721Receiver {\n    function onERC721Received(\n        address operator,\n        address from,\n        uint256 tokenId,\n        bytes calldata data\n    ) external returns (bytes4);\n}\n\n/**\n * @title ERC721A\n *\n * @dev Implementation of the [ERC721](https://eips.ethereum.org/EIPS/eip-721)\n * Non-Fungible Token Standard, including the Metadata extension.\n * Optimized for lower gas during batch mints.\n *\n * Token IDs are minted in sequential order (e.g. 0, 1, 2, 3, ...)\n * starting from `_startTokenId()`.\n *\n * Assumptions:\n *\n * - An owner cannot have more than 2**64 - 1 (max value of uint64) of supply.\n * - The maximum token ID cannot exceed 2**256 - 1 (max value of uint256).\n */\ncontract ERC721A is IERC721A {\n    // Bypass for a `--via-ir` bug (https://github.com/chiru-labs/ERC721A/pull/364).\n    struct TokenApprovalRef {\n        address value;\n    }\n\n    // =============================================================\n    //                           CONSTANTS\n    // =============================================================\n\n    // Mask of an entry in packed address data.\n    uint256 private constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1;\n\n    // The bit position of `numberMinted` in packed address data.\n    uint256 private constant _BITPOS_NUMBER_MINTED = 64;\n\n    // The bit position of `numberBurned` in packed address data.\n    uint256 private constant _BITPOS_NUMBER_BURNED = 128;\n\n    // The bit position of `aux` in packed address data.\n    uint256 private constant _BITPOS_AUX = 192;\n\n    // Mask of all 256 bits in packed address data except the 64 bits for `aux`.\n    uint256 private constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1;\n\n    // The bit position of `startTimestamp` in packed ownership.\n    uint256 private constant _BITPOS_START_TIMESTAMP = 160;\n\n    // The bit mask of the `burned` bit in packed ownership.\n    uint256 private constant _BITMASK_BURNED = 1 << 224;\n\n    // The bit position of the `nextInitialized` bit in packed ownership.\n    uint256 private constant _BITPOS_NEXT_INITIALIZED = 225;\n\n    // The bit mask of the `nextInitialized` bit in packed ownership.\n    uint256 private constant _BITMASK_NEXT_INITIALIZED = 1 << 225;\n\n    // The bit position of `extraData` in packed ownership.\n    uint256 private constant _BITPOS_EXTRA_DATA = 232;\n\n    // Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`.\n    uint256 private constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1;\n\n    // The mask of the lower 160 bits for addresses.\n    uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;\n\n    // The maximum `quantity` that can be minted with {_mintERC2309}.\n    // This limit is to prevent overflows on the address data entries.\n    // For a limit of 5000, a total of 3.689e15 calls to {_mintERC2309}\n    // is required to cause an overflow, which is unrealistic.\n    uint256 private constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000;\n\n    // The `Transfer` event signature is given by:\n    // `keccak256(bytes(\"Transfer(address,address,uint256)\"))`.\n    bytes32 private constant _TRANSFER_EVENT_SIGNATURE =\n        0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;\n\n    // =============================================================\n    //                            STORAGE\n    // =============================================================\n\n    // The next token ID to be minted.\n    uint256 private _currentIndex;\n\n    // The number of tokens burned.\n    uint256 private _burnCounter;\n\n    // Token name\n    string private _name;\n\n    // Token symbol\n    string private _symbol;\n\n    // Mapping from token ID to ownership details\n    // An empty struct value does not necessarily mean the token is unowned.\n    // See {_packedOwnershipOf} implementation for details.\n    //\n    // Bits Layout:\n    // - [0..159]   `addr`\n    // - [160..223] `startTimestamp`\n    // - [224]      `burned`\n    // - [225]      `nextInitialized`\n    // - [232..255] `extraData`\n    mapping(uint256 => uint256) private _packedOwnerships;\n\n    // Mapping owner address to address data.\n    //\n    // Bits Layout:\n    // - [0..63]    `balance`\n    // - [64..127]  `numberMinted`\n    // - [128..191] `numberBurned`\n    // - [192..255] `aux`\n    mapping(address => uint256) private _packedAddressData;\n\n    // Mapping from token ID to approved address.\n    mapping(uint256 => TokenApprovalRef) private _tokenApprovals;\n\n    // Mapping from owner to operator approvals\n    mapping(address => mapping(address => bool)) private _operatorApprovals;\n\n    // =============================================================\n    //                          CONSTRUCTOR\n    // =============================================================\n\n    constructor(string memory name_, string memory symbol_) {\n        _name = name_;\n        _symbol = symbol_;\n        _currentIndex = _startTokenId();\n    }\n\n    // =============================================================\n    //                   TOKEN COUNTING OPERATIONS\n    // =============================================================\n\n    /**\n     * @dev Returns the starting token ID.\n     * To change the starting token ID, please override this function.\n     */\n    function _startTokenId() internal view virtual returns (uint256) {\n        return 0;\n    }\n\n    /**\n     * @dev Returns the next token ID to be minted.\n     */\n    function _nextTokenId() internal view virtual returns (uint256) {\n        return _currentIndex;\n    }\n\n    /**\n     * @dev Returns the total number of tokens in existence.\n     * Burned tokens will reduce the count.\n     * To get the total number of tokens minted, please see {_totalMinted}.\n     */\n    function totalSupply() public view virtual override returns (uint256) {\n        // Counter underflow is impossible as _burnCounter cannot be incremented\n        // more than `_currentIndex - _startTokenId()` times.\n        unchecked {\n            return _currentIndex - _burnCounter - _startTokenId();\n        }\n    }\n\n    /**\n     * @dev Returns the total amount of tokens minted in the contract.\n     */\n    function _totalMinted() internal view virtual returns (uint256) {\n        // Counter underflow is impossible as `_currentIndex` does not decrement,\n        // and it is initialized to `_startTokenId()`.\n        unchecked {\n            return _currentIndex - _startTokenId();\n        }\n    }\n\n    /**\n     * @dev Returns the total number of tokens burned.\n     */\n    function _totalBurned() internal view virtual returns (uint256) {\n        return _burnCounter;\n    }\n\n    // =============================================================\n    //                    ADDRESS DATA OPERATIONS\n    // =============================================================\n\n    /**\n     * @dev Returns the number of tokens in `owner`'s account.\n     */\n    function balanceOf(address owner) public view virtual override returns (uint256) {\n        if (owner == address(0)) revert BalanceQueryForZeroAddress();\n        return _packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY;\n    }\n\n    /**\n     * Returns the number of tokens minted by `owner`.\n     */\n    function _numberMinted(address owner) internal view returns (uint256) {\n        return (_packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) & _BITMASK_ADDRESS_DATA_ENTRY;\n    }\n\n    /**\n     * Returns the number of tokens burned by or on behalf of `owner`.\n     */\n    function _numberBurned(address owner) internal view returns (uint256) {\n        return (_packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) & _BITMASK_ADDRESS_DATA_ENTRY;\n    }\n\n    /**\n     * Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).\n     */\n    function _getAux(address owner) internal view returns (uint64) {\n        return uint64(_packedAddressData[owner] >> _BITPOS_AUX);\n    }\n\n    /**\n     * Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).\n     * If there are multiple variables, please pack them into a uint64.\n     */\n    function _setAux(address owner, uint64 aux) internal virtual {\n        uint256 packed = _packedAddressData[owner];\n        uint256 auxCasted;\n        // Cast `aux` with assembly to avoid redundant masking.\n        assembly {\n            auxCasted := aux\n        }\n        packed = (packed & _BITMASK_AUX_COMPLEMENT) | (auxCasted << _BITPOS_AUX);\n        _packedAddressData[owner] = packed;\n    }\n\n    // =============================================================\n    //                            IERC165\n    // =============================================================\n\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        // The interface IDs are constants representing the first 4 bytes\n        // of the XOR of all function selectors in the interface.\n        // See: [ERC165](https://eips.ethereum.org/EIPS/eip-165)\n        // (e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)`)\n        return\n            interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165.\n            interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721.\n            interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata.\n    }\n\n    // =============================================================\n    //                        IERC721Metadata\n    // =============================================================\n\n    /**\n     * @dev Returns the token collection name.\n     */\n    function name() public view virtual override returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @dev Returns the token collection symbol.\n     */\n    function symbol() public view virtual override returns (string memory) {\n        return _symbol;\n    }\n\n    /**\n     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n     */\n    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {\n        if (!_exists(tokenId)) revert URIQueryForNonexistentToken();\n\n        string memory baseURI = _baseURI();\n        return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : '';\n    }\n\n    /**\n     * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each\n     * token will be the concatenation of the `baseURI` and the `tokenId`. Empty\n     * by default, it can be overridden in child contracts.\n     */\n    function _baseURI() internal view virtual returns (string memory) {\n        return '';\n    }\n\n    // =============================================================\n    //                     OWNERSHIPS OPERATIONS\n    // =============================================================\n\n    /**\n     * @dev Returns the owner of the `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function ownerOf(uint256 tokenId) public view virtual override returns (address) {\n        return address(uint160(_packedOwnershipOf(tokenId)));\n    }\n\n    /**\n     * @dev Gas spent here starts off proportional to the maximum mint batch size.\n     * It gradually moves to O(1) as tokens get transferred around over time.\n     */\n    function _ownershipOf(uint256 tokenId) internal view virtual returns (TokenOwnership memory) {\n        return _unpackedOwnership(_packedOwnershipOf(tokenId));\n    }\n\n    /**\n     * @dev Returns the unpacked `TokenOwnership` struct at `index`.\n     */\n    function _ownershipAt(uint256 index) internal view virtual returns (TokenOwnership memory) {\n        return _unpackedOwnership(_packedOwnerships[index]);\n    }\n\n    /**\n     * @dev Initializes the ownership slot minted at `index` for efficiency purposes.\n     */\n    function _initializeOwnershipAt(uint256 index) internal virtual {\n        if (_packedOwnerships[index] == 0) {\n            _packedOwnerships[index] = _packedOwnershipOf(index);\n        }\n    }\n\n    /**\n     * Returns the packed ownership data of `tokenId`.\n     */\n    function _packedOwnershipOf(uint256 tokenId) private view returns (uint256) {\n        uint256 curr = tokenId;\n\n        unchecked {\n            if (_startTokenId() <= curr)\n                if (curr < _currentIndex) {\n                    uint256 packed = _packedOwnerships[curr];\n                    // If not burned.\n                    if (packed & _BITMASK_BURNED == 0) {\n                        // Invariant:\n                        // There will always be an initialized ownership slot\n                        // (i.e. `ownership.addr != address(0) && ownership.burned == false`)\n                        // before an unintialized ownership slot\n                        // (i.e. `ownership.addr == address(0) && ownership.burned == false`)\n                        // Hence, `curr` will not underflow.\n                        //\n                        // We can directly compare the packed value.\n                        // If the address is zero, packed will be zero.\n                        while (packed == 0) {\n                            packed = _packedOwnerships[--curr];\n                        }\n                        return packed;\n                    }\n                }\n        }\n        revert OwnerQueryForNonexistentToken();\n    }\n\n    /**\n     * @dev Returns the unpacked `TokenOwnership` struct from `packed`.\n     */\n    function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) {\n        ownership.addr = address(uint160(packed));\n        ownership.startTimestamp = uint64(packed >> _BITPOS_START_TIMESTAMP);\n        ownership.burned = packed & _BITMASK_BURNED != 0;\n        ownership.extraData = uint24(packed >> _BITPOS_EXTRA_DATA);\n    }\n\n    /**\n     * @dev Packs ownership data into a single uint256.\n     */\n    function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) {\n        assembly {\n            // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.\n            owner := and(owner, _BITMASK_ADDRESS)\n            // `owner | (block.timestamp << _BITPOS_START_TIMESTAMP) | flags`.\n            result := or(owner, or(shl(_BITPOS_START_TIMESTAMP, timestamp()), flags))\n        }\n    }\n\n    /**\n     * @dev Returns the `nextInitialized` flag set if `quantity` equals 1.\n     */\n    function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) {\n        // For branchless setting of the `nextInitialized` flag.\n        assembly {\n            // `(quantity == 1) << _BITPOS_NEXT_INITIALIZED`.\n            result := shl(_BITPOS_NEXT_INITIALIZED, eq(quantity, 1))\n        }\n    }\n\n    // =============================================================\n    //                      APPROVAL OPERATIONS\n    // =============================================================\n\n    /**\n     * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n     * The approval is cleared when the token is transferred.\n     *\n     * Only a single account can be approved at a time, so approving the\n     * zero address clears previous approvals.\n     *\n     * Requirements:\n     *\n     * - The caller must own the token or be an approved operator.\n     * - `tokenId` must exist.\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address to, uint256 tokenId) public payable virtual override {\n        address owner = ownerOf(tokenId);\n\n        if (_msgSenderERC721A() != owner)\n            if (!isApprovedForAll(owner, _msgSenderERC721A())) {\n                revert ApprovalCallerNotOwnerNorApproved();\n            }\n\n        _tokenApprovals[tokenId].value = to;\n        emit Approval(owner, to, tokenId);\n    }\n\n    /**\n     * @dev Returns the account approved for `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function getApproved(uint256 tokenId) public view virtual override returns (address) {\n        if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken();\n\n        return _tokenApprovals[tokenId].value;\n    }\n\n    /**\n     * @dev Approve or remove `operator` as an operator for the caller.\n     * Operators can call {transferFrom} or {safeTransferFrom}\n     * for any token owned by the caller.\n     *\n     * Requirements:\n     *\n     * - The `operator` cannot be the caller.\n     *\n     * Emits an {ApprovalForAll} event.\n     */\n    function setApprovalForAll(address operator, bool approved) public virtual override {\n        _operatorApprovals[_msgSenderERC721A()][operator] = approved;\n        emit ApprovalForAll(_msgSenderERC721A(), operator, approved);\n    }\n\n    /**\n     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n     *\n     * See {setApprovalForAll}.\n     */\n    function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {\n        return _operatorApprovals[owner][operator];\n    }\n\n    /**\n     * @dev Returns whether `tokenId` exists.\n     *\n     * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.\n     *\n     * Tokens start existing when they are minted. See {_mint}.\n     */\n    function _exists(uint256 tokenId) internal view virtual returns (bool) {\n        return\n            _startTokenId() <= tokenId &&\n            tokenId < _currentIndex && // If within bounds,\n            _packedOwnerships[tokenId] & _BITMASK_BURNED == 0; // and not burned.\n    }\n\n    /**\n     * @dev Returns whether `msgSender` is equal to `approvedAddress` or `owner`.\n     */\n    function _isSenderApprovedOrOwner(\n        address approvedAddress,\n        address owner,\n        address msgSender\n    ) private pure returns (bool result) {\n        assembly {\n            // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.\n            owner := and(owner, _BITMASK_ADDRESS)\n            // Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean.\n            msgSender := and(msgSender, _BITMASK_ADDRESS)\n            // `msgSender == owner || msgSender == approvedAddress`.\n            result := or(eq(msgSender, owner), eq(msgSender, approvedAddress))\n        }\n    }\n\n    /**\n     * @dev Returns the storage slot and value for the approved address of `tokenId`.\n     */\n    function _getApprovedSlotAndAddress(uint256 tokenId)\n        private\n        view\n        returns (uint256 approvedAddressSlot, address approvedAddress)\n    {\n        TokenApprovalRef storage tokenApproval = _tokenApprovals[tokenId];\n        // The following is equivalent to `approvedAddress = _tokenApprovals[tokenId].value`.\n        assembly {\n            approvedAddressSlot := tokenApproval.slot\n            approvedAddress := sload(approvedAddressSlot)\n        }\n    }\n\n    // =============================================================\n    //                      TRANSFER OPERATIONS\n    // =============================================================\n\n    /**\n     * @dev Transfers `tokenId` from `from` to `to`.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token\n     * by either {approve} or {setApprovalForAll}.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) public payable virtual override {\n        uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);\n\n        if (address(uint160(prevOwnershipPacked)) != from) revert TransferFromIncorrectOwner();\n\n        (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);\n\n        // The nested ifs save around 20+ gas over a compound boolean condition.\n        if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))\n            if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();\n\n        if (to == address(0)) revert TransferToZeroAddress();\n\n        _beforeTokenTransfers(from, to, tokenId, 1);\n\n        // Clear approvals from the previous owner.\n        assembly {\n            if approvedAddress {\n                // This is equivalent to `delete _tokenApprovals[tokenId]`.\n                sstore(approvedAddressSlot, 0)\n            }\n        }\n\n        // Underflow of the sender's balance is impossible because we check for\n        // ownership above and the recipient's balance can't realistically overflow.\n        // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.\n        unchecked {\n            // We can directly increment and decrement the balances.\n            --_packedAddressData[from]; // Updates: `balance -= 1`.\n            ++_packedAddressData[to]; // Updates: `balance += 1`.\n\n            // Updates:\n            // - `address` to the next owner.\n            // - `startTimestamp` to the timestamp of transfering.\n            // - `burned` to `false`.\n            // - `nextInitialized` to `true`.\n            _packedOwnerships[tokenId] = _packOwnershipData(\n                to,\n                _BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked)\n            );\n\n            // If the next slot may not have been initialized (i.e. `nextInitialized == false`) .\n            if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {\n                uint256 nextTokenId = tokenId + 1;\n                // If the next slot's address is zero and not burned (i.e. packed value is zero).\n                if (_packedOwnerships[nextTokenId] == 0) {\n                    // If the next slot is within bounds.\n                    if (nextTokenId != _currentIndex) {\n                        // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.\n                        _packedOwnerships[nextTokenId] = prevOwnershipPacked;\n                    }\n                }\n            }\n        }\n\n        emit Transfer(from, to, tokenId);\n        _afterTokenTransfers(from, to, tokenId, 1);\n    }\n\n    /**\n     * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) public payable virtual override {\n        safeTransferFrom(from, to, tokenId, '');\n    }\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token\n     * by either {approve} or {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement\n     * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId,\n        bytes memory _data\n    ) public payable virtual override {\n        transferFrom(from, to, tokenId);\n        if (to.code.length != 0)\n            if (!_checkContractOnERC721Received(from, to, tokenId, _data)) {\n                revert TransferToNonERC721ReceiverImplementer();\n            }\n    }\n\n    /**\n     * @dev Hook that is called before a set of serially-ordered token IDs\n     * are about to be transferred. This includes minting.\n     * And also called before burning one token.\n     *\n     * `startTokenId` - the first token ID to be transferred.\n     * `quantity` - the amount to be transferred.\n     *\n     * Calling conditions:\n     *\n     * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be\n     * transferred to `to`.\n     * - When `from` is zero, `tokenId` will be minted for `to`.\n     * - When `to` is zero, `tokenId` will be burned by `from`.\n     * - `from` and `to` are never both zero.\n     */\n    function _beforeTokenTransfers(\n        address from,\n        address to,\n        uint256 startTokenId,\n        uint256 quantity\n    ) internal virtual {}\n\n    /**\n     * @dev Hook that is called after a set of serially-ordered token IDs\n     * have been transferred. This includes minting.\n     * And also called after one token has been burned.\n     *\n     * `startTokenId` - the first token ID to be transferred.\n     * `quantity` - the amount to be transferred.\n     *\n     * Calling conditions:\n     *\n     * - When `from` and `to` are both non-zero, `from`'s `tokenId` has been\n     * transferred to `to`.\n     * - When `from` is zero, `tokenId` has been minted for `to`.\n     * - When `to` is zero, `tokenId` has been burned by `from`.\n     * - `from` and `to` are never both zero.\n     */\n    function _afterTokenTransfers(\n        address from,\n        address to,\n        uint256 startTokenId,\n        uint256 quantity\n    ) internal virtual {}\n\n    /**\n     * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target contract.\n     *\n     * `from` - Previous owner of the given token ID.\n     * `to` - Target address that will receive the token.\n     * `tokenId` - Token ID to be transferred.\n     * `_data` - Optional data to send along with the call.\n     *\n     * Returns whether the call correctly returned the expected magic value.\n     */\n    function _checkContractOnERC721Received(\n        address from,\n        address to,\n        uint256 tokenId,\n        bytes memory _data\n    ) private returns (bool) {\n        try ERC721A__IERC721Receiver(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data) returns (\n            bytes4 retval\n        ) {\n            return retval == ERC721A__IERC721Receiver(to).onERC721Received.selector;\n        } catch (bytes memory reason) {\n            if (reason.length == 0) {\n                revert TransferToNonERC721ReceiverImplementer();\n            } else {\n                assembly {\n                    revert(add(32, reason), mload(reason))\n                }\n            }\n        }\n    }\n\n    // =============================================================\n    //                        MINT OPERATIONS\n    // =============================================================\n\n    /**\n     * @dev Mints `quantity` tokens and transfers them to `to`.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - `quantity` must be greater than 0.\n     *\n     * Emits a {Transfer} event for each mint.\n     */\n    function _mint(address to, uint256 quantity) internal virtual {\n        uint256 startTokenId = _currentIndex;\n        if (quantity == 0) revert MintZeroQuantity();\n\n        _beforeTokenTransfers(address(0), to, startTokenId, quantity);\n\n        // Overflows are incredibly unrealistic.\n        // `balance` and `numberMinted` have a maximum limit of 2**64.\n        // `tokenId` has a maximum limit of 2**256.\n        unchecked {\n            // Updates:\n            // - `balance += quantity`.\n            // - `numberMinted += quantity`.\n            //\n            // We can directly add to the `balance` and `numberMinted`.\n            _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);\n\n            // Updates:\n            // - `address` to the owner.\n            // - `startTimestamp` to the timestamp of minting.\n            // - `burned` to `false`.\n            // - `nextInitialized` to `quantity == 1`.\n            _packedOwnerships[startTokenId] = _packOwnershipData(\n                to,\n                _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)\n            );\n\n            uint256 toMasked;\n            uint256 end = startTokenId + quantity;\n\n            // Use assembly to loop and emit the `Transfer` event for gas savings.\n            // The duplicated `log4` removes an extra check and reduces stack juggling.\n            // The assembly, together with the surrounding Solidity code, have been\n            // delicately arranged to nudge the compiler into producing optimized opcodes.\n            assembly {\n                // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.\n                toMasked := and(to, _BITMASK_ADDRESS)\n                // Emit the `Transfer` event.\n                log4(\n                    0, // Start of data (0, since no data).\n                    0, // End of data (0, since no data).\n                    _TRANSFER_EVENT_SIGNATURE, // Signature.\n                    0, // `address(0)`.\n                    toMasked, // `to`.\n                    startTokenId // `tokenId`.\n                )\n\n                // The `iszero(eq(,))` check ensures that large values of `quantity`\n                // that overflows uint256 will make the loop run out of gas.\n                // The compiler will optimize the `iszero` away for performance.\n                for {\n                    let tokenId := add(startTokenId, 1)\n                } iszero(eq(tokenId, end)) {\n                    tokenId := add(tokenId, 1)\n                } {\n                    // Emit the `Transfer` event. Similar to above.\n                    log4(0, 0, _TRANSFER_EVENT_SIGNATURE, 0, toMasked, tokenId)\n                }\n            }\n            if (toMasked == 0) revert MintToZeroAddress();\n\n            _currentIndex = end;\n        }\n        _afterTokenTransfers(address(0), to, startTokenId, quantity);\n    }\n\n    /**\n     * @dev Mints `quantity` tokens and transfers them to `to`.\n     *\n     * This function is intended for efficient minting only during contract creation.\n     *\n     * It emits only one {ConsecutiveTransfer} as defined in\n     * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309),\n     * instead of a sequence of {Transfer} event(s).\n     *\n     * Calling this function outside of contract creation WILL make your contract\n     * non-compliant with the ERC721 standard.\n     * For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309\n     * {ConsecutiveTransfer} event is only permissible during contract creation.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - `quantity` must be greater than 0.\n     *\n     * Emits a {ConsecutiveTransfer} event.\n     */\n    function _mintERC2309(address to, uint256 quantity) internal virtual {\n        uint256 startTokenId = _currentIndex;\n        if (to == address(0)) revert MintToZeroAddress();\n        if (quantity == 0) revert MintZeroQuantity();\n        if (quantity > _MAX_MINT_ERC2309_QUANTITY_LIMIT) revert MintERC2309QuantityExceedsLimit();\n\n        _beforeTokenTransfers(address(0), to, startTokenId, quantity);\n\n        // Overflows are unrealistic due to the above check for `quantity` to be below the limit.\n        unchecked {\n            // Updates:\n            // - `balance += quantity`.\n            // - `numberMinted += quantity`.\n            //\n            // We can directly add to the `balance` and `numberMinted`.\n            _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);\n\n            // Updates:\n            // - `address` to the owner.\n            // - `startTimestamp` to the timestamp of minting.\n            // - `burned` to `false`.\n            // - `nextInitialized` to `quantity == 1`.\n            _packedOwnerships[startTokenId] = _packOwnershipData(\n                to,\n                _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)\n            );\n\n            emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to);\n\n            _currentIndex = startTokenId + quantity;\n        }\n        _afterTokenTransfers(address(0), to, startTokenId, quantity);\n    }\n\n    /**\n     * @dev Safely mints `quantity` tokens and transfers them to `to`.\n     *\n     * Requirements:\n     *\n     * - If `to` refers to a smart contract, it must implement\n     * {IERC721Receiver-onERC721Received}, which is called for each safe transfer.\n     * - `quantity` must be greater than 0.\n     *\n     * See {_mint}.\n     *\n     * Emits a {Transfer} event for each mint.\n     */\n    function _safeMint(\n        address to,\n        uint256 quantity,\n        bytes memory _data\n    ) internal virtual {\n        _mint(to, quantity);\n\n        unchecked {\n            if (to.code.length != 0) {\n                uint256 end = _currentIndex;\n                uint256 index = end - quantity;\n                do {\n                    if (!_checkContractOnERC721Received(address(0), to, index++, _data)) {\n                        revert TransferToNonERC721ReceiverImplementer();\n                    }\n                } while (index < end);\n                // Reentrancy protection.\n                if (_currentIndex != end) revert();\n            }\n        }\n    }\n\n    /**\n     * @dev Equivalent to `_safeMint(to, quantity, '')`.\n     */\n    function _safeMint(address to, uint256 quantity) internal virtual {\n        _safeMint(to, quantity, '');\n    }\n\n    // =============================================================\n    //                        BURN OPERATIONS\n    // =============================================================\n\n    /**\n     * @dev Equivalent to `_burn(tokenId, false)`.\n     */\n    function _burn(uint256 tokenId) internal virtual {\n        _burn(tokenId, false);\n    }\n\n    /**\n     * @dev Destroys `tokenId`.\n     * The approval is cleared when the token is burned.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _burn(uint256 tokenId, bool approvalCheck) internal virtual {\n        uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);\n\n        address from = address(uint160(prevOwnershipPacked));\n\n        (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);\n\n        if (approvalCheck) {\n            // The nested ifs save around 20+ gas over a compound boolean condition.\n            if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))\n                if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();\n        }\n\n        _beforeTokenTransfers(from, address(0), tokenId, 1);\n\n        // Clear approvals from the previous owner.\n        assembly {\n            if approvedAddress {\n                // This is equivalent to `delete _tokenApprovals[tokenId]`.\n                sstore(approvedAddressSlot, 0)\n            }\n        }\n\n        // Underflow of the sender's balance is impossible because we check for\n        // ownership above and the recipient's balance can't realistically overflow.\n        // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.\n        unchecked {\n            // Updates:\n            // - `balance -= 1`.\n            // - `numberBurned += 1`.\n            //\n            // We can directly decrement the balance, and increment the number burned.\n            // This is equivalent to `packed -= 1; packed += 1 << _BITPOS_NUMBER_BURNED;`.\n            _packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1;\n\n            // Updates:\n            // - `address` to the last owner.\n            // - `startTimestamp` to the timestamp of burning.\n            // - `burned` to `true`.\n            // - `nextInitialized` to `true`.\n            _packedOwnerships[tokenId] = _packOwnershipData(\n                from,\n                (_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked)\n            );\n\n            // If the next slot may not have been initialized (i.e. `nextInitialized == false`) .\n            if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {\n                uint256 nextTokenId = tokenId + 1;\n                // If the next slot's address is zero and not burned (i.e. packed value is zero).\n                if (_packedOwnerships[nextTokenId] == 0) {\n                    // If the next slot is within bounds.\n                    if (nextTokenId != _currentIndex) {\n                        // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.\n                        _packedOwnerships[nextTokenId] = prevOwnershipPacked;\n                    }\n                }\n            }\n        }\n\n        emit Transfer(from, address(0), tokenId);\n        _afterTokenTransfers(from, address(0), tokenId, 1);\n\n        // Overflow not possible, as _burnCounter cannot be exceed _currentIndex times.\n        unchecked {\n            _burnCounter++;\n        }\n    }\n\n    // =============================================================\n    //                     EXTRA DATA OPERATIONS\n    // =============================================================\n\n    /**\n     * @dev Directly sets the extra data for the ownership data `index`.\n     */\n    function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual {\n        uint256 packed = _packedOwnerships[index];\n        if (packed == 0) revert OwnershipNotInitializedForExtraData();\n        uint256 extraDataCasted;\n        // Cast `extraData` with assembly to avoid redundant masking.\n        assembly {\n            extraDataCasted := extraData\n        }\n        packed = (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << _BITPOS_EXTRA_DATA);\n        _packedOwnerships[index] = packed;\n    }\n\n    /**\n     * @dev Called during each token transfer to set the 24bit `extraData` field.\n     * Intended to be overridden by the cosumer contract.\n     *\n     * `previousExtraData` - the value of `extraData` before transfer.\n     *\n     * Calling conditions:\n     *\n     * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be\n     * transferred to `to`.\n     * - When `from` is zero, `tokenId` will be minted for `to`.\n     * - When `to` is zero, `tokenId` will be burned by `from`.\n     * - `from` and `to` are never both zero.\n     */\n    function _extraData(\n        address from,\n        address to,\n        uint24 previousExtraData\n    ) internal view virtual returns (uint24) {}\n\n    /**\n     * @dev Returns the next extra data for the packed ownership data.\n     * The returned result is shifted into position.\n     */\n    function _nextExtraData(\n        address from,\n        address to,\n        uint256 prevOwnershipPacked\n    ) private view returns (uint256) {\n        uint24 extraData = uint24(prevOwnershipPacked >> _BITPOS_EXTRA_DATA);\n        return uint256(_extraData(from, to, extraData)) << _BITPOS_EXTRA_DATA;\n    }\n\n    // =============================================================\n    //                       OTHER OPERATIONS\n    // =============================================================\n\n    /**\n     * @dev Returns the message sender (defaults to `msg.sender`).\n     *\n     * If you are writing GSN compatible contracts, you need to override this function.\n     */\n    function _msgSenderERC721A() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    /**\n     * @dev Converts a uint256 to its ASCII string decimal representation.\n     */\n    function _toString(uint256 value) internal pure virtual returns (string memory str) {\n        assembly {\n            // The maximum value of a uint256 contains 78 digits (1 byte per digit), but\n            // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.\n            // We will need 1 word for the trailing zeros padding, 1 word for the length,\n            // and 3 words for a maximum of 78 digits. Total: 5 * 0x20 = 0xa0.\n            let m := add(mload(0x40), 0xa0)\n            // Update the free memory pointer to allocate.\n            mstore(0x40, m)\n            // Assign the `str` to the end.\n            str := sub(m, 0x20)\n            // Zeroize the slot after the string.\n            mstore(str, 0)\n\n            // Cache the end of the memory to calculate the length later.\n            let end := str\n\n            // We write the string from rightmost digit to leftmost digit.\n            // The following is essentially a do-while loop that also handles the zero case.\n            // prettier-ignore\n            for { let temp := value } 1 {} {\n                str := sub(str, 1)\n                // Write the character to the pointer.\n                // The ASCII index of the '0' character is 48.\n                mstore8(str, add(48, mod(temp, 10)))\n                // Keep dividing `temp` until zero.\n                temp := div(temp, 10)\n                // prettier-ignore\n                if iszero(temp) { break }\n            }\n\n            let length := sub(end, str)\n            // Move the pointer 32 bytes leftwards to make room for the length.\n            str := sub(str, 0x20)\n            // Store the length.\n            mstore(str, length)\n        }\n    }\n}\n"
    },
    "erc721a/contracts/extensions/ERC4907A.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// ERC721A Contracts v4.2.3\n// Creator: Chiru Labs\n\npragma solidity ^0.8.4;\n\nimport './IERC4907A.sol';\nimport '../ERC721A.sol';\n\n/**\n * @title ERC4907A\n *\n * @dev [ERC4907](https://eips.ethereum.org/EIPS/eip-4907) compliant\n * extension of ERC721A, which allows owners and authorized addresses\n * to add a time-limited role with restricted permissions to ERC721 tokens.\n */\nabstract contract ERC4907A is ERC721A, IERC4907A {\n    // The bit position of `expires` in packed user info.\n    uint256 private constant _BITPOS_EXPIRES = 160;\n\n    // Mapping from token ID to user info.\n    //\n    // Bits Layout:\n    // - [0..159]   `user`\n    // - [160..223] `expires`\n    mapping(uint256 => uint256) private _packedUserInfo;\n\n    /**\n     * @dev Sets the `user` and `expires` for `tokenId`.\n     * The zero address indicates there is no user.\n     *\n     * Requirements:\n     *\n     * - The caller must own `tokenId` or be an approved operator.\n     */\n    function setUser(\n        uint256 tokenId,\n        address user,\n        uint64 expires\n    ) public virtual override {\n        // Require the caller to be either the token owner or an approved operator.\n        address owner = ownerOf(tokenId);\n        if (_msgSenderERC721A() != owner)\n            if (!isApprovedForAll(owner, _msgSenderERC721A()))\n                if (getApproved(tokenId) != _msgSenderERC721A()) revert SetUserCallerNotOwnerNorApproved();\n\n        _packedUserInfo[tokenId] = (uint256(expires) << _BITPOS_EXPIRES) | uint256(uint160(user));\n\n        emit UpdateUser(tokenId, user, expires);\n    }\n\n    /**\n     * @dev Returns the user address for `tokenId`.\n     * The zero address indicates that there is no user or if the user is expired.\n     */\n    function userOf(uint256 tokenId) public view virtual override returns (address) {\n        uint256 packed = _packedUserInfo[tokenId];\n        assembly {\n            // Branchless `packed *= (block.timestamp <= expires ? 1 : 0)`.\n            // If the `block.timestamp == expires`, the `lt` clause will be true\n            // if there is a non-zero user address in the lower 160 bits of `packed`.\n            packed := mul(\n                packed,\n                // `block.timestamp <= expires ? 1 : 0`.\n                lt(shl(_BITPOS_EXPIRES, timestamp()), packed)\n            )\n        }\n        return address(uint160(packed));\n    }\n\n    /**\n     * @dev Returns the user's expires of `tokenId`.\n     */\n    function userExpires(uint256 tokenId) public view virtual override returns (uint256) {\n        return _packedUserInfo[tokenId] >> _BITPOS_EXPIRES;\n    }\n\n    /**\n     * @dev Override of {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721A, IERC721A) returns (bool) {\n        // The interface ID for ERC4907 is `0xad092b5c`,\n        // as defined in [ERC4907](https://eips.ethereum.org/EIPS/eip-4907).\n        return super.supportsInterface(interfaceId) || interfaceId == 0xad092b5c;\n    }\n\n    /**\n     * @dev Returns the user address for `tokenId`, ignoring the expiry status.\n     */\n    function _explicitUserOf(uint256 tokenId) internal view virtual returns (address) {\n        return address(uint160(_packedUserInfo[tokenId]));\n    }\n}\n"
    },
    "contracts/ERC4907.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport { IERC721A } from \"erc721a/contracts/IERC721A.sol\";\nimport { ERC721A } from \"erc721a/contracts/ERC721A.sol\";\nimport { ERC4907A } from \"erc721a/contracts/extensions/ERC4907A.sol\";\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\n\ninterface IERC721Metadata {\n    function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n\ncontract ERC4907 is ERC4907A, Ownable {\n\n    struct AssetInfo {\n        address tokenAddress;\n        uint256 tokenId;\n    }\n\n    mapping(uint256 => AssetInfo) internal _assets;\n\n    constructor() ERC721A(\"BNPL\", \"BNPL\") {}\n    \n    function mint(address to, address tokenAddress, uint256 tokenId)\n        external\n        onlyOwner\n        returns (uint256 tid)\n    {\n        _mint(to, 1);\n        tid = _nextTokenId() - 1;\n        _assets[tid] = AssetInfo(tokenAddress, tokenId);\n    }\n\n    function burn(uint256 tokenId) external onlyOwner {\n        setUser(tokenId, address(0), 0);\n        _burn(tokenId);\n    }\n\n    function tokenURI(uint256 tokenId)\n        public\n        view\n        override (ERC721A, IERC721A)\n        returns (string memory)\n    {\n        AssetInfo memory asset = _assets[tokenId];\n        try IERC721Metadata(asset.tokenAddress).tokenURI(asset.tokenId) returns (string memory uri) {\n            return uri;\n        } catch {\n            return super.tokenURI(tokenId);\n        }\n    }\n}"
    },
    "@openzeppelin/contracts/access/Ownable.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n"
    },
    "@openzeppelin/contracts/utils/Context.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n}\n"
    },
    "@openzeppelin/contracts/token/ERC721/ERC721.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/ERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC721.sol\";\nimport \"./IERC721Receiver.sol\";\nimport \"./extensions/IERC721Metadata.sol\";\nimport \"../../utils/Address.sol\";\nimport \"../../utils/Context.sol\";\nimport \"../../utils/Strings.sol\";\nimport \"../../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including\n * the Metadata extension, but not including the Enumerable extension, which is available separately as\n * {ERC721Enumerable}.\n */\ncontract ERC721 is Context, ERC165, IERC721, IERC721Metadata {\n    using Address for address;\n    using Strings for uint256;\n\n    // Token name\n    string private _name;\n\n    // Token symbol\n    string private _symbol;\n\n    // Mapping from token ID to owner address\n    mapping(uint256 => address) private _owners;\n\n    // Mapping owner address to token count\n    mapping(address => uint256) private _balances;\n\n    // Mapping from token ID to approved address\n    mapping(uint256 => address) private _tokenApprovals;\n\n    // Mapping from owner to operator approvals\n    mapping(address => mapping(address => bool)) private _operatorApprovals;\n\n    /**\n     * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.\n     */\n    constructor(string memory name_, string memory symbol_) {\n        _name = name_;\n        _symbol = symbol_;\n    }\n\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {\n        return\n            interfaceId == type(IERC721).interfaceId ||\n            interfaceId == type(IERC721Metadata).interfaceId ||\n            super.supportsInterface(interfaceId);\n    }\n\n    /**\n     * @dev See {IERC721-balanceOf}.\n     */\n    function balanceOf(address owner) public view virtual override returns (uint256) {\n        require(owner != address(0), \"ERC721: address zero is not a valid owner\");\n        return _balances[owner];\n    }\n\n    /**\n     * @dev See {IERC721-ownerOf}.\n     */\n    function ownerOf(uint256 tokenId) public view virtual override returns (address) {\n        address owner = _owners[tokenId];\n        require(owner != address(0), \"ERC721: invalid token ID\");\n        return owner;\n    }\n\n    /**\n     * @dev See {IERC721Metadata-name}.\n     */\n    function name() public view virtual override returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @dev See {IERC721Metadata-symbol}.\n     */\n    function symbol() public view virtual override returns (string memory) {\n        return _symbol;\n    }\n\n    /**\n     * @dev See {IERC721Metadata-tokenURI}.\n     */\n    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {\n        _requireMinted(tokenId);\n\n        string memory baseURI = _baseURI();\n        return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : \"\";\n    }\n\n    /**\n     * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each\n     * token will be the concatenation of the `baseURI` and the `tokenId`. Empty\n     * by default, can be overridden in child contracts.\n     */\n    function _baseURI() internal view virtual returns (string memory) {\n        return \"\";\n    }\n\n    /**\n     * @dev See {IERC721-approve}.\n     */\n    function approve(address to, uint256 tokenId) public virtual override {\n        address owner = ERC721.ownerOf(tokenId);\n        require(to != owner, \"ERC721: approval to current owner\");\n\n        require(\n            _msgSender() == owner || isApprovedForAll(owner, _msgSender()),\n            \"ERC721: approve caller is not token owner nor approved for all\"\n        );\n\n        _approve(to, tokenId);\n    }\n\n    /**\n     * @dev See {IERC721-getApproved}.\n     */\n    function getApproved(uint256 tokenId) public view virtual override returns (address) {\n        _requireMinted(tokenId);\n\n        return _tokenApprovals[tokenId];\n    }\n\n    /**\n     * @dev See {IERC721-setApprovalForAll}.\n     */\n    function setApprovalForAll(address operator, bool approved) public virtual override {\n        _setApprovalForAll(_msgSender(), operator, approved);\n    }\n\n    /**\n     * @dev See {IERC721-isApprovedForAll}.\n     */\n    function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {\n        return _operatorApprovals[owner][operator];\n    }\n\n    /**\n     * @dev See {IERC721-transferFrom}.\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) public virtual override {\n        //solhint-disable-next-line max-line-length\n        require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: caller is not token owner nor approved\");\n\n        _transfer(from, to, tokenId);\n    }\n\n    /**\n     * @dev See {IERC721-safeTransferFrom}.\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) public virtual override {\n        safeTransferFrom(from, to, tokenId, \"\");\n    }\n\n    /**\n     * @dev See {IERC721-safeTransferFrom}.\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId,\n        bytes memory data\n    ) public virtual override {\n        require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: caller is not token owner nor approved\");\n        _safeTransfer(from, to, tokenId, data);\n    }\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n     * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n     *\n     * `data` is additional data, it has no specified format and it is sent in call to `to`.\n     *\n     * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.\n     * implement alternative mechanisms to perform token transfer, such as signature-based.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _safeTransfer(\n        address from,\n        address to,\n        uint256 tokenId,\n        bytes memory data\n    ) internal virtual {\n        _transfer(from, to, tokenId);\n        require(_checkOnERC721Received(from, to, tokenId, data), \"ERC721: transfer to non ERC721Receiver implementer\");\n    }\n\n    /**\n     * @dev Returns whether `tokenId` exists.\n     *\n     * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.\n     *\n     * Tokens start existing when they are minted (`_mint`),\n     * and stop existing when they are burned (`_burn`).\n     */\n    function _exists(uint256 tokenId) internal view virtual returns (bool) {\n        return _owners[tokenId] != address(0);\n    }\n\n    /**\n     * @dev Returns whether `spender` is allowed to manage `tokenId`.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {\n        address owner = ERC721.ownerOf(tokenId);\n        return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);\n    }\n\n    /**\n     * @dev Safely mints `tokenId` and transfers it to `to`.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must not exist.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _safeMint(address to, uint256 tokenId) internal virtual {\n        _safeMint(to, tokenId, \"\");\n    }\n\n    /**\n     * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is\n     * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.\n     */\n    function _safeMint(\n        address to,\n        uint256 tokenId,\n        bytes memory data\n    ) internal virtual {\n        _mint(to, tokenId);\n        require(\n            _checkOnERC721Received(address(0), to, tokenId, data),\n            \"ERC721: transfer to non ERC721Receiver implementer\"\n        );\n    }\n\n    /**\n     * @dev Mints `tokenId` and transfers it to `to`.\n     *\n     * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible\n     *\n     * Requirements:\n     *\n     * - `tokenId` must not exist.\n     * - `to` cannot be the zero address.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _mint(address to, uint256 tokenId) internal virtual {\n        require(to != address(0), \"ERC721: mint to the zero address\");\n        require(!_exists(tokenId), \"ERC721: token already minted\");\n\n        _beforeTokenTransfer(address(0), to, tokenId);\n\n        _balances[to] += 1;\n        _owners[tokenId] = to;\n\n        emit Transfer(address(0), to, tokenId);\n\n        _afterTokenTransfer(address(0), to, tokenId);\n    }\n\n    /**\n     * @dev Destroys `tokenId`.\n     * The approval is cleared when the token is burned.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _burn(uint256 tokenId) internal virtual {\n        address owner = ERC721.ownerOf(tokenId);\n\n        _beforeTokenTransfer(owner, address(0), tokenId);\n\n        // Clear approvals\n        _approve(address(0), tokenId);\n\n        _balances[owner] -= 1;\n        delete _owners[tokenId];\n\n        emit Transfer(owner, address(0), tokenId);\n\n        _afterTokenTransfer(owner, address(0), tokenId);\n    }\n\n    /**\n     * @dev Transfers `tokenId` from `from` to `to`.\n     *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must be owned by `from`.\n     *\n     * Emits a {Transfer} event.\n     */\n    function _transfer(\n        address from,\n        address to,\n        uint256 tokenId\n    ) internal virtual {\n        require(ERC721.ownerOf(tokenId) == from, \"ERC721: transfer from incorrect owner\");\n        require(to != address(0), \"ERC721: transfer to the zero address\");\n\n        _beforeTokenTransfer(from, to, tokenId);\n\n        // Clear approvals from the previous owner\n        _approve(address(0), tokenId);\n\n        _balances[from] -= 1;\n        _balances[to] += 1;\n        _owners[tokenId] = to;\n\n        emit Transfer(from, to, tokenId);\n\n        _afterTokenTransfer(from, to, tokenId);\n    }\n\n    /**\n     * @dev Approve `to` to operate on `tokenId`\n     *\n     * Emits an {Approval} event.\n     */\n    function _approve(address to, uint256 tokenId) internal virtual {\n        _tokenApprovals[tokenId] = to;\n        emit Approval(ERC721.ownerOf(tokenId), to, tokenId);\n    }\n\n    /**\n     * @dev Approve `operator` to operate on all of `owner` tokens\n     *\n     * Emits an {ApprovalForAll} event.\n     */\n    function _setApprovalForAll(\n        address owner,\n        address operator,\n        bool approved\n    ) internal virtual {\n        require(owner != operator, \"ERC721: approve to caller\");\n        _operatorApprovals[owner][operator] = approved;\n        emit ApprovalForAll(owner, operator, approved);\n    }\n\n    /**\n     * @dev Reverts if the `tokenId` has not been minted yet.\n     */\n    function _requireMinted(uint256 tokenId) internal view virtual {\n        require(_exists(tokenId), \"ERC721: invalid token ID\");\n    }\n\n    /**\n     * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.\n     * The call is not executed if the target address is not a contract.\n     *\n     * @param from address representing the previous owner of the given token ID\n     * @param to target address that will receive the tokens\n     * @param tokenId uint256 ID of the token to be transferred\n     * @param data bytes optional data to send along with the call\n     * @return bool whether the call correctly returned the expected magic value\n     */\n    function _checkOnERC721Received(\n        address from,\n        address to,\n        uint256 tokenId,\n        bytes memory data\n    ) private returns (bool) {\n        if (to.isContract()) {\n            try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {\n                return retval == IERC721Receiver.onERC721Received.selector;\n            } catch (bytes memory reason) {\n                if (reason.length == 0) {\n                    revert(\"ERC721: transfer to non ERC721Receiver implementer\");\n                } else {\n                    /// @solidity memory-safe-assembly\n                    assembly {\n                        revert(add(32, reason), mload(reason))\n                    }\n                }\n            }\n        } else {\n            return true;\n        }\n    }\n\n    /**\n     * @dev Hook that is called before any token transfer. This includes minting\n     * and burning.\n     *\n     * Calling conditions:\n     *\n     * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be\n     * transferred to `to`.\n     * - When `from` is zero, `tokenId` will be minted for `to`.\n     * - When `to` is zero, ``from``'s `tokenId` will be burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _beforeTokenTransfer(\n        address from,\n        address to,\n        uint256 tokenId\n    ) internal virtual {}\n\n    /**\n     * @dev Hook that is called after any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _afterTokenTransfer(\n        address from,\n        address to,\n        uint256 tokenId\n    ) internal virtual {}\n}\n"
    },
    "@openzeppelin/contracts/utils/Address.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length > 0;\n    }\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason, it is bubbled up by this\n     * function (like regular Solidity function calls).\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length > 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n                /// @solidity memory-safe-assembly\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n"
    },
    "@openzeppelin/contracts/utils/Strings.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp >>= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i > 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value & 0xf];\n            value >>= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n"
    },
    "@openzeppelin/contracts/token/ERC721/IERC721.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721 is IERC165 {\n    /**\n     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n     */\n    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n    /**\n     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n     */\n    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n    /**\n     * @dev Returns the number of tokens in ``owner``'s account.\n     */\n    function balanceOf(address owner) external view returns (uint256 balance);\n\n    /**\n     * @dev Returns the owner of the `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function ownerOf(uint256 tokenId) external view returns (address owner);\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId,\n        bytes calldata data\n    ) external;\n\n    /**\n     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n     * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must exist and be owned by `from`.\n     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) external;\n\n    /**\n     * @dev Transfers `tokenId` token from `from` to `to`.\n     *\n     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `tokenId` token must be owned by `from`.\n     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 tokenId\n    ) external;\n\n    /**\n     * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n     * The approval is cleared when the token is transferred.\n     *\n     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n     *\n     * Requirements:\n     *\n     * - The caller must own the token or be an approved operator.\n     * - `tokenId` must exist.\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address to, uint256 tokenId) external;\n\n    /**\n     * @dev Approve or remove `operator` as an operator for the caller.\n     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n     *\n     * Requirements:\n     *\n     * - The `operator` cannot be the caller.\n     *\n     * Emits an {ApprovalForAll} event.\n     */\n    function setApprovalForAll(address operator, bool _approved) external;\n\n    /**\n     * @dev Returns the account approved for `tokenId` token.\n     *\n     * Requirements:\n     *\n     * - `tokenId` must exist.\n     */\n    function getApproved(uint256 tokenId) external view returns (address operator);\n\n    /**\n     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n     *\n     * See {setApprovalForAll}\n     */\n    function isApprovedForAll(address owner, address operator) external view returns (bool);\n}\n"
    },
    "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title ERC721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n * from ERC721 asset contracts.\n */\ninterface IERC721Receiver {\n    /**\n     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}\n     * by `operator` from `from`, this function is called.\n     *\n     * It must return its Solidity selector to confirm the token transfer.\n     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.\n     *\n     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.\n     */\n    function onERC721Received(\n        address operator,\n        address from,\n        uint256 tokenId,\n        bytes calldata data\n    ) external returns (bytes4);\n}\n"
    },
    "@openzeppelin/contracts/utils/introspection/ERC165.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return interfaceId == type(IERC165).interfaceId;\n    }\n}\n"
    },
    "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC721.sol\";\n\n/**\n * @title ERC-721 Non-Fungible Token Standard, optional metadata extension\n * @dev See https://eips.ethereum.org/EIPS/eip-721\n */\ninterface IERC721Metadata is IERC721 {\n    /**\n     * @dev Returns the token collection name.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the token collection symbol.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n     */\n    function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n"
    },
    "@openzeppelin/contracts/utils/introspection/IERC165.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"
    },
    "contracts/test/TestERC721.sol": {
      "content": "// SPDX-License-Identifier: Unlicense\npragma solidity ^0.8.7;\n\nimport \"@openzeppelin/contracts/token/ERC721/ERC721.sol\";\n\n// Used for minting test ERC721s in our tests\ncontract TestERC721 is ERC721(\"Test721\", \"TST721\") {\n    function mint(address to, uint256 tokenId) public returns (bool) {\n        _mint(to, tokenId);\n        return true;\n    }\n\n    function tokenURI(uint256) public pure override returns (string memory) {\n        return \"tokenURI\";\n    }\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/ERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n    mapping(address => uint256) private _balances;\n\n    mapping(address => mapping(address => uint256)) private _allowances;\n\n    uint256 private _totalSupply;\n\n    string private _name;\n    string private _symbol;\n\n    /**\n     * @dev Sets the values for {name} and {symbol}.\n     *\n     * The default value of {decimals} is 18. To select a different value for\n     * {decimals} you should overload it.\n     *\n     * All two of these values are immutable: they can only be set once during\n     * construction.\n     */\n    constructor(string memory name_, string memory symbol_) {\n        _name = name_;\n        _symbol = symbol_;\n    }\n\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() public view virtual override returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @dev Returns the symbol of the token, usually a shorter version of the\n     * name.\n     */\n    function symbol() public view virtual override returns (string memory) {\n        return _symbol;\n    }\n\n    /**\n     * @dev Returns the number of decimals used to get its user representation.\n     * For example, if `decimals` equals `2`, a balance of `505` tokens should\n     * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n     *\n     * Tokens usually opt for a value of 18, imitating the relationship between\n     * Ether and Wei. This is the value {ERC20} uses, unless this function is\n     * overridden;\n     *\n     * NOTE: This information is only used for _display_ purposes: it in\n     * no way affects any of the arithmetic of the contract, including\n     * {IERC20-balanceOf} and {IERC20-transfer}.\n     */\n    function decimals() public view virtual override returns (uint8) {\n        return 18;\n    }\n\n    /**\n     * @dev See {IERC20-totalSupply}.\n     */\n    function totalSupply() public view virtual override returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * @dev See {IERC20-balanceOf}.\n     */\n    function balanceOf(address account) public view virtual override returns (uint256) {\n        return _balances[account];\n    }\n\n    /**\n     * @dev See {IERC20-transfer}.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - the caller must have a balance of at least `amount`.\n     */\n    function transfer(address to, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _transfer(owner, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-allowance}.\n     */\n    function allowance(address owner, address spender) public view virtual override returns (uint256) {\n        return _allowances[owner][spender];\n    }\n\n    /**\n     * @dev See {IERC20-approve}.\n     *\n     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n     * `transferFrom`. This is semantically equivalent to an infinite approval.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function approve(address spender, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-transferFrom}.\n     *\n     * Emits an {Approval} event indicating the updated allowance. This is not\n     * required by the EIP. See the note at the beginning of {ERC20}.\n     *\n     * NOTE: Does not update the allowance if the current allowance\n     * is the maximum `uint256`.\n     *\n     * Requirements:\n     *\n     * - `from` and `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     * - the caller must have allowance for ``from``'s tokens of at least\n     * `amount`.\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 amount\n    ) public virtual override returns (bool) {\n        address spender = _msgSender();\n        _spendAllowance(from, spender, amount);\n        _transfer(from, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev Atomically increases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, allowance(owner, spender) + addedValue);\n        return true;\n    }\n\n    /**\n     * @dev Atomically decreases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `spender` must have allowance for the caller of at least\n     * `subtractedValue`.\n     */\n    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        uint256 currentAllowance = allowance(owner, spender);\n        require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n        unchecked {\n            _approve(owner, spender, currentAllowance - subtractedValue);\n        }\n\n        return true;\n    }\n\n    /**\n     * @dev Moves `amount` of tokens from `from` to `to`.\n     *\n     * This internal function is equivalent to {transfer}, and can be used to\n     * e.g. implement automatic token fees, slashing mechanisms, etc.\n     *\n     * Emits a {Transfer} event.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     */\n    function _transfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual {\n        require(from != address(0), \"ERC20: transfer from the zero address\");\n        require(to != address(0), \"ERC20: transfer to the zero address\");\n\n        _beforeTokenTransfer(from, to, amount);\n\n        uint256 fromBalance = _balances[from];\n        require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n        unchecked {\n            _balances[from] = fromBalance - amount;\n        }\n        _balances[to] += amount;\n\n        emit Transfer(from, to, amount);\n\n        _afterTokenTransfer(from, to, amount);\n    }\n\n    /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n     * the total supply.\n     *\n     * Emits a {Transfer} event with `from` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     */\n    function _mint(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: mint to the zero address\");\n\n        _beforeTokenTransfer(address(0), account, amount);\n\n        _totalSupply += amount;\n        _balances[account] += amount;\n        emit Transfer(address(0), account, amount);\n\n        _afterTokenTransfer(address(0), account, amount);\n    }\n\n    /**\n     * @dev Destroys `amount` tokens from `account`, reducing the\n     * total supply.\n     *\n     * Emits a {Transfer} event with `to` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     * - `account` must have at least `amount` tokens.\n     */\n    function _burn(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: burn from the zero address\");\n\n        _beforeTokenTransfer(account, address(0), amount);\n\n        uint256 accountBalance = _balances[account];\n        require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n        unchecked {\n            _balances[account] = accountBalance - amount;\n        }\n        _totalSupply -= amount;\n\n        emit Transfer(account, address(0), amount);\n\n        _afterTokenTransfer(account, address(0), amount);\n    }\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n     *\n     * This internal function is equivalent to `approve`, and can be used to\n     * e.g. set automatic allowances for certain subsystems, etc.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     */\n    function _approve(\n        address owner,\n        address spender,\n        uint256 amount\n    ) internal virtual {\n        require(owner != address(0), \"ERC20: approve from the zero address\");\n        require(spender != address(0), \"ERC20: approve to the zero address\");\n\n        _allowances[owner][spender] = amount;\n        emit Approval(owner, spender, amount);\n    }\n\n    /**\n     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n     *\n     * Does not update the allowance amount in case of infinite allowance.\n     * Revert if not enough allowance is available.\n     *\n     * Might emit an {Approval} event.\n     */\n    function _spendAllowance(\n        address owner,\n        address spender,\n        uint256 amount\n    ) internal virtual {\n        uint256 currentAllowance = allowance(owner, spender);\n        if (currentAllowance != type(uint256).max) {\n            require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n            unchecked {\n                _approve(owner, spender, currentAllowance - amount);\n            }\n        }\n    }\n\n    /**\n     * @dev Hook that is called before any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * will be transferred to `to`.\n     * - when `from` is zero, `amount` tokens will be minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _beforeTokenTransfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual {}\n\n    /**\n     * @dev Hook that is called after any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * has been transferred to `to`.\n     * - when `from` is zero, `amount` tokens have been minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _afterTokenTransfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual {}\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 amount\n    ) external returns (bool);\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"
    },
    "contracts/test/TestERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\n\ncontract TestERC20 is ERC20 {\n\n    constructor() ERC20(\"TestERC20\", \"TestERC20\") {}\n\n    function mint(address recipient, uint256 amount) external {\n        require(amount != 0, \"amount == 0\");\n        _mint(recipient, amount);\n    }\n\n    function burn(uint256 amount) external {\n        _burn(_msgSender(), amount);\n    }\n}"
    },
    "contracts/helper/GenericERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\ncontract GenericERC20 is ERC20, Ownable {\n\n    constructor(\n        string memory name_,\n        string memory symbol_\n    ) ERC20(name_, symbol_) {}\n\n    function mint(address recipient, uint256 amount) external onlyOwner {\n        require(amount != 0, \"amount == 0\");\n        _mint(recipient, amount);\n    }\n\n    function burn(uint256 amount) external {\n        _burn(_msgSender(), amount);\n    }\n}"
    },
    "contracts/conduit/ConduitController.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.7;\n\nimport {\n    ConduitControllerInterface\n} from \"../interfaces/ConduitControllerInterface.sol\";\n\nimport { ConduitInterface } from \"../interfaces/ConduitInterface.sol\";\n\nimport { Conduit } from \"./Conduit.sol\";\n\n/**\n * @title ConduitController\n * @author 0age\n * @notice ConduitController enables deploying and managing new conduits, or\n *         contracts that allow registered callers (or open \"channels\") to\n *         transfer approved ERC20/721/1155 tokens on their behalf.\n */\ncontract ConduitController is ConduitControllerInterface {\n    // Register keys, owners, new potential owners, and channels by conduit.\n    mapping(address => ConduitProperties) internal _conduits;\n\n    // Set conduit creation code and runtime code hashes as immutable arguments.\n    bytes32 internal immutable _CONDUIT_CREATION_CODE_HASH;\n    bytes32 internal immutable _CONDUIT_RUNTIME_CODE_HASH;\n\n    /**\n     * @dev Initialize contract by deploying a conduit and setting the creation\n     *      code and runtime code hashes as immutable arguments.\n     */\n    constructor() {\n        // Derive the conduit creation code hash and set it as an immutable.\n        _CONDUIT_CREATION_CODE_HASH = keccak256(type(Conduit).creationCode);\n\n        // Deploy a conduit with the zero hash as the salt.\n        Conduit zeroConduit = new Conduit{ salt: bytes32(0) }();\n\n        // Retrieve the conduit runtime code hash and set it as an immutable.\n        _CONDUIT_RUNTIME_CODE_HASH = address(zeroConduit).codehash;\n    }\n\n    /**\n     * @notice Deploy a new conduit using a supplied conduit key and assigning\n     *         an initial owner for the deployed conduit. Note that the first\n     *         twenty bytes of the supplied conduit key must match the caller\n     *         and that a new conduit cannot be created if one has already been\n     *         deployed using the same conduit key.\n     *\n     * @param conduitKey   The conduit key used to deploy the conduit. Note that\n     *                     the first twenty bytes of the conduit key must match\n     *                     the caller of this contract.\n     * @param initialOwner The initial owner to set for the new conduit.\n     *\n     * @return conduit The address of the newly deployed conduit.\n     */\n    function createConduit(bytes32 conduitKey, address initialOwner)\n        external\n        override\n        returns (address conduit)\n    {\n        // Ensure that an initial owner has been supplied.\n        if (initialOwner == address(0)) {\n            revert InvalidInitialOwner();\n        }\n\n        // If the first 20 bytes of the conduit key do not match the caller...\n        if (address(uint160(bytes20(conduitKey))) != msg.sender) {\n            // Revert with an error indicating that the creator is invalid.\n            revert InvalidCreator();\n        }\n\n        // Derive address from deployer, conduit key and creation code hash.\n        conduit = address(\n            uint160(\n                uint256(\n                    keccak256(\n                        abi.encodePacked(\n                            bytes1(0xff),\n                            address(this),\n                            conduitKey,\n                            _CONDUIT_CREATION_CODE_HASH\n                        )\n                    )\n                )\n            )\n        );\n\n        // If derived conduit exists, as evidenced by comparing runtime code...\n        if (conduit.codehash == _CONDUIT_RUNTIME_CODE_HASH) {\n            // Revert with an error indicating that the conduit already exists.\n            revert ConduitAlreadyExists(conduit);\n        }\n\n        // Deploy the conduit via CREATE2 using the conduit key as the salt.\n        new Conduit{ salt: conduitKey }();\n\n        // Initialize storage variable referencing conduit properties.\n        ConduitProperties storage conduitProperties = _conduits[conduit];\n\n        // Set the supplied initial owner as the owner of the conduit.\n        conduitProperties.owner = initialOwner;\n\n        // Set conduit key used to deploy the conduit to enable reverse lookup.\n        conduitProperties.key = conduitKey;\n\n        // Emit an event indicating that the conduit has been deployed.\n        emit NewConduit(conduit, conduitKey);\n\n        // Emit an event indicating that conduit ownership has been assigned.\n        emit OwnershipTransferred(conduit, address(0), initialOwner);\n    }\n\n    /**\n     * @notice Open or close a channel on a given conduit, thereby allowing the\n     *         specified account to execute transfers against that conduit.\n     *         Extreme care must be taken when updating channels, as malicious\n     *         or vulnerable channels can transfer any ERC20, ERC721 and ERC1155\n     *         tokens where the token holder has granted the conduit approval.\n     *         Only the owner of the conduit in question may call this function.\n     *\n     * @param conduit The conduit for which to open or close the channel.\n     * @param channel The channel to open or close on the conduit.\n     * @param isOpen  A boolean indicating whether to open or close the channel.\n     */\n    function updateChannel(\n        address conduit,\n        address channel,\n        bool isOpen\n    ) external override {\n        // Ensure the caller is the current owner of the conduit in question.\n        _assertCallerIsConduitOwner(conduit);\n\n        // Call the conduit, updating the channel.\n        ConduitInterface(conduit).updateChannel(channel, isOpen);\n\n        // Retrieve storage region where channels for the conduit are tracked.\n        ConduitProperties storage conduitProperties = _conduits[conduit];\n\n        // Retrieve the index, if one currently exists, for the updated channel.\n        uint256 channelIndexPlusOne = (\n            conduitProperties.channelIndexesPlusOne[channel]\n        );\n\n        // Determine whether the updated channel is already tracked as open.\n        bool channelPreviouslyOpen = channelIndexPlusOne != 0;\n\n        // If the channel has been set to open and was previously closed...\n        if (isOpen && !channelPreviouslyOpen) {\n            // Add the channel to the channels array for the conduit.\n            conduitProperties.channels.push(channel);\n\n            // Add new open channel length to associated mapping as index + 1.\n            conduitProperties.channelIndexesPlusOne[channel] = (\n                conduitProperties.channels.length\n            );\n        } else if (!isOpen && channelPreviouslyOpen) {\n            // Set a previously open channel as closed via \"swap & pop\" method.\n            // Decrement located index to get the index of the closed channel.\n            uint256 removedChannelIndex;\n\n            // Skip underflow check as channelPreviouslyOpen being true ensures\n            // that channelIndexPlusOne is nonzero.\n            unchecked {\n                removedChannelIndex = channelIndexPlusOne - 1;\n            }\n\n            // Use length of channels array to determine index of last channel.\n            uint256 finalChannelIndex = conduitProperties.channels.length - 1;\n\n            // If closed channel is not last channel in the channels array...\n            if (finalChannelIndex != removedChannelIndex) {\n                // Retrieve the final channel and place the value on the stack.\n                address finalChannel = (\n                    conduitProperties.channels[finalChannelIndex]\n                );\n\n                // Overwrite the removed channel using the final channel value.\n                conduitProperties.channels[removedChannelIndex] = finalChannel;\n\n                // Update final index in associated mapping to removed index.\n                conduitProperties.channelIndexesPlusOne[finalChannel] = (\n                    channelIndexPlusOne\n                );\n            }\n\n            // Remove the last channel from the channels array for the conduit.\n            conduitProperties.channels.pop();\n\n            // Remove the closed channel from associated mapping of indexes.\n            delete conduitProperties.channelIndexesPlusOne[channel];\n        }\n    }\n\n    /**\n     * @notice Initiate conduit ownership transfer by assigning a new potential\n     *         owner for the given conduit. Once set, the new potential owner\n     *         may call `acceptOwnership` to claim ownership of the conduit.\n     *         Only the owner of the conduit in question may call this function.\n     *\n     * @param conduit The conduit for which to initiate ownership transfer.\n     * @param newPotentialOwner The new potential owner of the conduit.\n     */\n    function transferOwnership(address conduit, address newPotentialOwner)\n        external\n        override\n    {\n        // Ensure the caller is the current owner of the conduit in question.\n        _assertCallerIsConduitOwner(conduit);\n\n        // Ensure the new potential owner is not an invalid address.\n        if (newPotentialOwner == address(0)) {\n            revert NewPotentialOwnerIsZeroAddress(conduit);\n        }\n\n        // Ensure the new potential owner is not already set.\n        if (newPotentialOwner == _conduits[conduit].potentialOwner) {\n            revert NewPotentialOwnerAlreadySet(conduit, newPotentialOwner);\n        }\n\n        // Emit an event indicating that the potential owner has been updated.\n        emit PotentialOwnerUpdated(newPotentialOwner);\n\n        // Set the new potential owner as the potential owner of the conduit.\n        _conduits[conduit].potentialOwner = newPotentialOwner;\n    }\n\n    /**\n     * @notice Clear the currently set potential owner, if any, from a conduit.\n     *         Only the owner of the conduit in question may call this function.\n     *\n     * @param conduit The conduit for which to cancel ownership transfer.\n     */\n    function cancelOwnershipTransfer(address conduit) external override {\n        // Ensure the caller is the current owner of the conduit in question.\n        _assertCallerIsConduitOwner(conduit);\n\n        // Ensure that ownership transfer is currently possible.\n        if (_conduits[conduit].potentialOwner == address(0)) {\n            revert NoPotentialOwnerCurrentlySet(conduit);\n        }\n\n        // Emit an event indicating that the potential owner has been cleared.\n        emit PotentialOwnerUpdated(address(0));\n\n        // Clear the current new potential owner from the conduit.\n        _conduits[conduit].potentialOwner = address(0);\n    }\n\n    /**\n     * @notice Accept ownership of a supplied conduit. Only accounts that the\n     *         current owner has set as the new potential owner may call this\n     *         function.\n     *\n     * @param conduit The conduit for which to accept ownership.\n     */\n    function acceptOwnership(address conduit) external override {\n        // Ensure that the conduit in question exists.\n        _assertConduitExists(conduit);\n\n        // If caller does not match current potential owner of the conduit...\n        if (msg.sender != _conduits[conduit].potentialOwner) {\n            // Revert, indicating that caller is not current potential owner.\n            revert CallerIsNotNewPotentialOwner(conduit);\n        }\n\n        // Emit an event indicating that the potential owner has been cleared.\n        emit PotentialOwnerUpdated(address(0));\n\n        // Clear the current new potential owner from the conduit.\n        _conduits[conduit].potentialOwner = address(0);\n\n        // Emit an event indicating conduit ownership has been transferred.\n        emit OwnershipTransferred(\n            conduit,\n            _conduits[conduit].owner,\n            msg.sender\n        );\n\n        // Set the caller as the owner of the conduit.\n        _conduits[conduit].owner = msg.sender;\n    }\n\n    /**\n     * @notice Retrieve the current owner of a deployed conduit.\n     *\n     * @param conduit The conduit for which to retrieve the associated owner.\n     *\n     * @return owner The owner of the supplied conduit.\n     */\n    function ownerOf(address conduit)\n        external\n        view\n        override\n        returns (address owner)\n    {\n        // Ensure that the conduit in question exists.\n        _assertConduitExists(conduit);\n\n        // Retrieve the current owner of the conduit in question.\n        owner = _conduits[conduit].owner;\n    }\n\n    /**\n     * @notice Retrieve the conduit key for a deployed conduit via reverse\n     *         lookup.\n     *\n     * @param conduit The conduit for which to retrieve the associated conduit\n     *                key.\n     *\n     * @return conduitKey The conduit key used to deploy the supplied conduit.\n     */\n    function getKey(address conduit)\n        external\n        view\n        override\n        returns (bytes32 conduitKey)\n    {\n        // Attempt to retrieve a conduit key for the conduit in question.\n        conduitKey = _conduits[conduit].key;\n\n        // Revert if no conduit key was located.\n        if (conduitKey == bytes32(0)) {\n            revert NoConduit();\n        }\n    }\n\n    /**\n     * @notice Derive the conduit associated with a given conduit key and\n     *         determine whether that conduit exists (i.e. whether it has been\n     *         deployed).\n     *\n     * @param conduitKey The conduit key used to derive the conduit.\n     *\n     * @return conduit The derived address of the conduit.\n     * @return exists  A boolean indicating whether the derived conduit has been\n     *                 deployed or not.\n     */\n    function getConduit(bytes32 conduitKey)\n        external\n        view\n        override\n        returns (address conduit, bool exists)\n    {\n        // Derive address from deployer, conduit key and creation code hash.\n        conduit = address(\n            uint160(\n                uint256(\n                    keccak256(\n                        abi.encodePacked(\n                            bytes1(0xff),\n                            address(this),\n                            conduitKey,\n                            _CONDUIT_CREATION_CODE_HASH\n                        )\n                    )\n                )\n            )\n        );\n\n        // Determine whether conduit exists by retrieving its runtime code.\n        exists = (conduit.codehash == _CONDUIT_RUNTIME_CODE_HASH);\n    }\n\n    /**\n     * @notice Retrieve the potential owner, if any, for a given conduit. The\n     *         current owner may set a new potential owner via\n     *         `transferOwnership` and that owner may then accept ownership of\n     *         the conduit in question via `acceptOwnership`.\n     *\n     * @param conduit The conduit for which to retrieve the potential owner.\n     *\n     * @return potentialOwner The potential owner, if any, for the conduit.\n     */\n    function getPotentialOwner(address conduit)\n        external\n        view\n        override\n        returns (address potentialOwner)\n    {\n        // Ensure that the conduit in question exists.\n        _assertConduitExists(conduit);\n\n        // Retrieve the current potential owner of the conduit in question.\n        potentialOwner = _conduits[conduit].potentialOwner;\n    }\n\n    /**\n     * @notice Retrieve the status (either open or closed) of a given channel on\n     *         a conduit.\n     *\n     * @param conduit The conduit for which to retrieve the channel status.\n     * @param channel The channel for which to retrieve the status.\n     *\n     * @return isOpen The status of the channel on the given conduit.\n     */\n    function getChannelStatus(address conduit, address channel)\n        external\n        view\n        override\n        returns (bool isOpen)\n    {\n        // Ensure that the conduit in question exists.\n        _assertConduitExists(conduit);\n\n        // Retrieve the current channel status for the conduit in question.\n        isOpen = _conduits[conduit].channelIndexesPlusOne[channel] != 0;\n    }\n\n    /**\n     * @notice Retrieve the total number of open channels for a given conduit.\n     *\n     * @param conduit The conduit for which to retrieve the total channel count.\n     *\n     * @return totalChannels The total number of open channels for the conduit.\n     */\n    function getTotalChannels(address conduit)\n        external\n        view\n        override\n        returns (uint256 totalChannels)\n    {\n        // Ensure that the conduit in question exists.\n        _assertConduitExists(conduit);\n\n        // Retrieve the total open channel count for the conduit in question.\n        totalChannels = _conduits[conduit].channels.length;\n    }\n\n    /**\n     * @notice Retrieve an open channel at a specific index for a given conduit.\n     *         Note that the index of a channel can change as a result of other\n     *         channels being closed on the conduit.\n     *\n     * @param conduit      The conduit for which to retrieve the open channel.\n     * @param channelIndex The index of the channel in question.\n     *\n     * @return channel The open channel, if any, at the specified channel index.\n     */\n    function getChannel(address conduit, uint256 channelIndex)\n        external\n        view\n        override\n        returns (address channel)\n    {\n        // Ensure that the conduit in question exists.\n        _assertConduitExists(conduit);\n\n        // Retrieve the total open channel count for the conduit in question.\n        uint256 totalChannels = _conduits[conduit].channels.length;\n\n        // Ensure that the supplied index is within range.\n        if (channelIndex >= totalChannels) {\n            revert ChannelOutOfRange(conduit);\n        }\n\n        // Retrieve the channel at the given index.\n        channel = _conduits[conduit].channels[channelIndex];\n    }\n\n    /**\n     * @notice Retrieve all open channels for a given conduit. Note that calling\n     *         this function for a conduit with many channels will revert with\n     *         an out-of-gas error.\n     *\n     * @param conduit The conduit for which to retrieve open channels.\n     *\n     * @return channels An array of open channels on the given conduit.\n     */\n    function getChannels(address conduit)\n        external\n        view\n        override\n        returns (address[] memory channels)\n    {\n        // Ensure that the conduit in question exists.\n        _assertConduitExists(conduit);\n\n        // Retrieve all of the open channels on the conduit in question.\n        channels = _conduits[conduit].channels;\n    }\n\n    /**\n     * @dev Retrieve the conduit creation code and runtime code hashes.\n     */\n    function getConduitCodeHashes()\n        external\n        view\n        override\n        returns (bytes32 creationCodeHash, bytes32 runtimeCodeHash)\n    {\n        // Retrieve the conduit creation code hash from runtime.\n        creationCodeHash = _CONDUIT_CREATION_CODE_HASH;\n\n        // Retrieve the conduit runtime code hash from runtime.\n        runtimeCodeHash = _CONDUIT_RUNTIME_CODE_HASH;\n    }\n\n    /**\n     * @dev Private view function to revert if the caller is not the owner of a\n     *      given conduit.\n     *\n     * @param conduit The conduit for which to assert ownership.\n     */\n    function _assertCallerIsConduitOwner(address conduit) private view {\n        // Ensure that the conduit in question exists.\n        _assertConduitExists(conduit);\n\n        // If the caller does not match the current owner of the conduit...\n        if (msg.sender != _conduits[conduit].owner) {\n            // Revert, indicating that the caller is not the owner.\n            revert CallerIsNotOwner(conduit);\n        }\n    }\n\n    /**\n     * @dev Private view function to revert if a given conduit does not exist.\n     *\n     * @param conduit The conduit for which to assert existence.\n     */\n    function _assertConduitExists(address conduit) private view {\n        // Attempt to retrieve a conduit key for the conduit in question.\n        if (_conduits[conduit].key == bytes32(0)) {\n            // Revert if no conduit key was located.\n            revert NoConduit();\n        }\n    }\n}\n"
    },
    "contracts/conduit/Conduit.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.7;\n\nimport { ConduitInterface } from \"../interfaces/ConduitInterface.sol\";\n\nimport { ConduitItemType } from \"./lib/ConduitEnums.sol\";\n\nimport { TokenTransferrer } from \"../lib/TokenTransferrer.sol\";\n\nimport {\n    ConduitTransfer,\n    ConduitBatch1155Transfer\n} from \"./lib/ConduitStructs.sol\";\n\nimport \"./lib/ConduitConstants.sol\";\n\n/**\n * @title Conduit\n * @author 0age\n * @notice This contract serves as an originator for \"proxied\" transfers. Each\n *         conduit is deployed and controlled by a \"conduit controller\" that can\n *         add and remove \"channels\" or contracts that can instruct the conduit\n *         to transfer approved ERC20/721/1155 tokens. *IMPORTANT NOTE: each\n *         conduit has an owner that can arbitrarily add or remove channels, and\n *         a malicious or negligent owner can add a channel that allows for any\n *         approved ERC20/721/1155 tokens to be taken immediately — be extremely\n *         cautious with what conduits you give token approvals to!*\n */\ncontract Conduit is ConduitInterface, TokenTransferrer {\n    // Set deployer as an immutable controller that can update channel statuses.\n    address private immutable _controller;\n\n    // Track the status of each channel.\n    mapping(address => bool) private _channels;\n\n    /**\n     * @notice Ensure that the caller is currently registered as an open channel\n     *         on the conduit.\n     */\n    modifier onlyOpenChannel() {\n        // Utilize assembly to access channel storage mapping directly.\n        assembly {\n            // Write the caller to scratch space.\n            mstore(ChannelKey_channel_ptr, caller())\n\n            // Write the storage slot for _channels to scratch space.\n            mstore(ChannelKey_slot_ptr, _channels.slot)\n\n            // Derive the position in storage of _channels[msg.sender]\n            // and check if the stored value is zero.\n            if iszero(\n                sload(keccak256(ChannelKey_channel_ptr, ChannelKey_length))\n            ) {\n                // The caller is not an open channel; revert with\n                // ChannelClosed(caller). First, set error signature in memory.\n                mstore(ChannelClosed_error_ptr, ChannelClosed_error_signature)\n\n                // Next, set the caller as the argument.\n                mstore(ChannelClosed_channel_ptr, caller())\n\n                // Finally, revert, returning full custom error with argument.\n                revert(ChannelClosed_error_ptr, ChannelClosed_error_length)\n            }\n        }\n\n        // Continue with function execution.\n        _;\n    }\n\n    /**\n     * @notice In the constructor, set the deployer as the controller.\n     */\n    constructor() {\n        // Set the deployer as the controller.\n        _controller = msg.sender;\n    }\n\n    /**\n     * @notice Execute a sequence of ERC20/721/1155 transfers. Only a caller\n     *         with an open channel can call this function. Note that channels\n     *         are expected to implement reentrancy protection if desired, and\n     *         that cross-channel reentrancy may be possible if the conduit has\n     *         multiple open channels at once. Also note that channels are\n     *         expected to implement checks against transferring any zero-amount\n     *         items if that constraint is desired.\n     *\n     * @param transfers The ERC20/721/1155 transfers to perform.\n     *\n     * @return magicValue A magic value indicating that the transfers were\n     *                    performed successfully.\n     */\n    function execute(ConduitTransfer[] calldata transfers)\n        external\n        override\n        onlyOpenChannel\n        returns (bytes4 magicValue)\n    {\n        // Retrieve the total number of transfers and place on the stack.\n        uint256 totalStandardTransfers = transfers.length;\n\n        // Iterate over each transfer.\n        for (uint256 i = 0; i < totalStandardTransfers; ) {\n            // Retrieve the transfer in question and perform the transfer.\n            _transfer(transfers[i]);\n\n            // Skip overflow check as for loop is indexed starting at zero.\n            unchecked {\n                ++i;\n            }\n        }\n\n        // Return a magic value indicating that the transfers were performed.\n        magicValue = this.execute.selector;\n    }\n\n    /**\n     * @notice Execute a sequence of batch 1155 item transfers. Only a caller\n     *         with an open channel can call this function. Note that channels\n     *         are expected to implement reentrancy protection if desired, and\n     *         that cross-channel reentrancy may be possible if the conduit has\n     *         multiple open channels at once. Also note that channels are\n     *         expected to implement checks against transferring any zero-amount\n     *         items if that constraint is desired.\n     *\n     * @param batchTransfers The 1155 batch item transfers to perform.\n     *\n     * @return magicValue A magic value indicating that the item transfers were\n     *                    performed successfully.\n     */\n    function executeBatch1155(\n        ConduitBatch1155Transfer[] calldata batchTransfers\n    ) external override onlyOpenChannel returns (bytes4 magicValue) {\n        // Perform 1155 batch transfers. Note that memory should be considered\n        // entirely corrupted from this point forward.\n        _performERC1155BatchTransfers(batchTransfers);\n\n        // Return a magic value indicating that the transfers were performed.\n        magicValue = this.executeBatch1155.selector;\n    }\n\n    /**\n     * @notice Execute a sequence of transfers, both single ERC20/721/1155 item\n     *         transfers as well as batch 1155 item transfers. Only a caller\n     *         with an open channel can call this function. Note that channels\n     *         are expected to implement reentrancy protection if desired, and\n     *         that cross-channel reentrancy may be possible if the conduit has\n     *         multiple open channels at once. Also note that channels are\n     *         expected to implement checks against transferring any zero-amount\n     *         items if that constraint is desired.\n     *\n     * @param standardTransfers The ERC20/721/1155 item transfers to perform.\n     * @param batchTransfers    The 1155 batch item transfers to perform.\n     *\n     * @return magicValue A magic value indicating that the item transfers were\n     *                    performed successfully.\n     */\n    function executeWithBatch1155(\n        ConduitTransfer[] calldata standardTransfers,\n        ConduitBatch1155Transfer[] calldata batchTransfers\n    ) external override onlyOpenChannel returns (bytes4 magicValue) {\n        // Retrieve the total number of transfers and place on the stack.\n        uint256 totalStandardTransfers = standardTransfers.length;\n\n        // Iterate over each standard transfer.\n        for (uint256 i = 0; i < totalStandardTransfers; ) {\n            // Retrieve the transfer in question and perform the transfer.\n            _transfer(standardTransfers[i]);\n\n            // Skip overflow check as for loop is indexed starting at zero.\n            unchecked {\n                ++i;\n            }\n        }\n\n        // Perform 1155 batch transfers. Note that memory should be considered\n        // entirely corrupted from this point forward aside from the free memory\n        // pointer having the default value.\n        _performERC1155BatchTransfers(batchTransfers);\n\n        // Return a magic value indicating that the transfers were performed.\n        magicValue = this.executeWithBatch1155.selector;\n    }\n\n    /**\n     * @notice Open or close a given channel. Only callable by the controller.\n     *\n     * @param channel The channel to open or close.\n     * @param isOpen  The status of the channel (either open or closed).\n     */\n    function updateChannel(address channel, bool isOpen) external override {\n        // Ensure that the caller is the controller of this contract.\n        if (msg.sender != _controller) {\n            revert InvalidController();\n        }\n\n        // Ensure that the channel does not already have the indicated status.\n        if (_channels[channel] == isOpen) {\n            revert ChannelStatusAlreadySet(channel, isOpen);\n        }\n\n        // Update the status of the channel.\n        _channels[channel] = isOpen;\n\n        // Emit a corresponding event.\n        emit ChannelUpdated(channel, isOpen);\n    }\n\n    /**\n     * @dev Internal function to transfer a given ERC20/721/1155 item. Note that\n     *      channels are expected to implement checks against transferring any\n     *      zero-amount items if that constraint is desired.\n     *\n     * @param item The ERC20/721/1155 item to transfer.\n     */\n    function _transfer(ConduitTransfer calldata item) internal {\n        // Determine the transfer method based on the respective item type.\n        if (item.itemType == ConduitItemType.ERC20) {\n            // Transfer ERC20 token. Note that item.identifier is ignored and\n            // therefore ERC20 transfer items are potentially malleable — this\n            // check should be performed by the calling channel if a constraint\n            // on item malleability is desired.\n            _performERC20Transfer(item.token, item.from, item.to, item.amount);\n        } else if (item.itemType == ConduitItemType.ERC721) {\n            // Ensure that exactly one 721 item is being transferred.\n            if (item.amount != 1) {\n                revert InvalidERC721TransferAmount();\n            }\n\n            // Transfer ERC721 token.\n            _performERC721Transfer(\n                item.token,\n                item.from,\n                item.to,\n                item.identifier\n            );\n        } else if (item.itemType == ConduitItemType.ERC1155) {\n            // Transfer ERC1155 token.\n            _performERC1155Transfer(\n                item.token,\n                item.from,\n                item.to,\n                item.identifier,\n                item.amount\n            );\n        } else {\n            // Throw with an error.\n            revert InvalidItemType();\n        }\n    }\n}\n"
    },
    "contracts/conduit/lib/ConduitConstants.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.7;\n\n// error ChannelClosed(address channel)\nuint256 constant ChannelClosed_error_signature = (\n    0x93daadf200000000000000000000000000000000000000000000000000000000\n);\nuint256 constant ChannelClosed_error_ptr = 0x00;\nuint256 constant ChannelClosed_channel_ptr = 0x4;\nuint256 constant ChannelClosed_error_length = 0x24;\n\n// For the mapping:\n// mapping(address => bool) channels\n// The position in storage for a particular account is:\n// keccak256(abi.encode(account, channels.slot))\nuint256 constant ChannelKey_channel_ptr = 0x00;\nuint256 constant ChannelKey_slot_ptr = 0x20;\nuint256 constant ChannelKey_length = 0x40;\n"
    },
    "contracts/interfaces/IERC4907.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.7;\n\ninterface IERC4907 {\n\n    event UpdateUser(uint256 indexed tokenId, address indexed user, uint256 expires);\n\n    function mint(address to, address tokenAddress, uint256 tokenId) external returns (uint256);\n\n    function burn(uint256 tokenId) external;\n\n    function setUser(uint256 tokenId, address user, uint256 expires) external;\n\n    function userOf(uint256 tokenId) external view returns (address);\n\n    function userExpires(uint256 tokenId) external view returns (uint256);\n}"
    },
    "contracts/interfaces/MathUtil.sol": {
      "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nlibrary MathUtil {\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n}"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": true,
      "runs": 10000
    },
    "outputSelection": {
      "*": {
        "*": [
          "abi",
          "evm.bytecode",
          "evm.deployedBytecode",
          "evm.methodIdentifiers",
          "metadata",
          "devdoc",
          "userdoc",
          "storageLayout",
          "evm.gasEstimates"
        ],
        "": [
          "ast"
        ]
      }
    },
    "metadata": {
      "useLiteralContent": true
    }
  }
}