The distributeYieldWithLimit() function contains a flaw where integer division remainders from each batch are permanently lost and locked in the contract, while the regular distributeYield() function correctly handles these remainders. This creates an accumulating fund loss mechanism that can result in significant monetary losses over time, with no recovery method available.
Vulnerability Details
The issue stems from different remainder handling between two yield distribution functions:
distributeYield() (Works Correctly):
// Processes all holders except lastfor(uint256 i =0; i < lastProcessedIndex; i++){uint256 share =(amount * holderBalance)/ effectiveTotalSupply;// ... distribute share distributedSum += share;}// CRITICAL: Last holder gets ALL remainderuint256 lastShare = amount - distributedSum;// ← Captures remainderyToken.safeTransfer(lastHolder, lastShare);
distributeYieldWithLimit() (Loses Remainder):
Impact Details
Each batched distribution loses integer division remainders from every user calculation, with no recovery mechanism available. Even though there is no significant loss for a particular user, these per-user remainders accumulate into non-trivial amounts with each distribution, creating systematic fund loss that compounds over the contract's operational lifetime.
Permanent freezing of funds: the remainders accumulated per batch are not returned to recipients nor tracked for later distribution, so funds become permanently locked in the contract balance.
Proof of Concept
Add to ArcToken.t.sol:
References
Mentioned above
If you want, I can:
Suggest concrete fixes (e.g., accumulate distributed sum per batch and forward remainder to a designated recipient or track leftover for later distribution), or
Produce a small patch diff for ArcToken.sol implementing correct remainder handling in distributeYieldWithLimit().