ERC-721 NFT standard in Blockchain / Solidity - Time & Space Complexity
When working with ERC-721 NFTs, it's important to understand how the time to perform actions grows as the number of tokens increases.
We want to know how the cost of operations like transferring or checking ownership changes as more NFTs exist.
Analyze the time complexity of the following simplified ERC-721 transfer function.
function transferFrom(address from, address to, uint256 tokenId) public {
require(ownerOf(tokenId) == from, "Not owner");
require(to != address(0), "Invalid address");
_approve(address(0), tokenId);
_owners[tokenId] = to;
_balances[from] -= 1;
_balances[to] += 1;
emit Transfer(from, to, tokenId);
}
This code transfers ownership of a single NFT from one address to another.
Look for loops or repeated steps that depend on input size.
- Primary operation: Accessing and updating ownership and balances for one token.
- How many times: Each transfer handles exactly one token, so operations happen once per call.
The work done for transferring one token stays the same no matter how many tokens exist.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 1 operation (one per token transfer) |
| 100 | 1 operation (still one per transfer) |
| 1000 | 1 operation (one per transfer) |
Pattern observation: The time per transfer does not increase as more tokens exist; it stays constant.
Time Complexity: O(1)
This means transferring a token takes the same amount of time no matter how many NFTs are in the contract.
[X] Wrong: "Transferring a token gets slower as more tokens exist because the contract must check all tokens."
[OK] Correct: The contract uses direct mappings to find owners, so it looks up only the specific token without scanning others.
Understanding how blockchain operations scale helps you explain gas costs and efficiency clearly, a useful skill for blockchain development roles.
"What if the contract stored all tokens owned by an address in an array and had to search it to find a token? How would the time complexity change?"
Practice
ERC-721 standard in blockchain?Solution
Step 1: Understand ERC-721's role
ERC-721 is designed specifically for unique tokens, called NFTs, which are different from fungible tokens like cryptocurrencies.Step 2: Compare with other token standards
ERC-20 is for fungible tokens, while ERC-721 is for unique, non-fungible tokens.Final Answer:
To define a standard for unique non-fungible tokens (NFTs) -> Option AQuick Check:
ERC-721 = Unique NFTs [OK]
- Confusing ERC-721 with ERC-20 fungible tokens
- Thinking ERC-721 manages encryption
- Assuming ERC-721 handles contract deployment
Solution
Step 1: Recall ERC-721 standard function names
The standard definesownerOfwith auint256 tokenIdparameter returning anaddress.Step 2: Check function visibility and return type
The function isexternal viewand returns anaddress, matching function ownerOf(uint256 tokenId) external view returns (address); exactly.Final Answer:
function ownerOf(uint256 tokenId) external view returns (address); -> Option BQuick Check:
ownerOf(tokenId) returns owner address [OK]
- Using wrong function names like getOwner or tokenOwner
- Incorrect return types like string instead of address
- Missing view or external keywords
ownerOf(1) if token 1 is owned by address 0xABC...?
contract MyNFT is ERC721 {
mapping(uint256 => address) private _owners;
function ownerOf(uint256 tokenId) public view override returns (address) {
return _owners[tokenId];
}
function mint(address to, uint256 tokenId) public {
_owners[tokenId] = to;
}
}Solution
Step 1: Understand the mint function effect
Themintfunction sets the owner oftokenIdto the given address in the_ownersmapping.Step 2: Check ownerOf return value
TheownerOffunction returns the address stored in_owners[tokenId]. If token 1 was minted to0xABC..., it returns that address.Final Answer:
0xABC... -> Option CQuick Check:
ownerOf(1) = minted owner address [OK]
- Assuming default zero address if not minted
- Thinking function has no return
- Confusing compilation errors with runtime behavior
function transferFrom(address from, address to, uint256 tokenId) public override {
require(ownerOf(tokenId) == msg.sender, "Not owner");
_owners[tokenId] = to;
}Solution
Step 1: Check transferFrom permission logic
ERC-721 requires that the caller is either the owner or approved to transfer the token, not just the owner.Step 2: Identify missing approval check
The code only checks ifmsg.senderis the owner, missing approval checks, which can block valid transfers.Final Answer:
The require should check if msg.sender is approved or owner, not just owner -> Option AQuick Check:
transferFrom needs owner or approved check [OK]
- Only checking owner without approval
- Forgetting to override transferFrom
- Not updating ownership mapping
Solution
Step 1: Identify burn function in ERC-721
The_burninternal function handles token destruction in ERC-721 contracts.Step 2: Add ownership check for burning
To restrict burning to original minters, override_burnand add a check thatmsg.sendermatches the original minter address stored during minting.Final Answer:
Override_burnand check ifmsg.senderis the original minter -> Option DQuick Check:
Burn control = override _burn + minter check [OK]
- Trying to control burn in transferFrom or approve
- Not storing original minter address
- Checking approval instead of minter for burn
Ready to prove it?
Pass the test and this pattern moves unknown
