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;
}

嗯,这里要注意:ownerOfbalanceOf 是最常用的两个查询函数。我在项目中遇到过很多新手搞混这两个——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 项目的核心价值所在。到时候我会拿我实际做过的项目代码来拆解,保证干货满满。