見出し画像

第6回 solidity学習会 講義ノート(4/2 AM8:00~)

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

クリスペの会社です。

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

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

場所 meet.google.com/cas-bnjw-rpg

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

では、やっていきましょう。

1 はじめに

前回に引き続き、RemixにコピペしたLootのコードを元に進めていきます。

こちらがLootのコードです。

https://etherscan.io/address/0xff9c1b15b16263c61d017ee9f65c50e4ae0113d7

Remixはこちらです。

まずはじめに、こちらの「nonReentrant」を見てみましょう。

2 Reentrantとは?

再入可能という意味のようです。

今回はclaim機能にReentrantをしないように「nonReentrant」がついていました。

例えば、ほぼ同時にトークンID1をclaimされたらどうでしょう?

_safeMintの完了に一定の時間がかかることから、もし「nonReentrant」がなければ、同時にclaimすることができてしまいます。

ただ、実際にミントができるのは1人だけです。

そのため、もう一方の人は「ミント済み」というエラーになってしまいます。

一方、nonReentrantがあれば、claimをした瞬間、他の人はtokenId:1をclaimがそもそもできなくなります。

3 具体的にOpenZeppelinを見てみましょう

つまり、図にするとこんな感じだと思います。

4 修飾子の復習をしてみましょう

この勉強会でもよく出てきます、onlyOwnerも見てみましょう。

修飾子なので、実際の処理の部分が「_;」で表されています。


5 そもそも、なぜReentrantではダメなの?

結論としては、Reentrancy attacksを防ぐために、「nonReentrant」が使われます。

まず、前提として、ステート(状態)は一定に保たれている必要があります。

例えば、コントラクトのTotal supply100であれば、トークンの総数は100です。

これは下のように、Cさんが引き出しても同じです。

しかし、仮に下のような処理がなされている場合、①の瞬間は全供給量が125になっています。

この不整合な状態を狙ってくるのが、「Reentrancy attacks」です。

そのため、関数の処理が完了していない、不整合な状態で処理を行われないために、「nonReentrant」を行い、入って来れないようにしています。

6 Base64について

少し前まで、OpenZeppelinBase64のライブラリが存在していませんでした。

そのため、Lootなどでは独自のBase64が使われていました。

しかし、 OpenZeppelinでも実装されるようになりました。

Base64を使用する場合には、ぜひこちらもご参照ください。

7 OnChainMonkeyを参考にジェネレーティブを作ろう!

こちらのプロジェクトを元に、フルオンチェーンのジェネレーティブを学んでみましょう。

https://opensea.io/collection/onchainmonkey

8 フルオンチェーン・ジェネレーティブの作り方(テンプレートの一つ)

OnchainMonkeyから一つのテンプレートを作ってみましょう。

下のようなテンプレートをもとに具体的に見ていきましょう。

①パーツ格納用の構造体を作る
 ⇨配列の番号である、0,1などの数字を入れる

②確率・色用の配列を用意する
 ⇨確率用・色用の2つを用意するのがポイント

③パーツを分類する
 1)共通パーツ(顔の形など)
 2)レア・形共通パーツ(レアの場合、同じ形の帽子など)
 3)レア・形変形パーツ(レアの場合、さまざまな形のイヤリングなど)

④SVG合体用の関数を作る

ちなみに、パーツ部分については、次のようになります。

===============
③1)共通パーツ(顔の形など)
 (1)色以外のSVGを作り、配列に格納する
 (2)合体関数に組み込む

③2)レア・形共通パーツ(レアの場合、同じ形の帽子など)
 (1)色以外のSVGを作る
 (2)合体関数に組み込む

③3)レア・形変形パーツ(レアの場合、さまざまな形のイヤリングなど)
 (1)色以外のSVGを作る
 (2)パーツ作成用関数を作る
 (3)合体関数に組み込む
===============

では、次の章から具体的に見ていきましょう。

9 見やすいコードにするには?(SVGをわかりやすく)

まずは、tokenURI()を見てみましょう。

とてもコードがスッキリしていますね。

これは上の方で、SVGの部品を変数として格納しているためです。

これにより、コードの可読性を上げています。

とても良いテクニックなのではと思います。

10 構造体について

下のように、「struct」で複数の変数をセットにした構造体を作ることができます。

今回の場合、「Ape」という構造体の中に、bg(背景)fur(毛並みの色)eyes、、などの様々な情報を入れています。

ちなみに、下のようにして値を入れることができます。

11 uint8って何?

今まで、uint256の256などを扱っていなかったので、ここで触れてみたいと思います。

uint8の8はビットを表します。

1ビットは0と1の2通りを表せるため、8ビットは2の8乗である256通りを表すことができます。

つまり、uint256なら、2の256乗の数を表すことができます。

クリプトゾンビから

そのため、構造体の中で、あらかじめ変数で使う種類がわかっているような場合には、uint8などを用いて、ガス代を節約することができます。

12 重み付けのランダム値を作ってみよう

レア度について、完全なランダムではなく、確率を変えたい場合はどのようにコードを書けば良いでしょう。

それぞれの要素を見ると「_w」という数字が入った配列があります。

これがポイントです。

13 実際に見てみよう

今回はearingを元に見ていきます。

usewという関数を使っていますが、2つ目の引数には0~357のどれかの値を渡しています。

では、下のようにusewという関数を見てみましょう。

「_w」の配列と0~357の擬似ランダムな値が渡されています。

ランダムな値が0~250(251パターン)の時にが返されます。

そのため全パターンである358のうち、251の確率で、0が返されます。

つまり、251/358ですね。

ちなみに、358は「_w」の配列を全て足した数になっています。

これで過不足なく抽出できるようになっています。

14 形が同じ・色違い要素を作ってみよう

まずは、形が同じで、色だけが異なるものを抽出しましょう。

これらは形が同じなのでfill以外のSVGは固定されます。

これらは、下のように、色コードの直前までをそれぞれの要素として、配列に格納することで、便利に利用ができます。

なお、黒目の色などのように、要素の色まで固定の場合は、各要素に入れ込みます。

その要素を、上のように色と交互に組み合わせています。

15 レア要素を作ってみよう

まずは、どのようなレア度のタイプかを分類してみましょう。

1 形は変わらない
  ⇨ 帽子・服
2 形も変わる
  ⇨ 目の形・イヤリング

では、それぞれ見ていきましょう。

15ー1 形は変わらないタイプ

まずは、服のように形は変わらないものの実装の仕方を見てみましょう。

下のように、実装されています。

①レアの場合はSVGを入れ、レアでない場合は空白を入れる
②レアか否かに関わらず、abi.encodePacked()でくっつける

具体的に、ape.clothesを見てみましょう。

251 / 1329の確率で0となります。

0の時には「clost」は空白になり、それ以外の時は、それぞれのSVGが入ります。

15ー2 レア度によって形も変わるタイプ

では、形が変わるタイプはどうでしょう。

大まかに、次のような構成になっています。

①特定の関数を作る
②レアの場合はSVGを入れ、レアでない場合は空白
を入れる
レアか否かに関わらず、abi.encodePacked()でくっつける

実は、①特定の関数を作るだけが加わるだけで、あとは同じです。

イヤリングについて見てみましょう。

あとは、いつもと同様です。

これで、パーツごとの作り方を具体的に見ることができました。

これを元にすれば、自分自身のオリジナルのジェネレーティブを作ることができるかと思います。

以上です。


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