NFT Smart Contract Security 2 — Questions and Answers
Question 1: In an ERC-721 contract, which function should use _safeMint instead of _mint when the recipient may be a contract?
- When the recipient must be verified to accept ERC-721 tokens via onERC721Received (Correct answer)
- When minting to an externally owned account only
- When gas costs must be minimized at all costs
- When the token ID is randomly generated
Correct answer: When the recipient must be verified to accept ERC-721 tokens via onERC721Received
_safeMint checks that contract recipients implement onERC721Received, preventing tokens from being locked in incompatible contracts.
Question 2: What is a reentrancy attack in the context of an NFT marketplace contract?
- An attacker repeatedly calls back into the contract before state updates complete, draining funds (Correct answer)
- An attacker submits the same transaction twice in one block
- An attacker overflows a uint256 counter
- An attacker mints two tokens with the same ID
Correct answer: An attacker repeatedly calls back into the contract before state updates complete, draining funds
Reentrancy occurs when an external call lets an attacker re-enter the function before balances or ownership state are finalized.
Question 3: Which pattern best prevents reentrancy in a withdraw function?
- Checks-Effects-Interactions: update state before making external calls (Correct answer)
- Interactions-Effects-Checks order
- Calling external contracts first to validate
- Using tx.origin for authentication
Correct answer: Checks-Effects-Interactions: update state before making external calls
Updating internal state before external calls ensures a re-entrant call sees the already-updated state.
Question 4: Why is using tx.origin for authorization in an NFT contract dangerous?
- A malicious intermediary contract can trick the user into authorizing actions via phishing (Correct answer)
- It costs more gas than msg.sender
- It cannot be read inside modifiers
- It returns a random address each call
Correct answer: A malicious intermediary contract can trick the user into authorizing actions via phishing
tx.origin is the original EOA, so an intermediary contract the user calls can impersonate the user's authority.
Question 5: What does the OpenZeppelin ReentrancyGuard's nonReentrant modifier do?
- Sets a lock flag preventing the function from being called again until it completes (Correct answer)
- Caps the number of NFTs minted per block
- Validates ERC-165 interface support
- Encrypts the function's storage variables
Correct answer: Sets a lock flag preventing the function from being called again until it completes
nonReentrant uses a status flag to block recursive calls into guarded functions until the first call returns.
Question 6: An NFT minting function uses block.timestamp for randomness in trait assignment. Why is this insecure?
- Miners/validators can influence block.timestamp to manipulate outcomes (Correct answer)
- block.timestamp is always zero on mainnet
- It causes an integer underflow
- It is not accessible from within functions
Correct answer: Miners/validators can influence block.timestamp to manipulate outcomes
On-chain values like block.timestamp are predictable and partly manipulable, making them unsafe sources of randomness.
Question 7: What is the risk of leaving an NFT contract's mint function without access control?
- Anyone can mint unlimited tokens, destroying scarcity and value (Correct answer)
- The contract cannot be deployed
- Gas fees become unpredictable
- The metadata URI gets corrupted
Correct answer: Anyone can mint unlimited tokens, destroying scarcity and value
Without onlyOwner or role checks, any caller can mint arbitrarily, breaking the intended supply model.
In an ERC-721 contract, which function should use _safeMint instead of _mint when the recipient may be a contract?