LibUsdOracle will revert for stablecoins for 20 hours per day almost every day expect rare depeg events.
function getTokenPriceFromExternal(
address token,
uint256 lookback
) internal view returns (uint256 tokenPrice) {
AppStorage storage s = LibAppStorage.diamondStorage();
.....
return
uint256(1e24).div(
LibChainlinkOracle.getTokenPrice(
chainlinkOraclePriceAddress,
LibChainlinkOracle.FOUR_HOUR_TIMEOUT,
lookback
)
);
} else if (oracleImpl.encodeType == bytes1(0x02)) {
....
Implementation memory chainlinkOracleImpl = s.sys.oracleImplementation[chainlinkToken];
address chainlinkOraclePriceAddress = chainlinkOracleImpl.target;
.....
uint256 chainlinkTokenPrice = LibChainlinkOracle.getTokenPrice(
chainlinkOraclePriceAddress,
LibChainlinkOracle.FOUR_HOUR_TIMEOUT,
lookback
);
return tokenPrice.mul(chainlinkTokenPrice).div(1e6);
}
Chainlink stables have a heart beat of 24 hours i.e if the deviation threshold is not passed for this much time there will be no update to the price , but getTokenPriceFromExternal() hardcodes this limit to 4 hours which leads to price of token = 0 if the token is a stablecoin
* SPDX-License-Identifier: MIT
**/
pragma solidity ^0.8.20;
import "forge-std/Test.sol";
import {C} from "contracts/C.sol";
import {LibEthUsdOracle} from "../../../contracts/libraries/Oracle/LibEthUsdOracle.sol";
import {LibUniswapOracle} from "../../../contracts/libraries/Oracle/LibUniswapOracle.sol";
import {LibChainlinkOracle} from "../../../contracts/libraries/Oracle/LibChainlinkOracle.sol";
import {LibWstethUsdOracle} from "../../../contracts/libraries/Oracle/LibWstethUsdOracle.sol";
import "../../../contracts/libraries/Oracle/LibWstethEthOracle.sol";
import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
import {LibAppStorage} from "contracts/libraries/LibAppStorage.sol";
import {Implementation} from "contracts/beanstalk/storage/System.sol";
import {AppStorage} from "contracts/beanstalk/storage/AppStorage.sol";
import {LibRedundantMath256} from "contracts/libraries/LibRedundantMath256.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {console} from "forge-std/console.sol";
import {LibUsdOracle} from "../../../contracts/libraries/Oracle/LibUsdOracle.sol";
interface IERC20Decimals {
function decimals() external view returns (uint8);
}
interface ChainlinkPriceFeedRegistry {
function getFeed(address base, address quote) external view returns (address aggregator);
}
contract Diamond{
AppStorage internal s;
}
contract PriceTesterWstethETH is Diamond,Test{
address public constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
address public constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
address public constant DAIUSDC = 0x6c6Bc977E13Df9b0de53b251522280BB72383700;
address public constant USDCUSD = 0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6;
address public constant AAVEUSD = 0x547a514d5e3769680Ce22B2361c10Ea13619e8a9;
address public constant AAVE = 0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9;
using LibRedundantMath256 for uint256;
function setUp() public {
vm.label(DAI,"DAI");
vm.label(USDC,"USDC");
vm.label(DAIUSDC,"UniV3DaiUsdc");
vm.label(USDCUSD,"USDCFeed");
vm.label(AAVEUSD,"AAVEUSD");
vm.createSelectFork("https://rpc.ankr.com/eth",20008200);
}
function testPrice2() public {
bytes4 b;
Implementation memory a2 = Implementation({
target: USDCUSD,
selector: b,
encodeType:bytes1(0x01)
});
s.sys.oracleImplementation[USDC] = a2;
uint price2;
price2 = LibUsdOracle.getUsdPrice(USDC);
emit log_named_decimal_uint("price2", price2, 6);
}
}
where libUsdOracle is setting maxTimeout = 4 hours but the chainlink feeds only get updated once per day in most of the cases(strictly stablecoins) .
You can also verify the same by uncommenting the 2nd fork line USDC/USD was updated in 20253304 block number so then it will work but in blocks after that i.e for rest of 20 hours for the day it wont.
As it wont pass legitimacy checks in LibChainlinkOracle.sol
Run the Poc by putting it in test/foundry/OracleLibs(newDir)/Filename.t.sol for working imports
For stables set threshold(maxTmeout) of 24 hours.