尧图精选

ERC20、ERC721、ERC1155怎么选?三大代币标准的底层逻辑与实战指南

🕒 发布时间:2026/10/2 19:54:36 📁 来源:尧图网络
如果你早几年进入Web3开发圈一定躲不开一个问题给项目设计代币系统ERC20、ERC721、ERC1155到底怎么选我第一次做数字藏品合约时总想着把ERC20的代码改一改、加个tokenId就行了结果不但gas烧得厉害还搞得用户余额和资产归属一团乱。后来我才想明白这三个标准不是版本越新越高级而是每一代都对应一个具体的现实痛点。这篇文章我就把三套标准的底层逻辑、接口差异、实战坑位和选型思路一次讲透希望对正在做合约开发或准备发行资产的你有点参考价值。1. 从币、猫到游戏背包三种代币标准各自解决了什么问题1.1 ERC20让发币这件事从各自为政变成有章可循在ERC20出现之前以太坊上的每个项目方想发行代币基本上都是自己写一套转账逻辑。有的合约叫transfer有的叫sendTokens有的干脆只允许管理员手动记账。那时候的钱包和交易所要支持一个新代币就得专门写适配代码集成成本高得离谱。ERC20做的最重要的一件事就是给同质化资产定了一套统一接口totalSupply、balanceOf、transfer、transferFrom、approve、allowance。只要合约实现了这些函数钱包、去中心化交易所、扫码支付工具就能立刻认识它。你可以把ERC20想象成官方印制的货币每张10元纸币和另一张10元纸币在价值上完全等价用户只关心我钱包里有多少个不关心我拥有的是哪一串编号。这一套设计天然适合支付、积分、治理投票这类场景。也正是因为接口足够简单后来市面上绝大多数的治理代币、稳定币、DeFi项目里的LP份额都跑在ERC20这套标准上。它的生态完善程度到现在仍然是三种标准里最高的。1.2 ERC721独一无二的资产需要能指认的身份2017年底加密猫CryptoKitties把以太坊主网堵得水泄不通也让开发者第一次意识到一个问题有些资产是没法用余额来描述的。加密猫里的每只猫都有不同的基因、不同的外观、不同的稀有度两只猫不能直接等价互换。如果强行用ERC20来表示你能做的最多是给每只猫分配一个编号然后让合约维护编号到余额的映射。但这样既低效也无法简洁回答这只猫现在归谁所有这个关键问题。ERC721于是引入了ownerOf(tokenId)这个视角每种资产都有自己的唯一ID合约里记录的不再是某地址有多少个代币而是某个ID当前归属哪个地址。你可以把ERC721理解成演唱会门票每张票对应不同的座位区、排数和座位号票之间天然不可互换。它天然适合数字藏品、身份凭证、域名、票据、会员资质这类每个个体都有独立属性的资产。后来NFT市场爆发OpenSea这些平台默认支持的就是ERC721整个围绕稀缺性、收藏、拍卖的生态也是在这套标准上长出来的。1.3 ERC1155一个合约装下整个游戏的松一口气游戏开发者很快发现事情仍然麻烦。一个链游里往往同时存在多种资产金币是无限可分、同质化的药品可以有好几个但属性相同武器则是独一无二的。如果用ERC20放金币、用ERC721放武器还再部署一两个合约放其他道具那跨合约转账、授权、查询余额全都绕来绕去gas开销和管理成本都让人头疼。ERC1155被设计出来的目的就是在一个合约里同时管理同质化和非同质化资产。它引入了一个双重维度id代表资产种类account代表持有者。同一个id下可以有很多个数量就像游戏背包里的金币栏显示的是数字也可以每个id的数量固定为1这样就等价于一件独一无二的装备。更关键的是ERC1155原生支持批量操作一次safeBatchTransferFrom就能同时转多种资产一次balanceOfBatch就能查多个地址的多种余额。这背后还有一个很实际的好处批量转账可以显著减少链上交易次数省gas也省用户等待时间。当你要做一个包含大量道具、材料、合成系统的游戏时这套标准基本是唯一的理性选择。2. 技术骨架拆解余额模型、授权逻辑与转账语义到底差在哪2.1 三种余额存储模型对照很多初学者困惑的是为什么有的标准用balanceOf有的标准却用ownerOf。核心差异其实在数据结构的维度上。ERC20的存储模型是地址到余额的单层映射mapping(address uint256) private _balances;它适合回答某地址有多少币。所有代币没有个体差异所以不需要第二个维度。ERC721的存储模型是代币ID到地址的映射外加一个辅助的持有数量统计mapping(uint256 address) private _owners; mapping(address uint256) private _balances; // 该地址拥有的NFT数量它适合回答某个特定资产现在在谁手里。注意这里_owners才是核心数据_balances只是为了快速统计数量而存在的冗余索引。ERC1155则用一个双重映射同时表达两种性质mapping(uint256 mapping(address uint256)) private _balances;_balances[id][account]的值代表某个账号拥有多少个id类别的资产。如果这个值只允许是0或1那么这个id就表现为非同质化资产如果这个值可以很大那它表现为同质化资产。一个合约里可以同时存在这两种类型的id因此它叫Mixed Fungibility Standard。下表可以做一个快速对照维度ERC20ERC721ERC1155资产性质全同质化全非同质化同质化非同质化混合核心数据地址余额所有者映射ID地址双重映射唯一标识无tokenIdid查询函数balanceOf(address)ownerOf(tokenId)balanceOf(account, id)典型场景代币、积分、治理收藏品、身份、域名游戏道具、多资产组合2.2 授权机制从approve到setApprovalForAll授权机制解决的是用户不想每次都直接发起转账的问题。当你挂单到一个NFT交易市场或者把代币存入DeFi协议时合约需要提前获得替你转移资产的许可。ERC20的做法是approve(spender, amount)只批准某个额度。每次第三方想花你的钱就调用transferFrom消耗对应的allowance余额。这套模型适合额度可控的托管场景比如DEX用你的额度去拉取你计划卖出的币。ERC721面临一个麻烦代币数量可能成千上万如果每个token都要单独approve操作成本很高。所以它提供了两个层次——单点授权approve(spender, tokenId)让指定地址可以操作某一个具体资产整体授权setApprovalForAll(spender, approved)让某个地址可以操作你名下的所有NFT。市场类合约几乎都要求后者因为挂单时你还没决定具体卖哪个交给市场合约统一处理更顺。ERC1155没有单点授权只有setApprovalForAll(operator, approved)。原因很直接一个ERC1155合约里可能同时存在无数个id如果每次都要对具体某个id单独授权批量转账的优势就全没了。整体授权配合批量查询、批量转账才能构成完整的操作闭环。这一点经常被从ERC721转过来的开发者忽略在ERC1155里找不到approve(tokenId)如果你试图实现按id授权其实是偏离标准设计的。2.3 转账函数与安全回调的差异三个标准都提供了转给指定地址的接口但安全级别差别很大。ERC20的transfer和transferFrom非常简单从A向B转移余额然后完事。它不检查B是不是合约、合约能不能处理这笔代币。这个设计有历史原因ERC20诞生时链上应用还很原始没人想到代币会被转进一个没有处理逻辑的合约里。后果就是海量资产被永久锁在错误合约中至今还在持续发生。ERC721意识到了这个问题于是新增了safeTransferFrom。它会把代币转给目标地址然后要求如果目标地址是合约必须实现了onERC721Received函数否则本次转账直接回滚。这个安全回调机制相当于在转账后敲门问一句“你能接收吗”能避免把NFT发到一个黑洞合约里。需要注意的是标准里还有一个裸的transferFrom它不做回调检查很多代码库为了省gas会绕开安全版本但这是非常危险的操作习惯。ERC1155把回调机制做成了标配safeTransferFrom要求接收方实现onERC1155ReceivedsafeBatchTransferFrom要求实现onERC1155BatchReceived。同时它还允许接收方在回调函数里立即做出响应这为转账后自动处理打开了空间比如自动质押、自动拆分组合等高级玩法。3. 实现和交互中最容易踩的几个坑3.1 approve竞态条件ERC20用户的经典翻车现场ERC20这套授权模型虽然简单却有一个历史遗留问题额度变更的顺序竞争。假设你之前给某个DeFi协议授权了100个币现在想把额度改成50。你正常会调用approve(protocol, 50)。问题在于以太坊是公开内存池谁先打包谁先执行。如果协议方比你先执行了transferFrom(yourAddress, protocolAddress, 100)那你的旧额度100就被花光了。紧接着你的approve(protocol, 50)被打包这种情况下协议方手里又拿到了50个新额度可能在你还没反应过来的情况下继续转走50个。这就是所谓的approve竞态条件Race Condition。OpenZeppelin给出了一个标准解法增加increaseAllowance和decreaseAllowance函数。它们会让额度在原有基础上做增量或减量而不是直接覆盖为某个新值从机制上避免了改额度时被插队的风险。如果你在写合约时选择自己实现ERC20而非使用现成库一定要同时实现这两个增量接口或者强制要求UI端先approve(0)再approve(n)。后者体验比较差但不至于丢资产。3.2 转错地址与安全转账的正确使用姿势很多人在实际开发中已经知道要用safeTransferFrom但仍会在某些环节踩坑最常见的是为了省一次SLOAD而直接调用transferFrom。ERC721标准里确实保留了不带回调检查的transferFrom可一旦目标地址是个合约且没有实现接收接口资产就永久锁死在那个合约里。我遇到过的一个案例是某个代理合约的结算逻辑从用户A转NFT给用户B本来应该调safeTransferFrom但因为合约里用的是transferFrom恰好B是一个尚未部署接收逻辑的多签钱包结果NFT直接被转到多签合约地址谁也无法把它取出。最后只能通过硬分叉级别的社区治理解决。所以我的习惯是任何面向用户资产的转移一律使用safeTransferFrom或等价的安全逻辑。只有内部合约之间转移、并且你完全信任接收方处理能力时才考虑用transferFrom等裸转账接口。ERC1155的批量操作也同样safeBatchTransferFrom会逐个检查每个接收方单个失败则整体回滚这能很大程度避免部分资产转出、部分资产留存的半完成状态。3.3 tokenURI只是指针别指望它永垂不朽NFT的元数据图片、描述、属性通常不是直接存在链上的。ERC721和ERC1155的tokenURI(tokenId)返回的是一个URI字符串指向链下的JSON文件。链上只保存这个指针所以合约本身并不能保证元数据永远可访问。很多项目把元数据放在自己的中心化服务器上项目方关停或迁移服务器后NFT在钱包里就只剩一个空壳。稍微讲究一点的项目会放到IPFS上但IPFS默认也不保证永久在线需要配合Pin服务或专门的持久化存储方案。更极端的情况是有些项目在发布后修改元数据内容让同一个tokenId的图片悄悄换掉这就是常说的rug metadata。作为一个开发者我在发行NFT前会至少做两件事一是明确元数据存储的持久性方案能用IPFS加Pin服务就不要把鸡蛋放在一台服务器里二是在合约里考虑是否需要限制管理员修改URI的权限边界比如通过治理投票或时间锁来约束避免项目方随手改图。3.4 只读重入与状态变化的边界提到重入很多人第一反应是跨函数递归调用。但只读重入是更隐蔽的一种攻击者在一个safeTransferFrom的接收回调里对另一个合约发起一个看起来只读的查询而这个查询的结果又反过来影响当前合约的状态判断。比如某个借贷协议需要检查NFT的当前所有者来判断是否清算。正常情况下没有问题但如果它把“当前所有者是谁”作为清算依据攻击者就可以在NFT转移回调中制造一个状态快照诱导协议根据错误的所有者身份做借贷决策。以太坊上很多早期NFT借贷协议都吃过这种亏。应对思路总结起来就是三条第一涉及NFT跨合约调用的关键函数尽量加上可重入锁比如OpenZeppelin的ReentrancyGuard第二不要在回调执行期间依赖动态可变的NFTownerOf结果做核心决策需要的话先把所有者和相关状态锁定在本地变量中第三对safeTransferFrom接收方执行的回调要保持警惕默认情况下认为它可能做任何事。4. 选型的时候我在想什么场景拆分与最佳实践4.1 什么场景闭眼选ERC20如果你要发的资产是纯粹同质化的、可分割的、不关心个体差异的那就直接选ERC20。典型场景包括治理投票代币、平台积分、支付结算代币、稳定币、DeFi里的收益份额凭证。它的优势是生态兼容性无可匹敌。中心化交易所、去中心化交易所、钱包、指数平台、各类聚合器默认支持的都是ERC20。你的代币只要实现标准接口就能以最低成本接入几乎所有金融基建。如果你为了玩法多样而给纯积分系统套上ERC721后面做流动性池、上币、搞价格预言机都会非常痛苦。4.2 什么场景把ERC721作为第一选择当每个资产都有独立属性、稀缺性、并且可能被单独交易和收藏时ERC721是不二之选。典型场景数字藏品、加密艺术、域名ENS、身份凭证、票据、会员卡、元宇宙地块。ERC721生态里最成熟的是二级市场交易和拍卖协议。OpenSea、Blur这些平台拥有巨大的ERC721交易深度用户也早已形成这个标准代表收藏品的心理认知。而且ownerOf的表达力非常直接任何合约都可以方便地回答某个特定资产属于谁这种语义在版权登记、溯源、授权许可等场景非常有价值。4.3 ERC1155能解决哪些ERC721解决不了的问题很多开发者接触ERC1155之后才意识到之前用多个ERC721合约管理游戏资产是多么笨拙。ERC1155最典型的杀手级场景是游戏和经济系统富集在同一类体系下的多种资产。举个例子一个游戏里有金币、红药水、蓝药水、武器、防具。金币显然应该同质化药水同质化但数量多武器可能每把都有独特属性。如果用ERC721武器和药水都要一个个部署合约或者在一个合约里模拟复杂映射如果用ERC1155全部资产装进一个合约每种资产对应一个id批量合成、批量兑换、批量上架只需要一次调用。ERC1155还有一个容易被低估的特性半同质化Semi-Fungible。同一个id的资产可以有多个副本每个副本本身等价但它们和另一个id的资产不等价。这非常适合处理同一场演唱会的VIP票这一场次的所有VIP票价值相同但和普通票、其他场次的VIP票价值不同。这个模型在ERC20和ERC721里都很难优雅表达。4.4 混合标准方案和我的个人习惯实际项目里三个标准不一定非要用一个、排斥另外两个。一个完整的应用经常是组合使用治理代币用ERC20身份或者成就徽章用ERC721应用内的经济物品用ERC1155最后通过一个统一的资产管理合约来控制跨标准流转。在动手写合约之前我会先问自己三个问题第一这个资产可分割吗可分割意味着同质化倾向优先考虑ERC20或ERC1155的某个id。第二每个资产是否要作为独立个体被收藏、交易、追溯如果是考虑ERC721。第三这个系统里资产种类多不多、批量操作频率高不高如果多且高优先考虑ERC1155节省gas。从这几年的实践看ERC20的使用场景没有缩水但ERC1155的增长非常明显。越来越多的项目方在规划阶段就把游戏内资产、市场交易、跨应用互操作放在一起考虑而不是先发一个孤立的ERC721系列品相。如果你是刚开始做合约开发我建议你至少把ERC1155吃透它代表的是更现代的资产组织方式。我个人的体会是选标准别跟风也别追求新就是好。资产标准本质上是数据结构和接口契约的组合先想清楚你的资产形态、用户交互和生态集成需求再回头看这三个标准答案往往已经很清晰了。把每个标准背后的设计动机搞明白写合约的时候自然会少走很多弯路。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →