ConfidencePoolFactory.createPool() verifies that the supplied agreement is registered and owned
by the caller, but it does not verify the agreement's current AttackRegistry lifecycle state.
Likewise, ConfidencePool.initialize() checks isAgreementValid() without reading
getAgreementState().
As a result, the agreement owner can successfully create a pool after the agreement has already
entered PRODUCTION or CORRUPTED. These states are terminal in the BattleChain registry, and
both are permanently rejected by _assertDepositsAllowed():
The clone is therefore initialized, appended to getPoolsByAgreement(), and announced through a
normal PoolCreated event even though it can never accept a stake or bonus contribution. Every
subsequent deposit attempt reverts before transferring tokens.
This issue is limited to the terminal PRODUCTION and CORRUPTED states. Creation during
UNDER_ATTACK remains usable and is intentionally supported, while PROMOTION_REQUESTED can
return to UNDER_ATTACK if promotion is cancelled.
Likelihood
The condition is reached whenever the agreement owner creates a pool after the associated
agreement has already finalized as PRODUCTION or CORRUPTED.
This can occur through delayed deployment or automation that validates agreement registration
but does not separately query its lifecycle state.
All existing factory validations still pass because agreement validity and ownership do not
imply that the agreement remains deposit-eligible.
Impact
The creator pays to deploy and initialize a clone that cannot perform its primary purpose.
The unusable address is permanently appended to the factory's pool-discovery list and emits the
same PoolCreated event as a deposit-eligible pool, requiring integrators to perform an
additional registry-state query before presenting it as active.
The deterministic address for that agreement/index is consumed, and the clone cannot be removed
or reinitialized if creation was accidental.
No staker funds are lost because both deposit functions revert before token transfer; the impact
is unnecessary deployment cost and permanent factory/discovery pollution.
Add the following imports and test to test/unit/ConfidencePoolFactory.t.sol:
The test shows that factory creation and registration succeed, while both ways of funding the pool
are permanently unavailable once the agreement is terminal.
Read the live registry state during initialization and reject terminal agreements before the clone
is committed to the factory's discovery list:
Checking only terminal states preserves the intended ability to create and fund pools during
UNDER_ATTACK. It also permits creation during PROMOTION_REQUESTED, which may become usable
again if the promotion is cancelled. If the product intends to reject temporarily deposit-closed
pools as well, PROMOTION_REQUESTED can be included as an explicit policy choice.
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.