Let’s say we have a voting contract or a joint-spending contract similar to here. In this setting voters have some specific token that allows them to have a specific “voting power”. For example, if there are a total of 100
of token x
and Alice owns 15
x
then she has 15%
of the entire voting power.
We’d like to have an efficient way of voting. Voting is a general concept and many applications can be reduced to it, e.g., joint-spending, changing parameters of some dApp, etc.
Without the loss of generality, let’s consider the joint-spending case where there are some funds protected by a joint-spending contract similar to the idea here. How can we allow Alice to participate in a voting while:
- There may be many proposals for her to decide and vote on.
- Tokens that she owns may not be specifically issued for joint-spending and voting and she may want to keep them in her wallet because of other functionalities, e.g., LP tokens or governance tokens.
When we consider these realistic assumptions, we won’t be able to use naive approaches for voting.
For example, one naive approach is for Alice to put his tokens in some special contract that is showing that she has voted “yes” for some proposal. But how long does she have to wait for other voters to cast their votes and a decision be made for the proposal for her tokens to be released? What if she wants to participate in other proposals as well? What if she needs to have the tokens in her wallet for some reason?
In this post, I propose a solution to the outlined issues above. Particularly, I propose a solution which:
- Let’s Alice keep her tokens in her wallet all the time and hence allowing her to participate in as many simultaneous votes as she desires while having the luxury of tokens not leaving her wallet!
- Preventing Alice from double voting. Double voting is a side effect of not keeping her tokens in a special contract that makes sure she doesn’t use them multiple times.
This solution is a combination of already found design patterns here and here. Here is the procedure:
- Alice creates a transaction where the voting tokens (
x
in the example above) are in the first input. - Alice can simply decide the number of tokens she wants to include in the input which shows how much of her power she wants to use for voting.
- In that transaction, Alice issues a token which by definition will have the same ID as the box containing the voting tokens in the first input.
- Additional information may be placed in the registers of this output and it may also be protected by some special contract. These details are application-dependant and do not influence this proposal.
- Now it can easily be proven to the voting contract that Alice has voted for a specific proposal:
- Provide the issued token’s box as data input and the spent input (that contained the voting tokens) to the contract.
- With this information, the contract can first make sure that the vote is legit using here and also can know the number of cast votes.
- The voting contract also needs to make sure that this is not a double vote. This can be easily achieved by providing the current Alice’s unspent box(es) that contains her voting tokens as data inputs. Then the contract can check the spent box’s address is the same as the boxes that currently have the tokens. This only can be achieved if Alice keeps the tokens in the same address as she used for issuing the token. This requirement in practice is not limiting if the change address is used for issuing the token.
Some details are left out but the main idea should be clear! The limitation of this approach is that the final transaction that is collecting votes is going to be big if we have many voters. This remains to be solved!