Search code examples
substrateparitypolkadot

Match by call name and parameters, for a call from other pallets


I have a module method that associates fixed fees to Calls from various pallets. So I'm trying to match a Call passed to my method as a parameter by pallet, Call name, and Call parameters.

Something similar to this:

impl<T: Config> Module<T>
{
    fn compute_call_fee_(call: &<T as Config>::Call) -> Result<u64, &'static str> {
        let fee = match *call {
            Call::PalletA(palletA::Call::name_of_palletA_call(x,y)) => 50u64, // here this is not real syntax, this is what I need to figure out
            _ => 100u64
        };

        Ok(fee)
    }
}

for the case above the Config trait would implement the Config traits from the different pallets matched on:

pub trait Config: system::Config + palletA::Config + palletB::Config {
    type Call: Parameter + Dispatchable<Origin = Self::Origin> + GetDispatchInfo;
}

How can I match on call by origin pallet, function name, and function arguments ?

I've tried:

  • using similar syntax as above, without success

  • making the Config::Call implement GetCallMetadata: this only get me the origin pallet and function name, not the parameters

  • making the call implement IsSubType, and following this answer: How to decode and match a call when passed as a parameter in Substrate. This is not related to Calls from other pallets if I get it right.

    For using IsSubType, I've added it as a trait bound to the impl block rather than in the Config trait:

    impl<T: Config> Module<T>
    where
         <T as Config>::Call: IsSubType<Call<T>>, 
    {
        fn compute_call_fee_(call: &<T as Config>::Call) -> Result<u64, &'static str> {
            if let Some(local_call) = call.is_sub_type() {
                return match local_call {
                    palletA::Call::name_of_palletA_call(x,y) => Ok(42u64),
                    _ => Ok(0u64),
                }
            }
            Ok(21u64)
        }
    }
    

Solution

  • Hard to say until you paste your full code (specifically the type Call = xxx piece), but I can guess that what you miss is: type Call: IsSubType<pallet_balances::Call<Self>>;. You mentioned another question that recomended the same, but I can guess that you didn't use it correctly.

    Note that overall, the outer Call (the one which you are passing into your pallet here via type Call) implements two things:

    • From<pallet_call> for each individual pallet call. This will allow you to always convert an inner Call into an outer Call.
    • IsSubType<pallet_call> for each individual pallet call. This will allow you to conditionally convert an outer call into an inner call, if it exists.

    Perhaps the naming could have been a bit better here. I will consider at least renaming the outer Call to.. OuterCall.

    Lastly, definitely recommend running a cargo expand on the node template and look for enum Call.

    TLDR; this diff will work if you apply it on top of node-template, should answer your question as well.

    diff --git a/bin/node-template/pallets/template/Cargo.toml b/bin/node-template/pallets/template/Cargo.toml
    index 12b810de1..6f91e8c9a 100644
    --- a/bin/node-template/pallets/template/Cargo.toml
    +++ b/bin/node-template/pallets/template/Cargo.toml
    @@ -25,6 +25,11 @@ default-features = false
     version = "2.0.0"
     path = "../../../../frame/system"
     
    +[dependencies.pallet-balances]
    +default-features = false
    +version = "2.0.0"
    +path = "../../../../frame/balances"
    +
     [dev-dependencies.sp-core]
     default-features = false
     version = "2.0.0"
    @@ -46,5 +51,6 @@ default = ['std']
     std = [
        'codec/std',
        'frame-support/std',
    -   'frame-system/std'
    +   'frame-system/std',
    +   'pallet-balances/std'
     ]
    diff --git a/bin/node-template/pallets/template/src/lib.rs b/bin/node-template/pallets/template/src/lib.rs
    index 24de4f2f5..562675a0b 100644
    --- a/bin/node-template/pallets/template/src/lib.rs
    +++ b/bin/node-template/pallets/template/src/lib.rs
    @@ -14,9 +14,11 @@ mod mock;
     mod tests;
     
     /// Configure the pallet by specifying the parameters and types on which it depends.
    -pub trait Config: frame_system::Config {
    +use frame_support::traits::IsSubType;
    +pub trait Config: frame_system::Config + pallet_balances::Config {
        /// Because this pallet emits events, it depends on the runtime's definition of an event.
        type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;
    +   type Call: IsSubType<pallet_balances::Call<Self>>;
     }
     
     // The pallet's runtime storage items.
    diff --git a/bin/node-template/runtime/src/lib.rs b/bin/node-template/runtime/src/lib.rs
    index 51df3dd5a..4ca2ab613 100644
    --- a/bin/node-template/runtime/src/lib.rs
    +++ b/bin/node-template/runtime/src/lib.rs
    @@ -258,6 +258,7 @@ impl pallet_sudo::Config for Runtime {
     /// Configure the pallet template in pallets/template.
     impl template::Config for Runtime {
        type Event = Event;
    +   type Call = Call;
     }
     
     // Create the runtime by composing the FRAME pallets that were previously configured.