![見出し画像](https://assets.st-note.com/production/uploads/images/113480433/rectangle_large_type_2_2ed77834383048e91f72b94d704c4c70.png?width=800)
【完全保存版】ChainlinkのCCIPで異なるチェーンにメッセージを送ろう!
0 はじめに
今回は、「Chainlink」の「CCIP」を使い、「Sepolia」チェーンから「Mumbai」チェーンに「Hello World」などのメッセージを送ってみます。
そのため、事前に「Sepolia」、「Mumbai」のテストトークンの取得をお願いします。
・Sepolia
・Mumbai
https://faucet.polygon.technology/
また、「CCIP」では、「LINK」のテストトークンも必要なので、下から取得します。
下のように、ウォレットアドレスを貼り付けて、チェックをし、「Send me 20 testnet LINK」を選択します。
![](https://assets.st-note.com/img/1691821015038-wRf9KabIyX.png?width=800)
1 「Sepolia」から「Mumbai」にメッセージを送ろう
1 はじめに
本日は、ChainlinkのCCIP(Cross-Chain Interoperability Protocol)のデモを行います。
「Sepolia」というチェーンから「Mumbai」というチェーンにメッセージを送付します。
![](https://assets.st-note.com/img/1691815134925-qNAp5grqJn.png?width=800)
そして、下の青い部分に囲まれたところが「CCIP」です。
私たちが意識しなくて良い部分ですが、その仕組みも詳しく公式に書かれております。
![](https://assets.st-note.com/img/1691815215905-135OPYe6oX.png?width=800)
2 送り元コントラクトの作成について(Sepolia)
では、まずは送り元のコントラクトを作ってみましょう。
「Deploy the sender contract」の「Open in Remix」を選択します。
![](https://assets.st-note.com/img/1691816542972-lB5s8uJTTf.png?width=800)
「Home」のファイルが開かれるため、「Sender.sol」のファイルを開きます。
![](https://assets.st-note.com/img/1691816566069-35v6RXMy28.png?width=800)
下のように、コードが書かれているのが、確認できます。
しかし、エラーが出ているようです。
![](https://assets.st-note.com/img/1691813938492-lh8UyErSbA.png?width=800)
確認すると、コンパイラのバージョンが異なると出ています。
![](https://assets.st-note.com/img/1691813998936-ESTadeCIp8.png?width=800)
下の場所でコンパイルのバージョンを確認すると、確かに違うことが確認できます。
![](https://assets.st-note.com/img/1691814030919-PM0LbnVvRr.png?width=800)
こちらを選択して、「0.8.19」のバージョンに変更します。
![](https://assets.st-note.com/img/1691819954968-ivXM010tZZ.png?width=800)
すると、エラーが消えました。
では、下から、コンパイルを行います。
![](https://assets.st-note.com/img/1691814102447-U9XBWM7gmz.png?width=800)
次に、デプロイを行います。
「ENVIRONMENT」を下のように、「Injected Provider」に変更します。
「Sepolia」のチェーンIDである、「11155111」であることを確認し、下のボタンを押します。
![](https://assets.st-note.com/img/1691814199356-BCMQpoUzW5.png?width=800)
ここで、「ルーター」と「LINKトークン」のコントラクトアドレスを設定します。
「LINK」トークンは今回、ガス代として使用します。
![](https://assets.st-note.com/img/1691814256580-yH0OvX3yD9.png?width=800)
なお、アドレスはこちらの部分に記載があります。
![](https://assets.st-note.com/img/1691820294273-tiLOEsPdQ5.png?width=800)
その他、各チェーンでの「LINKトークン」コントラクトアドレスの一覧はこちらにあります。
![](https://assets.st-note.com/img/1691820376744-onYICKLDj8.png?width=800)
ちなみに、「ルーター」は、下の、左下の部分を設定していました。
![](https://assets.st-note.com/img/1691815263282-qMs694yl3p.png?width=800)
ちなみに、チェーンごとのCCIPの一覧は下のように確認することができます。
![](https://assets.st-note.com/img/1691820652785-yFm9HV5abz.png?width=800)
では、戻ります。
下のように、デプロイが完了しました。
次に、このコントラクトアドレスに「LINK」トークンを送付するために、アドレスをコピーします。
![](https://assets.st-note.com/img/1691814306328-o8TBz2J8vM.png?width=800)
メタマスクなどで、LINKトークンを送付します。
下は、「0.1LINK」ですが、もしかすると、足りないかもしれません。
![](https://assets.st-note.com/img/1691814352811-MPP7W9sKJU.png?width=800)
3 送り先コントラクトの作成について(Mumbai)
次に、「Deploy the receiver contract」から「Open in Remix」を選択します。
![](https://assets.st-note.com/img/1691821167132-R3GSK9roAr.png?width=800)
「Receiver.sol」ファイルを選択すると、このように、コードが記載されています。
![](https://assets.st-note.com/img/1691821209301-VuzE6iK7zD.png?width=800)
下のように、コンパイルを行います。
![](https://assets.st-note.com/img/1691821393100-loVFwb2CP1.png?width=800)
次に、デプロイを行います。
「mumbai」なので、メタマスクでチェーンを切り替え、チェーンIDが「80001」になっていることを確認します。
![](https://assets.st-note.com/img/1691814440612-eRYMYjVvuz.png?width=800)
こちらで、ルーターのコントラクトアドレスを設定します。
ちなみに、下の画像は「"0x7049…」のように、「"」が誤って入ってしまっていましたね。
最終的にこれはエラーになりました。「0x7049…」から入れるのが正しいです。
![](https://assets.st-note.com/img/1691814502091-JdvE40dbmq.png?width=800)
ちなみに、こちらが、今回設定するルーターのコントラクトアドレスです。
![](https://assets.st-note.com/img/1691821643088-yEBlwKPLhz.png?width=800)
もしくは、こちらの一覧から取得しても良いと思います。
![](https://assets.st-note.com/img/1691821734195-hQxD1wxHQg.png?width=800)
なお、今回設定したのは、下の右側のルーターです。
![](https://assets.st-note.com/img/1691815314686-7sqPHc1rhp.png?width=800)
ルーターを設定し、「mumbai」で下のようにデプロイしました。
4 メッセージを送ってみよう
では、こちらのコントラクトアドレスをコピーして、「Sender」コントラクトからメッセージを送ってみます。
![](https://assets.st-note.com/img/1691814543672-StBYn2KRmS.png?width=800)
では「Sepolia」の「Sender」コントラクトに戻ります。
メタマスクで、チェーンを「Sepolia」へ変更するのを忘れずに設定してください。
「sendMessage」の下の矢印を選択します。
![](https://assets.st-note.com/img/1691814626785-XjPhyUvWoO.png?width=800)
ここから、「mumbai」の「Receive」コントラクトにメッセージを送ります。
そのため、「mumbai」の宛先と「コントラクトアドレス」、「送るメッセージ」を入力します。
![](https://assets.st-note.com/img/1691814662312-P8yUaLl6fi.png?width=800)
「destinationChainSelector」には、こちらの「Mumbai」の「Chain Selector」を設定します。
また、「receive」には、先ほど「mumbai」で作ったコントラクトアドレスを貼り付けます。
できたら、「transact」を実行します。
![](https://assets.st-note.com/img/1691822131057-mn28lF1HD4.png?width=800)
これで、下のように、トランザクションが実行できました。
![](https://assets.st-note.com/img/1691814718376-GnJZontZ1l.png?width=800)
5 エクスプローラーで確認しよう
確認すると、下のように、「transaction hash」があるので、こちらをコピーします。
![](https://assets.st-note.com/img/1691814749076-KgJpuWPMAf.png?width=800)
こちらをCCIPエクスプローラーで確認します。
すると、下のように、「Waiting for finality」とファイナリティ待ちである旨が表示されます。
![](https://assets.st-note.com/img/1691814818339-s7X1KOMad1.png?width=800)
メタマスクで、チェーンを「mumbai」に変更し、「Receiver」コントラクトの「getLastReceivedMessageDetails」を確認すると、今は下のようになります。
![](https://assets.st-note.com/img/1691814861654-iuMdNjl8Hq.png?width=800)
そして、しばらく待つと、エクスプローラーのステータスが「Success」になります。
私の場合は、10分以上かかりました。
![](https://assets.st-note.com/img/1691814996431-pRAZAY2qdY.png?width=800)
6 メッセージを確認しよう
再び、関数を実行すると、下のように、メッセージが届いていることが確認できました。
![](https://assets.st-note.com/img/1691814969847-XZKuCaeu0a.png?width=800)
2 コードを見てみよう(「Sender」コントラクト)
では、「Sender」コントラクトの中身を見てみましょう。
1 errorとイベント
まずは、下のように残高不足の際の「error」とメッセージの送付が完了した時のイベントを書いています。
![](https://assets.st-note.com/img/1691822857270-BsBv1etQEY.png?width=800)
2 ルーターとトークンの初期化
次に、下のように、「IRouterClient」「LinkTokenInterface」のインターフェースを取得して、初期化をおこなっています。
![](https://assets.st-note.com/img/1691822957531-wLWmiaTLLl.png?width=800)
これでルーターとリンクトークンの初期化ができました。
![](https://assets.st-note.com/img/1692138694866-sWo4E1l3tp.png?width=800)
3 sendMessage関数について
次に、こちらの「sendMessage」関数を見てみましょう。
![](https://assets.st-note.com/img/1691823010615-X9uVmjrp7a.png?width=800)
4 メッセージの作成
まず、大まかに、下の部分で、メッセージを作成しています。
![](https://assets.st-note.com/img/1691823094638-KS1wAQUpAp.png?width=800)
具体的には、メッセージとして、こちらの「Client」ライブラリにある、「EVM2AnyMessage」という構造体を作っています。
![](https://assets.st-note.com/img/1691823172940-YXQ1eZn9m2.png?width=800)
下のように、受取人(receiver)やテキスト(data)、手数料のトークン(feeToken)を設定しています。
それぞれ、abi.encodeでエンコードしています。
![](https://assets.st-note.com/img/1691823274292-Jf35tdarPk.png?width=800)
こちらの「tokenAmounts」も見てみましょう。
(ただ、今回はトークンを送るわけではないので、配列のサイズは「0」になっています。)
![](https://assets.st-note.com/img/1691823298973-bZCGVsTAxi.png?width=800)
ちなみに、下のように、構成としては、トークンアドレスと送る量になっていました。
つまり、異なるトークンを同時に送ることができそうだと思いました。(ここは細かく見ていないので、想像です。)
![](https://assets.st-note.com/img/1691823385722-qYlEjRix72.png?width=800)
さらに下の部分では、追加の引数(extraArgs)を設定しています。
![](https://assets.st-note.com/img/1691823608541-fb9cCTwe1O.png?width=800)
具体的には、「gasLimit」と厳格にするか否かを「EVMExtraArgsV1」で設定しています。
そちらに、「CCIP EVMExtraArgsV1」を「keccak256」でハッシュ化した先頭の4バイト(0x97a657c9)をくっつけて、エンコードしています。
![](https://assets.st-note.com/img/1691823709926-r5krEB21Gx.png?width=800)
5 手数料の取得
そして、「IRouterClient」インターフェースにある、「getFee」関数で手数料を取得しています。
![](https://assets.st-note.com/img/1691823784171-7cqmw2pNBI.png?width=800)
こちらですね。
![](https://assets.st-note.com/img/1691823862469-p9wO0KEbWK.png?width=800)
6 残高の確認
手数料を取得したので、残高上、問題ないかを確認しています。
![](https://assets.st-note.com/img/1691823880408-0wwWB1sI5D.png?width=800)
「balanceOf」はこのように、「LinkTokenInterface」にあります。
![](https://assets.st-note.com/img/1691823956612-IiHbXAwcpa.png?width=800)
7 手数料のapprove
次に、「approve」を使い、ルーターコントラクトに手数料の送付権限を与えています。
これにより、コントラクトが持っている「LINK」トークンのうちの手数料をルーターコントラクトが送れるようになります。
![](https://assets.st-note.com/img/1691823981828-NzEx3zuoQc.png?width=800)
ちなみに、「approve」はこちらです。
![](https://assets.st-note.com/img/1691824002109-aGZXWpmrd9.png?width=800)
8 ccipSend関数について
そして、下の部分で、「ccipSend」を用いて、メッセージを送付し、「メッセージID」を取得しています。
![](https://assets.st-note.com/img/1691824021228-Ezfd3mMwPz.png?width=800)
具体的には、下のように、目的先のチェーンのセレクタとメッセージを渡しています。
![](https://assets.st-note.com/img/1691824126609-QOPDRXDlnh.png?width=800)
9 イベントの実行
それが終われば、「MessageSent」イベントを発火しています。
![](https://assets.st-note.com/img/1691824159730-oM2SN7DfHh.png?width=800)
10 メッセージIDの取得
そして、最後に「メッセージID」を返しています。
![](https://assets.st-note.com/img/1691824303978-l6CbpuW9Sx.png?width=800)
3 コードを見てみよう(「Receiver」コントラクト)
次に、「Receiver」コントラクトを見てみましょう。
![](https://assets.st-note.com/img/1692141207633-Tmqmb2bKY6.png?width=800)
1 ルーターの設定
まずは、「constructor」でルーターを設定しています。
![](https://assets.st-note.com/img/1692141228749-WWMYRq3ucx.png?width=800)
こちらになります。
![](https://assets.st-note.com/img/1692141839755-xLimyWAaPF.png?width=800)
2 _ccipReceive関数について
続いて、メッセージを受け取っているのが、こちらの「_ccipReceive」関数になります。
![](https://assets.st-note.com/img/1692141251415-43AnZkvAVj.png?width=800)
3 メッセージIDの取得
下のようにして、メッセージIDを取得しています。
なお、メッセージID、テキスト共に、受け取ったら上書きをしているようです。
![](https://assets.st-note.com/img/1692141289403-iYG6aaZ0hz.png?width=800)
具体的には、「Client」ライブラリの「Any2EVMMessage」の構造体の、こちらの「messageId」を取得しています。
![](https://assets.st-note.com/img/1692141395211-oAQ0VAy7Dp.png?width=800)
4 テキストの取得
テキストも同様ですが、下のように、受け取ったものをstringにデコードして、格納しています。
![](https://assets.st-note.com/img/1692141481551-rmE0MItf2B.png?width=800)
メッセージIDと同様に、「Any2EVMMessage」構造体の「data」を取得していました。
![](https://assets.st-note.com/img/1692141602729-fwsjdYVqci.png?width=800)
5 イベントの実行
そして、最後に受け取った旨の「MessageReceived」イベントを発火しています。
![](https://assets.st-note.com/img/1692141674662-wGpPzMXa1E.png?width=800)
今回は以上です。
サポートをしていただけたらすごく嬉しいです😄 いただけたサポートを励みに、これからもコツコツ頑張っていきます😊