DeFiHardhatFoundry
250,000 USDC
View results
Submission Details
Severity: medium
Invalid

Due to different scaled factor, calculated `wstethEthPrice` will suffer from sever precision loss

Summary

returned wstethEthPricefrom getWstethEthPricewill wrong due to precision loss in division

Vulnerability Details

In getWstethEthPrice()calculates wstETH in term of ETH with 6 decimal precision as mentioned in natspec comment.

wstethEthPrice = chainlinkPrice.add(uniswapPrice).div(AVERAGE_DENOMINATOR);
Here you can see that `chainlinkPrice` is scaled down by 10**6 and `uniswapPrice` is in scaled up by 10**6
and `wstethEthPrice` taking avarage of both of them by dividing these 2 addition by 2 `AVERAGE_DENOMINATOR = 2`

As both parameter to be added are of different decimal then their avarae could lead to huge precision loss and returned wstethEthPricewill be wrong.

https://github.com/Cyfrin/2024-05-beanstalk-the-finale/blob/main/protocol/contracts/libraries/Oracle/LibWstethEthOracle.sol#L94

Impact

refer Details section

Tools Used

Manual review

Recommendations

chainlinkPrice parameter should used directly without scaling it down.

https://github.com/Cyfrin/2024-05-beanstalk-the-finale/blob/main/protocol/contracts/libraries/Oracle/LibWstethEthOracle.sol#L78-L96

And at avarage calculation then it will scaled down by 10**6

chainlinkPrice = chainlinkPrice.mul(stethPerWsteth).div(CHAINLINK_DENOMINATOR);
uint256 stethPerWsteth = IWsteth(C.WSTETH).stEthPerToken();
chainlinkPrice = chainlinkPrice.mul(stethPerWsteth).div(CHAINLINK_DENOMINATOR);
// Uniswap V3 only supports a uint32 lookback.
if (lookback > type(uint32).max) return 0;
uint256 uniswapPrice = LibUniswapOracle.getTwap(
lookback == 0 ? LibUniswapOracle.FIFTEEN_MINUTES : uint32(lookback),
C.WSTETH_ETH_UNIV3_01_POOL,
C.WSTETH,
C.WETH,
ONE
);
// Check if the uniswapPrice oracle fails.
if (uniswapPrice == 0) return 0;
if (LibOracleHelpers.getPercentDifference(chainlinkPrice, uniswapPrice) < MAX_DIFFERENCE) {
wstethEthPrice = chainlinkPrice.add(uniswapPrice).div(AVERAGE_DENOMINATOR);
if (wstethEthPrice > stethPerWsteth) wstethEthPrice = stethPerWsteth;
wstethEthPrice = wstethEthPrice.div(PRECISION_DENOMINATOR);
Updates

Lead Judging Commences

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

Support

FAQs

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