When the registry reaches terminal CORRUPTED but the active-risk interval was never observed on-chain (riskWindowStart == 0), claimExpired skips the moderator grace window entirely and resolves EXPIRED, refunding stakers and latching claimsStarted. The sealed-window path (riskWindowStart != 0) instead defers to the moderator through expiry + MODERATOR_CORRUPTED_GRACE. The moderator's protection is therefore present exactly when the window was observed and absent exactly when it was not.
Likelihood:
Occurs whenever the agreement transitions through an active-risk state (UNDER_ATTACK / PROMOTION_REQUESTED) into terminal CORRUPTED while no stake, withdraw, contributeBonus, or pokeRiskWindow call lands during that interval — leaving riskWindowStart == 0. Low-activity pools and fast breaches (short active-risk window before corruption) satisfy this by default.
Occurs on the very first post-expiry interaction: claimExpired is permissionless, so any staker calls it the moment block.timestamp >= expiry, ahead of a moderator who is waiting out the (nonexistent, in this case) grace window.
Requires no privileges, no capital beyond an ordinary stake, and no timing precision — the graceless branch is the default resolution for an unobserved-window CORRUPTED registry.
Impact:
The whitehat / recoveryAddress beneficiary receives nothing on a genuine in-scope breach: the full pool that CORRUPTED would have routed to them is instead refunded to the stakers whose contracts were breached.
The moderator's correct CORRUPTED resolution is permanently foreclosed — claimExpired latches claimsStarted, so a subsequent flagOutcome(CORRUPTED, …) reverts OutcomeAlreadySet, even while still inside what should have been the grace window.
Identical breach and timing to the protected (sealed-window) path; the only difference is that no interaction sealed riskWindowStart.
The sealed-window control (test_L01_SealedWindow_ModeratorProtected) runs the same breach but seals the window with one pokeRiskWindow() call; there claimExpired() reverts AgreementCorruptedAwaitingModerator and the moderator resolves CORRUPTED with funds routing to recovery. The two tests diverge on exactly one sealed bit.
Defer to the moderator during grace in the unobserved-window case too, without auto-finalizing CORRUPTED . After grace elapses, the riskWindowStart == 0 path still falls through to the staker-favorable EXPIRED, preserving the documented default.
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.