1. NFT基础概念:什么是NFT、ERC-721标准、ERC-1155标准、NFT元数据与URI
好,咱们直接进入正题。
NFT,全称是 Non-Fungible Token,中文叫「非同质化代币」。说白了,就是每个代币都是独一无二的,不能像比特币那样「你给我一个,我还你一个,大家没区别」。你想想看,你手里的 CryptoPunk #5822 和我手里的 #3100,能一样吗?完全不一样。
我最早接触 NFT 是在 2017 年的 CryptoKitties 项目。那时候整个以太坊都被猫堵死了,gas 费飙到天上。我当时就在想:这东西到底有什么魔力?后来我明白了——它让数字资产第一次有了「稀缺性」和「所有权」的概念。
ERC-721 标准
ERC-721 是 NFT 的鼻祖标准。2018 年由 Dieter Shirley 等人提出,后来成了以太坊上的正式标准(EIP-721)。
它的核心思想很简单:每个 token 都有一个唯一的 tokenId。这个 ID 从 0 到 2^256-1,理论上够你用几辈子。
我给你们看一个最简化的 ERC-721 合约核心接口:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IERC721 {
function balanceOf(address owner) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function transferFrom(address from, address to, uint256 tokenId) external;
function safeTransferFrom(address from, address to, uint256 tokenId) external;
}
嗯,这里要注意:ownerOf 和 balanceOf 是最常用的两个查询函数。我在项目中遇到过很多新手搞混这两个——ownerOf 查的是某个 token 属于谁,balanceOf 查的是某个人有多少个 token。
关键点:ERC-721 的 tokenId 是全局唯一的。同一个合约里,不可能有两个 token 拥有相同的 ID。这是 NFT「非同质化」的根本保证。
ERC-1155 标准
ERC-1155 是 2019 年由 Enjin 团队提出的多代币标准。它解决了一个实际问题:游戏里既有「武器」(每个武器独一无二),又有「金币」(所有金币都一样),难道要部署两个合约?
ERC-1155 说:不用。一个合约搞定所有。
它的核心设计是:每个 token 都有一个 id,但 id 可以代表「同质化」或「非同质化」的资产。怎么区分?看 supply(总供应量)。
- 如果某个 id 的 supply = 1,那它就是 NFT
- 如果某个 id 的 supply > 1,那它就是 FT(同质化代币)
我给你们看一个典型的 ERC-1155 批量铸造代码:
function batchMint(
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) external {
for (uint i = 0; i < ids.length; i++) {
_mint(to, ids[i], amounts[i], data);
}
}
我个人习惯在游戏类项目里优先用 ERC-1155。为什么?因为 gas 费省太多了。一次交易可以铸造 100 种不同的道具,而 ERC-721 得交易 100 次。
实战建议:如果你的项目里既有「稀有装备」(每个都不同)又有「普通材料」(都一样),用 ERC-1155 准没错。我去年帮一个链游项目做合约,从 ERC-721 迁移到 ERC-1155 后,gas 费直接降了 70%。
NFT 元数据与 URI
好,现在到了最容易被忽视但极其重要的部分——元数据。
你想想看,区块链上存的是什么?是 tokenId 和 owner 的映射关系。那图片呢?名字呢?属性呢?这些都不在链上(除非你用昂贵的 calldata 存)。
解决方案就是:链上只存一个 URI(统一资源标识符),指向链下的元数据文件。
ERC-721 和 ERC-1155 都定义了 tokenURI(uint256 tokenId) 函数。这个函数返回一个字符串,通常是一个 HTTP 链接或 IPFS 链接。
元数据文件长什么样?标准格式是 JSON:
{
"name": "CryptoPunk #5822",
"description": "一个戴着太阳镜的像素外星人",
"image": "ipfs://QmX...",
"attributes": [
{"trait_type": "Type", "value": "Alien"},
{"trait_type": "Accessory", "value": "Sunglasses"},
{"trait_type": "Skin", "value": "Green"}
]
}
这里有个坑,我曾经踩过:元数据一旦上链,就不能改了(除非你用了可升级的代理合约)。所以铸造前一定要检查 JSON 格式对不对、图片链接能不能访问。
避坑指南:我曾经帮一个项目做审计,发现他们的 tokenURI 返回的是 https://myapi.com/metadata/{tokenId}。这看起来没问题对吧?但问题是,这个 API 是中心化的!如果服务器挂了,所有 NFT 都变成「白板」。后来我建议他们改用 IPFS 存储,永久可用。
关于 URI 的存储方式,目前主流有三种:
| 存储方式 | 优点 | 缺点 |
|---|---|---|
| HTTP 链接 | 方便更新,速度快 | 中心化,单点故障 |
| IPFS | 去中心化,内容寻址 | 需要 pin 服务,速度稍慢 |
| 链上存储 | 完全去中心化 | gas 费极高,数据量受限 |
我个人最推荐的做法是:元数据用 IPFS 存,但用一个中心化的网关做缓存。这样既保证了数据的永久性,又保证了访问速度。
最后说一句:tokenURI 这个函数名在 ERC-1155 里变成了 uri(uint256 id),但功能是一样的。别搞混了。
总结一下:
- NFT = 独一无二的数字资产,用 tokenId 区分
- ERC-721 = 每个 token 一个 ID,适合纯 NFT 项目
- ERC-1155 = 一个合约管理多种资产,适合游戏/多品类项目
- 元数据 = 描述 NFT 的 JSON 文件,通过 URI 链接到链上
- URI 存储 = 推荐 IPFS + 网关缓存
嗯,这一章就到这里。下一章咱们会深入讲「稀有度算法」——这才是 NFT 项目的核心价值所在。到时候我会拿我实际做过的项目代码来拆解,保证干货满满。