見出し画像

第3回 solidity学習会 講義ノート(3/5 AM8:00~)

こんにちは、CryptoGamesの高橋です。

クリスペの会社です。

また、CryptoMaidsのアンバサダーも務めさせていただいております。

今回は、3/5 AM8:00から次の場所で勉強会を行いますので、その講義ノートの公開です。

場所 https://meet.google.com/zme-pohq-hcm

予習や復習などに役立てていただければ幸いです。

はじめる前に

・実施はテストアカウントで行うことを推奨いたします。
Rinkebyというテストネットで実施を行いますが、操作を誤ってしまったときに実際のETHが使われないためです。

・シークレットNFTを行いますが、技術の話と法律面の話は別物だ考えています。今回はあくまでも、技術的にどのように実現するかというのみの話になります。

0 準備

第1回と同様のコードを利用します。

こちらの記事を参考に、Remixにコードを貼り付けてそれを元に見て行きましょう。(ここを省いても記事は読めます。)

1 その関数、見つかりますか?

こちらのEtherscanを元に見ていきます。

https://rinkeby.etherscan.io/address/0xa0092d257278d5d7cb2a247091aed51e69d0179f#code

「Read Contract」で下の「balanceOf」という関数を見てみましょう。

この関数の内容は、指定したウォレットアドレスがいくつのアセット(NFT)を持っているのかを返します。

スクリーンショット 2022-03-03 5.37.18

今回の例の場合、「0x961aEa560D4C38B08D9300D8219062Fe853c8315」3つのNFTを持っていることがわかります。

便利ですね。

一方、この「balanceOf」という関数は「Purple.sol」の中のどこで動作を定義しているでしょうか?

「ctrl」+「F」検索窓が出てきますので、検索してみて下さい。

スクリーンショット 2022-03-03 5.40.50

すると、利用している箇所は見つかったものの、定義している部分は見つからなそうです。

他にも、下のような関数を探してみて下さい。(変数+ getter関数という場合もありますが、今回その辺は省略)

スクリーンショット 2022-03-03 5.52.00

やはりなさそうです。

不思議ですね。どうやって使えるようになっているのでしょう。

2 継承について

2ー1 継承とは

ここで出てくるのが「継承」です。

他のコントラクトのコードを利用することができます。

スクリーンショット 2022-02-28 18.51.56

こんな形になっていますね。

contract 継承先 is 継承元 { 
 ・・・
}

継承により、「ERC721Enumerable」「Ownable」「PurpleEye」コントラクトで利用できるようになります。

図にするとこんな感じです。

スクリーンショット 2022-03-03 6.11.15

実はこれにより、前回「onlyOwner」を使えるようになりました。

スクリーンショット 2022-03-03 6.11.15

2ー2 具体的な継承の例を見てみよう

今回のコントラクトは「ERC721Enumerable」コントラクトを継承していました。

一方、「ERC721Enumerable」自身も、下のように継承を行っています。

スクリーンショット 2022-02-28 19.17.40

このように、「ERC721Enumerable」「ERC721」を継承していたのですね。

スクリーンショット 2022-03-03 6.06.44

これによって、ERC 721で定義された関数などもPurpleEyeで使えるようになりました。

2ー3 ERC721を読んでみよう

では、実際によく聞く「ERC721」を見てみましょう。

まずは、下のように、コントラクトの説明である、コメント部分を読んでみましょう。

スクリーンショット 2022-03-03 6.22.54

先ほど出てきた、Enumerable(内容は後で)については、含まれないと書いてあります。

だからこそ、Enumerableを利用したい場合はEnumerableを継承する必要があることがわかります。

スクリーンショット 2022-03-03 6.29.45

では、ERC721の中身も見てみましょう。

スクリーンショット 2022-03-03 6.36.28

具体的な関数の説明は省きますが、ここで

・balanceOf()
 ⇨いくつのアセット(NFT)を持っているか
・ownerOf()
 ⇨そのトークンIDの所有者は誰か

などが定義されているからこそ、「PurpleEye」でこれらを継承し、関数として使えるようになっていたのですね。

2ー4 ERC721Enumerableを読んでみよう

では、ERC721に含まれていない、「ERC721Enumerable」についても見てみましょう。

早速コメントを読んでみましょう。

スクリーンショット 2022-03-03 6.44.43

トークンIDを数えられるようにする、、とのことですが、イメージが湧きにくいので、実際に見てみましょう。

スクリーンショット 2022-03-03 7.06.52

このように、「何番目に何が入っているか」「全部でいくつあるのか」ということがわかるようになります。

スクリーンショット 2022-03-03 7.08.58

2−5 Enumerableがあるとどうなるの?

これは、こちらの「Ryo Manzoku」さんの説明資料がわかりやすいです。

よかったら、ぜひ見てみてください。

今回は詳細を省きますが、Enumerableがあることで列挙を行えるようになります。

スクリーンショット 2022-03-03 7.16.16

(「Ryo Manzoku」さんの上の資料から抜粋)

一方、ガス代がプラスにかかることになります。

なお、このガス代がかかるタイミングを最適化しようとしているのがAzukiのERC721Aというようにつながっていきます。

こちらもmanzokuさんの記事が分かりやすいと思います。

3 overrideについて

3ー1 tokenURIを見てみる

では、少し戻り、ERC721の中身を見てみましょう。

下のように「tokenURI」という関数が定義されています。

スクリーンショット 2022-02-28 19.20.22

これにより、ERC721で定義された「tokenURI」という関数は、「ERC721Enumerable」に継承され、さらに「PurpleEye」コントラクトに継承されています。

3ー2 オーバーライドによる再定義

上のように、「tokenURI」という関数がERC721で定義され、「PurpleEye」コントラクトで使用ができます。

でもちょっと関数をカスタマイズしたい時があります。

例えば今回は、シークレット機能として、NFTの公開前後によって、指定するトークンURIを変えたいとします。

そのために、関数を再定義するのが「override」です。

スクリーンショット 2022-02-28 19.33.29

ERC721で定義されたtokenURI()という関数がPurpleEyeでも定義されています。

これにより、関数がoverride(上書きのイメージ)されることになります。

今回はざっくりと「if文」「baseExtension」の機能を追加しているようです。(詳細は省きます。)

3ー3 virtualについて

このように「override」によって、関数の再定義ができるのですが、再定義をされたくない関数も当然存在します。

むしろその方が多そうですね。

そのため、「virtual」がついている関数だけがoverride(関数の再定義)が可能になっています。

スクリーンショット 2022-02-28 19.20.22

ERC721の「tokenURI」を見てみると、確かに、「virtual」がついていましたね。

4 payable(関数)

関数に「payable」の修飾子が付くとEtherを受け取ることができる関数になります。

スクリーンショット 2022-02-28 19.59.26

この関数はミント時にEtherを受け取っていそうです。(詳細は省きます。)

5 require文

関数を実行するための前提条件を確認するのがrequire文です。

括弧の中が正しくなければ(trueでなければ)、関数は実行されません。

スクリーンショット 2022-02-28 20.04.37

例えば「_mintAmount >0」はミントする数が0以下でしたら、ミントができませんね。

ちなみに、require文かつては引数が一つでしたが、現在では上のように「,」で区切って、エラー時の文言を書くようになっています。

6 ミントをできないようにする(pausedの利用)

一定の期日が来るまで、ミントができないようにする、などの実際の処理を見てみましょう。

下のようにbool型(○か×の2択の)pausedという変数を用意します。

スクリーンショット 2022-02-28 20.21.47

下のrequire文を見てみましょう。

仮にpausedtrueが入っていたとします。「!」「否定」を意味するので「!paused」は「false」になります。

スクリーンショット 2022-02-28 20.16.36

ということは、require文の括弧の中身が trueではないため、前提条件が満たされず、関数が実行されないことになります。

つまり、pausedtrueに設定すれば、ミントは行われないことになります。

実際に、pausedtrueにして、ミントができないことを確認してみてください。

7 msg.sender

Solidityにはコントラクト内で宣言していなくても使用できるグローバル変数が存在します。

その一つがmsg.senderです。

スクリーンショット 2022-02-28 20.33.59

msg.senderは関数を呼び出したアドレスを示します。

例えば、この関数を私(0x96....315)が使用した場合、msg.sender(0x96....315)になります。

他にもよく使うものとしては、下のようなものがあります。

① msg.value
 
トランザクションに関する送金したwei
② block.number
 現在のブロックナンバー
③ block.timestamp
 ブロックが作られたときのタイムスタンプ

8 Ownableコントラクトを読んでみよう

上で出てきた、 owner()関数を見てみましょう。

Ownable.solを見ると、このようにあります。

スクリーンショット 2022-03-01 7.52.50

また、せっかくなので、このコントラクトのコメントも読んでみましょう。

スクリーンショット 2022-03-01 7.52.59

例えば、読んでみると、コントラクトをデプロイしたアカウントownerであるということもわかります。

9 return構文

9ー1 はじめに

まずは、次の2つの関数を見てみましょう。

① tokenURI

スクリーンショット 2022-03-02 5.57.30

こちらはtokenIdを入れて「Query」を押すと、tokenURIの値が返ってきます。

② setCost

スクリーンショット 2022-03-02 5.59.09

こちらはcostの値を入れて「write」を押すと、costはセットされますが、特に何も返ってきません。

このように、関数には、値が返ってくるものと返ってこないものがあります。

9ー2 return構文を見てみよう

owner()関数に返り値があったので、見てみましょう。

その名の通り、現在のオーナーのアドレスが返ってくるようです。

スクリーンショット 2022-03-02 6.10.36

「return」「returns」となっていることにご注意ください。

また、「address」は「int」「0以上の整数」の型を表したように「アドレス」の型のものを返すということを記載しています。

10 アドレス型について

せっかくなので、アドレス型についても見てみましょう。

アドレス型には次の2つのアカウントのアドレスがあります。

① 外部アカウント(EOA)
 ⇨いわゆるウォレット
② コントラクトアカウント

コントラクトアカウントコードを持ち秘密鍵は持たないなどの違いがあります。

せっかくなので、公開鍵からウォレットアドレスを生成する方法を見ていきましょう。

秘密鍵⇨公開鍵は複雑なので省略しますが、ご興味がありましたら、まずはこちらを見てみて下さい。

下のように、公開鍵を使い、「ハッシュ値」というものに変換することで、ウォレットアドレスを求めることができます。

スクリーンショット 2022-03-02 6.42.10

参照(https://www.think-self.com/money/cryptocurrency/secp256k1/)

11 if文

if文は丸括弧()の中身が正しければ(trueなら)、波括弧{}の中身を実行します。

スクリーンショット 2022-03-01 6.44.39

上の例であれば、msg.sender(この関数を実行したアドレス)owner()と一致しなければ、波括弧{}の内容を実行します。

つまり、ミントを実行した人がオーナーでなければ波括弧{}の処理を行うようです。

12 for文

繰り返しの処理を行う場合は、for文を使います。

下の例では、i = 1,  i = 2,  i = 3の3回処理を実行することになります。 

スクリーンショット 2022-03-01 6.52.28

例えばsupply(ここでは、現在のミント総量)が3の時、

i = 1 の時
tokenId : 4(3 + 1) を実行者のアドレスにミント
i = 2の時
tokenId : 5(3 + 2) を実行者のアドレスにミント
i = 3 の時
tokenId : 6(3 + 3) を実行者のアドレスにミント

のようになります。


今回は以上といたします。


いいなと思ったら応援しよう!

ユウキ
サポートをしていただけたらすごく嬉しいです😄 いただけたサポートを励みに、これからもコツコツ頑張っていきます😊