By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.
Non?Fungible Tokens (NFTs) are unique digital assets stored on a blockchain. Unlike ERC?20 tokens, each NFT has its own identifier and metadata, making it impossible to swap one for another on a one?to?one basis. This uniqueness lets creators issue verifiable ownership of art, collectibles, tickets, or even real?world assets—think of a CryptoPunks portrait that lives forever on Ethereum and can be bought, sold, or displayed in a wallet just like a physical painting.
ERC?721: The original standard for NFTs; defines ownerOf, transferFrom, and tokenURI. solidity interface IERC721 { function ownerOf(uint256 tokenId) external view returns (address); function tokenURI(uint256 tokenId) external view returns (string memory); }
ownerOf
transferFrom
tokenURI
solidity interface IERC721 { function ownerOf(uint256 tokenId) external view returns (address); function tokenURI(uint256 tokenId) external view returns (string memory); }
ERC?1155: A multi?token standard that can hold both fungible and non?fungible items in one contract, saving gas for batch operations.
tokenId (uint256): The unique identifier for each NFT; usually generated by an incremental counter or a hash of the metadata.
tokenId
Metadata JSON: A publicly hosted JSON file (often on IPFS) that describes the NFT (name, description, image URL, attributes). Example: json { "name": "Pixel Dragon #42", "description": "A rare dragon from the 2024 collection.", "image": "ipfs://QmX.../dragon42.png", "attributes": [{ "trait_type": "Rarity", "value": "Epic" }] }
json { "name": "Pixel Dragon #42", "description": "A rare dragon from the 2024 collection.", "image": "ipfs://QmX.../dragon42.png", "attributes": [{ "trait_type": "Rarity", "value": "Epic" }] }
tokenURI(uint256 tokenId): Returns the metadata URI for a given token. In a simple contract you might concatenate a base URI with the tokenId.
tokenURI(uint256 tokenId)
Minting Function: The public or only?owner method that creates a new NFT and assigns it to a wallet. solidity function mint(address to, uint256 tokenId) external onlyOwner { _safeMint(to, tokenId); }
solidity function mint(address to, uint256 tokenId) external onlyOwner { _safeMint(to, tokenId); }
_safeMint vs _mint: _safeMint checks that the recipient is either an EOA or a contract that implements IERC721Receiver, preventing tokens from being locked in non?ERC?721?aware contracts.
_safeMint
_mint
IERC721Receiver
Marketplace Listing (ERC?721): A contract that holds a mapping(uint256 => Listing) where Listing stores seller, price, and status. Buyers call buy(uint256 tokenId) which transfers ETH and then calls safeTransferFrom.
mapping(uint256 => Listing)
Listing
buy(uint256 tokenId)
safeTransferFrom
Royalty Standard (ERC?2981): Allows creators to earn a percentage on secondary sales without modifying the marketplace code. solidity function royaltyInfo(uint256 _tokenId, uint256 _salePrice) external view returns (address receiver, uint256 royaltyAmount);
solidity function royaltyInfo(uint256 _tokenId, uint256 _salePrice) external view returns (address receiver, uint256 royaltyAmount);
IPFS CID: Content Identifier (e.g., QmX...) that points to immutable data; used for storing NFT images and metadata off?chain while keeping the reference on?chain.
QmX...
require(msg.sender == ownerOf(tokenId)): A simple access control pattern that ensures only the token owner can perform certain actions (e.g., updating metadata).
require(msg.sender == ownerOf(tokenId))
Gas?Optimized Counter: Using OpenZeppelin’s Counters library or a custom uint256 private _nextId; to avoid storage writes on every mint.
Counters
uint256 private _nextId;
ERC721Enumerable
ERC2981
npx hardhat compile
hardhat test
npx hardhat run scripts/deploy.js --network goerli
npx ipfs add -r ./metadata
mint
js const tx = await nft.mint(wallet.address, nextId); await tx.wait();
setApprovalForAll
createListing(tokenId, price)
buy(tokenId)
Mistake: Using tx.origin for owner checks. Correction: Always use msg.sender (or ownerOf(tokenId)) because tx.origin can be spoofed through a malicious contract, breaking the access control.
tx.origin
msg.sender
ownerOf(tokenId)
Mistake: Storing the full image on?chain (e.g., base64?encoded PNG). Correction: Keep large assets off?chain (IPFS or Arweave) and store only the CID in tokenURI; this saves gas and keeps the contract size under the limit.
Mistake: Forgetting to implement IERC721Receiver when sending NFTs to a contract. Correction: Use _safeMint/safeTransferFrom or add onERC721Received to the receiving contract; otherwise the token can become irretrievable.
onERC721Received
Mistake: Hard?coding the base URI and later needing to change it (e.g., after a migration). Correction: Make the base URI mutable via an onlyOwner setter, or store the full URI per token to avoid future upgrades.
onlyOwner
Mistake: Ignoring royalty enforcement, assuming every marketplace will honor ERC?2981. Correction: Include royalty logic in your own marketplace or verify that the target marketplace supports ERC?2981; otherwise creators lose secondary?sale income.
call
delegatecall
l2Bridge
Scenario: A contract uses require(tx.origin == owner) to restrict who can update an NFT’s metadata. Answer: Dangerous – tx.origin can be hijacked by a phishing contract, allowing an attacker to bypass the check. Use msg.sender and compare to ownerOf(tokenId).
require(tx.origin == owner)
Scenario: You want to batch?mint 100 NFTs in a single transaction. Which standard gives the lowest gas cost? Answer: ERC?1155, because it supports batch mint and safeTransferFrom operations that write fewer storage slots per token.
Scenario: A marketplace lists an NFT but the buyer’s transaction fails with “ERC721: transfer to non?ERC721Receiver implementer”. Answer: The buyer’s address is a contract that does not implement onERC721Received; the marketplace should use safeTransferFrom or the buyer must add the ERC721 receiver interface.
(salePrice * royaltyFraction) / 10_000
ERC721URIStorage
pragma solidity ^0.8.20;
Join 4M+ learners. Unlock unlimited quizzes, wrong-answer tracking, flashcards + reminders, study guides, and 1-on-1 challenges.