前言本文将针对ERC721、ERC721A与ERC721C这三个标准,从核心差异、关键机制、选型建议等多个维度进行系统梳理,并通过代码实现给出直观的对比分析。补充说明关于ERC721和ERC721A智能合约的开发测试部署可以参考博主的另外两篇文章《快速实现一个标准的NFT合约(实操篇)》和《ER
本文将针对ERC721、ERC721A与ERC721C这三个标准,从核心差异、关键机制、选型建议等多个维度进行系统梳理,并通过代码实现给出直观的对比分析。补充说明关于ERC721和ERC721A智能合约的开发测试部署可以参考博主的另外两篇文章《快速实现一个标准的NFT合约(实操篇)》和《ERC721与ERC721A:NFT标准的对比与特性分析》,本文着重对ERC721C合约的实现;
概述
ERC721 是 NFT 基础标准,ERC721A 是其批量铸造的 Gas 优化版,ERC721C 则聚焦创作者版税强制与转移管控,三者在核心目标、实现机制与适用场景上差异显著。当然了三个标准并非简单替代关系,而是针对不同痛点的专业化解决方案;
核心差异对比表
维度 ERC721(OpenZeppelin) ERC721A(Azuki) ERC721C(Creator Token) 定位 NFT 基础标准 批量铸造 Gas 优化实现 创作者版税与转移管控增强 数据结构 每个 tokenId 独立存储所有者 连续 ID 区间共享所有者(惰性初始化) 基于 ERC721 扩展转移限制与支付处理器 批量铸造 Gas 线性增长(10 个≈62 万) 近似常数(10 个≈14 万,优化 77%) 与 ERC721 相当,额外版税逻辑略增 首次转移成本 稳定(≈3.5 万) 略高(补齐存储),后续转移正常 随管控级别变化 核心特性 所有权与转移基础接口 批量铸造、低成本分发 强制版税、平台白名单、转移规则 兼容市场 全兼容 主流兼容 依赖支持 CAPS 的市场(OpenSea、Magic Eden) 适用场景 通用 NFT、单枚铸造 大型集合、批量空投 创作者经济、IP 管控、版税依赖项目
ERC721(基础标准)
ERC721A(Gas 优化)
ERC721C(版税与管控)
关于ERC721智能合约可以查看博主的此篇文章《快速实现一个标准的NFT合约(实操篇)》;包含了完整的开发、测试、部署全流程,相关内容就不赘述了;
关于ERC721A智能合约可以查看博主的此篇文章《ERC721与ERC721A:NFT标准的对比与特性分析》;包含了完整的开发、测试、部署全流程,相关内容就不赘述了;
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;/*
/**
@notice 极简 ERC-721 + ERC-2981 实现,使用 solady 优化字符串与签名 */ contract ERC721C is ERC721, ERC2981, Ownable { using LibString for uint256;
/////////////////////////////////////////////////////////////// CONFIG /////////////////////////////////////////////////////////////// uint96 private constant _DEFAULT_ROYALTY_BPS = 500; // 5% string private _baseTokenURI;
/////////////////////////////////////////////////////////////// CONSTRUCTOR /////////////////////////////////////////////////////////////// constructor( string memory name, string memory symbol, string memory baseURI, address royaltyReceiver ) ERC721(name, symbol) Ownable(_msgSender()) { baseTokenURI = baseURI; setDefaultRoyalty(royaltyReceiver, _DEFAULT_ROYALTY_BPS); }
/////////////////////////////////////////////////////////////// PUBLIC / EXTERNAL /////////////////////////////////////////////////////////////// /// @dev 安全铸造(仅合约拥有者) function safeMint(address to, uint256 tokenId) external onlyOwner { _safeMint(to, tokenId); }
/// @dev 批量安全铸造(仅合约拥有者) function safeBatchMint(address to, uint256[] calldata tokenIds) external onlyOwner { for (uint256 i; i < tokenIds.length; ) { _safeMint(to, tokenIds[i]); unchecked { ++i; } } }
/// @notice 更新 baseURI function setBaseURI(string calldata newBaseURI) external onlyOwner { _baseTokenURI = newBaseURI; }
/// @notice 更新版税(ERC-2981) function setRoyaltyInfo(address receiver, uint96 feeBps) external onlyOwner { _setDefaultRoyalty(receiver, feeBps); }
/////////////////////////////////////////////////////////////// INTERNAL / VIEW /////////////////////////////////////////////////////////////// function _baseURI() internal view override returns (string memory) { return _baseTokenURI; }
/// @dev 统一授权接口支持(ERC-721 + ERC-2981) function supportsInterface(bytes4 interfaceId) public view override(ERC721, ERC2981) returns (bool) { return super.supportsInterface(interfaceId); } }
### 编译指令
npx hardhat compile
## 智能合约部署脚本
**注释**:`采用HardhatV3中viem 或者ethers.js同理语法略有不同,关于ERC721和ERC721A部署详情可以参考以上对用的文章`
// scripts/deploy.js
import { network, artifacts } from "hardhat";
async function main() {
// 连接网络
const { viem } = await network.connect({ network: network.name });//指定网络进行链接
// 获取客户端
const [deployer] = await viem.getWalletClients();
const publicClient = await viem.getPublicClient();
const deployerAddress = deployer.account.address;
console.log("部署者的地址:", deployerAddress);
// 加载合约
const artifact = await artifacts.readArtifact("ERC721C");
const ipfsjsonuri="https://zygomorphic-magenta-bobolink.myfilebase.com/ipfs/QmQT8VpmWQVhUhoDCEK1mdHXaFaJ3KawkRxHm96GUhrXLB"
// 部署(构造函数参数:recipient, initialOwner)
const hash = await deployer.deployContract({
abi: artifact.abi,//获取abi
bytecode: artifact.bytecode,//硬编码
args: ["MyRoyaltyNFT","MRNFT",ipfsjsonuri,deployerAddress],//nft名称,nft符号,ipfsjsonuri,部署者地址
});
// 等待确认并打印地址
const receipt = await publicClient.waitForTransactionReceipt({ hash });
console.log("合约地址:", receipt.contractAddress);
}
main().catch(console.error);
npx hardhat run ./scripts/xxx.ts
注释:关于ERC721和ERC721A智能合约测试详情参考以上对应的两篇完整
import assert from "node:assert/strict";
import { describe, it,beforeEach } from "node:test";
import { formatEther,parseEther } from 'viem'
import { network } from "hardhat";
describe("ERC721C", async function () {
let viem: any;
let publicClient: any;
let owner: any, user1: any, user2: any, user3: any;
let deployerAddress: string;
let MyERC721C: any;
beforeEach (async function () {
const { viem } = await network.connect();
publicClient = await viem.getPublicClient();//创建一个公共客户端实例用于读取链上数据(无需私钥签名)。
[owner,user1,user2,user3] = await viem.getWalletClients();//获取第一个钱包客户端 写入联合交易
deployerAddress = owner.account.address;//钱包地址
const ipfsjsonuri="https://zygomorphic-magenta-bobolink.myfilebase.com/ipfs/QmQT8VpmWQVhUhoDCEK1mdHXaFaJ3KawkRxHm96GUhrXLB";
MyERC721C = await viem.deployContract("ERC721C", [
"My Royalty NFT",
"MRNFT",
ipfsjsonuri,
deployerAddress
]);//部署合约
console.log("MyRoyaltyNFT合约地址:", MyERC721C.address);
});
it("测试ERC721C", async function () {
//查询nft名称和符号
const name= await publicClient.readContract({
address: MyERC721C.address,
abi: MyERC721C.abi,
functionName: "name",
args: [],
});
const symbol= await publicClient.readContract({
address: MyERC721C.address,
abi: MyERC721C.abi,
functionName: "symbol",
args: [],
});
//查询合约拥有者
const ownerAddress= await publicClient.readContract({
address: MyERC721C.address,
abi: MyERC721C.abi,
functionName: "owner",
args: [],
});
console.log(name,symbol,ownerAddress)
//铸造单个nft
const safeMintHash=await owner.writeContract({
address: MyERC721C.address,
abi: MyERC721C.abi,
functionName: "safeMint",
args: [user1.account.address,0],
});
console.log("铸造单个nft交易哈希:",`${safeMintHash} eth`)
//等待交易确认
const receipt = await publicClient.getTransactionReceipt({
hash: safeMintHash,
});
console.log("铸造单个nft交易确认gas:",formatEther(receipt.gasUsed))
//批量铸造nft
const nftIds=[1,2,3]
const safeBatchMinthash =await owner.writeContract({
address: MyERC721C.address,
abi: MyERC721C.abi,
functionName: "safeBatchMint",
args: [user1.account.address,nftIds],
});
//估算gas费用
console.log("批量铸造nft交易哈希gas:",`${safeBatchMinthash} eth`)
//等待交易确认
const receipt1 = await publicClient.getTransactionReceipt({
hash: safeBatchMinthash,
});
console.log("批量铸造nft交易确认:",formatEther(receipt1.gasUsed))
//查询单个nft的tokenURI
const TokenURI= await publicClient.readContract({
address: MyERC721C.address,
abi: MyERC721C.abi,
functionName: "tokenURI",
args: [0],
});
console.log(TokenURI)
//查询余额和拥有者
const balanceOf=await publicClient.readContract({
address: MyERC721C.address,
abi: MyERC721C.abi,
functionName: "balanceOf",
args: [user1.account.address],
});
console.log(balanceOf)
//查询nft的拥有者
const ownerOf=await publicClient.readContract({
address: MyERC721C.address,
abi: MyERC721C.abi,
functionName: "ownerOf",
args: [0],
});
console.log(ownerOf)
//查询版税信息
const royaltyInfo=await publicClient.readContract({
address: MyERC721C.address,
abi: MyERC721C.abi,
functionName: "royaltyInfo",
args: [0,parseEther("2")],
});
console.log(royaltyInfo)
const GETAPPROVED=await publicClient.readContract({
address: MyERC721C.address,
abi: MyERC721C.abi,
functionName: "getApproved",
args: [0],
});
console.log(GETAPPROVED)
//设置BaseURI
const ipfsjsonuri1="https://zygomorphic-magenta-bobolink.myfilebase.com/ipfs/QmcN49MKt4MbSXSGckAcpvFqtea43uuPD2tvmuER1mG67s";
const setBaseURI=await owner.writeContract({
address: MyERC721C.address,
abi: MyERC721C.abi,
functionName: "setBaseURI",
args: [ipfsjsonuri1],
});
console.log(setBaseURI)
//查询更新后的tokenURI
const TokenURI1= await publicClient.readContract({
address: MyERC721C.address,
abi: MyERC721C.abi,
functionName: "tokenURI",
args: [0],
});
console.log("更新后",TokenURI1)
//设置默认版税
// const SETDEFAULTROYALTY=await owner.writeContract({
// address: MyRoyaltyNFT.address,
// abi: MyRoyaltyNFT.abi,
// functionName: "setDefaultRoyalty",
// args: [user3.account.address,"500"],
// });
// console.log(SETDEFAULTROYALTY)
//设置版税
const setRoyaltyInfo = await owner.writeContract({
address: MyERC721C.address,
abi: MyERC721C.abi,
functionName: "setRoyaltyInfo",
args: [user3.account.address,"200"],
});
//查询版税信息
const royaltyInfo1=await publicClient.readContract({
address: MyERC721C.address,
abi: MyERC721C.abi,
functionName: "royaltyInfo",
args: [0,parseEther("3")],
});
console.log("更新后版税信息",royaltyInfo1)
//转账nft
const TRANSFERFROM=await user1.writeContract({
address: MyERC721C.address,
abi: MyERC721C.abi,
functionName: "transferFrom",
args: [user1.account.address,user2.account.address,0],
});
//查询nft的新拥有者
const ownerOf1=await publicClient.readContract({
address: MyERC721C.address,
abi: MyERC721C.abi,
functionName: "ownerOf",
args: [0],
});
console.log(ownerOf1)
});
});
npx hardhat test ./test/xxx.ts
至此,关于 ERC721、ERC721A、ERC721C 三类 NFT 标准合约的功能特性、适用场景对比,以及基于 Hardhat V3 与 Viem 框架的开发、测试、部署全流程工作 已全部完成。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!