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

Beanstalk peg is compromised due to incorrect price when using Uniswap Oracle

Summary

The LibUsdOracleis used inside LibWell.getRationsAndBeanIndexwhich is the principal function to get the price of non-bean assets for the protocol. Beanstalk relies heavily on this function to keep its peg mechanism. i.e.: convert, sunrise, caseId & temperature, pods/soil, everything is affected by the price of non-bean assets.

The problem here is that the Convert/LibDeltaB use LibWell.getRatiosAndBeanIndex(tokens) with a 0 lookback.

when using the Uniswap Oracle(encodeType == 0x02) for a token and the LibWell.getRationsAndBeanIndex calls LibUsdOracle.getUsdPrice it will a lookback 0. The following will happen:

the function getTokenPriceFromExternal will add a lookback of 15 minutes for the Uniswap Price:

tokenPrice = LibUniswapOracle.getTwap(
@> lookback == 0 ? LibUniswapOracle.FIFTEEN_MINUTES : uint32(lookback),
oracleImpl.target,
chainlinkToken,
token,
uint128(10) ** uint128(IERC20Decimals(token).decimals())
);

Now: uniswap price * chainlink price / 6.

uint256 chainlinkTokenPrice = LibChainlinkOracle.getTokenPrice(
chainlinkOraclePriceAddress,
@> LibChainlinkOracle.FOUR_HOUR_TIMEOUT,
@> lookback
);
@> return tokenPrice.mul(chainlinkTokenPrice).div(1e6);

Notice that here we have the following scenario:

  • Uniswap will return the TWAP price of 15min

  • Chainlink can return the current price** OR** the price from 4/3/2/hours ago

This will lead Beanstalk to consume the incorrect price. i.e:

tokenPrice = WBTC = 50k USD

chainlinkTokenPrice = FRAX 0.95USD

But chainlinkTokenPrice 4 hours ago was 0.99USD

As shown above, using different limits for fetching assets' prices will** very often **lead the protocol to consume the incorrect price, because they are being fetched in different moments.

Impact

  • When using Convert:

    1. users can exploit this to buy assets for a cheaper price or sell assets for a higher price.

    2. Users can unfairly pay penalty fees due to the miscalculation of the deltaB

    3. Users can skip penalty fees due to the miscalculation of the deltaB

  • When sunrise is called

    1. It can miscalculate the deltaB and put the protocol in a situation that doesn't reflect the current state. I.e set abovePeg when in fact is under the peg.

    2. Miscalculate the caseId, hence several components like temperature, pod rate, soil issuance, etc.

    3. Minting more beans than it should.

    4. Issuing more debt than it should

Tools Used

Manual Review

Recommendations

In a previous report, I recommended adding an oracleTimeout parameter for each oracle instead of using hardcoded values. Considering this recommendation implemented, we can now implement the 2nd part:

Set a threshold to compare the time from Chainlink/Uniswap. If the time is within the limit, the price can be used otherwise return 0.

Updates

Lead Judging Commences

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

Appeal created

golanger85 Auditor
11 months ago
holydevoti0n Submitter
11 months ago
inallhonesty Lead Judge
11 months ago
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.