返回知识库
Day 22

NFT技术标准:ERC721与ERC1155深度对比

深入理解NFT技术标准ERC721和ERC1155的设计原理、应用场景、优劣对比,掌握NFT产品设计基础

2025-01-31
NFTERC721ERC1155智能合约Week4

Day 22: NFT 标准 - ERC721 与 ERC1155

Week 4 学习路径

Week 4: NFT与新范式
├── Day 22: ERC721/1155标准对比 ✅ ← 今天
├── Day 23: NFT市场机制(版税/稀有度)
├── Day 24: 账户抽象(AA) ERC4337
├── Day 25: 社交恢复、Gas代付
├── Day 26: The Graph Subgraph原理
├── Day 27: 集成Subgraph到项目
└── Day 28: Uniswap产品分析文章

核心概念

什么是 NFT?

> 类比理解:如果 ERC20 代币像钞票(每张100元都一样),那 NFT 就像艺术品或房产证——每一个都是独一无二的,有自己的编号和属性。NFT = Non-Fungible Token = 非同质化代币。

Token 类型对比
═══════════════════════════════════════════════════════════

同质化代币 (Fungible Token) - ERC20
├── 每个代币完全相同
├── 可以分割(0.5 ETH)
├── 互相可替换
└── 例:ETH, USDC, UNI

非同质化代币 (Non-Fungible Token) - ERC721
├── 每个代币独一无二
├── 不可分割(只能整个转移)
├── 不可互换(每个都不同)
└── 例:CryptoPunks, BAYC, 域名

半同质化代币 (Semi-Fungible Token) - ERC1155
├── 同类型代币相同,不同类型不同
├── 支持批量操作
├── 更灵活
└── 例:游戏道具、门票
═══════════════════════════════════════════════════════════

ERC721 标准详解

核心接口

// ERC721 核心接口
interface IERC721 {
    // 查询余额
    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);

    // 批量授权
    function setApprovalForAll(address operator, bool approved) external;

    // 查询批量授权
    function isApprovedForAll(
        address owner,
        address operator
    ) external view returns (bool);

    // 事件
    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);
}

ERC721 数据结构

ERC721 存储结构
═══════════════════════════════════════════════════════════

核心映射:
┌─────────────────────────────────────────────────────────┐
│ mapping(uint256 => address) private _owners;            │
│ // tokenId => 所有者地址                                │
│                                                         │
│ mapping(address => uint256) private _balances;          │
│ // 地址 => 持有数量                                     │
│                                                         │
│ mapping(uint256 => address) private _tokenApprovals;    │
│ // tokenId => 授权地址                                  │
│                                                         │
│ mapping(address => mapping(address => bool))            │
│     private _operatorApprovals;                         │
│ // 所有者 => 操作者 => 是否授权                         │
└─────────────────────────────────────────────────────────┘

每个 Token 独立存储:
Token #1 → Owner: 0xAlice
Token #2 → Owner: 0xBob
Token #3 → Owner: 0xAlice
...

查询某人持有的所有 NFT 需要遍历(Gas 高)
═══════════════════════════════════════════════════════════

ERC721 Metadata 扩展

// 元数据接口 - 让 NFT 有名字和图片
interface IERC721Metadata {
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function tokenURI(uint256 tokenId) external view returns (string memory);
}

// tokenURI 返回 JSON 地址,格式如:
// ipfs://QmXxx.../1.json
// 或 https://api.project.com/token/1

// JSON 内容标准格式:
{
    "name": "Cool Cat #1234",
    "description": "A very cool cat",
    "image": "ipfs://QmXxx.../1.png",
    "attributes": [
        {"trait_type": "Background", "value": "Blue"},
        {"trait_type": "Fur", "value": "Golden"},
        {"trait_type": "Eyes", "value": "Laser"}
    ]
}

ERC1155 标准详解

为什么需要 ERC1155?

ERC721 的局限性
═══════════════════════════════════════════════════════════

问题1:每个 Token 独立合约调用
├── 批量转移 10 个 NFT = 10 次交易
├── Gas 成本高
└── 用户体验差

问题2:不支持同质化场景
├── 游戏里 1000 把相同的剑怎么办?
├── 每把剑都要独立 tokenId?
└── 浪费存储空间

问题3:一个合约只能一种资产
├── 想发行多种 NFT 需要多个合约
└── 管理复杂

ERC1155 解决方案:
├── 支持批量操作
├── 同一合约支持多种资产(FT + NFT)
└── 更省 Gas
═══════════════════════════════════════════════════════════

ERC1155 核心接口

interface IERC1155 {
    // 查询余额(某地址某类型代币的数量)
    function balanceOf(
        address account,
        uint256 id
    ) external view returns (uint256);

    // 批量查询余额
    function balanceOfBatch(
        address[] calldata accounts,
        uint256[] calldata ids
    ) external view returns (uint256[] memory);

    // 授权
    function setApprovalForAll(address operator, bool approved) external;
    function isApprovedForAll(address account, address operator) external view returns (bool);

    // 单个转移
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes calldata data
    ) external;

    // 批量转移 - 核心优势!
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) external;

    // 事件
    event TransferSingle(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256 id,
        uint256 value
    );

    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );
}

ERC1155 数据结构

ERC1155 存储结构
═══════════════════════════════════════════════════════════

核心映射:
┌─────────────────────────────────────────────────────────┐
│ mapping(uint256 => mapping(address => uint256))         │
│     private _balances;                                  │
│ // tokenId => 地址 => 数量                              │
│                                                         │
│ 例:                                                    │
│ _balances[1][Alice] = 100  // Alice 有 100 个 Token#1   │
│ _balances[1][Bob] = 50     // Bob 有 50 个 Token#1      │
│ _balances[2][Alice] = 1    // Alice 有 1 个 Token#2     │
└─────────────────────────────────────────────────────────┘

灵活性:
├── Token#1 可以是同质化的(供应量 10000)
├── Token#2 可以是非同质化的(供应量 1)
└── 同一个合约,不同类型共存

游戏场景示例:
├── Token#1: 金币(同质化,每人可有多个)
├── Token#2: 普通剑(半同质化,同款可有多把)
├── Token#1001: 传说武器(NFT,全服唯一)
└── 一个合约搞定所有道具!
═══════════════════════════════════════════════════════════

ERC721 vs ERC1155 对比

功能对比

核心差异对比
═══════════════════════════════════════════════════════════

│ 特性           │ ERC721              │ ERC1155              │
├────────────────────────────────────────────────────────────┤
│ 代币类型       │ 只支持 NFT          │ FT + NFT 都支持      │
│ 批量转移       │ ❌ 不支持           │ ✅ 原生支持          │
│ 批量查询       │ ❌ 不支持           │ ✅ 原生支持          │
│ Gas 效率       │ 较高                │ 更低(批量时)       │
│ 合约复杂度     │ 简单                │ 较复杂               │
│ 单独授权       │ ✅ 支持             │ ❌ 只有全局授权      │
│ ownerOf        │ ✅ 有               │ ❌ 没有              │
│ 生态支持       │ 更广泛              │ 逐渐增加             │
│ OpenSea 支持   │ ✅ 完全             │ ✅ 完全              │
└────────────────────────────────────────────────────────────┘
═══════════════════════════════════════════════════════════

场景选择

如何选择标准?
═══════════════════════════════════════════════════════════

选择 ERC721:
├── 每个代币必须完全独特
├── 头像 PFP 项目(BAYC、Azuki)
├── 艺术品 1/1
├── 域名(ENS)
├── 需要单独授权功能
└── 生态兼容性要求高

选择 ERC1155:
├── 游戏道具(多种类型 + 可堆叠)
├── 门票/会员卡(同类型多份)
├── 需要批量操作节省 Gas
├── 一个合约管理多种资产
├── 音乐/版权(多版次发行)
└── SFT 半同质化场景

实际案例:
├── CryptoPunks: 早期,非标准实现
├── BAYC: ERC721
├── Uniswap V3 LP: ERC721(每个仓位独特)
├── OpenSea Storefront: ERC1155
├── Enjin 游戏道具: ERC1155
└── Aavegotchi: ERC721 + ERC1155 混合
═══════════════════════════════════════════════════════════

Gas 对比

Gas 成本对比(估算)
═══════════════════════════════════════════════════════════

单次转移:
├── ERC721 transferFrom: ~65,000 gas
└── ERC1155 safeTransferFrom: ~52,000 gas
    节省约 20%

批量转移 10 个:
├── ERC721: 10 × 65,000 = 650,000 gas
└── ERC1155 safeBatchTransferFrom: ~120,000 gas
    节省约 80%!

Mint 操作:
├── ERC721 单个 mint: ~95,000 gas
├── ERC721 批量 mint 10 个: ~500,000 gas
└── ERC1155 批量 mint 10 个: ~150,000 gas

结论:
├── 单次操作:差异不大
└── 批量操作:ERC1155 显著更省
═══════════════════════════════════════════════════════════

链上实操:Mint 一个免费 NFT

方法 1:使用测试网 Mint

在测试网体验 NFT Mint
═══════════════════════════════════════════════════════════

1. 准备工作
   ├── MetaMask 切换到 Sepolia 测试网
   ├── 确保有测试网 ETH(从 faucet 领取)
   └── sepoliafaucet.com 或 Google "Sepolia faucet"

2. 找一个测试网 NFT 项目
   ├── 访问 testnets.opensea.io
   └── 搜索免费 mint 的 NFT

3. Mint 操作
   ├── 连接钱包
   ├── 点击 Mint
   ├── 确认交易
   └── 等待确认

4. 查看你的 NFT
   ├── 在 OpenSea 个人页面查看
   └── 或在 Etherscan 查看交易详情
═══════════════════════════════════════════════════════════

方法 2:阅读 NFT 合约

在 Etherscan 阅读 NFT 合约
═══════════════════════════════════════════════════════════

1. 打开知名 NFT 合约
   BAYC: 0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D

2. 点击 Contract → Read Contract

3. 尝试查询:
   ├── name(): 返回 "BoredApeYachtClub"
   ├── symbol(): 返回 "BAYC"
   ├── totalSupply(): 返回 10000
   ├── ownerOf(1): 返回 Token#1 的所有者
   └── tokenURI(1): 返回元数据地址

4. 点击 tokenURI 返回的链接
   └── 查看 JSON 格式的 NFT 属性

5. 思考问题:
   ├── 图片存在哪里?(IPFS/中心化服务器)
   ├── 如果服务器关闭会怎样?
   └── 如何保证 NFT 的永久性?
═══════════════════════════════════════════════════════════

今日思考

PM 视角的 NFT 产品设计

1. 存储问题

  • 图片存 IPFS 还是中心化服务器?
  • 元数据可以修改吗?
  • 用户能接受图片加载慢吗?

2. Gas 优化

  • 如何降低用户 Mint 成本?
  • 批量操作用 ERC1155?
  • Lazy Minting(延迟铸造)?

3. 用户体验

  • 非 Crypto 用户如何理解 NFT?
  • 如何解释 Gas 费用?
  • 钱包连接流程如何简化?

面试题准备

问题:ERC721 和 ERC1155 有什么区别?如何选择?

30秒版本:
═══════════════════════════════════════════════════════════
ERC721 是 NFT 标准,每个代币独一无二;ERC1155 是多代币标准,
支持同质化和非同质化代币共存,并且支持批量操作更省 Gas。

选择建议:独特的 PFP/艺术品用 721,游戏道具/门票等需要批量
操作的用 1155。
═══════════════════════════════════════════════════════════

2分钟版本:
═══════════════════════════════════════════════════════════
核心区别:

ERC721:
- 每个 tokenId 对应唯一的所有者
- 有 ownerOf() 函数查询所有者
- 不支持批量转移
- 适合独特资产:头像、艺术品、域名

ERC1155:
- 每个 tokenId 可以有多个持有者和数量
- 用 balanceOf(address, id) 查询
- 支持批量转移,批量时节省 80% Gas
- 适合游戏道具、门票、版权等

实际案例:
- BAYC、CryptoPunks:ERC721(每只猴子独特)
- Uniswap V3 LP:ERC721(每个仓位独特)
- 游戏道具:ERC1155(同款剑可以有多把)
- OpenSea Storefront:ERC1155

产品选择考量:
1. 资产是否必须完全独特?
2. 是否需要批量操作?
3. 是否需要同一合约管理多种资产?
4. 生态兼容性要求?

大多数 PFP 项目选 ERC721,因为每个头像的唯一性是核心价值。
游戏类项目选 ERC1155,因为需要多种道具和批量操作。
═══════════════════════════════════════════════════════════

学习资源

资源链接说明
EIP-721eips.ethereum.org/EIPS/eip-721官方标准
EIP-1155eips.ethereum.org/EIPS/eip-1155官方标准
OpenZeppelindocs.openzeppelin.com标准实现库
OpenSea 文档docs.opensea.ioNFT 市场标准

明日预告

Day 23: NFT 市场机制
├── 版税机制 (EIP-2981)
├── 稀有度计算方法
├── OpenSea vs Blur 对比
├── NFT 市场产品分析
└── 体验 OpenSea/Blur