The Claimed event is declared with address indexed recipient as its second topic, intended for off-chain consumers (indexers, dashboards, notification services) to filter by the address that actually received the payout.
At the emit site msg.sender is passed in the recipient slot. Since claim() enforces recipient != msg.sender earlier in the same function, the emitted topic is guaranteed to be the wrong address on every successful claim; the topic labelled recipient in the ABI never contains the real recipient.
Likelihood:
Fires on every successful claim because the emit site is hardcoded and the recipient-is-caller case is explicitly blocked on line 86.
Any off-chain tool that filters Claimed logs by recipient address (e.g. a participant's own UI saying "your claim landed") will silently return empty or mismatched results.
Impact:
No funds at risk; the ETH transfer itself goes to the correct address.
Off-chain analytics and user-facing notifications keyed on the recipient topic are systematically corrupted. Leaderboards, explorers, and cron jobs that reconcile on-chain payouts against event logs will disagree with the chain state.
Debuggability is harmed: event filters keyed on the real recipient return zero matches, complicating incident response and post-hunt accounting.
Inspecting any successful claim() call surfaces the mismatch. The Transfer-like ETH movement on line 107 targets recipient, while the Claimed log emitted on line 111 records msg.sender in the second indexed topic. Because line 86 rejects the case where recipient == msg.sender, the two are never the same address in any valid execution path.
Emit recipient — the parameter the payout is sent to — so the log matches the ETH transfer and the ABI's topic name. If capturing both the claimer and the payout recipient is intentional, widen the event to three indexed parameters rather than repurposing an existing one.
The event is declared as event `Claimed(bytes32 indexed treasureHash, address indexed recipient);`, which clearly indicates that the second indexed field is meant to represent the reward recipient, but `claim()` emits `Claimed(treasureHash, msg.sender)` instead of `Claimed(treasureHash, recipient)`, even though the ETH transfer is sent to recipient and the proof itself is constructed around the public inputs (treasureHash, recipient). As a standalone finding, this is appropriately low severity because it is fundamentally an event/accounting inconsistency rather than a direct loss-of-funds issue: the core state transition and payout still follow the intended recipient, but off-chain consumers reading the event log will observe incorrect metadata about who was associated with the claim.
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.