pokeRiskWindow() is permissionless. If someone calls it during even a single-block UNDER_ATTACK window, it seals riskWindowStart, which is the gate that decides whether claimExpired() can auto-resolve as CORRUPTED. Without that poke, the fallback would be EXPIRED and stakers keep their principal.
The auto-CORRUPTED path in claimExpired() (line 532) checks:
So if nobody ever poked during UNDER_ATTACK, riskWindowStart stays at 0 and the pool falls through to EXPIRED - stakers get their money back. That's the safe default.
But pokeRiskWindow() can be called by anyone, and it triggers _observePoolState() which seals riskWindowStart if the registry is in an active-risk state. There's no minimum duration requirement.
Scenario:
Agreement briefly enters UNDER_ATTACK
Someone pokes immediately - riskWindowStart is now set
Agreement eventually hits CORRUPTED (out-of-scope breach)
Moderator goes dark
After expiry + 180 day grace, anyone calls claimExpired() -> auto-CORRUPTED fires
Entire pool sweeps to recoveryAddress
Without step 2, stakers would have gotten their principal back.
Require pokeRiskWindow to observe the active-risk state for at least some minimum duration (e.g. 1 hour) before sealing. Or document this edge case explicitly.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
View preliminary resultsAppeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.