Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Governor with multiple choice #3077

Open
frangio opened this issue Jan 5, 2022 · 11 comments
Open

Governor with multiple choice #3077

frangio opened this issue Jan 5, 2022 · 11 comments

Comments

@frangio
Copy link
Contributor

frangio commented Jan 5, 2022

There seems to be interest in the ability to create multiple choice proposals.

This issue is for gathering concrete use cases that can help guide the design. This may or may not be related to #3043.

@Amxx
Copy link
Collaborator

Amxx commented Jan 5, 2022

Would a multiple choice proposals be something like:

  • Option A: execute tx1
  • Option B: execute tx2
  • Option C: don't do anything

?

It's interesting, but it creates a lot of potential issues where, if tx1 and tx2 are somehow similar, they could lose to option C even though the sum of A and B outweigh C

@hack3r-0m
Copy link

does this proposal concern only with providing the ability to create multiple choice proposals or also with the nature and interpretation of the options/choices (for e.g if a proposal has options A, B, and C then does all need to be mutually exclusive)?

@frangio
Copy link
Contributor Author

frangio commented Jan 6, 2022

@hack3r-0m I think both. If we allow creation of multiple choice proposals we need to be clear about the meaning of such a proposal.

@Amxx Yes that sounds like something that could happen commonly. But the use case is legitimate: put up for a vote alternative proposals of which only one should be chosen. So what solution can we offer?

The problem you point out is that a naive simple majority is not ideal if some of the options are similar and voters are forced to choose between them even though they might support both. Maybe this means that multiple choice proposals should use some other voting system, like approval voting.

Maybe the answer is that multiple choice should be expressed as separate exclusive proposals somehow.

@kalikho
Copy link

kalikho commented Jan 6, 2022

Can a multi-choice proposal be thought of a single proposal with many sub-proposals as multiple choice options ? Also, can there be any provision for giving numeric score votes for the sub-proposals with already existing votes (for, against and abstain).

Consider a scenario for management of an asset. A proposal can be created with multiple sub-proposals as options such as the ownership duration, the minimum value price of the asset. Voters can vote for the proposal by giving their respective values for the options in case they are willing to do so or else they can simply abstain or reject.

At the end of the voting a suitable value for the sub-proposals can be obtained which can be an average of all the submitted values or any other suitable function.

@frangio
Copy link
Contributor Author

frangio commented Jan 7, 2022

Multiple choice proposals are those where the outcome is not "Yes or No", but "A or B or C or ...".

Proposals with sub-proposals, or voting with numeric scores, sounds like different features.

@crazyrabbitLTC
Copy link
Contributor

I would mention that the situation where Proposal A and B are similar and thus both lose out to the least popular C, is not really IMHO within the scope of the smart contract implementation. I think it's difficult to design the content of the proposals.

If you were to provide multiple executable code packages, and then provide the ability to choose which one executes in multiple-choice format, that seems like a very useful tool. Contradicting my own advice above, you could imagine a situation where the proposal is addressing one desired goal, but the multiple-choice part is for voters to choose their preferred implementation of that goal.

@LiveDuo
Copy link

LiveDuo commented Feb 21, 2022

Hey,

I’ve been looking for ways to implement multiple choice votes during the last week or two and just stumbled across this issue. Below I've written about my implementation, talk about an example and discuss some limitations of my implementation and possible ways to extend it.

Implementation

This POC allows creating a "proposal with options" where token holders can add options that other holders can vote on.

  • Extend propose function with proposeWithOptions. This creates a new proposal with a data type (eg. int, address, bool). For example, a proposal with an address data type can only have addresses options to vote one.
  • Create an addOptionToProposal method to allow adding options for voting. Options should respect the proposal data type. For example, a proposal with an address data type can only have addresses as options.
  • Extend _countVote so that votes are counted against their respective data type. This extends ProposalVote to contain an options field and a dataType field. For example, a proposal with an address data type will addresses as voting options. The address with the most votes will be included in the execution payload.
  • Extend queue with queueWithOptions and execute with queueWithOptions so the proposal queues and execute with calldata that include the parameter of the successful vote.

Relevant Contracts: GovernorContract.sol & GovernorCountingExtended.sol

Example

Consider a DAO that requires a real world action. This DAO can have an address hardcoded that will receive some funds to perform the real-world action or it can create a vote where anyone can apply with their address.

So any holder can proposal a transfer of ETH to the parameter address. Holders of the DAO token can add their address as a parameter. The address with the most votes will receive the ETH if the proposal succeeds.

Proposal Succeeded Scenario

Proposal: Transfer 2 ETH to parameter
Options: Address A, Address B, Address C, Abstain
Votes: Address A (60%), Address B (20%), Address C (10%), Abstain (10%)
Result: The "Address A" will receive 2 ETH

Proposal Fail Scenario

Proposal: Transfer 2 ETH to parameter
Options: Address A, Address B, Address C, Abstain
Votes: Address A (10%), Address B (20%), Address C (10%), Abstain (60%)
Result: Nothing will happen

Remarks

Backwards Compatibility

This is only backwards compatible with Compound Governance. So dashboards that only support Compound contracts won't fully work. It may be possible to create something that is completely compatible by creating multiple proposals and only allowing queuing and executing the one with the most votes. It seems a bit complex so I’m just throwing out the idea.

Adding Option Restrictions

Another thing to consider is restrictions in adding proposal options (ie. addOptionToProposal function). These should be fairly easy to extend the current implementation to support them. Possibilities include: quorum based limitations, pay to add a proposal, admin approval, restrict add options to only the proposal creator etc.

Counting Method

In the example code a proposal is succeeds if the sum proposal weighted votes is greater than the against votes. Another possible option is to require that the maximum votes is greater than against votes.

Voting System

The new propose function is a simple “plurality voting” system. It should be fairly easy to implement “approval voting” with minor adjustments to the _countVote method. Other systems that are multi round (eg. exhaustive ballot or instant-runoff) are not as similar and will require more changes to work.

PS: The example code above is a prototype and is expected to contain a quite a few bugs.

@yehted
Copy link

yehted commented Nov 22, 2022

What about something like https://eips.ethereum.org/EIPS/eip-1202, specifically the IERC1202MultiVote interface? I'm interested in something like this as well, and I just extended the OZ governor to implement that interface (although I did have to write my own custom counting module to tally up the multivote).

@nambrot
Copy link

nambrot commented Nov 27, 2022

Just wanted to leave a comment on here that we would love to collaborate with anybody interested in creating some kind of more flexible option. Even having the current simple Yes/No options be able to execute two different payloads would be progress in my opinion. A use case we have in mind is being able to vote on L2 where the governance contract holds some kind of voting power that it can then use on L1. Currently, a non-passing vote will not cause a no-vote on L1.

@0xShin0221
Copy link

0xShin0221 commented Feb 28, 2023

I have immense gratitude and respect for @LiveDuo for actually implementing such an example.

I have been contemplating this issue for a few days now, and it seems that making private variables public in the patch section could have various implications including potential security risks.

the patch:
https://github.com/LiveDuo/governance-example/blob/feature/multiple-options/patches/%40openzeppelin%2Bcontracts%2B4.4.1.patch

I also tried to focus on this area and attempted my own implementation, but it ended up being complicated with extensions to the governors and timelocks, as well as the need to handle the relevant patch’s issue like _proposals and _timelockIds in new storage as another name.

@LiveDuo
Copy link

LiveDuo commented Mar 1, 2023

@0xShin0221 Glad you had a deeper look.

I have been contemplating this issue for a few days now, and it seems that making private variables public in the patch section could have various implications including potential security risks.

I want to better understand the issue with the variables been public you have in mind. There's a problem with the variables been accessible from the smart contracts that imports governance which makes it easy update these variables by mistake. Then there's the issue of exposing these functions polluting the smart contract interface. Are there more security issues that I may be missing?


As a side note, I see these variable been public is not ideal. The reason I made them that way was to have minimal patches in the governor contracts and make it easy for other people who are familiar to understand my example.

A way to overcome the public variable might be to merge the code from GovernorContract.sol and openzeppelin-contracts/../Governor.sol into a new contract where there is access to _proposals and similarly openzeppelin-contracts/../GovernorTimelockControl.sol to access _timelock and _timelockIds.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants