solidity-crosschain: クロスチェーン開発スキル
クロスチェーン通信・ブリッジ設計・マルチチェーンデプロイのパターンを提供するドメイン特化スキル。
対象
-
ブリッジ設計(Lock & Mint、Burn & Mint、Liquidity Pool)
-
クロスチェーンメッセージング(LayerZero V2、Chainlink CCIP、Wormhole)
-
マルチチェーンデプロイ戦略(CREATE2 deterministic deploy)
ワークフロー
Step 1: クロスチェーン要件の整理
ユーザーの要件からクロスチェーンの対象パターンを判定する:
ユースケース リファレンス 読み込み時の注目ポイント
トークンブリッジ references/bridge-patterns.md
Lock & Mint vs Burn & Mint vs Liquidity Pool の選択基準、Rate Limiting パターン
クロスチェーンメッセージ送信 references/messaging-patterns.md
プロトコル別の送受信パターン(lzSend/lzReceive、ccipSend/ccipReceive)
マルチチェーンデプロイ references/bridge-patterns.md
CREATE2 deterministic deploy、チェーン間のアドレス一致
Omnichain Token (OFT) references/messaging-patterns.md
LayerZero OFT パターン、peer 設定、Rate Limiting
検証ゲート: 対象のクロスチェーンユースケースが特定できること。不明な場合は AskUserQuestion で「何を(トークン/メッセージ/NFT)」「どのチェーン間で」送信するか確認する。
Step 2: プロトコル選択
要件に基づきプロトコルを選択する:
判断基準 LayerZero V2 Chainlink CCIP Wormhole
セキュリティモデル Ultra Light Node + DVN(カスタム可能) DON(分散オラクルネットワーク) Guardian Network(19 ノード)
対応チェーン数 70+ 15+(拡大中) 30+
トークンブリッジ OFT / ONFT CCIP Token Transfer Portal Bridge
ガスコスト 中 高(LINK 支払い) 低
カスタマイズ性 高(DVN 選択可能) 中 中
成熟度 高(V2 は 2024〜) 高 中
選択ガイドライン:
-
セキュリティ最優先: Chainlink CCIP(DON の実績、保険あり)
-
広範なチェーン対応: LayerZero(70+ chains)
-
ガスコスト重視: Wormhole(低ガス)
-
トークンブリッジ: LayerZero OFT(シンプルな API)または CCIP(高セキュリティ)
判断が不明な場合: AskUserQuestion で「セキュリティ vs コスト」「対象チェーン」を確認する。
検証ゲート: プロトコルが決定し、対応する SDK / ライブラリが利用可能であること。
Step 3: コード生成
-
solidity-core の language-patterns.md に従い NatSpec・コーディング規約を適用する。
-
クロスチェーン固有のセキュリティ対策を組み込む:
-
送信元検証: _origin.srcEid / _origin.sender のホワイトリスト検証
-
リプレイ攻撃防止: メッセージ ID / nonce の重複チェック
-
Rate Limiting: 日次/時間あたりの流出量制限
-
ガスリミット: 受信側の lzReceive / ccipReceive に十分なガスを設定
-
テストコードを同時に生成する:
-
モックエンドポイント / ルーターでのローカルテスト
-
メッセージ送信 → 受信のフローテスト
-
不正な送信元からのメッセージ拒否テスト
-
Rate Limiting のテスト
検証ゲート: forge build がエラーなく完了すること。
Step 4: セキュリティ最終確認
クロスチェーン特有のセキュリティリスクを確認する:
-
メッセージ検証: 送信元チェーン ID・アドレスを検証しているか。ハードコードされた peer 設定が正しいか。
-
リプレイ攻撃: processedMessages[messageId] 等でメッセージの重複実行を防止しているか。
-
Rate Limiting: 大量の資金流出を防ぐ日次制限が設定されているか。閾値は TVL の 10-20% が推奨。
-
失敗メッセージの回復: lzReceive / ccipReceive が revert した場合のリカバリ機構があるか。LayerZero の RetryableMessage パターンを使用しているか。
-
ガスの十分性: 受信側の実行に十分なガスが設定されているか。extraOptions / gasLimit の値が適切か。
検証ゲート: CRITICAL レベルのセキュリティ問題が 0 件であること。
使用例
例 1: LayerZero OFT でクロスチェーントークン送信
ユーザー入力: 「Ethereum と Arbitrum 間でトークンを送信したい。LayerZero を使って」
アクション:
- Step 1: トークンブリッジ → bridge-patterns.md
- messaging-patterns.md を読み込み → OFT パターンを選択
-
Step 2: LayerZero V2 を選択(トークンブリッジ + 広範なチェーン対応)
-
Step 3: 以下を生成:
-
src/MyOFT.sol — @layerzerolabs/oft-evm/contracts/OFT.sol を継承。Rate Limiting 付き
-
test/MyOFT.t.sol — モックエンドポイントでの send / receive テスト、Rate Limiting テスト
-
script/DeployOFT.s.sol — Ethereum + Arbitrum デプロイスクリプト
-
script/SetPeers.s.sol — 双方向の peer 設定スクリプト
-
Step 4: peer 設定の正当性、Rate Limiting 閾値、ガス設定を確認
デプロイ手順:
-
Ethereum に MyOFT をデプロイ
-
Arbitrum に MyOFT をデプロイ
-
双方で setPeer(remoteEid, remoteAddress) を実行
-
Rate Limiting を設定(setRateLimits )
-
テスト送信で動作確認
結果: Ethereum ⇔ Arbitrum 間で OFT トークンが送受信可能になる。Rate Limiting で大量流出を防止。
例 2: Chainlink CCIP でトークン + メッセージ送信
ユーザー入力: 「CCIP で USDC をブリッジしつつ、カスタムデータも一緒に送りたい」
アクション:
-
Step 1: トークン + メッセージ → messaging-patterns.md の CCIP セクションを読み込み
-
Step 2: Chainlink CCIP を選択(高セキュリティ + トークン転送サポート)
-
Step 3: 以下を生成:
-
src/CCIPSender.sol — Client.EVM2AnyMessage 構築、LINK / Native 手数料支払い、ccipSend 実行
-
src/CCIPReceiver.sol — CCIPReceiver 継承、_ccipReceive でトークン + メッセージ処理
-
test/CCIP.t.sol — モックルーターでの送信テスト、不正メッセージ拒否テスト
-
Step 4: ルーターアドレスの正当性(公式デプロイ)、LINK 残高、送信元ホワイトリストを確認
結果: USDC とカスタムデータを同時にクロスチェーン送信するコントラクトが生成される。
例 3: マルチチェーンデプロイ(CREATE2)
ユーザー入力: 「全チェーンで同じアドレスにコントラクトをデプロイしたい」
アクション:
-
Step 1: マルチチェーンデプロイ → bridge-patterns.md の CREATE2 セクションを読み込み
-
Step 2: プロトコル依存なし(デプロイ戦略のみ)
-
Step 3: 以下を生成:
-
src/Deployer.sol — CREATE2 Factory。salt
- bytecode から deterministic アドレスを計算
-
script/MultiChainDeploy.s.sol — 複数チェーンに順次デプロイ。computeAddress でアドレス事前計算
-
test/Deployer.t.sol — アドレス事前計算と実際のデプロイアドレスの一致テスト
-
Step 4: deployer アドレスの nonce 管理、bytecode の完全一致(constructor args 含む)を確認
結果: 全チェーンで同一アドレスにコントラクトがデプロイされる。
トラブルシューティング
- クロスチェーンメッセージが届かない
症状: 送信トランザクションは成功したが、受信チェーンで実行されない
原因と対策:
-
ガス不足: 受信側の lzReceive / ccipReceive に設定したガスリミットが不足している。LayerZero の場合: OptionsBuilder.newOptions().addExecutorLzReceiveOption(200000, 0) でガスリミットを増加する。
-
peer 未設定: 送信元/受信先の setPeer が双方向で設定されているか確認する。LayerZero Scan / CCIP Explorer でメッセージステータスを確認する。
-
DVN 設定の問題(LayerZero): 送受信両方で同じ DVN が設定されているか確認する。デフォルトは LayerZero の DVN。
-
ルーターアドレスの不正(CCIP): 各チェーンの公式 CCIP Router アドレスを使用しているか確認する。
- setPeer が失敗する
症状: onlyOwner でリバート、または peer が正しく設定されない
原因と対策:
-
owner の不一致: デプロイ後の owner が正しいアドレスか確認する。マルチシグの場合は提案経由で実行する。
-
アドレスのバイト変換: setPeer は bytes32 型を受け取る。addressToBytes32(remoteContractAddress) で正しく変換しているか確認する。abi.encode(address) ではなく左パディングを使用する。
-
Endpoint ID の不一致: 各チェーンの LayerZero Endpoint ID(eid)が正しいか確認する。Mainnet と Testnet で異なる。
- Rate Limiting に引っかかる
症状: RateLimitExceeded でトランザクションがリバートする
原因と対策:
-
制限値の確認: 現在の日次制限と累計送信量を確認する。getRateLimitState() で残り枠を取得する。
-
制限値の調整: プロジェクトの TVL と想定トラフィックに基づき制限値を調整する。初期は TVL の 10% / 日を推奨。
-
リセットタイミング: Rate Limiting のリセットがローリングウィンドウ(sliding window)か固定期間(daily reset)か確認する。
- CREATE2 デプロイで異なるアドレスになる
症状: チェーン間でデプロイアドレスが一致しない
原因と対策:
-
constructor 引数の不一致: constructor の引数がチェーン間で異なっている(例: チェーン固有のアドレス)。引数も bytecode に含まれるため、全チェーンで同一にする必要がある。チェーン固有の設定は initialize 関数で設定する。
-
Factory アドレスの不一致: CREATE2 アドレスは deployer アドレスにも依存する。全チェーンで同じ Factory を同じアドレスにデプロイする。
-
salt の不一致: 全チェーンで同じ salt を使用しているか確認する。
- CCIP の手数料計算が失敗する
症状: getFee が予期しない値を返す、または ccipSend が手数料不足でリバート
原因と対策:
-
LINK 残高不足: コントラクトに十分な LINK トークンがデポジットされているか確認する。getFee で事前に手数料を見積もる。
-
Native 支払いの場合: msg.value が getFee の返り値以上であるか確認する。余剰分は返金される。
-
メッセージサイズ: データサイズが大きいと手数料が増加する。不要なデータを削減する。
注意事項
-
クロスチェーンプロトコルはまだ成熟途上であり、API の変更が頻繁。本番デプロイ前に各プロトコルの最新ドキュメントを必ず確認する。
-
クロスチェーンメッセージは非同期であり、失敗時のリカバリ設計が不可欠。lzReceive / ccipReceive が revert した場合の再試行機構を実装する。
-
Rate Limiting は必須。ブリッジの脆弱性が発見された場合の被害を最小限に抑える。
-
テストネットでの十分な検証を行ってから本番デプロイする。LayerZero Scan / CCIP Explorer でメッセージの状態を確認する。
-
基盤的なパターン(アクセス制御、ガス最適化等)は solidity-core を参照する。
-
フロントエンド統合(クロスチェーン送信 UI)は web3-frontend を参照する。