The k=2 bonus formula expands scores with absolute Unix timestamps, so a sufficiently large but valid ERC20 stake can overflow T * T * stake during _bonusShare. Once a SURVIVED or EXPIRED pool with a bonus is resolved in this state, staker claims revert and principal plus bonus remain stuck.
stake accepts any received ERC20 amount above minStake and adds it to totalEligibleStake without an upper bound. When the risk window opens, the pool first rewrites the global weighted sums by multiplying the total stake by the absolute timestamp at src/ConfidencePool.sol:814. At resolution, it snapshots those values and later computes the global bonus denominator by multiplying the absolute timestamp T twice by snapshotTotalStaked. These operations can overflow even when the actual elapsed-time score (T - entryTime)^2 * stake would fit, because the implementation expands the quadratic around Unix timestamps instead of first working in bounded deltas.
The same pattern is used for each claimant's numerator at src/ConfidencePool.sol:704, while claimSurvived and claimExpired both call _bonusShare before transferring principal. With current Unix timestamps around 1.75e9, any snapshot stake above roughly type(uint256).max / T^2 can trigger the claim-time overflow. A still larger stake can also make _markRiskWindowStart revert, preventing the pool from recording an observed risk window and causing the bonus to be treated as unearned. These thresholds are enormous, but they are valid ERC20 base-unit amounts and are not rejected by the pool.
This is an edge-case liveness and accounting bug requiring an unusually large standard ERC20 balance and a nonzero bonus pool. The impact is concrete, however: a malicious or accidental oversized stake can permanently prevent SURVIVED/EXPIRED stakers from claiming both principal and bonus.
If a large staker enters before the risk window and the pool later resolves SURVIVED or EXPIRED with any bonus, every claim that reaches _bonusShare can revert on arithmetic overflow. Honest stakers cannot withdraw after resolution, cannot claim principal through claimSurvived or claimExpired, and sweepUnclaimedBonus does not repair the broken claim path.
The following Foundry test was run against the repository using the Safe Harbor interfaces exported to /tmp/bcsh-audit:
PoC test:
The test passed: staking and resolution succeeded, but Alice's claim reverted when _bonusShare evaluated the overflow-prone expanded denominator.
Avoid expanding the score around absolute timestamps. Store or snapshot stake-weighted deltas from riskWindowStart, or compute scores from bounded differences such as (T - effectiveEntry) so the multiplication uses elapsed risk-window duration rather than Unix time. Also consider enforcing a maximum stake/snapshot bound that guarantees all score calculations fit for the configured expiry horizon.
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.