DeFiHardhatFoundry
250,000 USDC
View results
Submission Details
Severity: high
Valid

Inconsistent price normalizations in LibUsdOracle

Summary

LibUsdOracle returns extremely wrong price when price fetched from 0x02 type of oracles, i.e uniswap as no price normalization is done for 0x02 type oracles

Vulnerability Details

To understand the workings of getUsdPrice() we need to understand
getTokenPriceFromExternal() which returns value of 1e24/price in case of chainlink oracle

function getTokenPriceFromExternal(
address token,
uint256 lookback
) internal view returns (uint256 tokenPrice) {
....
return
uint256(1e24).div(
LibChainlinkOracle.getTokenPrice(
chainlinkOraclePriceAddress,
LibChainlinkOracle.FOUR_HOUR_TIMEOUT,
lookback
)
);
///@audit ^ normalization done
} else if (oracleImpl.encodeType == bytes1(0x02)) {
....
uint256 chainlinkTokenPrice = LibChainlinkOracle.getTokenPrice(
chainlinkOraclePriceAddress,
LibChainlinkOracle.FOUR_HOUR_TIMEOUT,
lookback
);
return tokenPrice.mul(chainlinkTokenPrice).div(1e6);
///@audit ^ no normalization done
}

but in case of uni oracle it directly returns the price

function getUsdPrice(address token, uint256 lookback) internal view returns (uint256) {
if (token == C.WETH) {
uint256 ethUsdPrice = LibEthUsdOracle.getEthUsdPrice(lookback);
if (ethUsdPrice == 0) return 0;
return uint256(1e24).div(ethUsdPrice);
}
if (token == C.WSTETH) {
uint256 wstethUsdPrice = LibWstethUsdOracle.getWstethUsdPrice(lookback);
if (wstethUsdPrice == 0) return 0;
return uint256(1e24).div(wstethUsdPrice);
}
// 1e18 * 1e6 = 1e24.
uint256 tokenPrice = getTokenPriceFromExternal(token, lookback);
if (tokenPrice == 0) return 0;
return uint256(1e24).div(tokenPrice);
}

but in get usdPrice it gets divided by 1e24 which leads to totally bogus price, but the chainlink price works fine cause 1e24 / (1e24 / price) = price but
1e24/ (price) != price in case of 0x02(uniswap) oracles

Code snippets-
https://github.com/Cyfrin/2024-05-beanstalk-the-finale/blob/4e0ad0b964f74a1b4880114f4dd5b339bc69cd3e/protocol/contracts/libraries/Oracle/LibUsdOracle.sol#L128-L160

https://github.com/Cyfrin/2024-05-beanstalk-the-finale/blob/4e0ad0b964f74a1b4880114f4dd5b339bc69cd3e/protocol/contracts/libraries/Oracle/LibUsdOracle.sol#L49-L65

Impact

Wrong price

Tools Used

Manual review

Recommendations

uint256 chainlinkTokenPrice = LibChainlinkOracle.getTokenPrice(
chainlinkOraclePriceAddress,
LibChainlinkOracle.FOUR_HOUR_TIMEOUT,
lookback
);
-- return tokenPrice.mul(chainlinkTokenPrice).div(1e6);
++ return 1e24.div(tokenPrice.mul(chainlinkTokenPrice).div(1e6));
Updates

Lead Judging Commences

inallhonesty Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Appeal created

kalyansingh2 Submitter
12 months ago
inallhonesty Lead Judge 12 months ago
Submission Judgement Published
Validated
Assigned finding tags:

`getUsdPrice` returns mixed decimals

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.