上链ON-CHAIN BLOCK 15 / 26
卷三 · 合约工程BLOCK 15

ERC-721 与 NFT


如果 ERC-20 是"每个币都一样"(fungible,像现金),那 ERC-721 就是"每个都独一无二"(non-fungible,像房产证)。把上一章的余额表换成"tokenId → 拥有者"的映射,NFT 的核心就出来了。这一章讲它的实现、那张常被误解的图片到底存在哪、以及市场是怎么运转的。

从"数量表"到"归属表"

ERC-20 记录 address → 数量。ERC-721 记录 tokenId → owner:每个 NFT 有唯一的 tokenId,归属被单独追踪。

Solidity · 核心存储对比
// ERC-20:谁有多少(可分割、无差别)
mapping(address => uint256) balanceOf;

// ERC-721:每个独一无二的 token 归谁(不可分割)
mapping(uint256 => address) ownerOf;      // tokenId → 拥有者
mapping(address => uint256) balanceOf;    // 地址持有几个(计数)
mapping(uint256 => address) getApproved;   // 单个 token 的授权
Android 类比

ERC-20 像 Map<User, Int>(每人一个可加减的数量);ERC-721 像 Map<SerialNumber, Owner>(每个序列号对应一个主人)。转 NFT 就是把某个 tokenId 的 owner 从 A 改成 B——又是改一行数字,只不过这次改的是"归属"而非"数量"。

mint:凭空造一个 NFT

Solidity · 基于 OpenZeppelin
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

contract MyNFT is ERC721 {
    uint256 public nextId;

    constructor() ERC721("MyNFT", "MNFT") {}

    function mint() external {
        _safeMint(msg.sender, nextId);  // 造出 tokenId=nextId,归调用者
        nextId++;
    }
}

_safeMint 里的 "safe" 有实义:如果接收方是合约,它会检查对方是否实现了 onERC721Received 回调,防止 NFT 被打进一个不会处理它、导致永久锁死的合约。这个"收款方要能接住"的设计,后面很多标准都借鉴了。

那张图片,到底存在哪?

最大的认知误区:NFT 合约里几乎不存图片。链上存的只是一个 tokenURI——一个指向"元数据(metadata)"的链接。元数据是一段 JSON,里面才有名字、属性、和图片的地址。

tokenURI 指向的 metadata JSON
{
  "name": "Cyber Cat #42",
  "description": "A very on-chain cat",
  "image": "ipfs://Qm.../42.png",       // 图片本体在别处
  "attributes": [{ "trait_type": "Color", "value": "Green" }]
}

链上 = 归属证明(你拥有 tokenId 42);图片和元数据 = 存在别处。存哪很关键:

存储方式去中心化程度风险
中心化服务器(https://…)项目方跑路/关服,图就没了(所谓"月球地契"骗局常此)
IPFS(内容寻址)需有人持续 pin,否则可能失效,但地址即哈希不可掉包
Arweave(永久存储)较高一次付费永久存,较可靠
完全上链(SVG 存 storage)最高最贵,但图随合约永存
风险记账

买 NFT 前该看它的元数据存哪。若 image 指向某个公司的普通服务器,那么你"永久拥有"的其实只是链上一个指向可能随时 404 的链接的指针。真正抗审查的项目会用 IPFS/Arweave,甚至把 SVG 完全塞进合约。"链上艺术"和"链下托管、链上只存链接"是两码事,别混为一谈。

市场与版税

NFT 交易市场(OpenSea、Blur 等)本身也是合约。挂单卖出的机制,底层就是第 14 章的授权模型:你 approve 市场合约操作你的 NFT,买家付款时市场合约用 transferFrom 把 NFT 转给买家、把钱转给你。版税(royalty)则由 ERC-2981 标准约定:合约提供一个"这笔交易该给创作者抽成多少"的查询函数,但注意——它只是建议,市场可以不遵守,链上无法强制。近年很多市场为竞争把版税设为可选,这是创作者要认清的现实。

ERC-1155:多合一

还有个常见标准 ERC-1155,一个合约里同时管"同质"和"非同质"资产——比如游戏里,"金币"(可堆叠、同质)和"传说之剑"(唯一)可以在同一个合约里,批量转移还更省 gas。游戏和多资产项目常用它。你理解了 20 和 721,1155 就是二者的融合体。

要点入账

NFT 祛魅:ERC-721 = 一张 tokenId→owner 的归属表 + 一个指向链下元数据的 tokenURI。合约证明的是"谁拥有哪个编号",图片本身往往在 IPFS/Arweave 或(危险地)某台服务器上。市场交易复用 approve/transferFrom 授权模型,版税只是不可强制的约定。看一个 NFT 是否"真去中心化",就看它的元数据和图存在哪。卷三收尾还剩两章硬骨头——安全与可升级,它们决定你的合约能不能在这个没有回滚按钮的世界里活下来。

本章小结

◆ 返回目录