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.
Appeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.