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.
View preliminary resultsAppeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.