Trick or Treat

First Flight #27
Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: low
Valid

[L-01] Incorrect Event Emission Misleads Users (Event Emitted Before NFT Transfer Causes Confusion)

Summary

The SpookySwap smart contract emits the Swapped event incorrectly when a user doesn't send enough ETH during a "trick" scenario. Specifically, the contract mints the NFT to itself (address(this)) but emits the Swapped event as if the user (msg.sender) received the NFT. This misleads users and off-chain systems into believing that the NFT has been transferred to the user when it hasn't. The issue lies in the event emission timing and the incorrect recipient address in the event parameters.

Vulnerability Details

Issue Overview

In the trickOrTreat function, when the costMultiplierNumerator is 2 and costMultiplierDenominator is 1, the contract handles the "double price" case (a trick). If the user doesn't send enough ETH (msg.value < requiredCost), the contract mints the NFT to itself and stores pending purchase details. However, it incorrectly emits the Swapped event with msg.sender as the recipient, suggesting that the NFT has been transferred to the user.

Affected Code

if (costMultiplierNumerator == 2 && costMultiplierDenominator == 1) {
// Double price case (trick)
if (msg.value >= requiredCost) {
// User sent enough ETH
mintTreat(msg.sender, treat);
} else {
// User didn't send enough ETH
// Mint NFT to contract and store pending purchase
uint256 tokenId = nextTokenId;
_mint(address(this), tokenId);
_setTokenURI(tokenId, treat.metadataURI);
nextTokenId += 1;
pendingNFTs[tokenId] = msg.sender;
pendingNFTsAmountPaid[tokenId] = msg.value;
tokenIdToTreatName[tokenId] = _treatName;
// Incorrect event emission
@> emit Swapped(msg.sender, _treatName, tokenId);
// User needs to call fellForTrick() to finish the transaction
}
}

Problem Explanation

  • Incorrect Recipient in Event: The Swapped event is emitted with msg.sender as the recipient, even though the NFT is minted to address(this), not to the user.

  • Misleading Event Timing: Emitting the event at this point suggests that the NFT transfer to the user is complete, which is not the case. The user must call resolveTrick() to finalize the transfer.

  • Potential for Confusion: Users and off-chain systems relying on the Swapped event may incorrectly assume the NFT is in the user's possession.

Impact

  • User Confusion: Users might believe they own the NFT and attempt actions like transferring or interacting with it, leading to failed transactions.

  • Misrepresentation in Off-Chain Systems: Wallets, explorers, and dApps that track events may display inaccurate ownership information.

  • Operational Integrity Issues: The misleading event undermines the trust in the contract's reliability and transparency.

Severity Classification: Low

Tools Used

Manual code review

Recommendations

  1. Adjust the Event Emission:

    • Update the Recipient Address:
      Change the emit Swapped statement to reflect the correct recipient (address(this)).

      emit Swapped(address(this), _treatName, tokenId);
    • Or Emit a Different Event:
      Emit a new event to indicate that the NFT is pending and the user needs to take further action.

      event TrickInitiated(address indexed user, string treatName, uint256 tokenId);
      emit TrickInitiated(msg.sender, _treatName, tokenId);
Updates

Appeal created

bube Lead Judge 9 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Incorrect Swapped event emission

The protocol emits a Swapped event even when the user has not sent enough ETH to complete the transaction.

Support

FAQs

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