SNARKeling Treasure Hunt

First Flight #59
Beginner FriendlyGameFiFoundry
100 EXP
View results
Submission Details
Severity: low
Valid

Wrong Event Emitter in claim() Function

Root + Impact

Description

  • The Claimed event should emits recipient as the recipient.

  • The Claimed event emits msg.sender as the recipient instead of the actual recipient parameter

// @>contracts/src/TreasureHunt.sol Line 111
emit Claimed(treasureHash, msg.sender); // BUG: should be 'recipient'

Risk

Likelihood:

  • Reason 1:Each seccessfull claim will emit a Claimedevent.

Impact:

  • Off-chain indexing services will incorrectly track who received the reward

  • The event data is misleading and doesn't reflect the actual recipient of funds

  • This breaks audit trails and makes it difficult to track legitimate claims

Proof of Concept

Whenever a claim succeeds, an event Claimedwith wrong recipient will be emitted.

Game starts...
A participant discovers a Treasure and starts to claim the reward.
At the end of `TreasureHunt.claim()`, an event `Claimed` with wrong recipient is called:
emit Claimed(treasureHash, msg.sender); // msg.sender may not be the recipient

Recommended Mitigation

Change line 111 to: emit Claimed(treasureHash, recipient);

Now, each Claimedwill emit correct recipient.

// file: contracts/src/TreasureHunt.sol
function claim(bytes calldata proof, bytes32 treasureHash, address payable recipient) external nonReentrant() {
if (paused) revert ContractPaused();
if (address(this).balance < REWARD) revert NotEnoughFunds();
if (recipient == address(0) || recipient == address(this) || recipient == owner || recipient == msg.sender) revert InvalidRecipient();
if (claimsCount >= MAX_TREASURES) revert AllTreasuresClaimed();
if (claimed[_treasureHash]) revert AlreadyClaimed(treasureHash);
if (msg.sender == owner) revert OwnerCannotClaim();
// Public inputs must match Noir circuit order:
// treasure_hash, recipient (recipient encoded into 160-bit integer in a Field).
bytes32[] memory publicInputs = new bytes32[](2);
publicInputs[0] = treasureHash;
publicInputs[1] = bytes32(uint256(uint160(address(recipient))));
// Verify proof against the public inputs.
// If valid, transfer the reward and mark the treasure as claimed.
bool ok = verifier.verify(proof, publicInputs);
if (!ok) revert InvalidProof();
_incrementClaimsCount();
_markClaimed(treasureHash);
(bool sent, ) = recipient.call{value: REWARD}("");
require(sent, "ETH_TRANSFER_FAILED");
- emit Claimed(treasureHash, msg.sender);
+ emit Claimed(treasureHash, recipient);
}
Updates

Lead Judging Commences

s3mvl4d Lead Judge 18 days ago
Submission Judgement Published
Validated
Assigned finding tags:

incorrect event parameter

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.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!