Trait XpLock

Source
pub trait XpLock
where Self: XpMutate + XpSystem<Extension: XpLockListener + XpSystemExtensions<Via = Self>>,
{ type Lock: Delimited; type LockReason: RuntimeEnum + VariantCount;
Show 17 methods // Required methods fn lock_exists( key: &Self::XpKey, reason: &Self::LockReason, ) -> DispatchResult; fn has_lock(key: &Self::XpKey) -> DispatchResult; fn get_lock_xp( key: &Self::XpKey, reason: &Self::LockReason, ) -> Result<Self::Points, DispatchError>; fn total_locked(key: &Self::XpKey) -> Result<Self::Points, DispatchError>; fn get_all_locks( key: &Self::XpKey, ) -> Result<Vec<Self::LockReason>, DispatchError>; fn burn_lock(key: &Self::XpKey, reason: &Self::LockReason) -> DispatchResult; fn set_lock( key: &Self::XpKey, reason: &Self::LockReason, points: Self::Points, ) -> DispatchResult; // Provided methods fn can_lock_xp(key: &Self::XpKey, points: Self::Points) -> DispatchResult { ... } fn can_lock_mutate( key: &Self::XpKey, reason: &Self::LockReason, points: Self::Points, ) -> DispatchResult { ... } fn can_lock_new(key: &Self::XpKey, points: Self::Points) -> DispatchResult { ... } fn maximum_locks() -> usize { ... } fn lock_xp( key: &Self::XpKey, reason: &Self::LockReason, points: Self::Points, ) -> DispatchResult { ... } fn withdraw_lock( key: &Self::XpKey, reason: &Self::LockReason, ) -> DispatchResult { ... } fn slash_lock( key: &Self::XpKey, reason: &Self::LockReason, points: Self::Points, ) -> Result<Self::Points, DispatchError> { ... } fn on_lock_update( key: &Self::XpKey, reason: &Self::LockReason, lock_points: Self::Points, ) { ... } fn on_lock_burn(key: &Self::XpKey, reason: &Self::LockReason) { ... } fn on_lock_slash( key: &Self::XpKey, reason: &Self::LockReason, slashed_points: Self::Points, ) { ... }
}
Expand description

Trait for issuing and managing XP locks.

Locked XP is set aside and made temporarily inaccessible, reducing the liquid (spendable) balance for the duration of the lock. Locks are typically used to enforce runtime constraints, commitments, or cooldowns, and are always scoped to a specific XP entry.

  • Multiple locks can exist per XP entry, each identified by a unique LockReason.
  • Locking is non-transferable and always local to the XP entry; locked XP cannot be moved or reassigned.
  • Locks are intended for internal runtime use (e.g., staking, governance, slashing) and should not be directly controlled by end users.

Typical use cases include staking, governance participation, temporary restrictions, or module isolation.

Additionally, this trait provides default support methods for common lock-related patterns, such as validation, locking, withdrawing, and slashing XP locks.

Required Associated Types§

Source

type Lock: Delimited

Structure representing lock metadata (e.g., ID, locked XP points).

It is merely given for alias and hygiene reason for the implementation

Locking should be internally controlled by runtime intent, not exposed to end users.

Note:

  • XP locks are strictly for internal use, not for direct user access (unlike fungible assets).
  • Allowing users direct control over locks can lead to manipulation or spam-like behavior.
Source

type LockReason: RuntimeEnum + VariantCount

The LockReason represents why XP is Locked or modified within the system.

It is expected to be a lightweight, bounded identifier that classifies the context or intent of runtime-level operations-such as staking, governance, or slashing.

Should be constrained to a small, enumerable set defined by the runtime to prevent storage bloat.

Example use cases:

  • LockReason::Staking - XP locked due to block author staking.
  • LockReason::Treasury - XP redirected for governance or public goods.

Required Methods§

Source

fn lock_exists(key: &Self::XpKey, reason: &Self::LockReason) -> DispatchResult

Checks if a lock exists for the given XP key and lock reason.

This method serves as a guard function to verify lock existence before performing operations that assume a specific lock is present.

§Returns
  • Ok(()) if a lock exists for the specified key and reason.
  • Err(DispatchError) if the lock does not exist or the XP key is invalid.
Source

fn has_lock(key: &Self::XpKey) -> DispatchResult

Checks if the XP entry has any active locks.

This method provides a quick existence check for any locks without checking a lock’s specific reason. Useful as a precondition check before performing lock-sensitive operations.

§Returns
  • Ok(()) if the XP entry has one or more active locks.
  • Err(DispatchError) if no locks exist for the XP key.
Source

fn get_lock_xp( key: &Self::XpKey, reason: &Self::LockReason, ) -> Result<Self::Points, DispatchError>

Retrieves the amount of XP locked under the specified lock reason.

This method returns the exact number of points currently locked for the given reason, allowing precise queries of lock states for accounting, validation, or display purposes.

§Returns
  • Ok(Points) containing the locked XP amount for the specified reason.
  • Err(DispatchError) if the XP key or lock does not exist.
Source

fn total_locked(key: &Self::XpKey) -> Result<Self::Points, DispatchError>

Retrieves the total points of XP actively locked for the given key.

Performance Tip: If total locked XP is available as high-level metadata in the XP structure, it is more efficient to query this value directly rather than summing individual locks.

§Returns
  • Ok(Points) containing the total locked XP amount.
  • Err(DispatchError) if the XP key does not exist.
Source

fn get_all_locks( key: &Self::XpKey, ) -> Result<Vec<Self::LockReason>, DispatchError>

Retrieves all active lock reasons associated with the XP key.

Returns an empty vector if no locks exist for the XP key. Use has_lock as a precondition to avoid unnecessary queries when no locks exist.

§Returns
  • Ok(Vec<LockReason>) containing all active lock reasons.
  • Err(DispatchError) if the XP key does not exist or lookup fails.
Source

fn burn_lock(key: &Self::XpKey, reason: &Self::LockReason) -> DispatchResult

Burns (permanently removes) a lock and its associated XP.

This method completely destroys both the lock entry and the XP it contained, representing full consumption of the locked value.

This is typically used for internal operations or full withdrawal of a lock, as locks cannot be partially withdrawn unlike reserves.

The handling of the burned XP is left to the caller or runtime logic.

§Note

This does not inherently indicate a penalty. For penalty-oriented reductions, prefer using Self::slash_lock.

§Returns
  • Ok(()) if the lock is successfully burned.
  • Err(DispatchError) if the XP key or lock does not exist or the operation fails.
Source

fn set_lock( key: &Self::XpKey, reason: &Self::LockReason, points: Self::Points, ) -> DispatchResult

Use with caution! Directly sets the locked XP for the given key and reason.

This function bypasses standard XP flow and permission checks, allowing direct manipulation of lock values. It is intended strictly for low-level runtime intents such as migrations, internal state resets, or administrative operations.

This method must never be exposed to users or XP providers, as it allows arbitrary creation or mutation of locks, which can break system invariants. Locks should always be created and withdrawn as whole units through controlled flows.

If a lock with the given reason does not exist, it will be created with the specified points.

§Returns
  • Ok(()) if a lock with specified XP key and reason is successfully created or mutated.
  • Err(DispatchError) if the operation fails due to system constraints.

Provided Methods§

Source

fn can_lock_xp(key: &Self::XpKey, points: Self::Points) -> DispatchResult

Checks if the specified points of XP can be locked for the given key.

This method performs comprehensive validation before allowing lock creation:

  • Verifies the XP key exists and can support new locks
  • Ensures the points to lock are non-zero
  • Confirms sufficient liquid XP is available
  • Validates that adding the lock won’t cause arithmetic overflow

This validation ensures that lock operations will succeed and maintain system invariants when performed.

§Returns
  • Ok(()) if the lock can be safely created.
  • Err(DispatchError) if any validation condition fails.
Source

fn can_lock_mutate( key: &Self::XpKey, reason: &Self::LockReason, points: Self::Points, ) -> DispatchResult

Checks if an existing lock can be mutated to the new value.

This method validates whether an existing lock’s value can be safely changed to the specified points. It handles both increases and decreases in lock value, ensuring that arithmetic operations won’t overflow or underflow and that the new value is valid (non-zero).

This is essential for lock modification operations that need to adjust existing lock points while maintaining system stability.

§Returns
  • Ok(()) if the lock mutation is allowed.
  • Err(DispatchError) if the mutation would cause arithmetic errors or violate constraints.
Source

fn can_lock_new(key: &Self::XpKey, points: Self::Points) -> DispatchResult

Determines if a new XP lock can be created for the given key and points.

This method validates the fundamental requirements for creating a new lock:

  • The XP key must exist in storage
  • The points to lock must be non-zero (prevents meaningless locks)
  • The number of existing locks must be below the maximum allowed
  • Adding the new lock must not cause arithmetic overflow

This is a more basic validation than can_lock_xp, focusing only on the structural requirements rather than liquid balance availability.

§Returns
  • Ok(()) if lock creation is structurally allowed.
  • Err(DispatchError) if any fundamental requirement fails.
Source

fn maximum_locks() -> usize

Returns the maximum number of concurrent locks allowed per XP key.

This value is determined by the number of variants in the LockReason enum, as returned by [VariantCountOf<Self::LockReason>]. Each lock must have a unique reason, so the maximum is bounded by the available lock reasons.

§Returns
  • Returns the maximum number of concurrent locks as a usize.
Source

fn lock_xp( key: &Self::XpKey, reason: &Self::LockReason, points: Self::Points, ) -> DispatchResult

Lock’s the specified points of XP under the given lock reason.

This method deducts the specified points from the liquid balance and creates or updates a lock with the given reason. If a lock with the same reason already exists, its value is increased; otherwise, a new lock is created.

The operation ensures atomic consistency by validating preconditions and updating both the liquid balance and lock state in a coordinated manner. This prevents partial updates that could leave the XP entry in an inconsistent state.

§Returns
  • Ok(()) if the lock is successfully created or updated.
  • Err(DispatchError) if the operation fails, with an appropriate error.
Source

fn withdraw_lock(key: &Self::XpKey, reason: &Self::LockReason) -> DispatchResult

Withdraws the specified lock, returning the locked XP to the liquid balance.

This method removes the entire lock and restores all its locked XP to the account’s liquid balance. The lock can only be withdrawn completely because partial withdrawals of locked points are not supported by this method.

The withdrawal operation is atomic, ensuring that both the lock removal and liquid balance update occur together to maintain consistency.

§Returns
  • Ok(()) if the lock is successfully withdrawn.
  • Err(DispatchError) if the XP key or lock does not exist or any of the operation fails.
Source

fn slash_lock( key: &Self::XpKey, reason: &Self::LockReason, points: Self::Points, ) -> Result<Self::Points, DispatchError>

Reduces or slashes locked XP under the given lock reason.

This method provides flexible slashing behavior based on the lock’s current value:

  • If the locked XP points is greater than specified points, only the requested amount is slashed
  • If the locked XP points is less than the requested points, the entire lock is burned

This is typically used for penalty enforcement, where locked XP is reduced or fully forfeited based on protocol rules.

§Returns
  • Ok(Points) containing the actual amount slashed or burned.
  • Err(DispatchError) if the XP key or lock does not exist or any of the operation fails.
Source

fn on_lock_update( key: &Self::XpKey, reason: &Self::LockReason, lock_points: Self::Points, )

Hook invoked after an XP lock is created or its value is updated.

The lock_points parameter reflects the current value of the lock after the update.

This method is a no-op by default, but can be overridden to:

  • Emit lock creation or update events
  • Update related metadata or statistics
  • Trigger side effects related to lock changes
Source

fn on_lock_burn(key: &Self::XpKey, reason: &Self::LockReason)

Hook invoked after an XP lock is burned (permanently removed).

This method is a no-op by default, but can be overridden to:

  • Emit lock removal or burn events
  • Update related metadata or statistics
  • Trigger side effects related to lock removal
Source

fn on_lock_slash( key: &Self::XpKey, reason: &Self::LockReason, slashed_points: Self::Points, )

Hook invoked after a lock is slashed.

The slashed_points parameter reflects the slashed value of the lock in points.

This method is a no-op by default, but can be overridden to:

  • Emit slashing events
  • Update related metadata or statistics
  • Trigger side effects related to lock slashing

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§