DeFiHardhatOracleProxyUpdates
100,000 USDC
View results
Submission Details
Severity: low
Invalid

Lack of final validation step in beans distribution to fertilizer

Summary

The function rewardToFertilizer is responsible for distributing Beans to fertilizers. However, a critical issue has been identified where the distribution logic lacks a final validation step, potentially leading to discrepancies between the amount distributed and the amount owed.

Impact

The issue arises when the distribution loop ends prematurely due to the absence of available fertilizers. In this scenario, the final distribution of Beans to the remaining fertilizers occurs outside the loop, where there is no validation to ensure that all owed Beans are indeed distributed. This oversight poses a risk of misallocation of Beans, which could result in inconsistencies between the distributed and owed amounts.

Recommendation

To address this issue, it's recommended to implement a final validation step outside the loop to ensure that all owed Beans are distributed accurately. This can be achieved by placing a require statement after the loop to validate that the total amount distributed equals the total amount owed across all fertilizers.

For example new code will look like this:

/**
* @dev Distributes Beans to Fertilizer.
*/
function rewardToFertilizer(uint256 amount) internal returns (uint256 newFertilized) {
// 1/3 of new Beans being minted
uint256 maxNewFertilized = amount.div(FERTILIZER_DENOMINATOR);
// Get the new Beans per Fertilizer and the total new Beans per Fertilizer
uint256 newBpf = maxNewFertilized.div(s.activeFertilizer); // @audit can s.activeFertilizer be zerO?
//Store the current Beans per Fertilizer (s.bpf) in oldTotalBpf and
uint256 oldTotalBpf = s.bpf;
//calculate the new total Beans per Fertilizer by adding newBpf to oldTotalBpf, storing the result in newTotalBpf.
uint256 newTotalBpf = oldTotalBpf.add(newBpf);
// Get the end Beans per Fertilizer of the first Fertilizer to run out.
uint256 firstEndBpf = s.fFirst; //3
//Loop to Distribute Beans
//While the new total Beans per Fertilizer (newTotalBpf) is greater than or equal to the Beans per Fertilizer
//of the first Fertilizer to run out (firstEndBpf), execute the loop.
//If the next fertilizer is going to run out, then step BPF according
while (newTotalBpf >= firstEndBpf) { // 3
// Calculate BPF and new Fertilized when the next Fertilizer ID ends
newBpf = firstEndBpf.sub(oldTotalBpf);
newFertilized = newFertilized.add(newBpf.mul(s.activeFertilizer));
// If there is no more fertilizer, end
if (!LibFertilizer.pop()) {
s.bpf = uint128(firstEndBpf); // SafeCast unnecessary here.
s.fertilizedIndex = s.fertilizedIndex.add(newFertilized);
require(s.fertilizedIndex == s.unfertilizedIndex, "Paid != owed");
return newFertilized;
}
// Calculate new Beans per Fertilizer values
newBpf = maxNewFertilized.sub(newFertilized).div(s.activeFertilizer);
oldTotalBpf = firstEndBpf;
newTotalBpf = oldTotalBpf.add(newBpf); //4
firstEndBpf = s.fFirst; // 3
}
// Distribute the rest of the Fertilized Beans
s.bpf = uint128(newTotalBpf); // SafeCast unnecessary here.
newFertilized = newFertilized.add(newBpf.mul(s.activeFertilizer));
s.fertilizedIndex = s.fertilizedIndex.add(newFertilized);
+ // Recommended final validation step
+ require(s.fertilizedIndex == s.unfertilizedIndex, "Paid != owed");
}
Updates

Lead Judging Commences

giovannidisiena Lead Judge about 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.