ERC-777是一种新的代币合约标准,解决了ERC-20的一些安全问题,可以让合约创建者、代币持有者和受众在无需更改代币合约的情况下扩展其功能。ERC-777从ERC-20和ERC-223等标准处汲取了很多想法,并在此基础上发展成为新一代标准,为开发者和用户提供了很多强大的特性。
本文主要介绍了代币合约,并讲解了ERC-777代币合约的特性、功能和用途。请注意,本文不涉及ERC-20。如果你想了解关于ERC-20代币合约的信息,可以看看另一篇文章。
什么是代币合约?
代币合约指的是一个包含了一组账户地址及其对应余额的智能合约,如下图所示。余额表示由合约创建者定义的一种价值:代币合约可以使用余额来表示实物、币值或持币者的声誉。一个单位的余额就是我们通常所说的代币。
-图1:地址及其代币余额表-
需要注意的是,一个最终用户可能会拥有任意多个地址。造成这种情况的原因有很多,例如,用户想把自己所持有的代币分散到不同的逻辑账户中,或使用不同的账户来代表不同的来源。
每当代币从一个账户转移到另一个账户,代币合约就会更新这两个账户的余额。例如,从0x2299…3ab7向0x1f59…3492转移10个代币之后,余额更新情况如下表所示:
-图2:从0x2299…3ab70向0x1f59…3492转移10个代币之后,余额的变化情况如标红处所示-
可以通过铸成新的代币来增加其总供应量。例如,在0x4ba5..ae22中铸成100个代币,则余额的更新情况如下表所示:
-图3:在0x4ba5..ae22中铸成100个代币,则余额的变化情况如标红处所示-
代币的总供给量可以通过销毁已有代币来减少。例如,0x4919…413d销毁了50个代币之后,余额的变化情况如下表所示:
-图4:销毁0x4919…431d中的50个代币之后,余额的变化情况如标红处所示-
简单的代币合约会将上述信息保存在地址与余额的映射表中。如果是在更复杂的场景下,如分红等,通常会另外采用更加强大的结构。然而,无论具体的实现细节如何,代币余额情况始终如上文的图表所示。
ERC-777代币合约的运营者
IMF今日发布的加密货币科普视频实为两年前旧闻,且存在诸多疏漏:国际货币基金组织IMF今日在推特上发布了一条关于加密货币的科普视频,这段时长两分钟的视频最初发布于2018年6月。该视频称加密货币是“货币进化的下一步”,但没有特别提到DLT、区块链,甚至是代币名称等术语。BTC、XRP和ETH只出现在说明加密交易的图形中。尽管这段视频到目前为止已经获得了超过13.7万的点击量和2900个赞,但来自加密社区的许多反应都是批评的,他们指出了信息中的漏洞和似乎具有误导性的措辞。
Reddit用户nanooverbtc称:“他们犯了很多错误,比如把私钥称为密码。”该视频也没有讨论挖矿或加密货币供应。Kraken策略师Pierre Rochard等知名人士表示:“可证明的稀缺性是比特币有趣的原因,你忘了提这一点。”(Cointelegraph)[2020/8/24]
ERC-777代币合约引入了运营者的概念。运营者是代表代币持有者进行操作的第三方,可以将代币从持有者的地址转移出来。请注意,由于运营者拥有很大权力,应该谨慎添加。
每个地址都包含一个经授权的运营者列表,如上表所示:
-图5:代币持有地址的运营者-
如上表所示,代币持有地址0x1f59…3492拥有两个运营者,其他两个地址各自拥有一个运营者。当然了,没有运营者的地址也是有效的。
使用运营者的一个简单例子是,用户在多个地址代币上都有代币,必须分别管理这些地址。在一般情况下,在将代币从一个地址发送到另一个地址之前,要先确保发送者的地址内有一笔ETH,足以用来支付gas费用。因此,在将ETH从一个账户发送到另一个账户之时,发送者需要先完成几个交易,如下图所示:
-图6:发送代币之前先往账户打钱-
如上图所示,地址0x93f1…1b09先向地址0x1f59…3492发送ETH,等待该交易完成后,地址0x1f59…3492向0x4ba5…ae22发送代币。如此繁多的步骤既降低了用户体验,又加大了网络负载量。
有了运营者之后,只要一个账户里有ETH,其他账户里有其他代币,即可由持有ETH的账户进行代币转账。接着上一个例子往下看,如果把0x93f1…1b09作为0x1f59…3492的运营者,那么由0x1f59…3492向0x4ba5…ae22发送代币的过程就可以简化为:
-图7:代表另一个账户发送代币-
这就大大降低了用户的负担。此外,这可以让用户在通过一个运营者账户控制ETH资金的同时,确保其代币分散于多个持币账户之中。
人大附中物理老师李永乐科普拜占庭将军问题和区块链:5月14日,人大附中物理老师、科普视频网红李永乐在其公众号发布视频《拜占庭将军问题是什么?区块链如何防范恶意节点?》。李永乐老师在视频中对拜占庭将军问题和区块链进行了讲解,他表示,拜占庭将军问题本质上指的是,在分布式计算机网络中,如果存在故障和恶意节点,是否能够保持正常节点的网络一致性问题。在近40年的时间里,人们提出了许多方案解决这一问题,称为拜占庭容错法。例如兰波特自己提出了口头协议、书面协议法,后来有人提出了实用拜占庭容错PBFT算法,在2008年,中本聪发明比特币后,人们又设想了通过区块链的方法解决这一问题。区块链通过算力证明来保持账本的一致性,也就是必须计算数学题,才能得到记账的权力,其他人对这个记账结果进行验证,如果是对的,就认可你的结果。与拜占庭问题比起来,就增加了叛徒的成本。[2020/5/14]
运营者也有可能是合约的形式,而且在代币合约创建的时候就可以为所有持币者预先定义好代币运营者合约。这样一来,运营者可以为所有持币用户提供服务,同时其功能又被限制在智能合约的功能范围内,代币合约就可以不费吹灰之力地为持有者提供更多功能。后文将详细阐述代币合约运营者拥有哪些权力。
ERC-777代币合约的定义
每个部署到以太坊上的ERC-777代币合约都会被分配一个地址,即代币地址。这个代币合约将会包含一些定义合约操作的参数。
首先要理解的是,由于代币合约缺少一个中心化的注册表,无法保证名称或符号具有唯一性。这样一来,获得并保有唯一身份的最佳方法就是公开你的代币合约。一旦你创建了一个代币合约,就应该把它添加到一些常用网站上,如Etherscan、MyEtherWallet、MyCrypto和CoinMarketCap等等,不过要确保遵守每个网站的要求,这样你的提交得到接受的可能性才最大。
代币合约的name就是用来指代合约本身的长名称,例如“Mytoken”。名称的长度并没有限制,但是一些钱包应用可能会将过长的名称截短,因此要将名称的长度控制在较短的范围内。
代币合约的symbol就是用来指代合约本身的短符号,例如“MYT”。这个符号跟股票代码差不多,虽然没有长度限制,但是通常都在3至4个字符左右。
Solidity不支持小数,但是可分割性对于代币来说是一个常见需求。ERC-777采用的解决方案是,所有代币的内部所示数额均使用其实际数额的1018整数倍来表示。例如,终端用户看到的1.2345代币其实在内部是用1.2345×1018来表示的。这样一来,即使一个代币被分割成了0.000000000000000001,在内部也依旧是以整数表示的,如下表所示:
-图8:代币内部所示数额是终端用户所见数额的1018-
一些代币合约的创建者可能不想让他们的代币分割得这么细。例如,有一名用户创建了一个软件许可证代币合约,他可能不想看见一个完整的许可证被分割的情况。又或者,有一名用户创建了一个黄金代币合约,用1token代表1Kg黄金,他可能想将转账金额限制在0.01Kg及以上。
动态 | 新浪财经:官媒针对区块链的报道从科普宣传转向打假监管:据新浪财经今日消息,“1025新政”满月,一个月间,官媒对区块链的态度风向已转。据11月初的一项统计,七家党媒在新政一周内发布了65篇直接相关报道,当时文章中的关键词是数据、产业、安全、创新等,大量文章偏向于科普区块链的概念以及应用介绍,提醒警惕虚拟货币炒作的仅有3篇。近期,官媒的批评焦点则纷纷指向借区块链之名进行的虚拟货币发行和炒作行为。据统计,新华网、人民网收录转载的,以打击虚拟货币或揭露假借区块链行为主题的文章,自10月25日到11月25日午间,共28篇;其中,11月19日至11月25日的一周内就高达15篇。这些文章主要围绕三个观点展开:厘清区块链和虚拟货币的关系,说明二者概念不等;打击伪“区块链”局,或是虚拟货币局揭露;提醒民众,区块链不能成为炒作的噱头,更不是行的招牌,需警惕此类活动,理性投资。[2019/11/26]
代币合约的granularity是代币内部所示数额的最小可分割单位。紧接着上面的例子,许可证代币的粒度应当是1018,而黄金代币的粒度应当是1016。
可以预期的是,绝大多数代币合约的粒度都是1,也就是说,这个代币可以被分割成1/1018,或是0.000000000000000001。根据上面给出的例子,如果对代币的可分割性有具体要求,可以选择不同的粒度。
不妨来探究一下ERC-777的粒度和ERC-20的小数之间的区别。虽然二者的都可以实现代币的可分割性,ERC-20是基于具体的值来移动小数点的位置,而ERC-777的小数点位置是固定的。这样一来,ERC-777代币的值就更容易在用户界面上显示,因为小数点的位置始终是固定的,只是去掉了后面一连串的0。
ERC-777代币合约的功能
ERC-777代币合约具有很多功能,可以让用户查找账户余额,并且在不同条件下将代币从一个账户转到另一个账户上。这些函数的详情如下。
totalSupply()函数说明了所有地址持有的代币总量。如果有新的代币被铸造出来,这个值就会增加,如果已有的代币被销毁,这个值就会减少。
balanceOf()函数说明了特定地址所持有的代币数量。要注意的是,任何人都可以询问任意地址的余额,因为区块链上的所有数据都是公开的。
send()函数将一定数量的代币从信息发送方的地址转到另一个地址上。相比于ERC-20代币,ERC-777代币的发送功能更完善,详情见后文。
burn()函数会销毁信息发送方所持有的一部分代币。相比于ERC-20代币,ERC-777代币的销毁功能更完善,详情见后文。
authorizeOperator()函数允许消息发送方将自己的代币授权给另一个地址。
revokeOperator()函数可以将撤销现有运营者控制消息发送方代币的权限。
isOperatorFor()说明了某个地址是否是某个代币持有者的运营者。
声音 | ETC Labs主管:科普教育是未来几年公链面临的巨大挑战:ETCLabs主管Darin Kotalik认为,科普教育是未来几年公链面临的巨大挑战,人们必须要对区块链有基本的认识,分清楚公链和私链的区别。[2019/8/25]
只要发送方拥有某个账户的运营者权限,就可以通过operatorSend()函数将一定数量的代币从那个账户发送至另一个账户。
defaultOperators()函数提供了一个代币运营者合约列表,列表中的运营者均已得到所有代币的全部权限;关于这个功能,可以参见下文的“代币运营者合约”一节。
ERC-777代币合约所涉及的事件
ERC-777定义了一些事件,可以用来追踪一个代币合约的个体和整体信息。
一旦有新的代币被铸造出来,就会触发Minted()事件。该事件包含了新铸代币的数量,及其目标地址的信息。
一旦现有代币被销毁,就会触发Burned()事件。该事件包含了被销毁代币的数量及源地址的信息。
一旦有代币从一个地址转移到另一个地址,就会触发Sent()事件。该事件包含了被转移代币的数量,以及持有者地址和接收者地址的信息。
除了上述几个事件之外,ERC-777代币标准还包含了两个管理型事件。一旦用户为己方地址添加了一个运营者,就会触发AuthorizedOperator()事件。一旦用户将己方地址的某个运营者移除,就会触发RevokedOperator()事件。要注意的是,这些事件不会包含关于代币数量和所有权变化的信息。
详解ERC-777代币合约的发送功能
将ERC-777代币从一个地址发送到另一个地址需要经过几个步骤来完成。在这一流程,ERC-777代币标准在功能性和安全性上都展现出了优越之处。
常见的代币发送流程如下图所示:
-图9:常见的代币发送流程-
具体步骤如下:
验证:确保输入参数是有效的,需验证该地址是否有足额代币可用来发送,以及所发送数额是否是该代币粒度的倍数
授权:确保发送方有权发送代币,发送方必须是这些代币的持有者或是拥有对应地址权限的运营者
发送:执行代币转账,更新代币合约上每个地址的持币信息
日志:发送包含所有操作细节的事件
ERC-777在上述步骤的基础上又新增了两个步骤,如下图所示:
-图10:ERC-777的代币发送流程-
可以看到,ERC-777在常见流程中新增了tokensToSend()和tokensReceived()这两个步骤。tokensToSend()的调用放在了验证交易信息以及完成授权之后,但是在更新合约地址的持币信息之前。tokensReceived()的调用放在了更新合约地址的持币信息之后。乍一看,新增的步骤似乎没有让整个流程变得很复杂。但是,tokensToSend()和tokensReceived()的强大之处在于,它们不是由合约地址定义的,而是分别位于代币发送方和接收方的合约内。由此一来,发送方和接收方就有权决定是否要达成交易,还可以实现更高级的功能。
动态 | 央行官微旧文重发“再科普”:范一飞详解数字货币:据中国经济网消息,今日,央行官微公众号头条重新发布央行副行长范一飞在2018年1月25日题为《关于央行数字货币的几点考虑》的文章,对央行数字货币再次进行科普。同时,微信公众号第二条发布支付司副司长穆长春8月10日在第三届中国金融四十人伊春论坛上的演讲。近年来,各主要国家和地区央行及货币当局均在对发行央行数字货币开展研究,新加坡央行和瑞典央行等已经开始进行相关试验,人民银行也在组织进行积极探索和研究。[2019/8/21]
-图11:位于不同合约内的tokensToSend()和TokensReceived()-
tokensToSend()允许持币者以“在代币离开该账户之前”的形式提供条件和操作。tokensReceived()允许代币接收方以“代币何时到达该账户...”的形式提供条件和操作。
tokensToSend()的目的
想象一个场景。假设有一家公司的首席财务官制定了多种货币资金的转出规则。这个首席财务官允许财务经理在遵守公司规则的情况下使用资金,同时保留对规则以及资金的控制权,就如下图所示:
如果这笔资金采用的是ERC-777代币的形式,就可轻松实现上图中的设置。需要执行以下步骤:
首席财务官制定的规则被编码进了一个代币控制合约内,且该合约被应用于该公司的持币地址
首席财务官授权财务经理成为公司持币地址的运营者
财务经理使用operatorSend()发送资金
首席财务官可以制定哪些规则?几乎所有规则都可以被编码进智能合约内,下面举了几个例子:
只允许运营者花费一定量的资金
对运营者设置每日/每周/每月的支出限额
运营者只能向一组经过授权的收款方发送资金
只有提供了对首席财务官批准过的发票的引用,运营者才可以花费这笔资金
等等
要留意的一点是,既可以针对公司所持有的不同种类的ERC-777代币制定多套规则,也可以对多种ERC-777代币实行同一套规则。这样一来,首席财务官就可以制定合乎自己公司情况的规则了,财务经理也只能遵守这些规则。
同一个地址也可以拥有多个运营者。因此,如果财务经理有代理人的话,只要其代理人也遵守同样的规则,就有权访问这笔资金。
tokensToSend()旨在通过对交易制定规则来控制一个或多个账户内资金的转出。说白了,tokensToSend()就是让用户把“在代币离开我的账户之前...”这句话补充完整。这些规则是在代币控制合约中定义的。同一个代币控制合约可用于多个ERC-777代币合约,以及多个账户之间,从而保证各账户之间规则的统一。
tokensReceived()的目的
与tokensToSend()类似,tokensReceived()会收到代币已转入该账户的通知。接着上文的例子,该公司有一个会计部门负责付款。每次收到付款,都需要核对是否与发票相符,并且分配给公司内部的部门。收到这笔资金之后,会计部门需要执行以下步骤:
如果收到的资金带有发票参考号,则将其与发票进行核对,并记入相应部门的贷方
如果收到的资金来自一个已知的发送方,则直接记入相应部门的贷方
除上述情况之外,将资金存入持币账户并进行调查
就tokensToSend()而言,上述过程只是一个实例,它实际上可以描述一切规则。例如,提早付款可享折扣,只接受哪几种货币,等等。这只需要一个步骤:
1.该部门的流程被编程进了一个代币控制合约,且该合约被应用于该公司的收款地址
通常来说,tokensReceived()之所以没有tokensToSend()那么复杂,是因为两个原因。第一,tokensReceived()通常只包含一个参与者,而tokensToSend()会涉及运营者。第二,相比收款来说,用户通常更关注付款。尽管如此,tokensReceived()是一个非常强大的功能,可以帮助像交易所之类的大型组织来管理已收到的资金。
tokensReceived()旨在通过对交易制定规则来控制进入一个或多个账户的资金。说白了,tokensReceived()就是让用户把“当代币进入我的账户之时...”这句话补充完整。这些规则都是在代币控制合约中定义的。同一个代币控制合约可用于多个ERC-777代币合约,以及多个账户之间,从而保证各账户之间规则的统一。
对tokensToSend()和tokensReceived()的要求
tokensToSend()是可选项;如果不选的话,就会按照常见流程发送代币。tokensReceived()也是可选的,除非收款账户是合约,在这种情况下就是强制的。强制所有收到代币的合约执行tokensReceived(),就可以确保代币只会被发送到主动说明可以处理这这些代币的合约处。这是ERC-223的主要目标。除此之外,ERC-777还实施了其他保障措施,就是强制收款方登记是否能够接收ERC-777代币和ERC-1820代币。
代币运营者合约
如上文所述,代币运营者合约就是在ERC-777代币合约上调用operatorSend()的合约。这类合约的强大之处就在于,它们能够在不需要改变ERC-777代币合约本身的情况下扩展ERC-777的功能。
当持币者想要把代币发送到另一个地址之时,他会直接在该代币合约上调用send(),如下图所示:
-图13:直接发送代币-
但是,任何用户也都可以通过调用代币运营者合约来发送代币。通过该合约,任何用户都可以代表持有者发送代币,如下图所示:
-图14:通过代币运营者合约发送代币-
在创建代币合约之时,就可为所有持有者都启用代币运营者合约,或是在有需要的情况下,为个别持有者启用该合约。
代币持有者合约可以为代币持有者提供额外的功能。例如,批量发送代币是一大常见需求,但是没有在ERC-777标准中注明。在部署ERC-777代币合约之前,有可能会新增批量发送的功能,但是这样会为代币合约引入自定义属性,因此更容易出现错误。
另一种解决方案是,编写一个可实现批量发送的独立代币运营者合约,并单独进行部署。这个代币运营者合约可以接受来自持币者的交易,并根据交易中所记录的将哪种代币发送给哪些收款方的细节,反复调用operatorSend()来发送这些代币。
为了实现批量转账的功能,在部署一个标准ERC-777代币合约的同时会指定一个批量发送运营者合约作为默认的运营者。现在,任何持币者都可以在代币运营者合约上调用send()函数,仅通过一个交易就可以将多种代币从自己的账户上发送出去。如果代币合约没有注明将批量发送运营者合约作为默认的运营者合约,则持币者可以针对账户进行自定义配置。
请注意,由上图可见,代币运营者合约只有一个send()函数,但是复杂的代币运营者合约可以有多个send()函数。例如,一个批量发送代币运营者合约可能具备以下功能,即,向多个收款方发送相同数量的代币,向多个收款方发送不同数量的代币,等等。
除了上述例子中提到的功能之外,调用代币运营者合约的用户也可以是除持币者之外的人。让外人代替持币者发送代币,这种做法可能听起来很危险,但实际上在很多场景下都非常有用。将持币者和要求转账的用户分开,就可以实现更多功能,例如:
在获得持币者授权的情况下发送代币
通过发送代币来换取其他代币
一旦满足特定条件,立即发送代币
简言之,代币运营者合约可以通过修改规则来规定代币在何时可以从一个账户转移到另一个账户。这是一个非常强大的功能,需要用户充分信任代币运营者合约。可以设想的是,以太坊主网上将会部署一些知名的代币运营者合约,用来实现特定的功能。代币合约创建者和个人持币者通过选择自己想要的代币运营者合约就可以扩展功能,从而提高代币转账的效率和安全性。
在下一篇文章中,我们将更深入地探究代币运营者合约。
代币运营者合约和代币控制合约之间的差别
乍一看,代币运营者合约跟代币控制合约中的tokensToSend()差异不大,其实二者还是有一些差别的。
代币运营者合约是可选的;任何持币者都可以忽视这个功能,直接调用send()。而代币控制合约是强制性的,不能被忽视。
任何人都可以调用代币运营者合约。代币控制合约是作为send()和operatorSend()操作的一部分调用的,因此只能由持币者调用。
一般而言,代币运营者合约侧重于扩展代币合约的功能。代币控制合约则侧重于控制来自账户的代币流。
下表汇总了代币运营者合约和代币控制合约之间的不同点:
与ERC-20的兼容性
敏锐的读者可能已经注意到了,虽然ERC-20和ERC-777提供的功能差不多,但是二者对这些功能的命名都不尽相同;ERC-20使用的名称是transfer()/approve()/transferFrom(),而ERC-777使用的名称是send()/operatorSend()。这就意味着,同一个代币合约有可能提供相同的ERC-20和ERC-777功能。ERC-777标准中详细说明了具体的操作方式和触发事件。
ERC-777实现
ERC-777带有一个参考实现,其中还包括了一个可兼容ERC-20标准的版本。代币运营者合约和代币控制合约的样本可单独获得。
更多关于ERC-777的信息
这里还有一篇文章也深入剖析了ERC-777代币运营者合约,里面提到了很多例子,都是关于如何使用该合约来扩展基本的ERC-777代币合约的功能的。
原文链接:
https://www.wealdtech.com/articles/understanding-erc777-token-contracts/
作者:JimMcDonald
翻译&校对:闵敏&阿剑
郑重声明: 本文版权归原作者所有, 转载文章仅为传播更多信息之目的, 如作者信息标记有误, 请第一时间联系我们修改或删除, 多谢。