ERC20 投票:ERC5805 和 ERC6372

文章详细介绍了ERC20 Votes的功能和实现方式,重点解释了ERC5805和ERC6372标准的功能及其在ERC20 Votes中的应用。文章还对比了ERC20 Votes与ERC20 Snapshot的区别,并讨论了何时使用哪种标准。

ERC20 VotesERC20 投票

需要假设你已了解 ERC20 Snapshot 的知识,请参阅我们关于 ERC20 Snapshot 的文章以获取主题介绍。ERC20 投票并不实际处理投票表决,它仍然是一个常规的 ERC20 代币,具有快照和委托投票能力。投票通常由治理合约处理。委托意味着一个地址可以将其投票权借给另一个地址,而无需将其代币转移到该地址。

ERC20 Snapshot 不同,它并不保留代币余额的快照,而是保留地址的投票权快照。这有几个动机:

  • 这允许被动股东通过委托其投票权参与治理
  • 余额较小的账户可以在不花费Gas费的情况下投票,因为受托人代为投票。这在生态系统层面节省了Gas费。如果所有参与者都委托给 5 个受托人,那么针对需要投票的项目只发生 5 次投票,而不是可能上千次。
  • 当然,快照(检查点)是必要的,以防止双重投票,就像 ERC20 Snapshot 所做的一样。

ERC20 投票继承自 ERC20、ERC6372 和 ERC5805。这意味着它具有 ERC20 代币所有功能以及下文描述的附加属性。

ERC5805 功能

getVotes(address delegate)

这个函数接受一个账户的地址,并返回它拥有的总投票权。如果其他地址已将他们的投票权委托给它,这可能大于 balanceOf(delegate)。

delegate(address delegatee)

这个函数允许 msg.sender 将他们的投票权委托给 delegatee,且 delegatee 将代表 msg.sender 投票。请注意,代币不会转移给 delegatee,仅投票权会转移。可以通过再次调用 delegate,使用不同的 delegatee 或 address(0),在任何时候更改或撤销委托。委托是全有或全无。没有选项可以委托部分投票权。重要的是要注意,地址必须先委托给自己才能计算它的投票。这一奇怪设计是出于Gas效率的原因。

delegates(address account)

这个函数返回 account 参数所委托的投票权的账户。

delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s)

函数 delegateBySig 允许用户通过无Gas费的交易委托投票权,并让另一个账户支付Gas费用并执行交易。过期会设置委托有效的时间,v、r 和 s 是椭圆曲线数字签名的组成部分。这个签名需要以 EIP 712 格式进行。内部,合约会按地址递增 nonce,如下所述。

nonces(address account)

签名需要 nonce 来防止重放攻击,因此该函数暴露了内部 nonce 跟踪。这使得签名方可以知道下一个应该签署的值。

getPastVotes(account, timepoint)

正如我们在 ERC20 Snapshot 文章 中讨论的那样,除非账户余额被快照,否则可能出现双重投票攻击。这是投票合约会查看过去快照的地方。与 ERC20 快照不同,快照并不是由于一个地址调用快照函数而触发。快照是当以下任何事件发生时,按账户触发的:

  • 发行
  • 销毁
  • 转移
  • 某人委托他们的投票

每当发生这些事件时,包含投票权和时间戳的结构会附加到存储该用户投票权历史的数组中。与 ERC20 Snapshot 一样,ERC20 投票将在时间戳上进行二分查找,以查找时间点之后的最早检查点。将在该时间点返回投票权。这意味着,与 ERC20 快照不同,没有“全局”快照 ID。如果你想查询过去的某个时间点,你可以选择一个时间戳或区块号,并将其作为“时间点”提供给函数。

事件

ERC5805 有两个事件,它们的名称正如字面意思:DelegateChangeDelegateVotesChagned

ERC5805 是一个接口,而不是一种代币

在本文中,我们解释了 ERC20 投票,但这并不意味着 ERC5805 必须是一种可替代代币。它可以是 NFT,甚至是以其他方式管理的投票记录,例如一个中心化实体将投票分配给地址,但想要保持投票权分配的不可变历史。

ERC6372

我们假设合约正在使用 block.timestamp 来记录检查点的方式。然而,一些合约可能使用 block.number 或这些全局变量的某种单调递增函数。ERC6372 是一个标准,允许合约查询它所使用的“时钟”的类型。它有两个函数:

clock()

这个函数返回一个 uint48,可能是区块号或区块时间戳或这些的某种函数。选择 uint48 是因为它有足够的位数来表示所有合理的时间表示,而区块号在未来比人类记录的历史更远。

CLOCK_MODE()

是的,蛇形命名法的全大写函数在 Solidity 中非常不寻常,但这就是 EIP 所指定的内容。这个函数返回一个字符串,告诉读者时钟使用的单位。

  • 如果是时间戳,它将是 “mode=timestamp”。
  • 如果是区块号,它将是 mode=blocknumber&from=default

这意味着它仅使用 block.number 变量。如果它起始于其他区块,必须指定链 ID 以及起始的区块号。例如,Avalanche 的链 ID 为 43114,因此如果它起始于第 100 个区块,CLOCK_MODE() 的响应将是 mode=blocknumber&from=43114:100。EIP 6372 没有事件。有关更多详细信息,请参见 EIP,该文档实际上是相当易读的。请注意,这个 EIP 尚未最终确定。

ERC20 Snapshot 和 ERC20 Votes 差异总结

时间的概念

  • ERC20 投票具有明确的时间概念
  • ERC20 快照通过作为计数器的副产品,使用随着时间增长的递增 ID

记录内容

  • ERC20 投票快照投票权
  • ERC20 快照跟踪余额

检查点何时更新

  • ERC20 投票在发生委托或转移时更新
  • ERC20 快照需要显式调用 “_snapshot()”

是否使用 ERC20 Snapshot 或 Votes

使用 ERC20 快照还是投票的选择主要取决于是否需要委托投票,或者更抽象地说,某些 ERC20 代币所赋予的权利。

了解更多

请查看我们的高级 Solidity 编程训练营 以及我们其他 区块链训练营 产品。最初发布于 2023 年 2 月 23 日

  • 原文链接: rareskills.io/post/erc20...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
RareSkills
RareSkills
https://www.rareskills.io/