多くのブロックチェーンがスケーラビリティと輻輳の問題を抱えていることはよく知られています。これらの問題は、取引時間の遅延から取引手数料の増加、ユーザー エクスペリエンスの低下まで、幅広い影響をもたらします。 1 つの解決策は、web3 を (レイヤー 2) チェーンを使用した にすることです。 、 、 などの Ethereum L2 は、Ethereum ネットワークの上に構築されますが、Ethereum よりも高速で安価です。 L2 マルチチェーン Optimism Arbitrum Polygon ただし、トレードオフとして、イーサリアムよりも安全性が低いことがよくあります。そのため、L2 は日々のユーザー アクティビティを処理しながら、安全で分散化された決済とデータ可用性レイヤーの舞台裏の基盤として Ethereum L1 に依拠しています。 これは優れたソリューションですが、イーサリアムだけでも多くの L2 が存在します。それぞれが独自のニュアンスと経験を持つスタンドアロン ネットワークです。 これらのネットワークと Ethereum L1 の間で相互運用および移動する dapps を構築して使用することは、ユーザーと開発者にとって退屈で困難であり、貧弱な経験になる可能性があります。 私たちが必要としているのは、web3 が エクスペリエンスになることです。そこでは、消費者は自分が使用しているチェーンを知る必要がなく (率直に言って気にしません)、開発者は dapps のニーズを最もよくサポートするネットワークに依存できます。 . マルチチェーン このブロックチェーンのマルチチェーン 移行することで、web3 は関係者全員にとってより良いエクスペリエンスになります。 インターネットに 残念ながら、dapps がチェーン間を移動できるようにすることは、技術的に困難な課題です。この記事では、Infura RPC エンドポイントと Truffle Box を使用して構築し、これらのネットワークをシームレスにブリッジする 1 つのソリューションを見ていきます。 具体的には、 を使用して、Ethereum Goerli テストネット上にプロジェクトを作成し、Optimism Goerli にブリッジします。 Optimism Bridge Truffle Box Infura と Truffle Box を使用したマルチチェーン Dapp の実行 トリュフボックス サンプル ソリューションの中核として、dapp の構築に使用できる ConsenSys の「ショートカット」ボイラープレート (コントラクト、ライブラリ、モジュール、さらには完全に機能する dapps など) である に依存します。 Truffle Boxes マルチチェーン ソリューションの場合、L2 ネットワークの多くで の上に構築されます。 Infura RPC ノード 上で述べたように、特に に依存します。このボックスには、L1 と L2 の両方から Optimism ブリッジと対話するために必要なすべてのコントラクトと、デプロイ、関数の呼び出し、およびレイヤー間でのメッセージ/値の受け渡しのための一連の移行が含まれています。 Optimism Bridge Truffle Box これには、すべての動作を確認するために必要なすべてを実行するヘルパー スクリプトもあります。箱から出して必要なものをすべて入手するだけです。 Trufflesuite.com によると、ボックスには次のものが含まれています。 「Optimism ブリッジを介してメッセージを送信する L1 コントラクト Ethereum から Optimism にメッセージを送信する移行 Optimism ブリッジを介してメッセージを送信する L2 コントラクト Optimism から Ethereum にメッセージを送信する移行 コントラクトのコンパイル、移行の実行、メッセージの送信を自動化するスクリプト ブリッジを介した ETH と DAO の送信を自動化するスクリプト」 注: は、独立したブロックチェーンが相互に通信し、トークンや NFT などを送信できるようにするツールです。 ブリッジ 前提条件 始める前に、次の前提条件が必要です。 とそのパッケージ マネージャー NPM。 Node.js 次のターミナル コマンドを使用して、Node.js がインストールされていることを確認します。 node -v && npm -v インフラアカウント アカウント メタマスク JavaScript と Solidity の基本的な理解 ステップ 1 — ネットワークにアクセスするための Infura アカウントを作成する 前提条件を満たしたら、Infura Web サイトにアクセスして (または新しいアカウントに ) します。 ログイン サインアップ サインアップに成功すると、以下に示すように、ページが Infura ダッシュボードにリダイレクトされ、そこで新しい API キーを作成できます。 「Create a New Key」ボタンをクリックし、必要な情報を入力します。 API キーを作成すると、以下に示すように、プロジェクト ID がダッシュボードの API KEY セクションの下に表示されます。コピーしてどこかに保管してください。このチュートリアルの後半で必要になります。 ステップ 2 — セットアップとインストール 次に、 を設定します。次のコマンドを使用して、選択した任意のディレクトリで unbox コマンドを実行できます。 Truffle Optimism Bridge Box npx truffle unbox optimism-bridge <DIRECTORY_NAME> <DIRECTORY_NAME> を任意のディレクトリ名に置き換えます。または、Truffle をグローバルにインストールして unbox コマンドを実行することもできます。 npm install -g truffle truffle unbox optimism-bridge <DIRECTORY_NAME> このコマンドは、ボックス化解除プロセスの一部として npm install をダウンロードして実行する必要があります。 次に、次のコマンドを実行して、ディレクトリを作成したばかりの新しいディレクトリに変更します。 cd truffle-bridge-demo 注: truffle-bridge-demo は、作成されたディレクトリの名前です。 以下に示すようなものがあるはずです。 。 npm パッケージがインストールされましたが、ボックス化解除後に作成される .env ファイルにいくつかの情報を追加する必要があります。 dotenv ファイルは、Ethereum Goerli および Optimism Goerli テストネットでコマンドを実行するために GOERLI_MNEMONIC 値が .env ファイルに存在すること、およびネットワークに接続するための INFURA_KEY が存在することを想定しています。 truffle-config.ovm.js GOERLI_MNEMONIC="<your-wallet-mnemonic>" INFURA_KEY="<your-infura-key>" <your-infura-key> を Infura ダッシュボードから取得した情報に置き換えます。 ( : 秘密鍵 (ニーモニック) を誰とも共有せず、安全に保管してください)。以下に示すように、 <your-wallet-mnemonic> をニーモニックに置き換えます。 注 メタマスクからニーモニックを取得するには、メタマスクの下に表示されているアイコンをクリックします。 次に、[ ] ボタンをクリックして、ニーモニックをコピーします。 秘密鍵のエクスポート Git は、このプロジェクトの .env ファイルを無視して、個人データを保護します。秘密鍵を GitHub に開示しないようにすることは、優れたセキュリティ プラクティスです。 ステップ 3 — Truffle L2 ボックスを使用したブリッジ プロジェクトを開封すると、プロジェクトに必要なすべてのコントラクトとスクリプトが作成されました。この次のステップでは、個々のコントラクトと移行について説明し、ネットワーク間でブリッジングと相互作用がどのように発生するかを理解しましょう。 コントラクト は、楽観主義ブリッジを介して L1 から L2 にメッセージを送信する方法を示しています。 contract/ethereum/GreeterL1.sol //SPDX-License-Identifier: Unlicense // This contract runs on L1, and controls a Greeter on L2. pragma solidity ^0.8.0; import { ICrossDomainMessenger } from "@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol"; contract GreeterL1 { address crossDomainMessengerAddr = 0x5086d1eEF304eb5284A0f6720f79403b4e9bE294; address greeterL2Addr = 0xC0836cCc8FBa87637e782Dde6e6572aD624fb984; function setGreeting(string calldata _greeting) public { bytes memory message; message = abi.encodeWithSignature("setGreeting(string)", _greeting); ICrossDomainMessenger(crossDomainMessengerAddr).sendMessage( greeterL2Addr, message, 1000000 // within the free gas limit amount ); } // function setGreeting } // contract GreeterL1 移行 は、上記のコントラクトを使用して、Ethereum から Optimism にメッセージを送信します。 migrations/3_set_L2_greeting.js var Greeter = artifacts.require("GreeterL1"); /** * Set L2 Greeting * Run this migration on L1 to update the L1 greeting. */ module.exports = async function (deployer) { console.log("Updating the L2 Greetings contract from L1! 👋👋"); const instance = await Greeter.deployed(); const tx = await instance.setGreeting("👋 Greetings from Truffle!"); console.log(`🙌 Greeter txn confirmed on L1! ${tx.receipt.transactionHash}`); console.log(`🛣️ Bridging message to L2 Greeter contract...`); console.log( `🕐 In about 1 minute, check the Greeter contract "read" function: https://goerli-optimism.etherscan.io/address/0xC0836cCc8FBa87637e782Dde6e6572aD624fb984#readContract` ); }; 次に、 コントラクトは、Optimism ブリッジを介して反対方向 (L2->L1) にメッセージを送信します。 contracts/optimism/GreeterL2.sol //SPDX-License-Identifier: Unlicense // This contract runs on L2, and controls a Greeter on L1. pragma solidity ^0.8.0; import { ICrossDomainMessenger } from "@eth-optimism/contracts/libraries/bridge/ICrossDomainMessenger.sol"; contract GreeterL2 { address crossDomainMessengerAddr = 0x4200000000000000000000000000000000000007; address greeterL1Addr = 0x7fA4D972bB15B71358da2D937E4A830A9084cf2e; function setGreeting(string calldata _greeting) public { bytes memory message; message = abi.encodeWithSignature("setGreeting(string)", _greeting); ICrossDomainMessenger(crossDomainMessengerAddr).sendMessage( greeterL1Addr, message, 1000000 // irrelevant here ); } // function setGreeting } // contract GreeterL2 移行 は、上記のコントラクトを使用して、Optimism から Ethereum にメッセージを送信します。 migrations/4_set_L1_greeting.js require("dotenv").config(); const sdk = require("@eth-optimism/sdk"); const ethers = require("ethers"); const Greeter = artifacts.require("GreeterL2"); const goerliMnemonic = process.env["GOERLI_MNEMONIC"]; const infuraKey = process.env["INFURA_KEY"]; const sleep = (milliseconds) => { return new Promise((resolve) => setTimeout(resolve, milliseconds)); }; /** * Set L1 Greeting * Run this migration on L1 to update the L1 greeting. */ module.exports = async function (deployer) { const newGreeting = "👋 Greetings from Truffle!"; //<---- CHANGE THIS VALUE TO YOUR NAME!!! const instance = await Greeter.deployed(); console.log("Updating the L1 Greetings contract from L2! 👋"); const tx = await instance.setGreeting(newGreeting); const txHash = tx.receipt.transactionHash; console.log(`🙌🙌 Greeter txn confirmed on L2! ${txHash}`); console.log( `🛣️ Bridging message to L1 Greeter contract.\n 🕐 This will take at least 1-5 min...` ); // Set providers for Optimism sdk const l1Provider = new ethers.providers.JsonRpcProvider( "https://goerli.infura.io/v3/" + infuraKey ); const l2Provider = new ethers.providers.JsonRpcProvider( "https://optimism-goerli.infura.io/v3/" + infuraKey ); // Connect an L1 signer const wallet = ethers.Wallet.fromMnemonic(goerliMnemonic); const l1Signer = wallet.connect(l1Provider); // Initialize sdk messenger const crossChainMessenger = new sdk.CrossChainMessenger({ l1ChainId: 5, l2ChainId: 420, l1SignerOrProvider: l1Signer, l2SignerOrProvider: l2Provider, }); let statusReady = false; // Sleep for 1 min during L2 -> L1 bridging await sleep(60000); // 60 seconds // Poll the L1 msg status while (!statusReady) { let status = null; status = await crossChainMessenger.getMessageStatus(txHash); statusReady = status == sdk.MessageStatus.READY_FOR_RELAY; if (!statusReady) { console.log( "Message not yet received on L1.\n 🕐 Retrying in 10 seconds..." ); await sleep(10000); // 10 seconds } } console.log("📬 Message received! Finalizing..."); // Open the message on L1 finalize = await crossChainMessenger.finalizeMessage(txHash); console.log( `🎉 Message finalized. Check the L1 Greeter contract "read" function: https://goerli.etherscan.io/address/0x7fA4D972bB15B71358da2D937E4A830A9084cf2e#readContract` ); }; scripts ディレクトリには、 と もあり、コントラクトのコンパイル、移行の実行、およびメッセージの送信のプロセスを自動化します。 goerli_bridge_message.mjs goerli_bridge_value.js ステップ 4 — Ethereum Goerli と Optimism Goerli の間のコントラクトの完全なコンパイル、移行、ブリッジング 次に、実際にコントラクトを Goerli にデプロイします。ヘルパー は、Ethereum Goerli と Optimism Goerli の間のメッセージのコンパイル、移行、ブリッジングを容易にします。 スクリプト これらのネットワークでは、テストネット ETH を使用する必要があります。一部を受け取るには を使用します。 必要もあります。 、蛇口 Optimism アドオンを Infura アカウントに追加する 次に、次のコマンドを実行してプロジェクトを開始します。 npm run deploy 以下は、移行が完了した後にブリッジされたメッセージを (Etherscan 経由で) 確認するための URL です。 4 回目の移行が完了すると、Etherscan を介してブリッジされたメッセージを確認するためのリンクが提供されます。 ステップ 5 — Block Explore を使用して Goerli テストネットでプロジェクトが正常に動作することを確認する 以前に箱から出したプロジェクトのセットアップ、インストール、ビルド、デプロイ、およびウォークスルーに成功しました。次に、Goerli Ethereum テストネットでプロジェクトを検証します。 ブロック エクスプローラーに移動し、展開時に CLI に表示された txn アドレス 0xbcc1746a9ebbfcfb71665225c1a353a8c8dc9a1aa528a3babcb5b046d615a353 を貼り付けます。 Goerli Etherscan https://goerli-optimism.etherscan.io/tx/0xbcc1746a9ebbfcfb71665225c1a353a8c8dc9a1aa528a3babcb5b046d615a353 結論 ユーザーと開発者のエクスペリエンスを改善し続けるには、マルチチェーンの web3 ワールドが不可欠です。そしてそれを達成するには、dapps がチェーン間で迅速かつシームレスに通信する方法が必要です。 Optimism Bridge Truffle Box を使用して説明した例で、比較的簡単かつ迅速に開始する方法を示していただければ幸いです。詳細について をご覧ください。 は、公式ドキュメント 本当に素晴らしい一日を!