github.com/cosmos/cosmos-sdk@v0.50.10/docs/architecture/adr-037-gov-split-vote.md (about) 1 # ADR 037: Governance split votes 2 3 ## Changelog 4 5 * 2020/10/28: Intial draft 6 7 ## Status 8 9 Accepted 10 11 ## Abstract 12 13 This ADR defines a modification to the governance module that would allow a staker to split their votes into several voting options. For example, it could use 70% of its voting power to vote Yes and 30% of its voting power to vote No. 14 15 ## Context 16 17 Currently, an address can cast a vote with only one options (Yes/No/Abstain/NoWithVeto) and use their full voting power behind that choice. 18 19 However, often times the entity owning that address might not be a single individual. For example, a company might have different stakeholders who want to vote differently, and so it makes sense to allow them to split their voting power. Another example use case is exchanges. Many centralized exchanges often stake a portion of their users' tokens in their custody. Currently, it is not possible for them to do "passthrough voting" and giving their users voting rights over their tokens. However, with this system, exchanges can poll their users for voting preferences, and then vote on-chain proportionally to the results of the poll. 20 21 ## Decision 22 23 We modify the vote structs to be 24 25 ```go 26 type WeightedVoteOption struct { 27 Option string 28 Weight sdk.Dec 29 } 30 31 type Vote struct { 32 ProposalID int64 33 Voter sdk.Address 34 Options []WeightedVoteOption 35 } 36 ``` 37 38 And for backwards compatibility, we introduce `MsgVoteWeighted` while keeping `MsgVote`. 39 40 ```go 41 type MsgVote struct { 42 ProposalID int64 43 Voter sdk.Address 44 Option Option 45 } 46 47 type MsgVoteWeighted struct { 48 ProposalID int64 49 Voter sdk.Address 50 Options []WeightedVoteOption 51 } 52 ``` 53 54 The `ValidateBasic` of a `MsgVoteWeighted` struct would require that 55 56 1. The sum of all the Rates is equal to 1.0 57 2. No Option is repeated 58 59 The governance tally function will iterate over all the options in a vote and add to the tally the result of the voter's voting power * the rate for that option. 60 61 ```go 62 tally() { 63 results := map[types.VoteOption]sdk.Dec 64 65 for _, vote := range votes { 66 for i, weightedOption := range vote.Options { 67 results[weightedOption.Option] += getVotingPower(vote.voter) * weightedOption.Weight 68 } 69 } 70 } 71 ``` 72 73 The CLI command for creating a multi-option vote would be as such: 74 75 ```shell 76 simd tx gov vote 1 "yes=0.6,no=0.3,abstain=0.05,no_with_veto=0.05" --from mykey 77 ``` 78 79 To create a single-option vote a user can do either 80 81 ```shell 82 simd tx gov vote 1 "yes=1" --from mykey 83 ``` 84 85 or 86 87 ```shell 88 simd tx gov vote 1 yes --from mykey 89 ``` 90 91 to maintain backwards compatibility. 92 93 ## Consequences 94 95 ### Backwards Compatibility 96 97 * Previous VoteMsg types will remain the same and so clients will not have to update their procedure unless they want to support the WeightedVoteMsg feature. 98 * When querying a Vote struct from state, its structure will be different, and so clients wanting to display all voters and their respective votes will have to handle the new format and the fact that a single voter can have split votes. 99 * The result of querying the tally function should have the same API for clients. 100 101 ### Positive 102 103 * Can make the voting process more accurate for addresses representing multiple stakeholders, often some of the largest addresses. 104 105 ### Negative 106 107 * Is more complex than simple voting, and so may be harder to explain to users. However, this is mostly mitigated because the feature is opt-in. 108 109 ### Neutral 110 111 * Relatively minor change to governance tally function.