Skip to content

Edit tutorials 9 and 10 #256

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 62 additions & 118 deletions docs/tutorial/09-voting.md
Original file line number Diff line number Diff line change
@@ -1,67 +1,40 @@
---
title: 9. Voting Contract
title: 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.

---

:::info

Open the starter code for this tutorial in the Flow Playground:
<a
href="https://play.flow.com/e8e2af39-370d-4a52-9f0b-bfb3b12c7eff"
target="_blank"
>
https://play.flow.com/e8e2af39-370d-4a52-9f0b-bfb3b12c7eff
</a>
The tutorial will be asking you to take various actions to interact with this code.

:::

:::info[Action]
## Objectives

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 onchain. This tutorial provides a trivial example of 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:

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.

1. Deploy the contract to account `0x06`
2. Create proposals for users to vote on
1. Deploy the contract to account `0x06`.
2. Create proposals for users to vote on.
3. Use a transaction with multiple signers to directly transfer the `Ballot` resource to another account.
4. Record and cast your vote in the central Voting contract
5. Read the results of the vote
4. Record and cast your vote in the central Voting contract.
5. Read the results of the vote.

Before proceeding with this tutorial, we highly recommend following the instructions in [Getting Started](./01-first-steps.md)
and [Hello, World!](./02-hello-world.md) to learn how to use the Playground tools and to learn the fundamentals of Cadence.
Before proceeding with this tutorial, we highly recommend following the instructions in [First Steps] and [Hello World] to learn how to use the Playground tools and to learn the fundamentals of Cadence.

## A Voting Contract in Cadence
## Getting started

In this contract, a Ballot is represented as a resource.
Open the starter code for this tutorial in the Flow Playground: [https://play.flow.com/e8e2af39-370d-4a52-9f0b-bfb3b12c7eff].

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.
The tutorial will prompt you to take various actions to interact with this code.

Using a [resource](../language/resources.mdx) 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.
## A voting contract in Cadence

## Write the Contract
In this contract, a ballot is represented as a resource.

Time to see the contract we'll be working with:
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.

:::info[Action]
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.

1. Open Contract 1 - the `ApprovalVoting` contract.
## Writing the contract

:::
To see the contract we'll be working with, open Contract 1 — the `ApprovalVoting` contract.

The contract should have the following contents:

Expand Down Expand Up @@ -97,14 +70,14 @@ contract ApprovalVoting {
// Entitlement: Admin entitlement that restricts the privileged fields
// of the Admin resource

// Resource: Ballot resource that is issued to users.
// When a user gets a Ballot object, they call the `vote` function
// to include their votes for each proposal, and then cast it in the smart contract
// Resource: ballot resource that is issued to users.
// When a user gets a ballot object, they call the `vote` function
// to include their votes for each proposal, and then cast them in the smart contract
// using the `cast` function to have their vote included in the polling
// Remember to track which proposals a user has voted yes for in the Ballot resource
// and remember to include proper pre and post conditions to ensure that no mistakes are made
// Remember to track which proposals a user has voted yes for in the ballot resource
// and remember to include proper pre- and post-conditions to ensure that no mistakes are made
// when a user submits their vote
access(all) resource Ballot {
access(all) resource ballot {

}

Expand All @@ -130,38 +103,29 @@ contract ApprovalVoting {

```

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

:::info[Action]
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!

1. In the bottom right deployment modal, press the arrow to expand and make sure account `0x06` is selected as the signer.
2. Click the Deploy button to deploy it to account `0x06`
## Deploying the contract

:::
To deploy:

## Perform Voting
1. In the bottom right deployment modal, press the arrow to expand.
2. Make sure account `0x06` is selected as the signer.
3. Click the **Deploy** button to deploy it to account `0x06`.

Performing the common actions in this voting contract only takes three types of transactions.
## Perform voting

1. Initialize Proposals
2. Send `Ballot` to a voter
3. Cast Vote
Performing the common actions in this voting contract only takes three types of transactions:

We have a transaction for each step that we provide a skeleton of for you.
With the `ApprovalVoting` contract deployed to account `0x06`:
1. Initialize Proposals.
2. Send `Ballot` to a voter.
3. Cast Vote.

:::info[Action]
We have a transaction for each step, which provides a skeleton of for you. With the `ApprovalVoting` contract deployed to account `0x06`:

1. Open Transaction 1 which should have `Create Proposals`
2. Submit the transaction with account `0x06` selected as the only signer.
1. Open Transaction 1, which should have `Create Proposals`
2. Submit the transaction with account `0x06` selected as the only signer:

:::

```cadence CreateProposals.cdc
import ApprovalVoting from 0x06
Expand Down Expand Up @@ -192,30 +156,19 @@ transaction {
}
```

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.
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, as we intended.

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
## 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!
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.

:::info[Action]
Here, we're just exposing the create ballot function through a public capability for simplicity, so let's use the transaction for a voter to create a ballot:

1. Open the `Create Ballot` transaction.
2. Select account `0x07` as a signer.
3. Submit the transaction by clicking the `Send` button

:::
3. Submit the transaction by clicking the `Send` button:

```cadence CreateBallot.cdc

Expand All @@ -242,23 +195,15 @@ transaction {

```

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.
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
## 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.

:::info[Action]
Now that account `0x07` has a `Ballot` in its storage, it can cast its vote. To do this, the account will call the `vote` method on its stored resource, then cast that `Ballot` by passing it to the `cast` function in the main smart contract:

1. Open the `Cast Ballot` transaction.
2. Select account `0x07` as the only transaction signer.
3. Click the `send` button to submit the transaction.

:::
3. Click the `send` button to submit the transaction:

```cadence CastBallot.cdc
import ApprovalVoting from 0x06
Expand All @@ -271,11 +216,11 @@ transaction {
// fill in the correct entitlements!
prepare(voter: auth() &Account) {

// Borrow a reference to the Ballot resource in the Voter's storage
// Borrow a reference to the ballot resource in the Voter's storage

// Vote on the proposal

// Issue a capability to the Ballot resource in the voter's storage
// Issue a capability to the ballot resource in the voter's storage

// Cast the vote by submitting it to the smart contract
}
Expand All @@ -286,19 +231,14 @@ 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.
In this transaction, the user votes for one of the proposals by submitting its votes on its 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.

:::info[Action]
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:

1. Open the `Get Votes` script.
2. Click the `execute` button to run the script.

:::
2. Click the `execute` button to run the script:

```cadence GetVotes.cdc
import ApprovalVoting from 0x06
Expand All @@ -319,11 +259,15 @@ access(all) fun main(): {
}
```

The return type should reflect the number of votes that were cast for each proposal
with the `Cast Vote` transaction.
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.

## Other Voting possibilities
<!-- Reference-style links. Will not render on page. -->

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.
[https://play.flow.com/e8e2af39-370d-4a52-9f0b-bfb3b12c7eff]: https://play.flow.com/e8e2af39-370d-4a52-9f0b-bfb3b12c7eff
[First Steps]: ./01-first-steps.md
[Hello World]: ./02-hello-world.md
[resource]: ../language/resources.mdx
Loading