Trick or Treat

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

Potential Lock of NFTs in the Contract

Summary

he contract manages various operations, including adding new treats (addTreat), setting treat costs (setTreatCost), handling ETH payments and NFT minting (trickOrTreat and resolveTrick), and withdrawing accumulated fees (withdrawFees). In scenarios where users attempt to purchase treats but do not send the required amount of ETH, the contract mints the NFT to itself and stores the purchase as pending. Users are expected to complete these pending purchases by calling the resolveTrick function to fulfill the remaining ETH requirement.

Vulnerability Details

function trickOrTreat(string memory _treatName) public payable nonReentrant {
// ... [initial logic] ...
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;
emit Swapped(msg.sender, _treatName, tokenId);
// User needs to call resolveTrick() to finish the transaction
}
} else {
// Normal price or half price
require(msg.value >= requiredCost, "Insufficient ETH sent for treat");
mintTreat(msg.sender, treat);
}
// ... [refund logic] ...
}

The contract permits NFTs to be minted to itself and held in a pending state when users send insufficient ETH during the trickOrTreat function. However, there is no mechanism for the contract owner to manage or reclaim these pending NFTs if users fail to complete their purchases by calling resolveTrick.

Users are required to call resolveTrick to complete their purchase by sending the remaining ETH. However, there is no enforced timeframe or automated mechanism to handle scenarios where users neglect or are unable to complete this step.

The contract lacks any administrative functions that allow the owner to manage, reclaim, or interact with NFTs held by the contract itself. This includes no functions to transfer these NFTs to another address, burn them, or otherwise handle them if the pending purchase is never resolved.

Impact

The primary consequence of NFTs being locked within the SpookySwap contract is that these assets become permanently inaccessible to users. When NFTs are minted to the contract itself and remain unclaimed due to incomplete purchases, users lose control over their intended digital assets.

Tools Used

Manual review

Recommendations

Introduce functions that allow the contract owner to reclaim or transfer NFTs held by the contract

Updates

Appeal created

bube Lead Judge 8 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

[invalid] Unlimited pending NFTs

The protocol can work correctly with more than 20000 tokens in it. It is informational.

Support

FAQs

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