SNARKeling Treasure Hunt

First Flight #59
Beginner FriendlyGameFiFoundry
100 EXP
Submission Details
Impact: high
Likelihood: high

Wrong Event Emitter in claim() Function

Author Revealed upon completion

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);
}

Support

FAQs

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

Give us feedback!