2

I have a custom pallet that is tightly coupled to the utility pallet. I am trying to call the batch function to perform a batch of balance transfers. The tests of the utility pallet (that create their own test runtime) construct a Vec of utility batch RuntimeCalls with the syntax:

Utility::batch(
            RuntimeOrigin::root(),
            vec![
                RuntimeCall::Balances(BalancesCall::force_transfer {
                    source: 1,
                    dest: 2,
                    value: 5
                }),
                    RuntimeCall::Balances(BalancesCall::force_transfer {
                        source: 1,
                        dest: 2,
                        value: 5
                    }),

                ]
            );

If I use this in my (tightly coupled to utility pallet) custom pallet like so, :

let disp_result =

            pallet_utility::Pallet::<T>::batch(
                origin,
                vec![
                    RuntimeCall::Balances(Call::force_transfer {
                        source: 1,
                        dest: 2,
                        value: 5
                    }),
                    RuntimeCall::Balances(Call::force_transfer {
                        source: 1,
                        dest: 2,
                        value: 5
                    }),
                    
                ]
            );

the rust compiler gives me the error:

error[E0433]: failed to resolve: use of undeclared type `RuntimeCall`
   --> pallets/clipbet2/src/lib.rs:364:6
    |
364 |                     RuntimeCall::Balances(Call::force_transfer {
    |                     ^^^^^^^^^^^ use of undeclared type `RuntimeCall`

If I specify the pallet Config such as: pallet::Config::RuntimeCall::Balances(Call::force_transfer The compiler gives me:

error[E0223]: ambiguous associated type
   --> pallets/clipbet2/src/lib.rs:364:6
    |
364 |                     pallet::Config::RuntimeCall::Balances(Call::force_transfer {
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<Type as pallet::Config>::RuntimeCall`

I realize it doesn't make sense to use the config trait and generics (such as <T as Config>::RuntimeCall) as I'm using the concrete Balances RuntimeCall to edit it's specific set of parameters.

How can I get this to work?

A whole pallet (that does nothing - with all irrelevant code removed) may look like this:

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

pub use pallet::*;

#[frame_support::pallet]
pub mod pallet {
    use frame_support::pallet_prelude::*;
    use frame_system::pallet_prelude::*;

    #[pallet::pallet]
    #[pallet::generate_store(pub(super) trait Store)]
    pub struct Pallet<T>(_);

    #[pallet::config]
    pub trait Config: frame_system::Config + pallet_utility::Config + pallet_balances::Config {
        type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
    }
    
        
    #[pallet::event]
    #[pallet::generate_deposit(pub(super) fn deposit_event)]
    pub enum Event<T: Config> {
        
        SomethingStored { something: u32, who: T::AccountId },
    }
    
        
    #[pallet::call]
    impl<T: Config> Pallet<T> {
        
        #[pallet::call_index(0)]
        #[pallet::weight(10_000)]
        pub fn do_something(origin: OriginFor<T>) -> DispatchResult {

            let disp_result =

            pallet_utility::Pallet::<T>::batch(
                origin,
                vec![
                    RuntimeCall::Balances(pallet_balances::Call::transfer {
                        
                        dest: 2,
                        value: 5
                    }),
                    RuntimeCall::Balances(pallet_balances::Call::transfer {
                        
                        dest: 2,
                        value: 5
                    }),
                    
                ]
            );
            
            Ok(())
        }

        
    }
}
5
  • I have confirmed my pallet tight coupling is working and is calling batch by using a line in a test extrinsic : pallet_utility::Pallet::<T>::batch(origin, call); where origin and call are supplied directly from the front end template parameters.
    – Paul Neale
    Commented Mar 4, 2023 at 10:56
  • What is the exact use case that makes you choose batching calls withing the runtime ? I'm trying to understand the scenario. Commented Mar 6, 2023 at 16:51
  • I'm creating a pallet that does something similar to the lottery pallet - However unlike the lottery pallet, rather than paying one winner the whole pot, I'm making a prediction market - "bets" are placed and paid to winners in relevant proportions.
    – Paul Neale
    Commented Mar 6, 2023 at 17:49
  • 1
    Why do you need the Utility pallet at all? You can just call the transfer function of your underlying Currency just like in the Lottery. Commented Mar 6, 2023 at 19:00
  • When the prediction market rewards are distributed, say I had a couple of hundred transfers to do, would it not be reasonable to use the utility pallet batch function to handle a large batch of transactions? Yes there are other ways, for example to get each user to claim their reward. But I'd like the option to do it this way.
    – Paul Neale
    Commented Mar 7, 2023 at 1:56

1 Answer 1

0

Usually there is no need to create a RuntimeCall within the runtime itself. One might need to create (and most likely sign) a call to ask to the runtime for some execution, but the runtime doesn't really need to call itself (from outside of the runtime) to get any computation, as you can directly declare what the runtime does.

You should be able to call any public function declared in Utility pallet directly from the pallet you are coding, and it would looks something similar to:

let _ = utility_pallet::Pallet::<T>::function();

Check out this piece of documentation here - https://docs.substrate.io/reference/how-to-guides/pallet-design/use-tight-coupling/

And here you can see an example of how Tips pallet is calling pot() function in Treasury pallet.

3
  • Thanks for the help. I'm calling the batch function with the tight coupling ok when I use a coded call via the front-end template. Where the "RuntimeCall" comes in is the batch function takes type: Vec<<T as Config>::RuntimeCall > as an argument. I want to construct this Vec of specific balance transfer calls in my pallet.
    – Paul Neale
    Commented Mar 6, 2023 at 15:34
  • True! Sorry, I think I have misread your question, my answer still holds true, but is not very applicable for what you were asking for. I'll post a more relevant answer :) Commented Mar 6, 2023 at 15:54
  • Thank you. This is similar - I'm trying to apply it to my case. substrate.stackexchange.com/questions/3360/…
    – Paul Neale
    Commented Mar 6, 2023 at 16:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.