Alert Source Discuss
🚧 Stagnant Standards Track: ERC

ERC-6506: P2P Escrowed Governance Incentives

Interface for building contracts that escrow funds based on an account taking action in a 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

Abstract

The following EIP defines the interface for a contract that facilitates the exchange of a governance-incentive for users to vote in a designated direction on a DAO-proposal while escrowing funds until the vote can be verified.

Motivation

While a ton of effort has gone into building bribe systems for DAOs like Curve, Frax, Convex, etc., not a lot of focus has been put on how bribes on other, more general DAO votes, may affect outcomes. Bribes are a lucrative market on many popular DAO’s, and it stands to reason that people are willing to accept them for voting on other proposals, especially if they have no personal stake in the outcome. There are however, problems with current systems:

  1. Current bribe schemes for votes based on pro-rata distribution are economically innefficient and result in worse outcomes for voters. For systems like Votium or Hidden-Hand, If Alice votes on a proposal with the expectation of receiving $10 in bribes, they can just be backrun by a larger voter, diluting their share of the pool. It may no longer be economical to make the decision they did. Using an OTC mechanisms is more efficient because the amount is “locked in” when the bribe is made and the recipient has much more concrete assurances on which to base their decision. These protocols are also centralized, relying on a central authority to accept and redistribute rewards fairly. Whenever possible, centralization should be avoided.

  2. The lack of an existing standard means that parties are relying entirely on trust in one-another to obey. Bob has to trust Alice to pay out and Alice has to trust Bob to vote. Even if the two of them were to use an escrow contract, it may have flaws like relying on a trusted third-party, or simply that it is outside the technical reach of both parties.

  3. There are no mechanisms for creating transparency into the collusion of actors. Users colluding off-chain to sway the vote of a large token-holder creates opaque outcomes with no accountability since everything happens off-chain.

  4. For actors that wish to solicit incentives for their vote, this may require either active management, or the doxxing of their identify/psuedononymous identifier. A user who wishes to negotiate would need to provide a way for incentivizers to contact them, engage in a negotiation process, write and deploy escrow contracts, vote, and then claim their reward. This is a lengthy and involved process that requires active management and communication. This creates a limit on who is able to solicit these incentives, and leads to the centralization of profit towards the few who can sustain this process at length.

  5. Bribe Revenue as subsidies. As Vitalik wrote in a 2019 article, On Collusion, a potential solution would be a token that requires voters for a proposal to purchase the governance-token if the proposal-passes, subsidizing the cost of a bad decision for everyone else. If the revenue generated from these incentives is used (at least partly) to directly buy back those tokens by the treasury, then you get a similar outcome. The impact of a bad proposal being passed via-bribing is subsidized for everyone who didn’t vote for it by having some value returned to token-holders. This not only makes malicious bribes more costly, as it has to offset the value accrued via buyback, but also means higher profits for recipients.

Specification

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119 and RFC 8174.

The key words “BRIBE” and “INCENTIVE” are to be interpreted as the transfer of a digital-asset(s) from user A to user B in exchange for an assurance that user B will vote in a specific-direction, on a specific proposal, for a specified-DAO. If user B does not honor the arrangement, the digital-asset(s) will be returned to user A.

The key words “BRIBER”, “INCENTIVIZER”, and “SENDER” shall refer to the user A offering monetrary compensation to user B. “RECIPIENT”, “VOTER”, and “INCENTIVIZEE” herein refer to user B whom shall formally receive their compensation upon the termination of the agreement.

The key word “VOTE” shall be interpreted as the casting of a ballot in any kind of governance system which uses accounts as a form of permissions.

Contracts wishing to implement such a standard must implement the following interface

interface IEscrowedGovIncentive {

  struct incentive {
    address incentiveToken;
    address incentivizer;
    address recipient;
    uint amount;
    uint256 proposalId;
    bytes32 direction; //the keccack256 of the vote direction
    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);

}

Optional Implementation Details

Below are three potential implementation examples of the above system for different aspects.

Complete Transparency

In this version all information about the vote direction, the amount, and the recipient are public at all times. Information is passed as calldata in plaintext and stored/emitted as such.

Opacity until Completion (OUC)

In this model, the recipient, the direction, and the amount are kept secret until the incentive is claimed. In this model, the data is committed to, and an encrypted version is passed as calldata. This data can be encrypted with the recipient’s public-key. It should be emitted as such which can then be decrypted off-chain by the recipient and used to make a determination on whether to oblige. In this model to ensure the privacy of transferring funds into escrow, the incentivizer could use methods such as deterministic-address-generation with the create2 opcode.

Upon the claiming of the bribe the recipient would simply open the committment, which would then be checked on-chain and funds released.

Compatibility with Off-Chain Voting

Many DAO’s operate off-chain, typically through voting platforms like snapshot. This sytem does allow for such compatability using known signature data. Consider the following example

  1. User A commits an incentive to user B to vote on snapshot. User B votes.
  2. Once the deadline has passed, a challenge window is initiated. The incentivizer has a predetermined window to demonstrate that the bribe was not honored. This can be done by simply passing to the contract a signature signed by User B voting in the opposite direction of the bribe. If the signature can be verified, then the arrangement was not honored and funds can be safely released back to user A.
  3. If the challenge window concludes without A being able produce proof of noncompliance, then B is able to claim the reward. If B voted inline with the incentive, A will not be able to produce a valid signature of noncompliance. The challenge window with A demonstrating noncompliance is necesarry, because otherwise B could simply sign a message and not broadcast it, allowing them to claim the reward without voting.
  4. In the event that B does NOT vote at all, then a special challenge period may be entered. Since B did not vote at all, A would not be able to produce the requisite proof, but B would still be able to claim the reward without complying. In this event, user A would have the option to enter a special dispute period. The details of this are determined by the contract implementation. This can include resolution by a trusted third-party, or other methods. An example includes using a merkle-root to show that B was not in the list of voters at the conclusion of the proposal. It should be considered making A present a

Methods

While this EIP defines a struct incentive, bytes memory should be used whenever possible. Given as each DAO will have its own implementation details, interfaces, and signature data, this should then be decoded using abi.decode() and interpreted according to those known specifications.

incentivize

The function where an incentivizer should commit to the details of their incentive. The commitment value can be calculated off-chain or calculated on-chain in a full transparency system. The function should take the input data from incentiveInfo and create store a new incentive object in the mapping incentives. If OUC is enabled, then only incentivizer and timestamp information need be public, everything else should be left as zero.

Function should account for fees taken from user at deposit. If fees are present, then incentivize should take them up front. This is to ensure that the amount quoted to a recipient is at least as much as they would receive.

MUST emit the incentiveSent event

- name: incentivize
  type: function
  stateMutability: payable

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

claimIncentive

Should be used by the intended recipient of a previously-committed incentive.

MUST revert if msg.sender != original_recipient and !allowedClaimer[original_recipient][msg.sender]

MUST revert if the data provided in reveal does not match the data committed to by incentiveId.

MUST revert if all funds committed to cannot be properly sent to recipient at conclusion of the function. If fees are present, then additional funds should be present at deposit to ensure that at least the amount committed to is sent to the user. This however, DOES NOT apply to any fees which may be taken by an approved claimer.

Ex: Alice commits to Bob an incentive 100 USDC. Bob has approved Eve to claim on his behalf in exchange for 5% of net value. Function should check that amount paid to Bob and Eve is >=100 USDC but NOT that Bob himself receives >=100 USDC

MUST revert if the voting direction of the original recipient cannot be verified as being in line with the intended direction of incentiveId, and no dispute resolution process is defined.

MUST revert if the specified incentive has a pending dispute.

If verification is successful then funds should be sent to recipient.

MUST emit the incentiveClaimed event if function does not revert.

- name: claimIncentive
  type: function
  stateMutability: nonpayable

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

reclaimIncentive

Function that should be invoked by the initial sender of incentiveId in the event that recipient did not vote in accordance with the incentive’s direction. Function should return the funds initially committed to by incentiveId to incentivizer

MUST revert if all of the funds committed to cannot be returned to the incentivizer.

MUST revert if the function cannot successfully verify the validity of msg.sender claim of non-compliance.

MUST emit the event incentiveReclaimed if verification is successful. If proof can be retrieved on-chain, then the proof parameter may be left empty.

MUST revert if the specified incentive has a pending dispute.

If fees are taken, then all funds including any prepaid fees committed to should be returned to the 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);

Function used to determine if the voter for incentive should receive the incentive originally committed to.

Functions may use whatever scheme they like to determine this information. Necesarry data should be encoded and passed through voteInfo.

MUST return false if voteInfo indicates that recipient did not vote in the direction committed to by incentive, and true otherwise.

- 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

Function changing the designation of an address as being approved to claim a bribe on behalf of another user. Only an approved claimer should be able to claim the incentive on behalf of the user which approved them.

- name: modifyClaimer
  type: function
  stateMutability: nonpayable

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

beginDispute

A function used to initiate the resolution of an incentive through an optional dispute-mechanism. At the discretion of the developers, and based on the specifics of the vote-verification mechanism in which a voting direction cannot be conclusively decided, the developers may opt for an additional mechanism to resolve dispute between parties. This may include third-party intervention, additional cryptographic evidence, etc. needed to determine whether to pay out rewards to recipient or return them to the incentivizer

Potential Examples requiring additional dispute mechanisms:

  1. Requiring a trusted third-party to resolve disputes.
  2. The recipient did not vote in an off-chain proposal, and additional off-chain information is needed to confirm.
  3. An additional unlocking mechanism is required to access previously deposited funds.

Dispute mechanisms may optionally choose to require a bond from the filer to prevent frivolous filings, to be returned to them on successful resolution of the dispute in their favor.

Must emit the event disputeInitiated

Once a dispute for a given incentive has been filed, neither the incentivizer nor recipient should be able to withdraw funds until completed.

- name: beginDispute
  type: function
  stateMutability: payable

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

resolveDispute

A function which is used to resolve pending disputes over incentiveId. The exact mechanism shall be specified by the developers.

MUST return false, and be “dismissed”, if the mechanisms resolves the dispute in favor of the defendant (recipient), by showing they did honor the incentive of incentiveId. If the dispute is “confirmed”, then the function should return true.

MUST transfer funds committed to by incentivizer to recipient if dispute is dismissed and return funds + fee + bond to the plaintiff. If dismissed, the distribution of the bond shall be at the discretion of the developers. This may including burning, awarding to the defendant, or donating to a community treasury.

MUST emit the event disputeResolved on successful resolution.

- name: resolveDispute
  type: function
  stateMutability: nonPayable

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

Events

incentiveSent

incentivizer has bribed recipient amount of token for some information.

If system is private then recipient, amount, and token may be left as zero.

- 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 claimed an incentive amount of token and any other data relevant.

- 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

A new claimer was either whitelisted by recipient or blacklisted.

- name: modifiedClaimer
  type: event

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

incentiveReclaimed

An incentivizer is reclaiming incentiveId, and outing the noncompliance of 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 has initiated a dispute with plaintiff over incentiveId

- name: disputeInitiated
  type: event

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

disputeResolved

The dispute over incentiveId has been resolved, either dismissed in favor of defendant or resolved in favor of the 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
      

Rationale

This design was motivated by a few factors:

  1. The issue of offering incentives for votes is an inevitability. There is no mechanism that can prevent users from colluding off-chain to vote a certain direction, and with enough obfuscation, can be completely hidden from the community’s view. The solution is therefore to realign the incentives of these actors in a way that both creates transparency, while allowing for the decentralization of bribe-revenue. Flashbots is a relevant example. Since MEV could not be prevented, the solution was to make it more fairly distributed by incentivizing miners to use Flashbots-Geth with profits. Using an OTC market structure would have the same effect, allowing anyone to reap the benefits of a potential incentive while also creating a more efficient marketplace.

  2. Injecting transparency about whom is bribing whom for what increases both fairness and profitability. This makes it possible for the community to organize around potential solutions. Ex: Alice pays Bob $10 for his 1k votes in the DAO. This is now known on-chain and next time someone who cares about the outcome can offer Bob $11 for the votes. This maximizes profit to the recipient.

Implementations should operate similar to the following example:

  1. Alice wants to give bob $10 to vote YES on DAO proposal #420. She wants an assurance he will do it and gets the money back if he doesn’t

  2. It should work as an escrow service for both on-chain and snapshot based voting, releasing funds only after the vote has concluded, and it can be verified the recipient voted in line with the vote. It should be done without requiring a trusted third-party to escrow and release the funds themselves.

  3. This EIP makes no discernment about the nature in which this information is relayed to the recipient. Implementation details are at the discretion of the protocol. This includes the optional decisions to enable privacy for both the recipient and the amount. Information on how this can be implemented is below. Once the vote has occured, then the contents of the bribe can be claimed, pending verification. This verification should satisfy both soundness and completeness, that only after the user can show they did vote in line with the incentive do they receive the funds, and that such proof cannot be forged or misleading in any way.

Factors to consider

  1. To remedy the problem of diluted rewards, the system uses a simple hash-based commitment scheme. When an incentive is sent, its data is committed to, and revealed when withdrawn.

  2. Once a bribe is committed to, it cannot be withdrawn until after the voting period for the proposal has concluded. This is to ensure the legitimacy of the escrow, so that user A cannot withdraw the bribe after B has voted, but before they can claim the reward.

Potential Ethical Issues

Potential ethical issues have been raised about the prospect of potentially encouraging users to accept monetary payment for their vote. This is the wrong frame of reference. The question is not whether it is ethical to encourage users to send/solicit, but rather the consequences of doing nothing. Returning to the flashbots example, the question is not whether MEV is ethical, but reprecussions of allowing it to flourish without pushback.

If nothing is done, the following outcomes are possible:

  1. Flywheel Effect - Only dedicated and financially endowed holders will solicit incentives with impunity. This centralization of profit allows them to purchase more voting-rights, increasing power and so on until they have accumulated a critical mass, exerting potentially harmful influence over operations. This can range anywhere from minor operational decisions, to votes over treasury resolution.

  2. Lack of transparency - Decisionmaking will occur behind closed doors as the true intentions of voters is unclear, and votes that should pass may fail, or vice-versa. The will of the community will not be honored.

Backwards Compatibility

No backward compatibility issues found.

Security Considerations

This standard is intended to work with existing governance systems. Any potential issue with existing governance may represent a potential attack on this as well. This includes voting-weight manipulation, vote forgery, verification discrepancies etc. All systems in which this EIP is integrated with should be properly audited for maximum security, as any issues may result in improper distribution of these governance incentives.

Potential implementations of this system may rely on complex cryptographic operations as well. This may include proper implementation of digitial-signatures to prevent replay attacks, or correctness requirements of SNARK proofs. These features may be non-trivial and thus require special care to ensure they are implemented and configured securely, otherwise features like confidentiality may be violated.

Copyright and related rights waived via CC0.

Citation

Please cite this document as:

Josh Weintraub (@jhweintraub), "ERC-6506: P2P Escrowed Governance Incentives [DRAFT]," Ethereum Improvement Proposals, no. 6506, February 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-6506.