Skip to main content

🎧 Listeners

Listeners are the extension layer of pallet-xp.

They allow external logic to react to XP lifecycle changes without modifying the core pallet itself.

The long-term intention is:

one unified extension model for both runtime and off-chain integrations

This means listeners are intended to support:

  • runtime-to-runtime integrations
  • off-chain services
  • indexers
  • automation layers
  • protocol adapters
  • external execution systems

However, today, only the runtime listener layer is implemented.

So currently:

Listeners = runtime code only

not off-chain extensions.

This system should still be treated as experimental.


Why Listeners Exist

XP should remain a core primitive, not a monolithic business-logic pallet.

That means:

  • XP handles identity
  • XP handles Pulse
  • XP handles reserve / lock rules
  • XP handles lifecycle safety

but external systems may still need to react to XP changes.

Examples:

  • staking logic reacting to XP progression
  • governance modules tracking contributor reputation
  • reward systems extending XP earning
  • protocol hooks triggered by lifecycle changes

Listeners provide this integration layer.

They are:

extensions, not replacements.


How Listeners Work

Internally, XP trait methods trigger hooks like:

on_xp_earn(...)
on_xp_transfer(...)
on_reserve_update(...)
on_lock_update(...)

which forward into:

Self::Extension::...

This allows external runtime logic to react without changing pallet internals.

Example:

earn_xp() -> on_xp_earn() -> Extension::xp_earned() -> your runtime logic

This keeps:

core protocol logic != extension behavior

cleanly separated.


What You Must Implement

To build a custom listener, your extension type must implement:

frame_suite::xp::XpSystemExtensions

and then the specific listener traits required by your runtime.

Common listener traits include:

TraitPurpose
XpOwnerListenerownership changes
XpMutateListenercreate / earn / slash / update
XpReserveListenerreserve updates / slashes
XpLockListenerlock updates / slashes
XpReapListenerlifecycle finalization
BeginXpListenerinitialization flow

You only implement what your protocol actually needs.


Example Runtime Extension

pub struct MyXpExtension;

impl XpSystemExtensions for MyXpExtension {
type Via = pallet_xp::Pallet<Runtime>;
}

impl XpMutateListener for MyXpExtension {
fn xp_earned(key: &XpId, earned: Points) {
// custom runtime reaction
}
}

Then wire it into runtime config:

impl pallet_xp::Config for Runtime {
type Extension = MyXpExtension;
}

Now XP lifecycle events trigger your runtime logic automatically.


Current Status

The intended future design is:

Runtime code + Off-chain integrations + External extension providers

through a unified extension architecture.

But today: only runtime listeners exist.

This means:

  • runtime listeners are available now
  • off-chain compatibility is still under design

There is not yet a finalized shared extension interface.

So the current system should be treated as:

experimental runtime extensions

not the final public extension model.


Future Direction

A unified extension model is planned.

This will provide cleaner support for:

  • runtime listeners
  • off-chain integrations
  • async automation layers
  • indexer compatibility
  • external execution adapters
  • shared extension interfaces

with better consistency across both runtime and external systems.

More formal documentation for this unified model will be provided soon.

Until then:

listeners should be treated as runtime-only and experimental.


Production Recommendation

Because the extension model is still evolving:

production systems should prefer:

type Extension = frame_suite::Ignore<pallet_xp::Pallet>;

unless runtime extensions are absolutely required.

This avoids:

  • unstable extension contracts
  • migration complexity later
  • unexpected runtime coupling
  • evolving API surface risks

Until the unified extension architecture is finalized:

production should default to Ignore

and treat custom listeners as advanced experimental integrations.

This is the safest production strategy.


🚀 Next Steps

Now that extensions are clear, the next step is understanding advanced protocol integrations like staking models and XP-backed execution flows.

👉 Advanced -> Staking