Rust资产转换与交易支付插件pallet-asset-conversion-tx-payment的使用:实现多链资产互换与手续费支付功能

pallet-asset-conversion-tx-payment

资产转换交易支付Pallet

该pallet允许包含它的运行时(runtime)使用除链原生代币以外的资产支付交易费用。

概述

通过扩展交易来包含一个可选的AssetId(默认None表示使用原生代币),该pallet实现了用指定资产支付交易费用的功能。它需要一个类似pallet-transaction-paymentOnChargeAssetTransaction实现。内置的AssetConversionAdapter(实现了OnChargeAssetTransaction)通过将pallet-transaction-payment计算出的手续费转换成所需资产来确定费用金额。

集成

该pallet封装了FRAME的交易支付pallet并作为其替代品。这意味着你应在construct_runtime宏中同时包含这两个pallet,但只需包含该pallet的TransactionExtension(ChargeAssetTxPayment)。

许可证: Apache-2.0

完整示例代码

// 在runtime/src/lib.rs中的集成示例

use frame_support::{
    construct_runtime,
    pallet_prelude::*,
    traits::Currency,
};

// 引入必要的pallet
pub use pallet_asset_conversion_tx_payment;
pub use pallet_transaction_payment;

// 配置交易支付pallet
impl pallet_transaction_payment::Config for Runtime {
    type OnChargeTransaction = pallet_asset_conversion_tx_payment::AssetConversionAdapter<Self>;
    // 其他配置...
}

// 配置资产转换交易支付pallet
impl pallet_asset_conversion_tx_payment::Config for Runtime {
    type Event = Event;
    type OnChargeAssetTransaction = pallet_asset_conversion_tx_payment::AssetConversionAdapter<Self>;
    // 其他配置...
}

construct_runtime!(
    pub enum Runtime where
        Block = Block,
        NodeBlock = opaque::Block,
        UncheckedExtrinsic = UncheckedExtrinsic
    {
        // 包含原生交易支付pallet
        TransactionPayment: pallet_transaction_payment,
        // 包含资产转换交易支付pallet
        AssetConversionTxPayment: pallet_asset_conversion_tx_payment,
        // 其他pallet...
    }
);

// 在runtime/src/lib.rs中实现交易扩展
impl frame_system::offchain::CreateTransaction<Runtime, UncheckedExtrinsic> for Runtime {
    type Public = <Signature as Verify>::Signer;
    type Signature = Signature;

    fn create_transaction<C: frame_system::offchain::AppCrypto<Self::Public, Self::Signature>>(
        call: Call,
        public: Self::Public,
        account: AccountId,
        nonce: Index,
    ) -> Option<(Call, <UncheckedExtrinsic as ExtrinsicT>::SignaturePayload)> {
        // 使用资产转换交易支付扩展
        let tip = 0.into();
        let asset_id = None; // None表示使用原生代币,Some(asset_id)表示使用指定资产
        
        let extra: pallet_asset_conversion_tx_payment::ChargeAssetTxPayment<Runtime> = 
            pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::from(tip, asset_id);
        
        Some((call, (account, nonce, extra)))
    }
}

更完整的集成示例

// runtime/src/lib.rs

#![cfg_attr(not(feature = "std"), no_std)]

use sp_std::prelude::*;
use frame_support::{
    construct_runtime, parameter_types,
    traits::{Currency, Imbalance, OnUnbalanced},
    weights::{Weight, DispatchClass},
};
use frame_system::EnsureRoot;
use pallet_transaction_payment::CurrencyAdapter;

// 定义原生代币类型
pub type Balance = u128;
pub type Amount = i128;

parameter_types! {
    pub const ExistentialDeposit: Balance = 1;
}

impl pallet_balances::Config for Runtime {
    type Balance = Balance;
    type DustRemoval = ();
    type Event = Event;
    type ExistentialDeposit = ExistentialDeposit;
    type AccountStore = System;
    type MaxLocks = ();
    type WeightInfo = ();
}

parameter_types! {
    pub const TransactionByteFee: Balance = 1;
    pub const OperationalFeeMultiplier: u8 = 5;
}

impl pallet_transaction_payment::Config for Runtime {
    type OnChargeTransaction = pallet_asset_conversion_tx_payment::AssetConversionAdapter<Self>;
    type TransactionByteFee = TransactionByteFee;
    type OperationalFeeMultiplier = OperationalFeeMultiplier;
    type WeightToFee = IdentityFee<Balance>;
    type FeeMultiplierUpdate = ();
}

impl pallet_asset_conversion_tx_payment::Config for Runtime {
    type Event = Event;
    type OnChargeAssetTransaction = pallet_asset_conversion_tx_payment::AssetConversionAdapter<Self>;
}

construct_runtime!(
    pub enum Runtime where
        Block = Block,
        NodeBlock = opaque::Block,
        UncheckedExtrinsic = UncheckedExtrinsic
    {
        System: frame_system,
        Balances: pallet_balances,
        TransactionPayment: pallet_transaction_payment,
        AssetConversionTxPayment: pallet_asset_conversion_tx_payment,
    }
);

// 实现交易扩展
impl frame_system::offchain::CreateTransaction<Runtime, UncheckedExtrinsic> for Runtime {
    type Public = <Signature as Verify>::Signer;
    type Signature = Signature;

    fn create_transaction<C: frame_system::offchain::AppCrypto<Self::Public, Self::Signature>>(
        call: Call,
        public: Self::Public,
        account: AccountId,
        nonce: Index,
    ) -> Option<(Call, <UncheckedExtrinsic as ExtrinsicT>::SignaturePayload)> {
        let tip = 0.into();
        // 使用资产ID 1作为示例
        let asset_id = Some(1);
        
        let extra: pallet_asset_conversion_tx_payment::ChargeAssetTxPayment<Runtime> = 
            pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::from(tip, asset_id);
        
        Some((call, (account, nonce, extra)))
    }
}

安装

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

cargo add pallet-asset-conversion-tx-payment

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

pallet-asset-conversion-tx-payment = "23.0.0"

1 回复

Rust资产转换与交易支付插件pallet-asset-conversion-tx-payment的使用

介绍

pallet-asset-conversion-tx-payment是Substrate框架中的一个功能强大的模块,它实现了两个核心功能:

  1. 多链资产互换功能
  2. 使用任意资产支付交易手续费

这个模块特别适合需要处理多种资产类型的区块链项目,允许用户使用非原生代币支付交易费用,并简化了不同资产之间的兑换流程。

主要功能

  1. 资产转换:支持不同资产之间的互换
  2. 手续费支付:允许使用非原生代币支付交易费用
  3. 多链兼容:设计用于跨链资产交互场景

完整示例代码

以下是使用pallet-asset-conversion-tx-payment的完整示例:

// 1. 在runtime中集成pallet
impl pallet_asset_conversion_tx_payment::Config for Runtime {
    type RuntimeEvent = RuntimeEvent;
    type OnChargeAssetTransaction = pallet_asset_conversion_tx_payment::FungiblesAdapter<
        pallet_assets::BalanceToAssetBalance<Balances, Runtime, ConvertInto>,
        pallet_assets::Assets<Runtime>,
    >;
    type AssetId = u32;  // 资产ID类型
    type Balance = u128; // 余额类型
    type Currency = Balances; // 原生代币模块
    type Assets = Assets; // 资产模块
}

// 2. 配置参数
parameter_types! {
    pub const AssetConversionTxPaymentPalletId: PalletId = PalletId(*b"py/ascon");
    pub const MaxPaymentAssets: u32 = 10; // 最大支持的支付资产数量
}

// 3. 资产转换操作示例
fn swap_assets(
    origin: OriginFor<Runtime>,
    asset1: u32,
    asset2: u32,
    asset3: u32,
    amount_in: u128,
    amount_out_min: u128,
    recipient: AccountId,
    deadline: BlockNumber,
) -> DispatchResult {
    // 创建兑换路径
    let path = vec![asset1, asset2, asset3];
    
    // 执行资产兑换
    let amount_out = AssetConversion::swap_exact_tokens_for_tokens(
        origin,
        amount_in,
        amount_out_min,
        path,
        recipient,
        deadline,
    )?;
    
    Ok(())
}

// 4. 设置支付资产示例
fn set_payment_asset(api: &RuntimeApi, asset_id: u32) -> Result<(), Error> {
    // 创建调用
    let call = Call::AssetConversionTxPayment::set_payment_asset { asset_id };
    
    // 创建并提交交易
    let tx = Extrinsic::new(call, None);
    api.submit_extrinsic(tx)?;
    
    Ok(())
}

// 5. 查询支付资产示例
fn get_payment_assets(account_id: AccountId) -> Vec<u32> {
    // 查询可用于支付手续费的资产列表
    AssetConversionTxPayment::payment_assets(account_id)
}

最佳实践

  1. 兑换路径优化:尽量使用直接兑换路径以减少费用
  2. 滑点保护:设置合理的amount_out_min防止大幅滑点
  3. 手续费评估:在使用非原生代币支付时,先估算手续费成本

注意事项

  1. 确保资产模块已正确配置并支持所需功能
  2. 兑换操作可能需要支付额外的网络费用
  3. 不同资产的兑换率可能会波动

这个模块为多资产区块链应用提供了极大的灵活性,特别是在DeFi和跨链应用场景中特别有用。

回到顶部