Expand description
The XP pallet provides a modular and extensible system for managing Experience Points (XP) as a non-monetary, programmable primitive representing reputation, contribution, or progression.
This pallet is built on top of frame_suite::xp and relies heavily
on its abstractions. It is strongly recommended to understand those traits
before using this pallet.
§Overview
Config- Runtime configurationCall- Dispatchable extrinsicsPallet- Trait implementation for external modules
Unlike traditional fungible systems such as pallet_balances, XP is:
- non-transferable as value
- not issuance-based (no total supply tracking)
- earned through controlled mechanisms
The only user-facing transfer is ownership transfer of an XP key via
Call::handover. All XP value changes must occur through
XpMutate::earn_xp
(typically invoked by runtime logic or other pallets) or internal runtime
mechanisms.
§Identity
XP is key-based, not account-based:
- Each XP entry is identified by an
XpId - Each XP key has exactly one owner
- A single account can own multiple XP keys (
XpOwners)
Account -- owns --> XpId (key)
|- free XP
|- reserved XP
|- locked XPXP keys do not hold private keys and therefore require explicit ownership.
Keys are deterministically generated using
XpOwner::xp_key_gen.
§Lifecycle
The standard XP lifecycle is:
begin_xp -> earn_xp -> (reserve / lock) -> reap- Use
BeginXp::begin_xpfor safe initialization - Use
XpMutate::earn_xpto grant XP
Note: For pre-defined accounts, prefer initializing via
GenesisConfiginstead ofBeginXp::begin_xp.
XP earning is not a simple increment. It integrates a pulse-based reputation system that:
- prevents same-block abuse
- enforces a minimum activity threshold (
MinPulse) - scales rewards based on accumulated reputation
- optionally accelerates growth when XP is locked
At a high level:
- Initially, actions build reputation (pulse) instead of granting XP
- Once active, XP grows approximately as:
XP += points * reputation
if pulse < MinPulse:
build reputation only
else:
XP += points * pulseThis results in:
- early usage -> builds reputation
- consistent usage -> earns increasing XP
- higher reputation -> amplifies future rewards
§Constraints: Reserve & Lock
XP supports two constraint mechanisms:
XpReserve- soft reservation (withdrawable, intent-based)XpLock- strict locking (non-partial withdrawal, protocol-enforced)
These are accessible via XP traits directly, or through the fungible adapter for interoperability.
§Fungible Compatibility
The pallet provides partial implementations of
fungible unbalanced traits
to support interoperability with pallets expecting balance-like behavior,
allowing the same logic to operate across both XP and fungible systems
when used appropriately.
However:
- XP is not fungible
total_issuanceandactive_issuanceare undefined- transfers of value are disallowed
Prefer using XP-specific traits for precise-requirements.
§Origin Model
Most Substrate logic operates on account-based origins. In this system, execution still originates from an account, but the XP key acts as the primary subject of state transitions for XP-related operations.
Runtime logic should treat the XP key as the unit of interaction and authorization, rather than the account itself.
origin: AccountId
input: XpId
ensure owner(origin, XpId)
execute on XpIdThis is facilitated via Call::call, where an XP key is provided and
validated against its owner, enabling XP-scoped execution within the
standard origin-driven model.
§Reaping & Liveness
XP does not use existential deposits. Instead, liveness is determined via activity:
- Each XP entry tracks a timestamp updated on XP earning, indicating activity
MinTimeStamp(set via root) defines the minimum liveness threshold- If an XP’s timestamp falls below this threshold, it is considered inactive
- XP with active locks is treated as in-use (runtime intent) and cannot be reaped
- Inactive XP entries can be reaped via
Call::disposeand are permanently invalidated
This ensures XP reflects active participation or active usage, rather than passive holding.
§Listeners & Hooks
The pallet exposes extensibility via Config::Extensions, where the current
extensions are listener traits defined in frame_suite::xp.
Each XP lifecycle event (create, earn, slash, reserve, lock, reap, transfer) invokes the corresponding listener hook, independent of standard event emission.
- Listeners are always executed regardless of
Config::EmitEvents - Using XP traits directly is expected to provide accurate, intent-aligned hooks
- Using fungible adapters will still function, but may not fully reflect XP-specific semantics
§Genesis Configuration
GenesisConfig sets how XP behaves from the start:
-
InitXp
Starting XP assigned when a new XP entry is created. -
PulseFactorControls how reputation (pulse) grows over time.
Repeated actions increase an internal counter, which periodically increases the pulse value.ⓘstep += per_count if step >= threshold: pulse += 1 step resets -
MinPulse
Minimum reputation required before XP is awarded.
Below this threshold, actions only build reputation.
Once reached, actions begin granting XP (scaled by reputation). -
MinTimeStamp
Minimum activity threshold (block number).
If an XP entry is not updated for a sufficient duration, it becomes inactive and can be reaped.ⓘif timestamp < MinTimeStamp and no active locks: XP can be reaped -
genesis_acc: XP identities initialized at genesis.
Flow:
-
Actions build pulse (reputation)
-
Once pulse reaches
MinPulse, XP starts accumulating -
Inactivity below
MinTimeStampallows XP to be reaped -
Call::force_genesis_config
Restricted to root origin.
Allows updating these parameters at runtime to adjust system behavior.
All genesis parameters are stored in runtime storage and can be updated during runtime; they are not fixed constants.
§Development Feature Gate
This pallet includes a dev feature gate for development and testing.
Core functionality is exposed via public APIs for RPC and UI usage.
The dev feature provides thin wrapper extrinsics and extended
events for direct inspection.
This feature must be disabled in production runtimes due to additional debugging overhead.
Re-exports§
pub use pallet::*;
Modules§
- fungible 🔒
- Implementation of compatible
fungibletraits for thePalletType. - pallet
- The
palletmodule in each FRAME pallet hosts the most important items needed to construct this pallet. - types
- Core types and aliases for the XP system.
- weights
- Autogenerated weights for
pallet_xp - xp 🔒
- Implementations of
XPtraits for thePalletType.