DCIPs/EIPS/eip-6506.md

486 lines
24 KiB
Markdown
Raw Normal View History

---
eip: 6506
title: P2P Escrowed Governance Incentives
description: Interface for building contracts that escrow funds based on an account taking action in a DAO
author: Josh Weintraub (@jhweintraub)
discussions-to: https://ethereum-magicians.org/t/escrowed-and-private-bribes-for-generalized-dao-voting/12694
status: Draft
type: Standards Track
category: ERC
created: 2023-02-15
---
## 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 DAOs, 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
```solidity
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
```yaml
- 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.
```yaml
- 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`.
```yaml
- 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.
```yaml
- 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.
```yaml
- 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.
```yaml
- 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.
```yaml
- 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.
```yaml
- 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.
```yaml
- 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.
```yaml
- 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`
```yaml
- 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`
```yaml
- 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`
```yaml
- 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 doesnt
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
Copyright and related rights waived via [CC0](../LICENSE.md).