今回は2つのBlockchainでTokenなどをやりとりするときのBridgeについて、その仕組みやサービスなどについてまとめていきます。
Bridgeの仕組みなどを説明する前に、事前に知っておくとBridgeの理解が深まることについてまとめていきます。
まずは「Cross Chain」です。Cross Chainとは、異なるブロックチェーン間でデータやトークンをtransferできる技術のことです。
通常、Dappsを複数のブロックチェーンに対応させる場合、ブロックチェーンごとにDappsをデプロイする必要があります。しかし、Cross Chainの仕組みを使用することで、1つのDapps上で複数のブロックチェーンとやり取りできるようになります。
「Multi Chain」とは、ブロックチェーンごとに独立したDappsをデプロイし、複数のブロックチェーンが共存しているエコシステムのことです。
複数ブロックチェーンの使用ができることで、ユーザーが使い慣れているブロックチェーン上でアプリケーションを提供することができるようになります。
「Cross Chain」と「Multi Chain」は似ているため違いについて説明します。
Cross Chain
Multi Chain
同じDappsが複数の異なるブロックチェーン上にデプロイされています。
Dapps間に接続はなくそれぞれが独立して動作しています。
各ブロックチェーンには、ETHやBTC、POLなどのネイティブトークンが存在します。ただ、このネイティブトークンは他ブロックチェーンに送ることができません。一方、ERC20トークンなどであれば、複数のブロックチェーンにコントラクトをデプロイすることでブロックチェーンを跨ぐことが可能です。
そこで、ネイティブトークンをERC20トークンでラップしたものが「Wrapped Token」です。Etheruem上のWETHトークン、Polygon上のWETHトークンなどを作成することで、ネイティブトークンを他チェーンにtransferできるようになります。
「Oracle(オラクル)」とは、外部情報をブロックチェーンに提供する仕組みです。
例えば、コントラクトではブロックチェーン上の情報にアクセスはできますが、例えば気象情報や資産価格、市場データなどにアクセスすることはできません。つまり、ブロックチェーン外の情報にアクセスすることができません。
Oracleはブロックチェーン外の情報を収集してブロックチェーン上で扱える仕組みを提供しています。
流動性プールと呼ばれる、特定のトークンペア(例: ETH/USDC)の資産を1つの場所に集めて自由に取引できる場所を提供する仕組み。主にDEX・DeFiなどで使用され、ユーザー同士が取引できます。
フローで説明すると以下になります。
流動性提供者(LP)がトークンをプールに預ける。
流動性提供者がETHとUSDCなどのトークンペアを流動性プールに預ける。通常、同じ価値の2つのトークンを50:50の割合で預けます。
LPトークンの発行
流動性プール内の自分のシェアを証明するトークンである、「LPトークン」を流動性提供者は受け取る。
ユーザーがトークンを交換
他のユーザーが流動性プールを使って取引を実行。
AMMによる価格調整
自動マーケットメイカー(AMM)が、プール内のトークン量に基づいて特定の計算式から価格を自動的に調整します。より詳しくは以下の記事を参考にしてください。
取引手数料の分配
取引が発生した時の手数料はプールに加算され、LPは手数料の一部を自身のシェアに応じて受け取ります。
流動性提供者がトークンを引き出す
流動性提供者が預けたトークンを引き出す時、受け取ったLPトークンを使用して自分のシェアに応じて資産を引き出せます。取引手数料も含まれているため、通常預けた時よりも多くの資産を受け取れるはずですが、インパーマネントロス(IL)などにより損失が発生する可能性もあります。
AMMについてより詳しくは以下の記事を参考にしてください。
前提知識を確認してきたところで、早速Bridgeについて見ていきましょう。まずは、Bridgeについて理解していきます。
ブロックチェーンにおける「Bridge」とは、異なるブロックチェーン間でトークンや資産を移動させたり、メッセージのやり取りを行う仕組みです。
通常、EthereumやSolana、Polygonなどの各ブロックチェーンは独立していて連携することはありません。Bridgeはこのブロックチェーン同士でやり取りを可能にする仕組みです。
Bridgeを行うためにもいくつか方法があります。
この方法は、複数のブロックチェーンでトークンの総供給量を常に一定に保つ方式です。
ブロックチェーンAでERC20トークンなどを取得して、そのトークンをブロックチェーンBに送りたい時以下の処理を実行します。
ブロックチェーンA上のBridgeコントラクトにERC20トークンを送付。
ブロックチェーンAのBridgeコントラクトでERC20トークンをBurn。
ブロックチェーンAでトークンがBurnされたことをOracleが確認してブロックチェーンBに伝達。
ブロックチェーンBのBridgeコントラクトでBurnされたトークンと同量(1:1の価値を持つ)のトークンをMint。
ブロックチェーンBのBridgeコントラクトでMintされたトークンをユーザーに送付。
この手順により、ブロックチェーンAとブロックチェーンBでトークンの総供給量が常に一定になります。
例)10トークンをMint(チェーンA)。
Bridgeコントラクトに10トークンを送付(Ethereum)。
Bridgeコントラクトで10トークンをBurn(Ethereum)。
EthereumでトークンがBurnされたことをOracleが確認してPolygonに伝達。
Bridgeコントラクトで10トークンをMint(Polygon)。
Bridgeコントラクトから10トークンをユーザーに送付(Polygon)。
この方法は、ブロックチェーンごとにトークンの総供給量を常に一定に保つ方式です。
ブロックチェーンAでERC20トークンなどを取得して、そのトークンをブロックチェーンBに送りたい時以下の処理を実行します。
ブロックチェーンAのBridgeコントラクトにERC20トークンを送付。
ブロックチェーンAのBridgeコントラクトでERC20トークンをLockして他に移動できなくする。
ブロックチェーンAでトークンがLockされたことをOracleが確認してブロックチェーンBに伝達。
ブロックチェーンBのBridgeコントラクトでLockされたトークンと同量(1:1の価値を持つ)のトークンをMint。
ブロックチェーンBのBridgeコントラクトでMintされたトークンをユーザーに送付。
この手順により、ブロックチェーンAとブロックチェーンBのそれぞれチェーンでトークンの総供給量が一定になります。
例)10トークンをMint(Ethereum)。
Bridgeコントラクトに10トークンを送付(Ethereum)。
Bridgeコントラクトで10トークンをLock(Ethereum)。
EthereumでトークンがLockされたことをOracleが確認してPolygonに伝達。
Bridgeコントラクトで10トークンをMint(Polygon)。
Bridgeコントラクトから10トークンをユーザーに送付(Polygon)。
流動性プール(Liquidity Pool)を使用してトークンを別のチェーンのトークンに変換する仕組みです。
ブロックチェーンAとブロックチェーンBでLP(Liquidity Provider)がERC20トークンをLiquidity Poolに預けます。その後、トークンをBridgeしたいユーザーが片方のチェーンにトークンを預け入れ、もう片方のチェーンでトークンを受け取っています。
ブロックチェーンAのLiquidity Poolに、ユーザーA(LP)がブロックチェーンA上のトークンAを預け入れる。
ブロックチェーンBのLiquidity Poolに、ユーザーB(LP)がブロックチェーンB上のトークンAを預け入れる。
ユーザーCがブロックチェーンA上でトークンAをLiquidity Poolに預け入れる。
オラクルがトークンAの預け入れを検知して、ブロックチェーンB上のLiquidity PoolからユーザーCに預け入れたトークンAと同量(1:1の価値を持つ)のトークンAをユーザーに送付。
この手順により、異なるブロックチェーン上でトークンを交換することができます。
例)10トークンA(Ethereum)をBridge。
ユーザーAがLiquidity PoolにトークンAを10トークン預け入れる(Ethereum)。
ユーザーBがLiquidity PoolにトークンAを20トークン預け入れる(Polygon)。
ユーザーCがブロックチェーンA上でトークンAを5トークンLiquidity Poolに預け入れる(Ethereum)。
オラクルが預け入れを検知して、トークンAをユーザーCに送付(Polygon)
また、この時2つのトークンをSwapしつつBridgeするパターンもあります。
*いろんなパターンがあるため、一概に上記の流れとは限りません。
ブロックチェーンAとブロックチェーンBでLP(Liquidity Provider)がERC20トークンであるトークンAとトークンBをLiquidity Poolに預けます。その後、トークンをBridgeしたいユーザーが片方のチェーンにトークンAを預け入れ、もう片方のチェーンでトークンBを受け取っています。
ブロックチェーンAのLiquidity Poolに、ユーザーA(LP)がブロックチェーンA上のトークンAとトークンBを預け入れてLP Tokenを受け取る。
ブロックチェーンBのLiquidity Poolに、ユーザーB(LP)がブロックチェーンA上のトークンAとトークンBを預け入れてLP Tokenを受け取る。
ユーザーCがブロックチェーンA上でトークンAをLiquidity Poolに預け入れる。
Liquidity Poolに預け入れられた時にWrapしたトークンが発行される。
オラクルがトークンAの預け入れを検知して、WrapしたトークンをBurn。
その後、ブロックチェーンB上のLiquidity PoolでWrapしたトークンをUnWrapして、ユーザーCに預け入れたトークンAと同量(1:1の価値を持つ)のトークンBをユーザーに送付。
この手順により、異なるブロックチェーン上でトークンを交換することができます。
例)10トークンA(Ethereum)をトークンB(Polygon)にBridge。
ユーザーAがLiquidity PoolにトークンAを10トークン、トークンBを10トークン預け入れてLP Tokenを受け取る(Ethereum)。
ユーザーBがLiquidity PoolにトークンAを10トークン、トークンBを20トークン預け入れてLP Tokenを受け取る(Polygon)。
ユーザーCがトークンAを5トークンLiquidity Poolに預け入れてWrap(Ethereum)。
オラクルがトークンAの預け入れを検知して、WrapしたトークンをBurn(Ethereum)。
Wrapしたトークンと同量のトークンをMintしてUnWrap(Polygon)。
UnWrapしたトークンをユーザーCに6.67トークンBをユーザーに送付(Polygon)。
この部分はLiquidity Pool内のトークンペア比率やロジックによって変わってきます。この例ではAMMを例に用いています。
トークンA(x)
トークンB(y)
ユーザーCが5トークンAを預け入れた時、新しいトークンAの量は、トークンAとなります。AMMでは以下のような計算をします。
プールにあるトークンBの量が減少し、トークンBの残量は約13.33トークンとなり、元々プールにあったトークンBの量は20トークンなのでその差がユーザーCが受け取るトークンBの量になります。
Layer Zeroは代表的なBridgeプロトコルです。複数のブロックチェーンをサポートしていて、分散型で2つのブロックチェーンでメッセージを送受信したり、ERC20やERC721などのトークンを行き来できます。
Layer Zeroの仕組みは上図にまとめられています。(この図ではメッセージのやり取りをもとに説明されています)
ユーザーは送信元のブロックチェーン上のOAPPコントラクト内で、以下の情報をもとにlzSend
メソッドを呼び出します。
送信メッセージや送信トークン
宛先LayerZeroエンドポイント
宛先OAppアドレス
オプションデータ
lzSend
メソッドは、送信元ブロックチェーンから宛先ブロックチェーンに指定されたメッセージやトークンを送信するトリガーです。
Sender OAppからのメッセージデータに基づいてパケットを生成します。このパケットには、それぞれ固有の連続番号(nonce
)が割り当てられ、メッセージの一意性と順序を保つために使用されます。
LayerZero Endpointは、OAppのowner
が指定したMessageLib
ライブラリを使用して、先ほど生成したパケットをエンコードします。MessageLib
は、メッセージをエンコードして指定されたセキュリティスタック(DVNs)とExecutorに転送し、送信処理を完了します。送信が完了すると、PacketSent
イベントが発行され、パケットの送信が完了したことがブロックチェーン上で記録されます。
Message Library(MessageLib
)は、OAppのowner
が設定する不変の検証ライブラリで、メッセージの送信と受信時にOAppの設定に基づいた厳密な制御を提供します。
MessageLib
は、送信エンドポイントからメッセージを受け取り、OApp構成に基づいてメッセージパケットの生成します。また、送信エンドポイントからメッセージを送信する時、指定されたセキュリティスタック(DVNs)とExecutorに送信することを保証します。
MessageLibは、宛先チェーン上でセキュリティスタック(DVNs)がメッセージパケットを検証したことを確認し、その後Executorがエンドポイントのメッセージチャネルにパケットハッシュをコミットできるようにします。
DVNs(分散検証ネットワーク)は、OAppによって設定された検証手法を使用してメッセージを検証します。宛先チェーンのMessageLib
は、OAppによって設定された特定のDVNsのみが検証を提出できるように制御しています。各DVNsは、検証の過程で送信されたメッセージが不正に改ざんされていないかを確認します。
Security Stackは、OAppでのメッセージ検証プロセスを強化するために、複数の分散検証ネットワーク(DVN: Decentralized Verifier Networks)を組み合わせて設定し、メッセージの整合性と安全性を確保します。
各OAppは、メッセージ整合性を確認するために、複数ののDVNs(「必須」or「任意」)を使用してSecurity Stackを構成します。任意のDVNsは、メッセージnonce
が検証済みと見なされるために必要な検証数の閾値を指定できます。
各DVNは、独自の検証方式を使用してメッセージのpayloadHash
の整合性を確認し、宛先チェーンのMessageLib
に対してその結果を検証します。
必須であるDVNと指定された閾値を超えた任意のDVNがpayloadHash
に同意すると、そのメッセージnonce
は宛先エンドポイントのメッセージチャネルにコミットされ、Executorなどの呼び出し元によって実行されます。
以下のようにメッセージnonceの状態を管理しています。
Nonce 1
payloadHash
を検証済みであり、nonce
がエンドポイントのメッセージチャネルにコミットされている。Nonce 2
payloadHash
を検証済みですが、まだnonce
はコミットされていない。Nonce 3
payloadHash
を検証しており、セキュリティ閾値に達しているが、nonce
はまだコミットされていない。Nonce 4
payloadHash
を検証するまでnonce
をコミットしない。Nonce 5
payloadHash
を検証しているが、任意DVNはまだ検証していない。Nonce 6
payloadHash
を検証済みだが、nonce
はまだコミットされていない。各DVNは、メッセージのpayloadHash
を確認するための独自の検証モデルを提供していて、OAppのowner
は、セキュリティやコスト効率のニーズに応じて最適なモデルを選択できます。また、DVNアダプターを使用することで、サードパーティのネットワーク(例: ネイティブアセットブリッジ、中間チェーンなど)やその他の検証方法をOAppのセキュリティスタックに統合できます。
OAppのセキュリティスタックに含まれる全てのDVNsによるメッセージの検証が完了すると、宛先チェーンのMessageLib
は、そのメッセージを「検証可能」としてマークし、宛先チェーン側でメッセージを処理できるようになります。
パケットの検証結果をエンドポイントにコミットし、宛先チェーンでの実行段階に進みます。
宛先エンドポイントでは、Executorによって配信されたパケットがDVNsによって検証されたメッセージと一致することを確認します
宛先チェーンのReceiver OAppのロジックに基づいて、コミットされたメッセージを処理するためにlzReceive
関数を呼び出します。
Executorsは、LayerZeroを使用したクロスチェーンメッセージングにおいて、宛先チェーンでメッセージが正しく実行されるように自動的に処理を行います。OAppのowner
が設定した制御をもとに、セキュリティスタックによるメッセージのpayloadHash
検証後、宛先チェーンのエンドポイントコントラクトでlzReceive
関数を呼び出し、メッセージの配信処理を開始します。クロスチェーンでメッセージを追跡する時、送信チェーンと宛先チェーンの両方でトランザクションを確認する必要があり、Executorはこれを自動化しています。
Executorは、メッセージオプションを利用してさまざまな宛先トランザクションの処理方法を制御できます。
lzReceiveOption
lzReceive
メソッドを呼び出す時にガスやmsg.value
の設定を管理。lzComposeOption
lzCompose
メソッドを呼び出す時のガスとmsg.value
の設定を管理。lzNativeDropOption
lzOrderedExecutionOption
nonce
順に実行することを保証。Executorは以下のようにカスタマイズできます。
Custom Executor
Build Executor
No Executor Option
自動Executorを使用せず、ユーザーが宛先チェーンでlzReceive
を手動で呼び出すオプション。
この場合、LayerZero Scanやブロックエクスプローラーを使って手動でトランザクションを実行。
最終的にメッセージは宛先チェーンのReceiver OApp Contractによって受信され、メッセージに基づいて指定されたアクションが実行されてBridgeプロセスが完了します。
Chainlinkが提供しているChainlink Cross-Chain Interoperability Protocol (CCIP) も代表的なBridgeプロトコルで、ブロックチェーン間でのトークンやデータ(メッセージ)のやり取りを安全かつ効率的に行います。
CCIPの主要機能。
任意のメッセージング(Arbitrary Messaging)
任意のデータをバイト形式でエンコードし、別のブロックチェーン上のコントラクトに送信できます。
これにより、異なるチェーンで特定のアクションをトリガーすることが可能になります。
例えば、別のチェーン上のコントラクトでNFTのミントやデータの変更の指示を送ることができます。
トークン転送(Token Transfer)
transfer
できます。プログラム可能なトークン転送(Programmable Token Transfer)
トークンとデータの両方を同時に、1つのトランザクションで送ることができます。
例えば、トークンを貸し出しプロトコルに送信し、そのトークンを担保として活用する指示を同時に送るなどです。
Chainlink CCIPにおいて、あるブロックチェーン(ソースチェーン)から別のブロックチェーン(デスティネーションチェーン)への一方向の通信経路を指します。例えば、「Ethereum Mainnet => Polygon Mainnet」と「Polygon Mainnet => Ethereum Mainnet」は、異なる2つのレーンとして扱われます。
DONは、オフチェーンのデータを取得し、ブロックチェーンに送信する分散型のノードネットワークです。クロスチェーントランザクションを監視し、送信されたメッセージやトークンの整合性を確認する役割をです。
CCIPのレーンには以下の2種類のDONが機能します。
Committing DON
送信元チェーンを監視し、複数のトランザクションを1つに束ねてMerkleルートを生成。
生成されたMerkleルートは、受信先チェーンに送信。
Executing DON
各DONは、観測データを基にコンセンサスアルゴリズム(OCR2: Off-Chain Reporting)を使用して、送信するデータの合意に達します。合意されたデータが生成されると、署名されてブロックチェーンに送信されます。各ラウンドで全てのノードがデータを送信するのではなく、ラウンドロビン方式で1つのノードが送信を担当します。
ラウンドロビン方式とは、複数のタスクやプロセスを均等に分配して処理するためのスケジューリング方法の一つです。この方式では、各タスクに順番に等しい時間やリソースが割り当てられ、すべてのタスクが公平に扱われます。
例えば、3つのタスク(A、B、C)があるとすると、ラウンドロビン方式では、まずタスクAにリソースが割り当てられ、次にタスクB、次にタスクCというように、順番に繰り返し処理が進められます。これにより、1つのタスクが長時間にわたってリソースを独占することを防ぎ、すべてのタスクが公平に進行するようにします。
クロスチェーン通信の安全性を確保するための追加のセキュリティ層です。取引が正常に行われているかどうかを監視し、異常があれば自動的にシステムを停止させます。
オフチェーンモニタリング
オンチェーンのリスク管理コントラクト
CCIPでは、コミットメント(トランザクションを束ねて保存するプロセス)と実行を分離しています。これにより、RMNが十分な時間をかけてメッセージの正当性を確認でき、以下のメリットがあります。
再編成や攻撃のチェック
ガスコストの最適化
コミットメント(Merkleルート)を保存するコストはガスが安く済みますが、ユーザーのコールバック処理(Destinationチェーンでトランザクションを処理してユーザーアクションを完了させる)はガスコストが高くなる可能性があります。
コミットメントと実行を分けることで、ガスコストが高くなった場合でもガスコストの見積もりを債権さんして適切なガスを設定することにより、失敗した実行をユーザーが再試行することが可能になります。
以下の2つのモードで動作します。
祝福(Blessing)
リスク管理ノードは、送信元チェーンで生成されたメッセージのMerkleルートを監視します。
Merkleルートは、複数のメッセージのハッシュから作られるもので、取引の検証に使用されます。
メッセージが正しいと認定されることを「祝福(Blessing)」と呼びます。
呪い(Cursing)
リスク管理ノードが異常を検知した場合、そのメッセージやシステムに対して処理を一時停止させます。
リスク管理ノードがメッセージやシステムに異常を発見したされたことを「呪い(Cursing)」と呼びます。
CCIPがサポートする各チェーンには、リスク管理コントラクトが1つ存在します。このコントラクトは、特定のノード(リスク管理ノード)によって操作され、以下の5つの機能を持っています。
Cursingに対する投票用のアドレス
Blessingに対する投票用のアドレス
Cursingの投票を撤回するためのアドレス
Cursingの重み(curse weight)
Blessingの重み(blessing weight)
BlessingとCursingの仕組み
リスク管理コントラクトは、「Blessing」と「Cursing」の2つの主要な投票モードに基づいて動作します。これにより、ノードがメッセージの安全性を確認したり、異常があった場合にシステムを停止します。
Blessingは、あるメッセージが正しく送信され、問題がないことを確認する手順です。具体的には、各リスク管理ノードがMerkleルートを確認し、そのルートを祝福するかどうかを投票します。
各ノードがBlessingを投票するたびに、そのノードの「Blessingの重み」がリスク管理コントラクトに追加されます。Blessingのしきい値に達すると、そのMerkleルートは「Blessed」とみなされ、取引やメッセージは安全に処理されたことが確認されます。
Cursingは、メッセージに異常が検出された場合に行われる手順です。各リスク管理ノードは、Cursingの投票を行い、その時にランダムな32バイトのIDが付与されます。
ノードは複数のCursing投票を同時に持つことができますが、少なくとも1つのCursing投票がアクティブである限り、そのノードは「Cursingに投票した」とみなされます。Cursingのしきい値に達すると、システム全体が「Cursed」と見なされ、CCIPの処理が一時停止されます。
Cursing解除の手順
リスク管理コントラクトが「Cursing」状態になると、コントラクトのオーナーが問題を解決する必要があります。オーナーは、問題が解決したと判断した場合、リスク管理ノードに代わって「Cursing」を解除することができます。
ERC20トークンの操作を効率化するための抽象レイヤーで、OnRampやOffRampでトークンをやり取りする時に使用されます。このプールは、各トークンごとに1つずつ存在し、特定のLane(チェーン間の通信経路)でトークンを送付する時に転送速度の制限を設定するレートリミットを設定でき、トークン発行者が指定した制限内でトークンが安全にやり取りされることを保証します。SourceチェーンでトークンをLockやBurnしたり、その後DestinationチェーンでUnlockやMintを行いトークンを移動します。
Tooken Poolには4つの主要なメカニズムがあります。
Burn&Mint
Lock&Mint
Burn&Unlock
Lock&Unlock
以下はトークン例です。
LINKトークン
Ethereumメインネットでのみ発行されており、固定供給で他のチェーンで新たにMintできません。そのため、LINKをtransfer
する場合は、EthereumメインネットでトークンをLockし、DestinationチェーンでMintします。逆に、別のチェーンからEthereumメインネットに戻す時は、トークンをBurnしてEthereum上でUnlockします。
Wrap Token(WETHなど)
WETHのようなラップされた資産は、Lock&Unlockの仕組みを使用します。例えば、EthereumメインネットからOptimismメインネットに10WETH
をtransfer
する場合、Ethereum上で10WETH
をLockし、Optimism上で10WETH
をUnlockします。
Stable Coin(USDCなど)
USDCのようなステーブルコインは、複数のブロックチェーン上でネイティブに発行できます。そのため、Burn&Mintの仕組みを使用してSourceチェーンでBurnされ、Destinationチェーンで新たにMintされます。
Proof of Reserve(PoR)トークン
PoR(リザーブ証明)フィードを持つトークンは、特定のチェーン上でしかその証明が有効でないため、他のチェーンでBurn&Mintができない場合があります。これらのトークンには、代わりにLock&Mintが使用されることが多いです。
ネイティブトークン(ETH)のtransfer
ETHをWETHにラップ
まず、WETHコントラクトやDEXを利用してETHをWETHに変換。
WETHをCCIPで送信
その後、CCIPのルーターを介してWETHをDestinationチェーンに送付。
WETHをETHに戻す
最後に、DestinationチェーンでWETHをETHに戻す。
SourceチェーンとDestinationチェーン間でのクロスチェーントランザクションを監視して以下の処理をします。
OnRamp契約のイベントを監視
各ジョブは、Sourceチェーン上にあるOnRampコントラクトからのイベントを監視。
ファイナリティを待つ
トランザクションが確定するのを待ちます。ファイナリティとは、トランザクションが確定して取り消されないことをさす。
トランザクションを束ねてMerkleルートを生成
複数のトランザクションをまとめて、Merkleルートを作成。Merkleルートは、送信元のブロックチェーンで行われた全トランザクションの証明になる。
Merkleルートに署名しCommitStoreに保存
複数のオラクルノード(Chainlinkネットワークの参加者)がこのMerkleルートに署名し、署名されたMerkleルートをDestinationチェーンのCommitStoreに保存。CommitStoreは、このルートが正当なものであることを管理する場所。
Destinationチェーンでトランザクションを実行します。
OnRamp契約のイベントを監視
Committing DONと同様に、SourceチェーンのOnRampコントラクトからのイベントを監視。
CommitStoreのMerkleルートを確認
DestinationチェーンのCommitStoreに保存されたMerkleルートを確認し、トランザクションがそのルートに含まれているか確認。
リスク管理ネットワークによる承認を待つ
トランザクションを実行する前に、リスク管理ネットワークがそのメッセージを承認するまで待機。
Merkle証明を生成しOffRampに送信
Merkleルートが正当であることが確認されると、Executing DONはMerkle証明(トランザクションが正しいことを証明するデータ)を生成し、OffRampに送信してDestinationチェーンでトランザクションを完了させます。
Sender
Source Blockchain
Message
Receiver
Destination Blockchain
主要コンポーネント
Router
ユーザーはルーターにトークン送付やメッセージ送信をリクエストして、クロスチェーンでのやり取りが開始されます。
トークンの送付時には、Routerコントラクトにapprove
する必要があります。
リクエストを受け取った後、ソースチェーン上のOnRampへリクエストをルーティングします。
Destinationチェーンでは、メッセージやトークンがOffRamp経由でルーターに戻されて受信者に届けられます。
OnRamp
Sourceチェーンで動作するコントラクトで、Destinationチェーンへ送るメッセージやトークンを管理します。
アドレス形式の検証やメッセージサイズやガスリミットの確認、シーケンス番号の管理などを行います。
トークンが関与するリクエストの場合は、Token Poolを使ってトークンのLockやBurnを行い、安全な送付をサポートします。
OffRamp
Destinationチェーンで動作するコントラクトで、OnRampから送信されたメッセージやトークンを検証して受信者へ送付します。
受け取ったメッセージやトークンが正当であることを検証した後、ルーターにデータを送信します。
トークン送付の場合、Token Poolを通じて適切なトークンが受信者に渡されます。
Commit Store
Sourceチェーンで送信されたトランザクションのMerkleルートを保存する場所です。
このルートは、リスク管理ネットワークによって承認される必要があります。
1つのレーンごとに1つのCommit Storeが存在し、メッセージの整合性を確保します。
送信者は、Sourceチェーンのルーターを介してトークンやメッセージを送信。
ルーターは、トランザクションをOnRampへルーティングし、トークンをLockまたはBurnしてトランザクションを準備。
Committing DONがトランザクションを監視し、Merkleルートを生成してCommit Storeに保存。
Executing DONが、DestinationチェーンでCommit Storeに保存されたMerkleルートを検証してメッセージを実行。
トークンが関与している場合、OffRampがトークンをUnlockまたはMintし、Receiverのアカウントにトークンを送付。
レートリミットは、セキュリティ強化のために設定されるもので、ある一定の時間内にtransfer
できるトークンの量を制限する仕組みです。このリミットには2つの要素があります。
最大容量(Maximum Capacity)
transfer
できるトークンの最大量。補充速度(Refill Rate)
transfer
後に、最大容量がどのくらいで回復するか(秒ごとに補充されるトークンの量)。
これにより、短期間に大量のトークンをtransfer
することで発生するセキュリティリスクを低減します。
レートリミットの仕組み
レートリミットは、送信元と受信先のブロックチェーン両方で適用され、セキュリティを強化しています。もしリミットを超えた場合、エラーが発生してユーザーに通知されます。これにより、ユーザーはdApp(分散型アプリケーション)内でエラーを処理し、スムーズなユーザー体験を維持できます。
トークンプールのレートリミット
トークンプールごとに、特定のトークンがLane(ブロックチェーン間の通信経路)でtransfer
される時のリミットが設定されています。このリミットは、トークンの価格(USD)に依存せず、トークンの数量に基づいて決定されます。
トークンプールのレートリミットの例
suUSD(ステーブルコイン)のトークンプールにおいて、EthereumメインネットからBaseメインネットへのLaneで、最大容量が200,000 suUSD
に設定されています。補充速度は2 suUSD/秒
です。最初に200,000 suUSD
をtransfer
した場合、その時点でトークンプールは空になります。 その後、20 suUSD
を転送したい場合、少なくとも10秒待たないとプールが再び満たされずtransfer
できません。このLaneでは、10分間で最大1200 suUSD
の転送が可能です。
アグリゲートレートリミット(総合レートリミット)
特定のLaneにおける全トークンの合計transfer
量に対して設定される制限です。各トークンプールのレートリミットの合計よりも低く設定されており、セキュリティをさらに強化しています。
アグリゲートレートリミットの例
あるLaneに対して、最大容量が100,000 USD
、補充速度が167 USD/秒
のアグリゲートレートリミットが設定されているとします。 このレーンで60,000 USD
分のトークンをすでにtransfer
した場合、残りの利用可能な容量は40,000 USD
です。 もし50,000 USD
相当のトークンをtransfer
しようとすると、10,000 USD
分が不足しているため、60秒待って補充が完了するまで待つ必要があります。 このレーンの最大スループット(処理能力)は、10分間で100,000 USD
です。
セキュリティ重視の設計
Chainlink CCIPは、セキュリティ優先のアプローチで設計されています。特に、ブロックチェーンの「ブロック再編成(block reorgs)」のリスクを最小限に抑えることを重視しています。reorgsとは、ブロックチェーン上の既存のブロックが取り消されて、新しいブロックが代わりに追加されてトランザクションが取り消されることです。
ファイナリティが重要
クロスチェーン取引の全体のトランザクション時間は、主にSourceチェーン上でトランザクションが「ファイナリティ(トランザクションが確定した状態)」に到達するまでの時間に依存します。 ブロックチェーンによってファイナリティにかかる時間は異なります。
Ethereumの場合、1つのブロックが完全に確定するまでに約15分かかります。これは、複数の確認が必要なためです。Avalancheのような高速ファイナリティを持つブロックチェーンでは、ファイナリティまでの時間が約1秒です。このため、クロスチェーン取引の処理時間が短くなります。実行にかかるガス代と遅延の関係
Sourceチェーンで支払われる手数料(ガス代)が、Destinationチェーンでの実行コストを下回らなければメッセージはリスク管理ネットワークによって承認された後、できるだけ早く転送されます。
しかし、トランザクションが要求された時点と実行される時点の間にガス代が上昇すると、CCIPは自動的にガス価格を増加させて成功するまで再実行。ただし、これによって実行に時間がかかる場合があります(遅延)。
Smart Executionによる遅延防止
実行に1時間以上の遅延が発生しないようにする仕組みです。時間ウィンドウという設定があり、この時間内にDON(分散型オラクルネットワーク)がトランザクションを実行できない場合、ユーザーが手動実行を許可することができます。
手動実行の仕組み
もしネットワーク状況が非常に悪く、Smart Executionの時間ウィンドウ内で実行できない場合、ユーザーはCCIP Explorerというツールを使用して手動でメッセージを実行できます。これにより、長時間の遅延を避けることが可能です。