Voting Contract
In this tutorial, we're going to deploy a contract that allows users to vote on multiple proposals that a voting administrator controls.
With the advent of blockchain technology and smart contracts, it has become popular to try to create decentralized voting mechanisms that allow large groups of users to vote completely on chain. This tutorial will provide an example for how this might be achieved by using a resource-oriented programming model.
We'll take you through these steps to get comfortable with the Voting contract.
- Deploy the contract to account
0x06 - Create proposals for users to vote on
- Use a transaction with multiple signers to directly transfer the
Ballotresource to another account. - Record and cast your vote in the central Voting contract
- Read the results of the vote
Open the starter code for this tutorial in the Flow Playground
A Voting Contract in Cadence
In this contract, a Ballot is represented as a resource.
An administrator can give Ballots to other accounts, then those accounts mark which proposals they vote for and submit the Ballot to the central smart contract to have their votes recorded.
Using a resource type is logical for this application, because if a user wants to delegate their vote, they can send that Ballot to another account, and the use case of voting ballots benefits from the uniqueness and existence guarantees inherent to resources.
Write the Contract
Open Contract 1 - the ApprovalVoting contract. Follow the instructions in the comments of the contract to write your own approval voting contract.
Instructions for transactions are also included in the sample transactions.
Deploy the Contract
- In the bottom right deployment modal, press the arrow to expand and make sure account
0x06is selected as the signer. - Click the Deploy button to deploy it to account
0x06
Perform Voting
Performing the common actions in this voting contract only takes three types of transactions.
- Initialize Proposals
- Send
Ballotto a voter - Cast Vote
We have a transaction for each step that we provide a skeleton of for you.
With the ApprovalVoting contract deployed to account 0x06:
- Open Transaction 1 which should have
Create Proposals - Submit the transaction with account
0x06selected as the only signer.
This transaction allows the Administrator of the contract to create new proposals for voting and save them to the smart contract. They do this by calling the initializeProposals function on their stored Administrator resource, giving it two new proposals to vote on. We use the post block to ensure that there were two proposals created, like we wished for.
Next, the Administrator needs to hand out Ballots to the voters. There isn't an easy deposit function this time for them to send a Ballot to another account, so how would they do it?
Putting Resource Creation in public capabilities
Unlike our other tutorial contracts, the Approval Voting contract puts its Ballot creation function in a resource instead of as a public function in a contract.
This way, the admin can control who can and cannot create a Ballot resource. There are also ways to consolidate all of the voting logic into the Admin resource so that there can be multiple sets of proposals being voted on at the same time without having to deploy a new contract for each one!
Here, we're just exposing the create ballot function through a public capability for simplicity, so lets use the transaction for a voter to create a ballot.
- Open the
Create Ballottransaction. - Select account
0x07as a signer. - Submit the transaction by clicking the
Sendbutton
After this transaction, account 0x07 should now have a Ballot resource object in its account storage. You can confirm this by selecting 0x07 from the lower-left sidebar and seeing Ballot resource listed under the Storage field.
Casting a Vote
Now that account 0x07 has a Ballot in their storage, they can cast their vote. To do this, they will call the vote method on their stored resource, then cast that Ballot by passing it to the cast function in the main smart contract.
- Open the
Cast Ballottransaction. - Select account
0x07as the only transaction signer. - Click the
sendbutton to submit the transaction.
In this transaction, the user votes for one of the proposals by submitting their votes on their own ballot and then sending the capability.
Reading the result of the vote
At any time, anyone could read the current tally of votes by directly reading the fields of the contract. You can use a script to do that, since it does not need to modify storage.
- Open the
Get Votesscript. - Click the
executebutton to run the script.
The return type should reflect the number of votes that were cast for each proposal with the Cast Vote transaction.
Other Voting possibilities
This contract was a very simple example of voting in Cadence. It clearly couldn't be used for a real-world voting situation, but hopefully you can see what kind of features could be added to it to ensure practicality and security.