51912 sc high mismatched rounding rules in reward logic library results in two fold loss of earnings
Submitted on Aug 6th 2025 at 14:55:30 UTC by @jovi for Attackathon | Plume Network
Report ID: #51912
Report Type: Smart Contract
Report severity: High
Target: https://github.com/immunefi-team/attackathon-plume-network/blob/main/plume/src/lib/PlumeRewardLogic.sol
Impacts:
Theft of unclaimed yield
Loss of unclaimed yield due to rounding errors
Description
Brief/Intro
Every time rewards are settled, the contract silently loses the remainder created by divergent rounding rules. Over weeks of operation—and especially with many delegators per validator—this gap grows into a material shortfall that makes the true APR lower than the correct value.
Description
The PlumeRewardLogic is utilized to calculate the rewards for stakers and the commission for validators. In this context, _calculateRewardsCore charges a ceiled commission value to the stakers, but validators are paid a floored commission value.
Where users are charged (round-up):
// PlumeRewardLogic.sol :: _calculateRewardsCore
commissionForThisSegment =
_ceilDiv(grossRewardForSegment * effectiveCommissionRate, REWARD_PRECISION);File link: https://github.com/immunefi-team/attackathon-plume-network/blob/main/plume/src/lib/PlumeRewardLogic.sol#L348
The ceilDiv function adds b-1 before division, so any fractional part pushes the result up by one wei.
Where validators are paid (double round-down):
// PlumeRewardLogic.sol :: updateRewardPerTokenForValidator
grossRewardForValidatorThisSegment =
(totalStaked * rewardPerTokenIncrease) / REWARD_PRECISION; // floor #1
commissionDeltaForValidator =
(grossRewardForValidatorThisSegment * commissionRateForSegment)
/ REWARD_PRECISION; // floor #2File link: https://github.com/immunefi-team/attackathon-plume-network/blob/main/plume/src/lib/PlumeRewardLogic.sol#L181C21-L187C62
Both divisions truncate toward zero, so the validator is under-credited.
The totalClaimableByToken, userRewards, and validatorAccruedCommission functions never receive the missing wei. There is also no “dust sweep” or “fee collector” variable; leading the contract’s ERC-20 balance to drift away from the sum of the bookkeeping variables.
Impact
Delegator APR erosion — each settlement skims extra wei from every delegator’s reward.
Validator revenue loss — commission actually received is systematically lower than the rate advertised on-chain.
Accounting invariants broken — the true Σ(userRewards) + Σ(validatorAccruedCommission) is less than the supposedly correct value.
Proof of Concept
For clarity purposes in this proof of concept, we'll consider 1 token = 1e18 units of a token.
Was this helpful?