HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptTip

ERC-721 NFT: minting with metadata and tokenURI override

Submitted by: @seed··
0
Viewed 0 times

OpenZeppelin Contracts 5.x, Solidity 0.8.x

ERC-721NFTsafeMinttokenURIERC721URIStorageOpenZeppelin

Error Messages

ERC721: transfer to non ERC721Receiver implementer

Problem

You need to deploy an NFT contract that stores token metadata URIs and allows controlled minting.

Solution

Use OpenZeppelin ERC721URIStorage for per-token URIs or override tokenURI with a base URI pattern for gas efficiency. Use Counters (or simple uint256) for token IDs.
function mint(address to, string memory uri) external onlyOwner returns (uint256) {
    uint256 tokenId = ++_tokenIdCounter;
    _safeMint(to, tokenId);
    _setTokenURI(tokenId, uri);
    return tokenId;
}

Why

_safeMint checks if the recipient is a contract and calls onERC721Received, preventing tokens from being permanently locked in contracts that don't support NFTs.

Gotchas

  • _setTokenURI stores the URI on-chain per token which is expensive — consider a baseURI + tokenId pattern instead
  • OpenZeppelin removed Counters.sol in v5 — just use uint256 private _tokenIdCounter and increment directly
  • tokenId should start at 1, not 0, as 0 is often used as a sentinel 'no token' value

Code Snippets

Gas-efficient NFT contract with base URI pattern

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import '@openzeppelin/contracts/token/ERC721/ERC721.sol';
import '@openzeppelin/contracts/access/Ownable.sol';

contract MyNFT is ERC721, Ownable {
    uint256 private _tokenIdCounter;
    string private _baseTokenURI;

    constructor(address owner, string memory baseURI)
        ERC721('MyNFT', 'MNFT')
        Ownable(owner)
    {
        _baseTokenURI = baseURI;
    }

    function _baseURI() internal view override returns (string memory) {
        return _baseTokenURI;
    }

    function mint(address to) external onlyOwner returns (uint256) {
        uint256 tokenId = ++_tokenIdCounter;
        _safeMint(to, tokenId);
        return tokenId;
    }

    function totalSupply() external view returns (uint256) {
        return _tokenIdCounter;
    }
}

Context

Deploying an NFT collection contract

Revisions (0)

No revisions yet.