9. 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.
Instructions that require you to take action are always included in a callout box like this one. These highlighted actions are all that you need to do to get your code running, but reading the rest is necessary to understand the language's design.
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 a trivial 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
Ballot
resource to another account. - Record and cast your vote in the central Voting contract
- Read the results of the vote
Before proceeding with this tutorial, we highly recommend following the instructions in Getting Started and Hello, World! to learn how to use the Playground tools and to learn the fundamentals of Cadence.
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
Time to see the contract we'll be working with:
- Open Contract 1 - the
ApprovalVoting
contract.
The contract should have the following contents:
Now is your chance to write some of your own Cadence code! See if you can 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. Once you're done, share your project with the Flow community in the Flow discord! :)
Deploy the Contract
- In the bottom right deployment modal, press the arrow to expand and make sure account
0x06
is 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
Ballot
to 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
0x06
selected 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 Ballot
s 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 Ballot
transaction. - Select account
0x07
as a signer. - Submit the transaction by clicking the
Send
button
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 Ballot
transaction. - Select account
0x07
as the only transaction signer. - Click the
send
button 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 Votes
script. - Click the
execute
button 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.