A ConfidencePool is only meant to exist during the agreement's commitment phase (NOT_DEPLOYED / NEW_DEPLOYMENT) — the exact pair the pool treats as "scope still open." Scope is chosen up front and locks one-way the moment _observePoolState first sees any other state, on the assumption that scope is committed before anyone knows how risk plays out.
initialize performs no lifecycle check. Its only agreement-side validation, isAgreementValid, is a provenance check (was this made by the factory), not a state gate — so a pool can be created against an agreement in any of the five non-commitment states. The impact splits on whether the state permits deposits (_assertDepositsAllowed):
ATTACK_REQUESTED / UNDER_ATTACK — fund-affecting. Deposits are open, so real money enters and the creator picks the covered-account list after learning which contract is under attack. They can exclude that contract; when the agreement is later marked CORRUPTED, the moderator resolves SURVIVED via the "breach outside this pool's scope" branch (https://github.com/CodeHawks-Contests/2026-07-bc-confidence-pools/blob/58e8ba4ce3f3277866e4926f3140e597f9554a1e/src/ConfidencePool.sol#L334-L340), refunds stakers in full, and pays whitehats nothing.
PROMOTION_REQUESTED / PRODUCTION / CORRUPTED — Deposits are gated shut, so no funds at risk, but the pool still deploys, advertises a scope, and reports UNRESOLVED — misleading indexers/UIs and enabling spam.
Likelihood:
Reasonably likely for the fund-affecting states — any creator can deploy at will; the only precondition is the agreement being in ATTACK_REQUESTED / UNDER_ATTACK, which requires no race or privilege. The escape uses only intended flows (initialize → stake → flagOutcome(SURVIVED)); nothing reverts.
Impact:
Live-pool abuse denies whitehats a bounty they staked/hunted against while refunding stakers in full — value redirected by a decision made with hindsight.
Zombie pools cause no fund loss but misrepresent on-chain state to participants and indexers, and enable spam.
test/unit/ConfidencePool.deployStateGate.t.sol (run forge test --match-path "deployStateGate"). The matrix test walks all seven states, proving initialize never reverts and mapping which states let funds in:
Results:
One check closes all five bad states. agreement is assigned before _replaceScope, so _getAgreementState() is already callable:
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.