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

`calcDeltaPodDemand()` will revert if `s.w.thisSowTime` is close to the maximum value

Summary

calcDeltaPodDemand() in LibEvaluate.sol will revert if s.w.thisSowTime is close to the maximum value. This is because in this statementL:

else if (s.w.thisSowTime <= s.w.lastSowTime.add(SOW_TIME_STEADY)) {

If s.w.lastSowTime is very close to uint32 max value, then we try to add SOW_TIME_STEADY and the function will revert.

Vulnerability Details

In LibEvaluate.sol we have calcDeltaPodDemand() function:

function calcDeltaPodDemand(
uint256 dsoil
)
internal
view
returns (Decimal.D256 memory deltaPodDemand, uint32 lastSowTime, uint32 thisSowTime)
{
AppStorage storage s = LibAppStorage.diamondStorage();
// `s.w.thisSowTime` is set to the number of seconds in it took for
// Soil to sell out during the current Season. If Soil didn't sell out,
// it remains `type(uint32).max`.
if (s.w.thisSowTime < type(uint32).max) {
if (
s.w.lastSowTime == type(uint32).max || // Didn't Sow all last Season
s.w.thisSowTime < SOW_TIME_DEMAND_INCR || // Sow'd all instantly this Season
(s.w.lastSowTime > SOW_TIME_STEADY &&
s.w.thisSowTime < s.w.lastSowTime.sub(SOW_TIME_STEADY)) // Sow'd all faster
) {
deltaPodDemand = Decimal.from(1e18);
} else if (s.w.thisSowTime <= s.w.lastSowTime.add(SOW_TIME_STEADY)) {
// Sow'd all in same time
deltaPodDemand = Decimal.one();
} else {
deltaPodDemand = Decimal.zero();
}
} else {
// Soil didn't sell out
uint256 lastDSoil = s.w.lastDSoil;
if (dsoil == 0) {
deltaPodDemand = Decimal.zero(); // If no one Sow'd
} else if (lastDSoil == 0) {
deltaPodDemand = Decimal.from(1e18); // If no one Sow'd last Season
} else {
deltaPodDemand = Decimal.ratio(dsoil, lastDSoil);
}
}
lastSowTime = s.w.thisSowTime; // Overwrite last Season
thisSowTime = type(uint32).max; // Reset for next Season
}

This function calculates the change in demand for soil using a combination of previous and current season data.

We should pay attention to the following part of the function:

if (s.w.thisSowTime < type(uint32).max) {
if (
s.w.lastSowTime == type(uint32).max || // Didn't Sow all last Season
s.w.thisSowTime < SOW_TIME_DEMAND_INCR || // Sow'd all instantly this Season
(s.w.lastSowTime > SOW_TIME_STEADY &&
s.w.thisSowTime < s.w.lastSowTime.sub(SOW_TIME_STEADY)) // Sow'd all faster
) {
deltaPodDemand = Decimal.from(1e18);
} else if (s.w.thisSowTime <= s.w.lastSowTime.add(SOW_TIME_STEADY)) {
// Sow'd all in same time
deltaPodDemand = Decimal.one();
} else {
deltaPodDemand = Decimal.zero();
}

The logic within this segment of the calcDeltaPodDemand assesses changes in the demand for soil based on how quickly it sold out.

  • thisSowTime: Time it took for all soil to sell out this season.

  • lastSowTime: Time it took for all soil to sell out last season.

The problem is in following part:

181: } else if (s.w.thisSowTime <= s.w.lastSowTime.add(SOW_TIME_STEADY)) {

If s.w.lastSowTime is very close to uint32 max value, then we try to add SOW_TIME_STEADY and the function will revert.

Impact

In the case where s.w.lastSowTime is close to the maximum value, the calcDeltaPodDemand() function will not work.
This means that the gm() function in SeasonFacet.sol will also revert because this is the flow: gm() -> calcCaseIdandUpdate() -> evaluateBeanstalk() -> getBeanstalkState() -> calcDeltaPodDemand().

Tools Used

Visual Studio Code

Recommendations

Add a special case where lastSowTime can be close to uint32.max.

Updates

Lead Judging Commences

giovannidisiena Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Informational/Invalid

Support

FAQs

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