You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Substrate中能否从函数入参Call提取pallet及函数数据实现自定义手续费

问题解答

你完全可以从Call类型参数中获取所属pallet、调用函数名及所有入参,基于调用参数自定义手续费的需求可以实现。

核心原理

Substrate的Runtime Call本质是自动生成的聚合枚举类型:

  • 每个一级枚举变体对应Runtime中集成的一个pallet
  • 每个pallet对应的二级枚举变体对应该pallet下的所有可调用函数,变体字段就是该函数的入参

具体实现方式

1. 针对特定调用硬匹配(适配staking::bond场景)

直接在pre_dispatch或者你自定义的手续费计算逻辑中对call做模式匹配,直接取出对应参数计算手续费,示例代码如下:

use pallet_staking::Call as StakingCall;

fn withdraw_fee(
    &self,
    who: &Self::AccountId,
    call: &Self::Call,
    info: &DispatchInfoOf<Self::Call>,
    len: usize
) -> Result<(BalanceOf<Self>, Imbalance<Self>), TransactionValidityError> {
    // 先匹配目标pallet和目标调用
    let custom_fee = match call {
        // 匹配staking pallet的bond调用,直接取出绑定金额value
        RuntimeCall::Staking(StakingCall::bond { value, .. }) => {
            // 自定义逻辑:例如按绑定金额的千分之一收取手续费
            value.saturating_mul(1u32.into()).saturating_div(1000u32.into())
        },
        // 其他调用走默认手续费计算逻辑
        _ => {
            // 原有默认手续费计算逻辑,比如基于权重和交易长度计算
            Self::default_fee_calculation(info, len)
        }
    };

    // 后续手续费扣除逻辑沿用原有实现即可
    // ...
}

2. 通用获取pallet名、函数名的方法

如果需要批量处理多个调用、不想逐个硬匹配,可直接调用Call类型实现的GetCallName trait提供的方法:

  • call.get_pallet_name():返回调用所属pallet的字符串名称,例如"Staking"
  • call.get_call_name():返回被调用函数的字符串名称,例如"bond"

注意事项

  • 自定义手续费逻辑需要做好数值溢出防护,建议统一使用saturating_*系列安全计算方法
  • 建议设置手续费兜底规则:比如自定义计算的手续费低于最小基础手续费时,按最小基础手续费收取,避免超低额交易手续费为0的问题
  • 若不需要完全重写交易手续费逻辑,仅扩展原有transaction-payment pallet的手续费计算规则即可,不需要替换整个pallet实现

内容的提问来源于stack exchange,提问作者Makam Aravind

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 06:54:00