Trait XpReserve

Source
pub trait XpReserve
where Self: XpMutate + XpSystem<Extension: XpReserveListener + XpSystemExtensions<Via = Self>>,
{ type Reserve: Delimited; type ReserveReason: RuntimeEnum + VariantCount;
Show 17 methods // Required methods fn reserve_exists( key: &Self::XpKey, reason: &Self::ReserveReason, ) -> DispatchResult; fn has_reserve(key: &Self::XpKey) -> DispatchResult; fn get_reserve_xp( key: &Self::XpKey, reason: &Self::ReserveReason, ) -> Result<Self::Points, DispatchError>; fn total_reserved(key: &Self::XpKey) -> Result<Self::Points, DispatchError>; fn get_all_reserves( key: &Self::XpKey, ) -> Result<Vec<Self::ReserveReason>, DispatchError>; fn set_reserve( key: &Self::XpKey, reason: &Self::ReserveReason, points: Self::Points, ) -> DispatchResult; // Provided methods fn can_reserve_xp(key: &Self::XpKey, points: Self::Points) -> DispatchResult { ... } fn can_reserve_mutate( key: &Self::XpKey, reason: &Self::ReserveReason, points: Self::Points, ) -> DispatchResult { ... } fn can_reserve_new( key: &Self::XpKey, points: Self::Points, ) -> DispatchResult { ... } fn maximum_reserves() -> usize { ... } fn reserve_xp( key: &Self::XpKey, reason: &Self::ReserveReason, points: Self::Points, ) -> DispatchResult { ... } fn withdraw_reserve( key: &Self::XpKey, reason: &Self::ReserveReason, ) -> DispatchResult { ... } fn reset_reserve( key: &Self::XpKey, reason: &Self::ReserveReason, ) -> Result<Self::Points, DispatchError> { ... } fn slash_reserve( key: &Self::XpKey, reason: &Self::ReserveReason, points: Self::Points, ) -> Result<Self::Points, DispatchError> { ... } fn withdraw_reserve_partial( key: &Self::XpKey, reason: &Self::ReserveReason, points: Self::Points, precision: Precision, ) -> DispatchResult { ... } fn on_reserve_update( key: &Self::XpKey, reason: &Self::ReserveReason, reserve_points: Self::Points, ) { ... } fn on_reserve_slash( key: &Self::XpKey, reason: &Self::ReserveReason, slashed_points: Self::Points, ) { ... }
}
Expand description

Trait for reserving XP under specific reasons with built-in support utilities.

Reserved XP is set aside for future intent, constraints, or commitments, and is temporarily excluded from the liquid/spendable pool. Reservations are keyed by ReserveReason to allow multiple reserved segments per XP record.

Reserved XP is inaccessible to the owner until unreserved, but may be used by the runtime for specific logical intents.

Typical use cases include planned usage, cooldowns, bonding, or module isolation.

Additionally, this trait provides default support methods for common reserve-related patterns, such as validation, reserving XP, withdrawing reserves, burning, and slashing reserved XP.

Required Associated Types§

Source

type Reserve: Delimited

Structure representing reserve metadata (e.g., reason and reserved XP points).

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

Reserve entries can be exposed to users for inspection or management.

Source

type ReserveReason: RuntimeEnum + VariantCount

The ReserveReason represents why XP is reserved or modified within the system.

It should 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:

  • ReserveReason::Staking - XP reserved for block author staking.
  • ReserveReason::Treasury - XP reserved for governance or public goods.

Required Methods§

Source

fn reserve_exists( key: &Self::XpKey, reason: &Self::ReserveReason, ) -> DispatchResult

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

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

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

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

Checks if the XP entry has any active reserves.

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

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

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

Retrieves the amount of XP reserved under the specified reserve reason.

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

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

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

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

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

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

fn get_all_reserves( key: &Self::XpKey, ) -> Result<Vec<Self::ReserveReason>, DispatchError>

Retrieves all active reserve reasons associated with the XP key.

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

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

fn set_reserve( key: &Self::XpKey, reason: &Self::ReserveReason, points: Self::Points, ) -> DispatchResult

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

This function bypasses standard XP flow and permission checks, allowing direct manipulation of reserve 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 reserves, which can break system invariants.

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

§Returns
  • Ok(()) if a reserve 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_reserve_xp(key: &Self::XpKey, points: Self::Points) -> DispatchResult

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

This method performs comprehensive validation before allowing reserve creation:

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

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

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

fn can_reserve_mutate( key: &Self::XpKey, reason: &Self::ReserveReason, points: Self::Points, ) -> DispatchResult

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

This method validates whether an existing reserve’s value can be safely changed to the specified points. It handles both increases and decreases in reserve value, ensuring that arithmetic operations won’t overflow or underflow.

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

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

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

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

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

  • The XP key must exist in storage
  • The number of existing reserves must be below the maximum allowed
  • Adding the new reserve must not cause arithmetic overflow

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

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

fn maximum_reserves() -> usize

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

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

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

fn reserve_xp( key: &Self::XpKey, reason: &Self::ReserveReason, points: Self::Points, ) -> DispatchResult

Reserve’s the specified points of XP under the given reserve reason.

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

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

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

fn withdraw_reserve( key: &Self::XpKey, reason: &Self::ReserveReason, ) -> DispatchResult

Withdraws the specified reserve, returning the reserved XP to the liquid balance.

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

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

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

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

Resets (permanently burns) all reserved XP points for the given reason.

This method completely resets the reserved XP balance to zero for the specified reason and returns the previous value. Unlike XpLock::burn_lock, the reserve entry structure is preserved but its point value is reset to zero, allowing for potential future reuse of the same reserve reason.

§Note

This is a low-level primitive intended for internal state resets or corrections. It does not inherently represent a penalty. For penalty-oriented reductions, prefer using slash_reserve.

§Returns
  • Ok(Points) containing the amount of reserved XP that was burned.
  • Err(DispatchError) if the XP key or reserve does not exist or any operation fails.
Source

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

Reduces or burns reserved XP under the given reserve reason.

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

  • If the reserved XP points is greater than specified points, only the requested amount is slashed
  • If the reserved XP points is less than the requested points, the entire reserve is reset
§Note

This is the preferred method for applying penalties to reserved XP. It provides a safe, high-level abstraction over reserve reduction.

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

fn withdraw_reserve_partial( key: &Self::XpKey, reason: &Self::ReserveReason, points: Self::Points, precision: Precision, ) -> DispatchResult

Withdraws a specified amount of reserved XP, returning it to the liquid balance.

This method allows for partial or full withdrawal of reserved XP depending on the specified points and the precision mode. The withdrawn XP is transferred from the reserve back to the liquid balance, making it available for normal operations again.

The precision parameter controls withdrawal behavior:

  • Exact: Only succeeds if the exact amount can be withdrawn, fails otherwise
  • BestEffort: Withdraws as much as possible up to the requested amount
§Returns
  • Ok(()) if the withdrawal completes successfully according to the precision mode.
  • Err(DispatchError) if the XP key or reserve does not exist, or if exact precision fails.
Source

fn on_reserve_update( key: &Self::XpKey, reason: &Self::ReserveReason, reserve_points: Self::Points, )

Hook invoked after a reserve is created or its value is updated.

The reserve_points parameter reflects the current value of the reserve after the update.

§Note

An update does not imply a slashing event. It may represent either:

  • Depositing XP into a reserve (increase), or
  • Withdrawing XP from a reserve (decrease).

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

  • Emit reserve creation or update events
  • Update related metadata or statistics
  • Trigger side effects related to reserve changes (optionally via listener XpReserveListener::reserve_updated)
Source

fn on_reserve_slash( key: &Self::XpKey, reason: &Self::ReserveReason, slashed_points: Self::Points, )

Hook invoked after a reserve is slashed.

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

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

  • Emit reserve slashing events
  • Update related metadata or statistics
  • Trigger side effects related to reserve slashing (optionally via listener XpReserveListener::reserve_slashed)

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§