Code in Github: aragon-apps/apps/voting
The Voting app is an entity that will execute a set of actions on other entities if token holders of a particular token decide to do so.
The Voting app is instantiated with a certain set of parameters that won’t be changeable for the lifetime of the app:
- Token: address of the MiniMe token whose holders have voting power proportional to their holdings.
- Support required: what % of the votes need to be positive for the vote to be executed. Making it 50% would be a 'simple democracy'.
- Minimum acceptance quorum: minimum % of all token supply that needs to approve in order for the voting to be executed.
- Voting time: number of seconds a vote will be opened, if not closed prematurely for outstanding support.
The only parameter that can be changed is 'Minimum acceptance quorum' for protecting against the case in which there is not enough voter turnout.
A Note on Percentages
If you are a front end user you can skip this section, but if you are a developer and want to manipulate the Voting contract directly these are some notes you should consider.
The variables "Support required" and "Minimum acceptance quorum" are percentages that are expressed between zero and a maximum of 10^18 (that represents 100%). As a consequence, it's important to consider that 1% is actually represented by 10^16.
Moreover you should pass to the smart contract the actual number, not the scientific notation so: - 10^16 is 10000000000000000 (or 1 with 16 zeros) - 10^18 is 1000000000000000000 (or 1 with 18 zeros)
Here are a few percentages you can use
|Percentage||Scientific Notation||actual input passed to the smart contract|
votingApp.newVote(bytes _executionScript, string _metadata)
A new vote is initialized with:
- Execution script: EVM call script to be executed on vote approval, contains a series of addresses and calldata payloads that will be executed.
- Metadata: An arbitrary string that can be used to describe the voting.
The voting app conforms to the aragonOS Forwarder interface. A generic forward action will create a vote with the provided execution script and empty metadata.
When a vote is created a reference to the previous block number is saved as the snapshot block for the vote. The reason the previous block number is used is to avoid double voting in the same block the vote is created. Whenever a vote is casted, the MiniMeToken associated with the app is checked for the token balance of the voter at the snapshot block.
votingApp.vote(uint256 _voteId, bool _supports)
In order for casting a vote all these conditions must be met:
- Sender had a positive token balance in the token at the vote snapshot block.
- Vote hasn't expired.
- Vote hasn't been already executed.
If the casted vote is in support of the vote, the number of tokens held by the sender at the snapshot block will be added to the vote
yea counter. In case a vote is against, it will add it to the
After any casted votes, the contract checks whether a vote already has the complete support to be executed (even if everyone else voted against, the vote would still be approved), in that case the vote is executed and closed.
After a vote has expired time-wise (and no more votes are allowed), the result of the vote can be executed by anyone if it was approved. For a vote to be considered approved both conditions must be true:
- The percentage of
yeaout of the total number of votes is greater than or equal the 'Support required' global parameter.
yeasupport is greater than or equal the 'Minimum acceptance quorum' global parameter.
Changing acceptance minimum quorum
At any time, the minimum acceptance quorum for the new votes can be modified.
Any open votes will maintain the value minimum acceptance quorum was when they were created.
Forwarding using the common interface executes a
votingApp.newVote(...) action. ACL is checked for whether the sender has permissions to create a vote.