第一回コントラクト輪読会レポート〜Lootのコントラクトを皆で読みながら理解を深めよう〜

contract-study-1-solidity-loot

どうも、イーサリアムnavi運営のでりおてんちょーです。

イーサリアムnaviでは、毎日大量に流れてくるクリプトニュースを調査し、その中でも面白いトピックやクリプトネイティブな題材を選び出し、それを分かりやすく読みやすい形でお伝えしています。パラパラと内容を眺めているだけでも、事業やリサーチの新たなヒントに繋がることがあります。世界の最先端では、どのようなクリプトコアな試みが行われているのかを認識するだけでも、 思わず狭くなりがちな視野を広げてくれるでしょう。

先日イーサリアムnaviでおこなった「コントラクトコードの輪読会」という勉強会のレポートを、記事としてまとめていきます。

今回の勉強会は、Lootというボトムアップ型NFTのコントラクトを読んで、SolidityならびにLootについての理解を深めることを目的としたものでした。

勉強会当日は、1時間半ほどzoomを使いながら進めていきましたが、非常に満足度の高い勉強会となり、これからSolidityの勉強をしたい人にも役に立つ内容だったため、備忘録としてレポートにしておこうと考えました。

本記事では

  1. 「Loot」のコードを見てみよう
  2. 「uint256」とは?
  3. 「Keccak256」とは?
  4. 「abi.encodePacked」とは?
  5. 「nonReentrant」とは?
  6. SVGについて
  7. Solidityにランダム関数はないの?
  8. まとめ

という構成で、第一回コントラクト輪読会レポートとしてまとめていきたいと思います。

本記事が、皆さんの「Loot」「Solidity」への理解の一助となりましたら幸いです。

※本記事は一般的な情報提供を目的としたものであり、法的または投資上のアドバイスとして解釈されることを意図したものではなく、また解釈されるべきではありません。ゆえに、特定のFT/NFTの購入を推奨するものではございませんので、あくまで勉強の一環としてご活用ください。

「定期購読プラン」の詳細はこちら

「定期購読プラン」は現在、トライアル期間を設けているため、初回は30日間無料でプランにご登録いただけます。この機会にぜひお試しいただき、サービスの魅力を体験していただければ幸いです。

※ 1ヶ月間の無料トライアル期間終了後に、自動的に有料プランへと移行します。
※ 無料トライアル期間中にご解約いただければ、ご利用料金は発生いたしません。


目次

「Loot」のコードを見てみよう

まず、Etherscanからコントラクトのコードを見てみましょう。

Lootのコントラクトアドレス『0xFF9C1b15B16263C61d017ee9F65C50e4AE0113D7』で検索

トランザクションを確認する際は「Transactions」の欄を見ますが、コードを読む際は「Contracrt」の欄を使います。

「Contract Source Code (Solidity)」を見ると、たくさんのコードが書かれていることが確認できます。

derio

この勉強会前まで素人であった筆者は、Command + Fでキーワード(Loot, mint…etc)を検索して、読みたいコードを探していました。

しかし、Etherscanでコードを読む際にはもっと良い方法があると教えていただいたので、最初にそれについて話します。

上写真のピンク枠左側の「Outline」から、各functionの内容を確認できます。

この検索機能により、調べたいfunction・気になるfunctionを見つけやすくなりますね。

さらに、ピンク枠右側の「More Options」から「Sol2Uml」をクリックすると、「Solidity UML Diagram」というものが見れます。

この機能により、.solファイルの構成や結びつきを俯瞰的に見ることができるようになるので、コントラクトの全体像を視覚的に理解しやすくなります。

図をクリックすると拡大して移動できる等とても便利なので、勉強会の際には画面共有で資料として使うこともできますね。

「uint256」とは?

Solidityではよく出てきますが、符号なし整数のことです。

一般的には整数表記でintを用いますが、Ethereumでは金額(ETH)を扱うことが多くあまりマイナス表記を使わないという理由で、uintが用いられると聞いたことがあります。

uintは、uint8からuint256まで8の倍数の型が存在し、この8の倍数の数字はbit数(パソコンが一度の処理に扱えるデータの大きさ)を表しています。

ちなみに未指定(uintとだけ表記)の場合は、uint256の扱いとなります。

読み方の通称は「ユーイント にごろ」だそうです。

「Keccak256」とは?

Ethereumで使われるハッシュ関数で、読み方の通称は「ケチャック にごろ」です。

ハッシュ化と聞くとややこしい印象をもつ方もいるでしょうが、Ethereumのアドレスも、公開鍵をkeccak256でハッシュ化したものの一部が使われています。

例:0xD2581aFe6e3B83AB9CC04a9287eaa1b37297b7F7

この後の『abi.encodePackedとは?』でも述べますが、Solidityでは文字(string)の扱い方がやや難しいため、keccak256が使われる場面が多いです。

「abi.encodePacked」とは?

Solidityに組み込みで用意されている関数で、文字(string)を結合する時に使います。

先ほども少し触れましたが、Solidityではstringを扱うことが難しい仕様になっています。

例えば、

  • 「筆者は」
  • 「でりおてんちょーです」

Solidityを使ってこの2つの文字列を結合したい場合、『「筆者は」+「でりおてんちょーです」』ではダメなのです。

ではどうするかというと、「筆者は」と「でりおてんちょーです」をabi.encodePackedを使って連結させる必要があります。

  • str1 = “筆者は”;
  • str2 = “でりおてんちょーです”;
  • abi.encodePacked(str1, str2);

また、上の場合は「連結」のパターンでしたが、Solidityで文字列を「比較」する際には、一度Keccak256関数を使って文字列をbytes32型にハッシュ化して、その値同士で比較しなければなりません。

keccak256(abi.encodePacked(str1)) == keccak256(abi.encodePacked(str2))

derio

このあたりの話は、以下doublejump.tokyo満足さんの資料が大変参考になるので、興味のある方はご覧ください。


出典:OpenSea

Lootでは上写真のように、文字だけが載った画像として出力されています。

これは、先に述べた「文字列の結合」の話で、abi.encodePacked(parts[0], parts[1], parts[2], ... , parts[16])) によって、文字列をどうにかひと固まりにしてoutputに値を格納していることが分かりますね。

「nonReentrant」とは?

nonReentrantは、Reentrancy攻撃対策のためのコントラクトモジュールです。

Lootでは、claim関数とownerClaim関数につけられています。

Reentrancy攻撃って何ですか?

という話は長くなるので割愛しますが、その昔あった「The DAO事件」でも用いられた攻撃方法です。

以下の動画や記事は参考になるので、Solidityのコードが少し読めるという方は観てみてください。
DAOハッキング事件とCall関数 【第14回】Solidity 基礎編 (スマートコントラクト プログラミング入門)
Reentrancy Attack On Smart Contracts: How To Identify The Exploitable And An Example Of An Attack Contract

OpenZeppelinには、ReentrancyGuardと呼ばれる使用可能な独自のmutex実装があり、このlibraryはmutexで関数をガードする「nonReentrant」と呼ばれる、すべての関数に適用できる修飾子を提供してくれています。

要は、LootでもReentrancy攻撃から守るために「nonReentrant」がつけられている訳なのですが、なぜ外部アドレスにETHを送るわけではないclaim関数とownerClaim関数にnonReentrantが必要なのかは不明です。

derio

ご存知の方がいたら、ぜひ教えてください。

追記:
「イーサリアムnavi」メンバーの方に、以下のように教えていただきました。

ERC721のclaimでも内部でOpenZeppelinの_safeMintを呼び出すとすると、受け取り側がコントラクトの場合にERC721を受け取れるかをチェックします。
そのコントラクトのIERC721Receiver.onERC721Receivedを呼び出すので制御が受け取り側のコントラクトにいってしまうため、リエントランシー攻撃の対策が必要そうです。

SVGについて

「フルオンチェーン=100%SVGファイル」という訳ではありませんが、一般的にフルオンチェーンとよばれるNFTは、tokenURIにSVG形式で書かれているケースが多く、Lootもそれに当たります。

コントラクト上でメタデータを生成し、かつコントラクトを叩くとURLではないメタデータを返す点で、LootはフルオンチェーンNFTであると言えますね。

ちなみに余談ですが、「Autoglyphs」というフルオンチェーンNFTのtokenURIは、こんな(↓)感じです。

出典:Etherscan

コントラクト上でメタデータを生成し、かつコントラクトを叩くとURLではないメタデータを返す」を満たしていますね!

フルオンチェーンNFTの場合、メタデータもEthereumブロックチェーン上に載せられていることから、Ethereumブロックチェーンが消滅しない限り、画像データもなくならないことを保証してくれています。

しかし、Lootのような文字だけなら問題ないですが、容量が大きくなってしまうとEthereumチェーンにのせるためのコスト(gas代)が膨大になってしまう問題が発生します。

Solidityにランダム関数はないの?

結論から言うと、Random.rangeのような組み込みで用意されたランダム関数は存在しません。

Solidityの設計思想に「スマートコントラクトはインプットが同じであれば、必ず同じ結果が返される」とあるため、Solidityには乱数生成の処理はないみたいです。

また、そもそもの話、ブロックチェーン上でランダム関数を作るのは難しい問題があるそうです。

例えば、ブロック番号を使ってハッシュ値の計算を行い、それを10や100で割った余りで0〜9、0〜99の乱数を生成する方法が考えられますよね?

しかし、ブロック番号を使うということはマイナーが操作することも理論的には可能なので、厳密には乱数ではないことになってしまいます。

以上の理由から、Solidityには組み込みで用意されたランダム関数が存在しないみたいですが、最近だとChainlinkがVRFというものを用意しているそうです。

Chainlinkをトラストする点には留意が必要ですが、興味のある方は以下記事を読んでみてください。
Introduction to Chainlink VRF

まとめ

本記事では、先日イーサリアムnaviでおこなった「コントラクトコードの輪読会」という勉強会のレポートを、記事としてまとめました。

derio

筆者は今までSolidityの勉強を独学でおこなってきましたが、初めてイベントのような形式でSolidityについて学び、理解を深めることができた点で、非常に新鮮で有意義な勉強会だったように感じました。

「もっとコードを読めるようになりたい!」という気持ちが強くなり、Solidityの勉強に対するモチベーションが非常に高くなったことも、個人的には大きな収穫だったと思います。

昨今はコロナ禍ということもあり、なかなかオフラインでのイベントも開催しづらいので、こういった形式の勉強会は今後も企画していきたいと考えています!

イーサリアムnaviを運営するSTILL合同会社では、web3/crypto関連のリサーチ代行、アドバイザー業務、その他(ご依頼・ご提案・ご相談など)に関するお問い合わせを受け付けております。

まずはお気軽に、こちらからご連絡ください。

みんなにも読んでほしいですか?
  • URLをコピーしました!
目次