Summary
Protocol widely assumes that price from oracle adapters has 1e6 precission. However it will return incorrect price when configured oracle for token is Chainlink price Price feed because it for some reason divides 1e24 by correct price.
Vulnerability Details
For some reason it returns 1e24 / chainlinkPrice
instead of chainlinkPrice
:
function getTokenPriceFromExternal(
address token,
uint256 lookback
) internal view returns (uint256 tokenPrice) {
....
if (oracleImpl.encodeType == bytes1(0x01)) {
address chainlinkOraclePriceAddress = oracleImpl.target;
if (chainlinkOraclePriceAddress == address(0)) {
chainlinkOraclePriceAddress = ChainlinkPriceFeedRegistry(chainlinkRegistry).getFeed(
token,
0x0000000000000000000000000000000000000348
);
}
return
@> uint256(1e24).div(
LibChainlinkOracle.getTokenPrice(
chainlinkOraclePriceAddress,
LibChainlinkOracle.FOUR_HOUR_TIMEOUT,
lookback
)
);
However it's widely assumed that function returns how much USD 1 token worths:
@> * @notice returns the price of a given token in USD (token:Usd Price)
@> * @dev if ETH returns 1000 USD, this function returns 1000
@> * (ignoring decimal precision)
*/
function getTokenPrice(address token, uint256 lookback) internal view returns (uint256) {
if (token == C.WETH) {
uint256 ethUsdPrice = LibEthUsdOracle.getEthUsdPrice(lookback);
if (ethUsdPrice == 0) return 0;
return ethUsdPrice;
}
if (token == C.WSTETH) {
uint256 wstethUsdPrice = LibWstethUsdOracle.getWstethUsdPrice(0);
if (wstethUsdPrice == 0) return 0;
return wstethUsdPrice;
}
@> return getTokenPriceFromExternal(token, lookback);
}
Impact
Incorrect price is returned.
Tools Used
Manual Review
Recommendations
Just return price:
return
- uint256(1e24).div(
LibChainlinkOracle.getTokenPrice(
chainlinkOraclePriceAddress,
LibChainlinkOracle.FOUR_HOUR_TIMEOUT,
lookback
)
- );