9. Voting Contract

[Previous << 8. Marketplace](https://qiita.com/flowcadence/items/4ccd756d0a2a71c6059b)
[Next >> 10. Composable Resources](https://qiita.com/flowcadence/items/729d4317f64df7882783)

https://qiita.com/flowcadence/items/3073d69c6e9895e68b5a#cadenceの言語仕様を学ぶ

このチュートリアルでは、投票管理者が管理する複数の提案に対してユーザーが投票できるスマートコントラクトをデプロイします。

:::note
ⓘ INFO
このチュートリアルのスターターコードをFlow Playgroundで開きます。
https://play.flow.com/e8e2af39-370d-4a52-9f0b-bfb3b12c7eff
チュートリアルでは、このコードとやり取りするためにさまざまな操作を行うよう求められます。
:::
:::note
ⓘ ACTION
ユーザーにアクションを要求する指示は、常にこのような吹き出しボックス内に記載されています。ハイライトされたアクションは、コードを実行するために必要なすべてですが、言語の設計を理解するためには、残りの部分を読むことも必要です。
:::
ブロックチェーン技術とスマートコントラクトの出現により、多数のユーザーが完全にオンチェーンで投票できる分散型投票メカニズムの作成が試みられるようになりました。このチュートリアルでは、リソース指向のプログラミングモデルを使用してこれをどのように実現できるかについて、簡単な例を紹介します。

以下の手順に従って、投票コントラクトに慣れていきましょう。
  1. コントラクトをアカウント0x06にデプロイする
  2. ユーザーが投票する提案を作成する
  3. 複数の署名者によるトランザクションを使用して、投票リソースを別のアカウントに直接転送します。
  4. 中央の投票コントラクトで投票を記録し、投票します
  5. 投票結果を読み取ります

このチュートリアルを進める前に、[Getting Started](https://qiita.com/flowcadence/items/d74e796356935d409ba4)および[Hello, World!](https://qiita.com/flowcadence/items/8d5bce1f1feaf5404d2b)の手順に従って、Playgroundツールの使用方法とCadenceの基礎を習得することを強くお勧めします。

<h1 id="A-Voting-Contract-in-Cadence">A Voting Contract in Cadence</h1>

このスマートコントラクトでは、投票用紙がリソースとして表現されます。

管理者が他のアカウントに投票用紙を渡し、それらのアカウントがどの提案に投票するかをマークし、投票用紙を中央のスマートコントラクトに提出することで、投票が記録されます。

ユーザーが投票を委任したい場合、その投票用紙を他のアカウントに送ることができるため、このアプリケーションでは[リソース](https://qiita.com/flowcadence/items/f9b95df70c80a90d3a20)型を使用するのが論理的です。投票用紙のユースケースは、リソースに固有の一意性と存在保証のメリットを享受します。

<h1 id="Write-the-Contract">Write the Contract</h1>

これから作業するスマートコントラクトを確認する時間：

:::note
ACTION
1 . Contract1を開く - `ApprovalVoting` コントラクト。
:::
スマートコントラクトには以下の内容が含まれているはずです。
```ruby:ApprovalVoting.cdc
/*
*
*   In this example, we want to create a simple approval voting contract
*   where a polling place issues ballots to addresses.
*
*   The run a vote, the Admin deploys the smart contract,
*   then initializes the proposals
*   using the initialize_proposals.cdc transaction.
*   The array of proposals cannot be modified after it has been initialized.
*
*   Then they will give ballots to users by
*   using the issue_ballot.cdc transaction.
*
*   Every user with a ballot is allowed to approve any number of proposals.
*   A user can choose their votes and cast them
*   with the cast_vote.cdc transaction.
*
*.  See if you can code it yourself!
*
*/

access(all)
contract ApprovalVoting {

    /* Field: An array of strings representing proposals to be approved

     * Field: A dictionary mapping the proposal index to the number of votes per proposal

     * 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
     * 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
     * when a user submits their vote */
    access(all) resource Ballot {

    }

    /* Resource: Administrator of the voting process
     * initialize the proposals and to provide a function for voters
     * to get a ballot resource
     * Remember to include proper conditions for each function!
     * Also make sure that the privileged fields are secured with entitlements! */
    access(all) resource Administrator {
        
    }

    /* Public function: A user can create a capability to their ballot resource
     * and send it to this function so its votes are tallied
     * Remember to include a provision so that a ballot can only be cast once!

     * initialize the contract fields by setting the proposals and votes to empty
     * and create a new Admin resource to put in storage */
    init() {
        
    }
}
```
今こそ、あなた自身のCadenceソースコードを書くチャンスです！スマートコントラクトのコメントに記載されている指示に従って、あなた自身の投票承認スマートコントラクトを書いてみましょう。サンプルトランザクションには、トランザクションの指示も含まれています。完了したら、Flow discordのFlowコミュニティであなたのプロジェクトを共有しましょう！:)

<h1 id="Deploy-the-Contract">Deploy the Contract</h1>

:::note
ⓘ ACTION
1 . 右下のデプロイ・モーダルで、矢印を押して展開し、アカウント`0x06`が署名者として選択されていることを確認します。
2 . Deployボタンをクリックして、アカウント`0x06`にデプロイします。
:::
<h1 id="Perform Voting">Perform Voting</h1>

この投票スマートコントラクトにおける共通のアクションを実行するには、3種類のトランザクションのみが必要です。

1. 提案(Proposals)の初期化
2. 投票者への`Ballot`の送信
3. 投票の実行

各ステップにはトランザクションがあり、その雛形を以下に示します。`ApprovalVoting`コントラクトをアカウント`0x06`にデプロイします。

:::note
ⓘ ACTION
1 . トランザクション1を開きます。`Create Proposals`がそこにはあるはずです。
2 . トランザクションを送信します。署名者はアカウント`0x06`のみを選択します。
:::
```ruby:CreateProposals.cdc
import ApprovalVoting from 0x06

/* This transaction allows the administrator of the Voting contract
   to create new proposals for voting and save them to the smart contract */

transaction {
    /* Fill in auth() with the correct entitlements you need! */
    prepare(admin: auth()) {

        /* borrow a reference to the admin Resource
         * remember to use descriptive error messages!

         * Call the initializeProposals function
         * to create the proposals array as an array of strings
         * Maybe we could create two proposals for the local basketball league:
         * ["Longer Shot Clock", "Trampolines instead of hardwood floors"]

         * Issue and public a public capability to the Administrator resource
         * so that voters can get their ballots! */
    }

    post {
        /* Verify that the proposals were initialized properly */
    }
}
```
このトランザクションにより、スマートコントラクトの`Administrator`は投票のための新しい提案を作成し、それをスマートコントラクトに保存できるようになります。 `Administrator`は、保存されている`Administrator`リソース上で`initializeProposals`関数を呼び出し、投票対象となる2つの新しい提案を与えます。 `post`ブロックを使用して、意図したとおりに2つの提案が作成されたことを確認します。

次に、`Administrator`は投票者に`Ballot`を配布する必要があります。今回は、`Ballot`を別のアカウントに送信するための簡単なデポジット(`deposit`)機能は用意されていません。では、どのように行うのでしょうか？
<h1 id="Putting-Resource-Creation-in-public-capabilities">Putting Resource Creation in public capabilities</h1>

他のチュートリアルのスマートコントラクトとは異なり、Approval Votingコントラクトでは、投票作成関数をスマートコントラクトのパブリック関数ではなくリソースに配置します。これにより、管理者が投票リソースを作成できるユーザーとできないユーザーを制御することができます。また、投票ロジックをすべて管理者リソースに統合する方法もあります。これにより、新しいスマートコントラクトを個別にデプロイすることなく、同時に複数の提案に対する投票を行うことができます。

ここでは、単純化のため、パブリックCapabilityを通じて投票作成関数のみを公開しています。それでは、有権者が投票を作成するためのトランザクションを使用してみましょう。

:::note
ⓘ ACTION
1 . `Create Ballot`トランザクションを開きます。
2 . 署名者としてアカウント`0x07`を選択します。
3 . `Send`ボタンをクリックしてトランザクションを送信します。
:::
```ruby:CreateBallot.cdc
import ApprovalVoting from 0x06

/* This transaction allows a user
 * to create a new ballot and store it in their account
 * by calling the public function on the Admin resource
 * through its public capability */

transaction {
    /* fill in the correct entitlements! */
    prepare(voter: auth() &Account) {

        /* Get the administrator's public account object
         * and borrow a reference to their Administrator resource

         * create a new Ballot by calling the issueBallot
         * function of the admin Reference

         * store that ballot in the voter's account storage */
    }
}
```
このトランザクションの後、アカウント`0x07`には、アカウントストレージに`Ballot`リソースオブジェクトが追加されているはずです。これを確認するには、左下のサイドバーから`0x07`を選択し、`Ballot`リソースが`Storage`フィールドの下にリストされていることを確認します。
<h1 id="Casting-a-Vote">Casting a Vote</h1>

アカウント`0x07`はストレージに`Ballot`を保持しているため、投票を行うことができます。これを行うには、ストレージリソースの`vote`メソッドを呼び出し、その`Ballot`をメインのスマートコントラクトの`cast`関数に渡してキャストします。

:::note
ⓘ ACTION
1 . `Cast Ballot`トランザクションを開きます。
2 . アカウント`0x07`を唯一のトランザクション署名者として選択します。
3 . `send`ボタンをクリックしてトランザクションを送信します。
:::
```ruby:CastBallot.cdc
import ApprovalVoting from 0x06

/* This transaction allows a voter to select the votes they would like to make
 * and cast that vote by using the cast vote function
 * of the ApprovalVoting smart contract */

transaction {
    /* fill in the correct entitlements! */
    prepare(voter: auth() &Account) {

        /* 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

         * Cast the vote by submitting it to the smart contract */
    }

    post {
        /* verify that the votes were cast properly */
    }
}
```
このトランザクションでは、ユーザーは自分の投票用紙に投票を記入し、その用紙を送信することで、いずれかの提案に投票します。

<h1 id="Reading-the-result-of-the-vote">Reading the result of the vote</h1>

いつでも誰でも、スマートコントラクトのフィールドを直接読むことで現在の投票集計を読むことができます。ストレージを変更する必要がないので、スクリプトを使用してそのようにすることができます。

:::note
ⓘ ACTION
1 . `Get Votes`スクリプトを開きます。
2 . `execute`ボタンをクリックしてスクリプトを実行します。
:::
```ruby:GetVotes.cdc
import ApprovalVoting from 0x06

/* This script allows anyone to read the tallied votes for each proposal
 *

 * Fill in a return type that can properly represent the number of votes
 * for each proposal
 * This might need a custom struct to represent the data */
access(all) fun main(): {

    /* Access the public fields of the contract to get
     * the proposal names and vote counts

     * return them to the calling context */

}
```
戻り値の型には、`Cast Vote` トランザクションで各提案に対して投票された票数を反映されているはずです。
<h1 id="Other-Voting-possibilities">Other Voting possibilities</h1>

このスマートコントラクトは、Cadenceにおける投票の非常に単純な例です。現実の投票状況には明らかに使用できませんが、実用性とセキュリティを確保するためにどのような機能が追加できるか、おわかりいただけたことと思います。

翻訳元

https://cadence-lang.org/docs/tutorial/voting

***
<b>[Previous << 8. Marketplace](https://qiita.com/flowcadence/items/4ccd756d0a2a71c6059b)
</b>

[Flow blockchain / Cadence version1.0ドキュメント](https://qiita.com/flowcadence/items/3073d69c6e9895e68b5a) (9. Voting Contract)

<b>[Next >> 10. Composable Resources](https://qiita.com/flowcadence/items/729d4317f64df7882783)</b>