FoundrySolidityLayer 2
7.25 ETH
Submission Details
Impact: medium
Likelihood: high

Permanent locking of bonus funds due to unrecoverable dust in _bonusShare

Author Revealed upon completion

Description


Normal Behavior:

The protocol is designed to distribute bonus rewards to stakers based on a time-weighted formula using Math.mulDiv.

Issue:

The _bonusShare function uses Math.mulDiv with integer division which rounds down. While this is intentional for the weighting, the contract lacks a mechanism to sweep or recover the residual "dust" that remains unclaimed due to precision loss. Consequently, this dust accumulates indefinitely in the contract.

Root cause:

The implementation of _bonusShare inside ConfidencePool.sol:ntences

@> return Math.mulDiv(userEligible, snapshotTotalBonus, snapshotTotalStaked);
@> return Math.mulDiv(userScore, snapshotTotalBonus, globalScore);

Risk

Likelihood:

  • This occurs whenever the calculated bonus share results in a remainder due to the rounding-down nature of integer division.

  • It will happen in every pool where the provided bonus does not perfectly divide among stakers.

Impact:

  • Permanent locking of bonus funds that stakers are technically entitled to.

  • Accumulation of "dust" leads to protocol inefficiency and locked capital that cannot be recovered by any user or sponsor.

Proof of Concept

function test_BonusDustAccumulation() public {
uint256 tinyStake = 1;
uint256 totalBonus = 100;
uint256 totalStake = 10001;
uint256 reward = Math.mulDiv(tinyStake, totalBonus, totalStake);
// Result is 0, yet the stake was legitimate.
// This lost reward remains stuck in the contract forever.
assertEq(reward, 0);
}

Recommended Mitigation

- return Math.mulDiv(userEligible, snapshotTotalBonus, snapshotTotalStaked);
+ // Option: Allow the final staker or owner to sweep remaining dust.
+ // Or implement rounding up (Rounding.Ceil) to ensure no dust remains.

Support

FAQs

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

Give us feedback!