creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "contracts/oracle/error.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\ncontract Error {\n    error FluidOracleError(uint256 errorId_);\n}\n"
      },
      "contracts/oracle/errorTypes.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nlibrary ErrorTypes {\n    /***********************************|\n    |           FluidOracleL2           | \n    |__________________________________*/\n\n    /// @notice thrown when sequencer on a L2 has an outage and grace period has not yet passed.\n    uint256 internal constant FluidOracleL2__SequencerOutage = 60000;\n\n    /***********************************|\n    |     UniV3CheckCLRSOracle          | \n    |__________________________________*/\n\n    /// @notice thrown when the delta between main price source and check rate source is exceeding the allowed delta\n    uint256 internal constant UniV3CheckCLRSOracle__InvalidPrice = 60001;\n\n    /// @notice thrown when an invalid parameter is passed to a method\n    uint256 internal constant UniV3CheckCLRSOracle__InvalidParams = 60002;\n\n    /// @notice thrown when the exchange rate is zero, even after all possible fallbacks depending on config\n    uint256 internal constant UniV3CheckCLRSOracle__ExchangeRateZero = 60003;\n\n    /***********************************|\n    |            sUSDe Oracle           | \n    |__________________________________*/\n\n    /// @notice thrown when an invalid parameter is passed to a method\n    uint256 internal constant SUSDeOracle__InvalidParams = 60102;\n\n    /***********************************|\n    |           Pendle Oracle           | \n    |__________________________________*/\n\n    /// @notice thrown when an invalid parameter is passed to a method\n    uint256 internal constant PendleOracle__InvalidParams = 60201;\n\n    /// @notice thrown when the Pendle market Oracle has not been initialized yet\n    uint256 internal constant PendleOracle__MarketNotInitialized = 60202;\n\n    /// @notice thrown when the Pendle market does not have 18 decimals\n    uint256 internal constant PendleOracle__MarketInvalidDecimals = 60203;\n\n    /// @notice thrown when the Pendle market returns an unexpected price\n    uint256 internal constant PendleOracle__InvalidPrice = 60204;\n\n    /***********************************|\n    |          Chainlink Oracle         | \n    |__________________________________*/\n\n    /// @notice thrown when an invalid parameter is passed to a method\n    uint256 internal constant ChainlinkOracle__InvalidParams = 61001;\n\n    /***********************************|\n    |          UniswapV3 Oracle         | \n    |__________________________________*/\n\n    /// @notice thrown when an invalid parameter is passed to a method\n    uint256 internal constant UniV3Oracle__InvalidParams = 62001;\n\n    /// @notice thrown when constructor is called with invalid ordered seconds agos values\n    uint256 internal constant UniV3Oracle__InvalidSecondsAgos = 62002;\n\n    /// @notice thrown when constructor is called with invalid delta values > 100%\n    uint256 internal constant UniV3Oracle__InvalidDeltas = 62003;\n\n    /***********************************|\n    |            WstETh Oracle          | \n    |__________________________________*/\n\n    /// @notice thrown when an invalid parameter is passed to a method\n    uint256 internal constant WstETHOracle__InvalidParams = 63001;\n\n    /***********************************|\n    |           Redstone Oracle         | \n    |__________________________________*/\n\n    /// @notice thrown when an invalid parameter is passed to a method\n    uint256 internal constant RedstoneOracle__InvalidParams = 64001;\n\n    /***********************************|\n    |          Fallback Oracle          | \n    |__________________________________*/\n\n    /// @notice thrown when an invalid parameter is passed to a method\n    uint256 internal constant FallbackOracle__InvalidParams = 65001;\n\n    /***********************************|\n    |       FallbackCLRSOracle          | \n    |__________________________________*/\n\n    /// @notice thrown when the exchange rate is zero, even for the fallback oracle source (if enabled)\n    uint256 internal constant FallbackCLRSOracle__ExchangeRateZero = 66001;\n\n    /***********************************|\n    |         WstETHCLRSOracle          | \n    |__________________________________*/\n\n    /// @notice thrown when the exchange rate is zero, even for the fallback oracle source (if enabled)\n    uint256 internal constant WstETHCLRSOracle__ExchangeRateZero = 67001;\n\n    /***********************************|\n    |        CLFallbackUniV3Oracle      | \n    |__________________________________*/\n\n    /// @notice thrown when the exchange rate is zero, even for the uniV3 rate\n    uint256 internal constant CLFallbackUniV3Oracle__ExchangeRateZero = 68001;\n\n    /***********************************|\n    |  WstETHCLRS2UniV3CheckCLRSOracle  | \n    |__________________________________*/\n\n    /// @notice thrown when the exchange rate is zero, even for the uniV3 rate\n    uint256 internal constant WstETHCLRS2UniV3CheckCLRSOracle__ExchangeRateZero = 69001;\n\n    /***********************************|\n    |             WeETh Oracle          | \n    |__________________________________*/\n\n    /// @notice thrown when an invalid parameter is passed to a method\n    uint256 internal constant WeETHOracle__InvalidParams = 70001;\n}\n"
      },
      "contracts/oracle/fluidOracle.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IFluidOracle } from \"./interfaces/iFluidOracle.sol\";\n\n/// @title   FluidOracle\n/// @notice  Base contract that any Fluid Oracle must implement\nabstract contract FluidOracle is IFluidOracle {\n    /// @inheritdoc IFluidOracle\n    function getExchangeRate() external view virtual returns (uint256 exchangeRate_);\n\n    /// @inheritdoc IFluidOracle\n    function getExchangeRateOperate() external view virtual returns (uint256 exchangeRate_);\n\n    /// @inheritdoc IFluidOracle\n    function getExchangeRateLiquidate() external view virtual returns (uint256 exchangeRate_);\n}\n"
      },
      "contracts/oracle/implementations/chainlinkOracleImpl.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { ErrorTypes } from \"../errorTypes.sol\";\nimport { IChainlinkAggregatorV3 } from \"../interfaces/external/IChainlinkAggregatorV3.sol\";\nimport { Error as OracleError } from \"../error.sol\";\nimport { OracleUtils } from \"../libraries/oracleUtils.sol\";\nimport { ChainlinkStructs } from \"./structs.sol\";\n\n/// @title   Chainlink Oracle implementation\n/// @notice  This contract is used to get the exchange rate via up to 3 hops at Chainlink price feeds.\n///          The rate is multiplied with the previous rate at each hop.\n///          E.g. to go from wBTC to USDC (assuming rates for example):\n///          1. wBTC -> BTC https://data.chain.link/ethereum/mainnet/crypto-other/wbtc-btc, rate: 0.92.\n///          2. BTC -> USD https://data.chain.link/ethereum/mainnet/crypto-usd/btc-usd rate: 30,000.\n///          3. USD -> USDC https://data.chain.link/ethereum/mainnet/stablecoins/usdc-usd rate: 0.98. Must invert feed: 1.02\n///          finale rate would be: 0.92 * 30,000 * 1.02 = 28,152\nabstract contract ChainlinkOracleImpl is OracleError, ChainlinkStructs {\n    /// @notice Chainlink price feed 1 to check for the exchange rate\n    IChainlinkAggregatorV3 internal immutable _CHAINLINK_FEED1;\n    /// @notice Chainlink price feed 2 to check for the exchange rate\n    IChainlinkAggregatorV3 internal immutable _CHAINLINK_FEED2;\n    /// @notice Chainlink price feed 3 to check for the exchange rate\n    IChainlinkAggregatorV3 internal immutable _CHAINLINK_FEED3;\n\n    /// @notice Flag to invert the price or not for feed 1 (to e.g. for WETH/USDC pool return prive of USDC per 1 WETH)\n    bool internal immutable _CHAINLINK_INVERT_RATE1;\n    /// @notice Flag to invert the price or not for feed 2 (to e.g. for WETH/USDC pool return prive of USDC per 1 WETH)\n    bool internal immutable _CHAINLINK_INVERT_RATE2;\n    /// @notice Flag to invert the price or not for feed 3 (to e.g. for WETH/USDC pool return prive of USDC per 1 WETH)\n    bool internal immutable _CHAINLINK_INVERT_RATE3;\n\n    /// @notice constant value for price scaling to reduce gas usage for feed 1\n    uint256 internal immutable _CHAINLINK_PRICE_SCALER_MULTIPLIER1;\n    /// @notice constant value for inverting price to reduce gas usage for feed 1\n    uint256 internal immutable _CHAINLINK_INVERT_PRICE_DIVIDEND1;\n\n    /// @notice constant value for price scaling to reduce gas usage for feed 2\n    uint256 internal immutable _CHAINLINK_PRICE_SCALER_MULTIPLIER2;\n    /// @notice constant value for inverting price to reduce gas usage for feed 2\n    uint256 internal immutable _CHAINLINK_INVERT_PRICE_DIVIDEND2;\n\n    /// @notice constant value for price scaling to reduce gas usage for feed 3\n    uint256 internal immutable _CHAINLINK_PRICE_SCALER_MULTIPLIER3;\n    /// @notice constant value for inverting price to reduce gas usage for feed 3\n    uint256 internal immutable _CHAINLINK_INVERT_PRICE_DIVIDEND3;\n\n    /// @notice constructor sets the Chainlink price feed and invertRate flag for each hop.\n    /// E.g. `invertRate_` should be true if for the USDC/ETH pool it's expected that the oracle returns USDC per 1 ETH\n    constructor(ChainlinkConstructorParams memory params_) {\n        if (\n            (params_.hops < 1 || params_.hops > 3) || // hops must be 1, 2 or 3\n            (address(params_.feed1.feed) == address(0) || params_.feed1.token0Decimals == 0) || // first feed must always be defined\n            (params_.hops > 1 && (address(params_.feed2.feed) == address(0) || params_.feed2.token0Decimals == 0)) || // if hops > 1, feed 2 must be defined\n            (params_.hops > 2 && (address(params_.feed3.feed) == address(0) || params_.feed3.token0Decimals == 0)) // if hops > 2, feed 3 must be defined\n        ) {\n            revert FluidOracleError(ErrorTypes.ChainlinkOracle__InvalidParams);\n        }\n\n        _CHAINLINK_FEED1 = params_.feed1.feed;\n        _CHAINLINK_FEED2 = params_.feed2.feed;\n        _CHAINLINK_FEED3 = params_.feed3.feed;\n\n        _CHAINLINK_INVERT_RATE1 = params_.feed1.invertRate;\n        _CHAINLINK_INVERT_RATE2 = params_.feed2.invertRate;\n        _CHAINLINK_INVERT_RATE3 = params_.feed3.invertRate;\n\n        // Actual desired output rate example USDC/ETH (6 decimals / 18 decimals).\n        // Note ETH has 12 decimals more than USDC.\n        //    0.000515525322211842331991619857165357691 // 39 decimals.  ETH for 1 USDC\n        // 1954.190000000000433             // 15 decimals. USDC for 1 ETH\n\n        // to get to PRICE_SCLAER_MULTIPLIER and INVERT_PRICE_DIVIDEND:\n        // fetched Chainlink price is in token1Decimals per 1 token0Decimals.\n        // E.g. for an USDC/ETH price feed it's in ETH 18 decimals.\n        //      for an  BTC/USD price feed it's in USD  8 decimals.\n        // So to scale to 1e27 we need to multiply by 1e27 - token0Decimals.\n        // E.g. for USDC/ETH it would be: fetchedPrice * 1e21\n        //\n        // or for inverted (x token0 per 1 token1), formula would be:\n        //    = 1e27 * 10**token0Decimals / fetchedPrice\n        // E.g. for USDC/ETH it would be: 1e33 / fetchedPrice\n\n        // no support for token1Decimals with more than OracleUtils.RATE_OUTPUT_DECIMALS decimals for now as extremely unlikely case\n        _CHAINLINK_PRICE_SCALER_MULTIPLIER1 = 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS - params_.feed1.token0Decimals);\n        _CHAINLINK_INVERT_PRICE_DIVIDEND1 = 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS + params_.feed1.token0Decimals);\n\n        _CHAINLINK_PRICE_SCALER_MULTIPLIER2 = params_.hops > 1\n            ? 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS - params_.feed2.token0Decimals)\n            : 1;\n        _CHAINLINK_INVERT_PRICE_DIVIDEND2 = params_.hops > 1\n            ? 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS + params_.feed2.token0Decimals)\n            : 1;\n\n        _CHAINLINK_PRICE_SCALER_MULTIPLIER3 = params_.hops > 2\n            ? 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS - params_.feed3.token0Decimals)\n            : 1;\n        _CHAINLINK_INVERT_PRICE_DIVIDEND3 = params_.hops > 2\n            ? 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS + params_.feed3.token0Decimals)\n            : 1;\n    }\n\n    /// @dev            Get the exchange rate from Chainlike oracle price feed(s)\n    /// @return rate_   The exchange rate in `OracleUtils.RATE_OUTPUT_DECIMALS`\n    function _getChainlinkExchangeRate() internal view returns (uint256 rate_) {\n        rate_ = _readFeedRate(\n            _CHAINLINK_FEED1,\n            _CHAINLINK_INVERT_RATE1,\n            _CHAINLINK_PRICE_SCALER_MULTIPLIER1,\n            _CHAINLINK_INVERT_PRICE_DIVIDEND1\n        );\n        if (rate_ == 0 || address(_CHAINLINK_FEED2) == address(0)) {\n            // rate 0 or only 1 hop -> return rate of price feed 1\n            return rate_;\n        }\n        rate_ =\n            (rate_ *\n                _readFeedRate(\n                    _CHAINLINK_FEED2,\n                    _CHAINLINK_INVERT_RATE2,\n                    _CHAINLINK_PRICE_SCALER_MULTIPLIER2,\n                    _CHAINLINK_INVERT_PRICE_DIVIDEND2\n                )) /\n            (10 ** OracleUtils.RATE_OUTPUT_DECIMALS);\n\n        if (rate_ == 0 || address(_CHAINLINK_FEED3) == address(0)) {\n            // rate 0 or 2 hops -> return rate of feed 1 combined with feed 2\n            return rate_;\n        }\n\n        // 3 hops -> return rate of feed 1 combined with feed 2 & feed 3\n        rate_ =\n            (rate_ *\n                _readFeedRate(\n                    _CHAINLINK_FEED3,\n                    _CHAINLINK_INVERT_RATE3,\n                    _CHAINLINK_PRICE_SCALER_MULTIPLIER3,\n                    _CHAINLINK_INVERT_PRICE_DIVIDEND3\n                )) /\n            (10 ** OracleUtils.RATE_OUTPUT_DECIMALS);\n    }\n\n    /// @dev reads the exchange `rate_` from a Chainlink price `feed_` taking into account scaling and `invertRate_`\n    function _readFeedRate(\n        IChainlinkAggregatorV3 feed_,\n        bool invertRate_,\n        uint256 priceMultiplier_,\n        uint256 invertDividend_\n    ) private view returns (uint256 rate_) {\n        try feed_.latestRoundData() returns (uint80, int256 exchangeRate_, uint256, uint256, uint80) {\n            // Return the price in `OracleUtils.RATE_OUTPUT_DECIMALS`\n            if (invertRate_) {\n                return invertDividend_ / uint256(exchangeRate_);\n            } else {\n                return uint256(exchangeRate_) * priceMultiplier_;\n            }\n        } catch {\n            return 0;\n        }\n    }\n\n    /// @notice returns all Chainlink oracle related data as utility for easy off-chain use / block explorer in a single view method\n    function chainlinkOracleData()\n        public\n        view\n        returns (\n            uint256 chainlinkExchangeRate_,\n            IChainlinkAggregatorV3 chainlinkFeed1_,\n            bool chainlinkInvertRate1_,\n            uint256 chainlinkExchangeRate1_,\n            IChainlinkAggregatorV3 chainlinkFeed2_,\n            bool chainlinkInvertRate2_,\n            uint256 chainlinkExchangeRate2_,\n            IChainlinkAggregatorV3 chainlinkFeed3_,\n            bool chainlinkInvertRate3_,\n            uint256 chainlinkExchangeRate3_\n        )\n    {\n        return (\n            _getChainlinkExchangeRate(),\n            _CHAINLINK_FEED1,\n            _CHAINLINK_INVERT_RATE1,\n            _readFeedRate(\n                _CHAINLINK_FEED1,\n                _CHAINLINK_INVERT_RATE1,\n                _CHAINLINK_PRICE_SCALER_MULTIPLIER1,\n                _CHAINLINK_INVERT_PRICE_DIVIDEND1\n            ),\n            _CHAINLINK_FEED2,\n            _CHAINLINK_INVERT_RATE2,\n            address(_CHAINLINK_FEED2) == address(0)\n                ? 0\n                : _readFeedRate(\n                    _CHAINLINK_FEED2,\n                    _CHAINLINK_INVERT_RATE2,\n                    _CHAINLINK_PRICE_SCALER_MULTIPLIER2,\n                    _CHAINLINK_INVERT_PRICE_DIVIDEND2\n                ),\n            _CHAINLINK_FEED3,\n            _CHAINLINK_INVERT_RATE3,\n            address(_CHAINLINK_FEED3) == address(0)\n                ? 0\n                : _readFeedRate(\n                    _CHAINLINK_FEED3,\n                    _CHAINLINK_INVERT_RATE3,\n                    _CHAINLINK_PRICE_SCALER_MULTIPLIER3,\n                    _CHAINLINK_INVERT_PRICE_DIVIDEND3\n                )\n        );\n    }\n}\n"
      },
      "contracts/oracle/implementations/chainlinkOracleImpl2.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { ErrorTypes } from \"../errorTypes.sol\";\nimport { IChainlinkAggregatorV3 } from \"../interfaces/external/IChainlinkAggregatorV3.sol\";\nimport { Error as OracleError } from \"../error.sol\";\nimport { OracleUtils } from \"../libraries/oracleUtils.sol\";\nimport { ChainlinkStructs } from \"./structs.sol\";\n\n//  @dev     Exact same contract as ChainlinkOracleImpl, just with all vars, immutables etc. renamed with a \"2\" to avoid\n//           conflicts when ChainlinkOracleImpl would have to be inherited twice.\n\n/// @title   Chainlink Oracle implementation.\n/// @notice  This contract is used to get the exchange rate via up to 3 hops at Chainlink price feeds.\n///          The rate is multiplied with the previous rate at each hop.\n///          E.g. to go from wBTC to USDC (assuming rates for example):\n///          1. wBTC -> BTC https://data.chain.link/ethereum/mainnet/crypto-other/wbtc-btc, rate: 0.92.\n///          2. BTC -> USD https://data.chain.link/ethereum/mainnet/crypto-usd/btc-usd rate: 30,000.\n///          3. USD -> USDC https://data.chain.link/ethereum/mainnet/stablecoins/usdc-usd rate: 0.98. Must invert feed: 1.02\n///          finale rate would be: 0.92 * 30,000 * 1.02 = 28,152\nabstract contract ChainlinkOracleImpl2 is OracleError, ChainlinkStructs {\n    /// @notice Chainlink price feed 1 to check for the exchange rate\n    IChainlinkAggregatorV3 internal immutable _CHAINLINK2_FEED1;\n    /// @notice Chainlink price feed 2 to check for the exchange rate\n    IChainlinkAggregatorV3 internal immutable _CHAINLINK2_FEED2;\n    /// @notice Chainlink price feed 3 to check for the exchange rate\n    IChainlinkAggregatorV3 internal immutable _CHAINLINK2_FEED3;\n\n    /// @notice Flag to invert the price or not for feed 1 (to e.g. for WETH/USDC pool return prive of USDC per 1 WETH)\n    bool internal immutable _CHAINLINK2_INVERT_RATE1;\n    /// @notice Flag to invert the price or not for feed 2 (to e.g. for WETH/USDC pool return prive of USDC per 1 WETH)\n    bool internal immutable _CHAINLINK2_INVERT_RATE2;\n    /// @notice Flag to invert the price or not for feed 3 (to e.g. for WETH/USDC pool return prive of USDC per 1 WETH)\n    bool internal immutable _CHAINLINK2_INVERT_RATE3;\n\n    /// @notice constant value for price scaling to reduce gas usage for feed 1\n    uint256 internal immutable _CHAINLINK2_PRICE_SCALER_MULTIPLIER1;\n    /// @notice constant value for inverting price to reduce gas usage for feed 1\n    uint256 internal immutable _CHAINLINK2_INVERT_PRICE_DIVIDEND1;\n\n    /// @notice constant value for price scaling to reduce gas usage for feed 2\n    uint256 internal immutable _CHAINLINK2_PRICE_SCALER_MULTIPLIER2;\n    /// @notice constant value for inverting price to reduce gas usage for feed 2\n    uint256 internal immutable _CHAINLINK2_INVERT_PRICE_DIVIDEND2;\n\n    /// @notice constant value for price scaling to reduce gas usage for feed 3\n    uint256 internal immutable _CHAINLINK2_PRICE_SCALER_MULTIPLIER3;\n    /// @notice constant value for inverting price to reduce gas usage for feed 3\n    uint256 internal immutable _CHAINLINK2_INVERT_PRICE_DIVIDEND3;\n\n    /// @notice constructor sets the Chainlink price feed and invertRate flag for each hop.\n    /// E.g. `invertRate_` should be true if for the USDC/ETH pool it's expected that the oracle returns USDC per 1 ETH\n    constructor(ChainlinkConstructorParams memory params_) {\n        if (\n            (params_.hops < 1 || params_.hops > 3) || // hops must be 1, 2 or 3\n            (address(params_.feed1.feed) == address(0) || params_.feed1.token0Decimals == 0) || // first feed must always be defined\n            (params_.hops > 1 && (address(params_.feed2.feed) == address(0) || params_.feed2.token0Decimals == 0)) || // if hops > 1, feed 2 must be defined\n            (params_.hops > 2 && (address(params_.feed3.feed) == address(0) || params_.feed3.token0Decimals == 0)) // if hops > 2, feed 3 must be defined\n        ) {\n            revert FluidOracleError(ErrorTypes.ChainlinkOracle__InvalidParams);\n        }\n\n        _CHAINLINK2_FEED1 = params_.feed1.feed;\n        _CHAINLINK2_FEED2 = params_.feed2.feed;\n        _CHAINLINK2_FEED3 = params_.feed3.feed;\n\n        _CHAINLINK2_INVERT_RATE1 = params_.feed1.invertRate;\n        _CHAINLINK2_INVERT_RATE2 = params_.feed2.invertRate;\n        _CHAINLINK2_INVERT_RATE3 = params_.feed3.invertRate;\n\n        // Actual desired output rate example USDC/ETH (6 decimals / 18 decimals).\n        // Note ETH has 12 decimals more than USDC.\n        //    0.000515525322211842331991619857165357691 // 39 decimals.  ETH for 1 USDC\n        // 1954.190000000000433             // 15 decimals. USDC for 1 ETH\n\n        // to get to PRICE_SCLAER_MULTIPLIER and INVERT_PRICE_DIVIDEND:\n        // fetched Chainlink price is in token1Decimals per 1 token0Decimals.\n        // E.g. for an USDC/ETH price feed it's in ETH 18 decimals.\n        //      for an  BTC/USD price feed it's in USD  8 decimals.\n        // So to scale to 1e27 we need to multiply by 1e27 - token0Decimals.\n        // E.g. for USDC/ETH it would be: fetchedPrice * 1e21\n        //\n        // or for inverted (x token0 per 1 token1), formula would be:\n        //    = 1e27 * 10**token0Decimals / fetchedPrice\n        // E.g. for USDC/ETH it would be: 1e33 / fetchedPrice\n\n        // no support for token1Decimals with more than OracleUtils.RATE_OUTPUT_DECIMALS decimals for now as extremely unlikely case\n        _CHAINLINK2_PRICE_SCALER_MULTIPLIER1 = 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS - params_.feed1.token0Decimals);\n        _CHAINLINK2_INVERT_PRICE_DIVIDEND1 = 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS + params_.feed1.token0Decimals);\n\n        _CHAINLINK2_PRICE_SCALER_MULTIPLIER2 = params_.hops > 1\n            ? 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS - params_.feed2.token0Decimals)\n            : 1;\n        _CHAINLINK2_INVERT_PRICE_DIVIDEND2 = params_.hops > 1\n            ? 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS + params_.feed2.token0Decimals)\n            : 1;\n\n        _CHAINLINK2_PRICE_SCALER_MULTIPLIER3 = params_.hops > 2\n            ? 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS - params_.feed3.token0Decimals)\n            : 1;\n        _CHAINLINK2_INVERT_PRICE_DIVIDEND3 = params_.hops > 2\n            ? 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS + params_.feed3.token0Decimals)\n            : 1;\n    }\n\n    /// @dev            Get the exchange rate from Chainlike oracle price feed(s)\n    /// @return rate_   The exchange rate in `OracleUtils.RATE_OUTPUT_DECIMALS`\n    function _getChainlinkExchangeRate2() internal view returns (uint256 rate_) {\n        rate_ = _readFeedRate2(\n            _CHAINLINK2_FEED1,\n            _CHAINLINK2_INVERT_RATE1,\n            _CHAINLINK2_PRICE_SCALER_MULTIPLIER1,\n            _CHAINLINK2_INVERT_PRICE_DIVIDEND1\n        );\n        if (rate_ == 0 || address(_CHAINLINK2_FEED2) == address(0)) {\n            // rate 0 or only 1 hop -> return rate of price feed 1\n            return rate_;\n        }\n        rate_ =\n            (rate_ *\n                _readFeedRate2(\n                    _CHAINLINK2_FEED2,\n                    _CHAINLINK2_INVERT_RATE2,\n                    _CHAINLINK2_PRICE_SCALER_MULTIPLIER2,\n                    _CHAINLINK2_INVERT_PRICE_DIVIDEND2\n                )) /\n            (10 ** OracleUtils.RATE_OUTPUT_DECIMALS);\n\n        if (rate_ == 0 || address(_CHAINLINK2_FEED3) == address(0)) {\n            // rate 0 or 2 hops -> return rate of feed 1 combined with feed 2\n            return rate_;\n        }\n\n        // 3 hops -> return rate of feed 1 combined with feed 2 & feed 3\n        rate_ =\n            (rate_ *\n                _readFeedRate2(\n                    _CHAINLINK2_FEED3,\n                    _CHAINLINK2_INVERT_RATE3,\n                    _CHAINLINK2_PRICE_SCALER_MULTIPLIER3,\n                    _CHAINLINK2_INVERT_PRICE_DIVIDEND3\n                )) /\n            (10 ** OracleUtils.RATE_OUTPUT_DECIMALS);\n    }\n\n    /// @dev reads the exchange `rate_` from a Chainlink price `feed_` taking into account scaling and `invertRate_`\n    function _readFeedRate2(\n        IChainlinkAggregatorV3 feed_,\n        bool invertRate_,\n        uint256 priceMultiplier_,\n        uint256 invertDividend_\n    ) private view returns (uint256 rate_) {\n        try feed_.latestRoundData() returns (uint80, int256 exchangeRate_, uint256, uint256, uint80) {\n            // Return the price in `OracleUtils.RATE_OUTPUT_DECIMALS`\n            if (invertRate_) {\n                return invertDividend_ / uint256(exchangeRate_);\n            } else {\n                return uint256(exchangeRate_) * priceMultiplier_;\n            }\n        } catch {\n            return 0;\n        }\n    }\n\n    /// @notice returns all Chainlink oracle related data as utility for easy off-chain use / block explorer in a single view method\n    function chainlinkOracleData2()\n        public\n        view\n        returns (\n            uint256 chainlinkExchangeRate_,\n            IChainlinkAggregatorV3 chainlinkFeed1_,\n            bool chainlinkInvertRate1_,\n            uint256 chainlinkExchangeRate1_,\n            IChainlinkAggregatorV3 chainlinkFeed2_,\n            bool chainlinkInvertRate2_,\n            uint256 chainlinkExchangeRate2_,\n            IChainlinkAggregatorV3 chainlinkFeed3_,\n            bool chainlinkInvertRate3_,\n            uint256 chainlinkExchangeRate3_\n        )\n    {\n        return (\n            _getChainlinkExchangeRate2(),\n            _CHAINLINK2_FEED1,\n            _CHAINLINK2_INVERT_RATE1,\n            _readFeedRate2(\n                _CHAINLINK2_FEED1,\n                _CHAINLINK2_INVERT_RATE1,\n                _CHAINLINK2_PRICE_SCALER_MULTIPLIER1,\n                _CHAINLINK2_INVERT_PRICE_DIVIDEND1\n            ),\n            _CHAINLINK2_FEED2,\n            _CHAINLINK2_INVERT_RATE2,\n            address(_CHAINLINK2_FEED2) == address(0)\n                ? 0\n                : _readFeedRate2(\n                    _CHAINLINK2_FEED2,\n                    _CHAINLINK2_INVERT_RATE2,\n                    _CHAINLINK2_PRICE_SCALER_MULTIPLIER2,\n                    _CHAINLINK2_INVERT_PRICE_DIVIDEND2\n                ),\n            _CHAINLINK2_FEED3,\n            _CHAINLINK2_INVERT_RATE3,\n            address(_CHAINLINK2_FEED3) == address(0)\n                ? 0\n                : _readFeedRate2(\n                    _CHAINLINK2_FEED3,\n                    _CHAINLINK2_INVERT_RATE3,\n                    _CHAINLINK2_PRICE_SCALER_MULTIPLIER3,\n                    _CHAINLINK2_INVERT_PRICE_DIVIDEND3\n                )\n        );\n    }\n}\n"
      },
      "contracts/oracle/implementations/fallbackOracleImpl.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { ErrorTypes } from \"../errorTypes.sol\";\nimport { IRedstoneOracle } from \"../interfaces/external/IRedstoneOracle.sol\";\nimport { Error as OracleError } from \"../error.sol\";\nimport { ChainlinkOracleImpl } from \"./chainlinkOracleImpl.sol\";\nimport { RedstoneOracleImpl } from \"./redstoneOracleImpl.sol\";\n\n/// @title   Fallback Oracle implementation\n/// @notice  This contract is used to get the exchange rate from a main oracle feed and a fallback oracle feed.\n//\n// @dev     inheriting contracts should implement a view method to expose `_FALLBACK_ORACLE_MAIN_SOURCE`\nabstract contract FallbackOracleImpl is OracleError, RedstoneOracleImpl, ChainlinkOracleImpl {\n    /// @dev which oracle to use as main source:\n    /// - 1 = Chainlink ONLY (no fallback)\n    /// - 2 = Chainlink with Redstone Fallback\n    /// - 3 = Redstone with Chainlink Fallback\n    uint8 internal immutable _FALLBACK_ORACLE_MAIN_SOURCE;\n\n    /// @notice                     sets the main source, Chainlink Oracle and Redstone Oracle data.\n    /// @param mainSource_          which oracle to use as main source:\n    ///                                  - 1 = Chainlink ONLY (no fallback)\n    ///                                  - 2 = Chainlink with Redstone Fallback\n    ///                                  - 3 = Redstone with Chainlink Fallback\n    /// @param chainlinkParams_     chainlink Oracle constructor params struct.\n    /// @param redstoneOracle_      Redstone Oracle data. (address can be set to zero address if using Chainlink only)\n    constructor(\n        uint8 mainSource_,\n        ChainlinkConstructorParams memory chainlinkParams_,\n        RedstoneOracleData memory redstoneOracle_\n    )\n        ChainlinkOracleImpl(chainlinkParams_)\n        RedstoneOracleImpl(\n            address(redstoneOracle_.oracle) == address(0)\n                ? RedstoneOracleData(IRedstoneOracle(_REDSTONE_ORACLE_NOT_SET_ADDRESS), false, 1)\n                : redstoneOracle_\n        )\n    {\n        if (mainSource_ < 1 || mainSource_ > 3) {\n            revert FluidOracleError(ErrorTypes.FallbackOracle__InvalidParams);\n        }\n        _FALLBACK_ORACLE_MAIN_SOURCE = mainSource_;\n    }\n\n    /// @dev returns the exchange rate for the main oracle source, or the fallback source (if configured) if the main exchange rate\n    /// fails to be fetched. If returned rate is 0, fetching rate failed or something went wrong.\n    /// @return exchangeRate_ exchange rate\n    /// @return fallback_ whether fallback was necessary or not\n    function _getRateWithFallback() internal view returns (uint256 exchangeRate_, bool fallback_) {\n        if (_FALLBACK_ORACLE_MAIN_SOURCE == 1) {\n            // 1 = Chainlink ONLY (no fallback)\n            exchangeRate_ = _getChainlinkExchangeRate();\n        } else if (_FALLBACK_ORACLE_MAIN_SOURCE == 2) {\n            // 2 = Chainlink with Redstone Fallback\n            exchangeRate_ = _getChainlinkExchangeRate();\n            if (exchangeRate_ == 0) {\n                fallback_ = true;\n                exchangeRate_ = _getRedstoneExchangeRate();\n            }\n        } else {\n            // 3 = Redstone with Chainlink Fallback\n            exchangeRate_ = _getRedstoneExchangeRate();\n            if (exchangeRate_ == 0) {\n                fallback_ = true;\n                exchangeRate_ = _getChainlinkExchangeRate();\n            }\n        }\n    }\n\n    /// @dev returns the exchange rate for Chainlink, or Redstone if configured & Chainlink fails.\n    function _getChainlinkOrRedstoneAsFallback() internal view returns (uint256 exchangeRate_) {\n        exchangeRate_ = _getChainlinkExchangeRate();\n\n        if (exchangeRate_ == 0 && _FALLBACK_ORACLE_MAIN_SOURCE != 1) {\n            // Chainlink failed but Redstone is configured too -> try Redstone\n            exchangeRate_ = _getRedstoneExchangeRate();\n        }\n    }\n}\n"
      },
      "contracts/oracle/implementations/fallbackOracleImpl2.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { ErrorTypes } from \"../errorTypes.sol\";\nimport { IRedstoneOracle } from \"../interfaces/external/IRedstoneOracle.sol\";\nimport { Error as OracleError } from \"../error.sol\";\nimport { ChainlinkOracleImpl2 } from \"./chainlinkOracleImpl2.sol\";\nimport { RedstoneOracleImpl2 } from \"./redstoneOracleImpl2.sol\";\n\n//  @dev     Exact same contract as FallbackOracleImpl, just with all vars, immutables etc. renamed with a \"2\" and inheriting\n//           to ChainlinkOracleImpl2 and RedstoneOracleImpl2 to avoid conflicts when FallbackOracleImpl would have to be inherited twice.\n\n/// @title   Fallback Oracle implementation\n/// @notice  This contract is used to get the exchange rate from a main oracle feed and a fallback oracle feed.\n//\n// @dev     inheriting contracts should implement a view method to expose `_FALLBACK_ORACLE2_MAIN_SOURCE`\nabstract contract FallbackOracleImpl2 is OracleError, RedstoneOracleImpl2, ChainlinkOracleImpl2 {\n    /// @dev which oracle to use as main source:\n    /// - 1 = Chainlink ONLY (no fallback)\n    /// - 2 = Chainlink with Redstone Fallback\n    /// - 3 = Redstone with Chainlink Fallback\n    uint8 internal immutable _FALLBACK_ORACLE2_MAIN_SOURCE;\n\n    /// @notice                     sets the main source, Chainlink Oracle and Redstone Oracle data.\n    /// @param mainSource_          which oracle to use as main source:\n    ///                                  - 1 = Chainlink ONLY (no fallback)\n    ///                                  - 2 = Chainlink with Redstone Fallback\n    ///                                  - 3 = Redstone with Chainlink Fallback\n    /// @param chainlinkParams_     chainlink Oracle constructor params struct.\n    /// @param redstoneOracle_      Redstone Oracle data. (address can be set to zero address if using Chainlink only)\n    constructor(\n        uint8 mainSource_,\n        ChainlinkConstructorParams memory chainlinkParams_,\n        RedstoneOracleData memory redstoneOracle_\n    )\n        ChainlinkOracleImpl2(chainlinkParams_)\n        RedstoneOracleImpl2(\n            address(redstoneOracle_.oracle) == address(0)\n                ? RedstoneOracleData(IRedstoneOracle(_REDSTONE2_ORACLE_NOT_SET_ADDRESS), false, 1)\n                : redstoneOracle_\n        )\n    {\n        if (mainSource_ < 1 || mainSource_ > 3) {\n            revert FluidOracleError(ErrorTypes.FallbackOracle__InvalidParams);\n        }\n        _FALLBACK_ORACLE2_MAIN_SOURCE = mainSource_;\n    }\n\n    /// @dev returns the exchange rate for the main oracle source, or the fallback source (if configured) if the main exchange rate\n    /// fails to be fetched. If returned rate is 0, fetching rate failed or something went wrong.\n    /// @return exchangeRate_ exchange rate\n    /// @return fallback_ whether fallback was necessary or not\n    function _getRateWithFallback2() internal view returns (uint256 exchangeRate_, bool fallback_) {\n        if (_FALLBACK_ORACLE2_MAIN_SOURCE == 1) {\n            // 1 = Chainlink ONLY (no fallback)\n            exchangeRate_ = _getChainlinkExchangeRate2();\n        } else if (_FALLBACK_ORACLE2_MAIN_SOURCE == 2) {\n            // 2 = Chainlink with Redstone Fallback\n            exchangeRate_ = _getChainlinkExchangeRate2();\n            if (exchangeRate_ == 0) {\n                fallback_ = true;\n                exchangeRate_ = _getRedstoneExchangeRate2();\n            }\n        } else {\n            // 3 = Redstone with Chainlink Fallback\n            exchangeRate_ = _getRedstoneExchangeRate2();\n            if (exchangeRate_ == 0) {\n                fallback_ = true;\n                exchangeRate_ = _getChainlinkExchangeRate2();\n            }\n        }\n    }\n\n    /// @dev returns the exchange rate for Chainlink, or Redstone if configured & Chainlink fails.\n    function _getChainlinkOrRedstoneAsFallback2() internal view returns (uint256 exchangeRate_) {\n        exchangeRate_ = _getChainlinkExchangeRate2();\n\n        if (exchangeRate_ == 0 && _FALLBACK_ORACLE2_MAIN_SOURCE != 1) {\n            // Chainlink failed but Redstone is configured too -> try Redstone\n            exchangeRate_ = _getRedstoneExchangeRate2();\n        }\n    }\n}\n"
      },
      "contracts/oracle/implementations/redstoneOracleImpl.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { ErrorTypes } from \"../errorTypes.sol\";\nimport { IRedstoneOracle } from \"../interfaces/external/IRedstoneOracle.sol\";\nimport { Error as OracleError } from \"../error.sol\";\nimport { OracleUtils } from \"../libraries/oracleUtils.sol\";\nimport { RedstoneStructs } from \"./structs.sol\";\n\n/// @title   Redstone Oracle implementation\n/// @notice  This contract is used to get the exchange rate from a Redstone Oracle\nabstract contract RedstoneOracleImpl is OracleError, RedstoneStructs {\n    /// @notice Redstone price oracle to check for the exchange rate\n    IRedstoneOracle internal immutable _REDSTONE_ORACLE;\n    /// @notice Flag to invert the price or not (to e.g. for WETH/USDC pool return prive of USDC per 1 WETH)\n    bool internal immutable _REDSTONE_INVERT_RATE;\n\n    /// @notice constant value for price scaling to reduce gas usage\n    uint256 internal immutable _REDSTONE_PRICE_SCALER_MULTIPLIER;\n    /// @notice constant value for inverting price to reduce gas usage\n    uint256 internal immutable _REDSTONE_INVERT_PRICE_DIVIDEND;\n\n    address internal immutable _REDSTONE_ORACLE_NOT_SET_ADDRESS = 0x000000000000000000000000000000000000dEaD;\n\n    /// @notice constructor sets the Redstone oracle data\n    constructor(RedstoneOracleData memory oracleData_) {\n        if (address(oracleData_.oracle) == address(0) || oracleData_.token0Decimals == 0) {\n            revert FluidOracleError(ErrorTypes.RedstoneOracle__InvalidParams);\n        }\n\n        _REDSTONE_ORACLE = oracleData_.oracle;\n        _REDSTONE_INVERT_RATE = oracleData_.invertRate;\n\n        // for explanation on how to get to scaler multiplier and dividend see `chainlinkOracleImpl.sol`.\n        // no support for token1Decimals with more than OracleUtils.RATE_OUTPUT_DECIMALS decimals for now as extremely unlikely case\n        _REDSTONE_PRICE_SCALER_MULTIPLIER = address(oracleData_.oracle) == _REDSTONE_ORACLE_NOT_SET_ADDRESS\n            ? 1\n            : 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS - oracleData_.token0Decimals);\n        _REDSTONE_INVERT_PRICE_DIVIDEND = address(oracleData_.oracle) == _REDSTONE_ORACLE_NOT_SET_ADDRESS\n            ? 1\n            : 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS + oracleData_.token0Decimals);\n    }\n\n    /// @dev           Get the exchange rate from Redstone oracle\n    /// @param rate_   The exchange rate in `OracleUtils.RATE_OUTPUT_DECIMALS`\n    function _getRedstoneExchangeRate() internal view returns (uint256 rate_) {\n        try _REDSTONE_ORACLE.getExchangeRate() returns (uint256 exchangeRate_) {\n            if (_REDSTONE_INVERT_RATE) {\n                // invert the price\n                return _REDSTONE_INVERT_PRICE_DIVIDEND / exchangeRate_;\n            } else {\n                return exchangeRate_ * _REDSTONE_PRICE_SCALER_MULTIPLIER;\n            }\n        } catch {\n            return 0;\n        }\n    }\n\n    /// @notice returns all Redstone oracle related data as utility for easy off-chain use / block explorer in a single view method\n    function redstoneOracleData()\n        public\n        view\n        returns (uint256 redstoneExchangeRate_, IRedstoneOracle redstoneOracle_, bool redstoneInvertRate_)\n    {\n        return (\n            address(_REDSTONE_ORACLE) == _REDSTONE_ORACLE_NOT_SET_ADDRESS ? 0 : _getRedstoneExchangeRate(),\n            _REDSTONE_ORACLE,\n            _REDSTONE_INVERT_RATE\n        );\n    }\n}\n"
      },
      "contracts/oracle/implementations/redstoneOracleImpl2.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { ErrorTypes } from \"../errorTypes.sol\";\nimport { IRedstoneOracle } from \"../interfaces/external/IRedstoneOracle.sol\";\nimport { Error as OracleError } from \"../error.sol\";\nimport { OracleUtils } from \"../libraries/oracleUtils.sol\";\nimport { RedstoneStructs } from \"./structs.sol\";\n\n//  @dev     Exact same contract as RedstoneOracleImpl, just with all vars, immutables etc. renamed with a \"2\" to avoid\n//           conflicts when RedstoneOracleImpl would have to be inherited twice.\n\n/// @title   Redstone Oracle implementation\n/// @notice  This contract is used to get the exchange rate from a Redstone Oracle\nabstract contract RedstoneOracleImpl2 is OracleError, RedstoneStructs {\n    /// @notice Redstone price oracle to check for the exchange rate\n    IRedstoneOracle internal immutable _REDSTONE2_ORACLE;\n    /// @notice Flag to invert the price or not (to e.g. for WETH/USDC pool return prive of USDC per 1 WETH)\n    bool internal immutable _REDSTONE2_INVERT_RATE;\n\n    /// @notice constant value for price scaling to reduce gas usage\n    uint256 internal immutable _REDSTONE2_PRICE_SCALER_MULTIPLIER;\n    /// @notice constant value for inverting price to reduce gas usage\n    uint256 internal immutable _REDSTONE2_INVERT_PRICE_DIVIDEND;\n\n    address internal immutable _REDSTONE2_ORACLE_NOT_SET_ADDRESS = 0x000000000000000000000000000000000000dEaD;\n\n    /// @notice constructor sets the Redstone oracle data\n    constructor(RedstoneOracleData memory oracleData_) {\n        if (address(oracleData_.oracle) == address(0) || oracleData_.token0Decimals == 0) {\n            revert FluidOracleError(ErrorTypes.RedstoneOracle__InvalidParams);\n        }\n\n        _REDSTONE2_ORACLE = oracleData_.oracle;\n        _REDSTONE2_INVERT_RATE = oracleData_.invertRate;\n\n        // for explanation on how to get to scaler multiplier and dividend see `chainlinkOracleImpl.sol`.\n        // no support for token1Decimals with more than OracleUtils.RATE_OUTPUT_DECIMALS decimals for now as extremely unlikely case\n        _REDSTONE2_PRICE_SCALER_MULTIPLIER = address(oracleData_.oracle) == _REDSTONE2_ORACLE_NOT_SET_ADDRESS\n            ? 1\n            : 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS - oracleData_.token0Decimals);\n        _REDSTONE2_INVERT_PRICE_DIVIDEND = address(oracleData_.oracle) == _REDSTONE2_ORACLE_NOT_SET_ADDRESS\n            ? 1\n            : 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS + oracleData_.token0Decimals);\n    }\n\n    /// @dev           Get the exchange rate from Redstone oracle\n    /// @param rate_   The exchange rate in `OracleUtils.RATE_OUTPUT_DECIMALS`\n    function _getRedstoneExchangeRate2() internal view returns (uint256 rate_) {\n        try _REDSTONE2_ORACLE.getExchangeRate() returns (uint256 exchangeRate_) {\n            if (_REDSTONE2_INVERT_RATE) {\n                // invert the price\n                return _REDSTONE2_INVERT_PRICE_DIVIDEND / exchangeRate_;\n            } else {\n                return exchangeRate_ * _REDSTONE2_PRICE_SCALER_MULTIPLIER;\n            }\n        } catch {\n            return 0;\n        }\n    }\n\n    /// @notice returns all Redstone oracle related data as utility for easy off-chain use / block explorer in a single view method\n    function redstoneOracleData2()\n        public\n        view\n        returns (uint256 redstoneExchangeRate_, IRedstoneOracle redstoneOracle_, bool redstoneInvertRate_)\n    {\n        return (\n            address(_REDSTONE2_ORACLE) == _REDSTONE2_ORACLE_NOT_SET_ADDRESS ? 0 : _getRedstoneExchangeRate2(),\n            _REDSTONE2_ORACLE,\n            _REDSTONE2_INVERT_RATE\n        );\n    }\n}\n"
      },
      "contracts/oracle/implementations/structs.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IChainlinkAggregatorV3 } from \"../interfaces/external/IChainlinkAggregatorV3.sol\";\nimport { IRedstoneOracle } from \"../interfaces/external/IRedstoneOracle.sol\";\n\nabstract contract ChainlinkStructs {\n    struct ChainlinkFeedData {\n        /// @param feed           address of Chainlink feed.\n        IChainlinkAggregatorV3 feed;\n        /// @param invertRate     true if rate read from price feed must be inverted.\n        bool invertRate;\n        /// @param token0Decimals decimals of asset 0. E.g. for a USDC/ETH feed, USDC is token0 and has 6 decimals.\n        ///                       (token1Decimals are available directly via Chainlink `FEED.decimals()`)\n        uint256 token0Decimals;\n    }\n\n    struct ChainlinkConstructorParams {\n        /// @param param        hops count of hops, used for sanity checks. Must be 1, 2 or 3.\n        uint8 hops;\n        /// @param feed1        Chainlink feed 1 data. Required.\n        ChainlinkFeedData feed1;\n        /// @param feed2        Chainlink feed 2 data. Required if hops > 1.\n        ChainlinkFeedData feed2;\n        /// @param feed3        Chainlink feed 3 data. Required if hops > 2.\n        ChainlinkFeedData feed3;\n    }\n}\n\nabstract contract RedstoneStructs {\n    struct RedstoneOracleData {\n        /// @param oracle         address of Redstone oracle.\n        IRedstoneOracle oracle;\n        /// @param invertRate     true if rate read from price feed must be inverted.\n        bool invertRate;\n        /// @param token0Decimals decimals of asset 0. E.g. for a USDC/ETH feed, USDC is token0 and has 6 decimals.\n        ///                       (token1Decimals are available directly via Redstone `Oracle.decimals()`)\n        uint256 token0Decimals;\n    }\n}\n"
      },
      "contracts/oracle/implementations/uniV3OracleImpl.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { ErrorTypes } from \"../errorTypes.sol\";\nimport { FullMath } from \"../libraries/FullMath.sol\";\nimport { TickMath } from \"../libraries/TickMath.sol\";\nimport { OracleUtils } from \"../libraries/oracleUtils.sol\";\nimport { IUniswapV3Pool } from \"../interfaces/external/IUniswapV3Pool.sol\";\nimport { Error as OracleError } from \"../error.sol\";\n\n/// @title   Uniswap V3 Oracle implementation\n/// @notice  This contract is used to get the exchange rate from from a Uniswap V3 Pool,\n///          including logic to check against TWAP max deltas.\n/// @dev     Uses 5 secondsAgos[] values and 3 TWAP maxDeltas:\n///          e.g. [240, 60, 15, 1, 0] -> [price240to60, price60to15, price 15to1, currentPrice]\n///          delta checks: price240to60 vs currentPrice, price60to15 vs currentPrice and 15to1 vs currentPrice.\nabstract contract UniV3OracleImpl is OracleError {\n    /// @dev Uniswap V3 Pool to check for the exchange rate\n    IUniswapV3Pool internal immutable _POOL;\n\n    /// @dev Flag to invert the price or not (to e.g. for WETH/USDC pool return prive of USDC per 1 WETH)\n    bool internal immutable _UNIV3_INVERT_RATE;\n\n    /// @dev Uniswap oracle delta for TWAP1 in 1e2 percent. If uniswap price TWAP1 is out of this delta,\n    /// current price fetching reverts. E.g. for delta of TWAP 240 -> 60 vs current price\n    uint256 internal immutable _UNI_TWAP1_MAX_DELTA_PERCENT;\n    /// @dev Uniswap oracle delta for TWAP2 in 1e2 percent. If uniswap price TWAP2 is out of this delta,\n    /// current price fetching reverts. E.g. for delta of TWAP 60 -> 15 vs current price\n    uint256 internal immutable _UNI_TWAP2_MAX_DELTA_PERCENT;\n    /// @dev Uniswap oracle delta for TWAP3 in 1e2 percent. If uniswap price TWAP3 is out of this delta,\n    /// current price fetching reverts. E.g. for delta of TWAP 15 -> 1 vs current price\n    uint256 internal immutable _UNI_TWAP3_MAX_DELTA_PERCENT;\n\n    /// @dev Uniswap oracle seconds ago for twap, 1. value, e.g. 240\n    uint256 internal immutable _UNI_SECONDS_AGO_1;\n    /// @dev Uniswap oracle seconds ago for twap, 2. value, e.g. 60\n    uint256 internal immutable _UNI_SECONDS_AGO_2;\n    /// @dev Uniswap oracle seconds ago for twap, 3. value, e.g. 15\n    uint256 internal immutable _UNI_SECONDS_AGO_3;\n    /// @dev Uniswap oracle seconds ago for twap, 4. value, e.g. 1\n    uint256 internal immutable _UNI_SECONDS_AGO_4;\n    /// @dev Uniswap oracle seconds ago for twap, 5. value, e.g. 0\n    uint256 internal immutable _UNI_SECONDS_AGO_5;\n\n    /// @dev Uniswap TWAP1 interval duration.\n    int256 internal immutable _UNI_TWAP1_INTERVAL;\n    /// @dev Uniswap TWAP2 interval duration.\n    int256 internal immutable _UNI_TWAP2_INTERVAL;\n    /// @dev Uniswap TWAP3 interval duration.\n    int256 internal immutable _UNI_TWAP3_INTERVAL;\n    /// @dev Uniswap TWAP4 interval duration.\n    int256 internal immutable _UNI_TWAP4_INTERVAL;\n\n    /// @dev stored array lengths to optimize gas\n    uint256 internal constant _SECONDS_AGOS_LENGTH = 5;\n    uint256 internal constant _TWAP_DELTAS_LENGTH = 3;\n\n    /// @dev constant value for price scaling to reduce gas usage\n    uint256 internal immutable _UNIV3_PRICE_SCALER_MULTIPLIER;\n    /// @dev constant value for inverting price to reduce gas usage\n    uint256 internal immutable _UNIV3_INVERT_PRICE_DIVIDEND;\n\n    struct UniV3ConstructorParams {\n        /// @param pool                   Uniswap V3 Pool to check for the exchange rate\n        IUniswapV3Pool pool;\n        /// @param invertRate             Flag to invert the Uniswap price or not\n        bool invertRate;\n        /// @param tWAPMaxDeltaPercents Uniswap oracle delta for TWAP1-2-3 in 1e2 percent\n        uint256[_TWAP_DELTAS_LENGTH] tWAPMaxDeltaPercents;\n        /// @param secondsAgos          Uniswap oracle seconds ago for the 3 TWAP values, from oldest to newest, e.g. [240, 60, 15, 1, 0]\n        uint32[_SECONDS_AGOS_LENGTH] secondsAgos;\n    }\n\n    /// @notice constructor sets the  Uniswap V3 `pool_` to check for the exchange rate and the `invertRate_` flag.\n    /// E.g. `invertRate_` should be true if for the WETH/USDC pool it's expected that the oracle returns USDC per 1 WETH\n    constructor(UniV3ConstructorParams memory params_) {\n        if (address(params_.pool) == address(0)) {\n            revert FluidOracleError(ErrorTypes.UniV3Oracle__InvalidParams);\n        }\n        // sanity check that seconds agos values are ordered ascending, e.g. [240, 60, 15, 1, 0]\n        if (\n            params_.secondsAgos[0] <= params_.secondsAgos[1] ||\n            params_.secondsAgos[1] <= params_.secondsAgos[2] ||\n            params_.secondsAgos[2] <= params_.secondsAgos[3] ||\n            params_.secondsAgos[3] <= params_.secondsAgos[4]\n        ) {\n            revert FluidOracleError(ErrorTypes.UniV3Oracle__InvalidSecondsAgos);\n        }\n        // sanity check that deltas are less than 100% and decreasing (as timespan is closer to current price):\n        // 1. delta must < 100%\n        // all following deltas must be <= than the previous one\n        if (\n            params_.tWAPMaxDeltaPercents[0] >= OracleUtils.HUNDRED_PERCENT_DELTA_SCALER ||\n            params_.tWAPMaxDeltaPercents[1] > params_.tWAPMaxDeltaPercents[0] ||\n            params_.tWAPMaxDeltaPercents[2] > params_.tWAPMaxDeltaPercents[1]\n        ) {\n            revert FluidOracleError(ErrorTypes.UniV3Oracle__InvalidDeltas);\n        }\n\n        _UNI_SECONDS_AGO_1 = uint256(params_.secondsAgos[0]);\n        _UNI_SECONDS_AGO_2 = uint256(params_.secondsAgos[1]);\n        _UNI_SECONDS_AGO_3 = uint256(params_.secondsAgos[2]);\n        _UNI_SECONDS_AGO_4 = uint256(params_.secondsAgos[3]);\n        _UNI_SECONDS_AGO_5 = uint256(params_.secondsAgos[4]);\n\n        _UNI_TWAP1_INTERVAL = int256(uint256(params_.secondsAgos[0] - params_.secondsAgos[1]));\n        _UNI_TWAP2_INTERVAL = int256(uint256(params_.secondsAgos[1] - params_.secondsAgos[2]));\n        _UNI_TWAP3_INTERVAL = int256(uint256(params_.secondsAgos[2] - params_.secondsAgos[3]));\n        _UNI_TWAP4_INTERVAL = int256(uint256(params_.secondsAgos[3] - params_.secondsAgos[4]));\n\n        _UNI_TWAP1_MAX_DELTA_PERCENT = params_.tWAPMaxDeltaPercents[0]; // e.g. for TWAP 240 -> 60 vs current price\n        _UNI_TWAP2_MAX_DELTA_PERCENT = params_.tWAPMaxDeltaPercents[1]; // e.g. for TWAP  60 -> 15 vs current price\n        _UNI_TWAP3_MAX_DELTA_PERCENT = params_.tWAPMaxDeltaPercents[2]; // e.g. for TWAP  15 ->  1 vs current price\n\n        _POOL = params_.pool;\n        _UNIV3_INVERT_RATE = params_.invertRate;\n\n        // uniswapV3 returned price is already scaled to token decimals.\n        _UNIV3_PRICE_SCALER_MULTIPLIER = 10 ** OracleUtils.RATE_OUTPUT_DECIMALS;\n        // uniV3 invert price dividend happens on the already scaled by 1e27 result for price in token1 per 1 token0\n        _UNIV3_INVERT_PRICE_DIVIDEND = 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS * 2);\n    }\n\n    /// @dev                        Get the last exchange rate from the pool's last observed value without any checks\n    /// @return exchangeRateUnsafe_ The exchange rate between the underlying asset and the peg asset in `OracleUtils.RATE_OUTPUT_DECIMALS`\n    function _getUniV3ExchangeRateUnsafe() internal view returns (uint256 exchangeRateUnsafe_) {\n        (uint160 sqrtPriceX96_, , , , , , ) = _POOL.slot0();\n\n        exchangeRateUnsafe_ = _UNIV3_INVERT_RATE\n            ? _invertUniV3Price(_getPriceFromSqrtPriceX96(sqrtPriceX96_))\n            : _getPriceFromSqrtPriceX96(sqrtPriceX96_);\n    }\n\n    /// @dev                   Get the last exchange rate from the pool's last observed value, checked against TWAP deviations.\n    /// @return exchangeRate_  The exchange rate between the underlying asset and the peg asset in `OracleUtils.RATE_OUTPUT_DECIMALS`\n    ///                        If 0 then the fetching the price failed or a delta was invalid.\n    function _getUniV3ExchangeRate() internal view returns (uint256 exchangeRate_) {\n        // build calldata bytes in a gas-optimized way without having to build an array / using abi.encode.\n        // gas efficient work around for Solidity not supporting immutable non-value types.\n        bytes memory data_ = abi.encodePacked(\n            hex\"883bdbfd\", // pack function selector\n            hex\"0000000000000000000000000000000000000000000000000000000000000020\", // pack start offset of dynamic array\n            _SECONDS_AGOS_LENGTH, // pack length of dynamic array\n            // pack seconds agos values:\n            _UNI_SECONDS_AGO_1,\n            _UNI_SECONDS_AGO_2,\n            _UNI_SECONDS_AGO_3,\n            _UNI_SECONDS_AGO_4,\n            _UNI_SECONDS_AGO_5\n        );\n\n        // get the tickCumulatives from Pool.observe()\n        (bool success_, bytes memory result_) = address(_POOL).staticcall(data_);\n\n        if (!success_) {\n            return 0;\n        }\n        int56[] memory tickCumulatives_ = abi.decode(result_, (int56[]));\n\n        unchecked {\n            int24 exchangeRateTick_;\n            {\n                int56 tickCumulativesDelta_ = (tickCumulatives_[_TWAP_DELTAS_LENGTH + 1] -\n                    tickCumulatives_[_TWAP_DELTAS_LENGTH]);\n                // _UNI_TWAP4_INTERVAL can not be 0 because of constructor sanity checks\n                exchangeRateTick_ = int24(tickCumulativesDelta_ / _UNI_TWAP4_INTERVAL);\n                // Always round to negative infinity, see UniV3 OracleLibrary\n                // https://github.com/Uniswap/v3-periphery/blob/697c2474757ea89fec12a4e6db16a574fe259610/contracts/libraries/OracleLibrary.sol#L36\n                if (tickCumulativesDelta_ < 0 && (tickCumulativesDelta_ % _UNI_TWAP4_INTERVAL != 0)) {\n                    exchangeRateTick_--;\n                }\n            }\n\n            // Check the latest Uniswap price is within the acceptable delta from each TWAP range\n            // TWAP 1 check\n            if (\n                _isInvalidTWAPDelta(\n                    int256(exchangeRateTick_),\n                    tickCumulatives_[1] - tickCumulatives_[0],\n                    _UNI_TWAP1_INTERVAL,\n                    int256(_UNI_TWAP1_MAX_DELTA_PERCENT)\n                )\n            ) {\n                return 0;\n            }\n\n            // TWAP 2 check\n            if (\n                _isInvalidTWAPDelta(\n                    int256(exchangeRateTick_),\n                    tickCumulatives_[2] - tickCumulatives_[1],\n                    _UNI_TWAP2_INTERVAL,\n                    int256(_UNI_TWAP2_MAX_DELTA_PERCENT)\n                )\n            ) {\n                return 0;\n            }\n\n            // TWAP 3 check\n            if (\n                _isInvalidTWAPDelta(\n                    int256(exchangeRateTick_),\n                    tickCumulatives_[3] - tickCumulatives_[2],\n                    _UNI_TWAP3_INTERVAL,\n                    int256(_UNI_TWAP3_MAX_DELTA_PERCENT)\n                )\n            ) {\n                return 0;\n            }\n\n            // get the current uniswap price, which is the last tick cumulatives interval, usually [..., 1, 0]\n            exchangeRate_ = _getPriceFromSqrtPriceX96(TickMath.getSqrtRatioAtTick(exchangeRateTick_));\n            if (_UNIV3_INVERT_RATE) {\n                exchangeRate_ = _invertUniV3Price(exchangeRate_);\n            }\n        }\n    }\n\n    /// @dev verifies that `exchangeRate_` is within `maxDelta_` for derived price from `tickCumulativesDelta_` and `interval_`.\n    /// returns true if delta is invalid\n    function _isInvalidTWAPDelta(\n        int256 exchangeRateTick_,\n        int256 tickCumulativesDelta_,\n        int256 interval_, // can not be 0 because of constructor sanity checks\n        int256 maxDelta_\n    ) internal pure returns (bool) {\n        unchecked {\n            int256 arithmeticMeanTick_ = int256(tickCumulativesDelta_ / interval_);\n            // Always round to negative infinity, see UniV3 OracleLibrary\n            // https://github.com/Uniswap/v3-periphery/blob/697c2474757ea89fec12a4e6db16a574fe259610/contracts/libraries/OracleLibrary.sol#L36\n            if (tickCumulativesDelta_ < 0 && (tickCumulativesDelta_ % interval_ != 0)) {\n                arithmeticMeanTick_--;\n            }\n\n            // Check that the uniswapPrice is within DELTA of the Uniswap TWAP (via tick)\n            // each univ3 tick is 0.01% increase or decrease in price. `maxDelta_` has near to same precision.\n            // Note: near to the same because each Uniswap tick is 0.01% away so price of ticks are if current one is 100 then next will be:\n            // 100 + 100 * 0.01% = 100.01\n            // 100.01 + 100.01 * 0.01% = 100.020001\n            if (\n                exchangeRateTick_ > (arithmeticMeanTick_ + maxDelta_) ||\n                exchangeRateTick_ < (arithmeticMeanTick_ - maxDelta_)\n            ) {\n                // Uniswap last price is NOT within the delta\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /// @notice returns all UniV3 oracle related data as utility for easy off-chain use / block explorer in a single view method\n    function uniV3OracleData()\n        public\n        view\n        returns (\n            IUniswapV3Pool uniV3Pool_,\n            bool uniV3InvertRate_,\n            uint32[] memory uniV3secondsAgos_,\n            uint256[] memory uniV3TwapDeltas_,\n            uint256 uniV3exchangeRateUnsafe_,\n            uint256 uniV3exchangeRate_\n        )\n    {\n        // Get the latest TWAP prices from the Uniswap Oracle for second intervals\n        uniV3secondsAgos_ = new uint32[](_SECONDS_AGOS_LENGTH);\n        uniV3secondsAgos_[0] = uint32(_UNI_SECONDS_AGO_1);\n        uniV3secondsAgos_[1] = uint32(_UNI_SECONDS_AGO_2);\n        uniV3secondsAgos_[2] = uint32(_UNI_SECONDS_AGO_3);\n        uniV3secondsAgos_[3] = uint32(_UNI_SECONDS_AGO_4);\n        uniV3secondsAgos_[4] = uint32(_UNI_SECONDS_AGO_5);\n\n        // Check the latest Uniswap price is within the acceptable delta from each TWAP range\n        uniV3TwapDeltas_ = new uint256[](_TWAP_DELTAS_LENGTH);\n        uniV3TwapDeltas_[0] = _UNI_TWAP1_MAX_DELTA_PERCENT;\n        uniV3TwapDeltas_[1] = _UNI_TWAP2_MAX_DELTA_PERCENT;\n        uniV3TwapDeltas_[2] = _UNI_TWAP3_MAX_DELTA_PERCENT;\n\n        return (\n            _POOL,\n            _UNIV3_INVERT_RATE,\n            uniV3secondsAgos_,\n            uniV3TwapDeltas_,\n            _getUniV3ExchangeRateUnsafe(),\n            _getUniV3ExchangeRate()\n        );\n    }\n\n    /// @dev                  Get the price from the sqrt price in `OracleUtils.RATE_OUTPUT_DECIMALS`\n    ///                       (see https://blog.uniswap.org/uniswap-v3-math-primer)\n    /// @param sqrtPriceX96_  The sqrt price to convert\n    function _getPriceFromSqrtPriceX96(uint160 sqrtPriceX96_) private view returns (uint256 priceX96_) {\n        return\n            FullMath.mulDiv(\n                uint256(sqrtPriceX96_) * uint256(sqrtPriceX96_),\n                _UNIV3_PRICE_SCALER_MULTIPLIER,\n                1 << 192 // 2^96 * 2\n            );\n    }\n\n    /// @dev                     Invert the price\n    /// @param price_            The price to invert\n    /// @return invertedPrice_   The inverted price in `OracleUtils.RATE_OUTPUT_DECIMALS`\n    function _invertUniV3Price(uint256 price_) private view returns (uint256 invertedPrice_) {\n        return _UNIV3_INVERT_PRICE_DIVIDEND / price_;\n    }\n}\n"
      },
      "contracts/oracle/implementations/wstETHOracleImpl.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { IWstETH } from \"../interfaces/external/IWstETH.sol\";\nimport { ErrorTypes } from \"../errorTypes.sol\";\nimport { Error as OracleError } from \"../error.sol\";\nimport { OracleUtils } from \"../libraries/oracleUtils.sol\";\n\n/// @title   wstETH Oracle Implementation\n/// @notice  This contract is used to get the exchange rate between wstETH and stETH\nabstract contract WstETHOracleImpl is OracleError {\n    /// @notice constant value for price scaling to reduce gas usage\n    uint256 internal immutable _WSTETH_PRICE_SCALER_MULTIPLIER;\n\n    /// @notice WSTETH contract, e.g. on mainnet 0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0\n    IWstETH internal immutable _WSTETH;\n\n    /// @notice constructor sets the wstETH `wstETH_` token address.\n    constructor(IWstETH wstETH_) {\n        if (address(wstETH_) == address(0)) {\n            revert FluidOracleError(ErrorTypes.WstETHOracle__InvalidParams);\n        }\n\n        _WSTETH = wstETH_;\n\n        _WSTETH_PRICE_SCALER_MULTIPLIER = 10 ** (OracleUtils.RATE_OUTPUT_DECIMALS - 18); // e.g. 1e9\n    }\n\n    /// @notice         Get the exchange rate from wstETH contract\n    /// @return rate_   The exchange rate in `OracleUtils.RATE_OUTPUT_DECIMALS`\n    function _getWstETHExchangeRate() internal view returns (uint256 rate_) {\n        return _WSTETH.stEthPerToken() * _WSTETH_PRICE_SCALER_MULTIPLIER;\n    }\n\n    /// @notice returns all wWtETH oracle related data as utility for easy off-chain use / block explorer in a single view method\n    function wstETHOracleData() public view returns (uint256 wstETHExchangeRate_, IWstETH wstETH_) {\n        return (_getWstETHExchangeRate(), _WSTETH);\n    }\n}\n"
      },
      "contracts/oracle/interfaces/external/IChainlinkAggregatorV3.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\n/// from https://github.com/smartcontractkit/chainlink/blob/master/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\n/// Copyright (c) 2018 SmartContract ChainLink, Ltd.\n\ninterface IChainlinkAggregatorV3 {\n    /// @notice represents the number of decimals the aggregator responses represent.\n    function decimals() external view returns (uint8);\n\n    function description() external view returns (string memory);\n\n    function version() external view returns (uint256);\n\n    function getRoundData(\n        uint80 _roundId\n    )\n        external\n        view\n        returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);\n\n    function latestRoundData()\n        external\n        view\n        returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);\n}\n"
      },
      "contracts/oracle/interfaces/external/IRedstoneOracle.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\ninterface IRedstoneOracle {\n    /// @notice Get the `exchangeRate_` between the underlying asset and the peg asset\n    // @dev custom Redstone adapter for Instadapp implementation\n    function getExchangeRate() external view returns (uint256 exchangeRate_);\n\n    /**\n     * @notice Returns the number of decimals for the price feed\n     * @dev By default, RedStone uses 8 decimals for data feeds\n     * @return decimals The number of decimals in the price feed values\n     */\n    // see https://github.com/redstone-finance/redstone-oracles-monorepo/blob/main/packages/on-chain-relayer/contracts/price-feeds/PriceFeedBase.sol#L51C12-L51C20\n    function decimals() external view returns (uint8);\n}\n"
      },
      "contracts/oracle/interfaces/external/IUniswapV3Pool.sol": {
        "content": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity 0.8.21;\n\n/// from https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces.\n/// Copyright (c) 2022 Uniswap Labs\n\n/// @title Pool state that never changes\n/// @notice These parameters are fixed for a pool forever, i.e., the methods will always return the same values\ninterface IUniswapV3PoolImmutables {\n    /// @notice The contract that deployed the pool, which must adhere to the IUniswapV3Factory interface\n    /// @return The contract address\n    function factory() external view returns (address);\n\n    /// @notice The first of the two tokens of the pool, sorted by address\n    /// @return The token contract address\n    function token0() external view returns (address);\n\n    /// @notice The second of the two tokens of the pool, sorted by address\n    /// @return The token contract address\n    function token1() external view returns (address);\n\n    /// @notice The pool's fee in hundredths of a bip, i.e. 1e-6\n    /// @return The fee\n    function fee() external view returns (uint24);\n\n    /// @notice The pool tick spacing\n    /// @dev Ticks can only be used at multiples of this value, minimum of 1 and always positive\n    /// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, i.e., ..., -6, -3, 0, 3, 6, ...\n    /// This value is an int24 to avoid casting even though it is always positive.\n    /// @return The tick spacing\n    function tickSpacing() external view returns (int24);\n\n    /// @notice The maximum amount of position liquidity that can use any tick in the range\n    /// @dev This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and\n    /// also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool\n    /// @return The max amount of liquidity per tick\n    function maxLiquidityPerTick() external view returns (uint128);\n}\n\n/// @title Pool state that is not stored\n/// @notice Contains view functions to provide information about the pool that is computed rather than stored on the\n/// blockchain. The functions here may have variable gas costs.\ninterface IUniswapV3PoolDerivedState {\n    /// @notice Returns the cumulative tick and liquidity as of each timestamp `secondsAgo` from the current block timestamp\n    /// @dev To get a time weighted average tick or liquidity-in-range, you must call this with two values, one representing\n    /// the beginning of the period and another for the end of the period. E.g., to get the last hour time-weighted average tick,\n    /// you must call it with secondsAgos = [3600, 0].\n    /// @dev The time weighted average tick represents the geometric time weighted average price of the pool, in\n    /// log base sqrt(1.0001) of token1 / token0. The TickMath library can be used to go from a tick value to a ratio.\n    /// @param secondsAgos From how long ago each cumulative tick and liquidity value should be returned\n    /// @return tickCumulatives Cumulative tick values as of each `secondsAgos` from the current block timestamp\n    /// @return secondsPerLiquidityCumulativeX128s Cumulative seconds per liquidity-in-range value as of each `secondsAgos` from the current block\n    /// timestamp\n    function observe(\n        uint32[] calldata secondsAgos\n    ) external view returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s);\n\n    /// @notice Returns a snapshot of the tick cumulative, seconds per liquidity and seconds inside a tick range\n    /// @dev Snapshots must only be compared to other snapshots, taken over a period for which a position existed.\n    /// I.e., snapshots cannot be compared if a position is not held for the entire period between when the first\n    /// snapshot is taken and the second snapshot is taken.\n    /// @param tickLower The lower tick of the range\n    /// @param tickUpper The upper tick of the range\n    /// @return tickCumulativeInside The snapshot of the tick accumulator for the range\n    /// @return secondsPerLiquidityInsideX128 The snapshot of seconds per liquidity for the range\n    /// @return secondsInside The snapshot of seconds per liquidity for the range\n    function snapshotCumulativesInside(\n        int24 tickLower,\n        int24 tickUpper\n    ) external view returns (int56 tickCumulativeInside, uint160 secondsPerLiquidityInsideX128, uint32 secondsInside);\n}\n\n/// @title Pool state that can change\n/// @notice These methods compose the pool's state, and can change with any frequency including multiple times\n/// per transaction\ninterface IUniswapV3PoolState {\n    /// @notice The 0th storage slot in the pool stores many values, and is exposed as a single method to save gas\n    /// when accessed externally.\n    /// @return sqrtPriceX96 The current price of the pool as a sqrt(token1/token0) Q64.96 value\n    /// tick The current tick of the pool, i.e. according to the last tick transition that was run.\n    /// This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick\n    /// boundary.\n    /// observationIndex The index of the last oracle observation that was written,\n    /// observationCardinality The current maximum number of observations stored in the pool,\n    /// observationCardinalityNext The next maximum number of observations, to be updated when the observation.\n    /// feeProtocol The protocol fee for both tokens of the pool.\n    /// Encoded as two 4 bit values, where the protocol fee of token1 is shifted 4 bits and the protocol fee of token0\n    /// is the lower 4 bits. Used as the denominator of a fraction of the swap fee, e.g. 4 means 1/4th of the swap fee.\n    /// unlocked Whether the pool is currently locked to reentrancy\n    function slot0()\n        external\n        view\n        returns (\n            uint160 sqrtPriceX96,\n            int24 tick,\n            uint16 observationIndex,\n            uint16 observationCardinality,\n            uint16 observationCardinalityNext,\n            uint8 feeProtocol,\n            bool unlocked\n        );\n\n    /// @notice The fee growth as a Q128.128 fees of token0 collected per unit of liquidity for the entire life of the pool\n    /// @dev This value can overflow the uint256\n    function feeGrowthGlobal0X128() external view returns (uint256);\n\n    /// @notice The fee growth as a Q128.128 fees of token1 collected per unit of liquidity for the entire life of the pool\n    /// @dev This value can overflow the uint256\n    function feeGrowthGlobal1X128() external view returns (uint256);\n\n    /// @notice The amounts of token0 and token1 that are owed to the protocol\n    /// @dev Protocol fees will never exceed uint128 max in either token\n    function protocolFees() external view returns (uint128 token0, uint128 token1);\n\n    /// @notice The currently in range liquidity available to the pool\n    /// @dev This value has no relationship to the total liquidity across all ticks\n    function liquidity() external view returns (uint128);\n\n    /// @notice Look up information about a specific tick in the pool\n    /// @param tick The tick to look up\n    /// @return liquidityGross the total amount of position liquidity that uses the pool either as tick lower or\n    /// tick upper,\n    /// liquidityNet how much liquidity changes when the pool price crosses the tick,\n    /// feeGrowthOutside0X128 the fee growth on the other side of the tick from the current tick in token0,\n    /// feeGrowthOutside1X128 the fee growth on the other side of the tick from the current tick in token1,\n    /// tickCumulativeOutside the cumulative tick value on the other side of the tick from the current tick\n    /// secondsPerLiquidityOutsideX128 the seconds spent per liquidity on the other side of the tick from the current tick,\n    /// secondsOutside the seconds spent on the other side of the tick from the current tick,\n    /// initialized Set to true if the tick is initialized, i.e. liquidityGross is greater than 0, otherwise equal to false.\n    /// Outside values can only be used if the tick is initialized, i.e. if liquidityGross is greater than 0.\n    /// In addition, these values are only relative and must be used only in comparison to previous snapshots for\n    /// a specific position.\n    function ticks(\n        int24 tick\n    )\n        external\n        view\n        returns (\n            uint128 liquidityGross,\n            int128 liquidityNet,\n            uint256 feeGrowthOutside0X128,\n            uint256 feeGrowthOutside1X128,\n            int56 tickCumulativeOutside,\n            uint160 secondsPerLiquidityOutsideX128,\n            uint32 secondsOutside,\n            bool initialized\n        );\n\n    /// @notice Returns 256 packed tick initialized boolean values. See TickBitmap for more information\n    function tickBitmap(int16 wordPosition) external view returns (uint256);\n\n    /// @notice Returns the information about a position by the position's key\n    /// @param key The position's key is a hash of a preimage composed by the owner, tickLower and tickUpper\n    /// @return _liquidity The amount of liquidity in the position,\n    /// Returns feeGrowthInside0LastX128 fee growth of token0 inside the tick range as of the last mint/burn/poke,\n    /// Returns feeGrowthInside1LastX128 fee growth of token1 inside the tick range as of the last mint/burn/poke,\n    /// Returns tokensOwed0 the computed amount of token0 owed to the position as of the last mint/burn/poke,\n    /// Returns tokensOwed1 the computed amount of token1 owed to the position as of the last mint/burn/poke\n    function positions(\n        bytes32 key\n    )\n        external\n        view\n        returns (\n            uint128 _liquidity,\n            uint256 feeGrowthInside0LastX128,\n            uint256 feeGrowthInside1LastX128,\n            uint128 tokensOwed0,\n            uint128 tokensOwed1\n        );\n\n    /// @notice Returns data about a specific observation index\n    /// @param index The element of the observations array to fetch\n    /// @dev You most likely want to use #observe() instead of this method to get an observation as of some amount of time\n    /// ago, rather than at a specific index in the array.\n    /// @return blockTimestamp The timestamp of the observation,\n    /// Returns tickCumulative the tick multiplied by seconds elapsed for the life of the pool as of the observation timestamp,\n    /// Returns secondsPerLiquidityCumulativeX128 the seconds per in range liquidity for the life of the pool as of the observation timestamp,\n    /// Returns initialized whether the observation has been initialized and the values are safe to use\n    function observations(\n        uint256 index\n    )\n        external\n        view\n        returns (\n            uint32 blockTimestamp,\n            int56 tickCumulative,\n            uint160 secondsPerLiquidityCumulativeX128,\n            bool initialized\n        );\n}\n\n/// @title The interface for a Uniswap V3 Pool\n/// @notice A Uniswap pool facilitates swapping and automated market making between any two assets that strictly conform\n/// to the ERC20 specification\n/// @dev The pool interface is broken up into many smaller pieces\ninterface IUniswapV3Pool is IUniswapV3PoolImmutables, IUniswapV3PoolState, IUniswapV3PoolDerivedState {\n\n}\n"
      },
      "contracts/oracle/interfaces/external/IWstETH.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\ninterface IWstETH {\n    /**\n     * @notice Get amount of stETH for 1 wstETH\n     * @return Amount of stETH for 1 wstETH\n     */\n    function stEthPerToken() external view returns (uint256);\n\n    /**\n     * @notice Get amount of wstETH for 1 stETH\n     * @return Amount of wstETH for 1 stETH\n     */\n    function tokensPerStEth() external view returns (uint256);\n}\n"
      },
      "contracts/oracle/interfaces/iFluidOracle.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\ninterface IFluidOracle {\n    /// @dev Deprecated. Use `getExchangeRateOperate()` and `getExchangeRateLiquidate()` instead. Only implemented for\n    ///      backwards compatibility.\n    function getExchangeRate() external view returns (uint256 exchangeRate_);\n\n    /// @notice Get the `exchangeRate_` between the underlying asset and the peg asset in 1e27 for operates\n    function getExchangeRateOperate() external view returns (uint256 exchangeRate_);\n\n    /// @notice Get the `exchangeRate_` between the underlying asset and the peg asset in 1e27 for liquidations\n    function getExchangeRateLiquidate() external view returns (uint256 exchangeRate_);\n}\n"
      },
      "contracts/oracle/libraries/FullMath.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.21;\n\n/// @dev   Modified from the original UniswapV3 library to support v0.8\n/// From:  uint256 twos = -denominator & denominator;\n/// To:    uint256 twos = (type(uint256).max - denominator + 1) & denominator;\n\n/// @title Contains 512-bit math functions\n/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision\n/// @dev Handles \"phantom overflow\" i.e., allows multiplication and division where an intermediate value overflows 256 bits\nlibrary FullMath {\n    /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n    /// @param a The multiplicand\n    /// @param b The multiplier\n    /// @param denominator The divisor\n    /// @return result The 256-bit result\n    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv\n    function mulDiv(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256 result) {\n        // 512-bit multiply [prod1 prod0] = a * b\n        // Compute the product mod 2**256 and mod 2**256 - 1\n        // then use the Chinese Remainder Theorem to reconstruct\n        // the 512 bit result. The result is stored in two 256\n        // variables such that product = prod1 * 2**256 + prod0\n        uint256 prod0; // Least significant 256 bits of the product\n        uint256 prod1; // Most significant 256 bits of the product\n        assembly {\n            let mm := mulmod(a, b, not(0))\n            prod0 := mul(a, b)\n            prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n        }\n\n        // Handle non-overflow cases, 256 by 256 division\n        if (prod1 == 0) {\n            require(denominator > 0);\n            assembly {\n                result := div(prod0, denominator)\n            }\n            return result;\n        }\n\n        // Make sure the result is less than 2**256.\n        // Also prevents denominator == 0\n        require(denominator > prod1);\n\n        ///////////////////////////////////////////////\n        // 512 by 256 division.\n        ///////////////////////////////////////////////\n\n        // Make division exact by subtracting the remainder from [prod1 prod0]\n        // Compute remainder using mulmod\n        uint256 remainder;\n        assembly {\n            remainder := mulmod(a, b, denominator)\n        }\n        // Subtract 256 bit number from 512 bit number\n        assembly {\n            prod1 := sub(prod1, gt(remainder, prod0))\n            prod0 := sub(prod0, remainder)\n        }\n\n        // Factor powers of two out of denominator\n        // Compute largest power of two divisor of denominator.\n        // Always >= 1.\n        /// @dev This line was modified for v0.8.x\n        // uint256 twos = -denominator & denominator;\n        uint256 twos = (type(uint256).max - denominator + 1) & denominator;\n        // Divide denominator by power of two\n        assembly {\n            denominator := div(denominator, twos)\n        }\n\n        // Divide [prod1 prod0] by the factors of two\n        assembly {\n            prod0 := div(prod0, twos)\n        }\n        // Shift in bits from prod1 into prod0. For this we need\n        // to flip `twos` such that it is 2**256 / twos.\n        // If twos is zero, then it becomes one\n        assembly {\n            twos := add(div(sub(0, twos), twos), 1)\n        }\n        prod0 |= prod1 * twos;\n\n        // Invert denominator mod 2**256\n        // Now that denominator is an odd number, it has an inverse\n        // modulo 2**256 such that denominator * inv = 1 mod 2**256.\n        // Compute the inverse by starting with a seed that is correct\n        // correct for four bits. That is, denominator * inv = 1 mod 2**4\n        uint256 inv = (3 * denominator) ^ 2;\n        // Now use Newton-Raphson iteration to improve the precision.\n        // Thanks to Hensel's lifting lemma, this also works in modular\n        // arithmetic, doubling the correct bits in each step.\n        inv *= 2 - denominator * inv; // inverse mod 2**8\n        inv *= 2 - denominator * inv; // inverse mod 2**16\n        inv *= 2 - denominator * inv; // inverse mod 2**32\n        inv *= 2 - denominator * inv; // inverse mod 2**64\n        inv *= 2 - denominator * inv; // inverse mod 2**128\n        inv *= 2 - denominator * inv; // inverse mod 2**256\n\n        // Because the division is now exact we can divide by multiplying\n        // with the modular inverse of denominator. This will give us the\n        // correct result modulo 2**256. Since the precoditions guarantee\n        // that the outcome is less than 2**256, this is the final result.\n        // We don't need to compute the high bits of the result and prod1\n        // is no longer required.\n        result = prod0 * inv;\n        return result;\n    }\n\n    /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n    /// @param a The multiplicand\n    /// @param b The multiplier\n    /// @param denominator The divisor\n    /// @return result The 256-bit result\n    function mulDivRoundingUp(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256 result) {\n        result = mulDiv(a, b, denominator);\n        if (mulmod(a, b, denominator) > 0) {\n            require(result < type(uint256).max);\n            result++;\n        }\n    }\n}\n"
      },
      "contracts/oracle/libraries/oracleUtils.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\n/// @title Oracle utils library\n/// @notice implements common utility methods for Fluid Oracles\nlibrary OracleUtils {\n    /// @dev The scaler for max delta point math (100%)\n    uint256 internal constant HUNDRED_PERCENT_DELTA_SCALER = 10_000;\n    /// @dev output precision of rates\n    uint256 internal constant RATE_OUTPUT_DECIMALS = 27;\n\n    /// @dev checks if `mainSourceRate_` is within a `maxDeltaPercent_` of `checkSourceRate_`. Returns true if so.\n    function isRateOutsideDelta(\n        uint256 mainSourceRate_,\n        uint256 checkSourceRate_,\n        uint256 maxDeltaPercent_\n    ) internal pure returns (bool) {\n        uint256 offset_ = (checkSourceRate_ * maxDeltaPercent_) / HUNDRED_PERCENT_DELTA_SCALER;\n        return (mainSourceRate_ > (checkSourceRate_ + offset_) || mainSourceRate_ < (checkSourceRate_ - offset_));\n    }\n}\n"
      },
      "contracts/oracle/libraries/TickMath.sol": {
        "content": "// SPDX-License-Identifier: GPL-2.0-or-later\npragma solidity 0.8.21;\n\n/// @dev   Modified from the original UniswapV3 library to support v0.8\n/// From:  require(absTick <= uint256(MAX_TICK), 'T');\n/// To:    require(absTick <= uint256(int(MAX_TICK)), 'T');\n\n/// @title Math library for computing sqrt prices from ticks and vice versa\n/// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports\n/// prices between 2**-128 and 2**128\nlibrary TickMath {\n    /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128\n    int24 internal constant MIN_TICK = -887272;\n    /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128\n    int24 internal constant MAX_TICK = -MIN_TICK;\n\n    /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)\n    uint160 internal constant MIN_SQRT_RATIO = 4295128739;\n    /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)\n    uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;\n\n    /// @notice Calculates sqrt(1.0001^tick) * 2^96\n    /// @dev Throws if |tick| > max tick\n    /// @param tick The input tick for the above formula\n    /// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)\n    /// at the given tick\n    function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) {\n        uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n        /// @dev This line was modified for v0.8.x\n        // require(absTick <= uint256(MAX_TICK), 'T');\n        require(absTick <= uint256(int(MAX_TICK)), \"T\");\n\n        uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000;\n        if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;\n        if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;\n        if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;\n        if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;\n        if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;\n        if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;\n        if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;\n        if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;\n        if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;\n        if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;\n        if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;\n        if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;\n        if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;\n        if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;\n        if (absTick & 0x8000 != 0) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;\n        if (absTick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;\n        if (absTick & 0x20000 != 0) ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;\n        if (absTick & 0x40000 != 0) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;\n        if (absTick & 0x80000 != 0) ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;\n\n        if (tick > 0) ratio = type(uint256).max / ratio;\n\n        // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.\n        // we then downcast because we know the result always fits within 160 bits due to our tick input constraint\n        // we round up in the division so getTickAtSqrtRatio of the output price is always consistent\n        sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));\n    }\n\n    /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio\n    /// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may\n    /// ever return.\n    /// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96\n    /// @return tick The greatest tick for which the ratio is less than or equal to the input ratio\n    function getTickAtSqrtRatio(uint160 sqrtPriceX96) internal pure returns (int24 tick) {\n        // second inequality must be < because the price can never reach the price at the max tick\n        require(sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO, \"R\");\n        uint256 ratio = uint256(sqrtPriceX96) << 32;\n\n        uint256 r = ratio;\n        uint256 msb = 0;\n\n        assembly {\n            let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))\n            msb := or(msb, f)\n            r := shr(f, r)\n        }\n        assembly {\n            let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF))\n            msb := or(msb, f)\n            r := shr(f, r)\n        }\n        assembly {\n            let f := shl(5, gt(r, 0xFFFFFFFF))\n            msb := or(msb, f)\n            r := shr(f, r)\n        }\n        assembly {\n            let f := shl(4, gt(r, 0xFFFF))\n            msb := or(msb, f)\n            r := shr(f, r)\n        }\n        assembly {\n            let f := shl(3, gt(r, 0xFF))\n            msb := or(msb, f)\n            r := shr(f, r)\n        }\n        assembly {\n            let f := shl(2, gt(r, 0xF))\n            msb := or(msb, f)\n            r := shr(f, r)\n        }\n        assembly {\n            let f := shl(1, gt(r, 0x3))\n            msb := or(msb, f)\n            r := shr(f, r)\n        }\n        assembly {\n            let f := gt(r, 0x1)\n            msb := or(msb, f)\n        }\n\n        if (msb >= 128) r = ratio >> (msb - 127);\n        else r = ratio << (127 - msb);\n\n        int256 log_2 = (int256(msb) - 128) << 64;\n\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            log_2 := or(log_2, shl(63, f))\n            r := shr(f, r)\n        }\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            log_2 := or(log_2, shl(62, f))\n            r := shr(f, r)\n        }\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            log_2 := or(log_2, shl(61, f))\n            r := shr(f, r)\n        }\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            log_2 := or(log_2, shl(60, f))\n            r := shr(f, r)\n        }\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            log_2 := or(log_2, shl(59, f))\n            r := shr(f, r)\n        }\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            log_2 := or(log_2, shl(58, f))\n            r := shr(f, r)\n        }\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            log_2 := or(log_2, shl(57, f))\n            r := shr(f, r)\n        }\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            log_2 := or(log_2, shl(56, f))\n            r := shr(f, r)\n        }\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            log_2 := or(log_2, shl(55, f))\n            r := shr(f, r)\n        }\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            log_2 := or(log_2, shl(54, f))\n            r := shr(f, r)\n        }\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            log_2 := or(log_2, shl(53, f))\n            r := shr(f, r)\n        }\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            log_2 := or(log_2, shl(52, f))\n            r := shr(f, r)\n        }\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            log_2 := or(log_2, shl(51, f))\n            r := shr(f, r)\n        }\n        assembly {\n            r := shr(127, mul(r, r))\n            let f := shr(128, r)\n            log_2 := or(log_2, shl(50, f))\n        }\n\n        int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number\n\n        int24 tickLow = int24((log_sqrt10001 - 3402992956809132418596140100660247210) >> 128);\n        int24 tickHi = int24((log_sqrt10001 + 291339464771989622907027621153398088495) >> 128);\n\n        tick = tickLow == tickHi ? tickLow : getSqrtRatioAtTick(tickHi) <= sqrtPriceX96 ? tickHi : tickLow;\n    }\n}\n"
      },
      "contracts/oracle/oracles/uniV3CheckCLRSOracle.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { FluidOracle } from \"../fluidOracle.sol\";\nimport { FallbackOracleImpl } from \"../implementations/fallbackOracleImpl.sol\";\nimport { UniV3OracleImpl } from \"../implementations/uniV3OracleImpl.sol\";\nimport { ErrorTypes } from \"../errorTypes.sol\";\nimport { OracleUtils } from \"../libraries/oracleUtils.sol\";\n\n/// @title   UniswapV3 checked against Chainlink / Redstone Oracle. Either one reported as exchange rate.\n/// @notice  Gets the exchange rate between the underlying asset and the peg asset by using:\n///          the price from a UniV3 pool (compared against 3 TWAPs) and (optionally) comparing it against a Chainlink\n///          or Redstone price (one of Chainlink or Redstone being the main source and the other one the fallback source).\n///          Alternatively it can also use Chainlink / Redstone as main price and use UniV3 as check price.\n/// @dev     The process for getting the aggregate oracle price is:\n///           1. Fetch the UniV3 TWAPS, the latest interval is used as the current price\n///           2. Verify this price is within an acceptable DELTA from the Uniswap TWAPS e.g.:\n///              a. 240 to 60s\n///              b. 60 to 15s\n///              c. 15 to 1s (last block)\n///              d. 1 to 0s (current)\n///           3. (unless UniV3 only mode): Verify this price is within an acceptable DELTA from the Chainlink / Redstone Oracle\n///           4. If it passes all checks, return the price. Otherwise use fallbacks, usually to Chainlink. In extreme edge-cases revert.\n/// @dev     For UniV3 with check mode, if fetching the check price fails, the UniV3 rate is used directly.\ncontract UniV3CheckCLRSOracle is FluidOracle, UniV3OracleImpl, FallbackOracleImpl {\n    /// @dev Rate check oracle delta percent in 1e2 percent. If current uniswap price is out of this delta,\n    /// current price fetching reverts.\n    uint256 internal immutable _RATE_CHECK_MAX_DELTA_PERCENT;\n\n    /// @dev which oracle to use as final rate source:\n    ///      - 1 = UniV3 ONLY (no check),\n    ///      - 2 = UniV3 with Chainlink / Redstone check\n    ///      - 3 = Chainlink / Redstone with UniV3 used as check.\n    uint8 internal immutable _RATE_SOURCE;\n\n    struct UniV3CheckCLRSConstructorParams {\n        /// @param uniV3Params                UniV3Oracle constructor params struct.\n        UniV3ConstructorParams uniV3Params;\n        /// @param chainlinkParams            ChainlinkOracle constructor params struct for UniV3CheckCLRSOracle.\n        ChainlinkConstructorParams chainlinkParams;\n        /// @param redstoneOracle             Redstone Oracle data for UniV3CheckCLRSOracle. (address can be set to zero address if using Chainlink only)\n        RedstoneOracleData redstoneOracle;\n        /// @param rateSource                 which oracle to use as final rate source for UniV3CheckCLRSOracle:\n        ///                                         - 1 = UniV3 ONLY (no check),\n        ///                                         - 2 = UniV3 with Chainlink / Redstone check\n        ///                                         - 3 = Chainlink / Redstone with UniV3 used as check.\n        uint8 rateSource;\n        /// @param fallbackMainSource         which oracle to use as CL/RS main source for UniV3CheckCLRSOracle: see FallbackOracleImpl constructor `mainSource_`\n        uint8 fallbackMainSource;\n        /// @param rateCheckMaxDeltaPercent   Rate check oracle delta in 1e2 percent for UniV3CheckCLRSOracle\n        uint256 rateCheckMaxDeltaPercent;\n    }\n\n    constructor(\n        UniV3CheckCLRSConstructorParams memory params_\n    )\n        UniV3OracleImpl(params_.uniV3Params)\n        FallbackOracleImpl(params_.fallbackMainSource, params_.chainlinkParams, params_.redstoneOracle)\n    {\n        if (\n            params_.rateSource < 1 ||\n            params_.rateSource > 3 ||\n            params_.rateCheckMaxDeltaPercent > OracleUtils.HUNDRED_PERCENT_DELTA_SCALER ||\n            // Chainlink only Oracle with UniV3 check. Delta would be ignored so revert this type of Oracle setup.\n            (params_.fallbackMainSource == 1 && params_.rateSource == 3)\n        ) {\n            revert FluidOracleError(ErrorTypes.UniV3CheckCLRSOracle__InvalidParams);\n        }\n\n        _RATE_CHECK_MAX_DELTA_PERCENT = params_.rateCheckMaxDeltaPercent;\n        _RATE_SOURCE = params_.rateSource;\n    }\n\n    /// @inheritdoc FluidOracle\n    function getExchangeRateOperate() public view virtual override returns (uint256 exchangeRate_) {\n        return _getExchangeRate();\n    }\n\n    /// @inheritdoc FluidOracle\n    function getExchangeRateLiquidate() public view virtual override returns (uint256 exchangeRate_) {\n        return _getExchangeRate();\n    }\n\n    /// @inheritdoc FluidOracle\n    function getExchangeRate() public view virtual override returns (uint256 exchangeRate_) {\n        return _getExchangeRate();\n    }\n\n    /// @notice returns all oracle related data as utility for easy off-chain / block explorer use in a single view method\n    function uniV3CheckOracleData()\n        public\n        view\n        returns (uint256 rateCheckMaxDelta_, uint256 rateSource_, uint256 fallbackMainSource_)\n    {\n        return (_RATE_CHECK_MAX_DELTA_PERCENT, _RATE_SOURCE, _FALLBACK_ORACLE_MAIN_SOURCE);\n    }\n\n    function _getExchangeRate() internal view returns (uint256 exchangeRate_) {\n        if (_RATE_SOURCE == 1) {\n            // uniswap is the only main source without check:\n            // 1. get uniV3 rate.\n            // 2. If that fails (outside delta range) -> revert (no other Oracle configured).\n            exchangeRate_ = _getUniV3ExchangeRate();\n\n            if (exchangeRate_ == 0) {\n                // fetching UniV3 failed or invalid delta -> revert\n                revert FluidOracleError(ErrorTypes.UniV3CheckCLRSOracle__ExchangeRateZero);\n            }\n\n            return exchangeRate_;\n        }\n\n        uint256 checkRate_;\n        bool fallback_;\n        if (_RATE_SOURCE == 2) {\n            // uniswap is main source, with Chainlink / Redstone as check\n            // 1. get uniV3 rate\n\n            // case uniV3 rate fails (outside delta range):\n            // 2. get Chainlink rate. -> if successful, use Chainlink as result\n            // 3. if Chainlink fails too, get Redstone -> if successful, use Redstone as result\n            // 4. if Redstone fails too, revert\n\n            // case if uniV3 rate is ok\n            // 2. get Chainlink or Redstone rate for check (one is configured as main check source, other one is fallback source)\n            //    -> if both fail to fetch, use uniV3 rate directly.\n            // 3. check the delta for uniV3 rate against the check soure rate. -> if ok, return uniV3 rate\n            // 4. if delta check fails, check delta against the fallback check source. -> if ok, return uniV3 rate\n            // 5. if delta check fails for both sources, return Chainlink price\n\n            exchangeRate_ = _getUniV3ExchangeRate();\n\n            if (exchangeRate_ == 0) {\n                // uniV3 failed or invalid delta -> use (Chainlink with Redstone as fallback)\n                exchangeRate_ = _getChainlinkOrRedstoneAsFallback();\n                if (exchangeRate_ == 0) {\n                    // Chainlink / Redstone failed too -> revert\n                    revert FluidOracleError(ErrorTypes.UniV3CheckCLRSOracle__ExchangeRateZero);\n                }\n                return exchangeRate_;\n            }\n\n            (checkRate_, fallback_) = _getRateWithFallback();\n            if (checkRate_ == 0) {\n                // check price source failed to fetch -> directly use uniV3 TWAP checked price\n                // Note uniV3 price fetching was successful, would have been caught otherwise above.\n                return exchangeRate_;\n            }\n        } else {\n            // Chainlink / Redstone is main source, with uniV3 as check.\n            // 1. get Chainlink / Redstone rate (one is configured as main source, other one is fallback source)\n\n            // case when both Chainlink & Redstone fail:\n            // 2. get uniV3 rate. if successful, use uniV3 rate. otherwise, revert (all oracles failed).\n\n            // case when Chainlink / Redstone fetch is successful:\n            // 2. get uniV3 rate for check.\n            // 3. if uniV3 rate fails to fetch (outside delta), use Chainlink / Redstone directly (skip check).\n            // 4. if uniV3 rate is ok, check the delta for Chainlink / Redstone rate against uniV3 rate.\n            //    -> if ok, return Chainlink / Redstone (main) rate\n            // 5. if delta check fails, check delta against the fallback main source.\n            //    -> if ok, return fallback main rate\n            // 6. if delta check fails for both sources, return Chainlink price.\n\n            (exchangeRate_, fallback_) = _getRateWithFallback();\n            checkRate_ = _getUniV3ExchangeRate();\n\n            if (exchangeRate_ == 0) {\n                if (checkRate_ == 0) {\n                    // all oracles failed, revert\n                    revert FluidOracleError(ErrorTypes.UniV3CheckCLRSOracle__ExchangeRateZero);\n                }\n\n                // Both Chainlink & Redstone failed -> directly use uniV3 TWAP checked price\n                // Note uniV3 price fetching was successful, would have been caught otherwise above.\n                return checkRate_;\n            }\n\n            if (checkRate_ == 0) {\n                // uniV3 failed -> skip check against Uniswap price.\n\n                return exchangeRate_;\n            }\n        }\n\n        if (OracleUtils.isRateOutsideDelta(exchangeRate_, checkRate_, _RATE_CHECK_MAX_DELTA_PERCENT)) {\n            if (fallback_) {\n                // fallback already used, no other rate available to check.\n\n                // if price is chainlink price -> return it.\n                if (_FALLBACK_ORACLE_MAIN_SOURCE == 3) {\n                    // redstone with Chainlink as fallback\n                    return _RATE_SOURCE == 2 ? checkRate_ : exchangeRate_; // if rate source is 2, Chainlink rate is in checkRate_\n                }\n\n                // if price is redstone price -> revert\n                revert FluidOracleError(ErrorTypes.UniV3CheckCLRSOracle__InvalidPrice);\n            }\n\n            if (_FALLBACK_ORACLE_MAIN_SOURCE == 1) {\n                // 1 = only chainlink and UniV3 is configured and delta check failed. no fallback available.\n                if (_RATE_SOURCE == 2) {\n                    // case where uniV3 is main source with only Chainlink as check rate Oracle configured.\n                    // delta check failed -> return Chainlink price (instead of uniV3 price).\n                    return checkRate_;\n                }\n\n                // here: if (_FALLBACK_ORACLE_MAIN_SOURCE == 1 && _RATE_SOURCE == 3)\n                // rate source is 3: Chainlink as main, uniV3 as delta. delta check failed.\n                // this Oracle type would basically be a more expensive Chainlink-only Oracle because the delta check against UniV3 is ignored.\n                // this setup is reverted in constructor, but in any case returning Chainlink price here even though this code should never be reached.\n                return exchangeRate_; // exchangeRate_ here is chainlink price\n            }\n\n            // fallback not done yet -> check against fallback price.\n            // So if originally Chainlink was fetched and delta failed, check against Redstone.\n            // if originally Redstone was fetched and delta failed, check against Chainlink.\n            if (_FALLBACK_ORACLE_MAIN_SOURCE == 2) {\n                // 2 = Chainlink with Redstone Fallback. delta check against Chainlink failed. try against Redstone.\n                uint256 redstoneRate_ = _getRedstoneExchangeRate();\n                uint256 chainlinkRate_;\n                if (_RATE_SOURCE == 2) {\n                    // uniV3 main source. -> update checkRate_ with Redstone price\n                    chainlinkRate_ = checkRate_;\n                    checkRate_ = redstoneRate_;\n                } else {\n                    // uniV3 is check source. -> update exchangeRate_ with Redstone price\n                    chainlinkRate_ = exchangeRate_;\n                    exchangeRate_ = redstoneRate_;\n                }\n\n                if (redstoneRate_ == 0) {\n                    // fetching Redstone failed. So delta UniV3 <> Chainlink failed, fetching Redstone as backup failed.\n                    // -> return chainlink price (for both cases when Chainlink is main and when UniV3 is the main source).\n                    return chainlinkRate_;\n                }\n\n                if (OracleUtils.isRateOutsideDelta(exchangeRate_, checkRate_, _RATE_CHECK_MAX_DELTA_PERCENT)) {\n                    // delta check against Redstone failed too. return Chainlink price\n                    return chainlinkRate_;\n                }\n\n                // delta check against Redstone passed. if uniV3 main source -> return uniV3, else return Redstone.\n                // exchangeRate_ is already set correctly for this.\n            } else {\n                // 3 = Redstone with Chainlink Fallback. delta check against Redstone failed. try against Chainlink.\n                uint256 chainlinkRate_ = _getChainlinkExchangeRate();\n                if (chainlinkRate_ == 0) {\n                    // fetching Chainlink failed. So delta UniV3 <> Redstone failed, fetching Chainlink as backup check failed.\n                    // -> revert.\n                    revert FluidOracleError(ErrorTypes.UniV3CheckCLRSOracle__InvalidPrice);\n                }\n\n                if (_RATE_SOURCE == 3) {\n                    // uniV3 is check source. -> update exchangeRate_ with Chainlink price.\n                    // Optimization: in this case we can directly return chainlink price, because if delta check between\n                    // Chainlink (new main source) and uniV3 (check source) fails, we anyway return Chainlink price still.\n                    return chainlinkRate_;\n                }\n\n                // uniV3 main source. -> update checkRate_ with Chainlink price and compare delta again\n                checkRate_ = chainlinkRate_;\n\n                if (OracleUtils.isRateOutsideDelta(exchangeRate_, checkRate_, _RATE_CHECK_MAX_DELTA_PERCENT)) {\n                    // delta check against Chainlink failed too. case here can only be where uniV3 would have been\n                    // main source and Chainlink check source. -> return Chainlink as price instead of uniV3\n                    return checkRate_;\n                }\n\n                // delta check against Chainlink passed. if uniV3 main source -> return uniV3, else return Chainlink.\n                // exchangeRate_ is already set correctly for this.\n            }\n        }\n    }\n}\n"
      },
      "contracts/oracle/oracles/wstETHCLRS2UniV3CheckCLRSOracle.sol": {
        "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.21;\n\nimport { FluidOracle } from \"../fluidOracle.sol\";\nimport { UniV3CheckCLRSOracle } from \"./uniV3CheckCLRSOracle.sol\";\nimport { WstETHOracleImpl } from \"../implementations/wstETHOracleImpl.sol\";\nimport { FallbackOracleImpl2 } from \"../implementations/fallbackOracleImpl2.sol\";\nimport { IWstETH } from \"../interfaces/external/IWstETH.sol\";\nimport { OracleUtils } from \"../libraries/oracleUtils.sol\";\nimport { ErrorTypes } from \"../errorTypes.sol\";\n\n// @dev uses FallbackOracleImpl2 to avoid conflicts with already used ChainlinkOracleImpl, RedstoneOracleImpl and\n// FallbackOracleImpl in UniV3CheckCLRSOracle.\n\n/// @title   wstETHCLRSOracle combined with a uniV3CheckCLRSOracle.\n/// @notice  Gets the exchange rate between the underlying asset and the peg asset by using:\n///          1. wstETH Oracle price in combination with rate from Chainlink price feeds (or Redstone as fallback).\n///             combining those two into one rate resulting in wstETH <> someToken\n///          2. result from 1. combined with a uniV3CheckCLRSOracle to get from someToken <> someToken2\n///          e.g. when going from wstETH to USDC:\n///          1. wstETH -> stETH wstETH Oracle, stETH -> ETH Chainlink feed.\n///          2. ETH -> USDC via UniV3 ETH <> USDC pool checked against ETH -> USDC Chainlink feed.\ncontract WstETHCLRS2UniV3CheckCLRSOracle is FluidOracle, WstETHOracleImpl, FallbackOracleImpl2, UniV3CheckCLRSOracle {\n    struct WstETHCLRS2ConstructorParams {\n        /// @param wstETH                         address of the wstETH contract\n        IWstETH wstETH;\n        /// @param fallbackMainSource             which oracle to use as main source for wstETH <> CLRS: 1 = Chainlink, 2 = Redstone (other one is fallback).\n        uint8 fallbackMainSource;\n        /// @param chainlinkParams                chainlink Oracle constructor params struct for wstETH <> CLRS.\n        ChainlinkConstructorParams chainlinkParams;\n        /// @param redstoneOracle                 Redstone Oracle data for wstETH <> CLRS. (address can be set to zero address if using Chainlink only)\n        RedstoneOracleData redstoneOracle;\n    }\n\n    /// @notice                       constructs a WstETHCLRS2UniV3CheckCLRSOracle with all inherited contracts\n    /// @param  wstETHCLRS2Params_    WstETHCLRS2ConstructorParams for wstETH <> CLRS Token2 conversion\n    /// @param  uniV3CheckCLRSParams_ UniV3CheckCLRSOracle constructor params\n    constructor(\n        WstETHCLRS2ConstructorParams memory wstETHCLRS2Params_,\n        UniV3CheckCLRSConstructorParams memory uniV3CheckCLRSParams_\n    )\n        WstETHOracleImpl(wstETHCLRS2Params_.wstETH)\n        FallbackOracleImpl2(\n            wstETHCLRS2Params_.fallbackMainSource,\n            wstETHCLRS2Params_.chainlinkParams,\n            wstETHCLRS2Params_.redstoneOracle\n        )\n        UniV3CheckCLRSOracle(uniV3CheckCLRSParams_)\n    {}\n\n    /// @inheritdoc FluidOracle\n    function getExchangeRateOperate()\n        public\n        view\n        override(FluidOracle, UniV3CheckCLRSOracle)\n        returns (uint256 exchangeRate_)\n    {\n        // 1. get CLRS Oracle rate for stETH <> CLRS feed. uses FallbackOracleImpl2\n        (exchangeRate_, ) = _getRateWithFallback2();\n        if (exchangeRate_ == 0) {\n            // revert if fetched exchange rate is 0\n            revert FluidOracleError(ErrorTypes.WstETHCLRS2UniV3CheckCLRSOracle__ExchangeRateZero);\n        }\n\n        // 2. combine CLRS feed price with wstETH price to have wstETH <> stETH <> SomeToken fully converted\n        exchangeRate_ = (_getWstETHExchangeRate() * exchangeRate_) / (10 ** OracleUtils.RATE_OUTPUT_DECIMALS);\n\n        // 3. get rate from UniV3Check Oracle (likely uniV3 / Chainlink checked against for delta). This always returns\n        //    a price if some rate is valid, with multiple fallbacks. Can not return 0. Combine this rate with existing.\n        //    (super.getExchangeRate returns UniV3CheckCLRSOracle rate, no other inherited contract has this.)\n        exchangeRate_ = (super.getExchangeRateOperate() * exchangeRate_) / (10 ** OracleUtils.RATE_OUTPUT_DECIMALS);\n    }\n\n    /// @inheritdoc FluidOracle\n    function getExchangeRateLiquidate()\n        public\n        view\n        override(FluidOracle, UniV3CheckCLRSOracle)\n        returns (uint256 exchangeRate_)\n    {\n        // 1. get CLRS Oracle rate for stETH <> CLRS feed. uses FallbackOracleImpl2\n        (exchangeRate_, ) = _getRateWithFallback2();\n        if (exchangeRate_ == 0) {\n            // revert if fetched exchange rate is 0\n            revert FluidOracleError(ErrorTypes.WstETHCLRS2UniV3CheckCLRSOracle__ExchangeRateZero);\n        }\n\n        // 2. combine CLRS feed price with wstETH price to have wstETH <> stETH <> SomeToken fully converted\n        exchangeRate_ = (_getWstETHExchangeRate() * exchangeRate_) / (10 ** OracleUtils.RATE_OUTPUT_DECIMALS);\n\n        // 3. get rate from UniV3Check Oracle (likely uniV3 / Chainlink checked against for delta). This always returns\n        //    a price if some rate is valid, with multiple fallbacks. Can not return 0. Combine this rate with existing.\n        //    (super.getExchangeRate returns UniV3CheckCLRSOracle rate, no other inherited contract has this.)\n        exchangeRate_ = (super.getExchangeRateLiquidate() * exchangeRate_) / (10 ** OracleUtils.RATE_OUTPUT_DECIMALS);\n    }\n\n    /// @inheritdoc FluidOracle\n    function getExchangeRate() public view override(FluidOracle, UniV3CheckCLRSOracle) returns (uint256 exchangeRate_) {\n        return getExchangeRateOperate();\n    }\n\n    /// @notice which oracle to use as main source:\n    ///          - 1 = Chainlink ONLY (no fallback)\n    ///          - 2 = Chainlink with Redstone Fallback\n    ///          - 3 = Redstone with Chainlink Fallback\n    function FALLBACK_ORACLE2_MAIN_SOURCE() public view returns (uint8) {\n        return _FALLBACK_ORACLE2_MAIN_SOURCE;\n    }\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 10000000
      },
      "evmVersion": "paris",
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "metadata": {
        "useLiteralContent": true
      },
      "libraries": {}
    }
  }}