Bird
Raised Fist0
Blockchain / Solidityprogramming~20 mins

ERC-721 implementation in Blockchain / Solidity - Practice Problems & Coding Challenges

Choose your learning style10 modes available
Challenge - 5 Problems
🎖️
ERC-721 Mastery
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ Predict Output
intermediate
2:00remaining
What is the output of this Solidity event emission?

Consider the following snippet from an ERC-721 contract. What event is emitted when _mint is called?

Blockchain / Solidity
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

function _mint(address to, uint256 tokenId) internal {
    require(to != address(0), "ERC721: mint to the zero address");
    require(!_exists(tokenId), "ERC721: token already minted");

    _balances[to] += 1;
    _owners[tokenId] = to;

    emit Transfer(address(0), to, tokenId);
}
ANo event is emitted
BTransfer event with from = zero address, to = recipient, tokenId = minted token
CApproval event with owner = zero address, approved = recipient, tokenId = minted token
DTransfer event with from = recipient, to = zero address, tokenId = minted token
Attempts:
2 left
💡 Hint

Minting a token means creating it from nothing, so the 'from' address is zero.

❓ Predict Output
intermediate
2:00remaining
What is the balance of an address after minting and transferring tokens?

Given this sequence of calls on an ERC-721 contract, what is the balance of 0xABC after all operations?

Blockchain / Solidity
function _mint(address to, uint256 tokenId) internal {
    _balances[to] += 1;
    _owners[tokenId] = to;
}

function _transfer(address from, address to, uint256 tokenId) internal {
    _balances[from] -= 1;
    _balances[to] += 1;
    _owners[tokenId] = to;
}

// Sequence:
// _mint(0xABC, 1);
// _mint(0xABC, 2);
// _transfer(0xABC, 0xDEF, 1);
A0
B2
C1
D3
Attempts:
2 left
💡 Hint

Think about how many tokens 0xABC owns after minting two and transferring one away.

🔧 Debug
advanced
2:00remaining
Why does this ERC-721 transfer function revert?

Examine this transfer function snippet. Why does it revert when called?

Blockchain / Solidity
function transferFrom(address from, address to, uint256 tokenId) public {
    require(_owners[tokenId] == from, "Not token owner");
    require(to != address(0), "Transfer to zero address");

    _approve(address(0), tokenId);
    _balances[from] -= 1;
    _balances[to] += 1;
    _owners[tokenId] = to;
}
AIt reverts because tokenId is not checked for existence
BIt reverts because _approve is called with address(0)
CIt reverts because balances are not updated
DIt reverts because there is no check that msg.sender is approved or owner
Attempts:
2 left
💡 Hint

Think about who is allowed to call transferFrom in ERC-721.

📝 Syntax
advanced
2:00remaining
Which option correctly implements the supportsInterface function for ERC-721?

Choose the correct Solidity code for supportsInterface that returns true for ERC-721 interface ID 0x80ac58cd and calls super otherwise.

A
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
    return interfaceId == 0x80ac58cd || super.supportsInterface(interfaceId);
}
B
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
    if (interfaceId == 0x80ac58cd) {
        return false;
    }
    return super.supportsInterface(interfaceId);
}
C
function supportsInterface(bytes4 interfaceId) public view override returns (bool) {
    if (interfaceId == 0x80ac58cd) {
        return true;
    } else {
        return super.supportsInterface(interfaceId);
    }
}
D
function supportsInterface(bytes4 interfaceId) public view override returns (bool) {
    return interfaceId == 0x80ac58cd && super.supportsInterface(interfaceId);
}
Attempts:
2 left
💡 Hint

Remember the logical OR operator returns true if either side is true.

🚀 Application
expert
3:00remaining
How many tokens are owned by an address after this sequence of mint, burn, and transfer?

Given this ERC-721 contract snippet and sequence, what is the final balance of 0x123?

Blockchain / Solidity
mapping(address => uint256) private _balances;
mapping(uint256 => address) private _owners;

function _mint(address to, uint256 tokenId) internal {
    _balances[to] += 1;
    _owners[tokenId] = to;
}

function _burn(uint256 tokenId) internal {
    address owner = _owners[tokenId];
    require(owner != address(0), "Token does not exist");
    _balances[owner] -= 1;
    delete _owners[tokenId];
}

function _transfer(address from, address to, uint256 tokenId) internal {
    require(_owners[tokenId] == from, "Not owner");
    _balances[from] -= 1;
    _balances[to] += 1;
    _owners[tokenId] = to;
}

// Sequence:
// _mint(0x123, 10);
// _mint(0x123, 20);
// _transfer(0x123, 0x456, 10);
// _burn(20);
A0
B3
C2
D1
Attempts:
2 left
💡 Hint

Track each token's ownership and balance changes carefully.

Practice

(1/5)
1.

What is the main purpose of the ERC-721 standard in blockchain?

easy
A. To create fungible tokens like cryptocurrencies
B. To manage smart contract ownership
C. To create unique, non-fungible tokens (NFTs)
D. To enable fast transaction processing

Solution

  1. Step 1: Understand ERC-721 token type

    ERC-721 defines a standard for unique tokens, unlike fungible tokens which are identical.
  2. Step 2: Identify the purpose of ERC-721

    It is used to create NFTs, which are unique digital assets on the blockchain.
  3. Final Answer:

    To create unique, non-fungible tokens (NFTs) -> Option C
  4. Quick Check:

    ERC-721 = Unique NFTs [OK]
Hint: ERC-721 is for unique tokens, not identical ones [OK]
Common Mistakes:
  • Confusing ERC-721 with ERC-20 fungible tokens
  • Thinking ERC-721 manages contract ownership
  • Assuming ERC-721 speeds up transactions
2.

Which of the following is the correct way to inherit OpenZeppelin's ERC721 contract in Solidity?

contract MyNFT is ? {}
easy
A. SafeMath
B. ERC721
C. Ownable
D. ERC20

Solution

  1. Step 1: Identify the correct base contract for NFTs

    ERC721 is the OpenZeppelin contract for NFTs, ERC20 is for fungible tokens.
  2. Step 2: Confirm inheritance syntax

    Using is ERC721 correctly inherits the NFT functionality.
  3. Final Answer:

    ERC721 -> Option B
  4. Quick Check:

    Inherit ERC721 for NFTs [OK]
Hint: Use ERC721 to inherit NFT features [OK]
Common Mistakes:
  • Using ERC20 instead of ERC721
  • Confusing Ownable with ERC721
  • Trying to inherit SafeMath for NFTs
3.

What will be the output of the following Solidity function when called?

function mintToken(address to, uint256 tokenId) public {
    _mint(to, tokenId);
}

// Assume _mint works as expected and tokenId = 1, to = 0x123...

What happens after calling mintToken(0x123..., 1)?

medium
A. A new NFT with tokenId 1 is assigned to address 0x123...
B. The tokenId 1 is burned from address 0x123...
C. The function throws a syntax error
D. The tokenId 1 is transferred from 0x123... to the caller

Solution

  1. Step 1: Understand the _mint function

    _mint creates a new token with the given tokenId and assigns it to the 'to' address.
  2. Step 2: Analyze the function call

    Calling mintToken with address 0x123... and tokenId 1 creates that NFT for 0x123....
  3. Final Answer:

    A new NFT with tokenId 1 is assigned to address 0x123... -> Option A
  4. Quick Check:

    mintToken creates NFT for 'to' address [OK]
Hint: _mint assigns new token to given address [OK]
Common Mistakes:
  • Thinking _mint burns tokens
  • Assuming _mint transfers tokens
  • Expecting syntax errors from correct code
4.

Identify the error in this Solidity snippet for minting an ERC-721 token:

function mint(address to, uint256 tokenId) public {
    _mint(tokenId, to);
}

medium
A. Function must be named mintToken, not mint
B. _mint cannot be called inside a public function
C. tokenId must be a string, not uint256
D. _mint parameters are reversed; should be (to, tokenId)

Solution

  1. Step 1: Check _mint function parameter order

    OpenZeppelin's _mint expects (address to, uint256 tokenId).
  2. Step 2: Compare with given code

    The code uses _mint(tokenId, to), reversing the parameters.
  3. Final Answer:

    _mint parameters are reversed; should be (to, tokenId) -> Option D
  4. Quick Check:

    _mint(to, tokenId) correct order [OK]
Hint: _mint needs (address, tokenId) order [OK]
Common Mistakes:
  • Swapping parameters of _mint
  • Thinking _mint can't be public
  • Confusing tokenId type
5.

You want to create an ERC-721 contract that only allows the contract owner to mint new tokens. Which of these Solidity code snippets correctly enforces this?

contract MyNFT is ERC721, Ownable {
    function mint(address to, uint256 tokenId) public {
        ?
        _mint(to, tokenId);
    }
}
hard
A. require(msg.sender == owner(), "Not owner");
B. require(to == owner(), "Not owner");
C. require(tokenId > 0, "Invalid tokenId");
D. require(msg.sender != owner(), "Owner cannot mint");

Solution

  1. Step 1: Understand ownership check

    Only the contract owner should mint, so check if msg.sender equals owner().
  2. Step 2: Analyze each require statement

    require(msg.sender == owner(), "Not owner"); correctly checks sender is owner; others check wrong conditions.
  3. Final Answer:

    require(msg.sender == owner(), "Not owner"); -> Option A
  4. Quick Check:

    Owner check uses msg.sender == owner() [OK]
Hint: Check msg.sender equals owner() before minting [OK]
Common Mistakes:
  • Checking 'to' address instead of sender
  • Allowing anyone to mint without checks
  • Using wrong require conditions
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard