patternjavascriptTip
ERC-721 NFT: minting with metadata and tokenURI override
Viewed 0 times
OpenZeppelin Contracts 5.x, Solidity 0.8.x
ERC-721NFTsafeMinttokenURIERC721URIStorageOpenZeppelin
Error Messages
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.