debridge

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

deBridge Solana SDK Development Guide

deBridge Solana SDK 开发指南

A comprehensive guide for building Solana programs with the deBridge Solana SDK - enabling decentralized cross-chain transfers of arbitrary messages and value between blockchains.
为使用deBridge Solana SDK构建Solana程序提供的全面指南——支持区块链之间任意消息和价值的去中心化跨链传输。

Overview

概述

deBridge is a cross-chain infrastructure protocol enabling:
  • Cross-Chain Transfers: Bridge assets between Solana and 20+ EVM chains
  • Message Passing: Send arbitrary messages across blockchains
  • External Calls: Execute smart contract calls on destination chains
  • Sub-Second Settlement: ~2 second median settlement time
  • Capital Efficiency: Intent-based architecture with 4bps lowest spreads
deBridge是一款跨链基础设施协议,支持:
  • 跨链转账:在Solana与20多条EVM链之间桥接资产
  • 消息传递:在区块链之间发送任意消息
  • 外部调用:在目标链上执行智能合约调用
  • 亚秒级结算:中位数结算时间约2秒
  • 资本效率:基于意图的架构,点差低至4个基点

Key Features

核心特性

  • 26+ security audits (Halborn, Zokyo, Ackee Blockchain)
  • $200K bug bounty on Immunefi
  • 100% uptime since launch
  • Zero security incidents
  • 26+次安全审计(由Halborn、Zokyo、Ackee Blockchain完成)
  • 在Immunefi上设有20万美元的漏洞赏金
  • 上线以来100%正常运行时间
  • 无安全事故

Quick Start

快速开始

Installation

安装

Add the SDK to your Anchor/Solana program:
bash
cargo add --git ssh://git@github.com/debridge-finance/debridge-solana-sdk.git debridge-solana-sdk
Or add to
Cargo.toml
:
toml
[dependencies]
debridge-solana-sdk = { git = "ssh://git@github.com/debridge-finance/debridge-solana-sdk.git" }
将SDK添加到你的Anchor/Solana程序中:
bash
cargo add --git ssh://git@github.com/debridge-finance/debridge-solana-sdk.git debridge-solana-sdk
或者添加到
Cargo.toml
toml
[dependencies]
debridge-solana-sdk = { git = "ssh://git@github.com/debridge-finance/debridge-solana-sdk.git" }

Basic Setup (Anchor)

基础设置(Anchor)

rust
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
}
rust
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
}

Core Concepts

核心概念

1. Chain IDs

1. 链ID

deBridge uses 32-byte chain identifiers for all supported networks:
rust
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
deBridge对所有支持的网络使用32字节的链标识符:
rust
use debridge_solana_sdk::chain_ids::*;

// Solana
let solana = SOLANA_CHAIN_ID;  // Solana主网

// 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. Program IDs

2. 程序ID

rust
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;
rust
use debridge_solana_sdk::{DEBRIDGE_ID, SETTINGS_ID};

// 用于发送/领取的主deBridge程序
let debridge_program = DEBRIDGE_ID;

// 设置和确认存储程序
let settings_program = SETTINGS_ID;

3. Fee Structure

3. 费用结构

deBridge supports multiple fee payment methods:
rust
// 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
deBridge支持多种费用支付方式:
rust
// 原生费用(SOL)
is_use_asset_fee: false  // 使用原生SOL支付费用

// 资产费用
is_use_asset_fee: true   // 使用桥接代币支付费用

// 费用常量
const BPS_DENOMINATOR: u64 = 10000;  // 基点除数

4. Flags

4. 标志位

Control transfer behavior with flags:
rust
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);
通过标志位控制转账行为:
rust
use debridge_solana_sdk::flags::*;

// 可用标志位(比特位位置)
const UNWRAP_ETH: u8 = 0;              // 在目标链上解包为原生ETH
const REVERT_IF_EXTERNAL_FAIL: u8 = 1; // 外部调用失败时回滚
const PROXY_WITH_SENDER: u8 = 2;       // 在代理调用中包含发送方信息
const SEND_HASHED_DATA: u8 = 3;        // 以哈希形式发送数据
const DIRECT_WALLET_FLOW: u8 = 31;     // 使用直接钱包流程

// 在提交参数中设置标志位
let mut flags = [0u8; 32];
flags.set_reserved_flag(UNWRAP_ETH);
flags.set_reserved_flag(REVERT_IF_EXTERNAL_FAIL);

Sending Cross-Chain Transfers

发送跨链转账

Basic Token Transfer

基础代币转账

rust
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(())
}
rust
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),  // 可选推荐码
        },
        ctx.remaining_accounts,
    )?;

    Ok(())
}

Transfer with Fixed Native Fee

固定原生费用转账

rust
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(())
}
rust
pub fn send_with_native_fee(
    ctx: Context<Send>,
    target_chain_id: [u8; 32],
    receiver: Vec<u8>,
    amount: u64,
) -> Result<()> {
    // 获取目标链的固定费用
    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(())
}

Transfer with Asset Fee

资产费用转账

rust
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(())
}
rust
pub fn send_with_asset_fee(
    ctx: Context<Send>,
    target_chain_id: [u8; 32],
    receiver: Vec<u8>,
    amount: u64,
) -> Result<()> {
    // 检查该链是否支持资产费用
    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,  // 使用资产支付费用
            amount,
            submission_params: None,
            referral_code: None,
        },
        ctx.remaining_accounts,
    )?;

    Ok(())
}

Transfer with Exact Amount

精确到账金额转账

rust
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(())
}
rust
pub fn send_exact_amount(
    ctx: Context<Send>,
    target_chain_id: [u8; 32],
    receiver: Vec<u8>,
    exact_receive_amount: u64,
) -> Result<()> {
    // 计算包含费用的总金额
    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(())
}

Transfer from PDA (Signed)

从PDA发送(签名版)

rust
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(())
}
rust
pub fn send_from_pda(
    ctx: Context<SendFromPda>,
    target_chain_id: [u8; 32],
    receiver: Vec<u8>,
    amount: u64,
    pda_seeds: Vec<Vec<u8>>,
) -> Result<()> {
    // 针对PDA持有的代币使用签名版方法
    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(())
}

Message Passing

消息传递

Send messages without token transfers:
rust
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(())
}
无需代币转账的纯消息发送:
rust
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<()> {
    // 创建包含消息的提交参数
    let submission_params = debridge_sending::SendSubmissionParamsInput {
        execution_fee: 0,
        flags: [0u8; 32],
        fallback_address: receiver.clone(),
        external_call_shortcut: compute_keccak256(&message_data),
    };

    // 发送消息(金额设为0)
    debridge_sending::invoke_send_message(
        debridge_sending::SendIx {
            target_chain_id,
            receiver,
            is_use_asset_fee: false,
            amount: 0,  // 无代币转账
            submission_params: Some(submission_params),
            referral_code: None,
        },
        ctx.remaining_accounts,
    )?;

    Ok(())
}

External Calls

外部调用

Execute smart contract calls on destination chains:
在目标链上执行智能合约调用:

Initialize External Call Buffer

初始化外部调用缓冲区

rust
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(())
}
rust
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(())
}

Send with External Call

带外部调用的转账

rust
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(())
}
rust
pub fn send_with_external_call(
    ctx: Context<SendWithExternalCall>,
    target_chain_id: [u8; 32],
    receiver: Vec<u8>,  // 目标合约地址
    amount: u64,
    external_call_data: Vec<u8>,
    execution_fee: u64,  // 目标链执行方的费用
) -> Result<()> {
    let shortcut = compute_keccak256(&external_call_data);

    // 设置外部调用行为的标志位
    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(())
}

Claim Verification

领取验证

Verify claims on the receiving side:
在接收方验证领取请求:

Validate Incoming Claims

验证 incoming 领取请求

rust
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(())
}
rust
use debridge_solana_sdk::check_claiming::*;

pub fn receive_tokens(ctx: Context<ReceiveTokens>) -> Result<()> {
    // 获取并验证父级领取指令
    let claim_ix = ValidatedExecuteExtCallIx::try_from_current_ix()?;

    // 验证提交详情
    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,
    )?;

    // 继续执行领取逻辑
    Ok(())
}

Get Submission Key

获取提交密钥

rust
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)
}
rust
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)
}

Fee Queries

费用查询

Get Transfer Fees

获取转账费用

rust
// 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,
)?;
rust
// 获取基础转账费用(基点)
let transfer_fee = debridge_sending::get_transfer_fee(
    ctx.remaining_accounts,
)?;

// 获取特定链的转账费用
let chain_fee = debridge_sending::get_transfer_fee_for_chain(
    &target_chain_id,
    ctx.remaining_accounts,
)?;

// 获取默认原生固定费用
let default_fee = debridge_sending::get_default_native_fix_fee(
    ctx.remaining_accounts,
)?;

// 获取链专属原生固定费用
let native_fee = debridge_sending::get_chain_native_fix_fee(
    &target_chain_id,
    ctx.remaining_accounts,
)?;

// 获取链的资产固定费用
let asset_fee = debridge_sending::try_get_chain_asset_fix_fee(
    &target_chain_id,
    ctx.remaining_accounts,
)?;

Calculate Total Amount with Fees

计算包含费用的总金额

rust
// 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,
)?;
rust
// 为金额添加转账费用
let with_transfer_fee = debridge_sending::add_transfer_fee(
    amount,
    ctx.remaining_accounts,
)?;

// 添加所有费用(转账费+执行费+资产费)
let total_amount = debridge_sending::add_all_fees(
    amount,
    &target_chain_id,
    ctx.remaining_accounts,
)?;

Chain Support Queries

链支持查询

rust
// 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,
)?;
rust
// 检查链是否受支持
let is_supported = debridge_sending::is_chain_supported(
    &target_chain_id,
    ctx.remaining_accounts,
)?;

// 获取链支持信息
let chain_info = debridge_sending::get_chain_support_info(
    &target_chain_id,
    ctx.remaining_accounts,
)?;

// 检查是否支持资产费用
let asset_fee_available = debridge_sending::is_asset_fee_available(
    &target_chain_id,
    ctx.remaining_accounts,
)?;

PDA Derivation

PDA推导

Bridge Account

桥接账户

rust
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)?;
rust
use debridge_solana_sdk::keys::*;

// 为代币铸币地址推导桥接PDA
let (bridge_address, bump) = BridgePubkey::find_bridge_address(&token_mint);

// 使用已知bump创建桥接地址
let bridge_address = BridgePubkey::create_bridge_address(&token_mint, bump)?;

Chain Support Info

链支持信息

rust
// Find chain support info PDA
let (chain_support_info, bump) = ChainSupportInfoPubkey::find_chain_support_info_address(
    &target_chain_id,
);
rust
// 推导链支持信息PDA
let (chain_support_info, bump) = ChainSupportInfoPubkey::find_chain_support_info_address(
    &target_chain_id,
);

Asset Fee Info

资产费用信息

rust
// 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();
rust
// 推导资产费用信息PDA
let (asset_fee_info, bump) = AssetFeeInfoPubkey::find_asset_fee_info_address(
    &bridge_pubkey,
    &target_chain_id,
);

// 获取默认桥接费用地址
let default_fee = AssetFeeInfoPubkey::default_bridge_fee_address();

External Call Storage

外部调用存储

rust
// 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,
);
rust
// 推导外部调用存储PDA
let (storage, bump) = ExternalCallStoragePubkey::find_external_call_storage_address(
    &shortcut,
    &owner,
);

// 推导外部调用元数据PDA
let (meta, bump) = ExternalCallMetaPubkey::find_external_call_meta_address(
    &storage_account,
);

Required Accounts

所需账户

The SDK requires specific accounts passed via
remaining_accounts
. The account order is important:
IndexAccountSignerWritableDescription
0BridgeNoYesBridge account for token
1Token MintNoNoSPL Token mint
2Staking WalletNoYesStaking rewards wallet
3Mint AuthorityNoNoToken mint authority
4Chain Support InfoNoNoTarget chain config
5Settings ProgramNoNodeBridge settings
6SPL Token ProgramNoNoToken program
7StateNoNoProtocol state
8deBridge ProgramNoNoMain deBridge program
...Additional accounts--Varies by operation
SDK要求通过
remaining_accounts
传入特定账户,账户顺序非常重要:
索引账户签名方可写描述
0Bridge代币对应的桥接账户
1Token MintSPL代币铸币地址
2Staking Wallet质押奖励钱包
3Mint Authority代币铸币权限
4Chain Support Info目标链配置
5Settings ProgramdeBridge设置程序
6SPL Token Program代币程序
7State协议状态
8deBridge Program主deBridge程序
...其他账户--随操作类型变化

TypeScript Client Integration

TypeScript客户端集成

Setup

设置

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');
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');

Build Send Transaction

构建发送交易

typescript
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);
}
typescript
import {
  TOKEN_PROGRAM_ID,
  getAssociatedTokenAddress
} from '@solana/spl-token';

async function buildSendTransaction(
  tokenMint: PublicKey,
  amount: bigint,
  targetChainId: Uint8Array,
  receiver: Uint8Array,
): Promise<Transaction> {
  // 推导所需PDA
  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
  );

  // 构建包含剩余账户的指令
  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 },
      // ... 其他所需账户
    ])
    .instruction();

  return new Transaction().add(instruction);
}

Build External Call Data

构建外部调用数据

typescript
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')]
);
typescript
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 };
}

// 示例:ERC20授权调用
const { data, shortcut } = buildExternalCallData(
  '0xTargetContract...',
  'function approve(address spender, uint256 amount)',
  ['0xSpenderAddress...', ethers.parseEther('1000')]
);

Testing

测试

Anchor Test Setup

Anchor测试设置

toml
undefined
toml
undefined

Anchor.toml

Anchor.toml

[provider] cluster = "mainnet" # Use mainnet for testing with real deBridge
[programs.mainnet] my_program = "YourProgramId..."
undefined
[provider] cluster = "mainnet" # 使用主网测试真实deBridge
[programs.mainnet] my_program = "YourProgramId..."
undefined

Run Tests

运行测试

bash
undefined
bash
undefined

Full build and test

完整构建并测试

cd example_program && anchor build && anchor test
cd example_program && anchor build && anchor test

Test only (skip rebuild)

仅测试(跳过重新构建和部署)

anchor test --skip-build --skip-deploy
undefined
anchor test --skip-build --skip-deploy
undefined

Local Testing Tips

本地测试技巧

  1. Use Mainnet Fork: deBridge infrastructure is on mainnet
  2. Mock Remaining Accounts: Create mock accounts for unit tests
  3. Test Fee Calculations: Verify fee amounts before sending
  1. 使用主网分叉:deBridge基础设施部署在主网
  2. 模拟剩余账户:为单元测试创建模拟账户
  3. 测试费用计算:发送前验证费用金额

Build Features

构建特性

The SDK supports different environments via Cargo features:
toml
undefined
SDK通过Cargo特性支持不同环境:
toml
undefined

Production (default) - uses hardcoded program IDs

生产环境(默认)- 使用硬编码程序ID

debridge-solana-sdk = { git = "..." }
debridge-solana-sdk = { git = "..." }

Custom environment - uses env vars

自定义环境 - 使用环境变量

debridge-solana-sdk = { git = "...", features = ["env"] }

Environment variables for custom networks:
- `DEBRIDGE_PROGRAM_PUBKEY`: Custom deBridge program ID
- `DEBRIDGE_SETTINGS_PROGRAM_PUBKEY`: Custom settings program ID
debridge-solana-sdk = { git = "...", features = ["env"] }

自定义网络的环境变量:
- `DEBRIDGE_PROGRAM_PUBKEY`: 自定义deBridge程序ID
- `DEBRIDGE_SETTINGS_PROGRAM_PUBKEY`: 自定义设置程序ID

Resources

资源

Skill Structure

Skill结构

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
debridge/
├── SKILL.md                          # 本文档
├── resources/
│   ├── sdk-api-reference.md          # 完整SDK API参考
│   ├── chain-ids.md                  # 支持的链标识符
│   ├── program-ids.md                # 程序ID和PDA
│   └── error-codes.md                # 错误类型与处理
├── examples/
│   ├── basic-transfer/               # 简单跨链转账
│   ├── external-calls/               # 外部调用执行
│   ├── message-passing/              # 纯消息转账
│   └── fee-configurations/           # 费用支付选项
└── docs/
    └── troubleshooting.md            # 常见问题与解决方案