creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "src/contracts/sUSDeTokenOracle.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.19;\n\n// ====================================================================\n// |     ______                   _______                             |\n// |    / _____________ __  __   / ____(_____  ____ _____  ________   |\n// |   / /_  / ___/ __ `| |/_/  / /_  / / __ \\/ __ `/ __ \\/ ___/ _ \\  |\n// |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |\n// | /_/   /_/   \\__,_/_/|_|  /_/   /_/_/ /_/\\__,_/_/ /_/\\___/\\___/   |\n// |                                                                  |\n// ====================================================================\n// ===================== sUSDECurveBoundedOracle ======================\n// ====================================================================\n// Frax Finance: https://github.com/FraxFinance\n\n// ====================================================================\n\nimport { Timelock2Step } from \"frax-std/access-control/v1/Timelock2Step.sol\";\nimport { ITimelock2Step } from \"frax-std/access-control/v1/interfaces/ITimelock2Step.sol\";\nimport { DualOracleBase, ConstructorParams as DualOracleBaseParams } from \"./DualOracleBase.sol\";\nimport { ICurvePoolEmaPriceOracleWithMinMax } from \"interfaces/oracles/abstracts/ICurvePoolEmaPriceOracleWithMinMax.sol\";\nimport { IEmaPriceOracleStableSwapNG } from \"interfaces/IEmaPriceOracleStableSwap.sol\";\nimport { ERC165Storage } from \"src/contracts/utils/ERC165Storage.sol\";\nimport { ISUSDE } from \"src/contracts/interfaces/ISUSDE.sol\";\nimport \"interfaces/IDualOracle.sol\";\n\nstruct ConstructorParams {\n    address sUSDeErc20;\n    address curvePoolEmaPriceOracleAddress;\n    uint256 minimumCurvePoolEma;\n    uint256 maximumCurvePoolEma;\n    address timelockAddress;\n}\n\ncontract SUSDeTokenOracle is DualOracleBase, Timelock2Step, ERC165Storage, ICurvePoolEmaPriceOracleWithMinMax {\n    /// @notice SUSDE contract\n    ISUSDE public immutable SUSDE_ERC20;\n\n    /// @notice Curve pool, source of EMA\n    address public immutable CURVE_POOL_EMA_PRICE_ORACLE;\n\n    /// @notice Precision of Curve pool price_oracle()\n    uint256 public constant CURVE_POOL_EMA_PRICE_ORACLE_PRECISION = 1e18;\n\n    /// @notice Maximum price of token1 in token0 units of the EMA\n    /// @dev Must match precision of EMA\n    uint256 public minimumCurvePoolEma;\n\n    /// @notice Maximum price of token1 in token0 units of the EMA\n    /// @dev Must match precision of EMA\n    uint256 public maximumCurvePoolEma;\n\n    constructor(\n        ConstructorParams memory _params\n    )\n        DualOracleBase(\n            DualOracleBaseParams({\n                baseToken0: address(840),\n                baseToken0Decimals: 18,\n                quoteToken0: _params.sUSDeErc20,\n                quoteToken0Decimals: 18,\n                baseToken1: address(840),\n                baseToken1Decimals: 18,\n                quoteToken1: _params.sUSDeErc20,\n                quoteToken1Decimals: 18\n            })\n        )\n        Timelock2Step()\n    {\n        _setTimelock({ _newTimelock: _params.timelockAddress });\n\n        SUSDE_ERC20 = ISUSDE(_params.sUSDeErc20);\n        _registerInterface({ interfaceId: type(ICurvePoolEmaPriceOracleWithMinMax).interfaceId });\n\n        CURVE_POOL_EMA_PRICE_ORACLE = _params.curvePoolEmaPriceOracleAddress;\n        minimumCurvePoolEma = _params.minimumCurvePoolEma;\n        maximumCurvePoolEma = _params.maximumCurvePoolEma;\n    }\n\n    // ====================================================================\n    // View Helpers\n    // ====================================================================\n\n    function name() external pure returns (string memory) {\n        return \"sUSDe Oracle Curve EMA w/ Bounds\";\n    }\n\n    // ====================================================================\n    // Internal Setters\n    // ====================================================================\n\n    /// @notice The ```setMaximumCurvePoolEma``` function sets the maximum price of the EMA\n    /// @dev Must match precision of the EMA\n    /// @param _maximumPrice The maximum price of the EMA\n    function _setMaximumCurvePoolEma(uint256 _maximumPrice) internal {\n        emit SetMaximumCurvePoolEma({ oldMaximum: maximumCurvePoolEma, newMaximum: _maximumPrice });\n        maximumCurvePoolEma = _maximumPrice;\n    }\n\n    /// @notice The ```setEmaMinimum``` function sets the minimum price of the EMA\n    /// @dev Must match precision of the EMA\n    /// @param _minimumPrice The minimum price of the EMA\n    function _setMinimumCurvePoolEma(uint256 _minimumPrice) internal {\n        emit SetMinimumCurvePoolEma({ oldMinimum: minimumCurvePoolEma, newMinimum: _minimumPrice });\n        minimumCurvePoolEma = _minimumPrice;\n    }\n\n    // ====================================================================\n    // Configuration Setters\n    // ====================================================================\n\n    function setMinimumCurvePoolEma(uint256 _maximumPrice) public {\n        _requireTimelock();\n        _setMaximumCurvePoolEma(_maximumPrice);\n    }\n\n    function setMaximumCurvePoolEma(uint256 _minimumPrice) public {\n        _requireTimelock();\n        _setMinimumCurvePoolEma(_minimumPrice);\n    }\n\n    // ====================================================================\n    // Price Functions\n    // ====================================================================\n\n    function getCurvePoolToken1EmaPrice() public view returns (uint256 _token1Price) {\n        // Collateral in terms of Frax\n        _token1Price = IEmaPriceOracleStableSwapNG(CURVE_POOL_EMA_PRICE_ORACLE).price_oracle(0);\n    }\n\n    /// @notice The ```getPricesNormalized``` function returns the normalized prices in human readable form\n    /// @return _isBadDataNormal If the oracle is stale\n    /// @return _priceLowNormal The normalized low price\n    /// @return _priceHighNormal The normalized high price\n    function getPricesNormalized()\n        external\n        view\n        returns (bool _isBadDataNormal, uint256 _priceLowNormal, uint256 _priceHighNormal)\n    {\n        (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) = _getPrices();\n        _isBadDataNormal = _isBadData;\n\n        _priceLowNormal = NORMALIZATION_0 > 0\n            ? _priceLow * 10 ** uint256(NORMALIZATION_0)\n            : _priceLow / 10 ** (uint256(-NORMALIZATION_0));\n\n        _priceHighNormal = NORMALIZATION_1 > 0\n            ? _priceHigh * 10 ** uint256(NORMALIZATION_1)\n            : _priceHigh / 10 ** (uint256(-NORMALIZATION_1));\n    }\n\n    function _getPrices() internal view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) {\n        uint256 tokenPrice = getCurvePoolToken1EmaPrice();\n        _isBadData = false;\n        uint256 usdePersUsde = SUSDE_ERC20.previewRedeem(1e18);\n\n        // USDe cannot be worth > 1 frax\n        if (tokenPrice > maximumCurvePoolEma) tokenPrice = maximumCurvePoolEma;\n        // If token price is above the minimumCurve EMA price\n        if (tokenPrice > minimumCurvePoolEma) {\n            uint256 sUsdePrice = (usdePersUsde * tokenPrice) / ORACLE_PRECISION;\n            // Price debt in terms of collateral -> inverse collateral/USD\n            _priceLow = _priceHigh = 1e36 / sUsdePrice;\n        } else {\n            uint256 minimumSUSDePrice = (usdePersUsde * minimumCurvePoolEma) / ORACLE_PRECISION;\n            // If token price is below the minimCurvePool EMA price\n            _priceHigh = 1e36 / tokenPrice;\n            // Cause price feeds to deviate -> pause FLP debt actions\n            _priceLow = 1e36 / minimumCurvePoolEma;\n        }\n    }\n\n    /// @notice The ```getPrices``` function is intended to return two prices from different oracles\n    /// @return _isBadData is true when data is stale or otherwise bad\n    /// @return _priceLow is the lower of the two prices\n    /// @return _priceHigh is the higher of the two prices\n    function getPrices() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh) {\n        return _getPrices();\n    }\n}\n"
      },
      "node_modules/frax-standard-solidity/src/access-control/v1/Timelock2Step.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity >=0.8.0;\n\n// ====================================================================\n// |     ______                   _______                             |\n// |    / _____________ __  __   / ____(_____  ____ _____  ________   |\n// |   / /_  / ___/ __ `| |/_/  / /_  / / __ \\/ __ `/ __ \\/ ___/ _ \\  |\n// |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |\n// | /_/   /_/   \\__,_/_/|_|  /_/   /_/_/ /_/\\__,_/_/ /_/\\___/\\___/   |\n// |                                                                  |\n// ====================================================================\n// ========================== Timelock2Step ===========================\n// ====================================================================\n// Frax Finance: https://github.com/FraxFinance\n\n// Primary Author\n// Drake Evans: https://github.com/DrakeEvans\n\n// Reviewers\n// Dennis: https://github.com/denett\n\n// ====================================================================\n\n/// @title Timelock2Step\n/// @author Drake Evans (Frax Finance) https://github.com/drakeevans\n/// @dev Inspired by the OpenZeppelin's Ownable2Step contract\n/// @notice  An abstract contract which contains 2-step transfer and renounce logic for a timelock address\nabstract contract Timelock2Step {\n    /// @notice The pending timelock address\n    address public pendingTimelockAddress;\n\n    /// @notice The current timelock address\n    address public timelockAddress;\n\n    constructor() {\n        timelockAddress = msg.sender;\n    }\n\n    /// @notice Emitted when timelock is transferred\n    error OnlyTimelock();\n\n    /// @notice Emitted when pending timelock is transferred\n    error OnlyPendingTimelock();\n\n    /// @notice The ```TimelockTransferStarted``` event is emitted when the timelock transfer is initiated\n    /// @param previousTimelock The address of the previous timelock\n    /// @param newTimelock The address of the new timelock\n    event TimelockTransferStarted(address indexed previousTimelock, address indexed newTimelock);\n\n    /// @notice The ```TimelockTransferred``` event is emitted when the timelock transfer is completed\n    /// @param previousTimelock The address of the previous timelock\n    /// @param newTimelock The address of the new timelock\n    event TimelockTransferred(address indexed previousTimelock, address indexed newTimelock);\n\n    /// @notice The ```_isSenderTimelock``` function checks if msg.sender is current timelock address\n    /// @return Whether or not msg.sender is current timelock address\n    function _isSenderTimelock() internal view returns (bool) {\n        return msg.sender == timelockAddress;\n    }\n\n    /// @notice The ```_requireTimelock``` function reverts if msg.sender is not current timelock address\n    function _requireTimelock() internal view {\n        if (msg.sender != timelockAddress) revert OnlyTimelock();\n    }\n\n    /// @notice The ```_isSenderPendingTimelock``` function checks if msg.sender is pending timelock address\n    /// @return Whether or not msg.sender is pending timelock address\n    function _isSenderPendingTimelock() internal view returns (bool) {\n        return msg.sender == pendingTimelockAddress;\n    }\n\n    /// @notice The ```_requirePendingTimelock``` function reverts if msg.sender is not pending timelock address\n    function _requirePendingTimelock() internal view {\n        if (msg.sender != pendingTimelockAddress) revert OnlyPendingTimelock();\n    }\n\n    /// @notice The ```_transferTimelock``` function initiates the timelock transfer\n    /// @dev This function is to be implemented by a public function\n    /// @param _newTimelock The address of the nominated (pending) timelock\n    function _transferTimelock(address _newTimelock) internal {\n        pendingTimelockAddress = _newTimelock;\n        emit TimelockTransferStarted(timelockAddress, _newTimelock);\n    }\n\n    /// @notice The ```_acceptTransferTimelock``` function completes the timelock transfer\n    /// @dev This function is to be implemented by a public function\n    function _acceptTransferTimelock() internal {\n        pendingTimelockAddress = address(0);\n        _setTimelock(msg.sender);\n    }\n\n    /// @notice The ```_setTimelock``` function sets the timelock address\n    /// @dev This function is to be implemented by a public function\n    /// @param _newTimelock The address of the new timelock\n    function _setTimelock(address _newTimelock) internal {\n        emit TimelockTransferred(timelockAddress, _newTimelock);\n        timelockAddress = _newTimelock;\n    }\n\n    /// @notice The ```transferTimelock``` function initiates the timelock transfer\n    /// @dev Must be called by the current timelock\n    /// @param _newTimelock The address of the nominated (pending) timelock\n    function transferTimelock(address _newTimelock) external virtual {\n        _requireTimelock();\n        _transferTimelock(_newTimelock);\n    }\n\n    /// @notice The ```acceptTransferTimelock``` function completes the timelock transfer\n    /// @dev Must be called by the pending timelock\n    function acceptTransferTimelock() external virtual {\n        _requirePendingTimelock();\n        _acceptTransferTimelock();\n    }\n\n    /// @notice The ```renounceTimelock``` function renounces the timelock after setting pending timelock to current timelock\n    /// @dev Pending timelock must be set to current timelock before renouncing, creating a 2-step renounce process\n    function renounceTimelock() external virtual {\n        _requireTimelock();\n        _requirePendingTimelock();\n        _transferTimelock(address(0));\n        _setTimelock(address(0));\n    }\n}\n"
      },
      "node_modules/frax-standard-solidity/src/access-control/v1/interfaces/ITimelock2Step.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.0;\n\ninterface ITimelock2Step {\n    event TimelockTransferStarted(address indexed previousTimelock, address indexed newTimelock);\n    event TimelockTransferred(address indexed previousTimelock, address indexed newTimelock);\n\n    function acceptTransferTimelock() external;\n\n    function pendingTimelockAddress() external view returns (address);\n\n    function renounceTimelock() external;\n\n    function timelockAddress() external view returns (address);\n\n    function transferTimelock(address _newTimelock) external;\n}\n"
      },
      "src/contracts/DualOracleBase.sol": {
        "content": "// SPDX-License-Identifier: ISC\npragma solidity ^0.8.20;\n\n// ====================================================================\n// |     ______                   _______                             |\n// |    / _____________ __  __   / ____(_____  ____ _____  ________   |\n// |   / /_  / ___/ __ `| |/_/  / /_  / / __ \\/ __ `/ __ \\/ ___/ _ \\  |\n// |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |\n// | /_/   /_/   \\__,_/_/|_|  /_/   /_/_/ /_/\\__,_/_/ /_/\\___/\\___/   |\n// |                                                                  |\n// ====================================================================\n// ========================== DualOracleBase ==========================\n// ====================================================================\n// Frax Finance: https://github.com/FraxFinance\n\n// Author\n// Drake Evans: https://github.com/DrakeEvans\n\n// ====================================================================\n\nimport \"interfaces/IDualOracle.sol\";\n\nstruct ConstructorParams {\n    address baseToken0;\n    uint8 baseToken0Decimals;\n    address quoteToken0;\n    uint8 quoteToken0Decimals;\n    address baseToken1;\n    uint8 baseToken1Decimals;\n    address quoteToken1;\n    uint8 quoteToken1Decimals;\n}\n\n/// @title DualOracleBase\n/// @author Drake Evans (Frax Finance) https://github.com/drakeevans\n/// @notice  Base Contract for Frax Dual Oracles\nabstract contract DualOracleBase is IDualOracle {\n    /// @notice The precision of the oracle\n    uint256 public constant ORACLE_PRECISION = 1e18;\n\n    /// @notice The first quote token\n    address public immutable QUOTE_TOKEN_0;\n\n    /// @notice The first quote token decimals\n    uint256 public immutable QUOTE_TOKEN_0_DECIMALS;\n\n    /// @notice The second quote token\n    address public immutable QUOTE_TOKEN_1;\n\n    /// @notice The second quote token decimals\n    uint256 public immutable QUOTE_TOKEN_1_DECIMALS;\n\n    /// @notice The first base token\n    address public immutable BASE_TOKEN_0;\n\n    /// @notice The first base token decimals\n    uint256 public immutable BASE_TOKEN_0_DECIMALS;\n\n    /// @notice The second base token\n    address public immutable BASE_TOKEN_1;\n\n    /// @notice The second base token decimals\n    uint256 public immutable BASE_TOKEN_1_DECIMALS;\n\n    /// @notice The first normalization factor which accounts for different decimals across ERC20s\n    /// @dev Normalization = quoteTokenDecimals - baseTokenDecimals\n    int256 public immutable NORMALIZATION_0;\n\n    /// @notice The second normalization factor which accounts for different decimals across ERC20s\n    /// @dev Normalization = quoteTokenDecimals - baseTokenDecimals\n    int256 public immutable NORMALIZATION_1;\n\n    constructor(ConstructorParams memory _params) {\n        QUOTE_TOKEN_0 = _params.quoteToken0;\n        QUOTE_TOKEN_0_DECIMALS = _params.quoteToken0Decimals;\n        QUOTE_TOKEN_1 = _params.quoteToken1;\n        QUOTE_TOKEN_1_DECIMALS = _params.quoteToken1Decimals;\n        BASE_TOKEN_0 = _params.baseToken0;\n        BASE_TOKEN_0_DECIMALS = _params.baseToken0Decimals;\n        BASE_TOKEN_1 = _params.baseToken1;\n        BASE_TOKEN_1_DECIMALS = _params.baseToken1Decimals;\n        NORMALIZATION_0 = int256(QUOTE_TOKEN_0_DECIMALS) - int256(BASE_TOKEN_0_DECIMALS);\n        NORMALIZATION_1 = int256(QUOTE_TOKEN_1_DECIMALS) - int256(BASE_TOKEN_1_DECIMALS);\n    }\n\n    // ====================================================================\n    // View Helpers\n    // ====================================================================\n\n    function decimals() external pure returns (uint8) {\n        return 18;\n    }\n}\n"
      },
      "src/contracts/interfaces/oracles/abstracts/ICurvePoolEmaPriceOracleWithMinMax.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.20;\n\nimport { IERC165 } from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\n\ninterface ICurvePoolEmaPriceOracleWithMinMax is IERC165 {\n    event SetMaximumCurvePoolEma(uint256 oldMaximum, uint256 newMaximum);\n    event SetMinimumCurvePoolEma(uint256 oldMinimum, uint256 newMinimum);\n\n    function CURVE_POOL_EMA_PRICE_ORACLE() external view returns (address);\n\n    function CURVE_POOL_EMA_PRICE_ORACLE_PRECISION() external view returns (uint256);\n\n    function getCurvePoolToken1EmaPrice() external view returns (uint256 _emaPrice);\n\n    function maximumCurvePoolEma() external view returns (uint256);\n\n    function minimumCurvePoolEma() external view returns (uint256);\n\n    function setMaximumCurvePoolEma(uint256 _maximumPrice) external;\n\n    function setMinimumCurvePoolEma(uint256 _minimumPrice) external;\n}\n"
      },
      "src/contracts/interfaces/IEmaPriceOracleStableSwap.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >=0.8.20;\n\ninterface IEmaPriceOracleStableSwap {\n    function price_oracle() external view returns (uint256);\n}\n\ninterface IEmaPriceOracleStableSwapNG {\n    function price_oracle(uint256) external view returns (uint256);\n}\n"
      },
      "src/contracts/utils/ERC165Storage.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165Storage.sol)\npragma solidity ^0.8.0;\n\nimport { ERC165 } from \"@openzeppelin/contracts/utils/introspection/ERC165.sol\";\n\n/**\n * @dev Storage based implementation of the {IERC165} interface.\n *\n * Contracts may inherit from this and call {_registerInterface} to declare\n * their support of an interface.\n */\nabstract contract ERC165Storage is ERC165 {\n    /**\n     * @dev Mapping of interface ids to whether or not it's supported.\n     */\n    mapping(bytes4 => bool) private _supportedInterfaces;\n\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return super.supportsInterface(interfaceId) || _supportedInterfaces[interfaceId];\n    }\n\n    /**\n     * @dev Registers the contract as an implementer of the interface defined by\n     * `interfaceId`. Support of the actual ERC165 interface is automatic and\n     * registering its interface id is not required.\n     *\n     * See {IERC165-supportsInterface}.\n     *\n     * Requirements:\n     *\n     * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).\n     */\n    function _registerInterface(bytes4 interfaceId) internal virtual {\n        require(interfaceId != 0xffffffff, \"ERC165: invalid interface id\");\n        _supportedInterfaces[interfaceId] = true;\n    }\n}\n"
      },
      "src/contracts/interfaces/ISUSDE.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.19;\n\ninterface ISUSDE {\n    function previewRedeem(uint256) external view returns (uint256);\n}\n"
      },
      "src/contracts/interfaces/IDualOracle.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity 0.8.20;\n\nimport \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\n\ninterface IDualOracle is IERC165 {\n    function ORACLE_PRECISION() external view returns (uint256);\n\n    function BASE_TOKEN_0() external view returns (address);\n\n    function BASE_TOKEN_0_DECIMALS() external view returns (uint256);\n\n    function BASE_TOKEN_1() external view returns (address);\n\n    function BASE_TOKEN_1_DECIMALS() external view returns (uint256);\n\n    function decimals() external view returns (uint8);\n\n    function getPricesNormalized() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh);\n\n    function getPrices() external view returns (bool _isBadData, uint256 _priceLow, uint256 _priceHigh);\n\n    function name() external view returns (string memory);\n\n    function NORMALIZATION_0() external view returns (int256);\n\n    function NORMALIZATION_1() external view returns (int256);\n\n    function QUOTE_TOKEN_0() external view returns (address);\n\n    function QUOTE_TOKEN_0_DECIMALS() external view returns (uint256);\n\n    function QUOTE_TOKEN_1() external view returns (address);\n\n    function QUOTE_TOKEN_1_DECIMALS() external view returns (uint256);\n}\n"
      },
      "node_modules/@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"
      },
      "node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n        return interfaceId == type(IERC165).interfaceId;\n    }\n}\n"
      }
    },
    "settings": {
      "remappings": [
        "ds-test/=node_modules/ds-test/src/",
        "forge-std/=node_modules/forge-std/src/",
        "frax-std/=node_modules/frax-standard-solidity/src/",
        "script/=src/script/",
        "src/=src/",
        "test/=src/test/",
        "interfaces/=src/contracts/interfaces/",
        "arbitrum/=node_modules/@arbitrum/",
        "rlp/=node_modules/solidity-rlp/contracts/",
        "@solmate/=node_modules/@rari-capital/solmate/src/",
        "@arbitrum/=node_modules/@arbitrum/",
        "@chainlink/=node_modules/@chainlink/",
        "@eth-optimism/=node_modules/@eth-optimism/",
        "@mean-finance/=node_modules/@mean-finance/",
        "@offchainlabs/=node_modules/@offchainlabs/",
        "@openzeppelin/=node_modules/@openzeppelin/",
        "@rari-capital/=node_modules/@rari-capital/",
        "@uniswap/=node_modules/@uniswap/",
        "base64-sol/=node_modules/base64-sol/",
        "frax-standard-solidity/=node_modules/frax-standard-solidity/",
        "hardhat/=node_modules/hardhat/",
        "prb-math/=node_modules/prb-math/",
        "solidity-bytes-utils/=node_modules/solidity-bytes-utils/",
        "solidity-rlp/=node_modules/solidity-rlp/"
      ],
      "optimizer": {
        "enabled": true,
        "runs": 1000000
      },
      "metadata": {
        "useLiteralContent": false,
        "bytecodeHash": "none",
        "appendCBOR": true
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "evmVersion": "shanghai",
      "viaIR": false,
      "libraries": {}
    }
  }}