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),
}
}
功能说明
-
XCM消息发送:
- 构建目标链的位置(MultiLocation)
- 定义XCM指令(如TransferAsset)
- 通过XcmPallet发送消息
-
XCM消息接收:
- 实现XCM消息处理逻辑
- 解析各种XCM指令
- 执行相应的跨链操作
-
资产转移:
- 定义资产类型和数量
- 指定接收方账户
- 处理跨链资产转移
注意事项
- 需要根据实际链配置调整参数类型
- XCM版本需要与目标链兼容
- 资产转换器需要正确实现本地资产与XCM资产的映射
以上示例展示了完整的XCM消息发送和接收流程,以及资产转移的实现。实际使用时需要根据具体链的配置进行调整和完善。
1 回复
Rust跨链通信库cumulus-pallet-xcm使用指南
概述
cumulus-pallet-xcm
是Polkadot生态系统中用于实现跨共识系统通信(XCM)的关键库,它允许不同平行链之间发送和接收XCM消息,实现跨链资产转移和智能合约调用。
主要功能
- 发送和接收XCM消息
- 跨链资产转移
- 跨链智能合约调用
- 支持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),
}
注意事项
- 确保链的XCM配置正确,包括支持的资产、权重限制等
- 注意XCM版本兼容性
- 考虑XCM执行费用和权重限制
- 测试网络先行,确保XCM消息能够正确传递和执行
最佳实践
- 使用
xcm-builder
简化XCM配置 - 为常见操作创建预编译XCM消息模板
- 实现监控机制跟踪XCM消息状态
- 考虑XCM消息的原子性和错误处理
通过cumulus-pallet-xcm
,开发者可以构建强大的跨链应用,实现Polkadot生态系统中不同链之间的无缝互操作。