When user calls gm
and the call for the chainlink oracle fails, it will return 0 for the deltaB
value and this will cause a cascade effect, making the calculation of caseId
= 3
and using the incorrect caseId
to set up the new temperature on Weather.sol
Every consumer of the temperature on the protocol will be affected like:
LibDibbler.morningTemperature
LibDibbler.beansToPods
LibDibbler.remainingPods
Sun.setSoilAbovePeg
Sun.stepSun
FieldFacet.maxTemperature
FieldFacet.totalSoil
FieldFacet._totalSoilAndTemperature
`FieldFacet.sowWithMin
gm
function uses the incorrect deltaB
(0) to calculate the caseId
which is then used to set the temperature.
The interest rate will be wrongly decreased to 1, compromising the protocol peg mechanism when it needs to be maintained with a high interest rate/ temperature.
Sow will be calculated with the lowest temperature, also compromising the peg mechanism due to the wrong exchange of Beans -> Sow -> Pods
Remaining pods function will return zero and users will have an inaccurate number representing their actual pods.
Prepare the environment to work with Foundry + Updated Mocks
https://gist.github.com/h0lydev/fcdb00c797adfdf8e4816031e095fd6c
Make sure to have the mainnet forked through Anvil: anvil --fork-url https://rpc.ankr.com/eth
Create the SeasonTemperature.t.sol
file under the folder foundry
and paste the code below. Then run forge test --match-contract SeasonTemperatureTest -vv
.
Output:
ps: a console.log was added to the handleRain
function to print the caseId.
Result: In a normal scenario the temperature would have remained at the value 5
but in this case was set to 1
and remaining pods/soil are also set to zero when in fact they should not.
Manual Review & Foundry
It is noticed that the developers have the intention of never reverting the sunrise function to decrease the risk of depeg and breaking the incentive for users calling it. But at the same time, those state variables shouldn't be updated as if the system is working correctly because they will impact the next season as stated in this finding.
It is tricky to propose a simple fix to the problem without impacting the system as a whole. Here are a few ideas that could be used:
(Recommended) An effective solution could be store the latest response from chainlink and in case it fails and the timeout(a limit that you can be added to accept a previous response from the oracle) is not reached yet, protocol could use the previous response. Liquity Protocol uses this approach, an example here: https://github.com/liquity/dev/blob/main/packages/contracts/contracts/PriceFeed.sol
This solution will be effective for the protocol because the oracle is also called in different places like when minting fertilizers(getMintFertilizerOut
), getting the well price(getRatiosAndBeanIndex
), and getConstantProductWell
. As the oracle is used along the protocol in many places, the latest successful price
would be often up-to-date and within the limit time defined to use the previous price when the chainlink oracle fails.
Additionally, consider handling the errors properly before updating the deltaB
and abovePeg
variables, as these disrupt the peg mechanism logic.
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.