.NET MAUIでNFTを発行してみた(初めてのWeb3)

# はじめに
Web3、それはどこまでも概念的でいまいち何なのかわからないもの

今回はそのWeb3の基本技術、NFTを.NET MAUIで発行できるのか、さわりだけで全く自分でもあまり理解できていないのですが、試してみました。

# Web3に挑戦してみた理由
.NET MAUIのCommunityToolkitにはすでにお絵かき機能を有しているライブラリがあるので、それを使用して書いたものをNFTで暗号資産にできるのではないかと思い始めてみました。

C#にはすでに「Nethereum」というNFTなどのWeb3技術を支援するライブラリがすでに存在しているので、簡単に導入できるのではないかと思い挑戦に思い立ったわけです。
やはりこのあたりの.NETの資産がすでに確立しているので.NET MAUIをクロスプラットフォームフレームワークとして使う大きなアドバンテージになりそうです。

Nethereumのドキュメント

http://docs.nethereum.com/en/latest/

# とりあえず最初のチュートリアルから
Nethereumのチュートリアルの初めからを読みながら進めていきます。
まず、Ethereumで使用する仮想通貨について確認する方法から始めてみます。

コードはまるまるNethereumPlayGroundというBlazorで作られているWeb実行環境に書いてあるのでそこからコピペで簡単でした。

http://playground.nethereum.com/


最初にライブラリをNuGetしましょう
Nethereum.Web3というライブラリになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3007605/7720a734-1278-5511-7768-5f0f2980fa8c.png)



.NET MAUIでは最初に「Nethereums」フォルダを作成し、Nethereum用のクラスを作成していきます。
```c#
using Nethereum.Web3;

namespace NethereumSample.Nethereums
{
    public class Nethe
    {
        public string Balance { get; set; }//Balance・・・仮想通貨の金額のようです。
        public string EtherAmount { get; set; }//EtherAmount・・・Etherは仮想通貨の単位

        public async Task GetAccountBalance()
        {   //↓ここのURLはInfraというサービスに登録して自分のアカウントの番号を入力しないと動きませんでした。(以下に詳細を載せます)
            var web3 = new Web3("https://mainnet.infura.io/v3/f73...");//←../v3/以降にInfraで登録した際に得られるアカウント番号が必要
            var balance = await web3.Eth.GetBalance.SendRequestAsync("0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae");//イーサリウム財団というところの今持ってる仮想通貨の金額を見る処理です。
            Balance = balance.Value.ToString();//←イーサリウム財団の持っているお金の値を文字列で取得

            var etherAmount = Web3.Convert.FromWei(balance.Value);//Weiというものが仮想通貨の最小単位なのでそれをEtherに変換している。(単位変換)
            EtherAmount=etherAmount.ToString();//
        }
    }
}
```
イーサリウム財団の所持しているEther(仮想通貨のお金(単位))を見ることのできるメソッドのようです。

ここでのBalanceは仮想通貨の金額とか財布とか中央に集約された価値のあるもののようなイメージです。
仮想通貨を受け渡すとき、個人個人のやり取りを連想しますが、このBalanceのそれぞれ所持しているものの領域を変化させることによって管理しているようです。

例えば1000円を相手に渡す場合はBalanceは1000:0から0:1000に変わるようなイメージです。

イーサリウムを使用している人たち全員の領域をこのBlanceが持ち、それぞれの領域を大きくしたり小さくしたりすることでお金の受け渡しを再現しているようです。

話は変わりますが、このチュートリアルにはInfraというサービスに登録しないと動かないようです。
これはイーサリウムという仮想通貨を管理できるサービスのようです。(詳しくはわからない)

https://app.infura.io/login

リンクからサインアップすると以下の写真のものが今回使うアカウント番号になります。

![スクリーンショット 2022-12-19 220427.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3007605/92514fb0-8043-5611-e534-807fe1b7aa4a.png)

たぶん最初にログインした時のページは上でしたが２回目にログインすると変わるので以下のように「ManageKey」ボタンから入れます。
![manegeKey.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3007605/2cddea37-03fd-5f9c-4823-ed47a26e3f78.png)

処理の続きですがMainPage.xaml.csのサンプルアプリですでに作っていたOnCounterClickedに以下のように追加すればOKです。
```cs
using NethereumSample.Nethereums;//using忘れず

～省略～
private async void OnCounterClicked(object sender, EventArgs e)
	{
		Nethe nethe= new Nethe();
		await nethe.GetAccountBalance();
		balanceLabel.Text= nethe.Balance;//MainPageにbalanceLabelを作成することを忘れず
		etherLabel.Text = nethe.EtherAmount;//MainPageにetherLabelを作成することを忘れず
	}
```
結果このようになります。

ボタンの下の文字がWei、その下のラベルがEtherを表しています。
Weiだけ見るとめっちゃ金持ってんなぁって思いますね。(相場わかりませんが)
![Screenshot_20221219-221427.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3007605/79fb412d-46ef-7a81-1604-40e11d9381b7.png)

# NFTを作ってみる
次もチュートリアルを参考にいよいよNFTを発行してみようと思います。

NFTの発行はスマートコントラクトと言うようです。
「Nethereums」フォルダに以下のクラスを作成します。

```cs
using Nethereum.Web3;
using Nethereum.Web3.Accounts;
using Nethereum.ABI.FunctionEncoding.Attributes;
using Nethereum.Contracts;
using System.Numerics;

namespace NethereumSample.Nethereums
{
    public class GetStartedSmartContracts
    {
        //*** Deployment message**** //
        //トークンを発行するためのトークンの型を決めている。今回は標準的なERC20の基準に合わせたトークンを作成する
        public class StandardTokenDeployment : ContractDeploymentMessage
        {
            //↓めちゃくちゃ長いがERC20のトークンの説明書をバイナリに変換したものらしい。これによって今回はERC20を使うよと指定している。
            public static string BYTECODE = "0x60606040526040516020806106f5833981016040528080519060200190919050505b80600160005060003373ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060005081905550806000600050819055505b506106868061006f6000396000f360606040523615610074576000357c010000000000000000000000000000000000000000000000000000000090048063095ea7b31461008157806318160ddd146100b657806323b872dd146100d957806370a0823114610117578063a9059cbb14610143578063dd62ed3e1461017857610074565b61007f5b610002565b565b005b6100a060048080359060200190919080359060200190919050506101ad565b6040518082815260200191505060405180910390f35b6100c36004805050610674565b6040518082815260200191505060405180910390f35b6101016004808035906020019091908035906020019091908035906020019091905050610281565b6040518082815260200191505060405180910390f35b61012d600480803590602001909190505061048d565b6040518082815260200191505060405180910390f35b61016260048080359060200190919080359060200190919050506104cb565b6040518082815260200191505060405180910390f35b610197600480803590602001909190803590602001909190505061060b565b6040518082815260200191505060405180910390f35b600081600260005060003373ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060005060008573ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905061027b565b92915050565b600081600160005060008673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050541015801561031b575081600260005060008673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060005060003373ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000505410155b80156103275750600082115b1561047c5781600160005060008573ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828282505401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a381600160005060008673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282825054039250508190555081600260005060008673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060005060003373ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828282505403925050819055506001905061048656610485565b60009050610486565b5b9392505050565b6000600160005060008373ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000505490506104c6565b919050565b600081600160005060003373ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050541015801561050c5750600082115b156105fb5781600160005060003373ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282825054039250508190555081600160005060008573ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828282505401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a36001905061060556610604565b60009050610605565b5b92915050565b6000600260005060008473ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060005060008373ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060005054905061066e565b92915050565b60006000600050549050610683565b9056";
            //↓上のバイナリによってERC20のトークンを作っている
            public StandardTokenDeployment() : base(BYTECODE)
            {
            }
            //↓配給プロパティを入れている
            [Parameter("uint256", "totalSupply")]
            public BigInteger TotalSupply { get; set; }
        }


        //**** END CONTRACT DEFINITIONS ***** ///

        public string ConstructAdress { get; set; }//コンストラクトのアドレスを作る

        ///*** THE MAIN PROGRAM ***
        public async Task CreateToken()
        {
            var privateKey = "0x7580e7fb49df1c861f0050fae31c2224c6aba908e116b8da44ee8cd927b990b0";//テスト用のプライベートキー
            var chainId = 444444444500; //NethereumのテストチェーンID
            var account = new Account(privateKey, chainId);//プライベートキーとチェーンIDでアカウントを作成(これはテストなのでテストキー,テストチェーンIDを使用している)

            //アカウントとテストチェーンを使用してWeb3のインスタンスを作成する
            var web3 = new Web3(account, "http://testchain.nethereum.com:8545");

            //100000の共有をする
            var deploymentMessage = new StandardTokenDeployment
            {
                TotalSupply = 100000
            };

            var deploymentHandler = web3.Eth.GetContractDeploymentHandler<StandardTokenDeployment>();
            var transactionReceiptDeployment = await deploymentHandler.SendRequestAndWaitForReceiptAsync(deploymentMessage);//デプロイメントメッセージから領収書を発行している
            var contractAddress = transactionReceiptDeployment.ContractAddress;//このコンストラクトアドレスがトークンIDだと思われる(100000サプライ)
            ConstructAdress=contractAddress;
        }
    }
}
```

とりあえずチュートリアルの一部だがトークンを作り出すところまでの関数を書きました。

これをまたMainPage.xaml.csで呼び出します。
```cs
    private async void OnCounterClicked(object sender, EventArgs e)
	{
		GetStartedSmartContracts smartContracts= new GetStartedSmartContracts();
		await smartContracts.CreateToken();
		constructAdress.Text = smartContracts.ConstructAdress;//constructAdressのラベルをMainPageに追加しておく
	}
```

#### 余談ですが
SmartContractに使われるコントラクトは「契約」という意味で、スマートに仮想通貨で契約ができますよのContractです。
ConstructAdressのコンストラクトは「建てる」という意味で、アドレスを作るという意味です。

字面が似ていますが意味が全く違うので注意してください。aもuに代わっているのでタイポ注意

デバッグしてみるとこんな感じです。
![Screenshot_20221219-221602.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3007605/12835a8c-6e0c-9484-122e-c77e795da516.png)

ボタンの下にトークンID(ConstructAdress)が表示されます。

# さいごに
とりあえずWeb3が全くわからないなりにチュートリアルを見ながらNFTを生成することができました。

ここからどうやってこのIDを絵に結び付けるのかまでは全くわかりません。
わかる人教えていただければと思います。

さいごに私がWeb3について思うことは、そこまではやし立てるくらいの大それた技術ではないと思います。
HTMLとかXMLとかJsonとかSQLとかそんな感じで重要だけど一般人が騒ぎ立てるほどでは、、、という形に使われて行って収束するのではないかなと思います。
(もちろんNFTなどの技術は普通にすごいので、、、)
最近だとGraphQLとかそんな感じですかね。