6

Could I have one pallet emit an event that other pallets are aware of?

For example:

  • assets-pallet emits an AssetCreated event
  • market-pallet listens for the AssetCreated event

So the assets-pallet is not aware of the market-pallet.

Is there anything within Substrate for this purpose?

2 Answers 2

11

Events are really for the communication of state-transitions which happen on-chain to logic or services off-chain which would like to know when such a transition happens.

They're not designed to be used for communication between different pieces of on-chain logic. To communicate between pallet instances, there are two main patterns: trait inheritance and config trait types.

Trait inheritance is the simpler but by far less flexible of the two. It is strictly one-directional and allows a "user" pallet to be certain that a "service" pallet exists in the runtime and to be able to call into it, view its storage items &c. It is done by having the "user" pallet's Config trait inherit the Config trait of the "service" pallet rather than, or in addition to, the System pallet's Config trait. For an example, see Tips pallet's Config trait, which uses the Treasury pallet:

pub trait Config: pallet_treasury::Config {
    // snip
}

Config trait types are the other way to allow for pallet interoperability. They're the most flexible and future-proof way of doing it and most regular Substrate pallets which need to use other pallets do this. It is also one-way, but you can use the pattern twice to make it bidirectional. It involves creating a trait, implementing it with the "service" pallet and introducing a new type item into the "user" pallet's Config trait which is required to implement it. This doesn't hard-code the relationship between the two pallets; the top-level runtime lib.rs actually wires them together, and so in the future you can replace either one of the pallets with an alternative which requires/implements the same trait.

For an example, see the Config trait of the Gilt pallet, which uses the ReservableCurrency trait to allow the top-level runtime lib.rs to connect it to the Balances pallet:

pub trait Config: frame_system::Config {
    /// Currency type that this works on.
    type Currency: ReservableCurrency<Self::AccountId, Balance = Self::CurrencyBalance>;
    // snip
}
2
  • Okay, so in my example when I create an asset in my assets-pallet I would call to a Config trait like T::MyMarketTrait::do_somthing(); and finally implement that in my runtime under pallet_assets::Config for Runtime {...}? Mar 28, 2022 at 13:38
  • Yes, typically your new trait will be implemented by another pallet and you'll just pass in that pallet as the Config trait's item.
    – Gav
    Apr 15, 2022 at 14:13
4

There are ways for pallets to communicate in the runtime, although I wouldn't use events for this (events are stored in an overlay that gets applied to storage at the end of the block (in pallet_system.on_finalize)). I'm not a core dev, so take this answer as an example/starting point, but definitely not exhaustive. Someone else may have a better solution.

An example of pallet communication is the reporting of Offences to Staking in Polkadot. Not every chain that has offenses/slashing necessarily uses staking, so this is left as a configuration.

Looking at pallet-offences, we have a Config item, OnOffenceHandler. When an offense is reported, it calls the handler.

In Polkadot, the runtime says that this Offense Handler is Staking. And indeed, the Staking pallet has an implementation of the OnOffenceHandler trait.

If you want a similar handler for something like the creation of assets, I'd make an issue/PR to add a handler to the Assets pallet. Then, if another runtime did not want to use that handler, it would just config it to AssetCreationHandler = (); in its runtime.

1

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.