EIP-721ERC代币标准Final(2018-01-24)非同质化代币(NFT)标准
每个 tokenId 唯一、不可互换的所有权标准。核心是 ownerOf + 安全转账 + 授权与元数据扩展。
适用链:全部 EVM 链 + 各 L2
为什么重要:NFT 的「唯一性」不是靠图片,而是靠链上 tokenId 到 owner 的映射。看懂 ERC-721 就能一眼分辨「真上链的藏品」和「只是一张指向服务器的图片链接」。
函数签名与选择器
选择器是签名的 keccak256 前 4 字节;事件则是完整的 32 字节 topic0。 点一下即可复制。
| 签名 / 字段 | 选择器 / topic0 | 说明 |
|---|---|---|
| balanceOf(address) | 该地址持有的 NFT 数量,不是 tokenId 列表。 | |
| ownerOf(uint256) | tokenId 的持有人。不存在的 tokenId 必须 revert。 | |
| transferFrom(address,address,uint256) | 直接转移,不检查接收方是否支持(转进合约可能永久锁死)。 | |
| safeTransferFrom(address,address,uint256) | 推荐用法:接收方是合约时会调用 onERC721Received 检查。 | |
| safeTransferFrom(address,address,uint256,bytes) | 带额外 data,用于传递业务上下文。 | |
| approve(address,uint256) | 授权单个 tokenId 给某人。 | |
| setApprovalForAll(address,bool) | 授权全部藏品给某操作者,NFT 市场靠它挂单,也是被盗重灾区。 | |
| getApproved(uint256) | 查询单个 tokenId 的授权对象。 | |
| isApprovedForAll(address,address) | 查询操作者是否被全局授权。 | |
| supportInterface(bytes4) | EIP-165:声明自己实现了 ERC-721 与 Metadata 扩展。 | |
| tokenURI(uint256) | Metadata 扩展:返回元数据 JSON 的 URI。 | |
| event Transfer(address,address,uint256)事件 | 与 ERC-20 同名但语义不同:第三个参数是 tokenId。 |
代码模板
最小实现(含 safeTransferFrom 接收检查)
最小实现(含 safeTransferFrom 接收检查)Solidity
转移时 delete _tokenApprovals 是必需的安全动作。漏掉它会让上一任 owner 给的授权在换手后依然有效。
元数据 JSON 的结构
元数据 JSON 的结构JSON
image 用 ipfs:// 而不是 https://,是区分「不可篡改」与「随时能换图」的关键信号。
实现与使用时的常见陷阱
- ✕setApprovalForAll 一旦授权,对方能搬走你该系列的全部藏品。挂单完成后及时撤销,或使用支持「限价单委托」的市场。
- ✕tokenURI 指向中心化服务器时,项目方随时能换掉图片,链上只留一个 tokenId。
- ✕transferFrom 不检查接收方,转进不支持 ERC-721 的合约会永久锁死;一律优先用 safeTransferFrom。
- ✕实现 Metadata 扩展时 tokenURI 必须对不存在的 tokenId revert,返回空字符串会让市场显示成「无元数据」。
- ✕supportsInterface 要返回 true 的 id 必须与实际实现一致,否则部分市场会拒绝展示。
相关标准
同属「代币标准」的其他标准