ERC721 NFT #
一、ERC721标准概述 #
1.1 标准接口 #
solidity
interface IERC721 {
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
function balanceOf(address owner) external view returns (uint256);
function ownerOf(uint256 tokenId) external view returns (address);
function safeTransferFrom(address from, address to, uint256 tokenId) external;
function transferFrom(address from, address to, uint256 tokenId) external;
function approve(address to, uint256 tokenId) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function setApprovalForAll(address operator, bool _approved) external;
function isApprovedForAll(address owner, address operator) external view returns (bool);
}
1.2 核心功能 #
| 功能 | 说明 |
|---|---|
| balanceOf | 查询NFT数量 |
| ownerOf | 查询NFT所有者 |
| transferFrom | 转移NFT |
| approve | 授权单个NFT |
| setApprovalForAll | 授权所有NFT |
二、完整实现 #
2.1 基础ERC721 #
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
contract MyNFT is ERC721 {
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
constructor() ERC721("MyNFT", "MNFT") {}
function mint(address to) public returns (uint256) {
_tokenIdCounter.increment();
uint256 tokenId = _tokenIdCounter.current();
_safeMint(to, tokenId);
return tokenId;
}
function totalSupply() public view returns (uint256) {
return _tokenIdCounter.current();
}
}
2.2 带元数据的NFT #
solidity
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
contract MyNFTWithURI is ERC721URIStorage {
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
constructor() ERC721("MyNFT", "MNFT") {}
function mint(address to, string memory uri) public returns (uint256) {
_tokenIdCounter.increment();
uint256 tokenId = _tokenIdCounter.current();
_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);
return tokenId;
}
}
三、扩展功能 #
3.1 可枚举 #
solidity
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
contract EnumerableNFT is ERC721Enumerable {
function mint(address to) public returns (uint256) {
uint256 tokenId = totalSupply() + 1;
_safeMint(to, tokenId);
return tokenId;
}
}
3.2 版税 #
solidity
import "@openzeppelin/contracts/token/common/ERC2981.sol";
contract RoyaltyNFT is ERC721, ERC2981 {
constructor() ERC721("RoyaltyNFT", "RNFT") {
_setDefaultRoyalty(msg.sender, 500); // 5%版税
}
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(ERC721, ERC2981)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
}
四、最佳实践 #
4.1 安全考虑 #
| 考虑点 | 说明 |
|---|---|
| 重入保护 | 使用ReentrancyGuard |
| 权限控制 | 使用Ownable |
| 元数据存储 | 使用IPFS或Arweave |
| 版税设置 | 实现ERC2981 |
4.2 Gas优化 #
solidity
// 使用ERC721A减少批量铸造Gas
import "erc721a/contracts/ERC721A.sol";
contract GasOptimizedNFT is ERC721A {
constructor() ERC721A("GasOptimizedNFT", "GONFT") {}
function mint(uint256 quantity) public {
_safeMint(msg.sender, quantity);
}
}
五、总结 #
ERC721要点:
| 功能 | 说明 |
|---|---|
| 核心接口 | 所有权和转移 |
| 元数据 | tokenURI |
| 扩展 | 可枚举、版税 |
| 安全 | 重入保护、权限控制 |
接下来,让我们学习去中心化交易所!
最后更新:2026-03-27