Bonus is meant to reward at-risk time: each deposit scores amount × (T − entryTime)², where every deposit's entryTime is floored at riskWindowStart — the moment the pool first observes the registry in an active-risk state (UNDER_ATTACK / PROMOTION_REQUESTED). Sealing this floor at the true transition means an early staker who bore risk longer earns a strictly larger bonus share than a late staker.
riskWindowStart is sealed at the block.timestamp of the first observation, not the true registry transition — and because deposits are allowed during UNDER_ATTACK, a late whale's own stake() can be that first observation. Sealing the window late retroactively floors every earlier staker's effective entry up to the whale's late timestamp (via the eager global reset in _markRiskWindowStart plus the lazy _clampUserSums), erasing the early stakers' time-weight advantage and equalizing per-token bonus weight. The whale bears zero risk during [t_transition, t_lateEntry] yet claims the same weight as stakers who bore it the whole time.
And the entry point that lets a late depositor be the first observer — UNDER_ATTACK is intentionally not blocked:
DESIGN.mdDESIGN §7 pre-rebuts manipulation of T (riskWindowEnd) as an accepted "contested public race," and §3 accepts UNDER_ATTACK deposits as "voluntary near-zero-bonus risk capital." This finding is the start-side (riskWindowStart) analogue that neither section covers, and the two assumptions the doc relies on both fail here:
"Late deposits earn ~zero bonus" (§3) is false in this scenario. §3 assumes a late depositor floors to an already-sealed early riskWindowStart, so their (T − entry)² is tiny. But when the late deposit is the first observer, it sets riskWindowStart to its own timestamp — so it floors to itself, earning full (equal) weight, not ~zero. The "self-crushing late entry" argument silently assumes the window is already open.
The "any counterparty can poke" defense (§7) is asymmetric on the start side. For T, both sides can poke the instant of transition and the bias collapses. For riskWindowStart, only the early stakers are harmed by a late seal, so only they are incentivized to poke — and they must do so at the true transition block, before the whale acts. The whale's winning move is inaction, which requires no race. §7's symmetry argument does not transfer.
So while it rhymes with documented races, A-1 sits in the gap between §3 and §7 and is not actually accepted by either.
Likelihood:
Occurs whenever the registry enters UNDER_ATTACK and no one interacts with the pool (no stake, no claim, no pokeRiskWindow) during the interval between the true transition and a later deposit — a "quiet interval" is the normal state of a pool nobody is actively watching.
The incentive is one-sided and rational: a late whale profits by deliberately withholding observation until their own stake, while early stakers must actively poke at the exact transition block to defend their share. The late party only needs one quiet interval; the early cohort must win a real-time race every time.
Impact:
Direct, zero-sum redistribution of the bonus pool from early (genuinely at-risk) stakers to the late whale. In the PoC the whale's bonus rises 5× (100e18 → 500e18) and the early staker's falls by the identical 400e18.
Breaks the protocol's core economic promise — that bonus tracks at-risk time — degrading the k=2 time-weighting to a flat amount-weighted split precisely when a late entrant games the seal. It is bonus-only (no principal at risk, no third-party loss), consistent with a Medium severity.
Two identical pools run on one monotonic timeline; the only difference is when riskWindowStart is observed. The test passes, printing the 900/100 honest split vs. the 500/500 gamed split (400e18 transferred whale-ward, zero-sum).
Place in test/unit/ConfidencePool.A1RiskWindowSeal.t.sol and run:
forge test --match-contract ConfidencePoolA1RiskWindowSealTest -vv
Result:
Remove the late-entry lever by closing deposits once the registry is attackable, so a late whale can no longer be the first observer and join at the equalized floor in the same transaction. This treats UNDER_ATTACK like PROMOTION_REQUESTED in the deposit gate:
This is a deliberate reversal of DESIGN §3, and its trade-off should be stated: it removes the (accepted) ability to add voluntary risk capital mid-attack, but that capital was exactly the vector here. If preserving UNDER_ATTACK deposits is required, the alternative is to forbid a deposit from being the sealing observation — i.e. revert a stake() that would itself open the risk window, forcing the window to be sealed by the permissionless pokeRiskWindow() / an existing interaction first, so no single actor can both seal and enter at the equalized floor atomically.
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.