docs/DESIGN.md §9 states the staker's bargain as a biconditional, then denies the failure outright: "a staker only forfeits the exit option once risk has actually materialized, which is exactly when they begin earning the risk premium." ... "A sponsor cannot grief stakers by keeping the agreement out of attackable mode, stakers can freely exit until risk materializes"
The code does not implement that biconditional: the exit gate reads live registry state, while the pool's record of risk is the one-way latch
The two sets are not complements. PRODUCTION sits in the gap: outside the withdraw allowlist (exit closed) yet outside _isActiveRiskState, so riskWindowStart stays 0 forever and _bonusShare returns 0 (:699). pokeRiskWindow cannot help - there is no active-risk transition to observe, and the state is irreversible (AttackRegistry.sol:744)
Two free upstream paths reach PRODUCTION with no active-risk state:
AttackRegistry.goToProduction:282 - "Skip attack mode and go directly to production... No fee or bond is collected." Callable by the agreement owner, whom createPool:82,99 forces to be the pool's owner, where the scope contracts are BattleChainDeployer-verified (s_authorizedOwner:289). It needs the agreement unregistered, i.e. the NOT_DEPLOYED state a pool may be created against, since isAgreementValid only checks it was factory-created. This is the scenario §9 denies: it is keeping the agreement out of attackable mode
No actor at all. Registering for the attack phase - requestUnderAttack:230 for BattleChainDeployer-verified contracts, or requestUnderAttackForUnverifiedContracts:254 otherwise - sets deadlineTimestamp = now + 14 days via _registerAgreement:794. This is the sponsor's normal, honest flow. If the DAO then never calls approveAttack, _getAgreementState:871-873 returns PRODUCTION - checked after attackApproved:867, so the latch never seals. The state flips with no transaction and no event
Not claimed: the zero bonus is correct (no risk was borne, §5's rule applies) and the sponsor reclaiming their unearned bonus is intended. The defect is solely the closed exit - a pairing §9 and §5 each describe separately but never together
Severity: Medium - Medium Impact x High Likelihood
Likelihood: High. Path 2 requires nobody to act: any agreement whose attack request the DAO does not approve within 14 days auto-promotes, trapping every staker. No attacker, no cost, no transaction. Path 1 is one free sponsor call available at any moment after stakers deposit, including the same block, so stakers cannot react
Impact: Medium. Capital is frozen with no exit from the moment PRODUCTION is observed until the moderator flags SURVIVED, or until expiry if the moderator is idle. Principal is fully recoverable at resolution, which bounds this below a loss. The duration sits inside the pool term (expiry is settable up to type(uint32).max before the first stake) and stakers earn zero throughout, because the pool records no risk. The harm is a forced zero-yield loan: the staker gave up the exit and got nothing in return, which is the exact inverse of the §9 bargain
Self-contained against the existing BaseConfidencePoolTest harness, no RPC needed. PASSES:
Path 2's reachability is verifiable from the registry code cited above. A fork run against the live BattleChain testnet (chainId 627) confirms it end-to-end: minting a real agreement via the live AgreementFactory, registering it via requestUnderAttackForUnverifiedContracts, then reaching PRODUCTION with no further action from anyone, purely because the DAO never approves
Gate withdraw on the pool's own risk record - the invariant §9 already states. The live-state clause is redundant, because _observePoolState() on line 290 seals the latch before the check. Retaining CORRUPTED preserves §5's principal-settlement gating.
§9's closing paragraph also needs correcting: goToProduction exists precisely to let a sponsor skip attackable mode
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.