|
| 1 | +// SPDX-License-Identifier: LicenseRef-DCL-1.0 |
| 2 | +// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd |
| 3 | +pragma solidity =0.8.25; |
| 4 | + |
| 5 | +import {PriceOracleV2} from "../../abstract/PriceOracleV2.sol"; |
| 6 | +import {IPyth} from "pyth-sdk/IPyth.sol"; |
| 7 | +import {PythStructs} from "pyth-sdk/PythStructs.sol"; |
| 8 | +import {LibDecimalFloat, Float} from "rain.math.float/lib/LibDecimalFloat.sol"; |
| 9 | + |
| 10 | +error NonPositivePrice(int256 price); |
| 11 | + |
| 12 | +struct PythOracleConfig { |
| 13 | + bytes32 priceFeedId; |
| 14 | + uint256 staleAfter; |
| 15 | + IPyth pythContract; |
| 16 | +} |
| 17 | + |
| 18 | +contract PythOracle is PriceOracleV2 { |
| 19 | + event Construction(address sender, PythOracleConfig config); |
| 20 | + |
| 21 | + //slither-disable-next-line naming-convention |
| 22 | + bytes32 public immutable I_PRICE_FEED_ID; |
| 23 | + //slither-disable-next-line naming-convention |
| 24 | + uint256 public immutable I_STALE_AFTER; |
| 25 | + //slither-disable-next-line naming-convention |
| 26 | + IPyth public immutable I_PYTH_CONTRACT; |
| 27 | + |
| 28 | + constructor(PythOracleConfig memory config) { |
| 29 | + I_PRICE_FEED_ID = config.priceFeedId; |
| 30 | + I_STALE_AFTER = config.staleAfter; |
| 31 | + I_PYTH_CONTRACT = config.pythContract; |
| 32 | + |
| 33 | + emit Construction(msg.sender, config); |
| 34 | + } |
| 35 | + |
| 36 | + function _price() internal virtual override returns (uint256) { |
| 37 | + // Slither false positive, confidence is checked here. |
| 38 | + // slither-disable-next-line pyth-unchecked-confidence |
| 39 | + PythStructs.Price memory priceData = I_PYTH_CONTRACT.getPriceNoOlderThan(I_PRICE_FEED_ID, I_STALE_AFTER); |
| 40 | + int256 conservativePrice = int256(priceData.price) - int256(uint256(priceData.conf)); |
| 41 | + if (conservativePrice <= 0) { |
| 42 | + revert NonPositivePrice(conservativePrice); |
| 43 | + } |
| 44 | + // It is safe to pack lossless here because the price data uses only |
| 45 | + // 64 bits while we have 224 bits for a packed signed coefficient, and |
| 46 | + // the exponent bit size is the same for both. |
| 47 | + Float conservativePriceFloat = LibDecimalFloat.packLossless(conservativePrice, priceData.expo); |
| 48 | + // We ignore precision loss here, truncating towards zero. |
| 49 | + //slither-disable-next-line unused-return |
| 50 | + (uint256 price18,) = LibDecimalFloat.toFixedDecimalLossy(conservativePriceFloat, 18); |
| 51 | + return price18; |
| 52 | + } |
| 53 | +} |
0 commit comments