A bad-faith CORRUPTED pool has no attacker bounty, so a bounty call on it should be rejected with InvalidGoodFaithParams.
On a bad-faith pool bountyEntitlement == 0 and bountyClaimed starts at 0, so the bountyClaimed == bountyEntitlement check (0 == 0) always fires first; the !goodFaith guard below it is therefore dead code, and the call reverts with the semantically-wrong BountyAlreadyClaimed.
Likelihood:
Triggered on every bad-faith-CORRUPTED bounty call attempt.
Impact:
Callers/integrators receive a misleading revert reason (BountyAlreadyClaimed instead of InvalidGoodFaithParams), and the contract carries an unreachable branch. No funds move.
The bounty path is only meaningful for a good-faith CORRUPTED resolution: flagOutcome sets
bountyEntitlement = snapshotTotalStaked + snapshotTotalBonus for good-faith, but bountyEntitlement = 0
for bad-faith (no named attacker, funds sweep to recoveryAddress instead). bountyClaimed is 0
until a payout occurs. So on a bad-faith pool, when anyone calls claimAttackerBounty, the guards evaluate
top-to-bottom as:
outcome != CORRUPTED → false (pool is CORRUPTED), continue.
bountyClaimed == bountyEntitlement → 0 == 0 is true → reverts BountyAlreadyClaimed.
!goodFaith → never reached — this is the branch that was meant to reject a bad-faith bounty call.
The caller is told the bounty was "already claimed" when in fact no bounty ever existed. The intended
error InvalidGoodFaithParams is unreachable for the entire bad-faith outcome.
Step-by-step reproduction (from test/fuzz/ConfidencePool.invariants.t.sol :: test_bounty_revert_matrix):
Run it with:
The test passes with the BountyAlreadyClaimed expectation, confirming the good-faith guard is dead code for
the bad-faith case and the revert reason is misleading.
Move the good-faith check above the entitlement check so the bad-faith case is rejected for the correct
reason before the 0 == 0 entitlement comparison can fire:
Ordering matters here because bountyEntitlement == 0 is a legitimate resting state for a bad-faith pool,
not evidence that a bounty was consumed. Checking !goodFaith first cleanly separates the two conditions:
"this pool has no bounty path" (InvalidGoodFaithParams) versus "the good-faith bounty is fully claimed"
(BountyAlreadyClaimed). After the reorder, the entitlement check only governs genuine good-faith pools,
where bountyClaimed == bountyEntitlement correctly means the bounty has been exhausted, and no branch is
left unreachable.
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.