![見出し画像](https://assets.st-note.com/production/uploads/images/114392450/rectangle_large_type_2_8a0ba2231cfb0ea301654048435b198f.png?width=1200)
【完全保存版】Autonomous WorldのMUDについてしっかり学ぼう!
0 注意!(はじめる前に)
実際に実行すると、私の環境では、こちらの「.foundry」フォルダにJSONファイルがどんどん溜まっていきました。
![](https://assets.st-note.com/img/1693000221747-jQY9crhEwz.png?width=1200)
PCの容量がどんどん減っていきますので、不要なものは削除したり、必要時以外はシステムを止めるのが良いと思います。
1 事前準備
こちらの公式に沿って進めていきます。
下の4つを準備してください。
![](https://assets.st-note.com/img/1692848286794-P04zhcCO4s.png?width=1200)
ちなみに、「pnpm」は「performant npm」の略のようです。
その名の通り、パフォーマンスの最適化を図っているようです。
こちらは参考に、chatGPTからです。
![](https://assets.st-note.com/img/1692769424526-NTqnQwMbNB.png?width=1200)
ちなみに、「pnpm」のコマンドがうまくいかない場合、第6章も参考にして見てください。
2 実際にやってみよう
では、実際にやってみましょう。
1 プロジェクトの作成
まずは、下のコマンドを実行し、「vanilla」を選択します。
pnpm create mud@next my-project
![](https://assets.st-note.com/img/1692769372238-BQTfZ1JeW5.png?width=1200)
ちなみに、依存関係として、「@latticexyz/cli」を入れています。
![](https://assets.st-note.com/img/1692769835159-jaNYWY2Qtm.png?width=1200)
この「Autonomous World」を作っている会社です。
![](https://assets.st-note.com/img/1692848640618-erD2LOghxK.png?width=1200)
2 プロジェクトの実行
では、次のコマンドで、実行してみましょう。
cd my-project
pnpm run dev
![](https://assets.st-note.com/img/1692848753287-HnPy2RkkD4.png?width=1200)
3 mud.config.tsからの生成
まずは、下のように、「mud.config.ts」というファイルによって、二つのsolidityファイルが作られています。
![](https://assets.st-note.com/img/1692769811114-RrtEDaMCGw.png?width=1200)
ちなみに、2つの関係性はこのようになっています。
今回は、1ずつ増えるだけの「Counter」を保持しています。
![](https://assets.st-note.com/img/1692849363609-if257RvZnG.png?width=1200)
4 コントラクトフォルダからの生成
そして、コントラクトフォルダを元に、インターフェースが作られます。
![](https://assets.st-note.com/img/1692770015292-gp2kW5QggP.png?width=1200)
具体的な仕組みの部分が「IIncrementSystem」になります。
![](https://assets.st-note.com/img/1692849846792-Y3uns8b6b7.png?width=1200)
5 Systemコントラクトのデプロイ
次に、「IncrementSystem」というコントラクトができました。
![](https://assets.st-note.com/img/1692770119595-ACxy10KzTV.png?width=1200)
![](https://assets.st-note.com/img/1692850291139-ZO73YvP7rX.png?width=1200)
6 モジュールコントラクトのデプロイ
次に、下の4つのモジュールがデプロイされました。
![](https://assets.st-note.com/img/1692770196569-GDn70tZRsA.png?width=1200)
![](https://assets.st-note.com/img/1692850536999-1oeEG2Ql85.png?width=1200)
7 Worldコントラクトのデプロイ
そして、最後に「World」がデプロイされました。
![](https://assets.st-note.com/img/1692770224934-NV8cyyYSv4.png?width=1200)
![](https://assets.st-note.com/img/1692850644626-jk5O1XT1jH.png?width=1200)
8 Coreモジュールのインポート
次に、こちらの「Core」モジュールをインポートしています。
![](https://assets.st-note.com/img/1692850770220-Dg9yJnpJ8v.png?width=1200)
9 テーブルの登録
次に、「Counter」というテーブルが登録されました。
![](https://assets.st-note.com/img/1692861530227-KtHcGaYPXB.png?width=1200)
10 システムの登録
その後、システムが登録されています。
![](https://assets.st-note.com/img/1692861590163-kgsS6ZMW0w.png?width=1200)
11 関数の登録
その上で、関数が登録されたようです。
![](https://assets.st-note.com/img/1692861633943-AczJB26169.png?width=1200)
最後に、結果が「Worlds.json」に格納されています。
![](https://assets.st-note.com/img/1692777998283-NnYgaCbAdl.png?width=1200)
12 動作を確認してみよう
では、実際に確認してみましょう。
http://localhost:3000/
に行き、「Increment」を選択すると、イベントが発生し、その結果がフロントにも反映されているようです。
下の場合、「ブロック番号」が7477で発火しているようです。
![](https://assets.st-note.com/img/1692778150669-OQvCuTGiQp.png?width=1200)
では、コードを見てみましょう。
3 全体構成について
まずは、全体像として、「packages」に「client」と「contracts」があります。
![](https://assets.st-note.com/img/1692778214786-hT8TDoP9B9.png?width=1200)
1 contractsについて
まずは、「contracts」については、主に下のようになります。
![](https://assets.st-note.com/img/1692778405984-I6uPFRZEnX.png?width=1200)
登場人物はこのようなイメージです。
![](https://assets.st-note.com/img/1692862186584-wZZtzuaBso.png?width=1200)
2 clientについて
一方、「client」は下のようになります。
後ほど、一つずつ見ていこうと思います。
![](https://assets.st-note.com/img/1692778495738-ykgbijfPxB.png?width=1200)
4 contractsについて
では、contractsについて細かく見てみましょう。
1 mud.config.tsについて
では、「mud.config.ts」を見てみましょう。
こちらは、使用するテーブルなどを指定します。
例えば、下では、「Counter」というテーブルを作っています。
![](https://assets.st-note.com/img/1692778642836-lrYgvuLfOq.png?width=1200)
今回は、すでに作られていますが、「contracts」フォルダ内で、下のコマンドを実行することで、ファイルが作成されます。
pnpm mud tablegen
2 Counter.solについて
コードの中身は下のようになっています。
下はゲッター系と登録を行う関数が並んでいます。
![](https://assets.st-note.com/img/1692779622564-ueEm3ogvcJ.png?width=1200)
また、最後まで見てみますと、セッター系やレコードの削除を行う関数もあります。
このように、テーブルの構成が決まれば、あとは自動でsolidityのファイルを作成しています。
![](https://assets.st-note.com/img/1692779677224-QHFKp8nMTG.png?width=1200)
つまり、下のようなことが行われています。
![](https://assets.st-note.com/img/1692862998057-zRx9fFTPcT.png?width=1200)
3 IncrementSystem.solについて
次に、「systems」内の「IncrementSystem」コントラクトを見てみましょう。
![](https://assets.st-note.com/img/1692778809148-tT6IU9z1Tz.png?width=1200)
下のように、ロジックと値が分離しています。
このコントラクトは、あくまでもロジックの部分のみで、値は「Counter」の「get」と「set」を使っています。
![](https://assets.st-note.com/img/1692863322599-rvmA556z2Q.png?width=1200)
![](https://assets.st-note.com/img/1692863764971-yK3emPBWIW.png?width=1200)
4 PostDeploy.s.solについて
次に、「PostDeploy.s.sol」を見てみましょう。
ここはその名の通り、デプロイ後に、特定の処理を行うコントラクトです。
![](https://assets.st-note.com/img/1692779331162-6gfY6ZnqCv.png?width=1200)
ただ、個人的に気になったのはこちらです。
処理は、「Iworld」から行われています。
![](https://assets.st-note.com/img/1692864197848-MjTGZpIXqQ.png?width=1200)
他の箇所でも書かれていたのですが、このように、処理は「World」を起点にして行われているようです。
![](https://assets.st-note.com/img/1692864471285-y5vFlCylBx.png?width=1200)
5 Tables.solについて
ちなみに、「Counter.sol」では、下のように、IDも取得しています。
![](https://assets.st-note.com/img/1692779847187-z6EONTIiiJ.png?width=1200)
この、「Counter」ライブラリと「ID(CounterTableId)」を「Table.sol」はインポートしています。
![](https://assets.st-note.com/img/1692779900385-8BcmKqhTI0.png?width=1200)
下の部分です。
![](https://assets.st-note.com/img/1692864804845-6EZBuuiOV0.png?width=1200)
5 clientについて
では、次に、「client」について見てみましょう。
1 index.tsについて
1ー1 setup関数について
まずは、index.tsを見てみましょう。
![](https://assets.st-note.com/img/1692949228477-bGFUHjNTst.png?width=1200)
トップレベルの非同期処理として、setup関数が実行されています。
そして、「components」「increment」「network」に分割代入しています。
1ー2 observableについて
次に、RxJSのobservableの部分を見てみましょう。
![](https://assets.st-note.com/img/1692953266909-qWE5S8MXIE.png?width=1200)
ご不明の方は、この辺りの記事が参考になると思います。
「components.Counter.update$」の部分がObservableになります。
「subscribe」関数で購読を開始しています。
![](https://assets.st-note.com/img/1692953391424-ux3n1KElTd.png?width=1200)
データが流れてくると、中のコールバック関数が実行され、表示が変わります。
なお、「subscribe」関数は登録を行なっているので、1回のみ行われます。
(その後、データが流れてくると、コールバック関数は実行されます。)
![](https://assets.st-note.com/img/1692953559254-SirDi39PfI.png?width=1200)
1ー3 windowオブジェクトへの関数の追加
下の部分では、「window」オブジェクトに「increment」関数を追加しています。
![](https://assets.st-note.com/img/1692954091985-p2LYsrA51j.png?width=1200)
これにより、consoleから直接実行ができるようになります。
![](https://assets.st-note.com/img/1692954296515-DOk3kN10ep.png?width=1200)
2 setup.tsについて
では、「index.ts」で行われた、「setup」関数を見てみましょう。
下のように構成されています。
① setupNetwork関数
② createClientComponents関数
③ createSystemCalls関数
![](https://assets.st-note.com/img/1693001065366-o5ay4G6EWs.png?width=1200)
3 getNetworkConfig.tsについて(ネットワーク構成の取得)
次に、「getNetworkConfig.ts」の「getNetworkConfig」関数を見てみましょう。
その名の通り、Networkの構成を取得すると考えられます。
![](https://assets.st-note.com/img/1692826066540-GWoiBs6Xdj.png?width=1200)
なお、結論としましては、下のような情報を取得します。
![](https://assets.st-note.com/img/1692866353546-zEMnMPNWex.png?width=1200)
3ー1 paramsの取得について
まずは、下の部分で、「クエリストリング」のキーと値のペアのオブジェクトを取得しました。
![](https://assets.st-note.com/img/1692826108710-6JH5zZjZj7.png?width=1200)
実際に見た方がイメージが湧くかもしれません。
下のような感じです。
![](https://assets.st-note.com/img/1692865281699-wMlruw0Nf2.png?width=1200)
3ー2 チェーン情報の取得について
次に、上で取得したparamsを元に、チェーンの情報を取得しています。
![](https://assets.st-note.com/img/1692826143800-9Y2MAHxYe7.png?width=1200)
3ー3 Worldアドレスの取得について
また、下の部分では、「World」のコントラクトアドレスを取得しています。
![](https://assets.st-note.com/img/1692826187331-XPdkjCZG6t.png?width=1200)
3ー4 初期ブロック番号の取得について
さらに、下の部分で最初のブロック番号についても設定しています。
![](https://assets.st-note.com/img/1692826229050-Bel6NTEJlp.png?width=1200)
3ー5 秘密鍵の取得について
なお、下の部分を見ると、秘密鍵は、一時的に実行しているアカウントのプライベートキーを取得しているようです。
![](https://assets.st-note.com/img/1692826277485-R80cc63oiy.png?width=1200)
3ー6 一時アカウントの秘密鍵の取得関数について
少しわきにそれますが、「getBurnerPrivateKey」関数を見てみましょう。
これは、一時的に作成したアカウントの秘密鍵を取得するものです。
まずは「localStorage」になないかを確認します。
![](https://assets.st-note.com/img/1692832052161-G1OoboJ67e.png?width=1200)
もしあるようなら、正しいものかを確認し、正しければ、その秘密鍵を返しています。
![](https://assets.st-note.com/img/1692832077723-0zDwC68brc.png?width=1200)
3ー7 秘密鍵生成関数について
ないようなら、「generatePrivateKey」関数を使って、秘密鍵を作成し、「localStorage」に保管しています。
![](https://assets.st-note.com/img/1692832130618-H8WxCo8Aa5.png?width=1200)
ちなみに、「generatePrivateKey」関数は下のように、「secp256k1」の「randomPrivateKey」関数を使っているようです。
![](https://assets.st-note.com/img/1692832202258-hfTYn1GRE8.png?width=1200)
3ー8 faucetについて
また、「faucetServiceUrl」では該当するものがあれば、「faucetUrl」を指定しているようです。
![](https://assets.st-note.com/img/1692826305771-P8cCHmDVgC.png?width=1200)
4 Worldについて
4ー1 Worldについて
次に、「world」を確認しましょう。
このように、createWorld関数の結果が格納されています。
![](https://assets.st-note.com/img/1692846308770-DuhIafpuj4.png?width=1200)
4ー2 createWorld関数について
下のようになっています。
![](https://assets.st-note.com/img/1692846256007-GRyDLx3i41.png?width=1200)
まとめると、このようになっていました。
![](https://assets.st-note.com/img/1692916164466-9WDtC9KKBS.png?width=1200)
5 setupNetworkについて
次は、「setupNetwork」関数を見てみましょう。
5ー1 networkConfigについて
まずは、「networkConfig」を取得しています。
![](https://assets.st-note.com/img/1692826493577-3kstuTMkSN.png?width=1200)
ちなみに、network configは次のようになっていました。
![](https://assets.st-note.com/img/1692917716590-rnuSH4Mb7M.png?width=1200)
5ー2 戻り値について
「setupNetwork」関数の戻り値は、こちらを返しています。
![](https://assets.st-note.com/img/1692830152024-ZLW7HLZvcJ.png?width=1200)
つまり、このようになります。
![](https://assets.st-note.com/img/1692944762188-zZ7jwyb14J.png?width=1200)
5ー3 clientOptinosについて
まずは、「clientOptinos」が次のように設定されています。
![](https://assets.st-note.com/img/1692826531318-vPppQP5H5Z.png?width=1200)
下のようになりました。
つまり、どのチェーンで、どのようにして、どのくらいの間隔で、ブロックチェーンとやりとりするのかを選択しています。
![](https://assets.st-note.com/img/1692918299711-e67mar1HRk.png?width=1200)
5ー4 publicClientについて
そして、この「clientOptions」を元にして、「publicClient」が作成されます。
![](https://assets.st-note.com/img/1692826618038-w2js0zosaB.png?width=1200)
下のようになりました。
![](https://assets.st-note.com/img/1692918789144-UDIyHNr6qS.png?width=1200)
5ー5 burnerWalletClientについて
次は、下の部分の「burnerWalletClient」を見てみましょう。
![](https://assets.st-note.com/img/1692826757676-qweRYeIA9n.png?width=1200)
このようにして、「client Options」を元にして、「burnerWalletClient」を作成しています。
![](https://assets.st-note.com/img/1692920036353-MsrC8A9RWV.png?width=1200)
5ー6 write$について
なお、write$では、Subject のインスタンスを作成しています。
![](https://assets.st-note.com/img/1692827726488-2dwZS2sejn.png?width=1200)
SubjectはObservableとObserverの両方の特徴を持ちます。
Subjectについてはこの辺りの記事がわかりやすいです。
これで、データストリームの変更が監視できます。
5ー7 worldContractについて
この部分で、「worldContract」を作成しています。
![](https://assets.st-note.com/img/1692827746808-3LHqlvM1Ie.png?width=1200)
状況としては、このようになっています。
![](https://assets.st-note.com/img/1692927330363-4vYzhzR1bR.png?width=1200)
重要なのはこの部分かと思います。
ここで、受け取ったwriteデータをwrite$に送信しています。
これにより、このSubjectを購読しているすべてのObserverにデータが配信されます。
![](https://assets.st-note.com/img/1693000615882-ggLNrlxk4O.png?width=1200)
5ー8 createStoreSync関数について
続いて、「createStoreSync」関数を確認してみましょう。
その名の通り、ここでブロックチェーンとStoreとの同期を行うための情報(主に、「blockStorateOperations$」) が作成されています。
![](https://assets.st-note.com/img/1692928223690-mLHfRO9ROM.png?width=1200)
構成としては、下のようになっています。
「開始ブロック」や「最大ブロック範囲」で同期するブロックを指定しています。
その他、「onProgress」で進行状況を報告し、「storageAdapter」はデータの読み書きのインターフェースとして利用されています。
![](https://assets.st-note.com/img/1692936129200-mgWzn9C9eF.png?width=1200)
これを元にして、最新ブロックやオペレーション(blockStorageOperations$)などを返しています。
![](https://assets.st-note.com/img/1692936146270-JRxJcRo3bm.png?width=1200)
5ー9 blockStorageOperations$について
また、こちらの「blockStorageOperations$」の部分を確認します。
初期のストレージ操作(initialStorageOperations$)とその後のブロックログ(blockLogs$)に基づいてストレージ操作を生成するストリームのようです。
![](https://assets.st-note.com/img/1692940352881-3mtFUKI8hg.png?width=1200)
5ー10 syncToRecs関数について
では、これを踏まえて、「syncToRecs」関数を見てみましょう。
![](https://assets.st-note.com/img/1692941053030-knYkQUcNgg.png?width=1200)
大まかに、下のようになっています。
![](https://assets.st-note.com/img/1692941512194-gobNEpe7Aw.png?width=1200)
下のように、途中で、「createStorageSync」を呼び出しています。
![](https://assets.st-note.com/img/1692941553464-PlkMzFK6jf.png?width=1200)
つまり、このようになっています。
![](https://assets.st-note.com/img/1692941891162-JqpB8CoXgl.png?width=1200)
そして、下の部分で、Observableからのデータやイベントを受け取るための購読を開始しています。
![](https://assets.st-note.com/img/1692942494184-Lc5LKs9dzG.png?width=1200)
では、「setupNetwork」関数に戻ります。
下のように、「syncToRecs」関数が実行されていることがわかります。
![](https://assets.st-note.com/img/1692942825187-OlPN8saejQ.png?width=1200)
つまり、こんな感じになりました。
![](https://assets.st-note.com/img/1692943254155-6Oh48LbMBG.png?width=1200)
5ー11 戻り値について
そして、「setupNetwork関数」の戻り値は下のようになっています。
![](https://assets.st-note.com/img/1692830152024-ZLW7HLZvcJ.png?width=1200)
それを含めると、次のようになりました。
![](https://assets.st-note.com/img/1692943601276-JFJeHPcVPb.png?width=1200)
6 createClientComponent.tsについて
引数として、「setupNetwork」関数の結果として取得した「components」を使用しています。
そして、下のように、「components」をそのまま返しています。
コメントにあるように、「client components」の追加や上書きも想定しているようです。
![](https://assets.st-note.com/img/1692780477332-y1voCLDYwP.png?width=1200)
7 createSystemCalls.tsについて
最後に、「createSystemCalls」関数を見てみましょう。
まずは、引数として、次を取得しています。
・「setupNetwork」関数の戻り値の「worldContract」、「waitForTransaction」関数
・「createClientComponent」関数の返り値の「Counter」
![](https://assets.st-note.com/img/1692845750222-gokdXlL9ii.png?width=1200)
そして、こちらの「increment」関数を返しています。
![](https://assets.st-note.com/img/1692845850224-u6FPnyPxFa.png?width=1200)
下のように、「increment」は「worldContract」を通じて行われていることが確認できます。
![](https://assets.st-note.com/img/1692845820557-vcXqUiwMGu.png?width=1200)
これで以上です。
ただ、まだまだ足りないと感じているため、こちらのノートは都度追加を行なっていきたいと思います。
6 追記 pnpmのコマンドが通らない時
pnpmのコマンドがうまく通らないとの連絡をいただきました。
パスが問題なのではと思いました。
下の部分ができているか、確認して見てください。
1 pnpmの保存場所の確認
まずは、次のコマンドで、pnpmがどこにあるのかを確認しましょう。
which pnpm
私の場合は、「/Users/ytakahashi/.npm-global/bin」の中にありました。
![](https://assets.st-note.com/img/1693184825594-LoKksHmywX.png?width=1200)
2 パスを確認しよう
次のコマンドで、パスを確認してみましょう。
echo $PATH
「:」は区切り文字です。
私の場合は、このように先頭にありました。
![](https://assets.st-note.com/img/1693184913720-KW1MBkmxhG.png?width=1200)
3 PATHを更新する場合
永続的に、PATHを更新する場合は、下のコマンドを行います。
echo 'export PATH=$PATH:<PATHの情報をここに>' >> ~/.zshrc
なお、bashの場合は、「.zshrc」の部分を「/.bashrc」にします。
![](https://assets.st-note.com/img/1693184974150-uRNQGx4mxd.png?width=1200)
なお、「bash」か「zsh」かは、次のコマンドで確認ができます。
echo $0
![](https://assets.st-note.com/img/1693185496970-UtJa5B7Hzf.png)
私のPCは「zsh」です。
ちなみに、先ほどのこちらのコマンド、最初はとっつきにくいと思います。
ただ、内容としては、$PATHに新しいパスを追記して、環境変数としてexportしているだけです。
![](https://assets.st-note.com/img/1693184974150-uRNQGx4mxd.png?width=1200)
最後に、下のコマンドで、現在のシェルセッションに反映させます。
source ~/.zshrc
シェルセッションとは、現在開いているターミナル(コマンドプロンプト)の一連の操作のことです。
これは、この窓を閉じると、このシェルセッションは閉じられます。
![](https://assets.st-note.com/img/1693184996004-mV2P9GGsLh.png?width=1200)
4 うまくいったかを確認しよう
最後に、パスが通っているかを確認してみましょう。
pnpm --version
下のように、バージョンが表示されましたら、成功です。
![](https://assets.st-note.com/img/1693186014386-LQgzTnXMaF.png)
いいなと思ったら応援しよう!
![ユウキ](https://assets.st-note.com/production/uploads/images/52347520/profile_e7d36b385c74618d7fec56da47f68a35.jpeg?width=600&crop=1:1,smart)