# 从ERC-20到ERC-3525，浅谈标准代币合约的用例和发展

By [ViaBTC Capital](https://paragraph.com/@viabtc-capital) · 2022-11-02

---

引言
--

相信大家一定都对代币和NFT非常熟悉了，也知道它们背后的经典代币标准，如ERC-20和ERC-721等。ERC-20是同质化代币，而ERC-721是非同质化的，非常适合用于艺术品或者具备稀缺性的资产。但是这些代币是如何实现的呢？为什么就能适合于相关的应用呢？

这篇文章就带大家来盘点一下这些代币合约的原理、适用范围以及未来的发展趋势，涵盖标准包括ERC-20、ERC-721、ERC-1155以及最近通过的ERC-3525。

（参考的ERC-20、ERC-721、ERC-1155代码来自OpenZeppelin，ERC-3525代币来自Solv Protocol）

哈希表
---

在了解代币合约的原理之前，首先要了解其中一个重要的概念——哈希表（Mapping），简单来说它是一种可以利用关键词（Key）快速查找值（Value）的映射数据结构。代币合约利用哈希表来储存资产信息、被授权人信息等。具体哈希表介绍可以看这里： [https://en.wikipedia.org/wiki/Hash\_table](https://en.wikipedia.org/wiki/Hash_table)

Data Hashing & 功能
-----------------

代币都有自己的Data Hashing的方式，这个方式会决定代币功能，可以理解为代币的资产构造以及记录的方式。Data Hashing按目的可以分为总体账号以及个体账号。总体账号记录代币的整体资产情况（包括代币种类、个数和整体授权等等），同时也有被授权人/管理人的设置（被授权人自由传输/再授权资产拥有者的资产）。

功能指的是基于代币的Data Hashing设计，代币的一些可实现功能（即public函数），其中包括资产的查询传输、铸造销毁等。

下文将会用这两个方面对各类型的代币标准进行盘点。

ERC-20
------

### 1\. Data Hashing

总体账户：ERC-20通过一个哈希表来管理和记录代币总体的资产，其中Key是用户地址，映射的Value是正整数用以记录每个地址拥有代币的个数。

![](https://storage.googleapis.com/papyrus_images/2f471b50bb93d409f3b79026769da644a2cbca64939b5729beae9374a482402a.png)

个体账户：ERC-20由于本身的简单性，一个记录总体的哈希表即可记录资产的数量，所以仅需要一个登记个人账户被授权人的表即可。这个表是一个以单个地址为Key映射另一个以地址为Key正整数为目标的表：

Mapping(address => (Mapping(address => unit 256))

举例来说，对于代币A下的一个账户，举例0x1，该地址是可以授权别的账户（如0x2，0x3）来代为使用自己的代币的。额度的授权只能由账户本身（即0x1）发起才能生效。

![](https://storage.googleapis.com/papyrus_images/16c340a1ee6a83474c273d4038ad11594d6f00abecb07b1f832f382d327f5bbf.png)

### 2\. 功能（基础版）

![](https://storage.googleapis.com/papyrus_images/29f23b4366ccb8ed55e5ed43037cb9aeb47fd3f87293cb356016243a68333ad9.png)

**ERC-20标准基本满足了流通货币、股权和大宗商品等概念的代币所需要的条件，而且简单好用。**

ERC-721
-------

### 1. Data Hashing

**总体账户：**

![](https://storage.googleapis.com/papyrus_images/2a6b48d5969211e1d2bbcc63b42df1651e178e1458638b903599081c7aabc27c.png)

这个表是把正整数映射给地址，即理解为id为Key，地址为Value，一个id能且只能对应一个地址。这实现了NFT的独一性以及稀缺性。

**个体账户：**

对比ERC-20的一个表记录所有地址的资产数额，721增加了个体账户资产记录的表，这个表以个人地址为Key，个人地址拥有的NFT数量为Value，记录了地址拥有总的NFT的个数；但是并没有记录个体账户拥有NFT的具体ID，这只能通过event查询。

![](https://storage.googleapis.com/papyrus_images/0d49c4c7a893c6c6158b5333e1046fbb4faa139c82484807357c6dfac43079cd.png)

被授权人授权方面，个人账户有一个整体被授权人，这个被授权地址可以操作该地址在账户中所有的该合约代币。授权人只能是个人地址本身。

![](https://storage.googleapis.com/papyrus_images/5dd8286bb1a27a63f83ae9fa5fd7e43f927fade629f45b4f8b45ddbd5dc2a468.png)

另一方面，单独id的NFT也可以被独立授权，被授权人可以操作该id的NFT。授权人可以是整体被授权人或者NFT拥有者本身。

![](https://storage.googleapis.com/papyrus_images/ec492802ca2f05885fd7f11fa65b0f177e00df8651f7c24cca8c4e46a0bda079.png)

总的来说，个人地址的被授权人可以有无数个，而且他们可以更改个人地址所有的id被授权人地址，而个体id的被授权人地址只能有一个。

举个例子来说，0x1拥有某系列3个NFT，id分别是1，2，3。0x1可以把自己这个系列授权给无数个别的地址，比如它设置给了0x2，那么0x2就有资格传输1，2，3这个3个NFT，同时0x2也有资格把单个id，如1，的传输权授予给其他地址，如0x3。这时候0x3可以自由传输1这个id的NFT。

### 2\. 功能

![](https://storage.googleapis.com/papyrus_images/d27697c7de2512c04917bc6b77bbe6eab9f60894fa077d7fd45b34544c606ed2.png)

\*\*721实现了数字艺术品的单一性和稀缺性，即一个id为一个藏品而且只能被一个地址拥有。\*\*而收藏者也可以收藏一个系列的多个id，同时支持查看个数。然而可能考虑到gas的消耗，721合约并不支持单个地址的所有NFT id咨询，比如0x1持有了2个该系列的NFT，通过合约功能仅仅可以查到0x1有2个NFT，但是并不知道是哪两个。想知道0x1持有的具体NFT id，就只能通过合约的log/event去查找。

ERC-1155
--------

### 1. Data Hashing

在ERC-1155里面，总体账户和个体账户同时实现。利用地址指向一个Mapping的Mapping完成了记录。

![](https://storage.googleapis.com/papyrus_images/890437d27be3d8d40c53ec004a7ebead2336f70e089279bd633914fe9c369dbb.png)

这里我们可以发现一个有趣的事实，就是1155的设计其实就是20和721的某种融合，可以理解为多个20标准和721标准（把数量设置为1地址只对应一个）的代币融合为一个整体的代币管理方案。

授权管理方面，没有了个体id的授权，只有个体账户的全部授权，可以简化授权的复杂度。

![](https://storage.googleapis.com/papyrus_images/951c0863d767a08e678b2ea2601f9c4188ed8e20d735991371fdf5a5a134d57c.png)

### 2\. 功能

![](https://storage.googleapis.com/papyrus_images/eb457d6f804fd9e1b697cb916b8767298c2c983d35cf9ac76cb7224bf4cee527.png)

总结来说，我们发现\*\*1155严格来说并不是某一个代币的标准，而是一个代币的管理集合。整体合约甚至没有Name或者Symbol，而且一个id允许被多个地址同时拥有，这让一个id可以选择拥有同质化或非同质化的性质。\*\*使用场景是适用于有多代币需求的情况，比如游戏中道具实现，从非同质化金币或者材料，到独一性的神器都可以用一个1155合约解决。或者可用于一个比较小型的整体生态，比如DEX的LP Token集合等。

  

同时\*\*由于有了数值的概念，如果设置一个id只有一个人拥有（可通过后续的合约实现），1155可以成为一个有数值概念的721（即Semi-Fungible Token的概念）。\*\*这意味着它有了NFT的可更新性。比如信用方面可以更新用户信用分数，而且可以构建多信用行为体系，每个信用的方面都有一个数值等级。

  

不过笔者个人觉得由于它对于授权的管理过于简单（只有全部授权，没有单个id的授权，也没有额度的授权），并不适用于大生态的代币系统管理；而且也没有完整的个人账户记录，即通过个人地址作为Key去Map出全部的相关id的资产。这个也只能通过log/event读取。

ERC-3525
--------

  

相比之下，这是一个复杂的合约，但是功能记录等都十分完善，可定制性也很高。

  

### 1\. Data Hashing

  

总体账户：3525在这方面创新地先构建了一个取名TokenData的struct作为单个id的描述。不了解代码的同学可以把这个理解为一个id的描述小卡片。内容包括了：id、S**lot（很重要，3525的一个核心创新）**、在这个id之下的代币数量、所有人、id的被授权人（只有一个）、可以花费这个id余额的被授权地址。

![](https://storage.googleapis.com/papyrus_images/028d1673e3bd027fa4f78c0fa78516b27478223dc6b0c028151f58c3e9fa67a9.png)

**有了这个小卡片，我们就可以把每个id的信息都记录下来。然后通过一个叫\_allTokens的list把一张张的小卡片放进去保存起来。**

**\_allTokens**: \[ TokenData, TokenData, TokenData............ \]

那当我们要取出查找我们想要看的小卡片的时候我们怎么定位呢？3525通过一个id到struct在list中的位置的映射完成。比如我们查到id 214的位置是在1，那么\_allTokens\[1\]就可以拿出小卡片查看。\_allTokens这个list记录了该3525的总体资产情况。

![](https://storage.googleapis.com/papyrus_images/d4d1b07e1ff5d0726e319eb73969ac1cac2e19df2613e47acf20c8a61a8d1b60.png)

id授权方面添加了值的目标，即用id作为Key，标记了各个地址对于这个id的使用额度。

![](https://storage.googleapis.com/papyrus_images/14378e2059b2bcd0cd74681b2085280e3bcb992cbd0e4b41235ef72eecb0b802.png)

个人账户：3525对于个人账户构建了一个AddressData小卡片和一个哈希表来管理。小卡片内容包括拥有的Token的id的列表，拥有的id在总体账户list的位置的哈希表，账户的被授权人的哈希表。即**小卡片实现了记录个人持有的id（每一个都记录）、以及账户被授权人。**

![](https://storage.googleapis.com/papyrus_images/3767196cd5c91c7c81f9a84a28e99bd56d382774fffa78ce896a3f1e45e42237.png)

后面再通过一个映射把**个人地址作为Key去记录了对应的小卡片（AddressData）信息**。

![](https://storage.googleapis.com/papyrus_images/2883445670d47834ac8b372afaca8591a5522a80b666d61fc6f7576599b9dc16.png)

### Slot

整体来看，3525的数据记录非常全面，而且也很有条理。但是到目前为止，和1155相比，3525并无太大不同，只是记录更加完善而已。下面要讲讲Slot，这个放在id小卡片里面的一个变量，正是这个变量让3525高度可定制化，能做1155不能做的事情。

  

简单来说，Slot是一个Struct，和前面介绍的AddressData和TokenData一样。但是在3525中，Slot这个Struct是需要开发者自定义的，即开发者可以根据自己产品的需求，给Slot添加变量的数量和类型。以Solv Protocol的一个可转债类型债券作为例子，Slot可以包含的信息有到期时间（Maturity Date）、行权价格（Conversion Price）、以及行权价值（Convertible）。加上之前的ID（#6800）、Balance（2400 USDC）等变量，就构建出了一个可转债的NFT。

![](https://storage.googleapis.com/papyrus_images/65c95c01487637ae1a27cf0d050919f2603047d31cc642d0c648773b7c727dbc.png)

### 2\. 功能

![](https://storage.googleapis.com/papyrus_images/1a0d59cf7211bb92860701219121ecd59f36c3e489202f1351b23e08f189d3ab.png)

由于3525的记帐本身非常全面，所以其功能也非常多，想象空间大。**其中关键的是实现了id数值的传输以及个人拥有的id之间的数值传输功能，这个实现可以让NFT有了更能多可能。**

  

比如由于有id数值传输的功能，NFT可以更新自己的数值状态。对于信用、灵魂绑定类NFT来说，如果只是简单不可传输的721是不可以实现所有功能需求的。因为个人信用应该是一个动态的过程。这时候3525可以通过改变数值来反应个人信用的变化，又或者可以用于类似Uniswap V3那种NFT仓位中，可以让用户更方便地更新仓位大小。不过**其实这个特性1155也可以实现**，只要在1155中把每个id的拥有者设为只有一个地址上就行了（虽然在Data Hashing结构上不是，但是可以后期实现），这时候也可以传输/更新数值；而且1155设计更加简洁，甚至在多代币需求的场景下1155有更好的适用性。

  

\*\*个人拥有的id之间的数值传输，这是3525在功能方面最大区别于1155和721的方面。\*\*这个功能的用例可以在金融中。比如两个不同期限的交割合约的展期，又或者不同金融账号之间的切换等（如现货账户到期货账户的转换，类比CEX的设计）。这个时候每个id就是一个金融账号，用Slot记录账号信息，数值就是账号余额。又比如V3的Range管理（不仅仅是数值），通过Slot记录Range，个人想改变仓位Range的时候通过id到id的数值传输就可以做到。

  

3525也留下了一些小遗憾。比如，可能是出于重叠id的问题又或者是便于管理的考虑，3525不能自定义id的名字，只能从0开始逐步叠加，即每一个新的NFT的id只能是以【系列总数量+1】开始。再者，在一些extension中，3525虽然做了Slot的记录以及排序，但是缺少了基于Slot的id分类/查询。笔者觉得这在很多的产品设计中可能是一个重要的方向以及用例，比如债券类产品，它们通过Slot记录不同的债的信息然后发行，如果可以用Slot把相同的期限id债券分出，则可以构建更方便功能化的交易/管理等产品。目前这个目的只可以通过查询id的Slot信息，然后通过这个查询构建Slot和id的DB，又或者通过event和log构建去实现。

  

结语
--

  

总结来看，20、721、1155、3525都有自己独特的使用范例，项目方根据自己代币经济需求去选择最适合的。但是相比之下，新型的3525则是一个比前三者都复杂很多的合约，它不仅继承了前面3个标准的特性，还加入了独特的Slot数据结构，而这让它可以完成一些新的任务。此外，虽然3525功能变多了，但它依然保持记录的条理性，目前感觉是个不错的创新。但是由于更多元的信息记录，可以预见的是3525相对高额的gas成本，以及一些未知的漏洞攻击（毕竟未受到时间检验）。

---

*Originally published on [ViaBTC Capital](https://paragraph.com/@viabtc-capital/erc-20-erc-3525)*
