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

Incorrect conditional in LibUsdOracle leads mal functioning price feeds

Summary

In LibUsdOracle.sol if oracleEncoded type 0x02 is passed than there is a possibility that in the uniswap pool both base token and quote token are passed as the same token due to error in conditional

Vulnerability Details

address chainlinkToken = IUniswapV3PoolImmutables(oracleImpl.target).token0();
chainlinkToken = chainlinkToken == token
? IUniswapV3PoolImmutables(oracleImpl.target).token1()
: token; ///@audit this conditional make chainlinkToken = token
tokenPrice = LibUniswapOracle.getTwap(
lookback == 0 ? LibUniswapOracle.FIFTEEN_MINUTES : uint32(lookback),
oracleImpl.target,
chainlinkToken, ///@audit hence in turn makes quote token = base
token, ///@audit as chainlinkToken = token
uint128(10) ** uint128(IERC20Decimals(token).decimals())
);

There will be 2 scenarios in 1st the code works correctly but in second it does not work -
(1st scenario where token = token0 of uni pool , 2nd where token = token1)

In the above code snippet first chalinkToken = Token0
now if chainlinkToken(token0) == token(token0) then chainlinkToken = token1
So in the this case the code works fine but consider the below scenario

chainlinkToken = Token0
now if chainlinkToken(token0) != token(token1) then chainlinkToken = token
so now both chainlinkToken & token = token1
& which passes token1= token0 in LibUniswap which getsQuoteAtTick by passing the same token twice

function getTwap(
uint32 lookback,
address pool,
address token1,
address token2,
uint128 oneToken
) internal view returns (uint256 price) {
(bool success, int24 tick) = consult(pool, lookback);
if (!success) return 0;
price = OracleLibrary.getQuoteAtTick(tick, oneToken, token1, token2);
///@audit ^ token1 = token2
}

which leads to malfunction price feed if uniswap pool is used

Please note that this is not the same as another vuln submitted by me , as that shows how base & quote token are interchanged but this shows how baseToken = quoteToken

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

Impact

Malfunctioning price feed

Tools Used

Manual Review

Recommendations

address chainlinkToken = IUniswapV3PoolImmutables(oracleImpl.target).token0();
-- chainlinkToken = chainlinkToken == token
-- ? IUniswapV3PoolImmutables(oracleImpl.target).token1()
-- : token;
++ if(chainlinkToken == token){
++ chainlinkToken=IUniswapV3PoolImmutables(oracleImpl.target).token1()
++ }
tokenPrice = LibUniswapOracle.getTwap(
lookback == 0 ? LibUniswapOracle.FIFTEEN_MINUTES : uint32(lookback),
oracleImpl.target,
chainlinkToken,
token,
uint128(10) ** uint128(IERC20Decimals(token).decimals())
);

The second conditional used is not required and is the root cause of the problem just one conditional is needed since we are first already setting chainlinkToken = token0 , now if chainlinkToken == token the we should just change it to token1 to make sure both the base and quote token are different.Incorrect conditional in LibUsdOracle leads mal functioning price feeds

Updates

Lead Judging Commences

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

Incorrect conditional in LibUsdOracle leads mal functioning price feeds

Support

FAQs

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