Normal behavior allows stakers to deposit an allowlisted standard ERC20, then later claim principal plus any bonus after the pool resolves to SURVIVED or EXPIRED. The k=2 bonus formula is intended to compute each staker's time-weighted score and distribute the bonus without blocking principal recovery.
The stake path only proves that received * block.timestamp * block.timestamp fits at deposit time. Later, _bonusShare recomputes T * T * userEligible and T * T * snapshotTotalStaked using a larger terminal timestamp. A stake amount accepted at deposit time can therefore overflow during claim-time score calculation before Math.mulDiv is reached, reverting claims and locking staker funds in the pool.
Likelihood:
Low. The path requires an allowlisted standard ERC20 with an extremely large base-unit supply and a very large stake amount near the uint256 arithmetic boundary.
This occurs when an allowlisted standard ERC20 has a very large base-unit supply and a staker deposits an amount that fits the deposit-time timestamp square but exceeds the later terminal-time square bound.
This occurs during ordinary claimSurvived or claimExpired execution after time has advanced and the pool snapshots a terminal outcome with the huge stake still included in snapshotTotalStaked.
Impact:
Medium. The affected claims revert before payout, causing a denial of principal/bonus recovery through the normal SURVIVED or EXPIRED paths, but there is no direct theft or attacker profit.
Claims revert before state updates, so stakers cannot recover principal through the SURVIVED or EXPIRED payout paths.
One huge accepted stake can overflow the global score and block smaller victims from claiming, even when the smaller victims did not create the oversized position.
Overall severity: Low. The impact is material claim denial, but the required token supply and stake size make the likelihood low, so the likelihood-impact matrix resolves this as a low-severity finding.
Create test/poc/ValidFindingsPoC.t.sol and add the shared imports/helper contracts from the PoC file. The finding-specific test is below.
Run it with:
This PoC uses a standard mock ERC20 and an extremely large stake amount that is accepted at the deposit timestamp. After the pool observes risk and reaches expiry, a small victim's claimExpired() call reverts because _bonusShare overflows on the later terminal timestamp square. The test proves impact by checking the victim remains unclaimed, the victim has no token balance, and the pool still holds the victim's principal plus the rest of the funds.
Enforce a pool-wide stake cap that is safe for the worst-case uint32 terminal timestamp, or change the scoring implementation to use bounded elapsed-time values instead of absolute timestamp squares. The cap below prevents accepted stake from later overflowing the claim-time score terms.
Alternatively, store and score bounded elapsed-time deltas instead of absolute timestamp products, or compute the absolute timestamp score terms with 512-bit intermediate arithmetic before subtraction.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.