Rust跨链通信库cumulus-pallet-xcm的使用,实现Polkadot生态XCM消息跨共识传输与资产转移

Rust跨链通信库cumulus-pallet-xcm的使用,实现Polkadot生态XCM消息跨共识传输与资产转移

安装

在项目目录中运行以下Cargo命令:

cargo add cumulus-pallet-xcm

或者在Cargo.toml中添加以下行:

cumulus-pallet-xcm = "0.21.0"

示例代码

以下是使用cumulus-pallet-xcm实现跨链通信和资产转移的完整示例:

use frame_support::{parameter_types, traits::Everything};
use xcm::latest::prelude::*;
use cumulus_pallet_xcm::{Config, Origin};

parameter_types! {
    pub const RelayLocation: MultiLocation = MultiLocation::parent();
    pub const AnyNetwork: NetworkId = NetworkId::Any;
    pub const UnitWeightCost: u64 = 1_000;
    pub const MaxInstructions: u32 = 100;
}

pub struct XcmConfig;
impl Config for XcmConfig {
    type RuntimeEvent = ();
    type XcmRouter = ();
    type SendXcmOrigin = Origin;
    type XcmExecuteFilter = Everything;
    type XcmExecutor = ();
    type Weigher = ();
    type LocationInverter = ();
    type AdvertisedXcmVersion = ();
    
    // 定义如何将本地资产转换为XCM资产
    type ConvertedConcreteId = ();
    type CurrencyMatcher = ();
    type CurrencyTransactor = ();
    type OriginConverter = ();
    type IsReserve = ();
    type Barrier = ();
    type Weigher = ();
}

// 发送XCM消息示例
fn send_xcm_message() {
    let dest = MultiLocation::new(
        1,
        X1(Junction::Parachain(1000))
    );
    
    let message = Xcm(vec![
        // 指令示例:转账资产
        TransferAsset {
            assets: vec![(Concrete(MultiLocation::here()), 100u128).into()],
            beneficiary: MultiLocation::new(
                0,
                X1(AccountId32 {
                    network: NetworkId::Any,
                    id: [0u8; 32],
                })
            ),
        },
    ]);
    
    // 实际发送XCM消息
    // XcmPallet::send(dest, message).unwrap();
}

// 接收XCM消息示例
fn handle_xcm_message(message: Xcm<()>) {
    match message {
        Xcm(instructions) => {
            for instruction in instructions {
                match instruction {
                    // 处理转账指令
                    TransferAsset { assets, beneficiary } => {
                        // 实现资产转移逻辑
                        println!("Received transfer asset instruction");
                    },
                    _ => println!("Unsupported XCM instruction"),
                }
            }
        }
    }
}

完整示例代码

以下是一个更完整的实现示例,包含了XCM消息发送和接收的完整流程:

use frame_support::{
    parameter_types, traits::Everything, weights::Weight,
    PalletId,
};
use xcm::latest::{
    prelude::*, 
    Junction::*, 
    MultiLocation, 
    NetworkId,
    Weight as XcmWeight
};
use cumulus_pallet_xcm::{Config, Origin};
use sp_runtime::traits::AccountIdConversion;
use sp_std::marker::PhantomData;

// 定义参数类型
parameter_types! {
    pub const RelayNetwork: NetworkId = NetworkId::Kusama;
    pub const RelayLocation: MultiLocation = MultiLocation::parent();
    pub const SelfLocation: MultiLocation = MultiLocation::here();
    pub const MaxAssetsForTransfer: usize = 2;
    pub const UnitWeightCost: u64 = 1_000_000;
    pub const MaxInstructions: u32 = 100;
}

// 自定义XCM配置结构体
pub struct OurXcmConfig;
impl Config for OurXcmConfig {
    type RuntimeEvent = RuntimeEvent;
    type XcmRouter = XcmRouter;
    type SendXcmOrigin = Origin;
    type XcmExecuteFilter = Everything;
    type XcmExecutor = XcmExecutor;
    type Weigher = Weigher;
    type LocationInverter = LocationInverter;
    type AdvertisedXcmVersion = AdvertisedXcmVersion;
    
    // 资产转换相关配置
    type ConvertedConcreteId = ConvertedConcreteId;
    type CurrencyMatcher = CurrencyMatcher;
    type CurrencyTransactor = CurrencyTransactor;
    type OriginConverter = OriginConverter;
    type IsReserve = IsReserve;
    type Barrier = Barrier;
}

// 实现XCM消息发送
pub fn send_transfer(
    dest: MultiLocation,
    assets: MultiAssets,
    beneficiary: MultiLocation,
) -> Result<(), SendError> {
    let message = Xcm(vec![
        WithdrawAsset(assets.clone()),
        BuyExecution {
            fees: assets,
            weight_limit: Unlimited,
        },
        DepositAsset {
            assets: Wild(All),
            max_assets: MaxAssetsForTransfer::get(),
            beneficiary,
        },
    ]);

    XcmPallet::<Runtime>::send(dest, message)
}

// 实现XCM消息处理
impl xcm_executor::traits::OnResponse for OurXcmConfig {
    fn expecting_response(
        _origin: &MultiLocation,
        _query_id: u64,
    ) -> bool {
        false
    }

    fn on_response(
        _origin: &MultiLocation,
        _query_id: u64,
        _response: Response,
        _max_weight: XcmWeight,
    ) -> Weight {
        0
    }
}

// 主函数示例
fn main() {
    // 示例:发送跨链转账
    let dest = MultiLocation::new(
        1,
        X1(Parachain(2000))  // 目标平行链ID
    );
    
    let assets: MultiAssets = vec![
        (Concrete(MultiLocation::here()), 100u128).into()
    ];
    
    let beneficiary = MultiLocation::new(
        0,
        X1(AccountId32 {
            network: NetworkId::Any,
            id: [1u8; 32],  // 接收方账户ID
        })
    );
    
    match send_transfer(dest, assets, beneficiary) {
        Ok(_) => println!("XCM transfer sent successfully"),
        Err(e) => println!("Failed to send XCM transfer: {:?}", e),
    }
}

功能说明

  1. XCM消息发送:

    • 构建目标链的位置(MultiLocation)
    • 定义XCM指令(如TransferAsset)
    • 通过XcmPallet发送消息
  2. XCM消息接收:

    • 实现XCM消息处理逻辑
    • 解析各种XCM指令
    • 执行相应的跨链操作
  3. 资产转移:

    • 定义资产类型和数量
    • 指定接收方账户
    • 处理跨链资产转移

注意事项

  • 需要根据实际链配置调整参数类型
  • XCM版本需要与目标链兼容
  • 资产转换器需要正确实现本地资产与XCM资产的映射

以上示例展示了完整的XCM消息发送和接收流程,以及资产转移的实现。实际使用时需要根据具体链的配置进行调整和完善。


1 回复

Rust跨链通信库cumulus-pallet-xcm使用指南

概述

cumulus-pallet-xcm是Polkadot生态系统中用于实现跨共识系统通信(XCM)的关键库,它允许不同平行链之间发送和接收XCM消息,实现跨链资产转移和智能合约调用。

主要功能

  1. 发送和接收XCM消息
  2. 跨链资产转移
  3. 跨链智能合约调用
  4. 支持Polkadot、Kusama等基于Substrate的链

基本使用方法

1. 添加依赖

[dependencies]
cumulus-pallet-xcm = { git = "https://github.com/paritytech/cumulus.git", branch = "polkadot-vX.Y.Z" }

2. 在runtime中集成

impl pallet_xcm::Config for Runtime {
    type Event = Event;
    type SendXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;
    type XcmRouter = XcmRouter;
    type ExecuteXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;
    type XcmExecuteFilter = Everything;
    type XcmExecutor = XcmExecutor<XcmConfig>;
    type XcmTeleportFilter = Everything;
    type XcmReserveTransferFilter = Everything;
    type Weigher = FixedWeightBounds<BaseXcmWeight, Call, MaxInstructions>;
    type LocationInverter = LocationInverter<Ancestry>;
    type Origin = Origin;
    type Call = Call;
}

示例代码

发送XCM消息

use xcm::latest::prelude::*;

// 定义目标链位置(平行链ID 2000)
let dest = MultiLocation::new(
    1,
    X1(Parachain(2000))
);

// 构建XCM消息
let message = Xcm(vec![
    // 从本地账户提取100单位资产
    WithdrawAsset((Here, 100u128).into()),
    // 支付执行费用
    BuyExecution {
        fees: (Here, 1u128).into(),
        weight_limit: Limited(100_000_000),
    },
    // 将资产存入目标链的ALICE账户
    DepositAsset {
        assets: All.into(),
        max_assets: 1,
        beneficiary: MultiLocation::new(
            0,
            X1(AccountId32 {
                network: NetworkId::Any,
                id: ALICE.into(),
            }),
        ),
    },
]);

// 发送XCM消息
pallet_xcm::Pallet::<T>::send_xcm(Here, dest, message)?;

接收XCM消息配置

impl pallet_xcm::Config for Runtime {
    // ... 其他配置
    
    // 配置XCM执行器
    type ExecuteXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;
    type XcmExecutor = XcmExecutor<XcmConfig>;
}

// XCM执行器配置
pub struct XcmConfig;
impl xcm_executor::Config for XcmConfig {
    type Call = Call;
    type XcmSender = XcmRouter;
    type AssetTransactor = LocalAssetTransactor;
    type OriginConverter = LocalOriginConverter;
    type IsReserve = NativeAsset;
    type IsTeleporter = ();
    type LocationInverter = LocationInverter<Ancestry>;
    type Barrier = Barrier;
    type Weigher = FixedWeightBounds<BaseXcmWeight, Call, MaxInstructions>;
    type Trader = FixedRateOfFungible<WeightPrice, ()>;
    type ResponseHandler = ();
    type AssetTrap = ();
    type AssetClaims = ();
    type SubscriptionService = ();
}

跨链资产转移

use xcm::latest::prelude::*;

// 定义目标链(平行链ID 2000)
let dest = MultiLocation::new(
    1,
    X1(Parachain(2000))
);

// 定义接收方账户(BOB)
let beneficiary = MultiLocation::new(
    0,
    X1(AccountId32 {
        network: NetworkId::Any,
        id: BOB.into(),
    }),
);

// 定义转移资产(100单位本地资产)
let assets = MultiAssets::from((Here, 100u128));

// 执行资产转移
pallet_xcm::Pallet::<T>::limited_reserve_transfer_assets(
    Origin::signed(ALICE),  // 发送方
    Box::new(dest.into()),  // 目标链
    Box::new(beneficiary.into()),  // 接收方
    Box::new(assets.into()),  // 转移资产
    0,  // 费用
    Unlimited,  // 权重限制
)?;

完整示例

下面是一个完整的跨链资产转移示例,包含runtime配置和调用代码:

// runtime/src/lib.rs

// 1. 配置XCM pallet
impl pallet_xcm::Config for Runtime {
    type Event = Event;
    type SendXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;
    type XcmRouter = XcmRouter;
    type ExecuteXcmOrigin = EnsureXcmOrigin<Origin, LocalOriginToLocation>;
    type XcmExecuteFilter = Everything;
    type XcmExecutor = XcmExecutor<XcmConfig>;
    type XcmTeleportFilter = Everything;
    type XcmReserveTransferFilter = Everything;
    type Weigher = FixedWeightBounds<BaseXcmWeight, Call, MaxInstructions>;
    type LocationInverter = LocationInverter<Ancestry>;
    type Origin = Origin;
    type Call = Call;
}

// 2. 定义XCM执行器配置
pub struct XcmConfig;
impl xcm_executor::Config for XcmConfig {
    type Call = Call;
    type XcmSender = XcmRouter;
    type AssetTransactor = LocalAssetTransactor;
    type OriginConverter = LocalOriginConverter;
    type IsReserve = NativeAsset;
    type IsTeleporter = ();
    type LocationInverter = LocationInverter<Ancestry>;
    type Barrier = Barrier;
    type Weigher = FixedWeightBounds<BaseXcmWeight, Call, MaxInstructions>;
    type Trader = FixedRateOfFungible<WeightPrice, ()>;
    type ResponseHandler = ();
    type AssetTrap = ();
    type AssetClaims = ();
    type SubscriptionService = ();
}

// 3. 调用示例
pub fn transfer_assets_to_parachain(
    origin: OriginFor<T>,
    dest_para_id: u32,
    beneficiary: AccountId,
    amount: Balance,
) -> DispatchResult {
    use xcm::latest::prelude::*;
    
    // 验证调用者签名
    let sender = ensure_signed(origin)?;
    
    // 构建目标位置
    let dest = MultiLocation::new(
        1,
        X1(Parachain(dest_para_id))
    );
    
    // 构建接收方位置
    let beneficiary = MultiLocation::new(
        0,
        X1(AccountId32 {
            network: NetworkId::Any,
            id: beneficiary.into(),
        }),
    );
    
    // 构建转移资产
    let assets = MultiAssets::from((Here, amount));
    
    // 执行资产转移
    pallet_xcm::Pallet::<T>::limited_reserve_transfer_assets(
        Origin::signed(sender),
        Box::new(dest.into()),
        Box::new(beneficiary.into()),
        Box::new(assets.into()),
        0,
        Unlimited,
    )
}

高级用法

自定义XCM指令

let custom_message = Xcm(vec![
    Transact {
        origin_type: OriginKind::SovereignAccount,
        require_weight_at_most: 1_000_000_000,
        call: <T as pallet_xcm::Config>::Call::from(
            pallet_balances::Call::transfer {
                dest: BOB.into(),
                value: 50,
            }
        ).encode().into(),
    }
]);

错误处理

match pallet_xcm::Pallet::<T>::send_xcm(Here, dest, message) {
    Ok(()) => log::info!("XCM发送成功"),
    Err(e) => log::error!("XCM发送失败: {:?}", e),
}

注意事项

  1. 确保链的XCM配置正确,包括支持的资产、权重限制等
  2. 注意XCM版本兼容性
  3. 考虑XCM执行费用和权重限制
  4. 测试网络先行,确保XCM消息能够正确传递和执行

最佳实践

  1. 使用xcm-builder简化XCM配置
  2. 为常见操作创建预编译XCM消息模板
  3. 实现监控机制跟踪XCM消息状态
  4. 考虑XCM消息的原子性和错误处理

通过cumulus-pallet-xcm,开发者可以构建强大的跨链应用,实现Polkadot生态系统中不同链之间的无缝互操作。

回到顶部