53072 sc high ceil vs floor rounding mismatch causes systematic underpayment and unclaimed yield leakage

Submitted on Aug 14th 2025 at 18:52:35 UTC by @r1ver for Attackathon | Plume Network

  • Report ID: #53072

  • 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

Description

Brief / Intro

In plume/src/lib/PlumeRewardLogic.sol, per-user commission uses ceiling division while validator commission accrues with floor division, so user deductions can exceed validator accrual; the excess isn’t credited to anyone, causing systematic underpayment and unclaimed-yield leakage.

Vulnerability Details

In plume/src/lib/PlumeRewardLogic.sol, updateRewardPerTokenForValidator calculates validator commission accrual using floor division:

PlumeRewardLogic.sol (validator floor example)
// Use regular division (floor) for validator's accrued commission
uint256 commissionDeltaForValidator = (
    grossRewardForValidatorThisSegment * commissionRateForSegment
) / PlumeStakingStorage.REWARD_PRECISION;

But per-user commission deduction in _calculateRewardsCore uses ceiling division:

Because Solidity lacks decimals and any non-integer division rounds, applying ceil per user per time-segment makes the sum of user-side commissions often exceed the validator’s floor-accrued commission. The difference is neither credited to validators nor returned to users, creating unclaimed-yield leakage and systematic underpayment that grows with more users, more segments, and more rate changes.

Impact Details

Users are systematically underpaid because per-user ceil commission can exceed validator floor-accrued commission, and the excess is not credited to anyone, causing accumulating unclaimed-yield leakage and breaking the accounting invariant (user_net + validator_commission < gross), which undermines auditability.

Proof of Concept

A test demonstrating the mismatch:

Run it with: forge test RoundingMismatchPOC -vvv

References

  • https://github.com/immunefi-team/attackathon-plume-network/blob/main/plume/src/lib/PlumeRewardLogic.sol#L184-L187

  • https://github.com/immunefi-team/attackathon-plume-network/blob/main/plume/src/lib/PlumeRewardLogic.sol#L346-L355

Notes / Remediation Suggestions (observational)

  • Ensure the same rounding convention is used for both the per-user deduction and the validator accrual (preferably use floor consistently or accumulate the rounding remainders and attribute them deterministically).

  • Alternatively, compute commission at the validator-level from the summed gross amounts before applying rounding, or aggregate per-segment remainder adjustments into a dedicated accounting bucket that is credited to validators or distributed back to users to preserve the invariant.

Was this helpful?