DeFiHardhat
35,000 USDC
View results
Submission Details
Severity: low
Invalid

[H] Malicious users can manipulate the price of barnRaiseToken by fronrunning the oracle and minting unfair amounts of Fertilizer.

Summary

Users can gain an unfair advantage over other users by manipulating the price of barnRaiseToken, which is used to mint Fertilizer. This manipulation can be achieved by frontrunning the oracle, inflating the price of barnRaiseToken, and minting Fertilizer at an advantageous rate over other users.

Vulnerability Details

With the implementation of Uniswap's V3 Pool version, the wstETH:ETH feed is used to determine the amount of Fertilizer
that can be minted.

The price oracle used (LibUniswapOracle) fetches the TWAP (Time Weighted Average Price) from a Uniswap V3 pool.
This oracle uses a modified version of the consult function, which rounds down the arithmeticMeanTick.

The issue here is, that the price of barnRaiseToken is determined by the oracle.

function _getMintFertilizerOut(uint256 tokenAmountIn, address barnRaiseToken)
public view returns (uint256 fertilizerAmountOut) {
fertilizerAmountOut = tokenAmountIn.div(LibUsdOracle.getUsdPrice(barnRaiseToken));//@audit ORACLE CALL
}

A malicious user can frontrun the oracle, using a flash loan to drive up the price of barnRaiseToken, i.e wstETH. Now that there is a higher price, when the arithmeticMeanTick is rounded down....................

function consult(address pool, uint32 secondsAgo) internal view returns
(bool success, int24 arithmeticMeanTick)
{
require(secondsAgo != 0, 'BP');
uint32[] memory secondsAgos = new uint32[](2);
secondsAgos[0] = secondsAgo;
secondsAgos[1] = 0;
try IUniswapV3Pool(pool).observe(secondsAgos) returns (//@audit
int56[] memory tickCumulatives,
uint160[] memory
) {
int56 tickCumulativesDelta = tickCumulatives[1] - tickCumulatives[0];
arithmeticMeanTick = int24(tickCumulativesDelta / secondsAgo);
// Always round to negative infinity
if (tickCumulativesDelta < 0 && (tickCumulativesDelta % secondsAgo != 0)) arithmeticMeanTick--;
success = true;
} catch {}
}

The difference between the minLPAmountOut specified by the malicious user and the actual amount of Fertilizer minted will be significant, leading to an unfair advantage over other users.

Because when the flash loan is repaid, the feed price of barnRaiseToken will return to a lower price.

(Whenever you use a getPrice in an oracle to fetch the latest price feed, this is susceptible to flash loans).

Any users who call mintFertilizer after this, may experience receiving a lower amount of Fertilizer or a revert
in the Well due to the rounding down of the arithmeticMeanTick and the minLPAmountOut specified.

Because the Oracle rounds down to the nearest tick (not the nearest decimal price), the difference can be quite dramatic

lpAmountOut = _calcLpTokenSupply(wellFunction(), reserves) - totalSupply();
if (lpAmountOut < minLpAmountOut) {
revert SlippageOut(lpAmountOut, minLpAmountOut);
}

Impact

Users can mint Fertilizer at an advantageous rate over other users by manipulating the price of barnRaiseToken,
breaking the fairness of Beantalk's mechanism for minting Fertilizer.

Tools Used

Manual Review/Foundry

Recommendations

Beanstalk could simply implement their own version of the consult, which involves not rounding down the arithmeticMeanTick. Another option could be strictly for the Twap method, to use a longer look back period to reduce the impact of frontrunning.

Updates

Lead Judging Commences

giovannidisiena Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Design choice
Assigned finding tags:

Informational/Invalid

Support

FAQs

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