Alert Source Discuss
🚧 Stagnant Standards Track: ERC

ERC-6506: P2P 托管治理激励

用于构建合约的接口,该合约基于账户在 DAO 中采取的行动来托管资金

Authors Josh Weintraub (@jhweintraub)
Created 2023-02-15
Discussion Link https://ethereum-magicians.org/t/escrowed-and-private-bribes-for-generalized-dao-voting/12694

摘要

以下 EIP 定义了一个合约的接口,该合约有助于交换治理激励,让用户在 DAO 提案上按指定方向投票,同时托管资金直到投票可以验证。

动机

虽然在为像 Curve、Frax、Convex 等 DAO 构建贿赂系统方面投入了大量精力,但对于其他更通用的 DAO 投票的贿赂如何影响结果,关注的并不多。贿赂在许多流行的 DAO 上都是一个利润丰厚的市场,因此有理由认为,人们愿意接受贿赂来对其他提案进行投票,尤其是在他们对结果没有个人利益的情况下。然而,目前的系统存在一些问题:

  1. 目前基于按比例分配的投票贿赂方案在经济上效率低下,并导致对选民来说更糟糕的结果。对于像 Votium 或 Hidden-Hand 这样的系统,如果 Alice 投票支持一个预计会收到 10 美元贿赂的提案,他们可能会被更大的选民抢先交易,从而稀释他们在池中的份额。做出他们所做的决定可能不再经济。使用场外交易机制效率更高,因为金额在贿赂时是“锁定的”,并且接收者在做出决定时有更具体的保证。这些协议也是中心化的,依赖于中心机构公平地接受和重新分配奖励。应尽可能避免中心化。

  2. 缺乏现有标准意味着各方完全依赖于彼此的信任来遵守。Bob 必须信任 Alice 会付款,而 Alice 必须信任 Bob 会投票。即使他们两个要使用托管合约,也可能存在缺陷,例如依赖可信的第三方,或者仅仅是因为它超出了双方的技术范围。

  3. 没有机制可以提高参与者串通的透明度。用户在线下串通以影响大型代币持有者的投票,会产生不透明的结果,且没有问责制,因为一切都发生在线下。

  4. 对于希望为其投票寻求激励的参与者来说,这可能需要主动管理,或披露其身份/伪匿名标识符。希望进行谈判的用户需要提供一种方式,让激励者可以联系他们、参与谈判过程、编写和部署托管合约、投票,然后领取奖励。这是一个漫长而复杂的过程,需要主动管理和沟通。这限制了能够寻求这些激励的人,并导致利润向少数能够长期维持这一过程的人集中化。

  5. 贿赂收入用作补贴。正如 Vitalik 在 2019 年的文章《论合谋》中写道的那样,一个潜在的解决方案是,如果提案通过,代币需要提案的投票者购买治理代币,从而补贴其他人做出错误决定的成本。如果来自这些激励措施的收入(至少部分地)被用于直接回购国库中的那些代币,那么你就会得到类似的结果。通过贿赂通过的糟糕提案的影响会得到补贴,因为它会将一些价值返还给代币持有者。这不仅使恶意贿赂的成本更高,因为它必须抵消通过回购积累的价值,而且还意味着接收者获得更高的利润。

规范

本文档中的关键词“必须 (MUST)”,“不得 (MUST NOT)”,“需要 (REQUIRED)”,“应 (SHALL)”,“不应 (SHALL NOT)”,“应当 (SHOULD)”,“不应当 (SHOULD NOT)”,“推荐 (RECOMMENDED)”,“不推荐 (NOT RECOMMENDED)”,“可以 (MAY)”,和“可选的 (OPTIONAL)”应按照 RFC 2119 和 RFC 8174 中的描述进行解释。

关键词 “BRIBE”(贿赂)和 “INCENTIVE”(激励)应解释为数字资产从用户 A 到用户 B 的转移,以换取用户 B 将在特定 DAO 的特定提案上按特定方向投票的保证。如果用户 B 不遵守协议,数字资产将返回给用户 A。

关键词 “BRIBER”(行贿者)、”INCENTIVIZER”(激励者)和 “SENDER”(发送者)应指用户 A 向用户 B 提供货币补偿。”RECIPIENT”(接收者)、”VOTER”(投票者)和 “INCENTIVIZEE”(被激励者)在此指用户 B,他们应在协议终止后正式收到其补偿。

关键词 “VOTE”(投票)应解释为在任何使用账户作为权限形式的治理系统中进行投票。

希望实施此类标准的合约必须实施以下接口

interface IEscrowedGovIncentive {

  struct incentive {
    address incentiveToken;
    address incentivizer;
    address recipient;
    uint amount;
    uint256 proposalId;
    bytes32 direction; //the keccack256 of the vote direction //投票方向的 keccack256
    uint96 deadline;
    uint96 timestamp;
    bool claimed;
  }

  event incentiveSent(address indexed incentivizer, address indexed token, uint256 indexed amount, address recipient, bytes data);

  event incentiveReclaimed(address incentivizer, address indexed recipient, address indexed token, uint256 indexed amount, bytes data);

  event modifiedClaimer(address recipient, address claimer, bool direction);

  event incentiveClaimed(address indexed incentivizer, address voter, bytes32 incentiveId, bytes proofData);

  event disputeInitiated(bytes32 indexed incentiveId, address indexed plaintiff, address indexed defendant);

  event disputeResolved(bytes32 indexed incentive, address indexed plaintiff, address indexed defendant, bool dismissed);


  //Core mechanism //核心机制
  function incentivize(bytes32 incentiveId, bytes memory incentiveInfo) external payable;

  function claimIncentive(bytes32 incentiveId, bytes memory reveal, address payable recipient) external;
  
  function reclaimIncentive(bytes32 incentiveId, bytes memory reveal) external;
  
  function verifyVote(bytes32 incentive, bytes memory voteInfo) external view returns (bool isVerifiable, bytes proofData);

  function modifyClaimer(address claimer, bool designation) external;

  //Dispute Mechanism //争议机制
  function beginDispute(bytes32 incentiveId, bytes memory disputeInfo) external payable;

  function resolveDispute(bytes32 incentiveId, bytes memory disputeResolutionInfo) external returns (bool isDismissed);

}

可选的实现细节

以下是上述系统针对不同方面的三个潜在实现示例。

完全透明

在此版本中,有关投票方向、金额和接收者的所有信息始终公开。信息以纯文本形式在 calldata 中传递,并按原样存储/发出。

完成前不透明 (OUC)

在此模型中,接收者、方向和金额在领取激励之前保持秘密。在此模型中,数据被提交,并且加密版本作为 calldata 传递。可以使用接收者的公钥加密此数据。它应该按原样发出,然后接收者可以在链下解密并用于确定是否遵守。在此模型中,为了确保将资金转移到托管中的隐私,激励者可以使用诸如具有 create2 操作码的确定性地址生成之类的方法。

在领取贿赂时,接收者只需打开提交内容,然后将在链上检查并释放资金。

与链下投票的兼容性

许多 DAO 在链下运行,通常通过像 snapshot 这样的投票平台。该系统允许使用已知的签名数据来实现此类兼容性。考虑以下示例

  1. 用户 A 向用户 B 承诺在 snapshot 上投票的激励。用户 B 投票。
  2. 一旦截止日期过去,就会启动一个质询窗口。激励者有一个预定的窗口来证明贿赂没有兑现。这可以通过简单地将用户 B 签署的签名传递给合约,该签名与贿赂的方向相反。如果可以验证签名,则该安排未得到兑现,并且可以安全地将资金返还给用户 A。
  3. 如果质询窗口结束时 A 无法提供不合规的证据,则 B 可以领取奖励。如果 B 的投票与激励一致,则 A 将无法生成有效的不合规签名。A 证明不合规的质询窗口是必要的,因为否则 B 可以简单地签署一条消息而不广播它,从而允许他们无需投票即可领取奖励。
  4. 如果 B 根本没有投票,则可以进入一个特殊的质询期。由于 B 根本没有投票,A 将无法提供必要的证据,但 B 仍然能够在不遵守的情况下领取奖励。在这种情况下,用户 A 将可以选择进入一个特殊的争议期。这方面的细节由合约实现决定。这可以包括由可信的第三方解决,或其他方法。一个例子是使用 merkle 根来表明 B 不在提案结论时的选民列表中。应考虑让 A 出示一个

方法

虽然此 EIP 定义了一个结构体 incentive,但应尽可能使用 bytes memory。鉴于每个 DAO 都有自己的实现细节、接口和签名数据,因此应使用 abi.decode() 解码并根据这些已知规范进行解释。

incentivize

激励者应该承诺其激励细节的函数。承诺值可以在链下计算,也可以在完全透明的系统中在链上计算。该函数应从 incentiveInfo 中获取输入数据,并在映射 incentives 中创建一个新的 incentive 对象。如果启用了 OUC,则只需要公开激励者和时间戳信息,其他所有内容都应保留为零。

函数应考虑从用户存款中收取的费用。如果存在费用,则 incentivize 应预先收取。这是为了确保向接收者报价的金额 至少 与他们将收到的金额一样多。

必须发出 incentiveSent 事件

- name: incentivize
  type: function
  stateMutability: payable

  inputs:
    - name: incentiveId
      type: bytes32
    - name: incentiveInfo
      type: bytes memory

claimIncentive

应由先前承诺的激励的预期接收者使用。

如果 msg.sender != original_recipient!allowedClaimer[original_recipient][msg.sender],则必须回退

如果 reveal 中提供的数据与 incentiveId 承诺的数据不匹配,则必须回退。

如果在函数结束时无法将承诺的所有资金 properly 发送到 recipient,则必须回退。如果存在费用,则在存款时应存在额外资金,以确保 至少 将承诺的金额发送给用户。但是,这 适用于批准的声明者可能收取的任何费用。

例如:Alice 承诺给 Bob 100 USDC 的激励。Bob 已批准 Eve 代表他领取,以换取净值的 5%。函数应检查支付给 Bob 和 Eve 的金额是否 >=100 USDC,但 检查 Bob 本身是否收到 >=100 USDC

如果无法验证原始接收者的投票方向是否与 incentiveId 的预期方向一致,并且未定义争议解决流程,则必须回退。

如果指定的激励存在待处理的争议,则必须回退。

如果验证成功,则应将资金发送给 recipient

如果函数未回退,则必须发出 incentiveClaimed 事件。

- name: claimIncentive
  type: function
  stateMutability: nonpayable

  inputs:
    - name: incentiveId
      type: bytes32
    - name: reveal
      type: bytes memory
    - name: recipient
      type: address payable

reclaimIncentive

函数应由 incentiveId 的初始发送者调用,以防 recipient 未按照激励的 direction 进行投票。该函数应将 incentiveId 最初承诺的资金返还给 incentivizer

如果无法将承诺的所有资金返还给激励者,则必须回退。

如果该函数无法成功验证 msg.sender 的不合规声明的有效性,则必须回退。

如果验证成功,则必须发出 incentiveReclaimed 事件。如果可以在链上检索证明,则 proof 参数可以留空。

如果指定的激励存在待处理的争议,则必须回退。

如果收取费用,则应将包括任何预付费用在内的所有资金返还给 incentivizer

- name: reclaimIncentive
    type: function
    stateMutability: nonpayable
  
    inputs:
      - name: incentiveId
        type: bytes32
      - name: reveal
        type: bytes memory

verifyVote

function verifyVote(bytes32 incentive, bytes memory voteInfo) public view returns (bool isVerifiable);

函数用于确定 incentive 的投票者是否应收到最初承诺的激励。

函数可以使用他们喜欢的任何方案来确定此信息。必要的数据应进行编码并通过 voteInfo 传递。

如果 voteInfo 表明 recipient 未按 incentive 承诺的方向投票,则必须返回 false,否则返回 true。

- name: verifyVote
  type: function
  stateMutability: view

  inputs:
    - name: incentiveId
      type: bytes32
    - name: voteInfo
      type: bytes memory

  outputs: 
    - name: isVerified
      type: bool
    - name: proofData
      type: bytes memory

modifyClaimer

函数更改地址的指定,使其被批准代表另一个用户领取贿赂。只有经过批准的声明者才能代表批准他们的用户领取激励。

- name: modifyClaimer
  type: function
  stateMutability: nonpayable

  inputs:
    - name: claimer
      type: address
    - name: designation
      type: bool

beginDispute

一个函数,用于通过可选的争议机制启动对激励的解决。开发人员可以自行决定,并根据投票验证机制的具体情况(其中无法最终确定投票方向),选择额外的机制来解决各方之间的争议。这可能包括第三方干预、额外的密码学证据等,以确定是将奖励支付给 recipient 还是将其返还给 incentivizer

可能需要额外争议机制的潜在示例:

  1. 需要可信的第三方来解决争议。
  2. 接收者未在链下提案中投票,并且需要额外的链下信息来确认。
  3. 需要额外的解锁机制才能访问先前存入的资金。

争议机制可以选择要求申诉人提供保证金,以防止无意义的申请,并在争议成功解决后将其退还给他们。

必须发出 disputeInitiated 事件

一旦对给定的激励提出争议,在完成之前,incentivizerrecipient 都不应能够提取资金。

- name: beginDispute
  type: function
  stateMutability: payable

  inputs:
    - name: incentiveId
      type: bytes32
    - name: disputeInfo
      type: bytes memory

resolveDispute

一个函数,用于解决关于 incentiveId 的待处理争议。确切的机制应由开发人员指定。

如果该机制通过表明他们确实兑现了 incentiveId 的激励措施来解决对被告 (recipient) 有利的争议,则必须返回 false,并且被 “驳回”。如果争议被 “确认”,则该函数应返回 true。

如果争议被 dismissed,则必须将 incentivizer 承诺的资金转移给 recipient,并将 funds + fee + bond 退还给 plaintiff。如果被驳回,则保证金的分配应由开发人员自行决定。这可能包括销毁、授予被告或捐赠给社区金库。

必须在成功解决后发出 disputeResolved 事件。

- name: resolveDispute
  type: function
  stateMutability: nonPayable

  inputs:
    - name: incentiveId
      type: bytes32
    - name: disputeResolutionInfo
      type: bytes memory
  
  outputs: 
    - name isDismissed
      type: bool

事件

incentiveSent

incentivizer 为某些信息贿赂了 recipient amounttoken

如果系统是私有的,则接收者、金额和 token 可以保留为零。

- name: incentiveSent
  type: event

  inputs: 
    - name incentivizer
      indexed: true
      type: address
    - name: token
      indexed: true
      type: address
    - name: amount
      indexed: true
      type: uint256
    - name: recipient
      indexed: true
      type: address

incentiveClaimed

recipient 领取了 amounttoken 的激励以及任何其他相关数据。

- name: incentiveClaimed
  - type: event

  inputs:
    - name: recipient
      indexed: true
      type: address
    - name: token
      indexed: true
      type: address
    - name: amount
      indexed: true
      type: uint256
    - name: data
      indexed: false
      type: bytes

modifiedClaimer

一个新的 claimer 要么被 recipient 列入白名单,要么被列入黑名单。

- name: modifiedClaimer
  type: event

  inputs:
    - name: recipient
      indexed: false
      type: address
    - name: claimer
      indexed: false
      type: address
    - name: direction
      indexed: false
      type: bool

incentiveReclaimed

incentivizer 正在收回 incentiveId,并揭露 voter 的不合规行为

- name: incentiveReclaimed
  type: event

  inputs: 
    - name: incentivizer
      indexed: true
      type: address
    - name: voter
      indexed: true
      type: address
    - name: incentiveId
      indexed: false
      type: bytes32
    - name: proofData
      indexed: false
      type: bytes

disputeInitiated

incentivizer 已针对 incentiveIdplaintiff 提起争议

- name: disputeInitiated
  type: event

  inputs: 
    - name: incentiveId
      indexed: true
      type: bytes32
    - name: plaintiff
      indexed: true
      type: address
    - name: defendant
      indexed: true
      type: address

disputeResolved

关于 incentiveId 的争议已解决,要么 dismisseddefendant 有利,要么解决对 plaintiff 有利

- name: disputeResolved
  type: event

  inputs:
    - name: incentiveId
      indexed: false
      type: bytes32
    - name: plaintiff
      indexed: true
      type: address
    - name: defendant
      indexed: true
      type: address
    - name: dismissed
      indexed: true
      type: bool
      

理由

这个设计是由几个因素驱动的:

  1. 为投票提供激励的问题是不可避免的。没有任何机制可以阻止用户在线下串通以按某个方向投票,并且通过足够的混淆,可以完全从社区的视野中隐藏起来。因此,解决方案是以一种既能提高透明度,又能实现贿赂收入去中心化的方式来重新调整这些参与者的激励措施。Flashbots 是一个相关的例子。由于 MEV 无法阻止,因此解决方案是通过激励矿工使用 Flashbots-Geth 来更公平地分配利润。使用场外交易市场结构具有相同的效果,允许任何人获得潜在激励的好处,同时还创建更有效的市场。

  2. 注入关于谁在贿赂谁以及为什么贿赂的透明度可以提高公平性和盈利能力。这使得社区有可能围绕潜在的解决方案进行组织。例如:Alice 为 Bob 在 DAO 中的 1k 票支付 10 美元。现在链上已知,下次关心结果的人可以为 Bob 的选票提供 11 美元。这最大限度地提高了接收者的利润。

实现应类似于以下示例:

  1. Alice 想给 Bob 10 美元,以便在 DAO 提案 #420 上投赞成票。她想要保证他会这样做,如果他没有这样做,就会拿回这笔钱

  2. 它应该作为一个托管服务,用于链上和基于 snapshot 的投票,只有在投票结束后才释放资金,并且可以验证接收者是否按投票进行投票。应该在不需要可信的第三方自己托管和释放资金的情况下完成。

  3. 此 EIP 不区分将此信息传递给接收者的性质。实现细节由协议自行决定。这包括为接收者和金额启用隐私的可选决定。以下是有关如何实现此目的的信息。一旦投票发生,则在验证后可以申领贿赂的内容。此验证应满足健全性和完整性,即只有在用户可以证明他们确实按照激励进行投票后,他们才能收到资金,并且此类证明不能以任何方式伪造或具有误导性。

要考虑的因素

  1. 为了解决奖励被稀释的问题,该系统使用了一个简单的基于哈希的承诺方案。当发送激励时,其数据会被承诺,并在提取时显示。

  2. 一旦承诺贿赂,在提案的投票期结束后才能撤回。这是为了确保托管的合法性,以便用户 A 在 B 投票后但在他们可以领取奖励之前无法撤回贿赂。

潜在的伦理问题

对于可能鼓励用户接受金钱支付以换取投票的前景,已经提出了一些潜在的伦理问题。这是一个错误的参照系。问题不在于鼓励用户发送/索取是否合乎道德,而在于什么都不做的后果。回到 flashbots 的例子,问题不在于 MEV 是否合乎道德,而在于允许它在没有反击的情况下蓬勃发展的后果。

如果不采取任何措施,可能会出现以下结果:

  1. 飞轮效应 - 只有专注且经济充裕的持有人才会肆无忌惮地索取激励。这种利润的集中化使他们能够购买更多的投票权,从而增加权力等等,直到他们积累了临界质量,从而对运营产生潜在的有害影响。这可能从 minor 的运营决策到财务决议的投票不等。

  2. 缺乏透明度 - 由于选民的真实意图不明确,决策将在闭门造车中进行,应该通过的投票可能会失败,反之亦然。社区的意愿将不会得到尊重。

向后兼容性

未发现向后兼容性问题。

安全考虑

本标准旨在与现有治理系统一起使用。现有治理中的任何潜在问题也可能代表对本标准的潜在攻击。这包括投票权重操纵、投票伪造、验证差异等。应正确审核与此 EIP 集成的所有系统,以实现最大安全性,因为任何问题都可能导致这些治理激励措施的分配不当。

该系统的潜在实现也可能依赖于复杂的密码学操作。这可能包括数字签名的正确实现以防止重放攻击,或 SNARK 证明的正确性要求。这些功能可能 并非微不足道,因此需要特别注意以确保它们安全地实施和配置,否则可能会违反诸如机密性之类的功能。

版权

版权和相关权利通过 CC0 放弃。

Citation

Please cite this document as:

Josh Weintraub (@jhweintraub), "ERC-6506: P2P 托管治理激励 [DRAFT]," Ethereum Improvement Proposals, no. 6506, February 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-6506.