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