The riskWindowStart is updated lazily in the _observePoolState() function. When a protocol goes UNDER_ATTACK in the AttackRegistry it is not guaranteed that this function gets called. If the protocol survives the attack and goes into PRODUCTION then the riskWindowEnd is set but the riskWindowStart remains 0. This will result in _bonusShare(...) returning 0, so no bonus is claimed by honest stakers.
Describe the normal behavior in one or more sentences
When a protocol goes UNDER_ATTACK and it survives, stakers should be able to call claimSurvived() and claim their capital + the bonus rewards.
Explain the specific issue or problem in one or more sentences
However, this invariant is breached if the riskWindowStart is never updated. A protocol going UNDER_ATTACK doesn't guarantee that riskWindowStart is set. When users try to call claimSurvived(), which calls _bonusShare(...) to calculate each user's bonus share it will result in 0 bonus amount for everyone:
This makes the expected flow of NOT_DEPLOYED -> ATTACK_REQUESTED -> UNDER_ATTACK -> PRODUCTION not reward stakers, while this is the whole point of staking.
Likelihood:
_observePoolState() is not called in the time window between UNDER_ATTACK and PRODUCTION.
Impact:
Honest stakers don't receive their bonus rewards.
Paste the following test in the test/unit/ConfidencePool.t.sol file and run through forge test --mt test_bonusForfeited_whenRiskWindowUnobserved
Consider implementing a Keeper bot that scans for Attack registry changes and calls pokeRiskWindow() in every change.
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.