Eggstravaganza

First Flight #37
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: medium
Valid

No Check if NFT Is Approved Before Transfer

πŸ“„ Summary

The EggHuntGame contract attempts to transfer NFTs from the user to the EggVault without verifying that the user has approved the game contract to perform the transfer. While this may revert due to standard ERC721 restrictions, the absence of a pre-check results in unclear UX, wasted gas, and potential unexpected reverts during execution.


πŸ› οΈ Vulnerability Details

Contract:

EggHuntGame.sol

Function:

function depositEggToVault(uint256 tokenId) external

Problem:

This function calls:

eggNFT.transferFrom(msg.sender, address(eggVault), tokenId);

Under ERC721 rules, this will revert if msg.sender has not explicitly approved the EggHuntGame or the EggVault contract to transfer their NFT. However, there is no prior check or user-facing validation to ensure the user has done so.


πŸ’₯ Impact

  • Unexpected Reverts: Users unaware of the approval requirement may call depositEggToVault() and experience failed transactions, losing gas.

  • Poor UX: Without a user-friendly error message or guidance, users will not understand why the transfer failed.

  • Frontend/Integration Failures: Dapps relying on this flow may not handle such reverts gracefully.


πŸ”§ Tools Used

  • Manual code review

  • ERC721 specification reference (OpenZeppelin)

  • UX impact assessment based on transaction reversion patterns


βœ… Recommendations

βœ… Solution 1: Add Explicit Approval Check

Use OpenZeppelin’s getApproved() or isApprovedForAll() to validate whether the transfer is authorized before attempting it.

function depositEggToVault(uint256 tokenId) external {
require(eggNFT.ownerOf(tokenId) == msg.sender, "Not owner of this egg");
// πŸ” Check for token approval
require(
eggNFT.getApproved(tokenId) == address(this) ||
eggNFT.isApprovedForAll(msg.sender, address(this)),
"Contract not approved to transfer NFT"
);
​
eggNFT.transferFrom(msg.sender, address(eggVault), tokenId);
eggVault.depositEgg(tokenId, msg.sender);
}

βœ… Solution 2: Use safeTransferFrom and Implement onERC721Received in EggVault

Using safeTransferFrom() ensures the recipient (EggVault) supports receiving NFTs and enables automatic callback handling:

eggNFT.safeTransferFrom(msg.sender, address(eggVault), tokenId);

Ensure EggVault implements:

function onERC721Received(...) public pure override returns (bytes4) {
return this.onERC721Received.selector;
}

🎯 Optional Enhancements

  • Include an error message for failed approval to be surfaced in frontend UIs.

  • Add UI guidance or helper function to prompt users to call approve() on the NFT contract before depositing.


Updates

Lead Judging Commences

m3dython Lead Judge about 2 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Unsafe ERC721 Transfer

NFTs are transferred to contracts without onERC721Received implementation.

Support

FAQs

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