AleoのTestnetを触ってみた②

※前回の続きとなります。
https://qiita.com/ais3/items/aeedf0f3de8fba5a257d

今回はトークンをmint、transferするコントラクトをテストネットにデプロイします。

# leoのプログラムを作成する
まずは、leoでプログラムを作ります。
もし環境がないという方は、前回の記事の私のDockerfileを使えば環境構築されたコンテナを使用できます。

以下のコマンドでleoのプロジェクトを作ります。

`leo new プロジェクト名`
※例としてtoken_test1で作ります。

カレントフォルダに以下のフォルダが作られます。
token_test1
　┣build
　┣inputs
　┣outputs
　┣.env
　┣.gitignore
　┣program.json
　┗README.md

中を見ると、srcというフォルダがあるので、ここのmain.leoにプログラムを書いていきます。
## mint関数の作成

```
// The 'token_test_1' program.
program token_test_1.aleo {
    record Token {
        owner: address,
        balance: u32
    }

    transition mint(balance: u32) -> Token{
        return Token {
            owner: self.caller,
            balance: balance
        };
    }
} 
```
#### プログラムの解説
まずは、tokenのデータ(所有者と所有量)を書きます。
Tokenの前にrecordと書くことで、Tokenはデータとして扱われることを宣言します。

このmint関数は、
mintするbalanceを引数にmint関数を呼び出すと、呼び出したアカウントにトークンを送ります。
mint関数の前にtransitionを書くことで、この関数は状態(今回ではトークンの量)を遷移させる関数であることを示しています。

これでプログラムは完成です。次はローカルでコンパイルします。

### コンパイル準備
コンパイルの前にinputファイルを編集します。
inputファイルにデフォルト値を定義しておくことで、チェーンへデプロイする前にプログラムの不具合がないかローカルでテストできるようになります。


inputsフォルダの中に`token_test1.in`というファイルがあると思います。

デフォルトでは
```
[main]
public a: u32 = 1u32;
b: u32 = 2u32;
```
が書かれていると思いますが、今回mint関数を作ったので、下記に書き換えます。
```
[mint]
balance: u32 = 100u32;
```

ここに書いた内容がleoプログラムをコンパイルして実行するときに、デフォルト値を与えることになります。mint関数の引数に一致させるように書いてください。

### コンパイル＆ローカル実行

ようやくコンパイルする準備ができたので、下記コマンドを実行します。

`leo run mint`

ローカルでmintが実行されて、inputに書いたトークン100がownerに送信されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3554089/e0ad56bc-b39e-9215-9803-91c4861ebfe6.png)

送信されたといっても、今はローカル環境上で実行しているだけなので、チェーン上にはありません。
現在ローカル使用しているアカウントはtoken_test1フォルダにある「.env」ファイルのPRIVATEKEY=に秘密鍵を入力したアカウントです。

画面に表示されたOutputという項目が、複合化されたレコードになります。

以上でmint関数が完成です。

## transfer関数の作成
次はtokenを送信する関数のtransferを作成します。
先ほど書いたmint関数の下に以下のプログラムを書いてください。
```
    transition transfer(receiver : address, amount: u32, input: Token) -> (Token,Token){
        let balance: u32 = input.balance - amount;
        let recipient: Token = Token{
            owner: receiver,
            balance: amount
        };

        let sender: Token = Token{
            owner: self.caller,
            balance
        };

        return(recipient,sender);
    }
```
#### プログラムの解説
transfer関数は引数に受信者のアドレスと転送量とトークンを受け取ります。
返却は受信者のトークン量と送信者のトークン量（余った量を送信者に返すため）となります。

### コンパイル前準備
またinputにデフォルトを書いてleoで実行してみましょう。
inputに書くのは以下です。
```
[transfer]
receiver: address = ;
amount: u32 = 10u32;
input: Token = Token{
 owner: xxxxxxxxxxxxxxxxxxxxxxxx,  
 balance: 100u32,
 _nonce: xxxxxxxxxxxxxxxxxxxxxxx,
};
```
#### 補足
reciverはトークン受信者の公開アドレス「aleo1......」を書きます。
amountは送るトークンの量です。
inputにはトークンの状態を書きます。

トークンの状態とは簡単に言うと、この人はこのくらいのトークンを持っています。ということが証明された情報です。

ぶっちゃけ先ほどmint関数を実行したOutputの内容を書けばOKです。
(outputの内容をコピペした後に.privateという文字列は消してください)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3554089/0984d908-2955-6f5a-f6b6-d51d57ec5431.png)


なぜOutputの内容でOKかというと、先ほどのmint関数が成功していれば、チェーン上(今回はローカル環境上)にこの人は100のトークンを持っています。というのがoutputの内容で証明されているからです。

### コンパイル&ローカル実行
inputファイルに書いたら下記を実行します。

leo run transfer

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3554089/1a49627b-5008-1e4e-39c9-cbc72897839c.png)


実行結果には２つのoutputがあります。

１つはトークンを送信した内容です。
トークン受信者のアドレスと受信量が書かれています。

もう一つは送信者にトークンが返ってくる内容です。
トークン送信者のアドレスとトークン送信後のトークン量が書かれています。

これで一連の流れが終わりました。
このコントラクトを使えば、トークンをmint関数を呼び出してmintして、mintしたトークンをtransfer関数を呼び出して他の人に送ることができます。

# テストネットにデプロイする

コンパイルできることと、ちゃんとプログラムが動くことを確認したのでデプロイします。
デプロイは下記コマンドを実行します。
```
snarkos developer deploy "アプリ名.aleo" --private-key "秘密鍵" --query "https://api.explorer.aleo.org/v1" --path "./build/" --broadcast "https://api.explorer.aleo.org/v1/testnet3/transaction/broadcast" --priority-fee 1000000
```
アプリ名と秘密鍵はそれぞれ置き換えてください。
<例>
アプリ名：token_test_1.aleo
秘密鍵：APrivateKey1zkpXXXXXXXXX（デプロイに使用するアカウントの秘密鍵）

実行すると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3554089/780ccf6b-f114-fc41-0cb6-893d82f4dd20.png)
デプロイが始まり、少し待っていると成功します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3554089/f38f3576-9a01-2dad-fe11-4e81518285e0.png)
Successfullyの次の行にTxIDが表示されるので、Explorerで検索しましょう。
https://explorer.hamp.app/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3554089/ebc09ead-6a84-5ef1-11a2-5a9144db195a.png)

こんな感じで表示されます。これでテストネットにデプロイできました。

これでsnarkOSのコマンドを使ってテストネット上でmintしたりtransferしたりできます。

# 最後に
今回はデプロイに焦点を当てたので、ウォレットの作成やテストネットトークンの取得方法は書いてません。
もしわからない場合はAleoのドキュメントから探せば出来て来ました。
https://developer.aleo.org/getting_started/

こちらのサイトはウォレットをサイト上で作れたりします
https://aleo.tools/account
Google拡張機能でウォレットもあります。
https://www.leo.app/

テストネットトークンはSMSでアドレスを送ってテストネットトークンをもらう流れです。