1. NFT基础概念与合约架构

大家好,我是你们的老朋友。今天咱们来聊聊NFT合约的基础知识。说实话,我见过太多人一上来就冲进NFT市场,结果连ERC-721和ERC-1155都分不清——嗯,这其实挺危险的。我自己在审计合约时,就遇到过因为标准选错导致项目重写的案例。

什么是NFT?

NFT,全称是Non-Fungible Token,中文叫「非同质化代币」。说白了,它就是区块链上独一无二的数字资产。你想想看,比特币、以太坊这些是同质化的——你手里的一个BTC和我手里的一个BTC完全一样,可以互换。但NFT不一样,每个都是唯一的,就像你家的猫和我家的猫,虽然都是猫,但长得不一样。

我个人习惯把NFT理解成「数字世界的房产证」。它证明你对某个数字内容拥有所有权。这个内容可以是图片、音乐、视频,甚至是一段文字。我在项目中遇到过有人把推特内容铸造成NFT,结果还真卖出去了——嗯,这世界就是这么神奇。

ERC-721与ERC-1155标准对比

这两个标准是NFT合约的基石。我刚开始接触时也搞混过,后来踩了几个坑才彻底明白。

特性 ERC-721 ERC-1155
代币类型 每个代币唯一 支持同质化+非同质化
批量操作 不支持 支持批量铸造/转账
Gas成本 较高(逐个操作) 较低(批量分摊)
适用场景 数字艺术品、收藏品 游戏道具、多品类资产
合约复杂度 简单 中等

为什么会有两个标准?其实ERC-721是最早的NFT标准,2018年就出来了。后来大家发现游戏里需要同时管理多种资产,比如武器、皮肤、金币,如果每个都单独部署一个ERC-721合约,那Gas费会高得吓人。于是ERC-1155应运而生,它用一个合约管理所有资产类型。

我记得有一次审计一个游戏项目,他们用了ERC-721来管理游戏里的100种道具。结果每次玩家交易道具,都要部署新的合约实例——这简直是灾难。后来我建议他们换成ERC-1155,Gas费直接降了70%。

核心区别一句话总结:ERC-721是「一个合约一种资产」,ERC-1155是「一个合约多种资产」。选哪个,取决于你的业务场景。

NFT合约核心函数解析

不管用哪个标准,有三个函数你必须要搞懂:mint、transfer、burn。这三个函数构成了NFT的生命周期。

1. mint(铸造)

铸造就是把NFT从无到有创造出来。这是整个合约的入口,也是最容易出问题的地方。

// ERC-721 标准铸造函数
function mint(address to, uint256 tokenId) external {
    require(msg.sender == owner, "只有合约所有者才能铸造");
    _safeMint(to, tokenId);
}

这里有个坑:_safeMint_mint的区别。我刚开始写合约时用了_mint,结果有用户把NFT转到了合约地址,直接锁死了。后来我才知道,_safeMint会检查接收方是不是合约,如果是合约,必须实现onERC721Received接口,否则交易回滚。嗯,这个教训让我记住了。

避坑指南:我曾经审计过一个项目,他们的mint函数没有做总量限制。结果有人写了个脚本,一次性铸造了10万个NFT,直接把合约的存储撑爆了。所以,mint函数一定要加maxSupply检查。

2. transfer(转账)

转账是NFT流通的核心。ERC-721提供了两种方式:transferFromsafeTransferFrom

// ERC-721 标准转账函数
function transferFrom(address from, address to, uint256 tokenId) external {
    require(_isApprovedOrOwner(msg.sender, tokenId), "你没有权限");
    _transfer(from, to, tokenId);
}

你想想看,为什么要有两个?transferFrom是基础版,它不会检查接收方。而safeTransferFrom会调用接收方的回调函数。我个人习惯在公开接口里只用safeTransferFrom,因为安全第一。

这里有个经典漏洞:重入攻击。攻击者可以在转账回调函数里再次调用转账,导致资产被多次转移。解决方案很简单——使用OpenZeppelin的ReentrancyGuard,或者先更新状态再转账。

3. burn(销毁)

销毁就是把NFT从流通中永久移除。这个函数看似简单,但很多人会忽略一个重要问题:销毁后,元数据怎么办?

// ERC-721 标准销毁函数
function burn(uint256 tokenId) external {
    require(_isApprovedOrOwner(msg.sender, tokenId), "你没有权限");
    _burn(tokenId);
}

我记得有个项目,用户销毁NFT后,对应的元数据URI还在IPFS上存着。结果有人通过URI找到了原始图片,直接复制粘贴,搞得社区一片混乱。所以,我建议在销毁时,最好把元数据也标记为「已销毁」。

个人经验:我在审计时发现,很多项目把burn函数设成了公开的,任何人都可以调用。这其实很危险。正确的做法是:只有合约所有者或者经过授权的地址才能销毁。或者,你可以设计一个「销毁冷却期」,防止误操作。

知识体系结构图

下面这张图是我自己画的,帮你理清NFT合约的核心脉络:

NFT合约核心知识体系 选择标准:ERC-721 vs ERC-1155 三大核心函数:mint → transfer → burn mint 总量限制 权限控制 transfer 安全转账 防重入 burn 元数据清理 权限验证 安全要点:权限检查 | 重入防护 | 总量控制 | 元数据管理

这张图把NFT合约的核心脉络理清楚了。从上到下,先选标准,再实现三个核心函数,最后别忘了安全防护。每一步都有坑,但只要你按这个框架来,基本不会出大问题。

好了,这一章的内容就到这里。记住,NFT合约看似简单,但细节决定成败。下一章我们会深入分析常见的NFT合约漏洞,到时候我会分享更多实战案例。

本章核心要点:

  • NFT是独一无二的数字资产,用ERC-721或ERC-1155标准实现
  • ERC-721适合单一资产,ERC-1155适合多品类资产
  • mint函数必须加总量限制和权限控制
  • transfer函数优先使用safeTransferFrom防丢失
  • burn函数要清理元数据,防止信息泄露

专注资料整理