mcpField
D
debridge

debridge

github.com/sendaifun開発130170 回インストール13 週間前に更新
リポジトリ

debridge について

Solana プログラムで deBridge Solana SDK を使うための開発スキル兼ガイドです。クロスチェーン資産転送、メッセージ送信、転送先チェーンでのコントラクト呼び出し、申請検証を説明します。

主な機能

  1. 01クロスチェーントークン転送
  2. 02チェーン間のメッセージ送信
  3. 03転送先チェーンのコントラクト呼び出し
  4. 04受信した申請の検証
  5. 05手数料計算とチェーンサポート確認

活用シーン

  1. 01Solana プログラムへの deBridge 転送機能の追加
  2. 02トークンを転送せずにクロスチェーンメッセージを送信
  3. 03転送先チェーンのコントラクト呼び出し

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/sendaifun/skills --skill debridge

インストール後、Claude Code で/debridgeを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

docs/
troubleshooting.md
examples/basic-transfer/
README.md
examples/external-calls/
README.md
examples/fee-configurations/
README.md
examples/message-passing/
README.md
resources/
chain-ids.md
error-codes.md
program-ids.md
sdk-api-reference.md

詳細

deBridge Solana SDK 開発ガイド

deBridge Solana SDK を使用して Solana プログラムを構築するための包括的なガイドです。ブロックチェーン間で任意のメッセージや価値を分散型でクロスチェーン転送できます。

概要

deBridge は、以下を可能にするクロスチェーンインフラストラクチャプロトコルです。

  • クロスチェーン転送:Solana と 20 以上の EVM チェーン間で資産をブリッジします
  • メッセージパッシング:ブロックチェーン間で任意のメッセージを送信します
  • 外部呼び出し:宛先チェーンでスマートコントラクト呼び出しを実行します
  • 1 秒未満の決済:決済時間の中央値は約 2 秒です
  • 資本効率:最低 4 bps のスプレッドを実現するインテントベースのアーキテクチャです
主な機能
  • 26 件以上のセキュリティ監査(Halborn、Zokyo、Ackee Blockchain)
  • Immunefi で 20 万ドルのバグ報奨金
  • ローンチ以来、稼働率 100%
  • セキュリティインシデントゼロ

クイックスタート

インストール

SDK を Anchor/Solana プログラムに追加します。

cargo add --git ssh://[email protected]/debridge-finance/debridge-solana-sdk.git debridge-solana-sdk

または、Cargo.toml に追加します。

[dependencies]
debridge-solana-sdk = { git = "ssh://[email protected]/debridge-finance/debridge-solana-sdk.git" }
基本設定(Anchor)
use anchor_lang::prelude::*;
use debridge_solana_sdk::prelude::*;

declare_id!("YourProgramId11111111111111111111111111111");

#[program]
pub mod my_bridge_program {
    use super::*;

    pub fn send_cross_chain(
        ctx: Context<SendCrossChain>,
        target_chain_id: [u8; 32],
        receiver: Vec<u8>,
        amount: u64,
    ) -> Result<()> {
        // Invoke deBridge send
        debridge_sending::invoke_debridge_send(
            debridge_sending::SendIx {
                target_chain_id,
                receiver,
                is_use_asset_fee: false,  // Use native SOL for fees
                amount,
                submission_params: None,
                referral_code: None,
            },
            ctx.remaining_accounts,
        )?;

        Ok(())
    }
}

#[derive(Accounts)]
pub struct SendCrossChain<'info> {
    #[account(mut)]
    pub sender: Signer<'info>,
    // Additional accounts passed via remaining_accounts
}

基本概念

1. チェーン ID

deBridge は、サポートされるすべてのネットワークに 32 バイトのチェーン識別子を使用します。

use debridge_solana_sdk::chain_ids::*;

// Solana
let solana = SOLANA_CHAIN_ID;  // Solana mainnet

// EVM Chains
let ethereum = ETHEREUM_CHAIN_ID;     // Chain ID: 1
let polygon = POLYGON_CHAIN_ID;       // Chain ID: 137
let bnb = BNB_CHAIN_CHAIN_ID;         // Chain ID: 56
let arbitrum = ARBITRUM_CHAIN_ID;     // Chain ID: 42161
let avalanche = AVALANCHE_CHAIN_ID;   // Chain ID: 43114
let fantom = FANTOM_CHAIN_ID;         // Chain ID: 250
let heco = HECO_CHAIN_ID;             // Chain ID: 128
2. プログラム ID
use debridge_solana_sdk::{DEBRIDGE_ID, SETTINGS_ID};

// Main deBridge program for sending/claiming
let debridge_program = DEBRIDGE_ID;

// Settings and confirmation storage program
let settings_program = SETTINGS_ID;
3. 手数料体系

deBridge は、複数の手数料支払い方法に対応しています。

// Native Fee (SOL)
is_use_asset_fee: false  // Pay fees in SOL

// Asset Fee
is_use_asset_fee: true   // Pay fees in the bridged token

// Fee Constants
const BPS_DENOMINATOR: u64 = 10000;  // Basis points divisor
4. フラグ

フラグを使って転送の動作を制御します。

use debridge_solana_sdk::flags::*;

// Available flags (bit positions)
const UNWRAP_ETH: u8 = 0;              // Unwrap to native ETH on destination
const REVERT_IF_EXTERNAL_FAIL: u8 = 1; // Revert if external call fails
const PROXY_WITH_SENDER: u8 = 2;       // Include sender in proxy call
const SEND_HASHED_DATA: u8 = 3;        // Send data as hash
const DIRECT_WALLET_FLOW: u8 = 31;     // Use direct wallet flow

// Setting flags on submission params
let mut flags = [0u8; 32];
flags.set_reserved_flag(UNWRAP_ETH);
flags.set_reserved_flag(REVERT_IF_EXTERNAL_FAIL);

クロスチェーン転送の送信

基本的なトークン転送
use debridge_solana_sdk::prelude::*;

pub fn send_tokens(
    ctx: Context<SendTokens>,
    amount: u64,
) -> Result<()> {
    debridge_sending::invoke_debridge_send(
        debridge_sending::SendIx {
            target_chain_id: chain_ids::ETHEREUM_CHAIN_ID,
            receiver: recipient_eth_address.to_vec(),
            is_use_asset_fee: false,
            amount,
            submission_params: None,
            referral_code: Some(12345),  // Optional referral
        },
        ctx.remaining_accounts,
    )?;

    Ok(())
}
固定ネイティブ手数料での転送
pub fn send_with_native_fee(
    ctx: Context<Send>,
    target_chain_id: [u8; 32],
    receiver: Vec<u8>,
    amount: u64,
) -> Result<()> {
    // Get the fixed fee for the target chain
    let fee = debridge_sending::get_chain_native_fix_fee(
        &target_chain_id,
        ctx.remaining_accounts,
    )?;

    debridge_sending::invoke_debridge_send(
        debridge_sending::SendIx {
            target_chain_id,
            receiver,
            is_use_asset_fee: false,
            amount,
            submission_params: None,
            referral_code: None,
        },
        ctx.remaining_accounts,
    )?;

    Ok(())
}
資産手数料での転送
pub fn send_with_asset_fee(
    ctx: Context<Send>,
    target_chain_id: [u8; 32],
    receiver: Vec<u8>,
    amount: u64,
) -> Result<()> {
    // Check if asset fee is available for this chain
    let is_available = debridge_sending::is_asset_fee_available(
        &target_chain_id,
        ctx.remaining_accounts,
    )?;

    if !is_available {
        return Err(error!(ErrorCode::AssetFeeNotAvailable));
    }

    debridge_sending::invoke_debridge_send(
        debridge_sending::SendIx {
            target_chain_id,
            receiver,
            is_use_asset_fee: true,  // Use asset for fees
            amount,
            submission_params: None,
            referral_code: None,
        },
        ctx.remaining_accounts,
    )?;

    Ok(())
}
正確な数量での転送
pub fn send_exact_amount(
    ctx: Context<Send>,
    target_chain_id: [u8; 32],
    receiver: Vec<u8>,
    exact_receive_amount: u64,
) -> Result<()> {
    // Calculate total amount including fees
    let total_with_fees = debridge_sending::add_all_fees(
        exact_receive_amount,
        &target_chain_id,
        ctx.remaining_accounts,
    )?;

    debridge_sending::invoke_debridge_send(
        debridge_sending::SendIx {
            target_chain_id,
            receiver,
            is_use_asset_fee: true,
            amount: total_with_fees,
            submission_params: None,
            referral_code: None,
        },
        ctx.remaining_accounts,
    )?;

    Ok(())
}
PDA からの転送(署名あり)
pub fn send_from_pda(
    ctx: Context<SendFromPda>,
    target_chain_id: [u8; 32],
    receiver: Vec<u8>,
    amount: u64,
    pda_seeds: Vec<Vec<u8>>,
) -> Result<()> {
    // Use signed variant for PDA-owned tokens
    debridge_sending::invoke_debridge_send_signed(
        debridge_sending::SendIx {
            target_chain_id,
            receiver,
            is_use_asset_fee: false,
            amount,
            submission_params: None,
            referral_code: None,
        },
        ctx.remaining_accounts,
        &pda_seeds,
    )?;

    Ok(())
}

メッセージパッシング

トークンを転送せずにメッセージを送信します。

use debridge_solana_sdk::prelude::*;

pub fn send_message(
    ctx: Context<SendMessage>,
    target_chain_id: [u8; 32],
    receiver: Vec<u8>,
    message_data: Vec<u8>,
) -> Result<()> {
    // Create submission params with message
    let submission_params = debridge_sending::SendSubmissionParamsInput {
        execution_fee: 0,
        flags: [0u8; 32],
        fallback_address: receiver.clone(),
        external_call_shortcut: compute_keccak256(&message_data),
    };

    // Send message (zero amount)
    debridge_sending::invoke_send_message(
        debridge_sending::SendIx {
            target_chain_id,
            receiver,
            is_use_asset_fee: false,
            amount: 0,  // No token transfer
            submission_params: Some(submission_params),
            referral_code: None,
        },
        ctx.remaining_accounts,
    )?;

    Ok(())
}

外部呼び出し

宛先チェーンでスマートコントラクト呼び出しを実行します。

外部呼び出しバッファーの初期化
pub fn init_external_call(
    ctx: Context<InitExternalCall>,
    target_chain_id: [u8; 32],
    external_call_data: Vec<u8>,
) -> Result<()> {
    let shortcut = compute_keccak256(&external_call_data);

    debridge_sending::invoke_init_external_call(
        debridge_sending::InitExternalCallIx {
            external_call_len: external_call_data.len() as u32,
            chain_id: target_chain_id,
            external_call_shortcut: shortcut,
            external_call: external_call_data,
        },
        ctx.remaining_accounts,
    )?;

    Ok(())
}
外部呼び出しを伴う送信
pub fn send_with_external_call(
    ctx: Context<SendWithExternalCall>,
    target_chain_id: [u8; 32],
    receiver: Vec<u8>,  // Target contract address
    amount: u64,
    external_call_data: Vec<u8>,
    execution_fee: u64,  // Fee for executor on destination
) -> Result<()> {
    let shortcut = compute_keccak256(&external_call_data);

    // Set flags for external call behavior
    let mut flags = [0u8; 32];
    flags.set_reserved_flag(flags::REVERT_IF_EXTERNAL_FAIL);

    let submission_params = debridge_sending::SendSubmissionParamsInput {
        execution_fee,
        flags,
        fallback_address: ctx.accounts.fallback.key().to_bytes().to_vec(),
        external_call_shortcut: shortcut,
    };

    debridge_sending::invoke_debridge_send(
        debridge_sending::SendIx {
            target_chain_id,
            receiver,
            is_use_asset_fee: false,
            amount,
            submission_params: Some(submission_params),
            referral_code: None,
        },
        ctx.remaining_accounts,
    )?;

    Ok(())
}

クレームの検証

受信側でクレームを検証します。

受信したクレームの検証
use debridge_solana_sdk::check_claiming::*;

pub fn receive_tokens(ctx: Context<ReceiveTokens>) -> Result<()> {
    // Get and validate the parent claim instruction
    let claim_ix = ValidatedExecuteExtCallIx::try_from_current_ix()?;

    // Validate submission details
    let validation = SubmissionAccountValidation {
        receiver_validation: Some(ctx.accounts.receiver.key()),
        token_mint_validation: Some(ctx.accounts.token_mint.key()),
        source_chain_id_validation: Some(chain_ids::ETHEREUM_CHAIN_ID),
        ..Default::default()
    };

    claim_ix.validate_submission_account(
        &ctx.accounts.submission_account,
        &validation,
    )?;

    // Proceed with claim logic
    Ok(())
}
送信キーの取得
pub fn get_claim_info(ctx: Context<ClaimInfo>) -> Result<Pubkey> {
    let claim_ix = ValidatedExecuteExtCallIx::try_from_current_ix()?;
    let submission_key = claim_ix.get_submission_key()?;
    Ok(submission_key)
}

手数料の照会

転送手数料の取得
// Get base transfer fee (in BPS)
let transfer_fee = debridge_sending::get_transfer_fee(
    ctx.remaining_accounts,
)?;

// Get transfer fee for specific chain
let chain_fee = debridge_sending::get_transfer_fee_for_chain(
    &target_chain_id,
    ctx.remaining_accounts,
)?;

// Get default native fix fee
let default_fee = debridge_sending::get_default_native_fix_fee(
    ctx.remaining_accounts,
)?;

// Get chain-specific native fix fee
let native_fee = debridge_sending::get_chain_native_fix_fee(
    &target_chain_id,
    ctx.remaining_accounts,
)?;

// Get asset fix fee for chain
let asset_fee = debridge_sending::try_get_chain_asset_fix_fee(
    &target_chain_id,
    ctx.remaining_accounts,
)?;
手数料込みの合計数量を計算
// Add transfer fee to amount
let with_transfer_fee = debridge_sending::add_transfer_fee(
    amount,
    ctx.remaining_accounts,
)?;

// Add all fees (transfer + execution + asset fees)
let total_amount = debridge_sending::add_all_fees(
    amount,
    &target_chain_id,
    ctx.remaining_accounts,
)?;

チェーンサポートの照会

// Check if chain is supported
let is_supported = debridge_sending::is_chain_supported(
    &target_chain_id,
    ctx.remaining_accounts,
)?;

// Get chain support info
let chain_info = debridge_sending::get_chain_support_info(
    &target_chain_id,
    ctx.remaining_accounts,
)?;

// Check if asset fee is available
let asset_fee_available = debridge_sending::is_asset_fee_available(
    &target_chain_id,
    ctx.remaining_accounts,
)?;

PDA の導出

ブリッジアカウント
use debridge_solana_sdk::keys::*;

// Find bridge PDA for a token mint
let (bridge_address, bump) = BridgePubkey::find_bridge_address(&token_mint);

// Create with known bump
let bridge_address = BridgePubkey::create_bridge_address(&token_mint, bump)?;
チェーンサポート情報
// Find chain support info PDA
let (chain_support_info, bump) = ChainSupportInfoPubkey::find_chain_support_info_address(
    &target_chain_id,
);
資産手数料情報
// Find asset fee info PDA
let (asset_fee_info, bump) = AssetFeeInfoPubkey::find_asset_fee_info_address(
    &bridge_pubkey,
    &target_chain_id,
);

// Get default bridge fee address
let default_fee = AssetFeeInfoPubkey::default_bridge_fee_address();
外部呼び出しストレージ
// Find external call storage PDA
let (storage, bump) = ExternalCallStoragePubkey::find_external_call_storage_address(
    &shortcut,
    &owner,
);

// Find external call meta PDA
let (meta, bump) = ExternalCallMetaPubkey::find_external_call_meta_address(
    &storage_account,
);

必須アカウント

SDK では、remaining_accounts を通じて特定のアカウントを渡す必要があります。アカウントの順序は重要です。

インデックスアカウント署名者書き込み可能説明
0ブリッジいいえはいトークン用のブリッジアカウント
1トークンミントいいえいいえSPL Token ミント
2ステーキングウォレットいいえはいステーキング報酬ウォレット
3ミント権限いいえいいえトークンミントの権限
4チェーンサポート情報いいえいいえ宛先チェーンの設定
5Settings ProgramいいえいいえdeBridge の設定
6SPL Token Programいいえいいえトークンプログラム
7Stateいいえいいえプロトコルの状態
8deBridge ProgramいいえいいえdeBridge のメインプログラム
...追加アカウント--操作によって異なります

TypeScript クライアントの統合

セットアップ
import { Connection, Keypair, PublicKey, Transaction } from '@solana/web3.js';
import { Program, AnchorProvider, Wallet } from '@coral-xyz/anchor';

const connection = new Connection('https://api.mainnet-beta.solana.com');
const wallet = new Wallet(keypair);
const provider = new AnchorProvider(connection, wallet, {});

// deBridge Program IDs
const DEBRIDGE_PROGRAM_ID = new PublicKey('DEbrdGj3HsRsAzx6uH4MKyREKxVAfBydijLUF3ygsFfh');
const SETTINGS_PROGRAM_ID = new PublicKey('DeSetTwWhjZq6Pz9Kfdo1KoS5NqtsM6G8ERbX4SSCSft');
送信トランザクションの構築
import {
  TOKEN_PROGRAM_ID,
  getAssociatedTokenAddress
} from '@solana/spl-token';

async function buildSendTransaction(
  tokenMint: PublicKey,
  amount: bigint,
  targetChainId: Uint8Array,
  receiver: Uint8Array,
): Promise<Transaction> {
  // Derive required PDAs
  const [bridge] = PublicKey.findProgramAddressSync(
    [Buffer.from('BRIDGE'), tokenMint.toBuffer()],
    DEBRIDGE_PROGRAM_ID
  );

  const [chainSupportInfo] = PublicKey.findProgramAddressSync(
    [Buffer.from('CHAIN_SUPPORT_INFO'), targetChainId],
    SETTINGS_PROGRAM_ID
  );

  const [state] = PublicKey.findProgramAddressSync(
    [Buffer.from('STATE')],
    DEBRIDGE_PROGRAM_ID
  );

  // Build instruction with remaining accounts
  const instruction = await program.methods
    .sendViaDebridge(
      Array.from(targetChainId),
      Array.from(receiver),
      new BN(amount.toString()),
    )
    .remainingAccounts([
      { pubkey: bridge, isSigner: false, isWritable: true },
      { pubkey: tokenMint, isSigner: false, isWritable: false },
      // ... additional required accounts
    ])
    .instruction();

  return new Transaction().add(instruction);
}
外部呼び出しデータの構築
import { ethers } from 'ethers';
import { keccak256 } from '@ethersproject/keccak256';

function buildExternalCallData(
  targetContract: string,
  functionSig: string,
  params: any[]
): { data: Uint8Array; shortcut: Uint8Array } {
  const iface = new ethers.Interface([functionSig]);
  const calldata = iface.encodeFunctionData(
    functionSig.split('(')[0].replace('function ', ''),
    params
  );

  const data = ethers.getBytes(calldata);
  const shortcut = ethers.getBytes(keccak256(data));

  return { data, shortcut };
}

// Example: ERC20 approve call
const { data, shortcut } = buildExternalCallData(
  '0xTargetContract...',
  'function approve(address spender, uint256 amount)',
  ['0xSpenderAddress...', ethers.parseEther('1000')]
);

テスト

Anchor テストのセットアップ
# Anchor.toml
[provider]
cluster = "mainnet"  # Use mainnet for testing with real deBridge

[programs.mainnet]
my_program = "YourProgramId..."
テストの実行
# Full build and test
cd example_program && anchor build && anchor test

# Test only (skip rebuild)
anchor test --skip-build --skip-deploy
ローカルテストのヒント
  1. Mainnet フォークを使用する:deBridge のインフラストラクチャは mainnet 上にあります
  2. 残りのアカウントをモックする:単体テスト用のモックアカウントを作成します
  3. 手数料計算をテストする:送信前に手数料の額を確認します

ビルド機能

SDK は Cargo のフィーチャーを通じて、さまざまな環境に対応しています。

# Production (default) - uses hardcoded program IDs
debridge-solana-sdk = { git = "..." }

# Custom environment - uses env vars
debridge-solana-sdk = { git = "...", features = ["env"] }

カスタムネットワーク用の環境変数:

  • DEBRIDGE_PROGRAM_PUBKEY:カスタム deBridge プログラム ID
  • DEBRIDGE_SETTINGS_PROGRAM_PUBKEY:カスタム Settings Program ID

リソース

スキルの構成

debridge/
├── SKILL.md                          # This file
├── resources/
│   ├── sdk-api-reference.md          # Complete SDK API reference
│   ├── chain-ids.md                  # Supported chain identifiers
│   ├── program-ids.md                # Program IDs and PDAs
│   └── error-codes.md                # Error types and handling
├── examples/
│   ├── basic-transfer/               # Simple cross-chain transfer
│   ├── external-calls/               # External call execution
│   ├── message-passing/              # Message-only transfers
│   └── fee-configurations/           # Fee payment options
└── docs/
    └── troubleshooting.md            # Common issues and solutions

コメント