The function getUsdPrice
from LibUsdOracle
should return the token value in USD. For example, one of its consumers is the function getMintFertilizerOut
:
fertilizerAmountOut = tokenAmountIn.div(LibUsdOracle.getUsdPrice(barnRaiseToken));
The goal of this function is to return the fertilizer amount with 0 decimals, therefore if the WETH value is at $1000 and the user would provide 1 WETH:
tokenAmountIn = 1e18.div(1e15) = 1e3 = 1000
Another critical use case for getUsdPrice
is: fetching the ratios to calculate the deltaB.
The function getRatiosAndBeanIndex
is used throughout the system, including in processes like Sunrise
and Convert
, to help Bean maintain its peg.
The first issue is that the price returned by getUsdPrice
will be incorrect for tokens that use "external oracle" due to the duplicated division using 1e24
.
This will result in an inaccurate price. For example, when the price of WBTC is $50,000, it will return 50000e6
instead of the correct value 2e13
. This discrepancy will cause Beanstalk to consider an erroneous ratio, resulting in an incorrect DeltaB.
Beanstalk uses deltaB to determine:
Whether the system is Above or below the peg
Sow and Pods(issuing debt)
Flood
Convert
In a nutshell, all components from Beanstalk will be affected by DeltaBs originating from tokens using Oracle with encodedType 0x01
.
The second issue is that the getTokenPriceFromExternal
doesn't check for the return from the Oracle value before div:
When the Chainlink Oracle fails to fetch the price it returns 0. Hence, the function will revert due to uint256(1e24).div(0)
.
For the incorrect price:
Add the following test on oracle.t.sol
Run: forge test --match-test test_getUsdPrice_whenExternalToken_priceIsInvalid
Output:
For the DoS when Chainlink oracle returns 0:
Add this test on oracle.t.sol
Run: forge test --match-test test_getUsdPrice_willDoS_whenOracleFail
Output:
High.
Incorrect price: This will compromise the entire system, as all peg-related components, including Sunrise and Convert, depend on the price.
DoS: Sunrise will revert and disrupt all other components that rely on the price. The risk of a DoS is increased due to stepOracle
calling multiple tokens(instead of one as previously) to fetch their prices, raising the chances of an Oracle failure.
Manual Review & Foundry
To fix both issues: On getTokenPriceFromExternal
return the price from Chainlink directly, instead of scaling it.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.