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

Precision loss in downcasting `fertilizerAmount` from uint256 to uint128

Summary

The addFertilizer function in the LibFertilizer library is responsible for processing the addition of fertilizer to the system. It begins by validating input parameters such as the season, token amount, fertilizer amount, and minimum LP. After converting the fertilizerAmount parameter to a uint128, the function calculates the Beans Per Fertilizer (BPF) based on the current season and humidity levels.

Subsequently, it updates various state variables in the contract to reflect the addition of fertilizer, including the total unfertilized index and active fertilizer amount. Additionally, it calculates and adds the corresponding underlying beans and LP tokens. If it's the first time adding fertilizer with a specific ID, the function logs the end BPF and adds it to the season queue. Finally, an event is emitted to notify external listeners about the fertilizer addition.

Vulnerability Details

Here, fertilizerAmount is a uint256, but it is being downcasted to a uint128. If fertilizerAmount exceeds the maximum value that can be represented by a uint128, downcasting will truncate the value, potentially causing an overflow or loss of precision.

For example, if fertilizerAmount is greater than 2^128 - 1, the downcast operation will result in an inaccurate representation of fertilizerAmount128, leading to unexpected behavior or vulnerabilities.

See the following code:

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);
// If not first time adding Fertilizer with this id, return
if (s.fertilizer[id] > fertilizerAmount128) return id;
// If first time, log end Beans Per Fertilizer and add to Season queue.
push(id);
emit SetFertilizer(id, bpf);
}

Impact

The impact of this issue can be severe. In the worst-case scenario, an attacker could exploit the downcasting vulnerability to manipulate the fertilizerAmount, causing unintended changes in the contract state, loss of funds, or disruption of the application logic.

Tools Used

Manual Review

Recommendations

To mitigate this issue, it's essential to handle the downcasting operation safely by performing appropriate range checks and ensuring that the converted value fits within the target data type.

Updates

Lead Judging Commences

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

Informational/Invalid

Support

FAQs

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