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

No deadline check in mintfertilizer could result in wrong bpf

Summary

No deadline check in mintfertilizer could result in wrong bpf

Vulnerability Details

The function mint fertilizer allows a user to mint fertilizer in exchange for barnraisetokens shown here.

function mintFertilizer(
uint256 tokenAmountIn,
uint256 minFertilizerOut,
uint256 minLPTokensOut
) external payable returns (uint256 fertilizerAmountOut) {
fertilizerAmountOut = _getMintFertilizerOut(tokenAmountIn, LibBarnRaise.getBarnRaiseToken());

The nested function addfertilizer, checks the season (beanstalk's internal timekeeping) and determines the bpf (beans per fertilizer) based on it, which can be thought of as the interest rate given to the user for minting fertilizer.

function addFertilizer(
uint128 season,
uint256 tokenAmountIn,
uint256 fertilizerAmount,
uint256 minLP
) internal returns (uint128 id) {
AppStorage storage s = LibAppStorage.diamondStorage();
uint128 fertilizerAmount128 = fertilizerAmount.toUint128();
// Calculate Beans Per Fertilizer and add to total owed
uint128 bpf = getBpf(season);
s.unfertilizedIndex = s.unfertilizedIndex.add(
fertilizerAmount.mul(bpf)
);
// Get id
id = s.bpf.add(bpf);
// Update Total and Season supply
s.fertilizer[id] = s.fertilizer[id].add(fertilizerAmount128);
s.activeFertilizer = s.activeFertilizer.add(fertilizerAmount);
// Add underlying to Unripe Beans and Unripe LP
addUnderlying(tokenAmountIn, fertilizerAmount.mul(DECIMALS), minLP);//@audit
// If not first time adding Fertilizer with this id, return
if (s.fertilizer[id] > fertilizerAmount128) return id;//can this go down?
// If first time, log end Beans Per Fertilizer and add to Season queue.
push(id);
emit SetFertilizer(id, bpf);
}
function getBpf(uint128 id) internal pure returns (uint128 bpf) {
bpf = getHumidity(id).add(1000).mul(PADDING);
}
function getHumidity(uint128 id) internal pure returns (uint128 humidity) {
if (id == 0) return 5000;
if (id >= END_DECREASE_SEASON) return 200;
uint128 humidityDecrease = id.sub(REPLANT_SEASON).mul(5);
humidity = RESTART_HUMIDITY.sub(humidityDecrease);
}

The problem here is that there is no deadline check for the the function mintfertilizer. This can be a problem in certain situations. For example let's say that a user calls the function mintfertilizer, and at the same time, the seasons is about to change (every 1 hour). In that time the user that called the mintfertilizer is expecting a certain bpf, but due to the lack of a deadline, there is no assurance about when the transaction will be executed as it can stay in the mempool for a significant amount of time due to not submitting enough gas or a malicious validator holding the user's transaction. This can cause the mintfertilizer function to execute later than expected, changing the expected bpf to a lower one.

Impact

There are multiple impacts that can come from this issue. One is that transactions can be executed at unexpected times, resulting in reverts. Secondly, if this transaction is done in between seasons, then a user can end up with a different bpf than what was expected, resulting in a potential loss of yield

Tools Used

Manual Review

Recommendations

Add a deadline for users in the mintfertilizer function to protect from a loss of yield.

Updates

Lead Judging Commences

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

Fertilizer deadline

Support

FAQs

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