creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../../utils/AddressUpgradeable.sol\";\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```solidity\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\n *     }\n * }\n *\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n *     function initializeV2() reinitializer(2) public {\n *         __ERC20Permit_init(\"MyToken\");\n *     }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n *     _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n    /**\n     * @dev Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 version);\n\n    /**\n     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n     * `onlyInitializing` functions can be used to initialize parent contracts.\n     *\n     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\n     * constructor.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = !_initializing;\n        require(\n            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),\n            \"Initializable: contract is already initialized\"\n        );\n        _initialized = 1;\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(1);\n        }\n    }\n\n    /**\n     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n     * used to initialize parent contracts.\n     *\n     * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n     * are added through upgrades and that require initialization.\n     *\n     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n     * cannot be nested. If one is invoked in the context of another, execution will revert.\n     *\n     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n     * a contract, executing them in the right order is up to the developer or operator.\n     *\n     * WARNING: setting the version to 255 will prevent any future reinitialization.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier reinitializer(uint8 version) {\n        require(!_initializing && _initialized < version, \"Initializable: contract is already initialized\");\n        _initialized = version;\n        _initializing = true;\n        _;\n        _initializing = false;\n        emit Initialized(version);\n    }\n\n    /**\n     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n     * {initializer} and {reinitializer} modifiers, directly or indirectly.\n     */\n    modifier onlyInitializing() {\n        require(_initializing, \"Initializable: contract is not initializing\");\n        _;\n    }\n\n    /**\n     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n     * through proxies.\n     *\n     * Emits an {Initialized} event the first time it is successfully executed.\n     */\n    function _disableInitializers() internal virtual {\n        require(!_initializing, \"Initializable: contract is initializing\");\n        if (_initialized != type(uint8).max) {\n            _initialized = type(uint8).max;\n            emit Initialized(type(uint8).max);\n        }\n    }\n\n    /**\n     * @dev Returns the highest version that has been initialized. See {reinitializer}.\n     */\n    function _getInitializedVersion() internal view returns (uint8) {\n        return _initialized;\n    }\n\n    /**\n     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n     */\n    function _isInitializing() internal view returns (bool) {\n        return _initializing;\n    }\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuardUpgradeable is Initializable {\n    // Booleans are more expensive than uint256 or any type that takes up a full\n    // word because each write operation emits an extra SLOAD to first read the\n    // slot's contents, replace the bits taken up by the boolean, and then write\n    // back. This is the compiler's defense against contract upgrades and\n    // pointer aliasing, and it cannot be disabled.\n\n    // The values being non-zero value makes deployment a bit more expensive,\n    // but in exchange the refund on every call to nonReentrant will be lower in\n    // amount. Since refunds are capped to a percentage of the total\n    // transaction's gas, it is best to keep them low in cases like this one, to\n    // increase the likelihood of the full refund coming into effect.\n    uint256 private constant _NOT_ENTERED = 1;\n    uint256 private constant _ENTERED = 2;\n\n    uint256 private _status;\n\n    function __ReentrancyGuard_init() internal onlyInitializing {\n        __ReentrancyGuard_init_unchained();\n    }\n\n    function __ReentrancyGuard_init_unchained() internal onlyInitializing {\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and making it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        _nonReentrantBefore();\n        _;\n        _nonReentrantAfter();\n    }\n\n    function _nonReentrantBefore() private {\n        // On the first call to nonReentrant, _status will be _NOT_ENTERED\n        require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n        // Any calls to nonReentrant after this point will fail\n        _status = _ENTERED;\n    }\n\n    function _nonReentrantAfter() private {\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n     * `nonReentrant` function in the call stack.\n     */\n    function _reentrancyGuardEntered() internal view returns (bool) {\n        return _status == _ENTERED;\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[49] private __gap;\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\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     * Furthermore, `isContract` will also return true if the target contract within\n     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,\n     * which only has an effect at the end of a transaction.\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://consensys.net/diligence/blog/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.8.0/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 functionCallWithValue(target, data, 0, \"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(address target, bytes memory data, uint256 value) 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        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, 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        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, 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        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n     *\n     * _Available since v4.8._\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        if (success) {\n            if (returndata.length == 0) {\n                // only check isContract if the call was successful and the return data is empty\n                // otherwise we already know that it was a contract\n                require(isContract(target), \"Address: call to non-contract\");\n            }\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason or 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            _revert(returndata, errorMessage);\n        }\n    }\n\n    function _revert(bytes memory returndata, string memory errorMessage) private pure {\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"
      },
      "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)\n\npragma solidity ^0.8.0;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\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 ContextUpgradeable is Initializable {\n    function __Context_init() internal onlyInitializing {\n    }\n\n    function __Context_init_unchained() internal onlyInitializing {\n    }\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    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[50] private __gap;\n}\n"
      },
      "@openzeppelin/contracts/token/ERC721/IERC721.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"../../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\n     *   a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) 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\n     *   {setApprovalForAll}.\n     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon\n     *   a safe transfer.\n     *\n     * Emits a {Transfer} event.\n     */\n    function safeTransferFrom(address from, address to, uint256 tokenId) external;\n\n    /**\n     * @dev Transfers `tokenId` token from `from` to `to`.\n     *\n     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721\n     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must\n     * understand this adds an external call which potentially creates a reentrancy vulnerability.\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(address from, address to, uint256 tokenId) 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 address zero.\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/utils/introspection/IERC165.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.20;\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/interfaces/internal/IFethMarket.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\n\npragma solidity ^0.8.18;\n\n/**\n * @notice Interface for functions the market uses in FETH.\n * @author batu-inal & HardlyDifficult\n */\ninterface IFethMarket {\n  function depositFor(address account) external payable;\n\n  function marketLockupFor(address account, uint256 amount) external payable returns (uint256 expiration);\n\n  function marketWithdrawFrom(address from, uint256 amount) external;\n\n  function marketWithdrawLocked(address account, uint256 expiration, uint256 amount) external;\n\n  function marketUnlockFor(address account, uint256 expiration, uint256 amount) external;\n\n  function marketChangeLockup(\n    address unlockFrom,\n    uint256 unlockExpiration,\n    uint256 unlockAmount,\n    address lockupFor,\n    uint256 lockupAmount\n  ) external payable returns (uint256 expiration);\n}\n"
      },
      "contracts/interfaces/internal/IMarketUtils.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"../../mixins/shared/MarketStructs.sol\";\n\ninterface IMarketUtils {\n  function getTransactionBreakdown(\n    MarketTransactionOptions calldata options\n  )\n    external\n    view\n    returns (\n      uint256 protocolFeeAmount,\n      address payable[] memory creatorRecipients,\n      uint256[] memory creatorShares,\n      uint256 sellerRev,\n      uint256 buyReferrerFee,\n      uint256 sellerReferrerFee\n    );\n}\n"
      },
      "contracts/interfaces/internal/INFTMarketGetters.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"../../mixins/shared/MarketStructs.sol\";\n\n/**\n * @title Interface with NFTMarket getters which are used by the router.\n * @author HardlyDifficult\n */\ninterface INFTMarketGetters {\n  function getBuyPrice(address nftContract, uint256 tokenId) external view returns (address seller, uint256 price);\n\n  function getSaleStartsAt(address nftContract, uint256 tokenId) external view returns (uint256 saleStartsAt);\n\n  function getReserveAuction(uint256 auctionId) external view returns (ReserveAuction memory auction);\n\n  function getReserveAuctionIdFor(address nftContract, uint256 tokenId) external view returns (uint256 auctionId);\n}\n"
      },
      "contracts/interfaces/internal/IWorldsSharedMarket.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\ninterface IWorldsSharedMarket {\n  error WorldsInventoryByNft_Not_In_A_World();\n\n  function getDefaultTakeRate(uint256 worldId) external view returns (uint16 defaultTakeRateInBasisPoints);\n\n  function addToWorldByCollectionV2(\n    uint256 worldId,\n    address nftContract,\n    uint16 takeRateInBasisPoints,\n    bytes calldata approvalData\n  ) external;\n\n  function addToWorldByNftV2(\n    uint256 worldId,\n    address nftContract,\n    uint256 nftTokenId,\n    uint16 takeRateInBasisPoints,\n    bytes calldata approvalData\n  ) external;\n\n  function removeFromWorldByNft(address nftContract, uint256 nftTokenId) external;\n\n  function getAssociationByCollection(\n    address nftContract,\n    address seller\n  ) external view returns (uint256 worldId, uint16 takeRateInBasisPoints);\n\n  function getAssociationByNft(\n    address nftContract,\n    uint256 nftTokenId,\n    address seller\n  ) external view returns (uint256 worldId, uint16 takeRateInBasisPoints);\n\n  function getPaymentAddress(uint256 worldId) external view returns (address payable worldPaymentAddress);\n}\n"
      },
      "contracts/interfaces/internal/IWorldsSoldByNft.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\ninterface IWorldsSoldByNft {\n  ////////////////////////////////////////////////////////////////\n  // NFT specific\n  ////////////////////////////////////////////////////////////////\n\n  function soldInWorldByNft(\n    address seller,\n    address nftContract,\n    uint256 nftTokenId,\n    address buyer,\n    uint256 salePrice\n  ) external returns (uint256 worldId, address payable worldPaymentAddress, uint16 takeRateInBasisPoints);\n}\n"
      },
      "contracts/interfaces/internal/roles/IAdminRole.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\n\npragma solidity ^0.8.18;\n\n/**\n * @notice Interface for AdminRole which wraps the default admin role from\n * OpenZeppelin's AccessControl for easy integration.\n * @author batu-inal & HardlyDifficult\n */\ninterface IAdminRole {\n  function isAdmin(address account) external view returns (bool);\n}\n"
      },
      "contracts/interfaces/internal/roles/IOperatorRole.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\n\npragma solidity ^0.8.18;\n\n/**\n * @notice Interface for OperatorRole which wraps a role from\n * OpenZeppelin's AccessControl for easy integration.\n * @author batu-inal & HardlyDifficult\n */\ninterface IOperatorRole {\n  function isOperator(address account) external view returns (bool);\n}\n"
      },
      "contracts/interfaces/internal/routes/INFTMarketBuyNow.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\n/**\n * @title Interface for routing calls to the NFT Market to set buy now prices.\n * @author HardlyDifficult\n */\ninterface INFTMarketBuyNow {\n  function cancelBuyPrice(address nftContract, uint256 tokenId) external;\n\n  function setBuyPrice(address nftContract, uint256 tokenId, uint256 price) external;\n}\n"
      },
      "contracts/interfaces/internal/routes/INFTMarketReserveAuction.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\n/**\n * @title Interface for routing calls to the NFT Market to create reserve auctions.\n * @author HardlyDifficult & reggieag\n */\ninterface INFTMarketReserveAuction {\n  function cancelReserveAuction(uint256 auctionId) external;\n\n  function createReserveAuction(\n    address nftContract,\n    uint256 tokenId,\n    uint256 reservePrice,\n    uint256 duration\n  ) external returns (uint256 auctionId);\n\n  function updateReserveAuction(uint256 auctionId, uint256 reservePrice) external;\n}\n"
      },
      "contracts/interfaces/internal/routes/INFTMarketScheduling.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\ninterface INFTMarketScheduling {\n  function setSaleStartsAt(address nftContract, uint256 tokenId, uint256 saleStartsAt) external;\n}\n"
      },
      "contracts/libraries/ReserveAuctionLibrary.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"../mixins/shared/Constants.sol\";\n\nlibrary ReserveAuctionLibrary {\n  error ReserveAuctionLibrary_Must_Set_Non_Zero_Reserve_Price();\n  error ReserveAuctionLibrary_Exceeds_Max_Duration(uint256 maxDuration);\n  error ReserveAuctionLibrary_Less_Than_Extension_Duration(uint256 extensionDuration);\n  error ReserveAuctionLibrary_Only_Callable_By_Seller(address seller);\n\n  function validateReserveAuctionConfig(\n    uint256 reservePrice,\n    uint256 duration\n  ) internal pure returns (uint256 updatedDuration) {\n    validateReserveAuctionPrice(reservePrice);\n\n    if (duration == 0) {\n      updatedDuration = DEFAULT_DURATION;\n    } else {\n      if (duration > MAX_DURATION) {\n        // This ensures that math in this file will not overflow due to a huge duration.\n        revert ReserveAuctionLibrary_Exceeds_Max_Duration(MAX_DURATION);\n      }\n      if (duration < EXTENSION_DURATION) {\n        // The auction duration configuration must be greater than the extension window of 2 minutes\n        revert ReserveAuctionLibrary_Less_Than_Extension_Duration(EXTENSION_DURATION);\n      }\n\n      updatedDuration = duration;\n    }\n  }\n\n  /// @notice Confirms that the reserve price is not zero.\n  function validateReserveAuctionPrice(uint256 reservePrice) internal pure {\n    if (reservePrice == 0) {\n      revert ReserveAuctionLibrary_Must_Set_Non_Zero_Reserve_Price();\n    }\n  }\n\n  function validateCalledBySeller(address msgSender, address seller) internal pure {\n    if (msgSender != seller) {\n      revert ReserveAuctionLibrary_Only_Callable_By_Seller(seller);\n    }\n  }\n}\n"
      },
      "contracts/libraries/RouteCallLibrary.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nerror RouteCallLibrary_Call_Failed_Without_Revert_Reason();\n\n/**\n * @title A library for calling external contracts with an address appended to the calldata.\n * @author HardlyDifficult\n */\nlibrary RouteCallLibrary {\n  /**\n   * @notice Routes a call to the specified contract, appending the from address to the end of the calldata.\n   * If the call reverts, this will revert the transaction and the original reason is bubbled up.\n   * @param from The address to use as the msg sender when calling the contract.\n   * @param to The contract address to call.\n   * @param callData The call data to use when calling the contract, without the sender appended.\n   */\n  function routeCallTo(address from, address to, bytes memory callData) internal returns (bytes memory returnData) {\n    // Forward the call, with the packed from address appended, to the specified contract.\n    bool success;\n    (success, returnData) = tryRouteCallTo(from, to, callData);\n\n    // If the call failed, bubble up the revert reason.\n    if (!success) {\n      revertWithError(returnData);\n    }\n  }\n\n  /**\n   * @notice Routes a call to the specified contract, appending the from address to the end of the calldata.\n   * This will not revert even if the external call fails.\n   * @param from The address to use as the msg sender when calling the contract.\n   * @param to The contract address to call.\n   * @param callData The call data to use when calling the contract, without the sender appended.\n   * @dev Consumers should look for positive confirmation that if the transaction is not successful, the returned revert\n   * reason is expected as an acceptable reason to ignore. Generically ignoring reverts will lead to out-of-gas errors\n   * being ignored and result in unexpected behavior.\n   */\n  function tryRouteCallTo(\n    address from,\n    address to,\n    bytes memory callData\n  ) internal returns (bool success, bytes memory returnData) {\n    // Forward the call, with the packed from address appended, to the specified contract.\n    // solhint-disable-next-line avoid-low-level-calls\n    (success, returnData) = to.call(abi.encodePacked(callData, from));\n  }\n\n  /**\n   * @notice Bubbles up the original revert reason of a low-level call failure where possible.\n   * @dev Copied from OZ's `Address.sol` library, with a minor modification to the final revert scenario.\n   * This should only be used when a low-level call fails.\n   */\n  function revertWithError(bytes memory returnData) internal pure {\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 RouteCallLibrary_Call_Failed_Without_Revert_Reason();\n    }\n  }\n\n  /**\n   * @notice Extracts the appended sender address from the calldata.\n   * @dev This uses the last 20 bytes of the calldata, with no guarantees that an address has indeed been appended.\n   * If this is used for a call that was not routed with `routeCallTo`, the address returned will be incorrect (and\n   * may be address(0)).\n   */\n  function extractAppendedSenderAddress() internal pure returns (address sender) {\n    assembly {\n      // The router appends the msg.sender to the end of the calldata\n      // source: https://github.com/opengsn/gsn/blob/v3.0.0-beta.3/packages/contracts/src/ERC2771Recipient.sol#L48\n      sender := shr(96, calldataload(sub(calldatasize(), 20)))\n    }\n  }\n}\n"
      },
      "contracts/libraries/TimeLibrary.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\n\npragma solidity ^0.8.18;\n\n/**\n * @title Helpers for working with time.\n * @author batu-inal & HardlyDifficult\n */\nlibrary TimeLibrary {\n  /**\n   * @notice Checks if the given timestamp is in the past.\n   * @dev This helper ensures a consistent interpretation of expiry across the codebase.\n   * This is different than `hasBeenReached` in that it will return false if the expiry is now.\n   */\n  function hasExpired(uint256 expiry) internal view returns (bool) {\n    return expiry < block.timestamp;\n  }\n\n  /**\n   * @notice Checks if the given timestamp is now or in the past.\n   * @dev This helper ensures a consistent interpretation of expiry across the codebase.\n   * This is different from `hasExpired` in that it will return true if the timestamp is now.\n   */\n  function hasBeenReached(uint256 timestamp) internal view returns (bool) {\n    return timestamp <= block.timestamp;\n  }\n}\n"
      },
      "contracts/mixins/nftMarket/NFTMarketAuction.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\n\npragma solidity ^0.8.18;\n\n/**\n * @title An abstraction layer for auctions.\n * @dev This contract can be expanded with reusable calls and data as more auction types are added.\n * @author batu-inal & HardlyDifficult\n */\nabstract contract NFTMarketAuction {\n  /// @notice A global id for auctions of any type.\n  uint256 private $nextAuctionId;\n\n  error NFTMarketAuction_Already_Initialized();\n\n  /// @notice Assigns a default to the sequence ID used for auctions, allowing different networks to use a unique range.\n  function _initializeNFTMarketAuction(uint256 networkAuctionIdOffset) internal {\n    if (networkAuctionIdOffset != 0) {\n      // If the offset is 0, then ignore this and continue using the value in storage.\n      // This scenario would apply to L1 networks only, which have a non-zero offset to preserve.\n\n      if ($nextAuctionId != 0) {\n        // Explicitly checking this here instead of leaning on initializer to be extra cautious of errors during future\n        // upgrades.\n        revert NFTMarketAuction_Already_Initialized();\n      }\n\n      $nextAuctionId = networkAuctionIdOffset + 1;\n    }\n  }\n\n  /**\n   * @notice Returns id to assign to the next auction.\n   */\n  function _getNextAndIncrementAuctionId() internal returns (uint256) {\n    // AuctionId cannot overflow 256 bits.\n    unchecked {\n      if ($nextAuctionId == 0) {\n        // Ensures that the first auctionId is 1.\n        ++$nextAuctionId;\n      }\n\n      // Returns the current nextAuctionId instead of ++nextAuctionId to ensure the sequence ID is preserved on mainnet.\n      return $nextAuctionId++;\n    }\n  }\n\n  /**\n   * @notice This empty reserved space is put in place to allow future versions to add new variables without shifting\n   * down storage in the inheritance chain. See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n   */\n  uint256[1_000] private __gap;\n}\n"
      },
      "contracts/mixins/nftMarket/NFTMarketBuyPrice.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\n\npragma solidity ^0.8.18;\n\nimport \"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\n\nimport \"../../interfaces/internal/INFTMarketGetters.sol\";\nimport \"../../interfaces/internal/routes/INFTMarketBuyNow.sol\";\n\nimport \"../shared/MarketFees.sol\";\nimport \"../shared/FETHNode.sol\";\nimport \"../shared/MarketSharedCore.sol\";\nimport \"../shared/WorldsNftNode.sol\";\nimport \"../shared/SendValueWithFallbackWithdraw.sol\";\n\nimport \"./NFTMarketCore.sol\";\nimport \"./NFTMarketScheduling.sol\";\nimport \"./NFTMarketWorlds.sol\";\n\n/// @param buyPrice The current buy price set for this NFT.\nerror NFTMarketBuyPrice_Cannot_Buy_At_Lower_Price(uint256 buyPrice);\nerror NFTMarketBuyPrice_Cannot_Buy_Unset_Price();\nerror NFTMarketBuyPrice_Cannot_Cancel_Unset_Price();\n/// @param owner The current owner of this NFT.\nerror NFTMarketBuyPrice_Only_Owner_Can_Cancel_Price(address owner);\n/// @param owner The current owner of this NFT.\nerror NFTMarketBuyPrice_Only_Owner_Can_Set_Price(address owner);\n/// @param owner The current owner of this NFT.\nerror NFTMarketBuyPrice_Only_Owner_Can_Update_Nft(address owner);\n/// @param owner The current owner of this NFT.\nerror NFTMarketBuyPrice_Only_Owner_Can_Update_Sale_Starts_At(address owner);\nerror NFTMarketBuyPrice_Price_Already_Set();\nerror NFTMarketBuyPrice_Price_Too_High();\n/// @param seller The current owner of this NFT.\nerror NFTMarketBuyPrice_Seller_Mismatch(address seller);\nerror NFTMarketBuyPrice_Listing_Is_Not_Active(uint256 startTime);\n\n/**\n * @title Allows sellers to set a buy price of their NFTs that may be accepted and instantly transferred to the buyer.\n * @notice NFTs with a buy price set are escrowed in the market contract.\n * @author batu-inal & HardlyDifficult\n */\nabstract contract NFTMarketBuyPrice is\n  INFTMarketGetters,\n  INFTMarketBuyNow,\n  WorldsNftNode,\n  ContextUpgradeable,\n  FETHNode,\n  MarketSharedCore,\n  NFTMarketCore,\n  ReentrancyGuardUpgradeable,\n  SendValueWithFallbackWithdraw,\n  MarketFees,\n  NFTMarketWorlds,\n  NFTMarketScheduling\n{\n  using AddressUpgradeable for address payable;\n\n  /// @notice Stores the buy price details for a specific NFT.\n  /// @dev The struct is packed into a single slot to optimize gas.\n  struct BuyPrice {\n    /// @notice The current owner of this NFT which set a buy price.\n    /// @dev A zero price is acceptable so a non-zero address determines whether a price has been set.\n    address payable seller;\n    /// @notice The current buy price set for this NFT.\n    uint96 price;\n  }\n\n  /// @notice Stores the current buy price for each NFT.\n  mapping(address => mapping(uint256 => BuyPrice)) private nftContractToTokenIdToBuyPrice;\n\n  /**\n   * @notice Emitted when an NFT is bought by accepting the buy price,\n   * indicating that the NFT has been transferred and revenue from the sale distributed.\n   * @dev The total buy price that was accepted is `totalFees` + `creatorRev` + `sellerRev`.\n   * @param nftContract The address of the NFT contract.\n   * @param tokenId The id of the NFT.\n   * @param buyer The address of the collector that purchased the NFT using `buy`.\n   * @param seller The address of the seller which originally set the buy price.\n   * @param totalFees The amount of ETH that was sent to Foundation & referrals for this sale.\n   * @param creatorRev The amount of ETH that was sent to the creator for this sale.\n   * @param sellerRev The amount of ETH that was sent to the owner for this sale.\n   */\n  event BuyPriceAccepted(\n    address indexed nftContract,\n    uint256 indexed tokenId,\n    address indexed seller,\n    address buyer,\n    uint256 totalFees,\n    uint256 creatorRev,\n    uint256 sellerRev\n  );\n\n  /**\n   * @notice Emitted when the buy price is removed by the owner of an NFT.\n   * @dev The NFT is transferred back to the owner unless it's still escrowed for another market tool,\n   * e.g. listed for sale in an auction.\n   * @param nftContract The address of the NFT contract.\n   * @param tokenId The id of the NFT.\n   */\n  event BuyPriceCanceled(address indexed nftContract, uint256 indexed tokenId);\n\n  /**\n   * @notice Emitted when a buy price is invalidated due to other market activity.\n   * @dev This occurs when the buy price is no longer eligible to be accepted,\n   * e.g. when a bid is placed in an auction for this NFT.\n   * @param nftContract The address of the NFT contract.\n   * @param tokenId The id of the NFT.\n   */\n  event BuyPriceInvalidated(address indexed nftContract, uint256 indexed tokenId);\n\n  /**\n   * @notice Emitted when a buy price is set by the owner of an NFT.\n   * @dev The NFT is transferred into the market contract for escrow unless it was already escrowed,\n   * e.g. for auction listing.\n   * @param nftContract The address of the NFT contract.\n   * @param tokenId The id of the NFT.\n   * @param seller The address of the NFT owner which set the buy price.\n   * @param price The price of the NFT.\n   */\n  event BuyPriceSet(address indexed nftContract, uint256 indexed tokenId, address indexed seller, uint256 price);\n\n  /**\n   * @notice Buy the NFT at the set buy price.\n   * `msg.value` must be <= `maxPrice` and any delta will be taken from the account's available FETH balance.\n   * @dev `maxPrice` protects the buyer in case a the price is increased but allows the transaction to continue\n   * when the price is reduced (and any surplus funds provided are refunded).\n   * @param nftContract The address of the NFT contract.\n   * @param tokenId The id of the NFT.\n   * @param maxPrice The maximum price to pay for the NFT.\n   * @param referrer The address of the referrer.\n   */\n  function buyV2(address nftContract, uint256 tokenId, uint256 maxPrice, address payable referrer) external payable {\n    BuyPrice storage buyPrice = nftContractToTokenIdToBuyPrice[nftContract][tokenId];\n    if (buyPrice.price > maxPrice) {\n      revert NFTMarketBuyPrice_Cannot_Buy_At_Lower_Price(buyPrice.price);\n    } else if (buyPrice.seller == address(0)) {\n      revert NFTMarketBuyPrice_Cannot_Buy_Unset_Price();\n    }\n\n    _buy(nftContract, tokenId, referrer);\n  }\n\n  /**\n   * @notice Removes the buy price set for an NFT.\n   * @dev The NFT is transferred back to the owner unless it's still escrowed for another market tool,\n   * e.g. listed for sale in an auction.\n   * @param nftContract The address of the NFT contract.\n   * @param tokenId The id of the NFT.\n   */\n  function cancelBuyPrice(address nftContract, uint256 tokenId) external nonReentrant {\n    address seller = nftContractToTokenIdToBuyPrice[nftContract][tokenId].seller;\n    address sender = _msgSender();\n    if (seller == address(0)) {\n      // This check is redundant with the next one, but done in order to provide a more clear error message.\n      revert NFTMarketBuyPrice_Cannot_Cancel_Unset_Price();\n    } else if (seller != sender) {\n      revert NFTMarketBuyPrice_Only_Owner_Can_Cancel_Price(seller);\n    }\n\n    // Remove the buy price\n    delete nftContractToTokenIdToBuyPrice[nftContract][tokenId];\n\n    // Transfer the NFT back to the owner if it is not listed in auction.\n    _transferFromEscrowIfAvailable(nftContract, tokenId, seller);\n\n    emit BuyPriceCanceled(nftContract, tokenId);\n  }\n\n  /**\n   * @notice Sets the buy price for an NFT and escrows it in the market contract.\n   * A 0 price is acceptable and valid price you can set, enabling a giveaway to the first collector that calls `buy`.\n   * @dev If there is an offer for this amount or higher, that will be accepted instead of setting a buy price.\n   * @param nftContract The address of the NFT contract.\n   * @param tokenId The id of the NFT.\n   * @param price The price at which someone could buy this NFT.\n   */\n  function setBuyPrice(address nftContract, uint256 tokenId, uint256 price) external nonReentrant {\n    // If there is a valid offer at this price or higher, accept that instead.\n    if (_autoAcceptOffer(nftContract, tokenId, price)) {\n      return;\n    }\n\n    if (price > type(uint96).max) {\n      // This ensures that no data is lost when storing the price as `uint96`.\n      revert NFTMarketBuyPrice_Price_Too_High();\n    }\n\n    BuyPrice storage buyPrice = nftContractToTokenIdToBuyPrice[nftContract][tokenId];\n    address seller = buyPrice.seller;\n\n    if (buyPrice.price == price && seller != address(0)) {\n      revert NFTMarketBuyPrice_Price_Already_Set();\n    }\n\n    // Store the new price for this NFT.\n    buyPrice.price = uint96(price);\n\n    address payable sender = payable(_msgSender());\n\n    if (seller == address(0)) {\n      // Transfer the NFT into escrow, if it's already in escrow confirm the `msg.sender` is the owner.\n      _transferToEscrow(nftContract, tokenId);\n\n      // The price was not previously set for this NFT, store the seller.\n      buyPrice.seller = sender;\n    } else if (seller != sender) {\n      // Buy price was previously set by a different user\n      revert NFTMarketBuyPrice_Only_Owner_Can_Set_Price(seller);\n    }\n\n    emit BuyPriceSet(nftContract, tokenId, sender, price);\n  }\n\n  function _isAuthorizedScheduleUpdate(\n    address nftContract,\n    uint256 tokenId\n  ) internal view virtual override returns (bool canUpdateNft) {\n    address seller = nftContractToTokenIdToBuyPrice[nftContract][tokenId].seller;\n\n    if (seller != address(0)) {\n      if (seller != _msgSender()) {\n        revert NFTMarketBuyPrice_Only_Owner_Can_Update_Nft(seller);\n      }\n\n      canUpdateNft = true;\n    } else {\n      canUpdateNft = super._isAuthorizedScheduleUpdate(nftContract, tokenId);\n    }\n  }\n\n  /**\n   * @notice If there is a buy price at this price or lower, accept that and return true.\n   */\n  function _autoAcceptBuyPrice(\n    address nftContract,\n    uint256 tokenId,\n    uint256 maxPrice\n  ) internal override returns (bool) {\n    BuyPrice storage buyPrice = nftContractToTokenIdToBuyPrice[nftContract][tokenId];\n    if (buyPrice.seller == address(0) || buyPrice.price > maxPrice) {\n      // No buy price was found, or the price is too high.\n      return false;\n    }\n\n    _buy(nftContract, tokenId, payable(0));\n    return true;\n  }\n\n  /**\n   * @inheritdoc NFTMarketCore\n   * @dev Invalidates the buy price on a auction start, if one is found.\n   */\n  function _beforeAuctionStarted(\n    address nftContract,\n    uint256 tokenId\n  ) internal virtual override(NFTMarketCore, NFTMarketScheduling) {\n    BuyPrice storage buyPrice = nftContractToTokenIdToBuyPrice[nftContract][tokenId];\n    if (buyPrice.seller != address(0)) {\n      // A buy price was set for this NFT, invalidate it.\n      _invalidateBuyPrice(nftContract, tokenId);\n    }\n    super._beforeAuctionStarted(nftContract, tokenId);\n  }\n\n  /**\n   * @notice Process the purchase of an NFT at the current buy price.\n   * @dev The caller must confirm that the seller != address(0) before calling this function.\n   */\n  function _buy(address nftContract, uint256 tokenId, address payable referrer) private nonReentrant {\n    _validateSaleStartsAtHasBeenReached(nftContract, tokenId);\n    BuyPrice memory buyPrice = nftContractToTokenIdToBuyPrice[nftContract][tokenId];\n\n    // Remove the buy now price\n    delete nftContractToTokenIdToBuyPrice[nftContract][tokenId];\n\n    // Cancel the buyer's offer if there is one in order to free up their FETH balance\n    // even if they don't need the FETH for this specific purchase.\n    _cancelSendersOffer(nftContract, tokenId);\n\n    address payable buyer = payable(_msgSender());\n    _tryUseFETHBalance({ fromAccount: buyer, totalAmount: buyPrice.price, shouldRefundSurplus: true });\n\n    (address payable sellerReferrerPaymentAddress, uint16 sellerReferrerTakeRateInBasisPoints) = _getWorldForPayment(\n      buyPrice.seller,\n      nftContract,\n      tokenId,\n      buyer,\n      buyPrice.price\n    );\n\n    // Transfer the NFT to the buyer.\n    // The seller was already authorized when the buyPrice was set originally set.\n    _transferFromEscrow(nftContract, tokenId, buyer, address(0));\n\n    // Distribute revenue for this sale.\n    (uint256 totalFees, uint256 creatorRev, uint256 sellerRev) = _distributeFunds(\n      DistributeFundsParams({\n        nftContract: nftContract,\n        firstTokenId: tokenId,\n        nftCount: 1,\n        nftRecipientIfKnown: buyer,\n        seller: buyPrice.seller,\n        price: buyPrice.price,\n        buyReferrer: referrer,\n        sellerReferrerPaymentAddress: sellerReferrerPaymentAddress,\n        sellerReferrerTakeRateInBasisPoints: sellerReferrerTakeRateInBasisPoints,\n        fixedProtocolFeeInWei: 0\n      })\n    );\n\n    emit BuyPriceAccepted(nftContract, tokenId, buyPrice.seller, buyer, totalFees, creatorRev, sellerRev);\n  }\n\n  /**\n   * @notice Clear a buy price and emit BuyPriceInvalidated.\n   * @dev The caller must confirm the buy price is set before calling this function.\n   */\n  function _invalidateBuyPrice(address nftContract, uint256 tokenId) private {\n    delete nftContractToTokenIdToBuyPrice[nftContract][tokenId];\n    emit BuyPriceInvalidated(nftContract, tokenId);\n  }\n\n  /**\n   * @inheritdoc NFTMarketCore\n   * @dev Invalidates the buy price if one is found before transferring the NFT.\n   * This will revert if there is a buy price set but the `authorizeSeller` is not the owner.\n   */\n  function _transferFromEscrow(\n    address nftContract,\n    uint256 tokenId,\n    address recipient,\n    address authorizeSeller\n  ) internal virtual override {\n    address seller = nftContractToTokenIdToBuyPrice[nftContract][tokenId].seller;\n    if (seller != address(0)) {\n      // A buy price was set for this NFT.\n      // `authorizeSeller != address(0) &&` could be added when other mixins use this flow.\n      // ATM that additional check would never return false.\n      if (seller != authorizeSeller) {\n        // When there is a buy price set, the `buyPrice.seller` is the owner of the NFT.\n        revert NFTMarketBuyPrice_Seller_Mismatch(seller);\n      }\n      // The seller authorization has been confirmed.\n      authorizeSeller = address(0);\n\n      // Invalidate the buy price as the NFT will no longer be in escrow.\n      _invalidateBuyPrice(nftContract, tokenId);\n    }\n\n    super._transferFromEscrow(nftContract, tokenId, recipient, authorizeSeller);\n  }\n\n  /**\n   * @inheritdoc NFTMarketCore\n   * @dev Checks if there is a buy price set, if not then allow the transfer to proceed.\n   */\n  function _transferFromEscrowIfAvailable(\n    address nftContract,\n    uint256 tokenId,\n    address originalSeller\n  ) internal virtual override(NFTMarketCore, NFTMarketWorlds, NFTMarketScheduling) {\n    address seller = nftContractToTokenIdToBuyPrice[nftContract][tokenId].seller;\n\n    // If a buy price has been set for this NFT then it should remain in escrow.\n    if (seller == address(0)) {\n      // Otherwise continue to attempt the transfer.\n      super._transferFromEscrowIfAvailable(nftContract, tokenId, originalSeller);\n    }\n  }\n\n  /**\n   * @inheritdoc NFTMarketCore\n   * @dev Checks if the NFT is already in escrow for buy now.\n   */\n  function _transferToEscrow(address nftContract, uint256 tokenId) internal virtual override {\n    address seller = nftContractToTokenIdToBuyPrice[nftContract][tokenId].seller;\n    if (seller == address(0)) {\n      // The NFT is not in escrow for buy now.\n      super._transferToEscrow(nftContract, tokenId);\n    } else if (seller != _msgSender()) {\n      // When there is a buy price set, the `seller` is the owner of the NFT.\n      revert NFTMarketBuyPrice_Seller_Mismatch(seller);\n    }\n  }\n\n  /**\n   * @notice Returns the buy price details for an NFT if one is available.\n   * @dev If no price is found, seller will be address(0) and price will be max uint256.\n   * @param nftContract The address of the NFT contract.\n   * @param tokenId The id of the NFT.\n   * @return seller The address of the owner that listed a buy price for this NFT.\n   * Returns `address(0)` if there is no buy price set for this NFT.\n   * @return price The price of the NFT.\n   * Returns max uint256 if there is no buy price set for this NFT (since a price of 0 is supported).\n   */\n  function getBuyPrice(address nftContract, uint256 tokenId) external view returns (address seller, uint256 price) {\n    seller = nftContractToTokenIdToBuyPrice[nftContract][tokenId].seller;\n    if (seller == address(0)) {\n      return (seller, type(uint256).max);\n    }\n    price = nftContractToTokenIdToBuyPrice[nftContract][tokenId].price;\n  }\n\n  /**\n   * @inheritdoc MarketSharedCore\n   * @dev Returns the seller if there is a buy price set for this NFT, otherwise\n   * bubbles the call up for other considerations.\n   */\n  function _getSellerOf(\n    address nftContract,\n    uint256 tokenId\n  ) internal view virtual override returns (address payable seller) {\n    seller = nftContractToTokenIdToBuyPrice[nftContract][tokenId].seller;\n    if (seller == address(0)) {\n      seller = super._getSellerOf(nftContract, tokenId);\n    }\n  }\n\n  ////////////////////////////////////////////////////////////////\n  // Inheritance Requirements\n  // (no-ops to avoid compile errors)\n  ////////////////////////////////////////////////////////////////\n\n  /**\n   * @inheritdoc MarketFees\n   */\n  function _distributeFunds(\n    DistributeFundsParams memory params\n  )\n    internal\n    virtual\n    override(MarketFees, NFTMarketScheduling)\n    returns (uint256 totalFees, uint256 creatorRev, uint256 sellerRev)\n  {\n    (totalFees, creatorRev, sellerRev) = super._distributeFunds(params);\n  }\n\n  /**\n   * @notice This empty reserved space is put in place to allow future versions to add new variables without shifting\n   * down storage in the inheritance chain. See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n   */\n  uint256[1_000] private __gap;\n}\n"
      },
      "contracts/mixins/nftMarket/NFTMarketCore.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\n\npragma solidity ^0.8.18;\n\nimport \"@openzeppelin/contracts/token/ERC721/IERC721.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\";\n\nimport \"../../interfaces/internal/IFethMarket.sol\";\n\nimport \"../shared/Constants.sol\";\nimport \"../shared/MarketSharedCore.sol\";\n\nerror NFTMarketCore_Seller_Not_Found();\nerror NFTMarketCore_Can_Not_Update_Unlisted_Nft();\n\n/**\n * @title A place for common modifiers and functions used by various NFTMarket mixins, if any.\n * @dev This also leaves a gap which can be used to add a new mixin to the top of the inheritance tree.\n * @author batu-inal & HardlyDifficult\n */\nabstract contract NFTMarketCore is ContextUpgradeable, MarketSharedCore {\n  using AddressUpgradeable for address;\n  using AddressUpgradeable for address payable;\n\n  /**\n   * @notice If there is a buy price at this amount or lower, accept that and return true.\n   */\n  function _autoAcceptBuyPrice(address nftContract, uint256 tokenId, uint256 amount) internal virtual returns (bool);\n\n  /**\n   * @notice If there is a valid offer at the given price or higher, accept that and return true.\n   */\n  function _autoAcceptOffer(address nftContract, uint256 tokenId, uint256 minAmount) internal virtual returns (bool);\n\n  /**\n   * @notice Notify implementors when an auction has received its first bid.\n   * Once a bid is received the sale is guaranteed to the auction winner\n   * and other sale mechanisms become unavailable.\n   * @dev Implementors of this interface should update internal state to reflect an auction has been kicked off.\n   */\n  function _beforeAuctionStarted(address /*nftContract*/, uint256 /*tokenId*/) internal virtual {\n    // No-op\n  }\n\n  /**\n   * @notice Requires that an NFT is listed for sale, not in active auction, and the msg.sender is the seller which\n   * listed the NFT.\n   */\n  function _authorizeScheduleUpdate(address nftContract, uint256 tokenId) internal view {\n    if (!_isAuthorizedScheduleUpdate(nftContract, tokenId)) {\n      revert NFTMarketCore_Can_Not_Update_Unlisted_Nft();\n    }\n  }\n\n  /**\n   * @notice Confirms permission to update the schedule for an NFT.\n   * @return canUpdateNft True if the NFT is listed for sale and authorize checks did not revert.\n   * @dev Verifies that the NFT is listed, not in active auction, and the sender is the owner.\n   */\n  function _isAuthorizedScheduleUpdate(\n    address /*nftContract*/,\n    uint256 /*tokenId*/\n  ) internal view virtual returns (bool canUpdateNft) {\n    // False by default, may be set to true by a market tool mixin if the NFT is listed.\n  }\n\n  /**\n   * @notice Cancel the `msg.sender`'s offer if there is one, freeing up their FETH balance.\n   * @dev This should be used when it does not make sense to keep the original offer around,\n   * e.g. if a collector accepts a Buy Price then keeping the offer around is not necessary.\n   */\n  function _cancelSendersOffer(address nftContract, uint256 tokenId) internal virtual;\n\n  /**\n   * @notice Transfers the NFT from escrow and clears any state tracking this escrowed NFT.\n   * @param authorizeSeller The address of the seller pending authorization.\n   * Once it's been authorized by one of the escrow managers, it should be set to address(0)\n   * indicated that it's no longer pending authorization.\n   */\n  function _transferFromEscrow(\n    address nftContract,\n    uint256 tokenId,\n    address recipient,\n    address authorizeSeller\n  ) internal virtual {\n    if (authorizeSeller != address(0)) {\n      revert NFTMarketCore_Seller_Not_Found();\n    }\n\n    IERC721(nftContract).transferFrom(address(this), recipient, tokenId);\n  }\n\n  /**\n   * @notice Transfers the NFT from escrow unless there is another reason for it to remain in escrow.\n   */\n  function _transferFromEscrowIfAvailable(\n    address nftContract,\n    uint256 tokenId,\n    address originalSeller\n  ) internal virtual {\n    _transferFromEscrow(nftContract, tokenId, originalSeller, address(0));\n  }\n\n  /**\n   * @notice Transfers an NFT into escrow,\n   * if already there this requires the msg.sender is authorized to manage the sale of this NFT.\n   */\n  function _transferToEscrow(address nftContract, uint256 tokenId) internal virtual {\n    IERC721(nftContract).transferFrom(_msgSender(), address(this), tokenId);\n  }\n\n  /**\n   * @dev Determines the minimum amount when increasing an existing offer or bid.\n   */\n  function _getMinIncrement(uint256 currentAmount) internal pure returns (uint256) {\n    uint256 minIncrement = currentAmount;\n    unchecked {\n      minIncrement /= MIN_PERCENT_INCREMENT_DENOMINATOR;\n    }\n    if (minIncrement == 0) {\n      // Since minIncrement reduces from the currentAmount, this cannot overflow.\n      // The next amount must be at least 1 wei greater than the current.\n      return currentAmount + 1;\n    }\n\n    return minIncrement + currentAmount;\n  }\n\n  /**\n   * @inheritdoc MarketSharedCore\n   */\n  function _getSellerOrOwnerOf(\n    address nftContract,\n    uint256 tokenId\n  ) internal view override returns (address payable sellerOrOwner) {\n    sellerOrOwner = _getSellerOf(nftContract, tokenId);\n    if (sellerOrOwner == address(0)) {\n      sellerOrOwner = payable(IERC721(nftContract).ownerOf(tokenId));\n    }\n  }\n\n  /**\n   * @notice Checks if an escrowed NFT is currently in active auction.\n   * @return Returns false if the auction has ended, even if it has not yet been settled.\n   */\n  function _isInActiveAuction(address nftContract, uint256 tokenId) internal view virtual returns (bool);\n\n  /**\n   * @notice This empty reserved space is put in place to allow future versions to add new variables without shifting\n   * down storage in the inheritance chain. See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n   * @dev 50 slots were consumed by adding `ReentrancyGuard`.\n   */\n  uint256[450] private __gap;\n}\n"
      },
      "contracts/mixins/nftMarket/NFTMarketOffer.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\n\npragma solidity ^0.8.18;\n\nimport \"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\n\nimport \"@openzeppelin/contracts/token/ERC721/IERC721.sol\";\n\nimport \"../../libraries/TimeLibrary.sol\";\n\nimport \"../shared/MarketFees.sol\";\nimport \"../shared/FETHNode.sol\";\nimport \"../shared/SendValueWithFallbackWithdraw.sol\";\n\nimport \"./NFTMarketCore.sol\";\nimport \"./NFTMarketWorlds.sol\";\n\nerror NFTMarketOffer_Cannot_Be_Made_While_In_Auction();\n/// @param currentOfferAmount The current highest offer available for this NFT.\nerror NFTMarketOffer_Offer_Below_Min_Amount(uint256 currentOfferAmount);\n/// @param expiry The time at which the offer had expired.\nerror NFTMarketOffer_Offer_Expired(uint256 expiry);\n/// @param currentOfferFrom The address of the collector which has made the current highest offer.\nerror NFTMarketOffer_Offer_From_Does_Not_Match(address currentOfferFrom);\n/// @param minOfferAmount The minimum amount that must be offered in order for it to be accepted.\nerror NFTMarketOffer_Offer_Must_Be_At_Least_Min_Amount(uint256 minOfferAmount);\n\n/**\n * @title Allows collectors to make an offer for an NFT, valid for 24-25 hours.\n * @notice Funds are escrowed in the FETH ERC-20 token contract.\n * @author batu-inal & HardlyDifficult\n */\nabstract contract NFTMarketOffer is\n  ContextUpgradeable,\n  FETHNode,\n  NFTMarketCore,\n  ReentrancyGuardUpgradeable,\n  SendValueWithFallbackWithdraw,\n  MarketFees,\n  NFTMarketWorlds\n{\n  using AddressUpgradeable for address;\n  using TimeLibrary for uint32;\n\n  /// @notice Stores offer details for a specific NFT.\n  struct Offer {\n    // Slot 1: When increasing an offer, only this slot is updated.\n    /// @notice The expiration timestamp of when this offer expires.\n    uint32 expiration;\n    /// @notice The amount, in wei, of the highest offer.\n    uint96 amount;\n    /// @notice First slot (of 16B) used for the offerReferrerAddress.\n    // The offerReferrerAddress is the address used to pay the\n    // referrer on an accepted offer.\n    uint128 offerReferrerAddressSlot0;\n    // Slot 2: When the buyer changes, both slots need updating\n    /// @notice The address of the collector who made this offer.\n    address buyer;\n    /// @notice Second slot (of 4B) used for the offerReferrerAddress.\n    uint32 offerReferrerAddressSlot1;\n    // 96 bits (12B) are available in slot 1.\n  }\n\n  /// @notice Stores the highest offer for each NFT.\n  mapping(address => mapping(uint256 => Offer)) private nftContractToIdToOffer;\n\n  /**\n   * @notice Emitted when an offer is accepted,\n   * indicating that the NFT has been transferred and revenue from the sale distributed.\n   * @dev The accepted total offer amount is `totalFees` + `creatorRev` + `sellerRev`.\n   * @param nftContract The address of the NFT contract.\n   * @param tokenId The id of the NFT.\n   * @param buyer The address of the collector that made the offer which was accepted.\n   * @param seller The address of the seller which accepted the offer.\n   * @param totalFees The amount of ETH that was sent to Foundation & referrals for this sale.\n   * @param creatorRev The amount of ETH that was sent to the creator for this sale.\n   * @param sellerRev The amount of ETH that was sent to the owner for this sale.\n   */\n  event OfferAccepted(\n    address indexed nftContract,\n    uint256 indexed tokenId,\n    address indexed buyer,\n    address seller,\n    uint256 totalFees,\n    uint256 creatorRev,\n    uint256 sellerRev\n  );\n  /**\n   * @notice Emitted when an offer is invalidated due to other market activity.\n   * When this occurs, the collector which made the offer has their FETH balance unlocked\n   * and the funds are available to place other offers or to be withdrawn.\n   * @dev This occurs when the offer is no longer eligible to be accepted,\n   * e.g. when a bid is placed in an auction for this NFT.\n   * @param nftContract The address of the NFT contract.\n   * @param tokenId The id of the NFT.\n   */\n  event OfferInvalidated(address indexed nftContract, uint256 indexed tokenId);\n  /**\n   * @notice Emitted when an offer is made.\n   * @dev The `amount` of the offer is locked in the FETH ERC-20 contract, guaranteeing that the funds\n   * remain available until the `expiration` date.\n   * @param nftContract The address of the NFT contract.\n   * @param tokenId The id of the NFT.\n   * @param buyer The address of the collector that made the offer to buy this NFT.\n   * @param amount The amount, in wei, of the offer.\n   * @param expiration The expiration timestamp for the offer.\n   */\n  event OfferMade(\n    address indexed nftContract,\n    uint256 indexed tokenId,\n    address indexed buyer,\n    uint256 amount,\n    uint256 expiration\n  );\n\n  /**\n   * @notice Accept the highest offer for an NFT.\n   * @dev The offer must not be expired and the NFT owned + approved by the seller or\n   * available in the market contract's escrow.\n   * @param nftContract The address of the NFT contract.\n   * @param tokenId The id of the NFT.\n   * @param offerFrom The address of the collector that you wish to sell to.\n   * If the current highest offer is not from this user, the transaction will revert.\n   * This could happen if a last minute offer was made by another collector,\n   * and would require the seller to try accepting again.\n   * @param minAmount The minimum value of the highest offer for it to be accepted.\n   * If the value is less than this amount, the transaction will revert.\n   * This could happen if the original offer expires and is replaced with a smaller offer.\n   */\n  function acceptOffer(\n    address nftContract,\n    uint256 tokenId,\n    address offerFrom,\n    uint256 minAmount\n  ) external nonReentrant {\n    Offer storage offer = nftContractToIdToOffer[nftContract][tokenId];\n    // Validate offer expiry and amount\n    if (offer.expiration.hasExpired()) {\n      revert NFTMarketOffer_Offer_Expired(offer.expiration);\n    } else if (offer.amount < minAmount) {\n      revert NFTMarketOffer_Offer_Below_Min_Amount(offer.amount);\n    }\n    // Validate the buyer\n    if (offer.buyer != offerFrom) {\n      revert NFTMarketOffer_Offer_From_Does_Not_Match(offer.buyer);\n    }\n\n    _acceptOffer(nftContract, tokenId);\n  }\n\n  /**\n   * @notice Make an offer for any NFT which is valid for 24-25 hours.\n   * The funds will be locked in the FETH token contract and become available once the offer is outbid or has expired.\n   * @dev An offer may be made for an NFT before it is minted, although we generally not recommend you do that.\n   * If there is a buy price set at this price or lower, that will be accepted instead of making an offer.\n   * `msg.value` must be <= `amount` and any delta will be taken from the account's available FETH balance.\n   * @param nftContract The address of the NFT contract.\n   * @param tokenId The id of the NFT.\n   * @param amount The amount to offer for this NFT.\n   * @param referrer The referrer address for the offer.\n   * @return expiration The timestamp for when this offer will expire.\n   * This is provided as a return value in case another contract would like to leverage this information,\n   * user's should refer to the expiration in the `OfferMade` event log.\n   * If the buy price is accepted instead, `0` is returned as the expiration since that's n/a.\n   */\n  function makeOfferV2(\n    address nftContract,\n    uint256 tokenId,\n    uint256 amount,\n    address payable referrer\n  ) external payable returns (uint256 expiration) {\n    // If there is a buy price set at this price or lower, accept that instead.\n    if (_autoAcceptBuyPrice(nftContract, tokenId, amount)) {\n      // If the buy price is accepted, `0` is returned as the expiration since that's n/a.\n      return 0;\n    }\n\n    if (_isInActiveAuction(nftContract, tokenId)) {\n      revert NFTMarketOffer_Cannot_Be_Made_While_In_Auction();\n    }\n\n    Offer storage offer = nftContractToIdToOffer[nftContract][tokenId];\n    address sender = _msgSender();\n\n    if (offer.expiration.hasExpired()) {\n      // This is a new offer for the NFT (no other offer found or the previous offer expired)\n\n      // Lock the offer amount in FETH until the offer expires in 24-25 hours.\n      expiration = feth.marketLockupFor{ value: msg.value }(sender, amount);\n    } else {\n      // A previous offer exists and has not expired\n\n      uint256 minIncrement = _getMinIncrement(offer.amount);\n      if (amount < minIncrement) {\n        // A non-trivial increase in price is required to avoid sniping\n        revert NFTMarketOffer_Offer_Must_Be_At_Least_Min_Amount(minIncrement);\n      }\n\n      // Unlock the previous offer so that the FETH tokens are available for other offers or to transfer / withdraw\n      // and lock the new offer amount in FETH until the offer expires in 24-25 hours.\n      expiration = feth.marketChangeLockup{ value: msg.value }(\n        offer.buyer,\n        offer.expiration,\n        offer.amount,\n        sender,\n        amount\n      );\n    }\n\n    // Record offer details\n    offer.buyer = sender;\n    // The FETH contract guarantees that the expiration fits into 32 bits.\n    offer.expiration = uint32(expiration);\n    // `amount` is capped by the ETH provided, which cannot realistically overflow 96 bits.\n    offer.amount = uint96(amount);\n\n    if (referrer == address(feth)) {\n      // FETH cannot be paid as a referrer, clear the value instead.\n      referrer = payable(0);\n    }\n\n    // Set offerReferrerAddressSlot0 to the first 16B of the referrer address.\n    // By shifting the referrer 32 bits to the right we obtain the first 16B.\n    offer.offerReferrerAddressSlot0 = uint128(uint160(address(referrer)) >> 32);\n    // Set offerReferrerAddressSlot1 to the last 4B of the referrer address.\n    // By casting the referrer address to 32bits we discard the first 16B.\n    offer.offerReferrerAddressSlot1 = uint32(uint160(address(referrer)));\n\n    emit OfferMade(nftContract, tokenId, sender, amount, expiration);\n  }\n\n  /**\n   * @notice Accept the highest offer for an NFT from the `msg.sender` account.\n   * The NFT will be transferred to the buyer and revenue from the sale will be distributed.\n   * @dev The caller must validate the expiry and amount before calling this helper.\n   * This may invalidate other market tools, such as clearing the buy price if set.\n   */\n  function _acceptOffer(address nftContract, uint256 tokenId) private {\n    Offer memory offer = nftContractToIdToOffer[nftContract][tokenId];\n\n    // Remove offer\n    delete nftContractToIdToOffer[nftContract][tokenId];\n    // Withdraw ETH from the buyer's account in the FETH token contract.\n    feth.marketWithdrawLocked(offer.buyer, offer.expiration, offer.amount);\n\n    address payable sender = payable(_msgSender());\n\n    (address payable sellerReferrerPaymentAddress, uint16 sellerReferrerTakeRateInBasisPoints) = _getWorldForPayment(\n      sender,\n      nftContract,\n      tokenId,\n      offer.buyer,\n      offer.amount\n    );\n\n    // Transfer the NFT to the buyer.\n    address owner = IERC721(nftContract).ownerOf(tokenId);\n    if (owner == address(this)) {\n      // The NFT is currently in escrow (e.g. it has a buy price set)\n      // This should revert if `msg.sender` is not the owner of this NFT or if the NFT is in active auction.\n      _transferFromEscrow(nftContract, tokenId, offer.buyer, sender);\n    } else {\n      // NFT should be in the seller's wallet. If attempted by the wrong sender or if the market is not approved this\n      // will revert.\n      IERC721(nftContract).transferFrom(sender, offer.buyer, tokenId);\n    }\n\n    // Distribute revenue for this sale leveraging the ETH received from the FETH contract in the line above.\n    (uint256 totalFees, uint256 creatorRev, uint256 sellerRev) = _distributeFunds(\n      DistributeFundsParams({\n        nftContract: nftContract,\n        firstTokenId: tokenId,\n        nftCount: 1,\n        nftRecipientIfKnown: offer.buyer,\n        seller: sender,\n        price: offer.amount,\n        buyReferrer: _getOfferReferrerFromSlots(offer.offerReferrerAddressSlot0, offer.offerReferrerAddressSlot1),\n        sellerReferrerPaymentAddress: sellerReferrerPaymentAddress,\n        sellerReferrerTakeRateInBasisPoints: sellerReferrerTakeRateInBasisPoints,\n        fixedProtocolFeeInWei: 0\n      })\n    );\n\n    emit OfferAccepted(nftContract, tokenId, offer.buyer, sender, totalFees, creatorRev, sellerRev);\n  }\n\n  /**\n   * @inheritdoc NFTMarketCore\n   * @dev Invalidates the highest offer when an auction is kicked off, if one is found.\n   */\n  function _beforeAuctionStarted(address nftContract, uint256 tokenId) internal virtual override {\n    _invalidateOffer(nftContract, tokenId);\n    super._beforeAuctionStarted(nftContract, tokenId);\n  }\n\n  /**\n   * @inheritdoc NFTMarketCore\n   */\n  function _autoAcceptOffer(address nftContract, uint256 tokenId, uint256 minAmount) internal override returns (bool) {\n    Offer storage offer = nftContractToIdToOffer[nftContract][tokenId];\n    if (offer.expiration.hasExpired() || offer.amount < minAmount) {\n      // No offer found, the most recent offer is now expired, or the highest offer is below the minimum amount.\n      return false;\n    }\n\n    _acceptOffer(nftContract, tokenId);\n    return true;\n  }\n\n  /**\n   * @inheritdoc NFTMarketCore\n   */\n  function _cancelSendersOffer(address nftContract, uint256 tokenId) internal override {\n    Offer storage offer = nftContractToIdToOffer[nftContract][tokenId];\n    if (offer.buyer == _msgSender()) {\n      _invalidateOffer(nftContract, tokenId);\n    }\n  }\n\n  /**\n   * @notice Invalidates the offer and frees ETH from escrow, if the offer has not already expired.\n   * @dev Offers are not invalidated when the NFT is purchased by accepting the buy price unless it\n   * was purchased by the same user.\n   * The user which just purchased the NFT may have buyer's remorse and promptly decide they want a fast exit,\n   * accepting a small loss to limit their exposure.\n   */\n  function _invalidateOffer(address nftContract, uint256 tokenId) private {\n    if (!nftContractToIdToOffer[nftContract][tokenId].expiration.hasExpired()) {\n      // An offer was found and it has not already expired\n      Offer memory offer = nftContractToIdToOffer[nftContract][tokenId];\n\n      // Remove offer\n      delete nftContractToIdToOffer[nftContract][tokenId];\n\n      // Unlock the offer so that the FETH tokens are available for other offers or to transfer / withdraw\n      feth.marketUnlockFor(offer.buyer, offer.expiration, offer.amount);\n\n      emit OfferInvalidated(nftContract, tokenId);\n    }\n  }\n\n  /**\n   * @notice Returns the minimum amount a collector must offer for this NFT in order for the offer to be valid.\n   * @dev Offers for this NFT which are less than this value will revert.\n   * Once the previous offer has expired smaller offers can be made.\n   * @param nftContract The address of the NFT contract.\n   * @param tokenId The id of the NFT.\n   * @return minimum The minimum amount that must be offered for this NFT.\n   */\n  function getMinOfferAmount(address nftContract, uint256 tokenId) external view returns (uint256 minimum) {\n    Offer storage offer = nftContractToIdToOffer[nftContract][tokenId];\n    if (!offer.expiration.hasExpired()) {\n      return _getMinIncrement(offer.amount);\n    }\n    // Absolute min is anything > 0\n    return 1;\n  }\n\n  /**\n   * @notice Returns details about the current highest offer for an NFT.\n   * @dev Default values are returned if there is no offer or the offer has expired.\n   * @param nftContract The address of the NFT contract.\n   * @param tokenId The id of the NFT.\n   * @return buyer The address of the buyer that made the current highest offer.\n   * Returns `address(0)` if there is no offer or the most recent offer has expired.\n   * @return expiration The timestamp that the current highest offer expires.\n   * Returns `0` if there is no offer or the most recent offer has expired.\n   * @return amount The amount being offered for this NFT.\n   * Returns `0` if there is no offer or the most recent offer has expired.\n   */\n  function getOffer(\n    address nftContract,\n    uint256 tokenId\n  ) external view returns (address buyer, uint256 expiration, uint256 amount) {\n    Offer storage offer = nftContractToIdToOffer[nftContract][tokenId];\n    if (offer.expiration.hasExpired()) {\n      // Offer not found or has expired\n      return (address(0), 0, 0);\n    }\n\n    // An offer was found and it has not yet expired.\n    return (offer.buyer, offer.expiration, offer.amount);\n  }\n\n  /**\n   * @notice Returns the current highest offer's referral for an NFT.\n   * @dev Default value of `payable(0)` is returned if\n   * there is no offer, the offer has expired or does not have a referral.\n   * @param nftContract The address of the NFT contract.\n   * @param tokenId The id of the NFT.\n   * @return referrer The payable address of the referrer for the offer.\n   */\n  function getOfferReferrer(address nftContract, uint256 tokenId) external view returns (address payable referrer) {\n    Offer storage offer = nftContractToIdToOffer[nftContract][tokenId];\n    if (offer.expiration.hasExpired()) {\n      // Offer not found or has expired\n      return payable(0);\n    }\n    return _getOfferReferrerFromSlots(offer.offerReferrerAddressSlot0, offer.offerReferrerAddressSlot1);\n  }\n\n  function _getOfferReferrerFromSlots(\n    uint128 offerReferrerAddressSlot0,\n    uint32 offerReferrerAddressSlot1\n  ) private pure returns (address payable referrer) {\n    // Stitch offerReferrerAddressSlot0 and offerReferrerAddressSlot1 to obtain the payable offerReferrerAddress.\n    // Left shift offerReferrerAddressSlot0 by 32 bits OR it with offerReferrerAddressSlot1.\n    referrer = payable(address((uint160(offerReferrerAddressSlot0) << 32) | uint160(offerReferrerAddressSlot1)));\n  }\n\n  /**\n   * @inheritdoc NFTMarketCore\n   */\n  function _transferFromEscrowIfAvailable(\n    address nftContract,\n    uint256 tokenId,\n    address originalSeller\n  ) internal virtual override(NFTMarketCore, NFTMarketWorlds) {\n    super._transferFromEscrowIfAvailable(nftContract, tokenId, originalSeller);\n  }\n\n  /**\n   * @notice This empty reserved space is put in place to allow future versions to add new variables without shifting\n   * down storage in the inheritance chain. See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n   */\n  uint256[1_000] private __gap;\n}\n"
      },
      "contracts/mixins/nftMarket/NFTMarketPrivateSaleGap.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\n\npragma solidity ^0.8.18;\n\n/**\n * @title Reserves space previously occupied by private sales.\n * @author batu-inal & HardlyDifficult\n */\nabstract contract NFTMarketPrivateSaleGap {\n  // Original data:\n  // bytes32 private __gap_was_DOMAIN_SEPARATOR;\n  // mapping(address => mapping(uint256 => mapping(address => mapping(address => mapping(uint256 =>\n  //   mapping(uint256 => bool)))))) private privateSaleInvalidated;\n  // uint256[999] private __gap;\n\n  /**\n   * @notice This empty reserved space is put in place to allow future versions to add new variables without shifting\n   * down storage in the inheritance chain. See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n   * @dev 1 slot was consumed by privateSaleInvalidated.\n   */\n  uint256[1001] private __gap;\n}\n"
      },
      "contracts/mixins/nftMarket/NFTMarketReserveAuction.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\n\npragma solidity ^0.8.18;\n\n// solhint-disable max-line-length\nimport { INFTMarketReserveAuction } from \"../../interfaces/internal/routes/INFTMarketReserveAuction.sol\";\nimport { INFTMarketGetters } from \"../../interfaces/internal/INFTMarketGetters.sol\";\n\nimport { ContextUpgradeable } from \"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol\";\nimport { ReentrancyGuardUpgradeable } from \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\n\nimport \"../shared/Constants.sol\";\nimport { ReserveAuctionLibrary } from \"../../libraries/ReserveAuctionLibrary.sol\";\nimport { TimeLibrary } from \"../../libraries/TimeLibrary.sol\";\nimport { ReserveAuction } from \"../shared/MarketStructs.sol\";\n\nimport { FETHNode } from \"../shared/FETHNode.sol\";\nimport { MarketFees } from \"../shared/MarketFees.sol\";\nimport { MarketSharedCore } from \"../shared/MarketSharedCore.sol\";\nimport { WorldsNftNode } from \"../shared/WorldsNftNode.sol\";\nimport { SendValueWithFallbackWithdraw } from \"../shared/SendValueWithFallbackWithdraw.sol\";\nimport { NFTMarketAuction } from \"./NFTMarketAuction.sol\";\nimport { NFTMarketCore } from \"./NFTMarketCore.sol\";\nimport { NFTMarketWorlds } from \"./NFTMarketWorlds.sol\";\nimport { NFTMarketScheduling } from \"./NFTMarketScheduling.sol\";\n// solhint-enable max-line-length\n\n/// @param auctionId The already listed auctionId for this NFT.\nerror NFTMarketReserveAuction_Already_Listed(uint256 auctionId);\n/// @param minAmount The minimum amount that must be bid in order for it to be accepted.\nerror NFTMarketReserveAuction_Bid_Must_Be_At_Least_Min_Amount(uint256 minAmount);\n/// @param reservePrice The current reserve price.\nerror NFTMarketReserveAuction_Cannot_Bid_Lower_Than_Reserve_Price(uint256 reservePrice);\n/// @param endTime The timestamp at which the auction had ended.\nerror NFTMarketReserveAuction_Cannot_Bid_On_Ended_Auction(uint256 endTime);\nerror NFTMarketReserveAuction_Cannot_Bid_On_Nonexistent_Auction();\nerror NFTMarketReserveAuction_Cannot_Finalize_Already_Settled_Auction();\n/// @param endTime The timestamp at which the auction will end.\nerror NFTMarketReserveAuction_Cannot_Finalize_Auction_In_Progress(uint256 endTime);\nerror NFTMarketReserveAuction_Cannot_Rebid_Over_Outstanding_Bid();\nerror NFTMarketReserveAuction_Cannot_Update_Auction_In_Progress();\nerror NFTMarketReserveAuction_Cannot_Update_Nft_While_Auction_In_Progress();\nerror NFTMarketReserveAuction_Cannot_Update_Sale_Starts_At_Auction_In_Progress();\n/// @param seller The current owner of the NFT.\nerror NFTMarketReserveAuction_Not_Matching_Seller(address seller);\n/// @param owner The current owner of the NFT.\nerror NFTMarketReserveAuction_Only_Owner_Can_Update_Sale_Starts_At(address owner);\nerror NFTMarketReserveAuction_Price_Already_Set();\n\n/**\n * @title Allows the owner of an NFT to list it in auction.\n * @notice NFTs in auction are escrowed in the market contract.\n * @dev There is room to optimize the storage for auctions, significantly reducing gas costs.\n * This may be done in the future, but for now it will remain as is in order to ease upgrade compatibility.\n * @author batu-inal & HardlyDifficult & reggieag\n */\nabstract contract NFTMarketReserveAuction is\n  INFTMarketGetters,\n  INFTMarketReserveAuction,\n  WorldsNftNode,\n  ContextUpgradeable,\n  FETHNode,\n  MarketSharedCore,\n  NFTMarketCore,\n  ReentrancyGuardUpgradeable,\n  SendValueWithFallbackWithdraw,\n  MarketFees,\n  NFTMarketWorlds,\n  NFTMarketScheduling,\n  NFTMarketAuction\n{\n  using TimeLibrary for uint256;\n\n  /// @notice Stores the auction configuration for a specific NFT.\n  /// @dev This allows us to modify the storage struct without changing external APIs.\n  struct ReserveAuctionStorage {\n    // Slot 0\n    /// @notice The address of the NFT contract.\n    address nftContract;\n    // (96-bits free space)\n\n    // Slot 1\n    /// @notice The id of the NFT.\n    uint256 tokenId;\n    // (slot full)\n\n    // Slot 2\n    /// @notice The owner of the NFT which listed it in auction.\n    address payable seller;\n    /// @notice First slot (12 bytes) used for the bidReferrerAddress.\n    /// The bidReferrerAddress is the address used to pay the referrer on finalize.\n    /// @dev This approach is used in order to pack storage, saving gas.\n    uint96 bidReferrerAddressSlot0;\n    // (slot full)\n\n    // Slot 3\n    /// @dev This field is no longer used but was previously assigned to.\n    uint256 __gap_was_duration;\n    // (slot full)\n\n    // Slot 4\n    /// @dev This field is no longer used but was previous assigned to.\n    uint256 __gap_was_extensionDuration;\n    // (slot full)\n\n    // Slot 5\n    /// @notice The time at which this auction will not accept any new bids.\n    /// @dev This is `0` until the first bid is placed.\n    uint256 endTime;\n    // (slot full)\n\n    // Slot 6\n    /// @notice The current highest bidder in this auction.\n    /// @dev This is `address(0)` until the first bid is placed.\n    address payable bidder;\n    /// @notice Second slot (8 bytes) used for the bidReferrerAddress.\n    uint64 bidReferrerAddressSlot1;\n    /// @dev Auction duration length in seconds.\n    uint32 duration;\n    // (slot full)\n\n    // Slot 7\n    /// @notice The latest price of the NFT in this auction.\n    /// @dev This is set to the reserve price, and then to the highest bid once the auction has started.\n    uint256 amount;\n    // (slot full)\n  }\n\n  /// @notice The auction configuration for a specific auction id.\n  mapping(address nftContract => mapping(uint256 tokenId => uint256 auctionId)) private nftContractToTokenIdToAuctionId;\n  /// @notice The auction id for a specific NFT.\n  /// @dev This is deleted when an auction is finalized or canceled.\n  mapping(uint256 => ReserveAuctionStorage) private auctionIdToAuction;\n\n  /**\n   * @dev Removing old unused variables in an upgrade safe way. Was:\n   * uint256 private __gap_was_minPercentIncrementInBasisPoints;\n   * uint256 private __gap_was_maxBidIncrementRequirement;\n   * uint256 private __gap_was_duration;\n   * uint256 private __gap_was_extensionDuration;\n   * uint256 private __gap_was_goLiveDate;\n   */\n  uint256[5] private __gap_was_config;\n\n  /**\n   * @notice Emitted when a bid is placed.\n   * @param auctionId The id of the auction this bid was for.\n   * @param bidder The address of the bidder.\n   * @param amount The amount of the bid.\n   * @param endTime The new end time of the auction (which may have been set or extended by this bid).\n   */\n  event ReserveAuctionBidPlaced(uint256 indexed auctionId, address indexed bidder, uint256 amount, uint256 endTime);\n\n  /**\n   * @notice Emitted when an auction is canceled.\n   * @dev This is only possible if the auction has not received any bids.\n   * @param auctionId The id of the auction that was canceled.\n   */\n  event ReserveAuctionCanceled(uint256 indexed auctionId);\n\n  /**\n   * @notice Emitted when an NFT is listed for auction.\n   * @param seller The address of the seller.\n   * @param nftContract The address of the NFT contract.\n   * @param tokenId The id of the NFT.\n   * @param duration The duration of the auction (always 24-hours).\n   * @param extensionDuration The duration of the auction extension window when the auction was created.\n   * Note: The current extension duration may not be the same as the duration when the auction was created.\n   * @param reservePrice The reserve price to kick off the auction.\n   * @param auctionId The id of the auction that was created.\n   */\n  event ReserveAuctionCreated(\n    address indexed seller,\n    address indexed nftContract,\n    uint256 indexed tokenId,\n    uint256 duration,\n    uint256 extensionDuration,\n    uint256 reservePrice,\n    uint256 auctionId\n  );\n\n  /**\n   * @notice Emitted when an auction that has already ended is finalized,\n   * indicating that the NFT has been transferred and revenue from the sale distributed.\n   * @dev The amount of the highest bid / final sale price for this auction\n   * is `totalFees` + `creatorRev` + `sellerRev`.\n   * @param auctionId The id of the auction that was finalized.\n   * @param seller The address of the seller.\n   * @param bidder The address of the highest bidder that won the NFT.\n   * @param totalFees The amount of ETH that was sent to Foundation & referrals for this sale.\n   * @param creatorRev The amount of ETH that was sent to the creator for this sale.\n   * @param sellerRev The amount of ETH that was sent to the owner for this sale.\n   */\n  event ReserveAuctionFinalized(\n    uint256 indexed auctionId,\n    address indexed seller,\n    address indexed bidder,\n    uint256 totalFees,\n    uint256 creatorRev,\n    uint256 sellerRev\n  );\n\n  /**\n   * @notice Emitted when an auction is invalidated due to other market activity.\n   * @dev This occurs when the NFT is sold another way, such as with `buy` or `acceptOffer`.\n   * @param auctionId The id of the auction that was invalidated.\n   */\n  event ReserveAuctionInvalidated(uint256 indexed auctionId);\n\n  /**\n   * @notice Emitted when the auction's reserve price is changed.\n   * @dev This is only possible if the auction has not received any bids.\n   * @param auctionId The id of the auction that was updated.\n   * @param reservePrice The new reserve price for the auction.\n   */\n  event ReserveAuctionUpdated(uint256 indexed auctionId, uint256 reservePrice);\n\n  /**\n   * @notice If an auction has been created but has not yet received bids, it may be canceled by the seller.\n   * @dev The NFT is transferred back to the owner unless there is still a buy price set.\n   * @param auctionId The id of the auction to cancel.\n   */\n  function cancelReserveAuction(uint256 auctionId) external nonReentrant {\n    ReserveAuctionStorage memory auction = auctionIdToAuction[auctionId];\n    address sender = _msgSender();\n    ReserveAuctionLibrary.validateCalledBySeller(sender, auction.seller);\n    if (auction.endTime != 0) {\n      revert NFTMarketReserveAuction_Cannot_Update_Auction_In_Progress();\n    }\n\n    // Remove the auction.\n    delete nftContractToTokenIdToAuctionId[auction.nftContract][auction.tokenId];\n    delete auctionIdToAuction[auctionId];\n\n    // Transfer the NFT unless it still has a buy price set.\n    _transferFromEscrowIfAvailable(auction.nftContract, auction.tokenId, sender);\n\n    emit ReserveAuctionCanceled(auctionId);\n  }\n\n  /**\n   * @notice Creates an auction for the given NFT.\n   * The NFT is held in escrow until the auction is finalized or canceled.\n   * @param nftContract The address of the NFT contract.\n   * @param tokenId The id of the NFT.\n   * @param reservePrice The initial reserve price for the auction.\n   * @param duration The length of the auction, in seconds.\n   * @return auctionId The id of the auction that was created.\n   */\n  function createReserveAuction(\n    address nftContract,\n    uint256 tokenId,\n    uint256 reservePrice,\n    uint256 duration\n  ) external nonReentrant returns (uint256 auctionId) {\n    duration = ReserveAuctionLibrary.validateReserveAuctionConfig(reservePrice, duration);\n    auctionId = _getNextAndIncrementAuctionId();\n\n    // If the `msg.sender` is not the owner of the NFT, transferring into escrow should fail.\n    _transferToEscrow(nftContract, tokenId);\n\n    // This check must be after _transferToEscrow in case auto-settle was required\n    if (nftContractToTokenIdToAuctionId[nftContract][tokenId] != 0) {\n      revert NFTMarketReserveAuction_Already_Listed(nftContractToTokenIdToAuctionId[nftContract][tokenId]);\n    }\n\n    // Store the auction details\n    address payable sender = payable(_msgSender());\n    nftContractToTokenIdToAuctionId[nftContract][tokenId] = auctionId;\n    ReserveAuctionStorage storage auction = auctionIdToAuction[auctionId];\n    auction.nftContract = nftContract;\n    auction.tokenId = tokenId;\n    auction.seller = sender;\n    auction.amount = reservePrice;\n    if (duration != DEFAULT_DURATION) {\n      // If duration is DEFAULT_DURATION, we don't need to write to storage.\n      // Safe cast is not required since duration is capped by MAX_DURATION.\n      auction.duration = uint32(duration);\n    }\n\n    emit ReserveAuctionCreated({\n      seller: sender,\n      nftContract: nftContract,\n      tokenId: tokenId,\n      duration: duration,\n      extensionDuration: EXTENSION_DURATION,\n      reservePrice: reservePrice,\n      auctionId: auctionId\n    });\n  }\n\n  /**\n   * @notice Once the countdown has expired for an auction, anyone can settle the auction.\n   * This will send the NFT to the highest bidder and distribute revenue for this sale.\n   * @param auctionId The id of the auction to settle.\n   */\n  function finalizeReserveAuction(uint256 auctionId) external nonReentrant {\n    if (auctionIdToAuction[auctionId].endTime == 0) {\n      revert NFTMarketReserveAuction_Cannot_Finalize_Already_Settled_Auction();\n    }\n    _finalizeReserveAuction({ auctionId: auctionId, keepInEscrow: false });\n  }\n\n  /**\n   * @notice Place a bid in an auction.\n   * A bidder may place a bid which is at least the amount defined by `getMinBidAmount`.\n   * If this is the first bid on the auction, the countdown will begin.\n   * If there is already an outstanding bid, the previous bidder will be refunded at this time\n   * and if the bid is placed in the final moments of the auction, the countdown may be extended.\n   * @dev `amount` - `msg.value` is withdrawn from the bidder's FETH balance.\n   * @param auctionId The id of the auction to bid on.\n   * @param amount The amount to bid, if this is more than `msg.value` funds will be withdrawn from your FETH balance.\n   * @param referrer The address of the referrer of this bid, or 0 if n/a.\n   */\n  function placeBidV2(uint256 auctionId, uint256 amount, address payable referrer) external payable nonReentrant {\n    ReserveAuctionStorage storage auction = auctionIdToAuction[auctionId];\n\n    if (auction.amount == 0) {\n      // No auction found\n      revert NFTMarketReserveAuction_Cannot_Bid_On_Nonexistent_Auction();\n    }\n\n    uint256 endTime = auction.endTime;\n    address payable sender = payable(_msgSender());\n\n    // Store the bid referral\n    if (referrer == address(feth)) {\n      // FETH cannot be paid as a referrer, clear the value instead.\n      referrer = payable(0);\n    }\n    if (referrer != address(0) || endTime != 0) {\n      auction.bidReferrerAddressSlot0 = uint96(uint160(address(referrer)) >> 64);\n      auction.bidReferrerAddressSlot1 = uint64(uint160(address(referrer)));\n    }\n\n    if (endTime == 0) {\n      // This is the first bid, kicking off the auction.\n\n      if (amount < auction.amount) {\n        // The bid must be >= the reserve price.\n        revert NFTMarketReserveAuction_Cannot_Bid_Lower_Than_Reserve_Price(auction.amount);\n      }\n\n      // Notify other market tools that an auction for this NFT has been kicked off.\n      // The only state change before this call is potentially withdrawing funds from FETH.\n      _beforeAuctionStarted(auction.nftContract, auction.tokenId);\n\n      // Store the bid details.\n      auction.amount = amount;\n      auction.bidder = sender;\n\n      // On the first bid, set the endTime to now + duration.\n      uint256 duration = auction.duration;\n      if (duration == 0) {\n        duration = DEFAULT_DURATION;\n      }\n      unchecked {\n        // Duration can't be more than MAX_DURATION (7 days), so the below can't overflow.\n        endTime = block.timestamp + duration;\n      }\n      auction.endTime = endTime;\n    } else {\n      if (endTime.hasExpired()) {\n        // The auction has already ended.\n        revert NFTMarketReserveAuction_Cannot_Bid_On_Ended_Auction(endTime);\n      } else if (auction.bidder == sender) {\n        // We currently do not allow a bidder to increase their bid unless another user has outbid them first.\n        revert NFTMarketReserveAuction_Cannot_Rebid_Over_Outstanding_Bid();\n      } else {\n        uint256 minIncrement = _getMinIncrement(auction.amount);\n        if (amount < minIncrement) {\n          // If this bid outbids another, it must be at least 10% greater than the last bid.\n          revert NFTMarketReserveAuction_Bid_Must_Be_At_Least_Min_Amount(minIncrement);\n        }\n      }\n\n      // Cache and update bidder state\n      uint256 originalAmount = auction.amount;\n      address payable originalBidder = auction.bidder;\n      auction.amount = amount;\n      auction.bidder = sender;\n\n      unchecked {\n        // When a bid outbids another, check to see if a time extension should apply.\n        // We confirmed that the auction has not ended, so endTime is always >= the current timestamp.\n        // Current time plus extension duration (always 2 mins) cannot overflow.\n        uint256 endTimeWithExtension = block.timestamp + EXTENSION_DURATION;\n        if (endTime < endTimeWithExtension) {\n          endTime = endTimeWithExtension;\n          auction.endTime = endTime;\n        }\n      }\n\n      // Refund the previous bidder\n      _sendValueWithFallbackWithdraw({\n        user: originalBidder,\n        amount: originalAmount,\n        gasLimit: SEND_VALUE_GAS_LIMIT_SINGLE_RECIPIENT\n      });\n    }\n\n    _tryUseFETHBalance({ fromAccount: sender, totalAmount: amount, shouldRefundSurplus: false });\n\n    emit ReserveAuctionBidPlaced({ auctionId: auctionId, bidder: sender, amount: amount, endTime: endTime });\n  }\n\n  /**\n   * @notice If an auction has been created but has not yet received bids, the reservePrice may be changed by the\n   * seller.\n   * @param auctionId The id of the auction to change.\n   * @param reservePrice The new reserve price for this auction.\n   */\n  function updateReserveAuction(uint256 auctionId, uint256 reservePrice) external {\n    ReserveAuctionLibrary.validateReserveAuctionPrice(reservePrice);\n    ReserveAuctionStorage storage auction = auctionIdToAuction[auctionId];\n    ReserveAuctionLibrary.validateCalledBySeller(_msgSender(), auction.seller);\n\n    if (auction.endTime != 0) {\n      revert NFTMarketReserveAuction_Cannot_Update_Auction_In_Progress();\n    }\n    if (auction.amount == reservePrice) {\n      revert NFTMarketReserveAuction_Price_Already_Set();\n    }\n\n    // Update the current reserve price.\n    auction.amount = reservePrice;\n\n    emit ReserveAuctionUpdated(auctionId, reservePrice);\n  }\n\n  /**\n   * @notice Settle an auction that has already ended.\n   * This will send the NFT to the highest bidder and distribute revenue for this sale.\n   * @param keepInEscrow If true, the NFT will be kept in escrow to save gas by avoiding\n   * redundant transfers if the NFT should remain in escrow, such as when the new owner\n   * sets a buy price or lists it in a new auction.\n   */\n  function _finalizeReserveAuction(uint256 auctionId, bool keepInEscrow) private {\n    ReserveAuctionStorage memory auction = auctionIdToAuction[auctionId];\n\n    if (!auction.endTime.hasExpired()) {\n      revert NFTMarketReserveAuction_Cannot_Finalize_Auction_In_Progress(auction.endTime);\n    }\n    (address payable sellerReferrerPaymentAddress, uint16 sellerReferrerTakeRateInBasisPoints) = _getWorldForPayment(\n      auction.seller,\n      auction.nftContract,\n      auction.tokenId,\n      auction.bidder,\n      auction.amount\n    );\n\n    // Remove the auction.\n    delete nftContractToTokenIdToAuctionId[auction.nftContract][auction.tokenId];\n    delete auctionIdToAuction[auctionId];\n\n    if (!keepInEscrow) {\n      // The seller was authorized when the auction was originally created\n      super._transferFromEscrow({\n        nftContract: auction.nftContract,\n        tokenId: auction.tokenId,\n        recipient: auction.bidder,\n        authorizeSeller: address(0)\n      });\n    }\n\n    // Distribute revenue for this sale.\n    (uint256 totalFees, uint256 creatorRev, uint256 sellerRev) = _distributeFunds(\n      DistributeFundsParams({\n        nftContract: auction.nftContract,\n        firstTokenId: auction.tokenId,\n        nftCount: 1,\n        nftRecipientIfKnown: auction.bidder,\n        seller: auction.seller,\n        price: auction.amount,\n        buyReferrer: payable(\n          address((uint160(auction.bidReferrerAddressSlot0) << 64) | uint160(auction.bidReferrerAddressSlot1))\n        ),\n        sellerReferrerPaymentAddress: sellerReferrerPaymentAddress,\n        sellerReferrerTakeRateInBasisPoints: sellerReferrerTakeRateInBasisPoints,\n        fixedProtocolFeeInWei: 0\n      })\n    );\n\n    emit ReserveAuctionFinalized(auctionId, auction.seller, auction.bidder, totalFees, creatorRev, sellerRev);\n  }\n\n  function _isAuthorizedScheduleUpdate(\n    address nftContract,\n    uint256 tokenId\n  ) internal view virtual override returns (bool canUpdateNft) {\n    uint256 auctionId = nftContractToTokenIdToAuctionId[nftContract][tokenId];\n\n    if (auctionId != 0) {\n      ReserveAuctionStorage storage auction = auctionIdToAuction[auctionId];\n\n      ReserveAuctionLibrary.validateCalledBySeller(_msgSender(), auction.seller);\n      if (auction.endTime != 0) {\n        revert NFTMarketReserveAuction_Cannot_Update_Nft_While_Auction_In_Progress();\n      }\n\n      canUpdateNft = true;\n    } else {\n      canUpdateNft = super._isAuthorizedScheduleUpdate(nftContract, tokenId);\n    }\n  }\n\n  /**\n   * @inheritdoc NFTMarketCore\n   * @dev If an auction is found:\n   *  - If the auction is over, it will settle the auction and confirm the new seller won the auction.\n   *  - If the auction has not received a bid, it will invalidate the auction.\n   *  - If the auction is in progress, this will revert.\n   */\n  function _transferFromEscrow(\n    address nftContract,\n    uint256 tokenId,\n    address recipient,\n    address authorizeSeller\n  ) internal virtual override {\n    uint256 auctionId = nftContractToTokenIdToAuctionId[nftContract][tokenId];\n    if (auctionId != 0) {\n      ReserveAuctionStorage storage auction = auctionIdToAuction[auctionId];\n      if (auction.endTime == 0) {\n        // The auction has not received any bids yet so it may be invalided.\n\n        if (authorizeSeller != address(0) && auction.seller != authorizeSeller) {\n          // The account trying to transfer the NFT is not the current owner.\n          revert NFTMarketReserveAuction_Not_Matching_Seller(auction.seller);\n        }\n\n        // Remove the auction.\n        delete nftContractToTokenIdToAuctionId[nftContract][tokenId];\n        delete auctionIdToAuction[auctionId];\n\n        emit ReserveAuctionInvalidated(auctionId);\n      } else {\n        // If the auction has ended, the highest bidder will be the new owner\n        // and if the auction is in progress, this will revert.\n\n        // `authorizeSeller != address(0)` does not apply here since an unsettled auction must go\n        // through this path to know who the authorized seller should be.\n        if (auction.bidder != authorizeSeller) {\n          revert NFTMarketReserveAuction_Not_Matching_Seller(auction.bidder);\n        }\n\n        // Finalization will revert if the auction has not yet ended.\n        _finalizeReserveAuction({ auctionId: auctionId, keepInEscrow: true });\n      }\n      // The seller authorization has been confirmed.\n      authorizeSeller = address(0);\n    }\n\n    super._transferFromEscrow(nftContract, tokenId, recipient, authorizeSeller);\n  }\n\n  /**\n   * @inheritdoc NFTMarketCore\n   * @dev Checks if there is an auction for this NFT before allowing the transfer to continue.\n   */\n  function _transferFromEscrowIfAvailable(\n    address nftContract,\n    uint256 tokenId,\n    address originalSeller\n  ) internal virtual override(NFTMarketCore, NFTMarketScheduling, NFTMarketWorlds) {\n    if (nftContractToTokenIdToAuctionId[nftContract][tokenId] == 0) {\n      // No auction was found\n      super._transferFromEscrowIfAvailable(nftContract, tokenId, originalSeller);\n    }\n  }\n\n  /**\n   * @inheritdoc NFTMarketCore\n   */\n  function _transferToEscrow(address nftContract, uint256 tokenId) internal virtual override {\n    uint256 auctionId = nftContractToTokenIdToAuctionId[nftContract][tokenId];\n    if (auctionId == 0) {\n      // NFT is not in auction\n      super._transferToEscrow(nftContract, tokenId);\n      return;\n    }\n    // Using storage saves gas since most of the data is not needed\n    ReserveAuctionStorage storage auction = auctionIdToAuction[auctionId];\n    address sender = _msgSender();\n    if (auction.endTime == 0) {\n      // Reserve price set, confirm the seller is a match\n      if (auction.seller != sender) {\n        revert NFTMarketReserveAuction_Not_Matching_Seller(auction.seller);\n      }\n    } else {\n      // Auction in progress, confirm the highest bidder is a match\n      if (auction.bidder != sender) {\n        revert NFTMarketReserveAuction_Not_Matching_Seller(auction.bidder);\n      }\n\n      // Finalize auction but leave NFT in escrow, reverts if the auction has not ended\n      _finalizeReserveAuction({ auctionId: auctionId, keepInEscrow: true });\n    }\n  }\n\n  /**\n   * @notice Returns the minimum amount a bidder must spend to participate in an auction.\n   * Bids must be greater than or equal to this value or they will revert.\n   * @param auctionId The id of the auction to check.\n   * @return minimum The minimum amount for a bid to be accepted.\n   */\n  function getMinBidAmount(uint256 auctionId) external view returns (uint256 minimum) {\n    ReserveAuctionStorage storage auction = auctionIdToAuction[auctionId];\n    if (auction.endTime == 0) {\n      return auction.amount;\n    }\n    return _getMinIncrement(auction.amount);\n  }\n\n  /**\n   * @notice Returns auction details for a given auctionId.\n   * @param auctionId The id of the auction to lookup.\n   */\n  function getReserveAuction(uint256 auctionId) external view returns (ReserveAuction memory auction) {\n    ReserveAuctionStorage storage auctionStorage = auctionIdToAuction[auctionId];\n    uint256 duration = auctionStorage.duration;\n    if (duration == 0) {\n      duration = DEFAULT_DURATION;\n    }\n    auction = ReserveAuction(\n      auctionStorage.nftContract,\n      auctionStorage.tokenId,\n      auctionStorage.seller,\n      duration,\n      EXTENSION_DURATION,\n      auctionStorage.endTime,\n      auctionStorage.bidder,\n      auctionStorage.amount\n    );\n  }\n\n  /**\n   * @notice Returns the auctionId for a given NFT, or 0 if no auction is found.\n   * @dev If an auction is canceled, it will not be returned. However the auction may be over and pending finalization.\n   * @param nftContract The address of the NFT contract.\n   * @param tokenId The id of the NFT.\n   * @return auctionId The id of the auction, or 0 if no auction is found.\n   */\n  function getReserveAuctionIdFor(address nftContract, uint256 tokenId) external view returns (uint256 auctionId) {\n    auctionId = nftContractToTokenIdToAuctionId[nftContract][tokenId];\n  }\n\n  /**\n   * @notice Returns the referrer for the current highest bid in the auction, or address(0).\n   */\n  function getReserveAuctionBidReferrer(uint256 auctionId) external view returns (address payable referrer) {\n    ReserveAuctionStorage storage auction = auctionIdToAuction[auctionId];\n    referrer = payable(\n      address((uint160(auction.bidReferrerAddressSlot0) << 64) | uint160(auction.bidReferrerAddressSlot1))\n    );\n  }\n\n  /**\n   * @inheritdoc MarketSharedCore\n   * @dev Returns the seller that has the given NFT in escrow for an auction,\n   * or bubbles the call up for other considerations.\n   */\n  function _getSellerOf(\n    address nftContract,\n    uint256 tokenId\n  ) internal view virtual override returns (address payable seller) {\n    seller = auctionIdToAuction[nftContractToTokenIdToAuctionId[nftContract][tokenId]].seller;\n    if (seller == address(0)) {\n      seller = super._getSellerOf(nftContract, tokenId);\n    }\n  }\n\n  /**\n   * @inheritdoc NFTMarketCore\n   */\n  function _isInActiveAuction(address nftContract, uint256 tokenId) internal view override returns (bool) {\n    uint256 auctionId = nftContractToTokenIdToAuctionId[nftContract][tokenId];\n    return auctionId != 0 && !auctionIdToAuction[auctionId].endTime.hasExpired();\n  }\n\n  ////////////////////////////////////////////////////////////////\n  // Inheritance Requirements\n  // (no-ops to avoid compile errors)\n  ////////////////////////////////////////////////////////////////\n\n  /**\n   * @inheritdoc NFTMarketCore\n   */\n  function _beforeAuctionStarted(\n    address nftContract,\n    uint256 tokenId\n  ) internal virtual override(NFTMarketCore, NFTMarketScheduling) {\n    super._beforeAuctionStarted(nftContract, tokenId);\n  }\n\n  /**\n   * @inheritdoc MarketFees\n   */\n  function _distributeFunds(\n    DistributeFundsParams memory params\n  )\n    internal\n    virtual\n    override(MarketFees, NFTMarketScheduling)\n    returns (uint256 totalFees, uint256 creatorRev, uint256 sellerRev)\n  {\n    (totalFees, creatorRev, sellerRev) = super._distributeFunds(params);\n  }\n\n  /**\n   * @notice This empty reserved space is put in place to allow future versions to add new variables without shifting\n   * down storage in the inheritance chain. See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n   */\n  uint256[1_000] private __gap;\n}\n"
      },
      "contracts/mixins/nftMarket/NFTMarketScheduling.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\n\npragma solidity ^0.8.18;\n\nimport \"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol\";\n\nimport \"../../libraries/TimeLibrary.sol\";\n\nimport \"../../interfaces/internal/routes/INFTMarketScheduling.sol\";\nimport \"../../interfaces/internal/INFTMarketGetters.sol\";\n\nimport \"../shared/Constants.sol\";\nimport \"../shared/MarketFees.sol\";\n\nimport \"./NFTMarketCore.sol\";\n\n// Errors when configuring a schedule\nerror NFTMarketScheduling_Sale_Starts_At_Already_Set();\nerror NFTMarketScheduling_Sale_Starts_At_Is_In_Past();\nerror NFTMarketScheduling_Sale_Starts_At_Too_Far_In_The_Future(uint256 maxStartsAt);\n\n// Errors when validating a schedule\nerror NFTMarketScheduling_Sale_Starts_At_Is_In_Future();\n\n/**\n * @title Allows listed NFTs to schedule a sale starts at time.\n * @dev This supports both Auctions and BuyNow.\n * @author HardlyDifficult & smhutch\n */\nabstract contract NFTMarketScheduling is\n  INFTMarketGetters,\n  INFTMarketScheduling,\n  ContextUpgradeable,\n  NFTMarketCore,\n  MarketFees\n{\n  using TimeLibrary for uint256;\n\n  /// @notice Stores the saleStartsAt time for listed NFTs\n  mapping(address => mapping(uint256 => uint256)) private $nftContractToTokenIdToSaleStartsAt;\n\n  /**\n   * @notice emitted when an a saleStartsAt time is changed for an NFT.\n   * @param nftContract The address of the NFT contract.\n   * @param tokenId The id of the NFT.\n   * @param operator The address that triggered this change.\n   * @param saleStartsAt The time at which the NFT will be available to buy or place bids on.\n   *  When zero, this represents that the NFT is unscheduled.\n   *  When above zero, this value represents the time in seconds since the Unix epoch.\n   */\n  event SetSaleStartsAt(\n    address indexed nftContract,\n    uint256 indexed tokenId,\n    address indexed operator,\n    uint256 saleStartsAt\n  );\n\n  ////////////////////////////////////////////////////////////////\n  // Configuration\n  ////////////////////////////////////////////////////////////////\n\n  /**\n   * @notice sets the saleStartsAt time for a listed NFT.\n   * @param nftContract The address of the NFT contract.\n   * @param tokenId The id of the NFT.\n   * @param saleStartsAt The time at which the NFT will be available to buy or place bids on.\n   *  When zero, the NFT has no saleStartsAt and can be purchased anytime.\n   *  When above zero, this value represents the time in seconds since the Unix epoch.\n   */\n  function setSaleStartsAt(address nftContract, uint256 tokenId, uint256 saleStartsAt) external {\n    // Check if it's already set first since this may be a common occurrence.\n    if ($nftContractToTokenIdToSaleStartsAt[nftContract][tokenId] == saleStartsAt) {\n      revert NFTMarketScheduling_Sale_Starts_At_Already_Set();\n    }\n\n    _authorizeScheduleUpdate(nftContract, tokenId);\n    if (saleStartsAt != 0) {\n      if (saleStartsAt.hasExpired()) {\n        revert NFTMarketScheduling_Sale_Starts_At_Is_In_Past();\n      }\n\n      if (saleStartsAt > block.timestamp + MAX_SCHEDULED_TIME_IN_THE_FUTURE) {\n        // Prevent arbitrarily large values from accidentally being set.\n        revert NFTMarketScheduling_Sale_Starts_At_Too_Far_In_The_Future(\n          block.timestamp + MAX_SCHEDULED_TIME_IN_THE_FUTURE\n        );\n      }\n    }\n\n    $nftContractToTokenIdToSaleStartsAt[nftContract][tokenId] = saleStartsAt;\n\n    emit SetSaleStartsAt({\n      nftContract: nftContract,\n      tokenId: tokenId,\n      operator: _msgSender(),\n      saleStartsAt: saleStartsAt\n    });\n  }\n\n  /**\n   * @notice Returns the saleStartsAt time for a listed NFT.\n   * @param nftContract The address of the NFT contract.\n   * @param tokenId The id of the NFT.\n   * @return saleStartsAt The time at which the NFT will be available to buy or place bids on.\n   * 0 if there is no schedule set and the NFT may be purchased anytime (or is not yet listed).\n   */\n  function getSaleStartsAt(address nftContract, uint256 tokenId) external view returns (uint256 saleStartsAt) {\n    saleStartsAt = $nftContractToTokenIdToSaleStartsAt[nftContract][tokenId];\n  }\n\n  ////////////////////////////////////////////////////////////////\n  // Validation\n  ////////////////////////////////////////////////////////////////\n\n  function _validateSaleStartsAtHasBeenReached(address nftContract, uint256 tokenId) internal view {\n    if (!$nftContractToTokenIdToSaleStartsAt[nftContract][tokenId].hasBeenReached()) {\n      revert NFTMarketScheduling_Sale_Starts_At_Is_In_Future();\n    }\n  }\n\n  /**\n   * @inheritdoc NFTMarketCore\n   * @dev Validates the saleStartsAt time for the NFT when the first bid is placed.\n   */\n  function _beforeAuctionStarted(address nftContract, uint256 tokenId) internal virtual override {\n    _validateSaleStartsAtHasBeenReached(nftContract, tokenId);\n    super._beforeAuctionStarted(nftContract, tokenId);\n  }\n\n  ////////////////////////////////////////////////////////////////\n  // Cleanup\n  ////////////////////////////////////////////////////////////////\n\n  function _clearScheduleIfSet(address nftContract, uint256 tokenId) private {\n    if ($nftContractToTokenIdToSaleStartsAt[nftContract][tokenId] != 0) {\n      // Clear the saleStartsAt time so that it does not apply to the next listing\n      delete $nftContractToTokenIdToSaleStartsAt[nftContract][tokenId];\n      emit SetSaleStartsAt({ nftContract: nftContract, tokenId: tokenId, operator: _msgSender(), saleStartsAt: 0 });\n    }\n  }\n\n  /**\n   * @dev When a sale occurs, clear the schedule if one was set.\n   */\n  function _distributeFunds(\n    DistributeFundsParams memory params\n  ) internal virtual override returns (uint256 totalFees, uint256 creatorRev, uint256 sellerRev) {\n    _clearScheduleIfSet(params.nftContract, params.firstTokenId);\n\n    (totalFees, creatorRev, sellerRev) = super._distributeFunds(params);\n  }\n\n  /**\n   * @dev Called when a listing is canceled. This mixin appears before the market tools in inheritance order, so when\n   * this is called we have already confirmed that the NFT is no longer listed and will indeed leave escrow.\n   */\n  function _transferFromEscrowIfAvailable(\n    address nftContract,\n    uint256 tokenId,\n    address originalSeller\n  ) internal virtual override {\n    _clearScheduleIfSet(nftContract, tokenId);\n\n    super._transferFromEscrowIfAvailable(nftContract, tokenId, originalSeller);\n  }\n\n  /**\n   * @notice This empty reserved space is put in place to allow future versions to add new variables without shifting\n   * down storage in the inheritance chain. See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n   * @dev This mixin uses 250 slots in total.\n   */\n  uint256[249] private __gap;\n}\n"
      },
      "contracts/mixins/nftMarket/NFTMarketWorlds.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\n\npragma solidity ^0.8.18;\n\nimport { IWorldsSoldByNft } from \"../../interfaces/internal/IWorldsSoldByNft.sol\";\n\nimport { NFTMarketCore } from \"./NFTMarketCore.sol\";\nimport { NFTMarketWorldsAPIs } from \"./NFTMarketWorldsAPIs.sol\";\n\n/**\n * @title Enables a curation surface for sellers to exhibit their NFTs.\n * @author HardlyDifficult\n * @dev [DEPRECATED] This mixin is being deprecated in favor of the Worlds NFT contract.\n */\nabstract contract NFTMarketWorlds is NFTMarketWorldsAPIs, NFTMarketCore {\n  // Was:\n  // struct Exhibition {\n  //   address payable curator;\n  //   uint16 takeRateInBasisPoints;\n  //   string name;\n  // }\n  // uint32 private $latestExhibitionId;\n  // bool private $worldMigrationCompleted;\n  // mapping(uint256 exhibitionId => Exhibition exhibitionDetails) private $idToExhibition;\n  // mapping(uint256 exhibitionId => mapping(address seller => bool isAllowed)) private $exhibitionIdToSellerToIsAllowed\n  // mapping(address nftContract => mapping(uint256 tokenId => uint256 exhibitionId))\n  //   private $nftContractToTokenIdToExhibitionId;\n  uint256[4] private __gap_was_exhibition;\n\n  /**\n   * @notice Returns World details if this NFT was assigned to one, and clears the assignment.\n   * @return worldPaymentAddress The address to send the payment to, or address(0) if n/a.\n   * @return takeRateInBasisPoints The rate of the sale which goes to the curator, or 0 if n/a.\n   */\n  function _getWorldForPayment(\n    address seller,\n    address nftContract,\n    uint256 tokenId,\n    address buyer,\n    uint256 salePrice\n  ) internal returns (address payable worldPaymentAddress, uint16 takeRateInBasisPoints) {\n    uint256 worldId;\n    (worldId, worldPaymentAddress, takeRateInBasisPoints) = IWorldsSoldByNft(worlds).soldInWorldByNft(\n      seller,\n      nftContract,\n      tokenId,\n      buyer,\n      salePrice\n    );\n\n    if (worldId != 0) {\n      // Clear the World association on sale\n      _removeFromWorldByNft(seller, nftContract, tokenId);\n    }\n  }\n\n  /**\n   * @inheritdoc NFTMarketCore\n   * @dev Removes the NFT from the World if it's listed.\n   */\n  function _transferFromEscrowIfAvailable(\n    address nftContract,\n    uint256 tokenId,\n    address originalSeller\n  ) internal virtual override {\n    // Clear the World association when removed from escrow.\n    _removeFromWorldByNftIfListed(originalSeller, nftContract, tokenId);\n\n    super._transferFromEscrowIfAvailable(nftContract, tokenId, originalSeller);\n  }\n\n  /**\n   * @notice This empty reserved space is put in place to allow future versions to add new variables without shifting\n   * down storage in the inheritance chain. See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n   * @dev This file uses a total of 250 slots.\n   */\n  uint256[246] private __gap;\n}\n"
      },
      "contracts/mixins/nftMarket/NFTMarketWorldsAPIs.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport { IWorldsSharedMarket } from \"../../interfaces/internal/IWorldsSharedMarket.sol\";\n\nimport { RouteCallLibrary } from \"../../libraries/RouteCallLibrary.sol\";\n\nimport { WorldsNftNode } from \"../shared/WorldsNftNode.sol\";\n\n/**\n * @title Routes calls to the Worlds contract, specifying to use the current _msgSender() as the caller.\n * @author HardlyDifficult\n */\nabstract contract NFTMarketWorldsAPIs is WorldsNftNode {\n  using RouteCallLibrary for address;\n\n  /**\n   * @param seller This is the seller which had originally listed the NFT, and may not be the current msg.sender.\n   */\n  function _removeFromWorldByNft(address seller, address nftContract, uint256 nftTokenId) internal {\n    seller.routeCallTo(worlds, abi.encodeCall(IWorldsSharedMarket.removeFromWorldByNft, (nftContract, nftTokenId)));\n  }\n\n  /**\n   * @param seller This is the seller which had originally listed the NFT, and may not be the current msg.sender.\n   */\n  function _removeFromWorldByNftIfListed(address seller, address nftContract, uint256 nftTokenId) internal {\n    (uint256 worldId, ) = IWorldsSharedMarket(worlds).getAssociationByNft(nftContract, nftTokenId, seller);\n    if (worldId != 0) {\n      seller.routeCallTo(worlds, abi.encodeCall(IWorldsSharedMarket.removeFromWorldByNft, (nftContract, nftTokenId)));\n    }\n  }\n}\n"
      },
      "contracts/mixins/shared/Constants.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\n\npragma solidity ^0.8.18;\n\n/// Constant values shared across mixins.\n\n/// @dev 100% in basis points.\nuint256 constant BASIS_POINTS = 10_000;\n\n/// @dev The default admin role defined by OZ ACL modules.\nbytes32 constant DEFAULT_ADMIN_ROLE = 0x00;\n\n/// @dev The `role` type used to validate drop collections have granted this market access to mint.\nbytes32 constant MINTER_ROLE = keccak256(\"MINTER_ROLE\");\n\n////////////////////////////////////////////////////////////////\n// Royalties & Take Rates\n////////////////////////////////////////////////////////////////\n\n/// @dev The max take rate a World can have.\nuint256 constant MAX_WORLD_TAKE_RATE = 5_000;\n\n/// @dev Cap the number of royalty recipients.\n/// A cap is required to ensure gas costs are not too high when a sale is settled.\nuint256 constant MAX_ROYALTY_RECIPIENTS = 5;\n\n/// @dev Default royalty cut paid out on secondary sales.\n/// Set to 10% of the secondary sale.\nuint96 constant ROYALTY_IN_BASIS_POINTS = 1_000;\n\n/// @dev Reward paid to referrers when a sale is made.\n/// Set to 20% of the protocol fee.\nuint96 constant BUY_REFERRER_IN_BASIS_POINTS = 2000;\n\n/// @dev 10%, expressed as a denominator for more efficient calculations.\nuint256 constant ROYALTY_RATIO = BASIS_POINTS / ROYALTY_IN_BASIS_POINTS;\n\n/// @dev 20%, expressed as a denominator for more efficient calculations.\nuint256 constant BUY_REFERRER_RATIO = BASIS_POINTS / BUY_REFERRER_IN_BASIS_POINTS;\n\n////////////////////////////////////////////////////////////////\n// Gas Limits\n////////////////////////////////////////////////////////////////\n\n/// @dev The gas limit used when making external read-only calls.\n/// This helps to ensure that external calls does not prevent the market from executing.\nuint256 constant READ_ONLY_GAS_LIMIT = 40_000;\n\n/// @dev The gas limit to send ETH to multiple recipients, enough for a 5-way split.\nuint256 constant SEND_VALUE_GAS_LIMIT_MULTIPLE_RECIPIENTS = 210_000;\n\n/// @dev The gas limit to send ETH to a single recipient, enough for a contract with a simple receiver.\nuint256 constant SEND_VALUE_GAS_LIMIT_SINGLE_RECIPIENT = 20_000;\n\n////////////////////////////////////////////////////////////////\n// Collection Type Names\n////////////////////////////////////////////////////////////////\n\n/// @dev The NFT collection type.\nstring constant NFT_COLLECTION_TYPE = \"NFT Collection\";\n\n/// @dev The NFT drop collection type.\nstring constant NFT_DROP_COLLECTION_TYPE = \"NFT Drop Collection\";\n\n/// @dev The NFT timed edition collection type.\nstring constant NFT_TIMED_EDITION_COLLECTION_TYPE = \"NFT Timed Edition Collection\";\n\n/// @dev The NFT limited edition collection type.\nstring constant NFT_LIMITED_EDITION_COLLECTION_TYPE = \"NFT Limited Edition Collection\";\n\n/// @dev The Multi-Token (ERC-1155) collection type.\nstring constant MULTI_TOKEN_COLLECTION_TYPE = \"Multi-Token Collection\";\n\n////////////////////////////////////////////////////////////////\n// Business Logic\n////////////////////////////////////////////////////////////////\n\n/// @dev Limits scheduled start/end times to be less than 2 years in the future.\nuint256 constant MAX_SCHEDULED_TIME_IN_THE_FUTURE = 365 days * 2;\n\n/// @dev The minimum increase of 10% required when making an offer or placing a bid.\nuint256 constant MIN_PERCENT_INCREMENT_DENOMINATOR = BASIS_POINTS / 1_000;\n\n/// @dev The fixed fee charged for each NFT minted.\nuint256 constant MINT_FEE_IN_WEI = 0.0008 ether;\n\n/// @dev Default for how long an auction lasts for once the first bid has been received.\nuint256 constant DEFAULT_DURATION = 1 days;\n\n/// @dev The window for auction extensions, any bid placed in the final 5 minutes\n/// of an auction will reset the time remaining to 5 minutes.\nuint256 constant EXTENSION_DURATION = 5 minutes;\n\n/// @dev Caps the max duration that may be configured for an auction.\nuint256 constant MAX_DURATION = 7 days;\n"
      },
      "contracts/mixins/shared/FETHNode.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport { IFethMarket } from \"../../interfaces/internal/IFethMarket.sol\";\n\nimport { AddressUpgradeable } from \"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\";\n\n/**\n * @title A mixin for interacting with the FETH contract.\n * @author batu-inal & HardlyDifficult\n */\nabstract contract FETHNode {\n  using AddressUpgradeable for address;\n  using AddressUpgradeable for address payable;\n\n  /// @notice The FETH ERC-20 token for managing escrow and lockup.\n  IFethMarket internal immutable feth;\n\n  error FETHNode_FETH_Address_Is_Not_A_Contract();\n  error FETHNode_Only_FETH_Can_Transfer_ETH();\n  error FethNode_Too_Much_Value_Provided(uint256 expectedValueAmount);\n\n  constructor(address _feth) {\n    if (!_feth.isContract()) {\n      revert FETHNode_FETH_Address_Is_Not_A_Contract();\n    }\n\n    feth = IFethMarket(_feth);\n  }\n\n  /**\n   * @notice Only used by FETH. Any direct transfer from users will revert.\n   */\n  receive() external payable {\n    if (msg.sender != address(feth)) {\n      revert FETHNode_Only_FETH_Can_Transfer_ETH();\n    }\n  }\n\n  /**\n   * @notice Withdraw the msg.sender's available FETH balance if they requested more than the msg.value provided.\n   * @dev This may revert if the msg.sender is non-receivable.\n   * This helper should not be used anywhere that may lead to locked assets.\n   * @param totalAmount The total amount of ETH required (including the msg.value).\n   * @param shouldRefundSurplus If true, refund msg.value - totalAmount to the msg.sender. Otherwise it will revert if\n   * the msg.value is greater than totalAmount.\n   */\n  function _tryUseFETHBalance(address payable fromAccount, uint256 totalAmount, bool shouldRefundSurplus) internal {\n    if (totalAmount > msg.value) {\n      // Withdraw additional ETH required from the user's available FETH balance.\n      unchecked {\n        // The if above ensures delta will not underflow.\n        // Withdraw ETH from the user's account in the FETH token contract,\n        // making the funds available in this contract as ETH.\n        feth.marketWithdrawFrom(fromAccount, totalAmount - msg.value);\n      }\n    } else if (totalAmount < msg.value) {\n      if (shouldRefundSurplus) {\n        // Return any surplus ETH to the user.\n        unchecked {\n          // The if above ensures this will not underflow\n          fromAccount.sendValue(msg.value - totalAmount);\n        }\n      } else {\n        revert FethNode_Too_Much_Value_Provided(totalAmount);\n      }\n    }\n  }\n\n  /**\n   * @notice Gets the FETH contract used to escrow offer funds.\n   * @return fethAddress The FETH contract address.\n   */\n  function getFethAddress() external view returns (address fethAddress) {\n    fethAddress = address(feth);\n  }\n}\n"
      },
      "contracts/mixins/shared/FoundationTreasuryNodeInterface.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nabstract contract FoundationTreasuryNodeInterface {\n  /**\n   * @notice Gets the Foundation treasury contract.\n   * @dev This call is used in the royalty registry contract.\n   * @return treasuryAddress The address of the Foundation treasury contract.\n   */\n  function getFoundationTreasury() public view virtual returns (address payable treasuryAddress);\n}\n"
      },
      "contracts/mixins/shared/FoundationTreasuryNodeV1.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport { AddressUpgradeable } from \"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\";\n\nimport { IAdminRole } from \"../../interfaces/internal/roles/IAdminRole.sol\";\nimport { IOperatorRole } from \"../../interfaces/internal/roles/IOperatorRole.sol\";\n\nimport { FoundationTreasuryNodeInterface } from \"./FoundationTreasuryNodeInterface.sol\";\n\n/**\n * @title Stores a reference to Foundation's treasury contract for other mixins to leverage.\n * @notice The treasury collects fees and defines admin/operator roles.\n * @author batu-inal & HardlyDifficult\n */\nabstract contract FoundationTreasuryNodeV1 is FoundationTreasuryNodeInterface {\n  using AddressUpgradeable for address payable;\n\n  /// @dev This value was replaced with an immutable version.\n  address payable private __gap_was_treasury;\n\n  /// @notice The address of the treasury contract.\n  address payable private immutable treasury;\n\n  error FoundationTreasuryNode_Address_Is_Not_A_Contract();\n  error FoundationTreasuryNode_Caller_Not_Admin();\n  error FoundationTreasuryNode_Caller_Not_Operator();\n\n  /// @notice Requires the caller is a Foundation admin.\n  modifier onlyFoundationAdmin() {\n    if (!IAdminRole(treasury).isAdmin(msg.sender)) {\n      revert FoundationTreasuryNode_Caller_Not_Admin();\n    }\n    _;\n  }\n\n  /// @notice Requires the caller is a Foundation operator.\n  modifier onlyFoundationOperator() {\n    if (!IOperatorRole(treasury).isOperator(msg.sender)) {\n      revert FoundationTreasuryNode_Caller_Not_Operator();\n    }\n    _;\n  }\n\n  /**\n   * @notice Set immutable variables for the implementation contract.\n   * @dev Assigns the treasury contract address.\n   */\n  constructor(address payable _treasury) {\n    if (!_treasury.isContract()) {\n      revert FoundationTreasuryNode_Address_Is_Not_A_Contract();\n    }\n\n    treasury = _treasury;\n  }\n\n  /// @inheritdoc FoundationTreasuryNodeInterface\n  function getFoundationTreasury() public view override returns (address payable treasuryAddress) {\n    treasuryAddress = treasury;\n  }\n\n  /**\n   * @notice This empty reserved space is put in place to allow future versions to add new variables without shifting\n   * down storage in the inheritance chain. See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n   * @dev This mixin uses a total of 2,001 slots.\n   */\n  uint256[2_000] private __gap;\n}\n"
      },
      "contracts/mixins/shared/GapSendValueWithFallbackWithdrawV1.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\n/**\n * @title Reserving space for an old variable that was used in some upgradeable proxy contracts.\n * @author HardlyDifficult\n */\nabstract contract GapSendValueWithFallbackWithdrawV1 {\n  /// @dev Removing old unused variables in an upgrade safe way.\n  uint256 private __gap_was_pendingWithdrawals;\n}\n"
      },
      "contracts/mixins/shared/MarketFees.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\n\npragma solidity ^0.8.18;\n\nimport { ContextUpgradeable } from \"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol\";\nimport { AddressUpgradeable } from \"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\";\n\nimport { IMarketUtils } from \"../../interfaces/internal/IMarketUtils.sol\";\n\nimport \"./Constants.sol\";\nimport \"./MarketStructs.sol\";\n\nimport { MarketSharedCore } from \"./MarketSharedCore.sol\";\nimport { SendValueWithFallbackWithdraw } from \"./SendValueWithFallbackWithdraw.sol\";\nimport { FoundationTreasuryNodeInterface } from \"./FoundationTreasuryNodeInterface.sol\";\n\nerror NFTMarketFees_Market_Utils_Is_Not_A_Contract();\nerror NFTMarketFees_Invalid_Protocol_Fee();\n\n/**\n * @title A mixin to distribute funds when an NFT is sold.\n * @author batu-inal & HardlyDifficult\n */\nabstract contract MarketFees is\n  FoundationTreasuryNodeInterface,\n  ContextUpgradeable,\n  MarketSharedCore,\n  SendValueWithFallbackWithdraw\n{\n  using AddressUpgradeable for address;\n  using AddressUpgradeable for address payable;\n\n  struct DistributeFundsParams {\n    address nftContract;\n    uint256 firstTokenId;\n    uint256 nftCount;\n    address nftRecipientIfKnown;\n    address payable seller;\n    uint256 price;\n    address payable buyReferrer;\n    address payable sellerReferrerPaymentAddress;\n    uint16 sellerReferrerTakeRateInBasisPoints;\n    uint256 fixedProtocolFeeInWei;\n  }\n\n  /**\n   * @dev Removing old unused variables in an upgrade safe way. Was:\n   * uint256 private _primaryFoundationFeeBasisPoints;\n   * uint256 private _secondaryFoundationFeeBasisPoints;\n   * uint256 private _secondaryCreatorFeeBasisPoints;\n   * mapping(address => mapping(uint256 => bool)) private _nftContractToTokenIdToFirstSaleCompleted;\n   */\n  uint256[4] private __gap_was_fees;\n\n  /// @notice True for the Drop market which only performs primary sales. False if primary & secondary are supported.\n  bool private immutable assumePrimarySale;\n\n  /// @notice The fee collected by Foundation for sales facilitated by this market contract.\n  uint256 private immutable defaultProtocolFeeInBasisPoints;\n\n  /// @notice Reference to our MarketUtils contract.\n  IMarketUtils private immutable marketUtils;\n\n  /**\n   * @notice Emitted when an NFT sold with a referrer.\n   * @param nftContract The address of the NFT contract.\n   * @param tokenId The id of the NFT.\n   * @param buyReferrer The account which received the buy referral incentive.\n   * @param buyReferrerFee The portion of the protocol fee collected by the buy referrer.\n   * @param buyReferrerSellerFee The portion of the owner revenue collected by the buy referrer (not implemented).\n   */\n  event BuyReferralPaid(\n    address indexed nftContract,\n    uint256 indexed tokenId,\n    address buyReferrer,\n    uint256 buyReferrerFee,\n    uint256 buyReferrerSellerFee\n  );\n\n  /**\n   * @notice Emitted when an NFT is sold when associated with a sell referrer.\n   * @param nftContract The address of the NFT contract.\n   * @param tokenId The id of the NFT.\n   * @param sellerReferrer The account which received the sell referral incentive.\n   * @param sellerReferrerFee The portion of the seller revenue collected by the sell referrer.\n   */\n  event SellerReferralPaid(\n    address indexed nftContract,\n    uint256 indexed tokenId,\n    address sellerReferrer,\n    uint256 sellerReferrerFee\n  );\n\n  /**\n   * @notice Emitted when a fixed protocol fee is paid as part of an NFT purchase.\n   * @param nftContract The address of the NFT contract.\n   * @param firstTokenId The id of the NFT, or the first/lowest id if it applies to multiple NFTs.\n   * @param nftRecipient The account which acquired an NFT from this transaction (may not be the same as the msg.sender)\n   * @param fixedProtocolFeeInWei The total fee collected by the protocol for this sale in wei.\n   * @param nftCount The number of NFTs in this sale.\n   * @dev Some of this amount may have been shared with a referrer, which would be emitted in via the BuyReferrerPaid\n   * event.\n   */\n  event FixedProtocolFeePaid(\n    address indexed nftContract,\n    uint256 indexed firstTokenId,\n    address indexed nftRecipient,\n    uint256 fixedProtocolFeeInWei,\n    uint256 nftCount\n  );\n\n  /**\n   * @notice Sets the immutable variables for this contract.\n   * @param _defaultProtocolFeeInBasisPoints The default protocol fee to use for this market.\n   * @param marketUtilsAddress The address to use for our MarketUtils contract.\n   * @param _assumePrimarySale True for the Drop market which only performs primary sales.\n   * False if primary & secondary are supported.\n   */\n  constructor(uint16 _defaultProtocolFeeInBasisPoints, address marketUtilsAddress, bool _assumePrimarySale) {\n    if (_defaultProtocolFeeInBasisPoints + BASIS_POINTS / ROYALTY_RATIO >= BASIS_POINTS - MAX_WORLD_TAKE_RATE) {\n      // The protocol fee must leave room for the creator royalties and the max World take rate.\n      // If the protocol fee is invalid, revert.\n      revert NFTMarketFees_Invalid_Protocol_Fee();\n    }\n\n    if (!marketUtilsAddress.isContract()) {\n      revert NFTMarketFees_Market_Utils_Is_Not_A_Contract();\n    }\n\n    assumePrimarySale = _assumePrimarySale;\n    defaultProtocolFeeInBasisPoints = _defaultProtocolFeeInBasisPoints;\n    marketUtils = IMarketUtils(marketUtilsAddress);\n  }\n\n  /**\n   * @notice Distributes funds to foundation, creator recipients, and NFT owner after a sale.\n   * @return totalFees The total fees collected by the protocol and referrals, excluding any fixed fee charged.\n   * @dev `virtual` allows other mixins to be notified anytime a sale occurs.\n   */\n  function _distributeFunds(\n    DistributeFundsParams memory params\n  ) internal virtual returns (uint256 totalFees, uint256 creatorRev, uint256 sellerRev) {\n    address payable[] memory creatorRecipients;\n    uint256[] memory creatorShares;\n\n    uint256 buyReferrerFee;\n    uint256 sellerReferrerFee;\n    (totalFees, creatorRecipients, creatorShares, sellerRev, buyReferrerFee, sellerReferrerFee) = getFees(\n      params.nftContract,\n      params.firstTokenId,\n      params.seller,\n      params.price,\n      params.buyReferrer,\n      params.sellerReferrerTakeRateInBasisPoints\n    );\n\n    // The `getFees` breakdown doesn't yet account for the fixed protocol fee, so we add that in separately.\n    if (params.fixedProtocolFeeInWei != 0) {\n      totalFees += params.fixedProtocolFeeInWei;\n\n      // The buy referrer is rewarded a portion of this fixed fee as well.\n      if (params.buyReferrer != address(0)) {\n        buyReferrerFee += params.fixedProtocolFeeInWei / BUY_REFERRER_RATIO;\n        totalFees -= buyReferrerFee;\n      }\n\n      emit FixedProtocolFeePaid(\n        params.nftContract,\n        params.firstTokenId,\n        params.nftRecipientIfKnown,\n        params.fixedProtocolFeeInWei,\n        params.nftCount\n      );\n    }\n\n    // Pay the creator(s)\n    {\n      // If just a single recipient was defined, use a larger gas limit in order to support in-contract split logic.\n      uint256 creatorGasLimit = creatorRecipients.length == 1\n        ? SEND_VALUE_GAS_LIMIT_MULTIPLE_RECIPIENTS\n        : SEND_VALUE_GAS_LIMIT_SINGLE_RECIPIENT;\n      unchecked {\n        for (uint256 i = 0; i < creatorRecipients.length; ++i) {\n          _sendValueWithFallbackWithdraw(creatorRecipients[i], creatorShares[i], creatorGasLimit);\n          // Sum the total creator rev from shares\n          // creatorShares is in ETH so creatorRev will not overflow here.\n          creatorRev += creatorShares[i];\n        }\n      }\n    }\n\n    // Pay the seller\n    _sendValueWithFallbackWithdraw(params.seller, sellerRev, SEND_VALUE_GAS_LIMIT_SINGLE_RECIPIENT);\n\n    // Pay the protocol fee\n    if (totalFees != 0) {\n      getFoundationTreasury().sendValue(totalFees);\n    }\n\n    // Pay the buy referrer fee\n    if (buyReferrerFee != 0) {\n      _sendValueWithFallbackWithdraw(params.buyReferrer, buyReferrerFee, SEND_VALUE_GAS_LIMIT_SINGLE_RECIPIENT);\n      emit BuyReferralPaid({\n        nftContract: params.nftContract,\n        tokenId: params.firstTokenId,\n        buyReferrer: params.buyReferrer,\n        buyReferrerFee: buyReferrerFee,\n        buyReferrerSellerFee: 0\n      });\n      unchecked {\n        // Add the referrer fee back into the total fees so that all 3 return fields sum to the total sale price.\n        totalFees += buyReferrerFee;\n      }\n    }\n\n    // Remove the fixed fee from the `totalFees` being returned so that all 3 return fields sum to the total sale price.\n    if (params.fixedProtocolFeeInWei != 0) {\n      unchecked {\n        totalFees -= params.fixedProtocolFeeInWei;\n      }\n    }\n\n    if (params.sellerReferrerPaymentAddress != address(0)) {\n      if (sellerReferrerFee != 0) {\n        // Add the seller referrer fee back to revenue so that all 3 return fields sum to the total sale price.\n        unchecked {\n          if (sellerRev == 0) {\n            // When sellerRev is 0, this is a primary sale and all revenue is attributed to the \"creator\".\n            creatorRev += sellerReferrerFee;\n          } else {\n            sellerRev += sellerReferrerFee;\n          }\n        }\n\n        _sendValueWithFallbackWithdraw(\n          params.sellerReferrerPaymentAddress,\n          sellerReferrerFee,\n          SEND_VALUE_GAS_LIMIT_SINGLE_RECIPIENT\n        );\n      }\n\n      emit SellerReferralPaid(\n        params.nftContract,\n        params.firstTokenId,\n        params.sellerReferrerPaymentAddress,\n        sellerReferrerFee\n      );\n    }\n  }\n\n  /// @dev Assumes the caller ensures that fixedProtocolFeeInWei > 0.\n  function _distributeFixedProtocolFee(\n    address nftContract,\n    uint256 firstTokenId,\n    uint256 nftCount,\n    address buyer,\n    uint256 fixedProtocolFeeInWei\n  ) internal {\n    getFoundationTreasury().sendValue(fixedProtocolFeeInWei);\n    emit FixedProtocolFeePaid(nftContract, firstTokenId, buyer, fixedProtocolFeeInWei, nftCount);\n  }\n\n  /**\n   * @notice Calculates how funds should be distributed for the given sale details.\n   * @dev When the NFT is being sold by the `tokenCreator`, all the seller revenue will\n   * be split with the royalty recipients defined for that NFT.\n   */\n  function getFees(\n    address nftContract,\n    uint256 tokenId,\n    address payable seller,\n    uint256 price,\n    address payable buyReferrer,\n    uint16 sellerReferrerTakeRateInBasisPoints\n  )\n    public\n    view\n    returns (\n      uint256 protocolFeeAmount,\n      address payable[] memory creatorRecipients,\n      uint256[] memory creatorShares,\n      uint256 sellerRev,\n      uint256 buyReferrerFee,\n      uint256 sellerReferrerFee\n    )\n  {\n    MarketTransactionOptions memory options = MarketTransactionOptions({\n      // Market info\n      marketTakeRateInBasisPoints: defaultProtocolFeeInBasisPoints,\n      assumePrimarySale: assumePrimarySale,\n      // Sale info\n      nftContract: nftContract,\n      tokenId: tokenId,\n      price: price,\n      seller: seller,\n      // Referrals\n      buyReferrer: buyReferrer,\n      sellerReferrerTakeRateInBasisPoints: sellerReferrerTakeRateInBasisPoints,\n      // Transaction info\n      sender: _msgSender()\n    });\n\n    (protocolFeeAmount, creatorRecipients, creatorShares, sellerRev, buyReferrerFee, sellerReferrerFee) = marketUtils\n      .getTransactionBreakdown(options);\n  }\n\n  /**\n   * @notice Returns how funds will be distributed for a sale at the given price point.\n   * @param nftContract The address of the NFT contract.\n   * @param tokenId The id of the NFT.\n   * @param price The sale price to calculate the fees for.\n   * @return totalFees How much will be sent to the Foundation treasury and/or referrals.\n   * @return creatorRev How much will be sent across all the `creatorRecipients` defined.\n   * @return creatorRecipients The addresses of the recipients to receive a portion of the creator fee.\n   * @return creatorShares The percentage of the creator fee to be distributed to each `creatorRecipient`.\n   * If there is only one `creatorRecipient`, this may be an empty array.\n   * Otherwise `creatorShares.length` == `creatorRecipients.length`.\n   * @return sellerRev How much will be sent to the owner/seller of the NFT.\n   * If the NFT is being sold by the creator, this may be 0 and the full revenue will appear as `creatorRev`.\n   * @return seller The address of the owner of the NFT.\n   * If `sellerRev` is 0, this may be `address(0)`.\n   * @dev Currently in use by the FNDMiddleware `getFees` call (now deprecated).\n   */\n  function getFeesAndRecipients(\n    address nftContract,\n    uint256 tokenId,\n    uint256 price\n  )\n    external\n    view\n    returns (\n      uint256 totalFees,\n      uint256 creatorRev,\n      address payable[] memory creatorRecipients,\n      uint256[] memory creatorShares,\n      uint256 sellerRev,\n      address payable seller\n    )\n  {\n    seller = _getSellerOrOwnerOf(nftContract, tokenId);\n    (totalFees, creatorRecipients, creatorShares, sellerRev, , ) = getFees({\n      nftContract: nftContract,\n      tokenId: tokenId,\n      seller: seller,\n      price: price,\n      // Notice: Setting this value is a breaking change for the FNDMiddleware contract.\n      // Will be wired in an upcoming release to communicate the buy referral information.\n      buyReferrer: payable(0),\n      sellerReferrerTakeRateInBasisPoints: 0\n    });\n\n    // Sum the total creator rev from shares\n    unchecked {\n      for (uint256 i = 0; i < creatorShares.length; ++i) {\n        creatorRev += creatorShares[i];\n      }\n    }\n  }\n\n  /**\n   * @notice returns the address of the MarketUtils contract.\n   */\n  function getMarketUtilsAddress() external view returns (address marketUtilsAddress) {\n    marketUtilsAddress = address(marketUtils);\n  }\n\n  /**\n   * @notice This empty reserved space is put in place to allow future versions to add new variables without shifting\n   * down storage in the inheritance chain. See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n   * @dev This mixins uses 504 slots in total.\n   */\n  uint256[500] private __gap;\n}\n"
      },
      "contracts/mixins/shared/MarketSharedCore.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\n\npragma solidity ^0.8.18;\n\nimport \"./FETHNode.sol\";\n\n/**\n * @title A place for common modifiers and functions used by various market mixins, if any.\n * @dev This also leaves a gap which can be used to add a new mixin to the top of the inheritance tree.\n * @author batu-inal & HardlyDifficult\n */\nabstract contract MarketSharedCore is FETHNode {\n  /**\n   * @notice Checks who the seller for an NFT is if listed in this market.\n   * @param nftContract The address of the NFT contract.\n   * @param tokenId The id of the NFT.\n   * @return seller The seller which listed this NFT for sale, or address(0) if not listed.\n   */\n  function getSellerOf(address nftContract, uint256 tokenId) external view returns (address payable seller) {\n    seller = _getSellerOf(nftContract, tokenId);\n  }\n\n  /**\n   * @notice Checks who the seller for an NFT is if listed in this market.\n   */\n  function _getSellerOf(address nftContract, uint256 tokenId) internal view virtual returns (address payable seller) {\n    // Returns address(0) by default.\n  }\n\n  /**\n   * @notice Checks who the seller for an NFT is if listed in this market or returns the current owner.\n   */\n  function _getSellerOrOwnerOf(\n    address nftContract,\n    uint256 tokenId\n  ) internal view virtual returns (address payable sellerOrOwner);\n\n  /**\n   * @notice This empty reserved space is put in place to allow future versions to add new variables without shifting\n   * down storage in the inheritance chain. See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n   */\n  uint256[450] private __gap;\n}\n"
      },
      "contracts/mixins/shared/MarketStructs.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\n\npragma solidity ^0.8.18;\n\n/// @notice Details about a marketplace sale.\nstruct MarketTransactionOptions {\n  ////////////////////////////////////////////////////////////////\n  // Market config\n  ////////////////////////////////////////////////////////////////\n  /// @notice Percentage of the transaction to go the the market, expressed in basis points.\n  uint256 marketTakeRateInBasisPoints;\n  /// @notice set to true when the token is being sold by it's creator\n  bool assumePrimarySale;\n  ////////////////////////////////////////////////////////////////\n  // Sale info\n  ////////////////////////////////////////////////////////////////\n  /// @notice The contract address of the nft\n  address nftContract;\n  /// @notice The token id of the nft.\n  uint256 tokenId;\n  /// @notice price at which the token is being sold\n  uint256 price;\n  /// @notice address of the account that is selling the token\n  address payable seller;\n  ////////////////////////////////////////////////////////////////\n  // Referrals\n  ////////////////////////////////////////////////////////////////\n  /// @notice Address of the account that referred the buyer.\n  address payable buyReferrer;\n  /// @notice Percentage of the transaction to go the the account which referred the seller, expressed in basis points.\n  uint16 sellerReferrerTakeRateInBasisPoints;\n  ////////////////////////////////////////////////////////////////\n  // Transaction info\n  ////////////////////////////////////////////////////////////////\n  /// @notice The msg.sender which executed the purchase transaction.\n  address sender;\n}\n\n/// @notice The auction configuration for a specific NFT.\nstruct ReserveAuction {\n  /// @notice The address of the NFT contract.\n  address nftContract;\n  /// @notice The id of the NFT.\n  uint256 tokenId;\n  /// @notice The owner of the NFT which listed it in auction.\n  address payable seller;\n  /// @notice The duration for this auction.\n  uint256 duration;\n  /// @notice The extension window for this auction.\n  uint256 extensionDuration;\n  /// @notice The time at which this auction will not accept any new bids.\n  /// @dev This is `0` until the first bid is placed.\n  uint256 endTime;\n  /// @notice The current highest bidder in this auction.\n  /// @dev This is `address(0)` until the first bid is placed.\n  address payable bidder;\n  /// @notice The latest price of the NFT in this auction.\n  /// @dev This is set to the reserve price, and then to the highest bid once the auction has started.\n  uint256 amount;\n}\n"
      },
      "contracts/mixins/shared/RouterContextSingle.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\n\npragma solidity ^0.8.18;\n\nimport \"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\";\n\nimport \"../../libraries/RouteCallLibrary.sol\";\n\nerror RouterContextSingle_Address_Is_Not_A_Contract();\n\n/**\n * @title Enables a trusted contract to override the usual msg.sender address.\n * @author HardlyDifficult\n */\nabstract contract RouterContextSingle is ContextUpgradeable {\n  using AddressUpgradeable for address;\n\n  address private immutable approvedRouter;\n\n  constructor(address router) {\n    if (!router.isContract()) {\n      revert RouterContextSingle_Address_Is_Not_A_Contract();\n    }\n\n    approvedRouter = router;\n  }\n\n  /**\n   * @notice Returns the contract which is able to override the msg.sender address.\n   * @return router The address of the trusted router.\n   */\n  function getApprovedRouterAddress() external view returns (address router) {\n    router = approvedRouter;\n  }\n\n  /**\n   * @notice Gets the sender of the transaction to use, overriding the usual msg.sender if the caller is a trusted\n   * router.\n   * @dev If the msg.sender is a trusted router contract, then the last 20 bytes of the calldata represents the\n   * authorized sender to use.\n   * If this is used for a call that was not routed with `routeCallTo`, the address returned will be incorrect (and\n   * may be address(0)).\n   */\n  function _msgSender() internal view virtual override returns (address sender) {\n    sender = super._msgSender();\n    if (sender == approvedRouter) {\n      sender = RouteCallLibrary.extractAppendedSenderAddress();\n    }\n  }\n}\n"
      },
      "contracts/mixins/shared/SendValueWithFallbackWithdraw.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport { AddressUpgradeable } from \"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\";\n\nimport { FETHNode } from \"./FETHNode.sol\";\nimport { FoundationTreasuryNodeInterface } from \"./FoundationTreasuryNodeInterface.sol\";\n\n/**\n * @title A mixin for sending ETH with a fallback withdraw mechanism.\n * @notice Attempt to send ETH and if the transfer fails or runs out of gas, store the balance\n * in the FETH token contract for future withdrawal instead.\n * @dev This mixin was recently switched to escrow funds in FETH.\n * Once we have confirmed all pending balances have been withdrawn, we can remove the escrow tracking here.\n * @author batu-inal & HardlyDifficult\n */\nabstract contract SendValueWithFallbackWithdraw is FoundationTreasuryNodeInterface, FETHNode {\n  using AddressUpgradeable for address payable;\n\n  /**\n   * @notice Emitted when escrowed funds are withdrawn to FETH.\n   * @param user The account which has withdrawn ETH.\n   * @param amount The amount of ETH which has been withdrawn.\n   */\n  event WithdrawalToFETH(address indexed user, uint256 amount);\n\n  /**\n   * @notice Attempt to send a user or contract ETH.\n   * If it fails store the amount owned for later withdrawal in FETH.\n   * @dev This may fail when sending ETH to a contract that is non-receivable or exceeds the gas limit specified.\n   */\n  function _sendValueWithFallbackWithdraw(address payable user, uint256 amount, uint256 gasLimit) internal {\n    if (amount == 0) {\n      return;\n    }\n\n    if (user == address(feth)) {\n      // FETH may revert on ETH transfers and will reject `depositFor` calls to itself, so redirect funds to the\n      // treasury contract instead.\n      user = getFoundationTreasury();\n    }\n\n    // Cap the gas to prevent consuming all available gas to block a tx from completing successfully\n    // solhint-disable-next-line avoid-low-level-calls\n    (bool success, ) = user.call{ value: amount, gas: gasLimit }(\"\");\n    if (!success) {\n      // Store the funds that failed to send for the user in the FETH token\n      feth.depositFor{ value: amount }(user);\n      emit WithdrawalToFETH(user, amount);\n    }\n  }\n\n  /**\n   * @notice This empty reserved space is put in place to allow future versions to add new variables without shifting\n   * down storage in the inheritance chain. See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n   */\n  uint256[999] private __gap;\n}\n"
      },
      "contracts/mixins/shared/WorldsNftNode.sol": {
        "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity ^0.8.18;\n\nimport \"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol\";\n\nerror WorldsNftNode_Worlds_NFT_Is_Not_A_Contract();\n\n/**\n * @title Stores a reference to the Worlds NFT contract for contracts to leverage.\n * @author HardlyDifficult\n */\nabstract contract WorldsNftNode {\n  using AddressUpgradeable for address;\n\n  address internal immutable worlds;\n\n  constructor(address worldsNft) {\n    if (!worldsNft.isContract()) {\n      revert WorldsNftNode_Worlds_NFT_Is_Not_A_Contract();\n    }\n\n    worlds = worldsNft;\n  }\n\n  /**\n   * @notice Returns the address of the Worlds NFT contract.\n   */\n  function getWorldsNftAddress() external view returns (address worldsNft) {\n    worldsNft = worlds;\n  }\n\n  // This mixin uses 0 slots.\n}\n"
      },
      "contracts/NFTMarket.sol": {
        "content": "/*\n  ･\n   *　★\n      ･ ｡\n        　･　ﾟ☆ ｡\n  　　　 *　★ ﾟ･｡ *  ｡\n          　　* ☆ ｡･ﾟ*.｡\n      　　　ﾟ *.｡☆｡★　･\n​\n                      `                     .-:::::-.`              `-::---...```\n                     `-:`               .:+ssssoooo++//:.`       .-/+shhhhhhhhhhhhhyyyssooo:\n                    .--::.            .+ossso+/////++/:://-`   .////+shhhhhhhhhhhhhhhhhhhhhy\n                  `-----::.         `/+////+++///+++/:--:/+/-  -////+shhhhhhhhhhhhhhhhhhhhhy\n                 `------:::-`      `//-.``.-/+ooosso+:-.-/oso- -////+shhhhhhhhhhhhhhhhhhhhhy\n                .--------:::-`     :+:.`  .-/osyyyyyyso++syhyo.-////+shhhhhhhhhhhhhhhhhhhhhy\n              `-----------:::-.    +o+:-.-:/oyhhhhhhdhhhhhdddy:-////+shhhhhhhhhhhhhhhhhhhhhy\n             .------------::::--  `oys+/::/+shhhhhhhdddddddddy/-////+shhhhhhhhhhhhhhhhhhhhhy\n            .--------------:::::-` +ys+////+yhhhhhhhddddddddhy:-////+yhhhhhhhhhhhhhhhhhhhhhy\n          `----------------::::::-`.ss+/:::+oyhhhhhhhhhhhhhhho`-////+shhhhhhhhhhhhhhhhhhhhhy\n         .------------------:::::::.-so//::/+osyyyhhhhhhhhhys` -////+shhhhhhhhhhhhhhhhhhhhhy\n       `.-------------------::/:::::..+o+////+oosssyyyyyyys+`  .////+shhhhhhhhhhhhhhhhhhhhhy\n       .--------------------::/:::.`   -+o++++++oooosssss/.     `-//+shhhhhhhhhhhhhhhhhhhhyo\n     .-------   ``````.......--`        `-/+ooooosso+/-`          `./++++///:::--...``hhhhyo\n                                              `````\n   *　\n      ･ ｡\n　　　　･　　ﾟ☆ ｡\n  　　　 *　★ ﾟ･｡ *  ｡\n          　　* ☆ ｡･ﾟ*.｡\n      　　　ﾟ *.｡☆｡★　･\n    *　　ﾟ｡·*･｡ ﾟ*\n  　　　☆ﾟ･｡°*. ﾟ\n　 ･ ﾟ*｡･ﾟ★｡\n　　･ *ﾟ｡　　 *\n　･ﾟ*｡★･\n ☆∴｡　*\n･ ｡\n*/\n\n// SPDX-License-Identifier: MIT OR Apache-2.0\n\npragma solidity ^0.8.18;\n\nimport { ContextUpgradeable } from \"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol\";\nimport { Initializable } from \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\n\nimport { FETHNode } from \"./mixins/shared/FETHNode.sol\";\nimport { FoundationTreasuryNodeV1 } from \"./mixins/shared/FoundationTreasuryNodeV1.sol\";\nimport { MarketFees } from \"./mixins/shared/MarketFees.sol\";\nimport { MarketSharedCore } from \"./mixins/shared/MarketSharedCore.sol\";\nimport { WorldsNftNode } from \"./mixins/shared/WorldsNftNode.sol\";\nimport { RouterContextSingle } from \"./mixins/shared/RouterContextSingle.sol\";\nimport { GapSendValueWithFallbackWithdrawV1 } from \"./mixins/shared/GapSendValueWithFallbackWithdrawV1.sol\";\nimport { SendValueWithFallbackWithdraw } from \"./mixins/shared/SendValueWithFallbackWithdraw.sol\";\n\nimport { NFTMarketAuction } from \"./mixins/nftMarket/NFTMarketAuction.sol\";\nimport { NFTMarketBuyPrice } from \"./mixins/nftMarket/NFTMarketBuyPrice.sol\";\nimport { NFTMarketCore } from \"./mixins/nftMarket/NFTMarketCore.sol\";\nimport { NFTMarketWorlds } from \"./mixins/nftMarket/NFTMarketWorlds.sol\";\nimport { NFTMarketOffer } from \"./mixins/nftMarket/NFTMarketOffer.sol\";\nimport { NFTMarketPrivateSaleGap } from \"./mixins/nftMarket/NFTMarketPrivateSaleGap.sol\";\nimport { NFTMarketReserveAuction } from \"./mixins/nftMarket/NFTMarketReserveAuction.sol\";\nimport { NFTMarketScheduling } from \"./mixins/nftMarket/NFTMarketScheduling.sol\";\nimport { NFTMarketWorldsAPIs } from \"./mixins/nftMarket/NFTMarketWorldsAPIs.sol\";\n\n/**\n * @title A market for NFTs on Foundation.\n * @notice The Foundation marketplace is a contract which allows traders to buy and sell NFTs.\n * It supports buying and selling via auctions, private sales, buy price, and offers.\n * @dev All sales in the Foundation market will pay the creator 10% royalties on secondary sales. This is not specific\n * to NFTs minted on Foundation, it should work for any NFT. If royalty information was not defined when the NFT was\n * originally deployed, it may be added using the [Royalty Registry](https://royaltyregistry.xyz/) which will be\n * respected by our market contract.\n * @author batu-inal & HardlyDifficult\n */\ncontract NFTMarket is\n  WorldsNftNode,\n  NFTMarketWorldsAPIs,\n  Initializable,\n  FoundationTreasuryNodeV1,\n  ContextUpgradeable,\n  RouterContextSingle,\n  FETHNode,\n  MarketSharedCore,\n  NFTMarketCore,\n  ReentrancyGuardUpgradeable,\n  GapSendValueWithFallbackWithdrawV1,\n  SendValueWithFallbackWithdraw,\n  MarketFees,\n  NFTMarketWorlds,\n  NFTMarketScheduling,\n  NFTMarketAuction,\n  NFTMarketReserveAuction,\n  NFTMarketPrivateSaleGap,\n  NFTMarketBuyPrice,\n  NFTMarketOffer\n{\n  ////////////////////////////////////////////////////////////////\n  // Setup\n  ////////////////////////////////////////////////////////////////\n\n  /**\n   * @notice Set immutable variables for the implementation contract.\n   * @dev Using immutable instead of constants allows us to use different values on testnet.\n   * @param treasury The Foundation Treasury contract address.\n   * @param feth The FETH ERC-20 token contract address.\n   * @param router The trusted router contract address.\n   * @param marketUtils The MarketUtils contract address.\n   * @param worldsNft The Worlds NFT contract address.\n   */\n  constructor(\n    address payable treasury,\n    address feth,\n    address router,\n    address marketUtils,\n    address worldsNft\n  )\n    FoundationTreasuryNodeV1(treasury)\n    FETHNode(feth)\n    WorldsNftNode(worldsNft)\n    MarketFees(\n      /* protocolFeeInBasisPoints: */\n      500,\n      marketUtils,\n      /* assumePrimarySale: */\n      false\n    )\n    RouterContextSingle(router)\n  {}\n\n  /**\n   * @notice Initialize mutable state.\n   * @param networkAuctionIdOffset The first auction created on this network will use\n   * `auctionId = networkAuctionIdOffset + 1`.\n   */\n  function initialize(uint256 networkAuctionIdOffset) external reinitializer(2) {\n    _initializeNFTMarketAuction(networkAuctionIdOffset);\n  }\n\n  ////////////////////////////////////////////////////////////////\n  // Inheritance Requirements\n  // (no-ops to avoid compile errors)\n  ////////////////////////////////////////////////////////////////\n\n  /**\n   * @inheritdoc NFTMarketCore\n   */\n  function _beforeAuctionStarted(\n    address nftContract,\n    uint256 tokenId\n  ) internal override(NFTMarketCore, NFTMarketScheduling, NFTMarketReserveAuction, NFTMarketBuyPrice, NFTMarketOffer) {\n    super._beforeAuctionStarted(nftContract, tokenId);\n  }\n\n  /**\n   * @inheritdoc MarketFees\n   */\n  function _distributeFunds(\n    DistributeFundsParams memory params\n  )\n    internal\n    virtual\n    override(MarketFees, NFTMarketBuyPrice, NFTMarketReserveAuction, NFTMarketScheduling)\n    returns (uint256 totalFees, uint256 creatorRev, uint256 sellerRev)\n  {\n    (totalFees, creatorRev, sellerRev) = super._distributeFunds(params);\n  }\n\n  /**\n   * @inheritdoc MarketSharedCore\n   */\n  function _getSellerOf(\n    address nftContract,\n    uint256 tokenId\n  )\n    internal\n    view\n    override(MarketSharedCore, NFTMarketReserveAuction, NFTMarketBuyPrice)\n    returns (address payable seller)\n  {\n    seller = super._getSellerOf(nftContract, tokenId);\n  }\n\n  /**\n   * @inheritdoc NFTMarketCore\n   */\n  function _isAuthorizedScheduleUpdate(\n    address nftContract,\n    uint256 tokenId\n  ) internal view override(NFTMarketCore, NFTMarketReserveAuction, NFTMarketBuyPrice) returns (bool canUpdateNft) {\n    canUpdateNft = super._isAuthorizedScheduleUpdate(nftContract, tokenId);\n  }\n\n  /**\n   * @inheritdoc RouterContextSingle\n   */\n  function _msgSender() internal view override(ContextUpgradeable, RouterContextSingle) returns (address sender) {\n    sender = super._msgSender();\n  }\n\n  /**\n   * @inheritdoc NFTMarketCore\n   */\n  function _transferFromEscrow(\n    address nftContract,\n    uint256 tokenId,\n    address recipient,\n    address authorizeSeller\n  ) internal override(NFTMarketCore, NFTMarketReserveAuction, NFTMarketBuyPrice) {\n    super._transferFromEscrow(nftContract, tokenId, recipient, authorizeSeller);\n  }\n\n  /**\n   * @inheritdoc NFTMarketCore\n   */\n  function _transferFromEscrowIfAvailable(\n    address nftContract,\n    uint256 tokenId,\n    address originalSeller\n  )\n    internal\n    override(\n      NFTMarketCore,\n      NFTMarketWorlds,\n      NFTMarketOffer,\n      NFTMarketScheduling,\n      NFTMarketReserveAuction,\n      NFTMarketBuyPrice\n    )\n  {\n    super._transferFromEscrowIfAvailable(nftContract, tokenId, originalSeller);\n  }\n\n  /**\n   * @inheritdoc NFTMarketCore\n   */\n  function _transferToEscrow(\n    address nftContract,\n    uint256 tokenId\n  ) internal override(NFTMarketCore, NFTMarketReserveAuction, NFTMarketBuyPrice) {\n    super._transferToEscrow(nftContract, tokenId);\n  }\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 1337000
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "evmVersion": "paris",
      "metadata": {
        "useLiteralContent": true
      },
      "libraries": {}
    }
  }}