pallet_commitment/
helpers.rs

1// SPDX-License-Identifier: MPL-2.0
2//
3// Part of Auguth Labs open-source softwares.
4// Built for the Substrate framework.
5//
6// This Source Code Form is subject to the terms of the Mozilla Public
7// License, v. 2.0. If a copy of the MPL was not distributed with this
8// file, You can obtain one at https://mozilla.org/MPL/2.0/.
9//
10// Copyright (c) 2026 Auguth Labs (OPC) Pvt Ltd, India
11
12// ===============================================================================
13// ```````````````````````````````` COMMIT HELPERS ```````````````````````````````
14// ===============================================================================
15
16//! Implementation of low-level [`commit-helpers`](crate::traits)
17//! traits for the internal [`CommitHelpers`] Type.
18//!
19//! [`CommitHelpers`] implements traits:
20//! - [`CommitBalance`]
21//! - [`CommitDeposit`]
22//! - [`CommitWithdraw`]
23//! - [`CommitOps`]
24//! - [`CommitInspect`]
25//! - [`PoolOps`]
26//! - [`IndexOps`]
27//!
28//! Local Tests for these traits are covered in `tests`    .
29
30// ===============================================================================
31// ```````````````````````````````````` IMPORTS ``````````````````````````````````
32// ===============================================================================
33
34// --- Local crate imports ---
35use crate::{
36    balance::*, traits::*, types::*, AssetToIssue, AssetToReap, CommitHelpers, CommitMap, Config,
37    DigestMap, EntryMap, Error, HoldReason, IndexMap, Pallet, PoolMap, ReasonValue,
38};
39
40// --- Core ---
41use core::cmp::Ordering;
42
43// --- FRAME Suite ---
44use frame_suite::{
45    commitment::{CommitIndex, CommitPool, CommitVariant, Commitment, DigestModel, InspectAsset},
46    misc::{Directive, PositionIndex},
47};
48
49// --- FRAME Support ---
50use frame_support::{
51    ensure,
52    traits::{
53        fungible::{Inspect, InspectHold, Mutate, MutateFreeze, Unbalanced, UnbalancedHold},
54        tokens::{Fortitude, Precision, Preservation},
55        VariantCount,
56    },
57};
58
59// --- Substrate primitives ---
60use sp_runtime::{
61    traits::{CheckedAdd, CheckedDiv, CheckedMul, CheckedSub, One, Saturating, Zero},
62    DispatchError, DispatchResult, FixedPointNumber, PerThing,
63};
64
65// ===============================================================================
66// `````````````````````````````` CONVENIENCE ALIASES ````````````````````````````
67// ===============================================================================
68
69/// The asset type used for `pallet-commitment`.
70type CommitmentAsset<T, I> = <Pallet<T, I> as InspectAsset<Proprietor<T>>>::Asset;
71
72/// The fungible compile-time freeze-reason (a runtime composite enum)
73/// type used for `pallet-commitment`.
74type CommitmentReason<T, I> = <Pallet<T, I> as Commitment<Proprietor<T>>>::Reason;
75
76/// The digest hash (yet account-id) type used for `pallet-commitment`.
77type CommitmentDigest<T, I> = <Pallet<T, I> as Commitment<Proprietor<T>>>::Digest;
78
79/// The shares type used for `pallet-commitment` for indexes and pools.
80type CommitmentShares<T, I> = <Pallet<T, I> as CommitIndex<Proprietor<T>>>::Shares;
81
82/// The digest-classifier type used for `pallet-commitment` to reduce digest ambiguity.
83type CommitmentDigestModel<T, I> = <Pallet<T, I> as DigestModel<Proprietor<T>>>::Model;
84
85/// The commit-variant or position type used for `pallet-commitment`.
86type CommitmentPosition<T, I> = <Pallet<T, I> as CommitVariant<Proprietor<T>>>::Position;
87
88// ===============================================================================
89// ``````````````````````````````` COMMIT BALANCE ````````````````````````````````
90// ===============================================================================
91
92/// Implements the [`CommitBalance`] trait for the pallet.
93///
94/// Provides low-level balance management.
95impl<T: Config<I>, I: 'static> CommitBalance<Proprietor<T>, Pallet<T, I>> for CommitHelpers<T, I> {
96    /// The structure representing a differential between deposited
97    /// and withdrawn asset values - used to determine how the balance should
98    /// be compensated.
99    type Imbalance = AssetDelta<T, I>;
100
101    /// Resolves an asset imbalance for a proprietor when a commitment is finalized
102    /// (e.g. during withdrawal).
103    ///
104    /// An imbalance may arise when a commitment's effective value changes due to
105    /// digest updates (for example via [`Commitment::set_digest_value`]). This
106    /// function reconciles the difference between deposited and withdrawn amounts
107    /// to preserve financial consistency.
108    ///
109    /// The reconciliation is performed through the pallet's [`Config::Asset`]
110    /// fungible adapter by **minting**, **burning**, or **reissuing** assets as
111    /// required.
112    ///
113    /// This function finalizes the pallet's internal accounting by settling
114    /// [`AssetToIssue`] and [`AssetToReap`] with the underlying asset system.
115    ///
116    /// Notably, this function does **not** rely on balanced fungible traits.
117    /// Instead, the original deposit is returned to the proprietor, and any
118    /// additional minting or burning is performed explicitly and independently
119    /// via unbalanced low-level fungible traits.
120    ///
121    /// This ensures balance adjustments occur in a controlled and safe manner
122    /// without directly mutating the proprietor's balance.
123    ///
124    /// ## Behavior
125    /// - `deposit < withdraw`: The shortfall is **minted** as a reward
126    ///   (accounted via [`AssetToIssue`]).
127    /// - `deposit == withdraw`: The values are balanced; no action is taken.
128    /// - `deposit > withdraw`: The surplus is **burned** as a penalty
129    ///   (accounted via [`AssetToReap`]).
130    ///
131    /// ## Returns
132    /// - `Ok(Asset)` containing the **final asset value returned to the proprietor**
133    ///   after resolving the imbalance.
134    /// - `Err(DispatchError)` if minting or burning fails or capacity is insufficient.
135    fn resolve_imbalance(
136        who: &Proprietor<T>,
137        imbalance: Self::Imbalance,
138    ) -> Result<CommitmentAsset<T, I>, DispatchError> {
139        let deposit = imbalance.deposit;
140        let withdraw = imbalance.withdraw;
141        match deposit.cmp(&withdraw) {
142            // Case 1: Deposit < Withdraw => Mint shortfall as reward
143            Ordering::Less => {
144                let reward = withdraw.saturating_sub(deposit);
145                // Reduce available issuance capacity.
146                AssetToIssue::<T, I>::mutate(|total_issued| -> DispatchResult {
147                    // AssetToIssue must be valid globally over all the updated digests over rewards
148                    let remaining_issue = total_issued.checked_sub(&reward);
149                    debug_assert!(
150                        remaining_issue.is_some(),
151                        "asset issuance is not in equilibrium with minting, 
152                        inconsistency detected, current total issuance {:?} and tried minting {:?}",
153                        total_issued,
154                        reward
155                    );
156                    let remaining_issue =
157                        remaining_issue.ok_or(Error::<T, I>::MintingMoreThanIssued)?;
158                    *total_issued = remaining_issue;
159                    Ok(())
160                })?;
161                // Top up the depositor first, if any base deposit exists.
162                if !deposit.is_zero() {
163                    T::Asset::increase_balance(who, deposit, Precision::Exact)?;
164                }
165                // Mint the shortfall as a reward to balance the commitment.
166                T::Asset::mint_into(who, reward)?;
167                let total_taken = deposit.saturating_add(reward);
168                Ok(total_taken)
169            }
170
171            // Case 2: Deposit == Withdraw  ->  Perfectly balanced
172            Ordering::Equal => {
173                T::Asset::increase_balance(who, withdraw, Precision::Exact)?;
174                Ok(withdraw)
175            }
176
177            // Case 3: Deposit > Withdraw  ->  Burn surplus as penalty
178            Ordering::Greater => {
179                let penalty = deposit.saturating_sub(withdraw);
180                // Reduce available reaping capacity.
181                AssetToReap::<T, I>::mutate(|total_to_reap| -> DispatchResult {
182                    let remaining_reap = total_to_reap.checked_sub(&penalty);
183                    debug_assert!(
184                        remaining_reap.is_some(),
185                        "asset-to-reap is not in equilibrium with burning, 
186                        inconsistency detected, current total-to-reap {:?} and tried burning {:?}",
187                        total_to_reap,
188                        penalty
189                    );
190                    let remaining_reap =
191                        remaining_reap.ok_or(Error::<T, I>::BurningMoreThanReapable)?;
192                    *total_to_reap = remaining_reap;
193                    Ok(())
194                })?;
195                // Always credit base deposit before applying the burn.
196                T::Asset::increase_balance(who, deposit, Precision::Exact)?;
197                // Burn any excess value to restore balance.
198                if !penalty.is_zero() {
199                    T::Asset::burn_from(
200                        who,
201                        penalty,
202                        Preservation::Expendable,
203                        Precision::Exact,
204                        Fortitude::Force,
205                    )?;
206                }
207                let total_taken = deposit.saturating_sub(penalty);
208                Ok(total_taken)
209            }
210        }
211    }
212
213    /// Deducts a specified asset value from the proprietor's balance.
214    ///
215    /// Held funds (under [`HoldReason::PrepareForCommit`]) are applied first,
216    /// followed by liquid funds if required. The deduction behavior is governed
217    /// by the provided precision and fortitude parameters:
218    ///
219    /// - **Precision**: Determines whether an **exact** amount is required or a
220    ///   **best-effort** deduction is acceptable.
221    /// - **Fortitude**: Determines whether deduction should be **polite** or
222    ///   **forceful**.
223    ///
224    /// When `Fortitude::Polite` is used, only held (commit-reserved) funds are
225    /// deducted. When `Fortitude::Force` is used, deduction first consumes any
226    /// available held funds and then continues from the liquid balance if needed.
227    ///
228    /// All balance operations are performed under a **preservation** context and
229    /// therefore never risk account closure.
230    ///
231    /// ## Returns
232    /// - `Ok(Asset)` containing the actual amount deducted.
233    /// - `Err(DispatchError)` if funds are insufficient or the deduction fails.
234    fn deduct_balance(
235        who: &Proprietor<T>,
236        value: CommitmentAsset<T, I>,
237        qualifier: &DispatchPolicy,
238    ) -> Result<CommitmentAsset<T, I>, DispatchError> {
239        let hold_reason = Into::<T::AssetHold>::into(HoldReason::PrepareForCommit);
240
241        // Get reserved balance for our commitment's hold reason
242        let reserve = T::Asset::balance_on_hold(&hold_reason, who);
243        let actual;
244
245        // Case 1 - Reserve covers the whole commitment
246        if reserve >= value {
247            T::Asset::decrease_balance_on_hold(&hold_reason, who, value, Precision::Exact)?;
248            actual = value;
249            return Ok(actual);
250        }
251
252        let force = qualifier.fortitude();
253        let precision = qualifier.precision();
254
255        // Case 2 - Polite mode: reject if exact precision required and reserves insufficient
256        if force == Fortitude::Polite {
257            if precision == Precision::Exact || reserve.is_zero() {
258                let total_reserve = T::Asset::total_balance_on_hold(who);
259                // Notify there are funds in other reserves which can be deposited
260                // to our commitment reserve since the caller needs only from reserve
261                // A safe way to avoid risking account-reaping
262                ensure!(total_reserve < value, Error::<T, I>::ExpectsHoldWithdrawal);
263                return Err(Error::<T, I>::InsufficientFunds.into());
264            }
265        }
266
267        // Check liquid balance availability without risking account-closure
268        let liquid = T::Asset::reducible_balance(who, Preservation::Preserve, Fortitude::Force);
269        let total = reserve
270            .checked_add(&liquid)
271            .ok_or(Error::<T, I>::ReserveLiquidOverflow)?;
272
273        // Case 3 - Liquid Funds and Commit-reserve insufficient
274        if total < value {
275            // Not enough funds, reject if exact precision required
276            if precision == Precision::Exact || total.is_zero() {
277                // This is total balance including reducible if its greater than
278                // the value, then other holds and locks are holding such amount.
279                let total_balance = T::Asset::total_balance(who);
280                ensure!(
281                    !(total_balance > value),
282                    Error::<T, I>::ExpectsFreezeAndHoldWithdrawal
283                );
284                return Err(Error::<T, I>::InsufficientFunds.into());
285            }
286
287            // Deduct all liquid and reserved funds since we require only Best Effort
288            T::Asset::decrease_balance(
289                who,
290                liquid,
291                Precision::Exact,
292                Preservation::Preserve,
293                Fortitude::Force,
294            )?;
295            T::Asset::decrease_balance_on_hold(&hold_reason, who, reserve, Precision::Exact)?;
296            actual = total;
297            return Ok(actual);
298        }
299
300        // Case 4 - Enough funds available via liquid + commit-reserve, deduct proportionally
301        let excess = total.saturating_sub(value);
302        let free = liquid.saturating_sub(excess);
303        T::Asset::decrease_balance(
304            who,
305            free,
306            Precision::Exact,
307            Preservation::Preserve,
308            Fortitude::Force,
309        )?;
310        T::Asset::decrease_balance_on_hold(&hold_reason, who, reserve, Precision::Exact)?;
311        actual = value;
312        Ok(actual)
313    }
314
315    /// Deducts a specified value from an existing imbalance, mutating it in-place.
316    ///
317    /// This function extracts `value` from that differential while preserving
318    /// correct economic accounting for rewards or penalties.
319    ///
320    /// ## Semantics
321    /// - If `withdraw > deposit` (reward state): the deduction first consumes
322    ///   the reward portion. Any excess deduction converts into a penalty,
323    ///   increasing [`AssetToReap`].
324    /// - If `withdraw == deposit` (neutral state): the deduction is treated as a
325    ///   penalty and directly increases [`AssetToReap`].
326    /// - If `withdraw < deposit` (penalty state): the deduction deepens the
327    ///   penalty, further increasing [`AssetToReap`].
328    ///
329    /// In all cases, the imbalance holder remains the sole party whose economic
330    /// position is adjusted, avoiding double mint/burn effects for both parties.
331    ///
332    /// ## Returns
333    /// Returns a neutral imbalance (`deposit == withdraw == value`). This allows
334    /// the caller to credit the deducted value directly to the underlying
335    /// fungible system without introducing additional reward or penalty logic.
336    ///
337    /// - `DispatchError` otherwise
338    fn deduct_from_imbalance(
339        imbalance: &mut Self::Imbalance,
340        value: CommitmentAsset<T, I>,
341    ) -> Result<Self::Imbalance, DispatchError> {
342        let given = &mut imbalance.deposit;
343        let taken = &mut imbalance.withdraw;
344        match given.cmp(&taken) {
345            // If the imbalance's withdrawal includes a reward, determine if the reward can cover the deduction
346            Ordering::Less => {
347                let reward = taken.saturating_sub(*given);
348                match value.cmp(&reward) {
349                    // Part of the imbalance's reward is retained by the proprietor after deduction
350                    Ordering::Less => {
351                        let actual_reward = reward.saturating_sub(value);
352                        *taken = given.saturating_add(actual_reward);
353                    }
354                    // The reward is fully collected by the deduction
355                    Ordering::Equal => {
356                        *taken = *given;
357                    }
358                    // Reward + extra from withdrawal incurs a more penalty to the imbalance holder
359                    Ordering::Greater => {
360                        let remaining = value.saturating_sub(reward);
361                        // We simulate that the imbalance holder incurs a penalty, so that the deduction
362                        // can be a simple increase balance to underlying fungible system instead of equating
363                        // asset mints and reaps doubly for both imbalance holder and deducter, by this method, we keep
364                        // accurate imbalance resolving only towards the imbalance holder
365                        AssetToReap::<T, I>::mutate(|total_to_reap| -> DispatchResult {
366                            *total_to_reap = total_to_reap
367                                .checked_add(&remaining)
368                                .ok_or(Error::<T, I>::MaxAssetReaped)?;
369                            Ok(())
370                        })?;
371                        *taken = given.saturating_sub(remaining);
372                    }
373                }
374            }
375            // If no reward or penalty, reduce the withdrawal to deduct
376            Ordering::Equal => {
377                AssetToReap::<T, I>::mutate(|total_to_reap| -> DispatchResult {
378                    *total_to_reap = total_to_reap
379                        .checked_add(&value)
380                        .ok_or(Error::<T, I>::MaxAssetReaped)?;
381                    Ok(())
382                })?;
383                *taken = taken.saturating_sub(value);
384            }
385            // If penalty, paying from the withdrawal incurs additional penalty to the imbalance holder
386            Ordering::Greater => {
387                AssetToReap::<T, I>::mutate(|total_to_reap| -> DispatchResult {
388                    *total_to_reap = total_to_reap
389                        .checked_add(&value)
390                        .ok_or(Error::<T, I>::MaxAssetReaped)?;
391                    Ok(())
392                })?;
393                *taken = taken.saturating_sub(value);
394            }
395        }
396
397        // Here we give nill imbalance-delta so the deduction's imbalance
398        // shall be a simple increase balance in the underlying system
399        Ok(AssetDelta {
400            deposit: value,
401            withdraw: value,
402        })
403    }
404}
405
406// ===============================================================================
407// ``````````````````````````````` COMMIT DEPOSIT ````````````````````````````````
408// ===============================================================================
409
410/// Implements the [`CommitDeposit`] trait for the pallet, providing low-level deposit
411/// functionality for digests, indexes, and pools within the commitment system.
412impl<T: Config<I>, I: 'static> CommitDeposit<Proprietor<T>, Pallet<T, I>> for CommitHelpers<T, I> {
413    /// Represents the "Receipt" of a digest at the time of a deposit.
414    ///
415    /// Reference [`CommitInstance`]'s generic alias documentation, where it
416    /// holds the deposit receipt from the digest's lazy balance
417    /// ([`LazyBalanceOf`]) when the deposit occurs.
418    ///
419    /// It ensures that later commitment resolution can account for the digest's
420    /// state accurately, even if the underlying digest values changes over time.
421    type Receipt = CommitInstance<T, I>;
422
423    /// Deposits a value for a given digest model and its specified variant.
424    ///
425    /// This function centralizes the dispatch logic to the appropriate handler
426    /// depending on the type of the digest model (Direct, Index, or Pool).
427    ///
428    /// ## Returns
429    /// - `Ok((DerivedBalance, Asset))` containing the deposit's receipt and the actual
430    /// depositted value.
431    /// - `Err(DispatchError)` if the deposit fails
432    fn deposit_to(
433        who: &Proprietor<T>,
434        reason: &CommitmentReason<T, I>,
435        digest_model: &CommitmentDigestModel<T, I>,
436        value: CommitmentAsset<T, I>,
437        variant: &CommitmentPosition<T, I>,
438        qualifier: &DispatchPolicy,
439    ) -> Result<(Self::Receipt, CommitmentAsset<T, I>), DispatchError> {
440        match digest_model {
441            DigestVariant::Direct(dir) => {
442                Self::deposit_to_digest(who, reason, dir, value, variant, qualifier)
443            }
444            DigestVariant::Index(index) => {
445                Self::deposit_to_index(who, reason, index, value, variant, qualifier)
446            }
447            DigestVariant::Pool(pool) => {
448                Self::deposit_to_pool(who, reason, pool, value, variant, qualifier)
449            }
450            _ => {
451                debug_assert!(
452                    false,
453                    "digest-model marker variants {:?} are constructed, 
454                    captured during deposit for proprietor {:?} 
455                    of reason {:?} are explicitly dis-allowed",
456                    digest_model, who, reason
457                );
458                return Err(Error::<T, I>::InvalidDigestModel.into());
459            }
460        }
461    }
462
463    /// Deposits a given asset value into a specific direct-digest's variant's balance
464    /// for a reason.
465    ///
466    /// This is a **low-level internal function** - it:
467    /// - Directly deposits value into the specified digest and its variant.
468    /// - Does not inspect or deduct balance, as argument.
469    ///
470    /// Digest variants represent different commitment positions (e.g., affirmative,
471    /// contrary, etc). This function ensures deposits go to the correct variant's
472    /// balance via [`PositionIndex`], as digest-balances will be stored as a vector
473    /// of variant balances.
474    ///
475    /// ## Returns
476    /// - `Ok((DerivedBalance, Asset))` containing the deposit's receipt and the actual
477    /// depositted value.
478    /// - `Err(DispatchError)` if the digest variant cannot be found or mutated
479    fn deposit_to_digest(
480        _who: &Proprietor<T>,
481        reason: &CommitmentReason<T, I>,
482        digest: &CommitmentDigest<T, I>,
483        value: CommitmentAsset<T, I>,
484        variant: &CommitmentPosition<T, I>,
485        qualifier: &DispatchPolicy,
486    ) -> Result<(Self::Receipt, CommitmentAsset<T, I>), DispatchError> {
487        // Mutate the digest map to update the balance for the given reason -> digest -> variant
488        let actual =
489            DigestMap::<T, I>::mutate((reason, digest), |result| -> Result<_, DispatchError> {
490                // Retrieve digest information; error if digest does not exist
491                let digest_info = result.as_mut().ok_or(Error::<T, I>::DigestNotFound)?;
492
493                // Attempt to retrieve the digest variant balance
494                let Some(digest_of) = digest_info.mut_balance(variant) else {
495                    digest_info.init_balance(variant)?;
496                    // Deposit value into the newly created variant balance
497                    let digest_of_new_variant = digest_info.mut_balance(variant);
498                    debug_assert!(
499                        digest_of_new_variant.is_some(),
500                        "recently initiated digest {:?} of reason {:?} variant {:?} 
501                    balance not accessible via vector",
502                        digest,
503                        reason,
504                        variant,
505                    );
506                    let digest_of_new_variant =
507                        digest_of_new_variant.ok_or(Error::<T, I>::DigestVariantBalanceNotFound)?;
508                    let (depositted, receipt) =
509                        deposit(digest_of_new_variant, variant, digest, &value, qualifier)?;
510                    // Early exit from mutate closure after depositing to newly created variant
511                    return Ok((receipt, depositted));
512                };
513
514                // If the variant exists, deposit directly into its balance
515                let (depositted, receipt) = deposit(digest_of, variant, digest, &value, qualifier)?;
516                Ok((receipt, depositted))
517            })?;
518
519        // Return the deposit (receipt, amount)
520        Ok(actual)
521    }
522
523    /// Deposits a given asset value into an index and distributes it across
524    /// its entries' digests.
525    ///
526    /// This is a **low-level internal function** - it:
527    /// - Splits the value proportionally across each entry based on its share/capital ratio.
528    /// - Delegates deposits into each entry's digest via [`Self::deposit_to_digest`].
529    /// - Updates the index's own top-level balance.
530    ///
531    /// Expected invariants:
532    /// - Total capital must be non-zero (no stale or invalid indexes).
533    /// - Total index capital must be **at least** the share value of each entry.
534    /// - Entry shares must be non-zero (no stale or invalid entries).
535    ///
536    /// The caller's `variant` is ignored because each entry already defines its own variant.
537    ///
538    /// If the index deposit has any remaining assets, they are refunded to the
539    /// proprietor here. Other commitment types (such as direct digests or pools)
540    /// do not require refunding, so the refund logic is handled exclusively at
541    /// this level.
542    ///
543    /// Since Index maintains entry-commit receipts in their own high-level structures
544    /// the receipt returned is a placeholder receipt (default), although the depositted
545    /// amount is valid.
546    ///
547    /// ## Returns
548    /// - `Ok((DerivedBalance, Asset))` containing a placeholder receipt and the actual
549    /// depositted value.
550    /// - `Err(DispatchError)` if the deposit cannot be conducted
551    fn deposit_to_index(
552        who: &Proprietor<T>,
553        reason: &CommitmentReason<T, I>,
554        index_of: &CommitmentDigest<T, I>,
555        value: CommitmentAsset<T, I>,
556        _variant: &CommitmentPosition<T, I>,
557        qualifier: &DispatchPolicy,
558    ) -> Result<(Self::Receipt, CommitmentAsset<T, I>), DispatchError> {
559        // Track the total successfully deposited value across all entries in the index
560        let mut actual = CommitmentAsset::<T, I>::zero();
561
562        // Mutate the index map for the given reason and index digest
563        IndexMap::<T, I>::mutate((reason, index_of), |result| -> DispatchResult {
564            // Retrieve the index information; error if index does not exist
565            let index_info = result.as_mut().ok_or(Error::<T, I>::IndexNotFound)?;
566            // Capital is used to compute proportional commitment values for each entry
567            let index_capital = index_info.capital();
568            debug_assert!(
569                !index_capital.is_zero(),
570                "index {:?} of reason {:?} capital is constructed at zero",
571                index_of,
572                reason
573            );
574            ensure!(!index_capital.is_zero(), Error::<T, I>::CapitalCannotBeZero);
575            // Iterate through each entry within the index
576            let entries = &index_info.entries();
577            for i in 0..entries.len() {
578                let entry = &entries[i];
579                // Entry's share value used to compute proportional commitment value to it individually.
580                let entry_share = entry.shares();
581                debug_assert!(
582                    !entry_share.is_zero(),
583                    "index {:?} of reason {:?} entry {:?} 
584                    share is found to be zero",
585                    index_of,
586                    reason,
587                    entry.digest()
588                );
589                ensure!(!entry_share.is_zero(), Error::<T, I>::ShareCannotBeZero);
590                debug_assert!(
591                    index_capital >= entry_share,
592                    "index {:?} of reason {:?}  capital of value {:?} is constructed 
593                    as lesser than the entry {:?} share {:?}",
594                    index_of,
595                    reason,
596                    index_capital,
597                    entry.digest(),
598                    entry_share
599                );
600                ensure!(
601                    index_capital >= entry_share,
602                    Error::<T, I>::ShareGreaterThanCapital
603                );
604                // Compute this entry's proportional factor (share / capital), use bias type as precision
605                let factor = T::Bias::checked_from_rational(entry_share, index_capital)
606                    .ok_or(Error::<T, I>::TooSmallShareValue)?;
607                // Convert committing value to its fixed-point equivalent representation
608                let value_fixed = T::Bias::saturating_from_integer(value);
609                // Compute scaled deposit value for this entry
610                let deposit_val_fixed = value_fixed
611                    .checked_mul(&factor)
612                    .ok_or(Error::<T, I>::DepositDeriveOverflowed)?;
613                // Skip this entry if the computed allocation rounds below 1 unit
614                // So its expected, that some entries of much lower shares may not get
615                // commitments if the deposited value is very lower
616                if deposit_val_fixed < One::one() {
617                    continue;
618                }
619                // Convert from fixed-point back to asset units
620                let deposit_val_scaled = deposit_val_fixed
621                    .into_inner()
622                    // ensured no NAN possibility
623                    .checked_div(&T::Bias::DIV)
624                    .ok_or(Error::<T, I>::DerivedLessThanZeroValue)?;
625                let deposit_val: CommitmentAsset<T, I> = deposit_val_scaled.into();
626
627                // Each entry has its own digest and variant; the caller's `_variant` is ignored
628                let entry_digest = &entry.digest();
629                let entry_variant = &entry.variant();
630                // Perform the actual deposit to the entry's digest
631                let (receipt, amount) = Self::deposit_to_digest(
632                    who,
633                    reason,
634                    entry_digest,
635                    deposit_val,
636                    entry_variant,
637                    qualifier,
638                )?;
639                // This stores the commitments to indexes in a higher structure for later retrieval,
640                // for raising commits and resolving it, since base commitments only allow a single
641                // digest per reason, whereas this map stores multiple digest, each for each entry of
642                // index, essentially a parallel storage map akin to `CommitMap`
643                // Accumulates a new commit-instance if existing commit exists, else inserts
644                // A single entry point for placing or raising commits belong to an entry of index
645                match EntryMap::<T, I>::contains_key((reason, index_of, &entry_digest, who)) {
646                    true => {
647                        // Mutate if its existing and add a new commit-instance i.e., raise-commit
648                        EntryMap::<T, I>::mutate(
649                            (reason, index_of, &entry_digest, who),
650                            |result| -> DispatchResult {
651                                debug_assert!(
652                                    result.is_some(),
653                                    "proprietor {:?} commit under index {:?} of entry {:?} exists, 
654                                    but cannot mutate its balance",
655                                    who,
656                                    index_of,
657                                    entry_digest
658                                );
659                                // Already checked if key contains, hence the try operation is dead code
660                                let value =
661                                    result.as_mut().ok_or(Error::<T, I>::EntryCommitNotFound)?;
662
663                                // New commit instance i.e., receipt to add to existing commits
664                                value.add_commit(receipt)?;
665                                Ok(())
666                            },
667                        )?;
668                    }
669                    false => {
670                        // Insert the first commit i.e., place commit
671                        EntryMap::<T, I>::insert(
672                            (reason, index_of, &entry_digest, who),
673                            Commits::<T, I>::new(receipt)?,
674                        );
675                    }
676                }
677                // Accumulate the deposited value across all entries
678                let try_accum = actual.checked_add(&amount);
679                debug_assert!(
680                    try_accum.is_some(),
681                    "found an invariant broken due to overflow during deposit to index
682                    by proprietor {:?} for index {:?} for entry {:?}, when 
683                    entry's share > total capital, only overflows when Share {:?} /Capital {:?} 
684                    ratio produced a factor greater than 1.",
685                    who,
686                    index_of,
687                    entry_digest,
688                    entry_share,
689                    index_capital
690                );
691                // Overflow here signals a proportional factor > 1, not a simple arithmetic bug
692                let try_accum = try_accum.ok_or(Error::<T, I>::FactorGreaterThanOne)?;
693                actual = try_accum;
694            }
695
696            // Refund any remaining difference (dust) directly to the caller
697            // Cannot use `resolve_imbalance` here because it interacts with issuance/reaping
698            let refund = value.saturating_sub(actual);
699            if !refund.is_zero() {
700                T::Asset::increase_balance(who, refund, Precision::Exact)?;
701            }
702
703            // Update the index's top-level balance for quick queries (total deposits only).
704            // A receipt is not required here, as balance sets are applied at the digest
705            // level only. Indexes and pools do not hold commitments directly; they act as
706            // convenience aggregation layers over base (direct) commitments.
707            let mut index_balance_of = index_info.principal();
708            index_balance_of = index_balance_of
709                .checked_add(&actual)
710                .ok_or(Error::<T, I>::MaxIndexCapacityReached)?;
711            index_info.set_balance(index_balance_of);
712
713            Ok(())
714        })?;
715
716        // Safe to return default receipt; individual entry receipts are tracked internally in
717        // `EntryMap`. The One reason One digest Commit invariant is enforced globally via this
718        // indirection. Although a base commitment always references a single qualified digest,
719        // that digest may represent an index. In such cases, the actual commit data
720        // is resolved via `EntryMap`, with the base commitment acting only as an
721        // indirection (pointer) to the underlying structure.
722        Ok((Self::Receipt::default(), actual))
723    }
724
725    /// Deposits a given asset value into a pool for a reason.
726    ///
727    /// This is a **low-level internal function** - it:
728    /// - Directly deposits value into the specified pool.
729    /// - Does not inspect or deduct balance, as argument `_who` is unused.
730    ///
731    /// The caller's `variant` is ignored because each pool's slot already
732    /// defines its own variant.
733    ///
734    /// At this level the logic is straightforward: the pool itself acts as a
735    /// **proprietor**. It receives funds and commits them to individual slot
736    /// digests, while external proprietors hold shares of the pool.
737    ///
738    /// As a result, every deposit into or withdrawal from the pool requires the
739    /// pool to temporarily release and then re-acquire the corresponding funds.
740    /// This mirrors how an index commitment is resolved and re-placed by a
741    /// proprietor.
742    ///
743    /// ### Returns
744    /// - `Ok((DerivedBalance, Asset))` containing the pool's deposit receipt
745    /// and the actual depositted value of the proprietor.
746    /// - `Err(DispatchError)` if the deposit cannot be conducted
747    fn deposit_to_pool(
748        _who: &Proprietor<T>,
749        reason: &CommitmentReason<T, I>,
750        pool_of: &CommitmentDigest<T, I>,
751        value: CommitmentAsset<T, I>,
752        _variant: &CommitmentPosition<T, I>,
753        qualifier: &DispatchPolicy,
754    ) -> Result<(Self::Receipt, CommitmentAsset<T, I>), DispatchError> {
755        // Release the pool's current balance to work with a mutable copy
756        let mut released_balance = Self::release_pool(reason, pool_of)?;
757
758        // Deposit the incoming value into the released pool balance
759        let (depositted, receipt) = deposit(
760            &mut released_balance,
761            &Default::default(),
762            pool_of,
763            &value,
764            qualifier,
765        )?;
766
767        // Recover the pool by writing the updated balance back into storage
768        Self::recover_pool(reason, pool_of, &released_balance)?;
769
770        // Unlike indexes, a pool behaves as a **pseudo-digest**: a proprietor deposits
771        // funds into the pool itself, effectively committing to the pool as a whole.
772        // The pool manager can access these funds (which direct commitment digests
773        // cannot) and, acting as a proprietor, commits the funds onward to individual
774        // slot digests according to their configured shares.
775        //
776        // Because the pool serves as the commitment target for the depositing
777        // proprietor, the correct balance receipt must reflect the pool's
778        // state at the moment the funds were handed over for management.
779        Ok((receipt, depositted))
780    }
781}
782
783// ===============================================================================
784// ``````````````````````````````` COMMIT WITHDRAW ```````````````````````````````
785// ===============================================================================
786
787/// Implements the [`CommitWithdraw`] trait for the pallet
788///
789/// Provides low-level withdraw functionality for digests, indexes,
790/// and pools within the commitment system.
791impl<T: Config<I>, I: 'static> CommitWithdraw<Proprietor<T>, Pallet<T, I>> for CommitHelpers<T, I> {
792    /// Withdraws the proprietor's total committed value for a given digest
793    /// model and reason.
794    ///
795    /// This function centralizes the dispatches to the appropriate underlying
796    /// handler depending on the type of the digest model (Direct, Index, or Pool).
797    ///
798    /// Digest models represent different
799    /// commitment structures:
800    /// - **Direct**: a single digest commitment.
801    /// - **Index**: a grouped commitment of multiple entry digests.
802    /// - **Pool**: a shared resource i.e., a collective single commitment.
803    ///
804    /// ## Imbalance Semantics
805    /// The returned imbalance captures the difference between the original deposit
806    /// made when the commitment was placed and the value withdrawn at resolution
807    /// time. Since digests may accrue rewards or penalties over time, the withdrawn
808    /// amount may differ from the original deposit; this difference is expected and
809    /// is represented explicitly in the imbalance.
810    ///
811    /// ## Notes
812    /// - Callers are expected to resolve this imbalance probably
813    /// via [`CommitBalance::resolve_imbalance`]
814    /// - The caller's `variant` is ignored because each commit already defines
815    /// its own variant during deposit operation.
816    ///
817    /// ## Returns
818    /// - `Ok(Imbalance)` containing:
819    ///   - `deposit`: the original amount deposited when the commitment was placed.
820    ///   - `withdraw`: the amount withdrawn at resolution time.
821    /// - `Err(DispatchError)` if any underlying withdrawal operation fails.
822    fn withdraw_for(
823        who: &Proprietor<T>,
824        reason: &CommitmentReason<T, I>,
825        digest_model: &CommitmentDigestModel<T, I>,
826        variant: &CommitmentPosition<T, I>,
827    ) -> Result<Self::Imbalance, DispatchError> {
828        match digest_model {
829            DigestVariant::Direct(dir) => Self::withdraw_from_digest(who, reason, dir, variant),
830            DigestVariant::Index(index) => Self::withdraw_from_index(who, reason, index, variant),
831            DigestVariant::Pool(pool) => Self::withdraw_from_pool(who, reason, pool, variant),
832            _ => {
833                debug_assert!(
834                    false,
835                    "digest-model marker variants {:?} are constructed, 
836                    captured during withdraw for proprietor {:?} 
837                    of reason {:?} are explicitly dis-allowed",
838                    digest_model, who, reason
839                );
840                return Err(Error::<T, I>::InvalidDigestModel.into());
841            }
842        }
843    }
844
845    /// Withdraws the committed value for a single direct digest and variant.
846    ///
847    /// This low-level function calculates the real-time effective value for all
848    /// commit instances associated with this proprietor and digest, then updates
849    /// the digest's balance accordingly.
850    ///
851    /// ## Imbalance Semantics
852    /// The returned imbalance captures the difference between the original deposit
853    /// made when the commitment was placed and the value withdrawn at resolution
854    /// time. Since digests may accrue rewards or penalties over time, the withdrawn
855    /// amount may differ from the original deposit; this difference is expected and
856    /// is represented explicitly in the imbalance.
857    ///
858    /// ## Notes
859    /// - Callers are expected to resolve this imbalance probably
860    /// via [`CommitBalance::resolve_imbalance`]
861    /// - The caller's `variant` is ignored because each commit already defines
862    /// its own variant during deposit operation.
863    ///
864    /// ## Returns
865    /// - `Ok(Imbalance)` containing both the deposited and the withdrawn value
866    /// - `Err(DispatchError)` if the digest or variant is not found
867    fn withdraw_from_digest(
868        who: &Proprietor<T>,
869        reason: &CommitmentReason<T, I>,
870        digest: &CommitmentDigest<T, I>,
871        _variant: &CommitmentPosition<T, I>,
872    ) -> Result<Self::Imbalance, DispatchError> {
873        // Initialize zero values. `taken` tracks total withdrawn, `given` tracks total deposited.
874        let mut given = CommitmentAsset::<T, I>::zero();
875        let mut taken = CommitmentAsset::<T, I>::zero();
876
877        // We take the variant of the commit - the actual variant
878        //
879        let variant = Pallet::<T, I>::get_commit_variant(who, reason)?;
880
881        // Mutate the digest map to update the new balance (after withdrawal value)
882        // for the given reason and digest
883        DigestMap::<T, I>::mutate((reason, digest), |result| -> DispatchResult {
884            // Retrieve digest information; error if digest does not exist
885            let digest_info = result.as_mut().ok_or(Error::<T, I>::DigestNotFound)?;
886
887            // Access the specific variant balance
888            let balance = digest_info.mut_balance(&variant);
889
890            debug_assert!(
891                balance.is_some(),
892                "digest {:?} of reason {:?} variant {:?} balance 
893                was not initiated properly in the balance vector 
894                during the deposit for proprietor {:?}",
895                digest,
896                reason,
897                variant,
898                who
899            );
900
901            let balance = balance.ok_or(Error::<T, I>::DigestVariantBalanceNotFound)?;
902
903            CommitMap::<T, I>::mutate((who, reason), |result| -> DispatchResult {
904                // Retrieve the proprietor's commit information for this reason
905                let commit_info = result.as_mut().ok_or(Error::<T, I>::CommitNotFound)?;
906                // Iterate over each commit instance associated with this proprietor
907                let commits = &commit_info.commits();
908                for commit in commits {
909                    // Deposit accumulation
910                    given = given
911                        .checked_add(&receipt_deposit_value(commit)?)
912                        .ok_or(Error::<T, I>::DepositAccumulationExhausted)?;
913                    // Withdraw Accumulation
914                    taken = taken
915                        .checked_add(&withdraw(balance, &variant, digest, commit)?)
916                        .ok_or(Error::<T, I>::WithdrawAccumulationExhausted)?;
917                }
918
919                Ok(())
920            })?;
921
922            Ok(())
923        })?;
924
925        // Return the withdrawn and deposited amounts as the imbalance for this proprietor
926        Ok(AssetDelta {
927            deposit: given,
928            withdraw: taken,
929        })
930    }
931
932    /// Withdraws the committed value for a given index digest.
933    ///
934    /// Iterates over all entries in the index, calculates each entry's effective
935    /// withdrawal, and updates entry digest balances while
936    /// removing commitment records from storage.
937    ///
938    /// ## Imbalance Semantics
939    /// The returned imbalance captures the difference between the original deposit
940    /// made when the commitment was placed and the value withdrawn at resolution
941    /// time. Since digests may accrue rewards or penalties over time, the withdrawn
942    /// amount may differ from the original deposit; this difference is expected and
943    /// is represented explicitly in the imbalance.
944    ///
945    /// ## Notes
946    /// - Callers are expected to resolve this imbalance probably
947    /// via [`CommitBalance::resolve_imbalance`]
948    /// - The caller's `variant` is ignored because each commit belongs to an entry already
949    /// defines its own variant during deposit operation.
950    /// - Since an index is an immutable structure-where entry updates result in a
951    /// new index, no inconsistencies can arise.
952    ///
953    /// ## Returns
954    /// - `Ok(Imbalance)` representing total withdrawn and deposited values across all entries
955    /// - `Err(DispatchError)` if the index or any entry is not found
956    fn withdraw_from_index(
957        who: &Proprietor<T>,
958        reason: &CommitmentReason<T, I>,
959        index_of: &CommitmentDigest<T, I>,
960        _variant: &CommitmentPosition<T, I>,
961    ) -> Result<Self::Imbalance, DispatchError> {
962        // Initialize zero values. `taken` tracks total withdrawn, `given` tracks total deposited.
963        // Since indexes composed of multiple entry digests we have to iterate over each digest in
964        // the assumption of a single commit per entry digest (high-level structure) and track balances
965        let mut taken = CommitmentAsset::<T, I>::zero();
966        let mut given = CommitmentAsset::<T, I>::zero();
967
968        // Mutate the index map to for the given index digest and reason, to
969        // retrieve entry infos and update its balance for high-level queries
970        IndexMap::<T, I>::mutate((reason, index_of), |result| -> DispatchResult {
971            let index_info = result.as_mut().ok_or(Error::<T, I>::IndexNotFound)?;
972
973            // Iterate over each entry within the index
974            let entries = &index_info.entries();
975            for entry in entries {
976                let entry_digest = entry.digest();
977                let entry_variant = entry.variant();
978
979                // Retrieve all commit instances for this proprietor and entry
980                let commits_of = EntryMap::<T, I>::get((reason, index_of, &entry_digest, who))
981                    .ok_or(Error::<T, I>::CommitNotFoundForEntry)?;
982
983                for commit in &commits_of.commits() {
984                    // Commit value represents the amount deposited previously.
985                    // Each commit instance is stored as a receipt, so this value reflects
986                    // the original deposit.
987                    let commit_value = receipt_deposit_value(commit)?;
988
989                    // Accumulate total deposited amount for this entry
990                    given = given
991                        .checked_add(&commit_value)
992                        .ok_or(Error::<T, I>::DepositAccumulationExhausted)?;
993
994                    DigestMap::<T, I>::mutate(
995                        (reason, &entry_digest),
996                        |result| -> DispatchResult {
997                            let digest_info =
998                                result.as_mut().ok_or(Error::<T, I>::EntryDigestNotFound)?;
999                            let digest_of = digest_info.mut_balance(&entry_variant);
1000                            debug_assert!(
1001                                digest_of.is_some(),
1002                                "entry-digest {:?} of index {:?} of reason {:?} variant {:?} balance 
1003                                was not initiated properly in the balance vector 
1004                                during the deposit for proprietor {:?}",
1005                                entry_digest,
1006                                index_of,
1007                                reason,
1008                                entry_variant,
1009                                who
1010                            );
1011                            let digest_of =
1012                                digest_of.ok_or(Error::<T, I>::DigestVariantBalanceNotFound)?;
1013
1014                            // Perform withdrawal from the entry's digest
1015                            let take = withdraw(digest_of, &entry_variant, &entry_digest, commit)?;
1016
1017                            // Accumulate total withdrawn value across all entries
1018                            taken = taken
1019                                .checked_add(&take)
1020                                .ok_or(Error::<T, I>::WithdrawAccumulationExhausted)?;
1021
1022                            Ok(())
1023                        },
1024                    )?;
1025                }
1026
1027                // Remove all commit instances for this proprietor for the current entry
1028                EntryMap::<T, I>::remove((reason, index_of, entry_digest, who));
1029            }
1030
1031            // Subtract total deposits from the index's top-level simple balance for noting deposits
1032            let index_balance = &index_info.principal();
1033            let new_balance = index_balance.checked_sub(&given);
1034            debug_assert!(
1035                new_balance.is_some(),
1036                "previous deposit value {:?} of proprietor {:?} for index {:?} 
1037                of reason {:?} is subtracted from index principal balance {:?} 
1038                during withdrawal underflowed, should not fail",
1039                given,
1040                who,
1041                index_of,
1042                reason,
1043                index_balance
1044            );
1045            let new_balance = new_balance.ok_or(Error::<T, I>::IndexBalanceUnderflow)?;
1046            index_info.set_balance(new_balance);
1047            Ok(())
1048        })?;
1049
1050        // Return the accumulated deposits and withdrawals
1051        // as the proprietor's imbalance
1052        Ok(AssetDelta {
1053            deposit: given,
1054            withdraw: taken,
1055        })
1056    }
1057
1058    /// Withdraws the committed value for a pool digest.
1059    ///
1060    /// The pool balance is released first, then each commitment within the pool is resolved.
1061    /// Withdrawn values are accumulated, pool state is recovered,
1062    /// and commissions are handled (provided to manager internally itself) according
1063    /// to the pool's configuration.
1064    ///
1065    /// This low-level operation ensures the proprietor receives their imbalance while also
1066    /// minting, burning, or reallocating tokens due to commission configuration for the
1067    /// manager only.
1068    ///
1069    /// ## Returns
1070    /// - `Ok(Imbalance)` containing total deposited and withdrawn amounts after commissions
1071    /// - `Err(DispatchError)` if the pool is not found or withdrawal fails
1072    fn withdraw_from_pool(
1073        who: &Proprietor<T>,
1074        reason: &CommitmentReason<T, I>,
1075        pool_of: &CommitmentDigest<T, I>,
1076        _variant: &CommitmentPosition<T, I>,
1077    ) -> Result<Self::Imbalance, DispatchError> {
1078        // Initialize zero values. For each slot, these will accumulate total deposits and withdrawals.
1079        let mut taken = CommitmentAsset::<T, I>::zero();
1080        let mut given = CommitmentAsset::<T, I>::zero();
1081
1082        // Pools do not have the same indirection as indexes. We maintain the proprietor's balance
1083        // as a local commitment to the pool (similar to a direct digest commitment).
1084        let commits_of =
1085            CommitMap::<T, I>::get((who, reason)).ok_or(Error::<T, I>::CommitNotFound)?;
1086        let commits = commits_of.commits();
1087
1088        // Release the pool to determine the withdrawal value. Since pools are collective funds,
1089        // we update them every time by releasing and then recovering.
1090        // Retrieve the mutable pool balance structure, analogous to a digest's
1091        // balance (just as digests track proprietor commitments, pools track
1092        // funders' deposits). This balance is temporarily exposed for mutation
1093        // during the current operation and must be recovered back to the pool
1094        // immediately afterward via `recover_pool()`.
1095        let mut pool_balance = Self::release_pool(reason, pool_of)?;
1096
1097        // Iterate through the commit instances depositted to the pool
1098        for commit in &commits {
1099            // The commit value was depositted earlier; it represents the deposited amount,
1100            // not the real-time value
1101            let commit_value = receipt_deposit_value(commit)?;
1102
1103            // Accumulate total deposits to each slot of the digest
1104            given = given
1105                .checked_add(&commit_value)
1106                .ok_or(Error::<T, I>::DepositAccumulationExhausted)?;
1107
1108            // Accumulate the withdrawal values
1109            let take = withdraw(&mut pool_balance, &Default::default(), pool_of, commit)?;
1110            taken = taken
1111                .checked_add(&take)
1112                .ok_or(Error::<T, I>::WithdrawAccumulationExhausted)?;
1113        }
1114
1115        // Recover the pool's state to the new state after withdrawal
1116        Self::recover_pool(reason, pool_of, &pool_balance)?;
1117
1118        let pool = PoolMap::<T, I>::get((reason, pool_of));
1119        debug_assert!(
1120            pool.is_some(),
1121            "recently recovered pool {:?} of reason {:?} after 
1122            withdrawal for proprietor {:?} not accessible",
1123            pool_of,
1124            reason,
1125            who
1126        );
1127
1128        let pool = pool.ok_or(Error::<T, I>::PoolNotFound)?;
1129        let commission = pool.commission();
1130
1131        let mut imbalance = AssetDelta {
1132            deposit: given,
1133            withdraw: taken,
1134        };
1135
1136        // Pools may have a commission, which is handled internally and only returned to the proprietor
1137        if commission.is_zero() {
1138            return Ok(imbalance);
1139        }
1140
1141        // Get the pool's manager
1142        let pay_to = Pallet::<T, I>::get_manager(reason, pool_of);
1143        debug_assert!(
1144            pay_to.is_ok(),
1145            "pool {:?} of reason {:?} exists but manager is not",
1146            pool_of,
1147            reason
1148        );
1149        let pay_to = pay_to?;
1150
1151        // Calculate the amount to pay the manager
1152        let parts = CommitmentAsset::<T, I>::from(commission.deconstruct());
1153        let accuracy = CommitmentAsset::<T, I>::from(T::Commission::ACCURACY);
1154
1155        // Calculate the amount to pay the manager
1156        let to_pay = taken
1157            .checked_mul(&parts)
1158            .ok_or(Error::<T, I>::CommissionOverflow)?
1159            .checked_div(&accuracy)
1160            .ok_or(Error::<T, I>::DerivedLessThanZeroValue)?;
1161
1162        // Early return if the payment is zero
1163        if to_pay.is_zero() {
1164            return Ok(imbalance);
1165        }
1166
1167        // Derive commission payout imbalance for pool manager internally done with equillibrium
1168        // maintained via safe deduction over an existing imbalance
1169        let manager_imbalance = Self::deduct_from_imbalance(&mut imbalance, to_pay)?;
1170
1171        // Expected to be a simple increase balance since the earlier call maintained equillibrium
1172        // and the `manager_imbalance` is expected to be nill imbalance-delta
1173        let manager_withdraw = Self::resolve_imbalance(&pay_to, manager_imbalance)?;
1174
1175        // Since commission payout is to the underlying system, not reinvested to
1176        // commitment system itself as the caller only expects proprietor's imbalance
1177        // Hence to maintain per reason total value maintained for quick queries
1178        Self::sub_from_total_value(reason, manager_withdraw)?;
1179
1180        // Mutated imbalance when deducted for commission payout
1181        Ok(imbalance)
1182    }
1183}
1184
1185// ===============================================================================
1186// `````````````````````````````` COMMIT OPERATIONS ``````````````````````````````
1187// ===============================================================================
1188
1189/// Implements the [`CommitOps`] trait for the pallet
1190///
1191/// Provides low-level (not-lowest, but still unchecked) write functionalities for digests, indexes,
1192/// and pools within the commitment system. This may utilize other commit-helper trait methods
1193impl<T: Config<I>, I: 'static> CommitOps<Proprietor<T>, Pallet<T, I>> for CommitHelpers<T, I> {
1194    /// Places (creates) a commitment for a given digest model with the specified variant.
1195    ///
1196    /// This function centralizes the dispatches to the appropriate underlying handler
1197    /// depending on the type of the digest model (Direct, Index, or Pool).
1198    ///
1199    /// Digest models represent different
1200    /// commitment structures:
1201    /// - **Direct**: a single digest commitment.
1202    /// - **Index**: a grouped commitment of multiple entry digests.
1203    /// - **Pool**: a shared resource i.e., a collective single commitment.
1204    ///
1205    /// ## Returns
1206    /// - `Ok(Asset)` containing the committed amount
1207    /// - `Err(DispatchError)` if placement fails
1208    fn place_commit_of(
1209        who: &Proprietor<T>,
1210        reason: &CommitmentReason<T, I>,
1211        digest_model: &CommitmentDigestModel<T, I>,
1212        value: CommitmentAsset<T, I>,
1213        variant: &CommitmentPosition<T, I>,
1214        qualifier: &DispatchPolicy,
1215    ) -> Result<CommitmentAsset<T, I>, DispatchError> {
1216        match digest_model {
1217            DigestVariant::Direct(dir) => {
1218                Self::place_digest_commit(who, reason, dir, value, variant, qualifier)
1219            }
1220            DigestVariant::Index(index) => {
1221                Self::place_index_commit(who, reason, index, value, variant, qualifier)
1222            }
1223            DigestVariant::Pool(pool) => {
1224                Self::place_pool_commit(who, reason, pool, value, variant, qualifier)
1225            }
1226            _ => {
1227                debug_assert!(
1228                    false,
1229                    "digest-model marker variants {:?} are constructed, 
1230                    captured during place commit for proprietor {:?} 
1231                    of reason {:?} are explicitly dis-allowed",
1232                    digest_model, who, reason
1233                );
1234                return Err(Error::<T, I>::InvalidDigestModel.into());
1235            }
1236        }
1237    }
1238
1239    /// Places (creates) a direct commitment for a specific digest of a given variant under a reason.
1240    ///
1241    /// This function is the base implementation for placing commitments when the digest
1242    /// represents a **single, direct item** (not an index or pool).
1243    ///
1244    /// Allows placing a commitment even if the digest does not already exist in the system.
1245    ///
1246    /// ### Returns
1247    /// - `Ok(Asset)` containing the actual committed amount
1248    /// - `Err(DispatchError)` if placement fails
1249    fn place_digest_commit(
1250        who: &Proprietor<T>,
1251        reason: &CommitmentReason<T, I>,
1252        digest: &CommitmentDigest<T, I>,
1253        value: CommitmentAsset<T, I>,
1254        variant: &CommitmentPosition<T, I>,
1255        qualifier: &DispatchPolicy,
1256    ) -> Result<CommitmentAsset<T, I>, DispatchError> {
1257        // If the digest does not exist yet, initialize it with default DigestInfo
1258        // Callers should ensure that the digest must have a deterministic way to get
1259        // into the system, else the commitment will be dormant
1260        if let Err(_) = Pallet::<T, I>::digest_exists(reason, digest) {
1261            DigestMap::<T, I>::insert((reason, digest), DigestInfo::default());
1262        }
1263        let try_actual = Self::deduct_balance(who, value, qualifier)?;
1264        let (receipt, amount) =
1265            Self::deposit_to_digest(who, reason, digest, try_actual, &variant, qualifier)?;
1266        finalize_place_commit::<T, I>(who, reason, digest, variant, &receipt, amount)?;
1267        Ok(amount)
1268    }
1269
1270    /// Places a commitment to an index digest under the specified reason.
1271    ///
1272    /// Distributes the committed value proportionally across index entries based on their
1273    /// shares, creates entry-level commitment records, and updates the index balance.
1274    ///
1275    /// ## Returns
1276    /// - `Ok(Asset)` containing the actual committed amount
1277    /// - `Err(DispatchError)` if placement fails
1278    fn place_index_commit(
1279        who: &Proprietor<T>,
1280        reason: &CommitmentReason<T, I>,
1281        index_of: &CommitmentDigest<T, I>,
1282        value: CommitmentAsset<T, I>,
1283        variant: &CommitmentPosition<T, I>,
1284        qualifier: &DispatchPolicy,
1285    ) -> Result<CommitmentAsset<T, I>, DispatchError> {
1286        let try_actual = Self::deduct_balance(who, value, qualifier)?;
1287        let (receipt, amount) =
1288            Self::deposit_to_index(who, reason, index_of, try_actual, variant, qualifier)?;
1289        finalize_place_commit::<T, I>(who, reason, index_of, variant, &receipt, amount)?;
1290        Ok(amount)
1291    }
1292
1293    /// Places a commitment to a pool digest under the specified reason.
1294    ///
1295    /// Deposits to the pool's collective balance, updates slot digests proportionally,
1296    /// and maintains pool-level commitment records.
1297    ///
1298    /// ## Returns
1299    /// - `Ok(Asset)` containing the actual committed amount
1300    /// - `Err(DispatchError)` if placement fails
1301    fn place_pool_commit(
1302        who: &Proprietor<T>,
1303        reason: &CommitmentReason<T, I>,
1304        pool_of: &CommitmentDigest<T, I>,
1305        value: CommitmentAsset<T, I>,
1306        variant: &CommitmentPosition<T, I>,
1307        qualifier: &DispatchPolicy,
1308    ) -> Result<CommitmentAsset<T, I>, DispatchError> {
1309        let try_actual = Self::deduct_balance(who, value, qualifier)?;
1310        let (receipt, amount) =
1311            Self::deposit_to_pool(who, reason, pool_of, try_actual, variant, qualifier)?;
1312        finalize_place_commit::<T, I>(who, reason, pool_of, variant, &receipt, amount)?;
1313        Ok(amount)
1314    }
1315
1316    /// Raises (increases) an existing commitment for a given digest model.
1317    ///
1318    /// This function centralizes the dispatches to the appropriate underlying handler
1319    /// depending on the type of the digest model (Direct, Index, or Pool).
1320    ///
1321    /// Digest models represent different
1322    /// commitment structures:
1323    /// - **Direct**: a single digest commitment.
1324    /// - **Index**: a grouped commitment of multiple entry digests.
1325    /// - **Pool**: a shared resource i.e., a collective single commitment.
1326    ///
1327    /// ## Returns
1328    /// - `Ok(Asset)` containing the raised amount
1329    /// - `Err(DispatchError)` if the raise operation fails
1330    fn raise_commit_of(
1331        who: &Proprietor<T>,
1332        reason: &CommitmentReason<T, I>,
1333        digest_model: &CommitmentDigestModel<T, I>,
1334        value: CommitmentAsset<T, I>,
1335        qualifier: &DispatchPolicy,
1336    ) -> Result<CommitmentAsset<T, I>, DispatchError> {
1337        match digest_model {
1338            DigestVariant::Direct(dir) => {
1339                Self::raise_digest_commit(who, reason, dir, value, qualifier)
1340            }
1341            DigestVariant::Index(index) => {
1342                Self::raise_index_commit(who, reason, index, value, qualifier)
1343            }
1344            DigestVariant::Pool(pool) => {
1345                Self::raise_pool_commit(who, reason, pool, value, qualifier)
1346            }
1347            _ => {
1348                debug_assert!(
1349                    false,
1350                    "digest-model marker variants {:?} are constructed, 
1351                    captured during raise commit for proprietor {:?} 
1352                    of reason {:?} are explicitly dis-allowed",
1353                    digest_model, who, reason
1354                );
1355                return Err(Error::<T, I>::InvalidDigestModel.into());
1356            }
1357        }
1358    }
1359
1360    /// Raises (increases) a commitment for a direct digest under a given reason.
1361    ///
1362    /// This function is the base implementation for raising commitments when the target
1363    /// is an **direct digest** rather than a index or pool.
1364    ///
1365    /// Unlike [`Self::place_digest_commit`] this adds a additional commit instance to the list
1366    /// of commits to the same direct digest enforcing the **One Reason One Digest Per
1367    /// Proprietor** invariant.
1368    ///
1369    /// ## Returns
1370    /// - `Ok(Asset)` containing the raised amount
1371    /// - `Err(DispatchError)` if the raise operation fails
1372    fn raise_digest_commit(
1373        who: &Proprietor<T>,
1374        reason: &CommitmentReason<T, I>,
1375        digest: &CommitmentDigest<T, I>,
1376        value: CommitmentAsset<T, I>,
1377        qualifier: &DispatchPolicy,
1378    ) -> Result<CommitmentAsset<T, I>, DispatchError> {
1379        let commit_variant = Pallet::<T, I>::get_commit_variant(who, reason)?;
1380        let try_actual = Self::deduct_balance(who, value, qualifier)?;
1381        let (receipt, raised) =
1382            Self::deposit_to_digest(who, reason, digest, try_actual, &commit_variant, qualifier)?;
1383        finalize_raise_commit::<T, I>(who, reason, &receipt, raised)?;
1384        Ok(raised)
1385    }
1386
1387    /// Raises (increases) an existing commitment for a specific index under a given reason.
1388    ///
1389    /// This function is the base implementation for raising commitments when the target
1390    /// is an **index** rather than a digest or pool.
1391    ///
1392    /// Unlike [`Self::place_index_commit`] this adds a additional commit instance to the list
1393    /// of commits to the same index digest enforcing the **One Reason One Digest Per
1394    /// Proprietor** invariant.
1395    ///
1396    /// ## Returns
1397    /// - `Ok(Asset)` containing the raised amount
1398    /// - `Err(DispatchError)` if the raise operation fails
1399    fn raise_index_commit(
1400        who: &Proprietor<T>,
1401        reason: &CommitmentReason<T, I>,
1402        index_of: &CommitmentDigest<T, I>,
1403        value: CommitmentAsset<T, I>,
1404        qualifier: &DispatchPolicy,
1405    ) -> Result<CommitmentAsset<T, I>, DispatchError> {
1406        let try_actual = Self::deduct_balance(who, value, qualifier)?;
1407        let (receipt, raised) = Self::deposit_to_index(
1408            who,
1409            reason,
1410            index_of,
1411            try_actual,
1412            &T::Position::default(),
1413            qualifier,
1414        )?;
1415        finalize_raise_commit::<T, I>(who, reason, &receipt, raised)?;
1416        Ok(raised)
1417    }
1418
1419    /// Raises (increases) an existing commitment for a specific pool digest under a given reason.
1420    ///
1421    /// This function is the base implementation for raising commitments when the target
1422    /// is an **pool** rather than a digest or index.
1423    ///
1424    /// Unlike [`Self::place_pool_commit`] this adds a additional commit instance to the list
1425    /// of commits to the same pool digest enforcing the **One Reason One Digest Per
1426    /// Proprietor** invariant.
1427    ///
1428    /// ## Returns
1429    /// - `Ok(Asset)` containing the raised amount
1430    /// - `Err(DispatchError)` if the raise operation fails
1431    fn raise_pool_commit(
1432        who: &Proprietor<T>,
1433        reason: &CommitmentReason<T, I>,
1434        pool_of: &CommitmentDigest<T, I>,
1435        value: CommitmentAsset<T, I>,
1436        qualifier: &DispatchPolicy,
1437    ) -> Result<CommitmentAsset<T, I>, DispatchError> {
1438        let try_actual = Self::deduct_balance(who, value, qualifier)?;
1439        let (receipt, raised) = Self::deposit_to_pool(
1440            who,
1441            reason,
1442            pool_of,
1443            try_actual,
1444            &T::Position::default(),
1445            qualifier,
1446        )?;
1447        finalize_raise_commit::<T, I>(who, reason, &receipt, raised)?;
1448        Ok(raised)
1449    }
1450
1451    /// Resolves (withdraws) and finalizes a commitment for a given digest model.
1452    ///
1453    /// This function centralizes the dispatches to the appropriate underlying handler
1454    /// depending on the type of the digest model (Direct, Index, or Pool).
1455    ///
1456    /// Digest models represent different
1457    /// commitment structures:
1458    /// - **Direct**: a single digest commitment.
1459    /// - **Index**: a grouped commitment of multiple entry digests.
1460    /// - **Pool**: a shared resource i.e., a collective single commitment.
1461    ///
1462    /// ## Returns
1463    /// - `Ok(Asset)` containing the resolved commitment value
1464    /// - `Err(DispatchError)` if resolution fails
1465    fn resolve_commit_of(
1466        who: &Proprietor<T>,
1467        reason: &CommitmentReason<T, I>,
1468        digest_model: &CommitmentDigestModel<T, I>,
1469    ) -> Result<CommitmentAsset<T, I>, DispatchError> {
1470        match digest_model {
1471            DigestVariant::Direct(dir) => Self::resolve_digest_commit(who, reason, dir),
1472            DigestVariant::Index(index) => Self::resolve_index_commit(who, reason, index),
1473            DigestVariant::Pool(pool) => Self::resolve_pool_commit(who, reason, pool),
1474            _ => {
1475                debug_assert!(
1476                    false,
1477                    "digest-model marker variants {:?} are constructed, 
1478                    captured during resolve commit for proprietor {:?} 
1479                    of reason {:?} are explicitly dis-allowed",
1480                    digest_model, who, reason
1481                );
1482                return Err(Error::<T, I>::InvalidDigestModel.into());
1483            }
1484        }
1485    }
1486
1487    /// Resolves (withdraws) and finalizes a commitment for a direct digest under a given reason.
1488    ///
1489    /// This function is the base implementation for resolving commitments when the target
1490    /// is an **direct digest** rather than a index or pool.
1491    ///
1492    /// It resolves all commit instances tied to a direct digest of a reason.
1493    ///
1494    /// ## Returns
1495    /// - `Ok(Asset)` containing the resolved commitment value
1496    /// - `Err(DispatchError)` if resolution fails
1497    fn resolve_digest_commit(
1498        who: &Proprietor<T>,
1499        reason: &CommitmentReason<T, I>,
1500        digest: &CommitmentDigest<T, I>,
1501    ) -> Result<CommitmentAsset<T, I>, DispatchError> {
1502        let variant = Pallet::<T, I>::get_commit_variant(who, reason)?;
1503        let imbalance = Self::withdraw_from_digest(who, reason, digest, &variant)?;
1504        finalize_resolve_commit::<T, I>(who, reason, imbalance)
1505    }
1506
1507    /// Resolves (withdraws) and finalizes a commitment for a index digest under a given reason.
1508    ///
1509    /// This function is the base implementation for resolving commitments when the target
1510    /// is an **index** rather than a direct digest or pool.
1511    ///
1512    /// It resolves all commit instances tied to a index digest of a reason.
1513    ///
1514    /// ## Returns
1515    /// - `Ok(Asset)` containing the resolved commitment value
1516    /// - `Err(DispatchError)` if resolution fails
1517    fn resolve_index_commit(
1518        who: &Proprietor<T>,
1519        reason: &CommitmentReason<T, I>,
1520        index_of: &CommitmentDigest<T, I>,
1521    ) -> Result<CommitmentAsset<T, I>, DispatchError> {
1522        let variant = Pallet::<T, I>::get_commit_variant(who, reason)?;
1523        let imbalance = Self::withdraw_from_index(who, reason, index_of, &variant)?;
1524        finalize_resolve_commit::<T, I>(who, reason, imbalance)
1525    }
1526
1527    /// Resolves (withdraws) and finalizes a commitment for a pool digest under a given reason.
1528    ///
1529    /// This function is the base implementation for resolving commitments when the target
1530    /// is an **pool** rather than a direct digest or index.
1531    ///
1532    /// It resolves all commit instances tied to a pool digest of a reason.
1533    ///
1534    /// ### Returns
1535    /// - `Ok(Asset)` containing the resolved commitment value
1536    /// - `Err(DispatchError)` if resolution fails
1537    fn resolve_pool_commit(
1538        who: &Proprietor<T>,
1539        reason: &CommitmentReason<T, I>,
1540        pool_of: &CommitmentDigest<T, I>,
1541    ) -> Result<CommitmentAsset<T, I>, DispatchError> {
1542        let variant = Pallet::<T, I>::get_commit_variant(who, reason)?;
1543        let imbalance = Self::withdraw_from_pool(who, reason, pool_of, &variant)?;
1544        finalize_resolve_commit::<T, I>(who, reason, imbalance)
1545    }
1546
1547    /// Sets the total asset value for a given reason.
1548    ///
1549    /// **Use with caution!** This is a low-level storage operation
1550    /// that directly updates the reason's total value without validation.
1551    ///
1552    /// For safe usage [`Self::add_to_total_value`] and [`Self::sub_from_total_value`].
1553    ///
1554    /// Used internally during deposit and withdrawal operations to maintain
1555    /// accurate aggregate tracking.
1556    ///
1557    /// This value should not be treated like digest values,
1558    /// rewards/inflation, or penalties/deflation.
1559    fn set_total_value(reason: &CommitmentReason<T, I>, value: CommitmentAsset<T, I>) {
1560        ReasonValue::<T, I>::set(reason, Some(value));
1561    }
1562}
1563
1564// ===============================================================================
1565// ````````````````````````````` FINALIZATION HELPERS ````````````````````````````
1566// ===============================================================================
1567
1568/// Low-level helper that centralizes the finalization logic for placing commits.
1569///
1570/// This function is used across direct, index, and pool digests and serves as
1571/// the final step of the place a new commit's operation.
1572///
1573/// Highly unchecked and assumes all invariants are already validated.
1574/// Therefore, it is kept private and scoped to this module.
1575fn finalize_place_commit<T: Config<I>, I: 'static>(
1576    who: &Proprietor<T>,
1577    reason: &CommitmentReason<T, I>,
1578    digest: &CommitmentDigest<T, I>,
1579    variant: &CommitmentPosition<T, I>,
1580    receipt: &CommitInstance<T, I>,
1581    total_commit: CommitmentAsset<T, I>,
1582) -> Result<(), DispatchError> {
1583    // New freeze for the reason; set_freeze is used because this is a fresh freeze
1584    // unlike raise_* methods which would increase an existing frozen amount
1585    T::Asset::set_freeze(reason, who, total_commit)?;
1586
1587    // Add a new commit to the list of commits for this proprietor
1588    // Unlike raise_* methods, which add new instances to existing commits,
1589    // this creates a new CommitInfo (which will include the first commit-instance)
1590    let commit_info = CommitInfo::<T, I>::new(digest.clone(), receipt.clone(), variant.clone())?;
1591    CommitMap::<T, I>::insert((who, reason), commit_info);
1592
1593    // Adds to the reason's total value for quick queries
1594    CommitHelpers::<T, I>::add_to_total_value(reason, total_commit)?;
1595
1596    Ok(())
1597}
1598
1599/// Low-level helper that centralizes the finalization logic for raising commits.
1600///
1601/// This function is used across direct, index, and pool digests and serves as
1602/// the final step of the raise an existing commit's operation.
1603///
1604/// Highly unchecked and assumes all invariants are already validated.
1605/// Therefore, it is kept private and scoped to this module.
1606fn finalize_raise_commit<T: Config<I>, I: 'static>(
1607    who: &Proprietor<T>,
1608    reason: &CommitmentReason<T, I>,
1609    receipt: &CommitInstance<T, I>,
1610    total_raise: CommitmentAsset<T, I>,
1611) -> Result<(), DispatchError> {
1612    // Increase the frozen balance for the proprietor for this reason (since it is a raise)
1613    T::Asset::increase_frozen(reason, who, total_raise)?;
1614
1615    // Add a new commit instance to the existing commit info
1616    CommitMap::<T, I>::mutate((who, reason), |result| -> DispatchResult {
1617        let commit_info = result.as_mut();
1618        debug_assert!(
1619            commit_info.is_some(),
1620            "finalize raise commit for proprietor {:?} already commited 
1621            digest of reason {:?} called without assuring commit-exists for 
1622            raising {:?}",
1623            who,
1624            reason,
1625            total_raise,
1626        );
1627        let commit_info = commit_info.ok_or(Error::<T, I>::CommitNotFound)?;
1628        commit_info.add_commit(receipt.clone())?;
1629        Ok(())
1630    })?;
1631
1632    // Adds to the reason's total value for quick queries
1633    CommitHelpers::<T, I>::add_to_total_value(reason, total_raise)?;
1634
1635    Ok(())
1636}
1637
1638/// Low-level helper that centralizes the finalization logic for resolving commits.
1639///
1640/// This function is used across direct, index, and pool digests and serves as
1641/// the final step of the resolving an existing commit's operation.
1642///
1643/// Highly unchecked and assumes all invariants are already validated.
1644/// Therefore, it is kept private and scoped to this module.
1645fn finalize_resolve_commit<T: Config<I>, I: 'static>(
1646    who: &Proprietor<T>,
1647    reason: &CommitmentReason<T, I>,
1648    imbalance: AssetDelta<T, I>,
1649) -> Result<CommitmentAsset<T, I>, DispatchError> {
1650    // Remove the commitment for the reason, as a proprietor can
1651    // have utmost a single commitment (commit-instances) to a digest of reason
1652    CommitMap::<T, I>::remove((who, reason));
1653    // Removes the fungible freeze lock completely, we don't
1654    // care about the value, as its the finalization step
1655    T::Asset::thaw(reason, who)?;
1656    // Resolve the asset balance to the proprietor back
1657    let resolved = CommitHelpers::<T, I>::resolve_imbalance(who, imbalance)?;
1658    // Take from the reason's total value as its resolved from the commitment system
1659    // to the underlying fungible system.
1660    CommitHelpers::<T, I>::sub_from_total_value(reason, resolved)?;
1661    Ok(resolved)
1662}
1663
1664// ===============================================================================
1665// ```````````````````````````````` COMMIT INSPECT ```````````````````````````````
1666// ===============================================================================
1667
1668/// Implements the [`CommitInspect`] trait for the pallet, providing low-level
1669/// inspection and querying capabilities for committed values across digests,
1670/// indexes, and pools.
1671///
1672/// This implementation allows retrieving **real-time committed values** without
1673/// altering state, supporting precise accounting and auditability. All functions
1674/// are **low-level and unchecked**, meaning callers are responsible for ensuring
1675/// correctness and invariants before invoking.
1676impl<T: Config<I>, I: 'static> CommitInspect<Proprietor<T>, Pallet<T, I>> for CommitHelpers<T, I> {
1677    /// Retrieves the total committed value of a proprietor for a
1678    /// fully resolved digest model.
1679    ///
1680    /// This function centralizes the dispatch logic to the appropriate
1681    /// handler depending on the type of the digest model.
1682    ///
1683    /// Digest models represent different
1684    /// commitment structures:
1685    /// - **Direct**: a single digest commitment.
1686    /// - **Index**: a grouped commitment of multiple entry digests.
1687    /// - **Pool**: a shared resource i.e., a collective single commitment.
1688    ///
1689    /// ## Returns
1690    /// - `Ok(Asset)` containing the real-time committed value
1691    /// - `Err(DispatchError)` if the digest model is invalid or any underlying query fails
1692    fn commit_value_of(
1693        who: &Proprietor<T>,
1694        reason: &CommitmentReason<T, I>,
1695        digest_model: &CommitmentDigestModel<T, I>,
1696    ) -> Result<CommitmentAsset<T, I>, DispatchError> {
1697        match digest_model {
1698            DigestVariant::Direct(dir) => Self::digest_commit_value(who, reason, dir),
1699            DigestVariant::Index(index) => Self::index_commit_value(who, reason, index),
1700            DigestVariant::Pool(pool) => Self::pool_commit_value(who, reason, pool),
1701            _ => {
1702                debug_assert!(
1703                    false,
1704                    "digest-model marker variants {:?} are constructed, 
1705                    captured during commit value query for proprietor {:?} 
1706                    of reason {:?} are explicitly dis-allowed",
1707                    digest_model, who, reason
1708                );
1709                return Err(Error::<T, I>::InvalidDigestModel.into());
1710            }
1711        }
1712    }
1713
1714    /// Retrieves the proprietor's committed value for a **direct digest**
1715    /// of a given reason.
1716    ///
1717    /// ## Returns
1718    /// - `Ok(Asset)` representing the real-time committed value for
1719    /// the digest
1720    /// - `Err(DispatchError)` otherwise
1721    fn digest_commit_value(
1722        who: &Proprietor<T>,
1723        reason: &CommitmentReason<T, I>,
1724        digest: &CommitmentDigest<T, I>,
1725    ) -> Result<CommitmentAsset<T, I>, DispatchError> {
1726        // Retrieve the digest information for the given reason and digest
1727        let digest_info =
1728            DigestMap::<T, I>::get((reason, digest)).ok_or(Error::<T, I>::DigestNotFound)?;
1729
1730        // Retrieve the proprietor's commit information for this reason
1731        let commit_info =
1732            CommitMap::<T, I>::get((who, reason)).ok_or(Error::<T, I>::CommitNotFound)?;
1733
1734        // Initialize total committed value accumulator for commit-instances folding
1735        let mut total = CommitmentAsset::<T, I>::zero();
1736
1737        // Determine the index of the digest variant for this commit
1738        let variant = commit_info.variant();
1739
1740        // Retrieve the balance for the specific digest variant
1741        let digest_of = digest_info.get_balance(&variant);
1742        debug_assert!(
1743            digest_of.is_some(),
1744            "digest {:?} of reason {:?} variant {:?} balance 
1745            was not initiated properly in the balance vector
1746            during the deposit for proprietor {:?}",
1747            digest,
1748            reason,
1749            variant,
1750            who
1751        );
1752        let digest_of = digest_of.ok_or(Error::<T, I>::DigestVariantBalanceNotFound)?;
1753
1754        // Iterate over each commit instance associated with this proprietor
1755        let commits = commit_info.commits();
1756        for commit in &commits {
1757            let take = receipt_active_value(digest_of, &variant, digest, commit)?;
1758            // Accumulate the real-time commit value into the total
1759            total = total
1760                .checked_add(&take)
1761                .ok_or(Error::<T, I>::CommitsAccumulationExhausted)?;
1762        }
1763
1764        // Return the aggregated real-time committed value for this digest
1765        Ok(total)
1766    }
1767
1768    /// Computes the total committed value of a proprietor for a
1769    /// given index digest.
1770    ///
1771    /// ## Returns
1772    /// - `Ok(Asset)` with the total committed value for the index
1773    /// - `Err(DispatchError)` otherwise
1774    fn index_commit_value(
1775        who: &Proprietor<T>,
1776        reason: &CommitmentReason<T, I>,
1777        index_of: &CommitmentDigest<T, I>,
1778    ) -> Result<CommitmentAsset<T, I>, DispatchError> {
1779        // Initialize accumulator for total committed value
1780        let mut total = CommitmentAsset::<T, I>::zero();
1781
1782        // Retrieve index info and its entries
1783        let index_info = Pallet::<T, I>::get_index(reason, index_of)?;
1784        let entries = index_info.entries();
1785
1786        // Iterate through each entry in the index
1787        for entry in entries {
1788            let entry_digest = &entry.digest();
1789            let entry_variant = &entry.variant();
1790
1791            // Retrieve all commit instances for this proprietor and entry
1792            let commits = EntryMap::<T, I>::get((reason, &index_of, entry_digest, who))
1793                .ok_or(Error::<T, I>::CommitNotFoundForEntry)?;
1794            // Retrieve digest info for this entry
1795            let digest_info = DigestMap::<T, I>::get((reason, &entry_digest))
1796                .ok_or(Error::<T, I>::EntryOfIndexNotFound)?;
1797
1798            let digest_of = digest_info.get_balance(entry_variant);
1799            debug_assert!(
1800                digest_of.is_some(),
1801                "index-digest {:?} of reason {:?} entry {:?} variant {:?} balance 
1802                was not initiated properly in the balance vector 
1803                during the deposit for proprietor {:?}",
1804                index_of,
1805                reason,
1806                entry_digest,
1807                entry_variant,
1808                who
1809            );
1810            let digest_of = digest_of.ok_or(Error::<T, I>::DigestVariantBalanceNotFound)?;
1811            // Iterate through each commit to compute its effective contribution
1812            for commit in &commits.commits() {
1813                let take = receipt_active_value(digest_of, entry_variant, entry_digest, commit)?;
1814
1815                // Accumulate into total committed value
1816                total = total
1817                    .checked_add(&take)
1818                    .ok_or(Error::<T, I>::CommitsAccumulationExhausted)?;
1819            }
1820        }
1821
1822        Ok(total)
1823    }
1824
1825    /// Computes the total committed value of a proprietor for a
1826    /// specific entry within an index.
1827    ///
1828    /// ## Returns
1829    /// - `Ok(Asset)` containing the total committed value for the entry
1830    /// - `Err(DispatchError)` otherwise
1831    fn index_entry_commit_value(
1832        who: &Proprietor<T>,
1833        reason: &CommitmentReason<T, I>,
1834        index_of: &CommitmentDigest<T, I>,
1835        entry_of: &CommitmentDigest<T, I>,
1836    ) -> Result<CommitmentAsset<T, I>, DispatchError> {
1837        // Retrieve the index and its entries
1838        let index_info = Pallet::<T, I>::get_index(reason, index_of)?;
1839        let entries = index_info.entries();
1840
1841        // Locate the entry within the index
1842        let mut entry_idx = None;
1843        for (i, entry) in entries.iter().enumerate() {
1844            if entry.digest() == *entry_of {
1845                entry_idx = Some(i);
1846            }
1847        }
1848        let Some(entry_idx) = entry_idx else {
1849            return Err(Error::<T, I>::EntryOfIndexNotFound.into());
1850        };
1851
1852        // Get the entry object and its variant
1853        let entry = entries
1854            .get(entry_idx)
1855            .ok_or(Error::<T, I>::EntryOfIndexNotFound)?;
1856        let entry_variant = &entry.variant();
1857
1858        // Retrieve all commit instances for this proprietor and entry
1859        let commits = EntryMap::<T, I>::get((reason, index_of, entry_of, who))
1860            .ok_or(Error::<T, I>::CommitNotFoundForEntry)?;
1861
1862        // Initialize accumulator for total committed value
1863        let mut total = CommitmentAsset::<T, I>::zero();
1864        // Retrieve the digest info for this entry
1865
1866        let digest_info =
1867            DigestMap::<T, I>::get((reason, entry_of)).ok_or(Error::<T, I>::EntryDigestNotFound)?;
1868        let digest_of = digest_info.get_balance(entry_variant);
1869        debug_assert!(
1870            digest_of.is_some(),
1871            "index-digest {:?} of reason {:?} entry {:?} variant {:?} balance 
1872            was not initiated properly in the balance vector
1873            during the deposit for proprietor {:?}",
1874            index_of,
1875            reason,
1876            entry_of,
1877            entry_variant,
1878            who
1879        );
1880        let digest_of = digest_of.ok_or(Error::<T, I>::DigestVariantBalanceNotFound)?;
1881
1882        // Iterate through each commit to compute its effective contribution
1883        for commit in &commits.commits() {
1884            let take = receipt_active_value(digest_of, entry_variant, entry_of, commit)?;
1885            // Accumulate into total committed value
1886            total = total
1887                .checked_add(&take)
1888                .ok_or(Error::<T, I>::CommitsAccumulationExhausted)?;
1889        }
1890
1891        Ok(total)
1892    }
1893
1894    /// Computes the total committed value of a proprietor
1895    /// for a given pool.
1896    ///
1897    /// ## Returns
1898    /// - `Ok(Asset)` with the total effective committed value
1899    /// - `Err(DispatchError)` otherwise
1900    fn pool_commit_value(
1901        who: &Proprietor<T>,
1902        reason: &CommitmentReason<T, I>,
1903        pool_of: &CommitmentDigest<T, I>,
1904    ) -> Result<CommitmentAsset<T, I>, DispatchError> {
1905        let pool_info = Pallet::<T, I>::get_pool(reason, pool_of)?;
1906        let commit_info =
1907            CommitMap::<T, I>::get((who, reason)).ok_or(Error::<T, I>::CommitNotFound)?;
1908        ensure!(
1909            commit_info.digest() == *pool_of,
1910            Error::<T, I>::CommitNotFoundForPool
1911        );
1912
1913        // Initialize zero values. For each slot, these will accumulate total
1914        // deposits and withdrawals.
1915        let mut taken = CommitmentAsset::<T, I>::zero();
1916
1917        let pool_capital = pool_info.capital();
1918        debug_assert!(
1919            !pool_capital.is_zero(),
1920            "pool {:?} of reason {:?} capital is constructed at zero",
1921            pool_of,
1922            reason
1923        );
1924        ensure!(!pool_capital.is_zero(), Error::<T, I>::CapitalCannotBeZero);
1925
1926        let slots = &pool_info.slots();
1927        let first_slot = &slots.iter().next();
1928        debug_assert!(
1929            first_slot.is_some(),
1930            "pool {:?} of reason {:?} constructed with empty slots",
1931            pool_of,
1932            reason,
1933        );
1934        let first_slot = first_slot.ok_or(Error::<T, I>::EmptySlotsNotAllowed)?;
1935        if first_slot.commit() == Default::default() {
1936            return Ok(Zero::zero());
1937        }
1938
1939        // Iterate through all active pool slots
1940        for slot in slots {
1941            let digest = &slot.digest();
1942            let slot_share = slot.shares();
1943
1944            debug_assert!(
1945                !slot_share.is_zero(),
1946                "pool {:?} of reason {:?} slot {:?} 
1947                share is found to be zero",
1948                pool_of,
1949                reason,
1950                slot.digest()
1951            );
1952            ensure!(!slot_share.is_zero(), Error::<T, I>::ShareCannotBeZero);
1953            debug_assert!(
1954                pool_capital >= slot_share,
1955                "pool {:?} of reason {:?}  capital of value {:?} is constructed 
1956                as lesser than the slot {:?} share {:?}",
1957                pool_of,
1958                reason,
1959                pool_capital,
1960                slot.digest(),
1961                slot_share
1962            );
1963
1964            let slot_commit = &slot.commit();
1965
1966            let digest_info = DigestMap::<T, I>::get((reason, digest))
1967                .ok_or(Error::<T, I>::SlotOfPoolNotFound)?;
1968
1969            // Take slot's variant in the pool to find the variant in the digest
1970            let slot_variant = &slot.variant();
1971
1972            // variant balance of the slot's digest
1973            let balance = digest_info.get_balance(slot_variant);
1974            debug_assert!(
1975                balance.is_some(),
1976                "pool-digest {:?} of reason {:?} slot {:?} variant {:?} balance 
1977                was not initiated properly in the balance vector
1978                properly during pool-value operation",
1979                pool_of,
1980                reason,
1981                digest,
1982                slot_variant,
1983            );
1984            let balance = balance.ok_or(Error::<T, I>::DigestVariantBalanceNotFound)?;
1985
1986            let take = receipt_active_value(balance, slot_variant, digest, slot_commit)?;
1987
1988            taken = taken
1989                .checked_add(&take)
1990                .ok_or(Error::<T, I>::WithdrawAccumulationExhausted)?;
1991        }
1992
1993        let mut pool_balance = pool_info.balance();
1994        let pool_effective = balance_total(&pool_balance, &Default::default(), pool_of)?;
1995        match pool_effective.cmp(&taken) {
1996            Ordering::Less => {
1997                let lack = taken.saturating_sub(pool_effective);
1998                let minted = mint(
1999                    &mut pool_balance,
2000                    &Default::default(),
2001                    pool_of,
2002                    &lack,
2003                    &Directive::new(Precision::Exact, Fortitude::Force),
2004                )?;
2005                ensure!(minted.eq(&lack), Error::<T, I>::PoolUnsupported);
2006            }
2007            Ordering::Greater => {
2008                let excess = pool_effective.saturating_sub(taken);
2009                let reaped = reap(
2010                    &mut pool_balance,
2011                    &Default::default(),
2012                    pool_of,
2013                    &excess,
2014                    &Directive::new(Precision::Exact, Fortitude::Force),
2015                )?;
2016                ensure!(reaped.eq(&excess), Error::<T, I>::PoolUnsupported);
2017            }
2018            Ordering::Equal => {}
2019        }
2020
2021        let mut total = CommitmentAsset::<T, I>::zero();
2022        for commit in commit_info.commits() {
2023            let take = withdraw(&mut pool_balance, &Default::default(), pool_of, &commit)?;
2024            total = total
2025                .checked_add(&take)
2026                .ok_or(Error::<T, I>::CommitsAccumulationExhausted)?;
2027        }
2028        Ok(total)
2029    }
2030
2031    /// Computes the commit value of a specific slot for a given proprietor
2032    /// within a pool.
2033    ///
2034    /// ## Returns
2035    /// - `Ok(Asset>)` representing the slot's effective value for the proprietor
2036    /// - `Err(DispatchError)` if calculation fails
2037    fn pool_slot_commit_value(
2038        who: &Proprietor<T>,
2039        reason: &CommitmentReason<T, I>,
2040        pool_of: &CommitmentDigest<T, I>,
2041        slot_of: &CommitmentDigest<T, I>,
2042    ) -> Result<CommitmentAsset<T, I>, DispatchError> {
2043        let pool_commit = Self::pool_commit_value(who, reason, pool_of)?;
2044        let pool_info = Pallet::<T, I>::get_pool(reason, pool_of);
2045        debug_assert!(
2046            pool_info.is_ok(),
2047            "pool {:?} of reason {:?} commit value for proprietor 
2048            {:?} dervied, but underlying info cannot get",
2049            pool_of,
2050            reason,
2051            who
2052        );
2053        let pool_info = pool_info?;
2054        let mut slot_share = None;
2055        for slot in pool_info.slots() {
2056            if slot.digest() == *slot_of {
2057                slot_share = Some(slot.shares());
2058            }
2059        }
2060        let slot_share = slot_share.ok_or(Error::<T, I>::SlotOfPoolNotFound)?;
2061        debug_assert!(
2062            !slot_share.is_zero(),
2063            "pool {:?} of reason {:?} slot {:?} 
2064            share is found to be zero",
2065            pool_of,
2066            reason,
2067            slot_of
2068        );
2069        ensure!(!slot_share.is_zero(), Error::<T, I>::ShareCannotBeZero);
2070        let pool_capital = pool_info.capital();
2071        debug_assert!(
2072            pool_capital >= slot_share,
2073            "pool {:?} of reason {:?}  capital of value {:?} is constructed 
2074             as lesser than the slot {:?} share {:?}",
2075            pool_of,
2076            reason,
2077            pool_capital,
2078            slot_of,
2079            slot_share
2080        );
2081        let factor = T::Bias::checked_from_rational(slot_share, pool_capital)
2082            .ok_or(Error::<T, I>::TooSmallShareValue)?;
2083        let value_fixed = T::Bias::saturating_from_integer(pool_commit);
2084        let val_fixed = value_fixed
2085            .checked_mul(&factor)
2086            .ok_or(Error::<T, I>::WithdrawalOverflow)?;
2087        if val_fixed < One::one() {
2088            return Ok(Zero::zero());
2089        }
2090        let val_scaled = val_fixed
2091            .into_inner()
2092            // ensured no NAN possibility
2093            .checked_div(&T::Bias::DIV)
2094            .ok_or(Error::<T, I>::DerivedLessThanZeroValue)?;
2095
2096        let val: CommitmentAsset<T, I> = val_scaled.into();
2097        Ok(val)
2098    }
2099
2100    /// Retrieves the total value of a reason or a specific digest model.
2101    ///
2102    /// For a specific digest model, computes the total of all dispositions
2103    /// (`Affirmative`, `Contrary`, `Awaiting`) for direct digests, or delegates to
2104    /// index/pool calculations as appropriate. If no model is provided, returns the
2105    /// stored top-level reason value.
2106    ///
2107    /// ### Returns
2108    /// - `Ok(CommitmentAsset<T, I>)` representing the total value
2109    /// - `Err(DispatchError)` if the reason is not found or digest value calculation fails
2110    fn value_of(
2111        digest_model: Option<&CommitmentDigestModel<T, I>>,
2112        reason: &CommitmentReason<T, I>,
2113    ) -> Result<CommitmentAsset<T, I>, DispatchError> {
2114        if let Some(model) = digest_model {
2115            let mut value: CommitmentAsset<T, I> = Zero::zero();
2116            match model {
2117                // Direct digest: sum up all dispositions
2118                DigestVariant::Direct(dir) => {
2119                    let len = <T::Position as VariantCount>::VARIANT_COUNT;
2120                    for i in 0..len {
2121                        let curr = Pallet::<T, I>::get_digest_variant_value(
2122                            reason,
2123                            dir,
2124                            &T::Position::position_of(i as usize)
2125                                .ok_or(Error::<T, I>::InvalidCommitVariantIndex)?,
2126                        )?;
2127                        value = value.saturating_add(curr)
2128                    }
2129                }
2130
2131                // Index digest: get the aggregated index value
2132                DigestVariant::Index(index) => {
2133                    value = Pallet::<T, I>::get_index_value(reason, index)?;
2134                }
2135
2136                // Pool digest: get the aggregated pool value
2137                DigestVariant::Pool(pool) => {
2138                    value = Pallet::<T, I>::get_pool_value(reason, pool)?;
2139                }
2140
2141                _ => {
2142                    debug_assert!(
2143                        false,
2144                        "digest-model marker variants {:?} are constructed, 
2145                        captured during value query for reason {:?} are explicitly 
2146                        dis-allowed",
2147                        digest_model, reason
2148                    );
2149                    return Err(Error::<T, I>::InvalidDigestModel.into());
2150                }
2151            }
2152            return Ok(value);
2153        }
2154
2155        // Return top-level reason value if no model is provided
2156        let value =
2157            ReasonValue::<T, I>::get(reason).ok_or(Error::<T, I>::CommitsNotFoundForReason)?;
2158        Ok(value)
2159    }
2160}
2161
2162// ===============================================================================
2163// ``````````````````````````````` POOL OPERATIONS ```````````````````````````````
2164// ===============================================================================
2165
2166/// Implementation of [`PoolOps`] for the pallet, defining how pools slots
2167/// are queried, inserted, updated, or removed within a given index digest.
2168///
2169/// Each function operates on the *pool-slot composition layer* - maintaining
2170/// relationships between an pool digest and its subordinate slot digests.
2171impl<T: Config<I>, I: 'static> PoolOps<Proprietor<T>, Pallet<T, I>> for CommitHelpers<T, I> {
2172    /// Uses [`LazyBalanceOf`] to track both the *real-time effective* balance and the
2173    /// *total principal deposits* contributed by all proprietors of the pool.
2174    ///
2175    /// Each proprietor's deposit (commit) into the pool is recorded as a [`CommitInstance`]
2176    /// inside its storage.
2177    type PoolBalance = LazyBalanceOf<T, I>;
2178
2179    /// Releases a pool's balance into a detached representation.
2180    ///
2181    /// Resolves all active slot digests belonging to the pool, withdraws their
2182    /// values proportionally, and resets the pool's stored balance to default.
2183    /// The released balance can then be modified before being recovered.
2184    ///
2185    /// ## Returns
2186    /// - `Ok(Balance)` containing the released pool balance
2187    /// - `Err(DispatchError)` if the pool is not found or release fails
2188    fn release_pool(
2189        reason: &CommitmentReason<T, I>,
2190        pool_of: &CommitmentDigest<T, I>,
2191    ) -> Result<Self::PoolBalance, DispatchError> {
2192        // In case if pool is empty, return early
2193        let pool = Pallet::<T, I>::get_pool(reason, pool_of)?;
2194        let mut pool_balance = pool.balance();
2195        if pool_balance == Self::PoolBalance::default() {
2196            return Ok(pool_balance);
2197        }
2198
2199        // Initialize zero values. For each slot, these will accumulate total deposits and withdrawals.
2200        let mut taken = CommitmentAsset::<T, I>::zero();
2201        let pool_capital = pool.capital();
2202        debug_assert!(
2203            !pool_capital.is_zero(),
2204            "pool {:?} of reason {:?} capital is constructed at zero",
2205            pool_of,
2206            reason
2207        );
2208        ensure!(!pool_capital.is_zero(), Error::<T, I>::CapitalCannotBeZero);
2209        // Mutate the pool storage entry for (reason, pool_of)
2210        PoolMap::<T, I>::mutate((reason, pool_of), |result| -> DispatchResult {
2211            let pool_info = result.as_mut();
2212            debug_assert!(
2213                pool_info.is_some(),
2214                "pool {:?} of reason {:?} exists, but cannot mutate",
2215                pool_of,
2216                reason
2217            );
2218            let pool_info = pool_info.ok_or(Error::<T, I>::PoolNotFound)?;
2219            // Iterate through all active pool slots
2220            let slots = &pool_info.slots();
2221            for slot in slots {
2222                let digest = &slot.digest();
2223                let slot_share = slot.shares();
2224
2225                debug_assert!(
2226                    !slot_share.is_zero(),
2227                    "pool {:?} of reason {:?} slot {:?} 
2228                    share is found to be zero",
2229                    pool_of,
2230                    reason,
2231                    slot.digest()
2232                );
2233                ensure!(!slot_share.is_zero(), Error::<T, I>::ShareCannotBeZero);
2234                debug_assert!(
2235                    pool_capital >= slot_share,
2236                    "pool {:?} of reason {:?}  capital of value {:?} is constructed 
2237                    as lesser than the slot {:?} share {:?}",
2238                    pool_of,
2239                    reason,
2240                    pool_capital,
2241                    slot.digest(),
2242                    slot_share
2243                );
2244
2245                let slot_commit = &slot.commit();
2246
2247                if *slot_commit == Default::default() {
2248                    continue;
2249                }
2250
2251                // Release each slot via its digest
2252                DigestMap::<T, I>::mutate((reason, digest), |result| -> DispatchResult {
2253                    let digest_info = result.as_mut().ok_or(Error::<T, I>::SlotOfPoolNotFound)?;
2254
2255                    // Take slot's variant in the pool to find the variant in the digest
2256                    let slot_variant = &slot.variant();
2257
2258                    // variant balance of the slot's digest
2259                    let balance = digest_info.mut_balance(slot_variant);
2260                    debug_assert!(
2261                        balance.is_some(),
2262                        "pool-digest {:?} of reason {:?} slot {:?} variant {:?} balance 
2263                        was not initiated properly in the balance vector
2264                        properly during release-pool operation",
2265                        pool_of,
2266                        reason,
2267                        digest,
2268                        slot_variant,
2269                    );
2270                    let balance = balance.ok_or(Error::<T, I>::DigestVariantBalanceNotFound)?;
2271
2272                    let take = withdraw(balance, &Default::default(), pool_of, slot_commit)?;
2273
2274                    taken = taken
2275                        .checked_add(&take)
2276                        .ok_or(Error::<T, I>::WithdrawAccumulationExhausted)?;
2277                    Ok(())
2278                })?;
2279            }
2280            pool_info.balance_reset();
2281            Ok(())
2282        })?;
2283        let pool_effective = balance_total(&pool_balance, &Default::default(), pool_of)?;
2284        match pool_effective.cmp(&taken) {
2285            Ordering::Less => {
2286                let lack = taken.saturating_sub(pool_effective);
2287                let minted = mint(
2288                    &mut pool_balance,
2289                    &Default::default(),
2290                    pool_of,
2291                    &lack,
2292                    &Directive::new(Precision::Exact, Fortitude::Force),
2293                )?;
2294                ensure!(minted.eq(&lack), Error::<T, I>::PoolUnsupported);
2295            }
2296            Ordering::Greater => {
2297                let excess = pool_effective.saturating_sub(taken);
2298                let reaped = reap(
2299                    &mut pool_balance,
2300                    &Default::default(),
2301                    pool_of,
2302                    &excess,
2303                    &Directive::new(Precision::Exact, Fortitude::Force),
2304                )?;
2305                ensure!(reaped.eq(&excess), Error::<T, I>::PoolUnsupported);
2306            }
2307            Ordering::Equal => {}
2308        }
2309        Ok(pool_balance)
2310    }
2311
2312    /// Restores a pool's state after a prior release.
2313    ///
2314    /// Redistributes the recovered balance among slots proportionally based on
2315    /// their shares, and reconciles any dust with the pool manager. This function
2316    /// should only be called after `release_pool`.
2317    ///
2318    /// ## Returns
2319    /// - `Ok(())` if the pool state was successfully recovered
2320    /// - `Err(DispatchError)` with `ReleasePoolToRecover` if pool is not in released state, or recovery fails
2321    fn recover_pool(
2322        reason: &CommitmentReason<T, I>,
2323        pool_of: &CommitmentDigest<T, I>,
2324        balance: &Self::PoolBalance,
2325    ) -> DispatchResult {
2326        let effective = balance_total(balance, &Default::default(), pool_of)?;
2327
2328        PoolMap::<T, I>::mutate((reason, pool_of), |result| -> DispatchResult {
2329            let pool_info = result.as_mut().ok_or(Error::<T, I>::PoolNotFound)?;
2330
2331            // Ensure the pool is in a "released" state (balance must be zero) before recovery.
2332            let is_released = pool_info.balance() == Self::PoolBalance::default();
2333            debug_assert!(
2334                is_released,
2335                "pool {:?} of reason {:?} attempted 
2336                recovering without being released or empty",
2337                pool_of, reason
2338            );
2339            ensure!(is_released, Error::<T, I>::ReleasePoolToRecover);
2340
2341            let mut taken = CommitmentAsset::<T, I>::zero();
2342            let pool_capital = pool_info.capital();
2343            debug_assert!(
2344                !pool_capital.is_zero(),
2345                "pool {:?} of reason {:?} capital is constructed at zero",
2346                pool_of,
2347                reason
2348            );
2349            ensure!(!pool_capital.is_zero(), Error::<T, I>::CapitalCannotBeZero);
2350
2351            // Iterate over each slot to allocate its share of the recovered balance.
2352            let slots = &pool_info.slots();
2353            for slot in slots {
2354                let digest = &slot.digest();
2355                let slot_shares = slot.shares();
2356                debug_assert!(
2357                    !slot_shares.is_zero(),
2358                    "pool {:?} of reason {:?} slot {:?} 
2359                    share is found to be zero",
2360                    pool_of,
2361                    reason,
2362                    slot.digest()
2363                );
2364                ensure!(!slot_shares.is_zero(), Error::<T, I>::ShareCannotBeZero);
2365                debug_assert!(
2366                    pool_capital >= slot_shares,
2367                    "pool {:?} of reason {:?}  capital of value {:?} is constructed 
2368                    as lesser than the slot {:?} share {:?}",
2369                    pool_of,
2370                    reason,
2371                    pool_capital,
2372                    slot.digest(),
2373                    slot_shares
2374                );
2375                let variant = &slot.variant();
2376
2377                // Calculate slot's proportional factor: shares / total capital.
2378                let factor = T::Bias::saturating_from_rational(slot_shares, pool_capital);
2379                // Convert the effective balance to fixed point representation.
2380                let effective_fixed = T::Bias::saturating_from_integer(effective);
2381                // Calculate the deposit value for this slot.
2382                let slot_deposit_fixed = effective_fixed
2383                    .checked_mul(&factor)
2384                    .ok_or(Error::<T, I>::DepositDeriveOverflowed)?;
2385                let slot_deposit_scaled = slot_deposit_fixed
2386                    .into_inner()
2387                    .checked_div(&T::Bias::DIV)
2388                    .ok_or(Error::<T, I>::DerivedLessThanZeroValue)?;
2389                let slot_deposit: CommitmentAsset<T, I> = slot_deposit_scaled.into();
2390
2391                let mut commit_instance = Default::default();
2392
2393                if slot_deposit.is_zero() {
2394                    pool_info.set_slot_commit(digest, commit_instance)?;
2395                    continue;
2396                }
2397
2398                // Track the slot's commit-instance after deposit.
2399                // Mutate the slot's digest to update the deposit.
2400                DigestMap::<T, I>::mutate((reason, digest), |result| -> DispatchResult {
2401                    let digest_info = result.as_mut().ok_or(Error::<T, I>::SlotOfPoolNotFound)?;
2402
2403                    let Some(balance) = digest_info.mut_balance(variant) else {
2404                        digest_info.init_balance(variant)?;
2405                        // Deposit value into the newly created variant balance
2406                        let digest_of_new_variant = digest_info.mut_balance(variant);
2407                        debug_assert!(
2408                            digest_of_new_variant.is_some(),
2409                            "recently initiated digest {:?} of reason {:?} variant {:?} 
2410                            balance not accessible via vector",
2411                            digest,
2412                            reason,
2413                            variant,
2414                        );
2415                        let digest_of_new_variant = digest_of_new_variant
2416                            .ok_or(Error::<T, I>::DigestVariantBalanceNotFound)?;
2417                        let (depositted, receipt) = deposit(
2418                            digest_of_new_variant,
2419                            variant,
2420                            digest,
2421                            &slot_deposit,
2422                            &Directive::new(Precision::Exact, Fortitude::Force),
2423                        )?;
2424                        ensure!(depositted.eq(&slot_deposit), Error::<T, I>::PoolUnsupported);
2425                        taken = taken
2426                            .checked_add(&depositted)
2427                            .ok_or(Error::<T, I>::WithdrawAccumulationExhausted)?;
2428                        commit_instance = receipt;
2429
2430                        // Early exit from mutate closure after depositing to newly created variant
2431                        return Ok(());
2432                    };
2433
2434                    // Deposit the slot's share.
2435                    let (depositted, receipt) = deposit(
2436                        balance,
2437                        variant,
2438                        digest,
2439                        &slot_deposit,
2440                        &Directive::new(Precision::Exact, Fortitude::Force),
2441                    )?;
2442                    ensure!(depositted.eq(&slot_deposit), Error::<T, I>::PoolUnsupported);
2443                    taken = taken
2444                        .checked_add(&depositted)
2445                        .ok_or(Error::<T, I>::WithdrawAccumulationExhausted)?;
2446
2447                    commit_instance = receipt;
2448
2449                    Ok(())
2450                })?;
2451
2452                // Now mutate the slot via mutable pool to set slot balance
2453                // Update the slot's commit holding deposit.
2454                pool_info.set_slot_commit(digest, commit_instance)?;
2455            }
2456
2457            // Compute any leftover amount ("dust") due to rounding or proportional distribution.
2458            let dust = effective.saturating_sub(taken);
2459
2460            if dust.is_zero() {
2461                // If there is no dust, simply set the recovered balance as the pool's balance.
2462                pool_info.set_balance(balance.clone());
2463                return Ok(());
2464            }
2465
2466            // If dust exists, resolve it with the pool manager.
2467            let manager = Pallet::<T, I>::get_manager(reason, pool_of);
2468            debug_assert!(
2469                manager.is_ok(),
2470                "pool {:?} of reason {:?} exists but manager is not",
2471                pool_of,
2472                reason
2473            );
2474            let manager = manager?;
2475
2476            let manager_imbalance = AssetDelta {
2477                deposit: dust,
2478                withdraw: dust,
2479            };
2480
2481            let manager_withdraw = Self::resolve_imbalance(&manager, manager_imbalance)?;
2482            Self::sub_from_total_value(reason, manager_withdraw)?;
2483
2484            // Adjust recovered balance to remove dust.
2485            let mut new_balance = balance.clone();
2486            // Usually reap/mint are seen in `set_digest_*` functions, we do it here, since
2487            // there are no structural level mutations on `LazyBalance`
2488            let reaped = reap(
2489                &mut new_balance,
2490                &Default::default(),
2491                pool_of,
2492                &dust,
2493                &Directive::new(Precision::Exact, Fortitude::Force),
2494            )?;
2495            ensure!(reaped.eq(&dust), Error::<T, I>::PoolUnsupported);
2496
2497            // Update the pool's balance to the recovered balance after adjustments.
2498            pool_info.set_balance(new_balance);
2499
2500            Ok(())
2501        })?;
2502
2503        Ok(())
2504    }
2505
2506    /// Removes a specific slot from a given pool.
2507    ///
2508    /// The function first *releases* the pool to safely mutate it, ensuring no
2509    /// lazy balance state remains. Once verified, it searches for the specified slot
2510    /// and removes it. The pool's capital is then adjusted to account for the
2511    /// removed slot's shares. Finally, the pool state is *recovered*.
2512    ///
2513    /// ## Returns
2514    /// - `Ok(())` if the slot is successfully removed or not found
2515    /// - `Err(DispatchError)` if pool or slot state is invalid
2516    fn remove_pool_slot(
2517        _who: &Proprietor<T>,
2518        reason: &CommitmentReason<T, I>,
2519        pool_of: &CommitmentDigest<T, I>,
2520        slot_of: &CommitmentDigest<T, I>,
2521    ) -> DispatchResult {
2522        // Temporarily release the pool to allow mutation.
2523        let balance = Self::release_pool(reason, pool_of)?;
2524
2525        PoolMap::<T, I>::mutate((reason, pool_of), |result| -> DispatchResult {
2526            let pool_info = result.as_mut();
2527            debug_assert!(
2528                pool_info.is_some(),
2529                "pool-released {:?} of reason {:?} but cannot mutate during removing its slot {:?}",
2530                pool_of,
2531                reason,
2532                slot_of
2533            );
2534            let pool_info = pool_info.ok_or(Error::<T, I>::PoolNotFound)?;
2535
2536            pool_info.remove_slot(slot_of)?;
2537
2538            let slots = &pool_info.slots();
2539
2540            ensure!(!slots.is_empty(), Error::<T, I>::EmptySlotsNotAllowed);
2541
2542            let capital = pool_info.capital();
2543            debug_assert!(
2544                !capital.is_zero(),
2545                "pool {:?} of reason {:?} newly derived capital after slot {:?} removal is zero",
2546                pool_of,
2547                reason,
2548                slot_of
2549            );
2550            ensure!(!capital.is_zero(), Error::<T, I>::CapitalCannotBeZero);
2551
2552            Ok(())
2553        })?;
2554
2555        // Reapply pool state after mutation.
2556        Self::recover_pool(reason, pool_of, &balance)?;
2557        Ok(())
2558    }
2559
2560    /// Inserts or updates a slot within an existing pool. For removing use
2561    /// [`Self::remove_pool_slot`] instead.
2562    ///
2563    /// The pool is first *released* for safe modification.  
2564    /// If the slot already exists, it is removed and replaced with the updated one.
2565    /// Capital adjustments are performed based on the delta between old and new
2566    /// share allocations. The pool is then *recovered* post-mutation.
2567    ///
2568    /// ## Returns
2569    /// - `Ok(())` if the slot is successfully set
2570    /// - `Err(DispatchError)` if pool is not in released state, if slot capacity exceeded, or operation fails
2571    fn set_pool_slot(
2572        _who: &Proprietor<T>,
2573        reason: &CommitmentReason<T, I>,
2574        pool_of: &CommitmentDigest<T, I>,
2575        slot_of: &CommitmentDigest<T, I>,
2576        shares: CommitmentShares<T, I>,
2577        variant: &CommitmentPosition<T, I>,
2578    ) -> DispatchResult {
2579        ensure!(!shares.is_zero(), Error::<T, I>::ShareCannotBeZero);
2580        // Temporarily release the pool to allow mutable access.
2581        let balance = Self::release_pool(reason, pool_of)?;
2582
2583        PoolMap::<T, I>::mutate((reason, pool_of), |result| -> DispatchResult {
2584            let pool_info = result.as_mut();
2585            debug_assert!(
2586                pool_info.is_some(),
2587                "pool-released {:?} of reason {:?} but cannot mutate during removing its slot {:?}",
2588                pool_of,
2589                reason,
2590                slot_of
2591            );
2592            let pool_info = pool_info.ok_or(Error::<T, I>::PoolNotFound)?;
2593
2594            if pool_info.slot_exists(slot_of).is_ok() {
2595                pool_info.remove_slot(slot_of)?;
2596            }
2597
2598            let entry = EntryInfo::<T, I>::new(slot_of.clone(), shares, variant.clone())?;
2599            pool_info.add_slot(entry)?;
2600
2601            Ok(())
2602        })?;
2603
2604        // Restore the pool's active balance state.
2605        Self::recover_pool(reason, pool_of, &balance)?;
2606        Ok(())
2607    }
2608}
2609
2610// ===============================================================================
2611// `````````````````````````````` INDEX OPERATIONS ```````````````````````````````
2612// ===============================================================================
2613
2614/// Implementation of [`IndexOps`] for the pallet, defining how index entries
2615/// are queried, inserted, updated, or removed within a given index digest.
2616///
2617/// Each function operates on the *index-entry composition layer* - maintaining
2618/// relationships between an index digest and its subordinate entry digests.
2619impl<T: Config<I>, I: 'static> IndexOps<Proprietor<T>, Pallet<T, I>> for CommitHelpers<T, I> {
2620    /// Removes a specific entry from an existing index.
2621    ///
2622    /// The function retrieves the target index, searches for the specified entry,
2623    /// and removes it if found. The index digest is then re-generated and updated
2624    /// to reflect the new structure as indexes are immutable, changes may create
2625    /// new index digest.
2626    ///
2627    /// ## Returns
2628    /// - `Ok(IndexDigest)` containing the new index digest after entry removal
2629    /// - `Err(DispatchError)` if the operation fails
2630    fn remove_index_entry(
2631        who: &Proprietor<T>,
2632        reason: &CommitmentReason<T, I>,
2633        index_of: &CommitmentDigest<T, I>,
2634        entry_of: &CommitmentDigest<T, I>,
2635    ) -> Result<CommitmentDigest<T, I>, DispatchError> {
2636        // Retrieve the current index and its entries.
2637        let index_info = Pallet::<T, I>::get_index(reason, index_of)?;
2638        let mut new_entries = index_info.reveal_entries();
2639        new_entries.remove_entry(entry_of)?;
2640
2641        // Construct the updated index info and generate a new digest.
2642        let new_index = IndexInfo::<T, I>::new(&mut new_entries)?;
2643        let digest = Pallet::<T, I>::gen_index_digest(who, reason, &new_index)?;
2644
2645        // Commit the updated index structure.
2646        Pallet::<T, I>::set_index(who, reason, &new_index, &digest)?;
2647        Ok(digest)
2648    }
2649
2650    /// Inserts or updates an entry within a given index. For removing use
2651    /// [`Self::remove_index_entry`] instead.
2652    ///
2653    /// Since indexes are immutable, this operation creates a new index
2654    /// with the modified entry configuration and generates a new digest.
2655    ///
2656    /// If the entry exists, its shares and variant are updated; otherwise,
2657    /// a new entry is appended.
2658    ///
2659    /// ## Returns
2660    /// - `Ok(IndexDigest)` containing the new index digest after entry modification
2661    /// - `Err(DispatchError)` if the operation fails
2662    fn set_index_entry(
2663        who: &Proprietor<T>,
2664        reason: &CommitmentReason<T, I>,
2665        index_of: &CommitmentDigest<T, I>,
2666        entry_of: &CommitmentDigest<T, I>,
2667        shares: CommitmentShares<T, I>,
2668        variant: &CommitmentPosition<T, I>,
2669    ) -> Result<CommitmentDigest<T, I>, DispatchError> {
2670        ensure!(!shares.is_zero(), Error::<T, I>::ShareCannotBeZero);
2671        // Retrieve the target index and clone its entries for mutation.
2672        let index_info = Pallet::<T, I>::get_index(reason, index_of)?;
2673        let mut new_entries = index_info.reveal_entries();
2674
2675        if index_info.entry_exists(entry_of).is_ok() {
2676            new_entries.remove_entry(entry_of)?;
2677        };
2678
2679        new_entries.add_entry(EntryInfo::<T, I>::new(
2680            entry_of.clone(),
2681            shares,
2682            variant.clone(),
2683        )?)?;
2684
2685        // Generate updated index info and its new digest.
2686        let new_index = IndexInfo::<T, I>::new(&mut new_entries)?;
2687        let digest = Pallet::<T, I>::gen_index_digest(who, reason, &new_index)?;
2688
2689        // Persist the updated index.
2690        Pallet::<T, I>::set_index(who, reason, &new_index, &digest)?;
2691
2692        Ok(digest)
2693    }
2694}
2695
2696// ===============================================================================
2697// `````````````````````````````````` UNIT TESTS `````````````````````````````````
2698// ===============================================================================
2699
2700/// Unit tests for [`commit-helpers`](crate::traits) trait
2701/// implementations over internal type [`CommitHelpers`].
2702#[cfg(test)]
2703mod tests {
2704
2705    // ===============================================================================
2706    // ``````````````````````````````````` IMPORTS ```````````````````````````````````
2707    // ===============================================================================
2708
2709    // --- Local crate imports ---
2710    use crate::{assert_debug_panic_or_err, balance::*, mock::*, traits::*};
2711
2712    // --- FRAME Suite ---
2713    use frame_suite::{
2714        commitment::*,
2715        misc::{Directive, PositionIndex},
2716    };
2717
2718    // --- FRAME Support ---
2719    use frame_support::{
2720        assert_err, assert_ok,
2721        traits::{
2722            fungible::{Inspect, InspectFreeze, InspectHold, UnbalancedHold},
2723            tokens::{Fortitude, Precision},
2724        },
2725    };
2726
2727    // ===============================================================================
2728    // ```````````````````````````````` COMMIT BALANCE ```````````````````````````````
2729    // ===============================================================================
2730
2731    #[test]
2732    fn resolve_imbalance_success_minting() {
2733        commit_test_ext().execute_with(|| {
2734            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, STANDARD_VALUE).unwrap();
2735            assert_eq!(AssetOf::balance(&ALICE), 20);
2736            // reward scenario
2737            let imbalance = AssetDelta::new(20, 25);
2738            // 5 units of tokens should have been pre-allocated to AssetToIssue during digest value updates via set_digest_value,
2739            // representing the system's capacity to mint rewards when withdrawal > deposit (25 > 20)
2740            AssetToIssue::put(5);
2741            let total_taken = CommitHelper::resolve_imbalance(&ALICE, imbalance.clone()).unwrap();
2742            assert_eq!(total_taken, imbalance.withdraw);
2743            assert_eq!(AssetToIssue::get(), 0);
2744            assert_eq!(AssetOf::balance(&ALICE), 45);
2745        })
2746    }
2747
2748    #[test]
2749    fn resolve_imbalance_err_cannot_mint_asset() {
2750        commit_test_ext().execute_with(|| {
2751            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, STANDARD_VALUE).unwrap();
2752            assert_eq!(AssetOf::balance(&ALICE), 20);
2753            let imbalance = AssetDelta::new(20, 25);
2754            assert_eq!(AssetToIssue::get(), 0);
2755
2756            assert_debug_panic_or_err!(
2757                CommitHelper::resolve_imbalance(&ALICE, imbalance,),
2758                Error::MaxAssetIssued
2759            )
2760        })
2761    }
2762
2763    #[test]
2764    fn resolve_imbalance_success_penalty() {
2765        commit_test_ext().execute_with(|| {
2766            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, STANDARD_VALUE).unwrap();
2767            assert_eq!(AssetOf::balance(&ALICE), 20);
2768            // penalty scenario
2769            let imbalance = AssetDelta::new(20, 14);
2770            // 6 units tokens should have been pre-allocated to AssetToReap during digest value updates via set_digest_value,
2771            // representing the system's capacity to reap penalty when withdrawal < deposit (14 < 20)
2772            AssetToReap::put(6);
2773            let total_taken = CommitHelper::resolve_imbalance(&ALICE, imbalance.clone()).unwrap();
2774            assert_eq!(total_taken, imbalance.withdraw);
2775            assert_eq!(AssetToReap::get(), 0);
2776            assert_eq!(AssetOf::balance(&ALICE), 34);
2777        })
2778    }
2779
2780    #[test]
2781    fn resolve_imbalance_err_cannot_reap_asset() {
2782        commit_test_ext().execute_with(|| {
2783            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, STANDARD_VALUE).unwrap();
2784            assert_eq!(AssetOf::balance(&ALICE), 20);
2785            let imbalance = AssetDelta::new(20, 14);
2786            assert_eq!(AssetToReap::get(), 0);
2787            assert_debug_panic_or_err!(
2788                CommitHelper::resolve_imbalance(&ALICE, imbalance),
2789                Error::MaxAssetReaped
2790            )
2791        })
2792    }
2793
2794    #[test]
2795    fn resolve_imbalance_success_equal() {
2796        commit_test_ext().execute_with(|| {
2797            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, STANDARD_VALUE).unwrap();
2798            assert_eq!(AssetOf::balance(&ALICE), 20);
2799            let imbalance = AssetDelta::new(20, 20);
2800            let total_taken = CommitHelper::resolve_imbalance(&ALICE, imbalance.clone()).unwrap();
2801            assert_eq!(total_taken, imbalance.withdraw);
2802            assert_eq!(AssetOf::balance(&ALICE), 40);
2803        })
2804    }
2805
2806    #[test]
2807    fn deduct_balance_with_reserve_balance_success() {
2808        commit_test_ext().execute_with(|| {
2809            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, STANDARD_VALUE).unwrap();
2810            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 10);
2811            assert_eq!(AssetOf::balance(&ALICE), 20);
2812            let deducted_balance = CommitHelper::deduct_balance(
2813                &ALICE,
2814                7,
2815                &Directive::new(Precision::BestEffort, Fortitude::Polite),
2816            )
2817            .unwrap();
2818            assert_eq!(deducted_balance, 7);
2819            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 3);
2820        })
2821    }
2822
2823    #[test]
2824    fn deduct_balance_err_insufficient_funds() {
2825        commit_test_ext().execute_with(|| {
2826            initiate_key_and_set_balance_and_hold(ALICE, STANDARD_VALUE, SMALL_VALUE).unwrap();
2827            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 5);
2828            assert_eq!(AssetOf::balance(&ALICE), 10);
2829            assert_err!(
2830                CommitHelper::deduct_balance(
2831                    &ALICE,
2832                    LARGE_VALUE,
2833                    &Directive::new(Precision::Exact, Fortitude::Polite)
2834                ),
2835                Error::InsufficientFunds
2836            );
2837        })
2838    }
2839
2840    #[test]
2841    fn deduct_balance_err_expects_hold_withdrawal() {
2842        commit_test_ext().execute_with(|| {
2843            initiate_key_and_set_balance_and_hold(ALICE, STANDARD_VALUE, SMALL_VALUE).unwrap();
2844            AssetOf::set_balance_on_hold(&EXTERNAL_HOLD, &ALICE, LARGE_VALUE).unwrap();
2845            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 5);
2846            assert_eq!(AssetOf::balance_on_hold(&EXTERNAL_HOLD, &ALICE), 20);
2847            assert_eq!(AssetOf::balance(&ALICE), 10);
2848            // total_reserve = 5 + 20 -> 25
2849            // since, total_reserve > value it expects hold withdrawal
2850            assert_err!(
2851                CommitHelper::deduct_balance(
2852                    &ALICE,
2853                    LARGE_VALUE,
2854                    &Directive::new(Precision::Exact, Fortitude::Polite)
2855                ),
2856                Error::ExpectsHoldWithdrawal
2857            );
2858        })
2859    }
2860
2861    #[test]
2862    fn deduct_balance_success_with_precision_bestefforts() {
2863        commit_test_ext().execute_with(|| {
2864            initiate_key_and_set_balance_and_hold(ALICE, STANDARD_VALUE, SMALL_VALUE).unwrap();
2865            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 5);
2866            assert_eq!(AssetOf::balance(&ALICE), 10);
2867            // since, the total_balance (reserve + free) is 15, with precision as BestEfforts
2868            // the balance is reduced as much as possible without throwing InsufficientFunds error.
2869            let deducted_balance = CommitHelper::deduct_balance(
2870                &ALICE,
2871                20,
2872                &Directive::new(Precision::BestEffort, Fortitude::Polite),
2873            )
2874            .unwrap();
2875            // 15 units deducted instead of 20 (requested value)
2876            assert_eq!(deducted_balance, 15);
2877            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 0);
2878            assert_eq!(AssetOf::balance(&ALICE), 0);
2879        })
2880    }
2881
2882    #[test]
2883    fn deduct_balance_success_with_enough_total_balance() {
2884        commit_test_ext().execute_with(|| {
2885            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, SMALL_VALUE).unwrap();
2886            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 5);
2887            assert_eq!(AssetOf::balance(&ALICE), 20);
2888            let deducted_balance = CommitHelper::deduct_balance(
2889                &ALICE,
2890                10,
2891                &Directive::new(Precision::BestEffort, Fortitude::Polite),
2892            )
2893            .unwrap();
2894            assert_eq!(deducted_balance, 10);
2895            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 0);
2896            assert_eq!(AssetOf::balance(&ALICE), 15);
2897        })
2898    }
2899
2900    #[test]
2901    fn deduct_balance_success_with_enough_free_balance_but_empty_reserve() {
2902        commit_test_ext().execute_with(|| {
2903            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, ZERO_VALUE).unwrap();
2904            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), ZERO_VALUE);
2905            assert_eq!(AssetOf::balance(&ALICE), 20);
2906            let deducted_balance = CommitHelper::deduct_balance(
2907                &ALICE,
2908                10,
2909                &Directive::new(Precision::Exact, Fortitude::Force),
2910            )
2911            .unwrap();
2912            assert_eq!(deducted_balance, 10);
2913            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 0);
2914            assert_eq!(AssetOf::balance(&ALICE), 10);
2915        })
2916    }
2917
2918    // ===============================================================================
2919    // ```````````````````````````````` COMMIT DEPOSIT ```````````````````````````````
2920    // ===============================================================================
2921
2922    #[test]
2923    fn deposit_to_success_for_direct_digest_model() {
2924        commit_test_ext().execute_with(|| {
2925            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, STANDARD_VALUE).unwrap();
2926            initiate_digest_with_default_balance(STAKING, ALPHA_DIGEST).unwrap();
2927            assert_ok!(Pallet::digest_exists(&STAKING, &ALPHA_DIGEST));
2928            // before deposit
2929            let digest_info = DigestMap::get((STAKING, ALPHA_DIGEST)).unwrap();
2930            let digest_of = digest_info.get_balance(&Default::default()).unwrap();
2931            assert!(has_deposits(digest_of, &Default::default(), &ALPHA_DIGEST).is_err());
2932            assert_eq!(
2933                balance_total(digest_of, &Default::default(), &ALPHA_DIGEST).unwrap(),
2934                0
2935            );
2936            let (receipt, amount) = CommitHelper::deposit_to(
2937                &ALICE,
2938                &STAKING,
2939                &DigestVariant::Direct(ALPHA_DIGEST),
2940                STANDARD_VALUE,
2941                &Position::default(),
2942                &Default::default(),
2943            )
2944            .unwrap();
2945            assert_eq!(amount, STANDARD_VALUE);
2946            assert_eq!(receipt_deposit_value(&receipt).unwrap(), STANDARD_VALUE);
2947            // after deposit
2948            let digest_info = DigestMap::get((STAKING, ALPHA_DIGEST)).unwrap();
2949            let digest_of = digest_info.get_balance(&Default::default()).unwrap();
2950            assert!(has_deposits(digest_of, &Default::default(), &ALPHA_DIGEST).is_ok());
2951            assert_eq!(
2952                balance_total(digest_of, &Default::default(), &ALPHA_DIGEST).unwrap(),
2953                STANDARD_VALUE
2954            );
2955        })
2956    }
2957
2958    #[test]
2959    fn deposit_to_success_for_index_digest_model() {
2960        commit_test_ext().execute_with(|| {
2961            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2962            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
2963            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, 40).unwrap();
2964            Pallet::place_commit(
2965                &ALICE,
2966                &STAKING,
2967                &ALPHA_ENTRY_DIGEST,
2968                LARGE_VALUE,
2969                &Directive::new(Precision::BestEffort, Fortitude::Polite),
2970            )
2971            .unwrap();
2972            Pallet::place_commit(
2973                &BOB,
2974                &STAKING,
2975                &BETA_ENTRY_DIGEST,
2976                STANDARD_VALUE,
2977                &Directive::new(Precision::BestEffort, Fortitude::Polite),
2978            )
2979            .unwrap();
2980            prepare_and_initiate_index(
2981                CHARLIE,
2982                STAKING,
2983                &[(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)],
2984                ALPHA_INDEX_DIGEST,
2985            )
2986            .unwrap();
2987            // Balance before deposit
2988            let entries_value_before =
2989                Pallet::get_entries_value(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
2990            assert_eq!(
2991                entries_value_before,
2992                vec![(ALPHA_ENTRY_DIGEST, 0), (BETA_ENTRY_DIGEST, 0)]
2993            );
2994            CommitHelper::deposit_to(
2995                &CHARLIE,
2996                &STAKING,
2997                &DigestVariant::Index(ALPHA_INDEX_DIGEST),
2998                35,
2999                &Position::default(),
3000                &Default::default(),
3001            )
3002            .unwrap();
3003            // Balance after deposit
3004            let entries_value_after =
3005                Pallet::get_entries_value(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
3006            assert_eq!(
3007                entries_value_after,
3008                vec![(ALPHA_ENTRY_DIGEST, 14), (BETA_ENTRY_DIGEST, 21)]
3009            );
3010        })
3011    }
3012
3013    #[test]
3014    fn deposit_to_success_for_pool_digets_pool() {
3015        commit_test_ext().execute_with(|| {
3016            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3017            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
3018            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, 40).unwrap();
3019            Pallet::place_commit(
3020                &ALICE,
3021                &STAKING,
3022                &ALPHA_ENTRY_DIGEST,
3023                LARGE_VALUE,
3024                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3025            )
3026            .unwrap();
3027            Pallet::place_commit(
3028                &BOB,
3029                &STAKING,
3030                &BETA_ENTRY_DIGEST,
3031                STANDARD_VALUE,
3032                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3033            )
3034            .unwrap();
3035            prepare_and_initiate_pool(
3036                CHARLIE,
3037                STAKING,
3038                &[(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)],
3039                ALPHA_INDEX_DIGEST,
3040                ALPHA_POOL_DIGEST,
3041                COMMISSION_ZERO,
3042            )
3043            .unwrap();
3044            // Balance before deposit
3045            let slots_value_before = Pallet::get_slots_value(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
3046            assert_eq!(
3047                slots_value_before,
3048                vec![(ALPHA_ENTRY_DIGEST, 0), (BETA_ENTRY_DIGEST, 0)]
3049            );
3050            CommitHelper::deposit_to(
3051                &CHARLIE,
3052                &STAKING,
3053                &DigestVariant::Pool(ALPHA_POOL_DIGEST),
3054                35,
3055                &Position::default(),
3056                &Default::default(),
3057            )
3058            .unwrap();
3059            // Balance before deposit
3060            let slots_value_after = Pallet::get_slots_value(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
3061            assert_eq!(
3062                slots_value_after,
3063                vec![(ALPHA_ENTRY_DIGEST, 14), (BETA_ENTRY_DIGEST, 21)]
3064            );
3065        })
3066    }
3067
3068    #[test]
3069    fn deposit_to_digest_success() {
3070        commit_test_ext().execute_with(|| {
3071            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, STANDARD_VALUE).unwrap();
3072            initiate_digest_with_default_balance(STAKING, ALPHA_DIGEST).unwrap();
3073            assert_ok!(Pallet::digest_exists(&STAKING, &ALPHA_DIGEST));
3074            // before deposit
3075            let digest_info = DigestMap::get((STAKING, ALPHA_DIGEST)).unwrap();
3076            let digest_of = digest_info.get_balance(&Default::default()).unwrap();
3077            assert!(has_deposits(digest_of, &Default::default(), &ALPHA_DIGEST).is_err());
3078            assert_eq!(
3079                balance_total(digest_of, &Default::default(), &ALPHA_DIGEST).unwrap(),
3080                0
3081            );
3082            let (receipt, amount) = CommitHelper::deposit_to_digest(
3083                &ALICE,
3084                &STAKING,
3085                &ALPHA_DIGEST,
3086                STANDARD_VALUE,
3087                &Position::default(),
3088                &Default::default(),
3089            )
3090            .unwrap();
3091            assert_eq!(amount, STANDARD_VALUE);
3092            assert_eq!(receipt_deposit_value(&receipt).unwrap(), STANDARD_VALUE);
3093            // after deposit
3094            let digest_info = DigestMap::get((STAKING, ALPHA_DIGEST)).unwrap();
3095            let digest_of = digest_info.get_balance(&Default::default()).unwrap();
3096            assert_eq!(
3097                balance_total(digest_of, &Default::default(), &ALPHA_DIGEST).unwrap(),
3098                STANDARD_VALUE
3099            );
3100            assert!(has_deposits(digest_of, &Default::default(), &ALPHA_DIGEST).is_ok());
3101        })
3102    }
3103
3104    #[test]
3105    fn deposit_to_index_success() {
3106        commit_test_ext().execute_with(|| {
3107            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3108            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
3109            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, 40).unwrap();
3110            Pallet::place_commit(
3111                &ALICE,
3112                &STAKING,
3113                &ALPHA_ENTRY_DIGEST,
3114                LARGE_VALUE,
3115                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3116            )
3117            .unwrap();
3118            Pallet::place_commit(
3119                &BOB,
3120                &STAKING,
3121                &BETA_ENTRY_DIGEST,
3122                STANDARD_VALUE,
3123                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3124            )
3125            .unwrap();
3126            prepare_and_initiate_index(
3127                CHARLIE,
3128                STAKING,
3129                &[(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)],
3130                ALPHA_INDEX_DIGEST,
3131            )
3132            .unwrap();
3133            // Balance before deposit
3134            let entries_value_before =
3135                Pallet::get_entries_value(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
3136            assert_eq!(
3137                entries_value_before,
3138                vec![(ALPHA_ENTRY_DIGEST, 0), (BETA_ENTRY_DIGEST, 0)]
3139            );
3140            CommitHelper::deposit_to_index(
3141                &CHARLIE,
3142                &STAKING,
3143                &ALPHA_INDEX_DIGEST,
3144                35,
3145                &Position::default(),
3146                &Default::default(),
3147            )
3148            .unwrap();
3149            // Balance after deposit
3150            let entries_value_after =
3151                Pallet::get_entries_value(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
3152            assert_eq!(
3153                entries_value_after,
3154                vec![(ALPHA_ENTRY_DIGEST, 14), (BETA_ENTRY_DIGEST, 21)]
3155            );
3156        })
3157    }
3158
3159    #[test]
3160    fn deposit_to_pool_success() {
3161        commit_test_ext().execute_with(|| {
3162            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3163            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
3164            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, 40).unwrap();
3165            Pallet::place_commit(
3166                &ALICE,
3167                &STAKING,
3168                &ALPHA_ENTRY_DIGEST,
3169                LARGE_VALUE,
3170                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3171            )
3172            .unwrap();
3173            Pallet::place_commit(
3174                &BOB,
3175                &STAKING,
3176                &BETA_ENTRY_DIGEST,
3177                STANDARD_VALUE,
3178                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3179            )
3180            .unwrap();
3181            prepare_and_initiate_pool(
3182                CHARLIE,
3183                STAKING,
3184                &[(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)],
3185                ALPHA_INDEX_DIGEST,
3186                ALPHA_POOL_DIGEST,
3187                COMMISSION_ZERO,
3188            )
3189            .unwrap();
3190            // Balance before deposit
3191            let slots_value_before = Pallet::get_slots_value(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
3192            assert_eq!(
3193                slots_value_before,
3194                vec![(ALPHA_ENTRY_DIGEST, 0), (BETA_ENTRY_DIGEST, 0)]
3195            );
3196            CommitHelper::deposit_to_pool(
3197                &CHARLIE,
3198                &STAKING,
3199                &ALPHA_POOL_DIGEST,
3200                35,
3201                &Position::default(),
3202                &Default::default(),
3203            )
3204            .unwrap();
3205            // Balance before deposit
3206            let slots_value_after = Pallet::get_slots_value(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
3207            assert_eq!(
3208                slots_value_after,
3209                vec![(ALPHA_ENTRY_DIGEST, 14), (BETA_ENTRY_DIGEST, 21)]
3210            );
3211        })
3212    }
3213
3214    #[test]
3215    fn deposit_to_digest_err_direct_digest_not_found() {
3216        commit_test_ext().execute_with(|| {
3217            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, STANDARD_VALUE).unwrap();
3218            DigestMap::insert((&STAKING, &ALPHA_DIGEST), DigestInfo::default());
3219            assert_ok!(Pallet::digest_exists(&STAKING, &ALPHA_DIGEST));
3220            assert_err!(
3221                CommitHelper::deposit_to_digest(
3222                    &ALICE,
3223                    &STAKING,
3224                    &BETA_DIGEST,
3225                    STANDARD_VALUE,
3226                    &Position::default(),
3227                    &Default::default(),
3228                ),
3229                Error::DigestNotFound
3230            );
3231        })
3232    }
3233
3234    // ===============================================================================
3235    // ```````````````````````````````` COMMIT WITHDRAW ``````````````````````````````
3236    // ===============================================================================
3237
3238    #[test]
3239    fn withdraw_for_success_for_direct_digest_model() {
3240        commit_test_ext().execute_with(|| {
3241            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, STANDARD_VALUE).unwrap();
3242            Pallet::place_commit(
3243                &ALICE,
3244                &STAKING,
3245                &ALPHA_DIGEST,
3246                STANDARD_VALUE,
3247                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3248            )
3249            .unwrap();
3250            let actual_imbalance = CommitHelper::withdraw_for(
3251                &ALICE,
3252                &STAKING,
3253                &DigestVariant::Direct(ALPHA_DIGEST),
3254                &Default::default(),
3255            )
3256            .unwrap();
3257            let expected_imbalance = AssetDelta::new(10, 10);
3258            assert_eq!(expected_imbalance, actual_imbalance);
3259            let digest_info = DigestMap::get((STAKING, ALPHA_DIGEST)).unwrap();
3260            let digest_of = digest_info.get_balance(&Default::default()).unwrap();
3261            assert!(has_deposits(digest_of, &Default::default(), &ALPHA_DIGEST).is_err());
3262            assert_eq!(
3263                balance_total(digest_of, &Default::default(), &ALPHA_DIGEST).unwrap(),
3264                0
3265            );
3266        })
3267    }
3268
3269    #[test]
3270    fn withdraw_for_success_for_index_digest_model() {
3271        commit_test_ext().execute_with(|| {
3272            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3273            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
3274            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, 40).unwrap();
3275            Pallet::place_commit(
3276                &ALICE,
3277                &STAKING,
3278                &ALPHA_ENTRY_DIGEST,
3279                LARGE_VALUE,
3280                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3281            )
3282            .unwrap();
3283            Pallet::place_commit(
3284                &BOB,
3285                &STAKING,
3286                &BETA_ENTRY_DIGEST,
3287                STANDARD_VALUE,
3288                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3289            )
3290            .unwrap();
3291            prepare_and_initiate_index(
3292                CHARLIE,
3293                STAKING,
3294                &[(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)],
3295                ALPHA_INDEX_DIGEST,
3296            )
3297            .unwrap();
3298            Pallet::place_commit(
3299                &CHARLIE,
3300                &STAKING,
3301                &ALPHA_INDEX_DIGEST,
3302                35,
3303                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3304            )
3305            .unwrap();
3306            // Balance after deposit
3307            let actual_entries_value =
3308                Pallet::get_entries_value(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
3309            assert_eq!(
3310                actual_entries_value,
3311                vec![(ALPHA_ENTRY_DIGEST, 14), (BETA_ENTRY_DIGEST, 21)]
3312            );
3313            // Withdraw for index digets model
3314            let actual_imbalance = CommitHelper::withdraw_for(
3315                &CHARLIE,
3316                &STAKING,
3317                &DigestVariant::Index(ALPHA_INDEX_DIGEST),
3318                &Position::default(),
3319            )
3320            .unwrap();
3321            let expected_imbalance = AssetDelta::new(35, 35);
3322            assert_eq!(expected_imbalance, actual_imbalance);
3323            // Balance after withdraw
3324            let actual_entries_value =
3325                Pallet::get_entries_value(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
3326            assert_eq!(
3327                actual_entries_value,
3328                vec![(ALPHA_ENTRY_DIGEST, 0), (BETA_ENTRY_DIGEST, 0)]
3329            );
3330        })
3331    }
3332
3333    #[test]
3334    fn withdraw_for_success_for_pool_digest_model() {
3335        commit_test_ext().execute_with(|| {
3336            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3337            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
3338            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, 40).unwrap();
3339            Pallet::place_commit(
3340                &ALICE,
3341                &STAKING,
3342                &ALPHA_ENTRY_DIGEST,
3343                LARGE_VALUE,
3344                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3345            )
3346            .unwrap();
3347            Pallet::place_commit(
3348                &BOB,
3349                &STAKING,
3350                &BETA_ENTRY_DIGEST,
3351                STANDARD_VALUE,
3352                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3353            )
3354            .unwrap();
3355            prepare_and_initiate_pool(
3356                CHARLIE,
3357                STAKING,
3358                &[(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)],
3359                ALPHA_INDEX_DIGEST,
3360                ALPHA_POOL_DIGEST,
3361                COMMISSION_ZERO,
3362            )
3363            .unwrap();
3364            Pallet::place_commit(
3365                &CHARLIE,
3366                &STAKING,
3367                &ALPHA_POOL_DIGEST,
3368                35,
3369                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3370            )
3371            .unwrap();
3372            // Balance after deposit
3373            let actual_slots_value = Pallet::get_slots_value(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
3374            let expected_slots_value = vec![(ALPHA_ENTRY_DIGEST, 14), (BETA_ENTRY_DIGEST, 21)];
3375            assert_eq!(actual_slots_value, expected_slots_value);
3376            // Withdraw for pool digets model
3377            let actual_imbalance = CommitHelper::withdraw_for(
3378                &CHARLIE,
3379                &STAKING,
3380                &DigestVariant::Pool(ALPHA_POOL_DIGEST),
3381                &Position::default(),
3382            )
3383            .unwrap();
3384            let expected_imbalance = AssetDelta::new(35, 35);
3385            assert_eq!(expected_imbalance, actual_imbalance);
3386            // Balance after withdraw
3387            let actual_slots_value = Pallet::get_slots_value(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
3388            let expected_slots_value = vec![(ALPHA_ENTRY_DIGEST, 0), (BETA_ENTRY_DIGEST, 0)];
3389            assert_eq!(actual_slots_value, expected_slots_value);
3390        })
3391    }
3392
3393    #[test]
3394    fn withdraw_from_digest_success() {
3395        commit_test_ext().execute_with(|| {
3396            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, STANDARD_VALUE).unwrap();
3397            Pallet::place_commit(
3398                &ALICE,
3399                &STAKING,
3400                &ALPHA_DIGEST,
3401                STANDARD_VALUE,
3402                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3403            )
3404            .unwrap();
3405            let new_reward_value = 15;
3406            Pallet::set_digest_value(
3407                &STAKING,
3408                &ALPHA_DIGEST,
3409                new_reward_value,
3410                &Default::default(),
3411            )
3412            .unwrap();
3413            let digest_info = DigestMap::get((STAKING, ALPHA_DIGEST)).unwrap();
3414            let digest_of = digest_info.get_balance(&Default::default()).unwrap();
3415            assert!(has_deposits(digest_of, &Default::default(), &ALPHA_DIGEST).is_ok());
3416            assert_eq!(
3417                balance_total(digest_of, &Default::default(), &ALPHA_DIGEST).unwrap(),
3418                15
3419            );
3420            let actual_imbalance = CommitHelper::withdraw_from_digest(
3421                &ALICE,
3422                &STAKING,
3423                &ALPHA_DIGEST,
3424                &Default::default(),
3425            )
3426            .unwrap();
3427            let expected_imbalance = AssetDelta::new(10, 15);
3428            assert_eq!(expected_imbalance, actual_imbalance);
3429            let digest_info = DigestMap::get((STAKING, ALPHA_DIGEST)).unwrap();
3430            let digest_of = digest_info.get_balance(&Default::default()).unwrap();
3431            assert!(has_deposits(digest_of, &Default::default(), &ALPHA_DIGEST).is_err());
3432            assert_eq!(
3433                balance_total(digest_of, &Default::default(), &ALPHA_DIGEST).unwrap(),
3434                0
3435            );
3436        })
3437    }
3438
3439    #[test]
3440    fn withdraw_from_digest_err_digest_not_found() {
3441        commit_test_ext().execute_with(|| {
3442            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, STANDARD_VALUE).unwrap();
3443            Pallet::place_commit(
3444                &ALICE,
3445                &STAKING,
3446                &ALPHA_DIGEST,
3447                STANDARD_VALUE,
3448                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3449            )
3450            .unwrap();
3451            assert_err!(
3452                CommitHelper::withdraw_from_digest(
3453                    &ALICE,
3454                    &STAKING,
3455                    &BETA_DIGEST,
3456                    &Default::default(),
3457                ),
3458                Error::DigestNotFound
3459            );
3460        })
3461    }
3462
3463    #[test]
3464    fn withdraw_from_index_success() {
3465        commit_test_ext().execute_with(|| {
3466            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3467            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
3468            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, 40).unwrap();
3469            Pallet::place_commit(
3470                &ALICE,
3471                &STAKING,
3472                &ALPHA_ENTRY_DIGEST,
3473                LARGE_VALUE,
3474                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3475            )
3476            .unwrap();
3477            Pallet::place_commit(
3478                &BOB,
3479                &STAKING,
3480                &BETA_ENTRY_DIGEST,
3481                STANDARD_VALUE,
3482                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3483            )
3484            .unwrap();
3485            prepare_and_initiate_index(
3486                CHARLIE,
3487                STAKING,
3488                &[(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)],
3489                ALPHA_INDEX_DIGEST,
3490            )
3491            .unwrap();
3492            Pallet::place_commit(
3493                &CHARLIE,
3494                &STAKING,
3495                &ALPHA_INDEX_DIGEST,
3496                35,
3497                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3498            )
3499            .unwrap();
3500            // Balance after deposit
3501            let actual_entries_value =
3502                Pallet::get_entries_value(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
3503            assert_eq!(
3504                actual_entries_value,
3505                vec![(ALPHA_ENTRY_DIGEST, 14), (BETA_ENTRY_DIGEST, 21)]
3506            );
3507            // Withdraw from index
3508            let actual_imbalance = CommitHelper::withdraw_from_index(
3509                &CHARLIE,
3510                &STAKING,
3511                &ALPHA_INDEX_DIGEST,
3512                &Position::default(),
3513            )
3514            .unwrap();
3515            let expected_imbalance = AssetDelta::new(35, 35);
3516            assert_eq!(expected_imbalance, actual_imbalance);
3517            // Balance after withdraw
3518            let actual_entries_value =
3519                Pallet::get_entries_value(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
3520            assert_eq!(
3521                actual_entries_value,
3522                vec![(ALPHA_ENTRY_DIGEST, 0), (BETA_ENTRY_DIGEST, 0)]
3523            );
3524        })
3525    }
3526
3527    #[test]
3528    fn withdraw_from_index_err_index_not_found() {
3529        commit_test_ext().execute_with(|| {
3530            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3531            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
3532            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, 40).unwrap();
3533            Pallet::place_commit(
3534                &ALICE,
3535                &STAKING,
3536                &ALPHA_ENTRY_DIGEST,
3537                LARGE_VALUE,
3538                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3539            )
3540            .unwrap();
3541            Pallet::place_commit(
3542                &BOB,
3543                &STAKING,
3544                &BETA_ENTRY_DIGEST,
3545                STANDARD_VALUE,
3546                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3547            )
3548            .unwrap();
3549            prepare_and_initiate_index(
3550                CHARLIE,
3551                STAKING,
3552                &[(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)],
3553                ALPHA_INDEX_DIGEST,
3554            )
3555            .unwrap();
3556            Pallet::place_commit(
3557                &CHARLIE,
3558                &STAKING,
3559                &ALPHA_INDEX_DIGEST,
3560                35,
3561                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3562            )
3563            .unwrap();
3564            assert_err!(
3565                CommitHelper::withdraw_from_index(
3566                    &CHARLIE,
3567                    &STAKING,
3568                    &BETA_INDEX_DIGEST,
3569                    &Position::default(),
3570                ),
3571                Error::IndexNotFound
3572            );
3573        })
3574    }
3575
3576    #[test]
3577    fn withdraw_from_pool_success() {
3578        commit_test_ext().execute_with(|| {
3579            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3580            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
3581            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, 100).unwrap();
3582            initiate_key_and_set_balance_and_hold(ALAN, LARGE_VALUE, 100).unwrap();
3583            Pallet::place_commit(
3584                &ALICE,
3585                &STAKING,
3586                &ALPHA_ENTRY_DIGEST,
3587                LARGE_VALUE,
3588                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3589            )
3590            .unwrap();
3591            Pallet::place_commit(
3592                &BOB,
3593                &STAKING,
3594                &BETA_ENTRY_DIGEST,
3595                STANDARD_VALUE,
3596                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3597            )
3598            .unwrap();
3599            prepare_and_initiate_pool(
3600                ALAN, // manager
3601                STAKING,
3602                &[(ALPHA_ENTRY_DIGEST, 60), (BETA_ENTRY_DIGEST, 40)],
3603                ALPHA_INDEX_DIGEST,
3604                ALPHA_POOL_DIGEST,
3605                COMMISSION_LOW,
3606            )
3607            .unwrap();
3608            Pallet::place_commit(
3609                &CHARLIE,
3610                &STAKING,
3611                &ALPHA_POOL_DIGEST,
3612                100,
3613                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3614            )
3615            .unwrap();
3616            // Balance after deposit
3617            let actual_slots_value = Pallet::get_slots_value(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
3618            let expected_slots_value = vec![(ALPHA_ENTRY_DIGEST, 60), (BETA_ENTRY_DIGEST, 40)];
3619            assert_eq!(actual_slots_value, expected_slots_value);
3620            // Withdraw from pool
3621            let actual_imbalance = CommitHelper::withdraw_from_pool(
3622                &CHARLIE,
3623                &STAKING,
3624                &ALPHA_POOL_DIGEST,
3625                &Position::default(),
3626            )
3627            .unwrap();
3628            let expected_imbalance = AssetDelta::new(100, 95);
3629            assert_eq!(expected_imbalance, actual_imbalance);
3630            // Balance after withdraw
3631            let actual_slots_value = Pallet::get_slots_value(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
3632            let expected_slots_value = vec![(ALPHA_ENTRY_DIGEST, 0), (BETA_ENTRY_DIGEST, 0)];
3633            assert_eq!(actual_slots_value, expected_slots_value);
3634            // Commission distribution for manager
3635            let alan_balance = AssetOf::balance(&ALAN);
3636            assert_eq!(alan_balance, 25); // 20 (existing balance) + 5 (commission)
3637        })
3638    }
3639
3640    #[test]
3641    fn withdraw_from_pool_err_pool_not_found() {
3642        commit_test_ext().execute_with(|| {
3643            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3644            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
3645            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, 40).unwrap();
3646            Pallet::place_commit(
3647                &ALICE,
3648                &STAKING,
3649                &ALPHA_ENTRY_DIGEST,
3650                LARGE_VALUE,
3651                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3652            )
3653            .unwrap();
3654            Pallet::place_commit(
3655                &BOB,
3656                &STAKING,
3657                &BETA_ENTRY_DIGEST,
3658                STANDARD_VALUE,
3659                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3660            )
3661            .unwrap();
3662            prepare_and_initiate_pool(
3663                CHARLIE,
3664                STAKING,
3665                &[(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)],
3666                ALPHA_INDEX_DIGEST,
3667                ALPHA_POOL_DIGEST,
3668                COMMISSION_ZERO,
3669            )
3670            .unwrap();
3671            Pallet::place_commit(
3672                &CHARLIE,
3673                &STAKING,
3674                &ALPHA_POOL_DIGEST,
3675                35,
3676                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3677            )
3678            .unwrap();
3679            assert_err!(
3680                CommitHelper::withdraw_from_pool(
3681                    &CHARLIE,
3682                    &STAKING,
3683                    &BETA_POOL_DIGEST,
3684                    &Position::default(),
3685                ),
3686                Error::PoolNotFound
3687            );
3688        })
3689    }
3690
3691    // ===============================================================================
3692    // `````````````````````````````` COMMIT OPERATIONS ``````````````````````````````
3693    // ===============================================================================
3694
3695    #[test]
3696    fn place_commit_of_success_for_direct_digest_model() {
3697        commit_test_ext().execute_with(|| {
3698            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, STANDARD_VALUE).unwrap();
3699            assert_err!(
3700                Pallet::commit_exists(&ALICE, &STAKING),
3701                Error::CommitNotFound
3702            );
3703            assert_err!(
3704                Pallet::digest_exists(&STAKING, &ALPHA_DIGEST),
3705                Error::DigestNotFound
3706            );
3707            CommitHelper::place_commit_of(
3708                &ALICE,
3709                &STAKING,
3710                &DigestVariant::Direct(ALPHA_DIGEST),
3711                STANDARD_VALUE,
3712                &Default::default(),
3713                &Directive::new(Precision::BestEffort, Fortitude::Force),
3714            )
3715            .unwrap();
3716            // Commit and digest enquirey
3717            assert_ok!(Pallet::commit_exists(&ALICE, &STAKING));
3718            assert_ok!(Pallet::digest_exists(&STAKING, &ALPHA_DIGEST));
3719            // Balance and freeze enquirey
3720            let balace_after = AssetOf::balance(&ALICE);
3721            let balace_on_hold_after = AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE);
3722            let expected_balance_after = 20;
3723            let expected_balance_on_hold_after = 0;
3724            assert_eq!(expected_balance_after, balace_after);
3725            assert_eq!(expected_balance_on_hold_after, balace_on_hold_after);
3726            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), STANDARD_VALUE);
3727            // Commit info enquiery
3728            let commit_info = CommitMap::get((ALICE, STAKING)).unwrap();
3729            assert_eq!(commit_info.digest(), ALPHA_DIGEST);
3730            let commits = commit_info.commits();
3731            let commit = commits.get(0).unwrap();
3732            assert_eq!(receipt_deposit_value(commit).unwrap(), STANDARD_VALUE);
3733            // Digest info enquiery
3734            let digest_info = DigestMap::get((STAKING, ALPHA_DIGEST)).unwrap();
3735            let digests = digest_info.reveal();
3736            let digest_of = digests.get(0).unwrap();
3737            assert!(has_deposits(digest_of, &Default::default(), &ALPHA_DIGEST).is_ok());
3738            assert_eq!(
3739                balance_total(digest_of, &Default::default(), &ALPHA_DIGEST).unwrap(),
3740                STANDARD_VALUE
3741            );
3742            // Total value enquiery
3743            let reason_value = ReasonValue::get(STAKING).unwrap();
3744            assert_eq!(reason_value, 10);
3745        })
3746    }
3747
3748    #[test]
3749    fn place_commit_of_success_for_index_digest_model() {
3750        commit_test_ext().execute_with(|| {
3751            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3752            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
3753            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
3754            Pallet::place_commit(
3755                &ALICE,
3756                &STAKING,
3757                &ALPHA_ENTRY_DIGEST,
3758                LARGE_VALUE,
3759                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3760            )
3761            .unwrap();
3762            Pallet::place_commit(
3763                &BOB,
3764                &STAKING,
3765                &BETA_ENTRY_DIGEST,
3766                STANDARD_VALUE,
3767                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3768            )
3769            .unwrap();
3770            prepare_and_initiate_index(
3771                ALICE,
3772                STAKING,
3773                &[(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)],
3774                ALPHA_INDEX_DIGEST,
3775            )
3776            .unwrap();
3777            assert_ok!(Pallet::index_exists(&STAKING, &ALPHA_INDEX_DIGEST));
3778            // Before placing a commit to the index
3779            let index_info = Pallet::get_index(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
3780            assert_eq!(index_info.capital(), 100);
3781            assert_eq!(index_info.principal(), 0);
3782            let actual_entries_value =
3783                Pallet::get_entries_value(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
3784            let expected_entries_value = vec![(ALPHA_ENTRY_DIGEST, 0), (BETA_ENTRY_DIGEST, 0)];
3785            assert_eq!(actual_entries_value, expected_entries_value);
3786            let reason_value = ReasonValue::get(STAKING).unwrap();
3787            assert_eq!(reason_value, 30);
3788            // Place commit to an index
3789            assert_ok!(CommitHelper::place_commit_of(
3790                &CHARLIE,
3791                &STAKING,
3792                &DigestVariant::Index(ALPHA_INDEX_DIGEST),
3793                LARGE_VALUE,
3794                &Position::default(),
3795                &Directive::new(Precision::BestEffort, Fortitude::Polite)
3796            ));
3797            // After placing a commit to the index
3798            let index_info = Pallet::get_index(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
3799            assert_eq!(index_info.capital(), 100);
3800            assert_eq!(index_info.principal(), LARGE_VALUE);
3801            let actual_entries_value =
3802                Pallet::get_entries_value(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
3803            let expected_entries_value = vec![(ALPHA_ENTRY_DIGEST, 8), (BETA_ENTRY_DIGEST, 12)];
3804            assert_eq!(actual_entries_value, expected_entries_value);
3805            let reason_value = ReasonValue::get(STAKING).unwrap();
3806            assert_eq!(reason_value, 50);
3807            let commit_variant = Pallet::get_commit_variant(&ALICE, &STAKING).unwrap();
3808            assert_eq!(commit_variant, Position::default());
3809        })
3810    }
3811
3812    #[test]
3813    fn place_commit_of_success_for_pool_digest_model() {
3814        commit_test_ext().execute_with(|| {
3815            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3816            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
3817            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
3818            Pallet::place_commit(
3819                &ALICE,
3820                &STAKING,
3821                &ALPHA_ENTRY_DIGEST,
3822                LARGE_VALUE,
3823                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3824            )
3825            .unwrap();
3826            Pallet::place_commit(
3827                &BOB,
3828                &STAKING,
3829                &BETA_ENTRY_DIGEST,
3830                STANDARD_VALUE,
3831                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3832            )
3833            .unwrap();
3834            let entries = vec![(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)];
3835            prepare_and_initiate_pool(
3836                ALICE,
3837                STAKING,
3838                &entries,
3839                ALPHA_INDEX_DIGEST,
3840                ALPHA_POOL_DIGEST,
3841                COMMISSION_ZERO,
3842            )
3843            .unwrap();
3844            // Before placing commit to pool
3845            let pool_info = PoolMap::get((STAKING, ALPHA_POOL_DIGEST)).unwrap();
3846            let pool_balance_of = &pool_info.balance();
3847            assert!(
3848                has_deposits(pool_balance_of, &Default::default(), &ALPHA_POOL_DIGEST).is_err()
3849            );
3850            assert_eq!(
3851                balance_total(pool_balance_of, &Default::default(), &ALPHA_POOL_DIGEST).unwrap(),
3852                0
3853            );
3854            let pool_capital = pool_info.capital();
3855            assert_eq!(pool_capital, 100);
3856            let actual_slots_value = Pallet::get_slots_value(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
3857            let expected_slots_value = vec![(ALPHA_ENTRY_DIGEST, 0), (BETA_ENTRY_DIGEST, 0)];
3858            assert_eq!(actual_slots_value, expected_slots_value);
3859            let reason_value = ReasonValue::get(STAKING).unwrap();
3860            assert_eq!(reason_value, 30);
3861            // Placing commit to  pool
3862            assert_ok!(CommitHelper::place_commit_of(
3863                &CHARLIE,
3864                &STAKING,
3865                &DigestVariant::Pool(ALPHA_POOL_DIGEST),
3866                LARGE_VALUE,
3867                &Position::default(),
3868                &Directive::new(Precision::BestEffort, Fortitude::Polite)
3869            ));
3870            // After placing commit to pool
3871            let pool_info = PoolMap::get((STAKING, ALPHA_POOL_DIGEST)).unwrap();
3872            let pool_balance_of = pool_info.balance();
3873            assert!(
3874                has_deposits(&pool_balance_of, &Default::default(), &ALPHA_POOL_DIGEST).is_ok()
3875            );
3876            assert_eq!(
3877                balance_total(&pool_balance_of, &Default::default(), &ALPHA_POOL_DIGEST).unwrap(),
3878                20
3879            );
3880            let actual_slots_value = Pallet::get_slots_value(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
3881            let expected_slots_value = vec![(ALPHA_ENTRY_DIGEST, 8), (BETA_ENTRY_DIGEST, 12)];
3882            assert_eq!(actual_slots_value, expected_slots_value);
3883            let reason_value = ReasonValue::get(STAKING).unwrap();
3884            assert_eq!(reason_value, 50);
3885            // Balance and freeze enquirey
3886            let balace_after = AssetOf::balance(&CHARLIE);
3887            let balace_on_hold_after = AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &CHARLIE);
3888            let expected_balance_after = 20;
3889            let expected_balance_on_hold_after = 0;
3890            assert_eq!(expected_balance_after, balace_after);
3891            assert_eq!(expected_balance_on_hold_after, balace_on_hold_after);
3892            assert_eq!(AssetOf::balance_frozen(&STAKING, &CHARLIE), LARGE_VALUE);
3893        })
3894    }
3895
3896    #[test]
3897    fn place_digest_commit_success() {
3898        commit_test_ext().execute_with(|| {
3899            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, STANDARD_VALUE).unwrap();
3900            assert_err!(
3901                Pallet::commit_exists(&ALICE, &STAKING),
3902                Error::CommitNotFound
3903            );
3904            assert_err!(
3905                Pallet::digest_exists(&STAKING, &ALPHA_DIGEST),
3906                Error::DigestNotFound
3907            );
3908            CommitHelper::place_digest_commit(
3909                &ALICE,
3910                &STAKING,
3911                &ALPHA_DIGEST,
3912                STANDARD_VALUE,
3913                &Default::default(),
3914                &Directive::new(Precision::BestEffort, Fortitude::Force),
3915            )
3916            .unwrap();
3917            // Commit and digest enquirey
3918            assert_ok!(Pallet::commit_exists(&ALICE, &STAKING));
3919            assert_ok!(Pallet::digest_exists(&STAKING, &ALPHA_DIGEST));
3920            // Balance and freeze enquirey
3921            let balace_after = AssetOf::balance(&ALICE);
3922            let balace_on_hold_after = AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE);
3923            let expected_balance_after = 20;
3924            let expected_balance_on_hold_after = 0;
3925            assert_eq!(expected_balance_after, balace_after);
3926            assert_eq!(expected_balance_on_hold_after, balace_on_hold_after);
3927            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), STANDARD_VALUE);
3928            // Commit info enquiery
3929            let commit_info = CommitMap::get((ALICE, STAKING)).unwrap();
3930            assert_eq!(commit_info.digest(), ALPHA_DIGEST);
3931            let commits = commit_info.commits();
3932            let commit = commits.get(0).unwrap();
3933            assert_eq!(receipt_deposit_value(commit).unwrap(), STANDARD_VALUE);
3934            // Digest info enquiery
3935            let digest_info = DigestMap::get((STAKING, ALPHA_DIGEST)).unwrap();
3936            let digests = digest_info.reveal();
3937            let digest_of = digests.get(0).unwrap();
3938            assert!(has_deposits(digest_of, &Default::default(), &ALPHA_DIGEST).is_ok());
3939            assert_eq!(
3940                balance_total(digest_of, &Default::default(), &ALPHA_DIGEST).unwrap(),
3941                STANDARD_VALUE
3942            );
3943            // Total value enquiery
3944            let reason_value = ReasonValue::get(STAKING).unwrap();
3945            assert_eq!(reason_value, 10);
3946        })
3947    }
3948
3949    #[test]
3950    fn place_index_commit_success() {
3951        commit_test_ext().execute_with(|| {
3952            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3953            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
3954            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
3955            Pallet::place_commit(
3956                &ALICE,
3957                &STAKING,
3958                &ALPHA_ENTRY_DIGEST,
3959                LARGE_VALUE,
3960                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3961            )
3962            .unwrap();
3963            Pallet::place_commit(
3964                &BOB,
3965                &STAKING,
3966                &BETA_ENTRY_DIGEST,
3967                STANDARD_VALUE,
3968                &Directive::new(Precision::BestEffort, Fortitude::Polite),
3969            )
3970            .unwrap();
3971            prepare_and_initiate_index(
3972                ALICE,
3973                STAKING,
3974                &[(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)],
3975                ALPHA_INDEX_DIGEST,
3976            )
3977            .unwrap();
3978            assert_ok!(Pallet::index_exists(&STAKING, &ALPHA_INDEX_DIGEST));
3979            // Before placing a commit to the index
3980            let index_info = Pallet::get_index(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
3981            assert_eq!(index_info.capital(), 100);
3982            assert_eq!(index_info.principal(), 0);
3983            let actual_entries_value =
3984                Pallet::get_entries_value(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
3985            let expected_entries_value = vec![(ALPHA_ENTRY_DIGEST, 0), (BETA_ENTRY_DIGEST, 0)];
3986            assert_eq!(actual_entries_value, expected_entries_value);
3987            let reason_value = ReasonValue::get(STAKING).unwrap();
3988            assert_eq!(reason_value, 30);
3989            // Place commit to an index
3990            assert_ok!(CommitHelper::place_index_commit(
3991                &CHARLIE,
3992                &STAKING,
3993                &ALPHA_INDEX_DIGEST,
3994                LARGE_VALUE,
3995                &Position::default(),
3996                &Directive::new(Precision::BestEffort, Fortitude::Polite)
3997            ));
3998            // After placing a commit to the index
3999            let index_info = Pallet::get_index(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
4000            assert_eq!(index_info.capital(), 100);
4001            assert_eq!(index_info.principal(), LARGE_VALUE);
4002            let actual_entries_value =
4003                Pallet::get_entries_value(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
4004            let expected_entries_value = vec![(ALPHA_ENTRY_DIGEST, 8), (BETA_ENTRY_DIGEST, 12)];
4005            assert_eq!(actual_entries_value, expected_entries_value);
4006            let reason_value = ReasonValue::get(STAKING).unwrap();
4007            assert_eq!(reason_value, 50);
4008            // Commit info check
4009            assert_ok!(Pallet::commit_exists(&CHARLIE, &STAKING));
4010            let commit_info = CommitMap::get((CHARLIE, STAKING)).unwrap();
4011            assert_eq!(commit_info.digest(), ALPHA_INDEX_DIGEST);
4012            assert_eq!(commit_info.variant(), Position::default());
4013
4014            // Here commits via CommitMap are nothing but a placeholder only for index commits
4015            // EntryMap only holds all individual entries commits, so querying value via this
4016            // returns error due to default receipt - i.e., invalid
4017            let commits = commit_info.commits();
4018            let commit = commits.get(0).unwrap();
4019            assert!(receipt_deposit_value(commit).is_err(),);
4020
4021            // Digest info check
4022            let digest_info = DigestMap::get((STAKING, ALPHA_ENTRY_DIGEST)).unwrap();
4023            let digests = digest_info.reveal();
4024            let digest_of = digests.get(0).unwrap();
4025            assert!(has_deposits(digest_of, &Default::default(), &ALPHA_ENTRY_DIGEST).is_ok());
4026            assert_eq!(
4027                balance_total(digest_of, &Default::default(), &ALPHA_ENTRY_DIGEST).unwrap(),
4028                28
4029            );
4030            let digest_info = DigestMap::get((STAKING, BETA_ENTRY_DIGEST)).unwrap();
4031            let digests = digest_info.reveal();
4032            let digest_of = digests.get(0).unwrap();
4033            assert!(has_deposits(digest_of, &Default::default(), &BETA_ENTRY_DIGEST).is_ok());
4034            assert_eq!(
4035                balance_total(digest_of, &Default::default(), &BETA_ENTRY_DIGEST).unwrap(),
4036                22
4037            );
4038            // Entry info check
4039            let alpha_entry_info =
4040                EntryMap::get((STAKING, ALPHA_INDEX_DIGEST, ALPHA_ENTRY_DIGEST, CHARLIE)).unwrap();
4041            let alpha_entries = alpha_entry_info.commits();
4042            let alpha_commit = alpha_entries.get(0).unwrap();
4043            assert_eq!(receipt_deposit_value(alpha_commit).unwrap(), 8);
4044            let beta_entry_info =
4045                EntryMap::get((STAKING, ALPHA_INDEX_DIGEST, BETA_ENTRY_DIGEST, CHARLIE)).unwrap();
4046            let beta_entries = beta_entry_info.commits();
4047            let beta_commit = beta_entries.get(0).unwrap();
4048            assert_eq!(receipt_deposit_value(beta_commit).unwrap(), 12);
4049            // Balance and freeze enquirey
4050            let balace_after = AssetOf::balance(&CHARLIE);
4051            let balace_on_hold_after = AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &CHARLIE);
4052            let expected_balance_after = 20;
4053            let expected_balance_on_hold_after = 0;
4054            assert_eq!(expected_balance_after, balace_after);
4055            assert_eq!(expected_balance_on_hold_after, balace_on_hold_after);
4056            assert_eq!(AssetOf::balance_frozen(&STAKING, &CHARLIE), LARGE_VALUE);
4057        })
4058    }
4059
4060    #[test]
4061    fn place_pool_commit_success() {
4062        commit_test_ext().execute_with(|| {
4063            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4064            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
4065            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
4066            Pallet::place_commit(
4067                &ALICE,
4068                &STAKING,
4069                &ALPHA_ENTRY_DIGEST,
4070                LARGE_VALUE,
4071                &Directive::new(Precision::BestEffort, Fortitude::Polite),
4072            )
4073            .unwrap();
4074            Pallet::place_commit(
4075                &BOB,
4076                &STAKING,
4077                &BETA_ENTRY_DIGEST,
4078                STANDARD_VALUE,
4079                &Directive::new(Precision::BestEffort, Fortitude::Polite),
4080            )
4081            .unwrap();
4082            let entries = vec![(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)];
4083            prepare_and_initiate_pool(
4084                ALICE,
4085                STAKING,
4086                &entries,
4087                ALPHA_INDEX_DIGEST,
4088                ALPHA_POOL_DIGEST,
4089                COMMISSION_ZERO,
4090            )
4091            .unwrap();
4092            // Before placing commit to pool
4093            let pool_info = PoolMap::get((STAKING, ALPHA_POOL_DIGEST)).unwrap();
4094            let pool_balance_of = pool_info.balance();
4095            assert!(
4096                has_deposits(&pool_balance_of, &Default::default(), &ALPHA_POOL_DIGEST).is_err()
4097            );
4098            assert_eq!(
4099                balance_total(&pool_balance_of, &Default::default(), &ALPHA_POOL_DIGEST).unwrap(),
4100                0
4101            );
4102            let pool_capital = pool_info.capital();
4103            assert_eq!(pool_capital, 100);
4104            let actual_slots_value = Pallet::get_slots_value(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
4105            let expected_slots_value = vec![(ALPHA_ENTRY_DIGEST, 0), (BETA_ENTRY_DIGEST, 0)];
4106            assert_eq!(actual_slots_value, expected_slots_value);
4107            let reason_value = ReasonValue::get(STAKING).unwrap();
4108            assert_eq!(reason_value, 30);
4109            // Placing commit to  pool
4110            assert_ok!(CommitHelper::place_pool_commit(
4111                &CHARLIE,
4112                &STAKING,
4113                &ALPHA_POOL_DIGEST,
4114                LARGE_VALUE,
4115                &Position::default(),
4116                &Directive::new(Precision::BestEffort, Fortitude::Polite)
4117            ));
4118            // After placing commit to pool
4119            let pool_info = PoolMap::get((STAKING, ALPHA_POOL_DIGEST)).unwrap();
4120            let pool_balance_of = pool_info.balance();
4121            assert!(
4122                has_deposits(&pool_balance_of, &Default::default(), &ALPHA_POOL_DIGEST).is_ok()
4123            );
4124            assert_eq!(
4125                balance_total(&pool_balance_of, &Default::default(), &ALPHA_POOL_DIGEST).unwrap(),
4126                20
4127            );
4128            let actual_slots_value = Pallet::get_slots_value(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
4129            let expected_slots_value = vec![(ALPHA_ENTRY_DIGEST, 8), (BETA_ENTRY_DIGEST, 12)];
4130            assert_eq!(actual_slots_value, expected_slots_value);
4131            let reason_value = ReasonValue::get(STAKING).unwrap();
4132            assert_eq!(reason_value, 50);
4133            // Commit info check
4134            assert_ok!(Pallet::commit_exists(&CHARLIE, &STAKING));
4135            let commit_info = CommitMap::get((CHARLIE, STAKING)).unwrap();
4136            assert_eq!(commit_info.digest(), ALPHA_POOL_DIGEST);
4137            assert_eq!(commit_info.variant(), Position::default());
4138            let commits = commit_info.commits();
4139            let commit = commits.get(0).unwrap();
4140            assert_eq!(receipt_deposit_value(commit).unwrap(), LARGE_VALUE);
4141            // Digest info check
4142            let digest_info = DigestMap::get((STAKING, ALPHA_ENTRY_DIGEST)).unwrap();
4143            let digests = digest_info.reveal();
4144            let digest_of = digests.get(0).unwrap();
4145            assert!(has_deposits(digest_of, &Default::default(), &ALPHA_ENTRY_DIGEST).is_ok());
4146            assert_eq!(
4147                balance_total(digest_of, &Default::default(), &ALPHA_ENTRY_DIGEST).unwrap(),
4148                28
4149            );
4150            let digest_info = DigestMap::get((STAKING, BETA_ENTRY_DIGEST)).unwrap();
4151            let digests = digest_info.reveal();
4152            let digest_of = digests.get(0).unwrap();
4153            assert!(has_deposits(digest_of, &Default::default(), &BETA_ENTRY_DIGEST).is_ok());
4154            assert_eq!(
4155                balance_total(digest_of, &Default::default(), &BETA_ENTRY_DIGEST).unwrap(),
4156                22
4157            );
4158            // Balance and freeze enquirey
4159            let balace_after = AssetOf::balance(&CHARLIE);
4160            let balace_on_hold_after = AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &CHARLIE);
4161            let expected_balance_after = 20;
4162            let expected_balance_on_hold_after = 0;
4163            assert_eq!(expected_balance_after, balace_after);
4164            assert_eq!(expected_balance_on_hold_after, balace_on_hold_after);
4165            assert_eq!(AssetOf::balance_frozen(&STAKING, &CHARLIE), LARGE_VALUE);
4166        })
4167    }
4168
4169    #[test]
4170    fn raise_commit_of_success_for_direct_digest_model() {
4171        commit_test_ext().execute_with(|| {
4172            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4173            Pallet::place_commit(
4174                &ALICE,
4175                &STAKING,
4176                &ALPHA_DIGEST,
4177                STANDARD_VALUE,
4178                &Directive::new(Precision::BestEffort, Fortitude::Polite),
4179            )
4180            .unwrap();
4181            let commit_value_before = Pallet::get_commit_value(&ALICE, &STAKING).unwrap();
4182            assert_eq!(commit_value_before, 10);
4183            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), STANDARD_VALUE);
4184            let total_value = Pallet::get_total_value(&STAKING);
4185            assert_eq!(total_value, STANDARD_VALUE);
4186            assert_ok!(CommitHelper::raise_digest_commit(
4187                &ALICE,
4188                &STAKING,
4189                &ALPHA_DIGEST,
4190                SMALL_VALUE,
4191                &Directive::new(Precision::BestEffort, Fortitude::Polite)
4192            ));
4193            let commit_value_after = Pallet::get_commit_value(&ALICE, &STAKING).unwrap();
4194            assert_eq!(commit_value_after, 15);
4195            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), 15);
4196            let total_value = Pallet::get_total_value(&STAKING);
4197            assert_eq!(total_value, 15);
4198            // new commit instance added
4199            let commit_info = CommitMap::get((ALICE, STAKING)).unwrap();
4200            let commits = commit_info.commits();
4201            let commit = commits.get(0).unwrap();
4202            assert_eq!(receipt_deposit_value(commit).unwrap(), 10);
4203            // raise commit instance added
4204            let commit = commits.get(1).unwrap();
4205            assert_eq!(receipt_deposit_value(commit).unwrap(), 5);
4206        })
4207    }
4208
4209    #[test]
4210    fn raise_commit_of_success_for_index_digest_model() {
4211        commit_test_ext().execute_with(|| {
4212            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, 50).unwrap();
4213            initiate_digest_with_default_balance(STAKING, ALPHA_ENTRY_DIGEST).unwrap();
4214            initiate_digest_with_default_balance(STAKING, BETA_ENTRY_DIGEST).unwrap();
4215            prepare_and_initiate_index(
4216                ALICE,
4217                STAKING,
4218                &[(ALPHA_ENTRY_DIGEST, 60), (BETA_ENTRY_DIGEST, 40)],
4219                ALPHA_INDEX_DIGEST,
4220            )
4221            .unwrap();
4222            // alice balance inspect
4223            assert_eq!(AssetOf::balance(&ALICE), 20);
4224            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 50);
4225            Pallet::place_commit(
4226                &ALICE,
4227                &STAKING,
4228                &ALPHA_INDEX_DIGEST,
4229                20,
4230                &Directive::new(Precision::BestEffort, Fortitude::Polite),
4231            )
4232            .unwrap();
4233            // Before raising the index commit value
4234            let index_info = Pallet::get_index(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
4235            assert_eq!(index_info.capital(), 100);
4236            assert_eq!(index_info.principal(), 20);
4237            let actual_entries_value =
4238                Pallet::get_entries_value(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
4239            let expected_entries_value = vec![(ALPHA_ENTRY_DIGEST, 12), (BETA_ENTRY_DIGEST, 8)];
4240            assert_eq!(actual_entries_value, expected_entries_value);
4241            let reason_value = ReasonValue::get(STAKING).unwrap();
4242            assert_eq!(reason_value, 20);
4243            // alice balance inspect
4244            assert_eq!(AssetOf::balance(&ALICE), 20);
4245            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 30);
4246            // Raise index commit value
4247            assert_ok!(CommitHelper::raise_index_commit(
4248                &ALICE,
4249                &STAKING,
4250                &ALPHA_INDEX_DIGEST,
4251                10,
4252                &Directive::new(Precision::BestEffort, Fortitude::Polite)
4253            ));
4254            // After placing a commit to the index
4255            let index_info = Pallet::get_index(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
4256            assert_eq!(index_info.capital(), 100);
4257            assert_eq!(index_info.principal(), 30);
4258            let actual_entries_value =
4259                Pallet::get_entries_value(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
4260            let expected_entries_value = vec![(ALPHA_ENTRY_DIGEST, 18), (BETA_ENTRY_DIGEST, 12)];
4261            assert_eq!(actual_entries_value, expected_entries_value);
4262            let reason_value = ReasonValue::get(STAKING).unwrap();
4263            assert_eq!(reason_value, 30);
4264            // entry info check
4265            // new instance added for raise commit
4266            let alpha_entry_info =
4267                EntryMap::get((STAKING, ALPHA_INDEX_DIGEST, ALPHA_ENTRY_DIGEST, ALICE)).unwrap();
4268            let alpha_entries = alpha_entry_info.commits();
4269            let commit = alpha_entries.get(1).unwrap();
4270            assert_eq!(receipt_deposit_value(commit).unwrap(), 6);
4271            let beta_entry_info =
4272                EntryMap::get((STAKING, ALPHA_INDEX_DIGEST, BETA_ENTRY_DIGEST, ALICE)).unwrap();
4273            let beta_entries = beta_entry_info.commits();
4274            let commit = beta_entries.get(1).unwrap();
4275            assert_eq!(receipt_deposit_value(commit).unwrap(), 4);
4276            // Balance and freeze enquirey
4277            let actual_balance = AssetOf::balance(&ALICE);
4278            let actual_balace_on_hold = AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE);
4279            let expected_balance = 20;
4280            let expected_balance_on_hold = 20;
4281            assert_eq!(actual_balance, expected_balance);
4282            assert_eq!(actual_balace_on_hold, expected_balance_on_hold);
4283            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), 30);
4284        })
4285    }
4286
4287    #[test]
4288    fn raise_commit_of_success_for_pool_digest_model() {
4289        commit_test_ext().execute_with(|| {
4290            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, 60).unwrap();
4291            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
4292            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
4293            Pallet::place_commit(
4294                &BOB,
4295                &STAKING,
4296                &ALPHA_ENTRY_DIGEST,
4297                LARGE_VALUE,
4298                &Directive::new(Precision::BestEffort, Fortitude::Polite),
4299            )
4300            .unwrap();
4301            Pallet::place_commit(
4302                &CHARLIE,
4303                &STAKING,
4304                &BETA_ENTRY_DIGEST,
4305                STANDARD_VALUE,
4306                &Directive::new(Precision::BestEffort, Fortitude::Polite),
4307            )
4308            .unwrap();
4309            let entries = vec![(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)];
4310            prepare_and_initiate_pool(
4311                ALICE,
4312                STAKING,
4313                &entries,
4314                ALPHA_INDEX_DIGEST,
4315                ALPHA_POOL_DIGEST,
4316                COMMISSION_ONE,
4317            )
4318            .unwrap();
4319            // alice balance inspect
4320            assert_eq!(AssetOf::balance(&ALICE), 20);
4321            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 60);
4322            Pallet::place_commit(
4323                &ALICE,
4324                &STAKING,
4325                &ALPHA_POOL_DIGEST,
4326                35,
4327                &Directive::new(Precision::BestEffort, Fortitude::Polite),
4328            )
4329            .unwrap();
4330            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 25);
4331            // Before raising the pool commit value
4332            let pool_info = PoolMap::get((STAKING, ALPHA_POOL_DIGEST)).unwrap();
4333            let pool_balance_of = pool_info.balance();
4334            assert!(
4335                has_deposits(&pool_balance_of, &Default::default(), &ALPHA_POOL_DIGEST).is_ok()
4336            );
4337            assert_eq!(
4338                balance_total(&pool_balance_of, &Default::default(), &ALPHA_POOL_DIGEST).unwrap(),
4339                35
4340            );
4341            let actual_slots_value = Pallet::get_slots_value(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
4342            let expected_slots_value = vec![(ALPHA_ENTRY_DIGEST, 14), (BETA_ENTRY_DIGEST, 21)];
4343            assert_eq!(actual_slots_value, expected_slots_value);
4344            let reason_value = ReasonValue::get(STAKING).unwrap();
4345            assert_eq!(reason_value, 65); // 20 + 10 + 35
4346
4347            // Raise commit value
4348            assert_ok!(CommitHelper::raise_pool_commit(
4349                &ALICE,
4350                &STAKING,
4351                &ALPHA_POOL_DIGEST,
4352                20,
4353                &Directive::new(Precision::BestEffort, Fortitude::Polite)
4354            ));
4355            // // After raising the pool commit value
4356            let pool_info = PoolMap::get((STAKING, ALPHA_POOL_DIGEST)).unwrap();
4357            let pool_balance_of = pool_info.balance();
4358            assert!(
4359                has_deposits(&pool_balance_of, &Default::default(), &ALPHA_POOL_DIGEST).is_ok()
4360            );
4361            assert_eq!(
4362                balance_total(&pool_balance_of, &Default::default(), &ALPHA_POOL_DIGEST).unwrap(),
4363                55
4364            );
4365            let pool_capital = pool_info.capital();
4366            assert_eq!(pool_capital, 100);
4367            let actual_slots_value = Pallet::get_slots_value(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
4368            let expected_slots_value = vec![(ALPHA_ENTRY_DIGEST, 22), (BETA_ENTRY_DIGEST, 33)];
4369            assert_eq!(actual_slots_value, expected_slots_value);
4370            let reason_value = ReasonValue::get(STAKING).unwrap();
4371            assert_eq!(reason_value, 85);
4372            // new commit instance added
4373            let commit_info = CommitMap::get((ALICE, STAKING)).unwrap();
4374            let commits = commit_info.commits();
4375            let commit = commits.get(0).unwrap();
4376            assert_eq!(receipt_deposit_value(commit).unwrap(), 35);
4377            // raise commit instance is added
4378            let raise_commit = commits.get(1).unwrap();
4379            assert_eq!(receipt_deposit_value(raise_commit).unwrap(), 20);
4380        })
4381    }
4382
4383    #[test]
4384    fn raise_digest_commit_success() {
4385        commit_test_ext().execute_with(|| {
4386            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4387            Pallet::place_commit(
4388                &ALICE,
4389                &STAKING,
4390                &ALPHA_DIGEST,
4391                STANDARD_VALUE,
4392                &Directive::new(Precision::BestEffort, Fortitude::Polite),
4393            )
4394            .unwrap();
4395            let commit_value_before = Pallet::get_commit_value(&ALICE, &STAKING).unwrap();
4396            assert_eq!(commit_value_before, 10);
4397            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), STANDARD_VALUE);
4398            let total_value = Pallet::get_total_value(&STAKING);
4399            assert_eq!(total_value, STANDARD_VALUE);
4400            assert_ok!(CommitHelper::raise_digest_commit(
4401                &ALICE,
4402                &STAKING,
4403                &ALPHA_DIGEST,
4404                SMALL_VALUE,
4405                &Directive::new(Precision::BestEffort, Fortitude::Polite)
4406            ));
4407            let commit_value_after = Pallet::get_commit_value(&ALICE, &STAKING).unwrap();
4408            assert_eq!(commit_value_after, 15);
4409            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), 15);
4410            let total_value = Pallet::get_total_value(&STAKING);
4411            assert_eq!(total_value, 15);
4412            // new commit instance added
4413            let commit_info = CommitMap::get((ALICE, STAKING)).unwrap();
4414            let commits = commit_info.commits();
4415            let commit = commits.get(0).unwrap();
4416            assert_eq!(receipt_deposit_value(commit).unwrap(), 10);
4417            // raise commit instance added
4418            let commit = commits.get(1).unwrap();
4419            assert_eq!(receipt_deposit_value(commit).unwrap(), 5);
4420        })
4421    }
4422
4423    #[test]
4424    fn raise_digest_commit_err_max_commits_reached() {
4425        commit_test_ext().execute_with(|| {
4426            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, 50).unwrap();
4427            Pallet::place_commit(
4428                &ALICE,
4429                &STAKING,
4430                &ALPHA_DIGEST,
4431                STANDARD_VALUE,
4432                &Directive::new(Precision::BestEffort, Fortitude::Polite),
4433            )
4434            .unwrap();
4435            assert_ok!(CommitHelper::raise_digest_commit(
4436                &ALICE,
4437                &STAKING,
4438                &ALPHA_DIGEST,
4439                SMALL_VALUE,
4440                &Directive::new(Precision::BestEffort, Fortitude::Polite)
4441            ));
4442            let commit_value_after = Pallet::get_commit_value(&ALICE, &STAKING).unwrap();
4443            assert_eq!(commit_value_after, 15);
4444            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), 15);
4445            assert_ok!(CommitHelper::raise_digest_commit(
4446                &ALICE,
4447                &STAKING,
4448                &ALPHA_DIGEST,
4449                STANDARD_VALUE,
4450                &Directive::new(Precision::BestEffort, Fortitude::Polite)
4451            ));
4452            let commit_value_after = Pallet::get_commit_value(&ALICE, &STAKING).unwrap();
4453            assert_eq!(commit_value_after, 25);
4454            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), 25);
4455            // new commit instance added
4456            let commit_info = CommitMap::get((ALICE, STAKING)).unwrap();
4457            let commits = commit_info.commits();
4458            let commit = commits.get(0).unwrap();
4459            assert_eq!(receipt_deposit_value(commit).unwrap(), 10);
4460            // raise commit instance added
4461            let commit = commits.get(1).unwrap();
4462            assert_eq!(receipt_deposit_value(commit).unwrap(), 5);
4463            // raise commit instance added
4464            let commit = commits.get(2).unwrap();
4465            assert_eq!(receipt_deposit_value(commit).unwrap(), 10);
4466            // since, the max commits allowed is set to 3, making an another raise commit will cause error
4467            assert_err!(
4468                CommitHelper::raise_digest_commit(
4469                    &ALICE,
4470                    &STAKING,
4471                    &ALPHA_DIGEST,
4472                    STANDARD_VALUE,
4473                    &Directive::new(Precision::BestEffort, Fortitude::Polite)
4474                ),
4475                Error::MaxCommitsReached
4476            );
4477        })
4478    }
4479
4480    #[test]
4481    fn raise_index_commit_success() {
4482        commit_test_ext().execute_with(|| {
4483            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, 50).unwrap();
4484            initiate_digest_with_default_balance(STAKING, ALPHA_ENTRY_DIGEST).unwrap();
4485            initiate_digest_with_default_balance(STAKING, BETA_ENTRY_DIGEST).unwrap();
4486            prepare_and_initiate_index(
4487                ALICE,
4488                STAKING,
4489                &[(ALPHA_ENTRY_DIGEST, 60), (BETA_ENTRY_DIGEST, 40)],
4490                ALPHA_INDEX_DIGEST,
4491            )
4492            .unwrap();
4493            // alice balance inspect
4494            assert_eq!(AssetOf::balance(&ALICE), 20);
4495            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 50);
4496            Pallet::place_commit(
4497                &ALICE,
4498                &STAKING,
4499                &ALPHA_INDEX_DIGEST,
4500                20,
4501                &Directive::new(Precision::BestEffort, Fortitude::Polite),
4502            )
4503            .unwrap();
4504            // Before raising the index commit value
4505            let index_info = Pallet::get_index(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
4506            assert_eq!(index_info.capital(), 100);
4507            assert_eq!(index_info.principal(), 20);
4508            let actual_entries_value =
4509                Pallet::get_entries_value(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
4510            let expected_entries_value = vec![(ALPHA_ENTRY_DIGEST, 12), (BETA_ENTRY_DIGEST, 8)];
4511            assert_eq!(actual_entries_value, expected_entries_value);
4512            let reason_value = ReasonValue::get(STAKING).unwrap();
4513            assert_eq!(reason_value, 20);
4514            // alice balance inspect
4515            assert_eq!(AssetOf::balance(&ALICE), 20);
4516            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 30);
4517            // Raise index commit value
4518            assert_ok!(CommitHelper::raise_index_commit(
4519                &ALICE,
4520                &STAKING,
4521                &ALPHA_INDEX_DIGEST,
4522                10,
4523                &Directive::new(Precision::BestEffort, Fortitude::Polite)
4524            ));
4525            // After placing a commit to the index
4526            let index_info = Pallet::get_index(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
4527            assert_eq!(index_info.capital(), 100);
4528            assert_eq!(index_info.principal(), 30);
4529            let actual_entries_value =
4530                Pallet::get_entries_value(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
4531            let expected_entries_value = vec![(ALPHA_ENTRY_DIGEST, 18), (BETA_ENTRY_DIGEST, 12)];
4532            assert_eq!(actual_entries_value, expected_entries_value);
4533            let reason_value = ReasonValue::get(STAKING).unwrap();
4534            assert_eq!(reason_value, 30);
4535            // entry info check
4536            // new instance added for raise commit
4537            let alpha_entry_info =
4538                EntryMap::get((STAKING, ALPHA_INDEX_DIGEST, ALPHA_ENTRY_DIGEST, ALICE)).unwrap();
4539            let alpha_entries = alpha_entry_info.commits();
4540            let commit = alpha_entries.get(1).unwrap();
4541            assert_eq!(receipt_deposit_value(commit).unwrap(), 6);
4542            let beta_entry_info =
4543                EntryMap::get((STAKING, ALPHA_INDEX_DIGEST, BETA_ENTRY_DIGEST, ALICE)).unwrap();
4544            let beta_entries = beta_entry_info.commits();
4545            let commit = beta_entries.get(1).unwrap();
4546            assert_eq!(receipt_deposit_value(commit).unwrap(), 4);
4547            // Balance and freeze enquirey
4548            let actual_balance = AssetOf::balance(&ALICE);
4549            let actual_balace_on_hold = AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE);
4550            let expected_balance = 20;
4551            let expected_balance_on_hold = 20;
4552            assert_eq!(actual_balance, expected_balance);
4553            assert_eq!(actual_balace_on_hold, expected_balance_on_hold);
4554            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), 30);
4555        })
4556    }
4557
4558    #[test]
4559    fn raise_index_commit_err_max_commits_reached() {
4560        commit_test_ext().execute_with(|| {
4561            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, 50).unwrap();
4562            initiate_digest_with_default_balance(STAKING, ALPHA_ENTRY_DIGEST).unwrap();
4563            initiate_digest_with_default_balance(STAKING, BETA_ENTRY_DIGEST).unwrap();
4564            prepare_and_initiate_index(
4565                ALICE,
4566                STAKING,
4567                &[(ALPHA_ENTRY_DIGEST, 60), (BETA_ENTRY_DIGEST, 40)],
4568                ALPHA_INDEX_DIGEST,
4569            )
4570            .unwrap();
4571            Pallet::place_commit(
4572                &ALICE,
4573                &STAKING,
4574                &ALPHA_INDEX_DIGEST,
4575                20,
4576                &Directive::new(Precision::BestEffort, Fortitude::Polite),
4577            )
4578            .unwrap();
4579            // Raise index commit value
4580            assert_ok!(CommitHelper::raise_index_commit(
4581                &ALICE,
4582                &STAKING,
4583                &ALPHA_INDEX_DIGEST,
4584                10,
4585                &Directive::new(Precision::BestEffort, Fortitude::Polite)
4586            ));
4587            // Raise index commit value
4588            assert_ok!(CommitHelper::raise_index_commit(
4589                &ALICE,
4590                &STAKING,
4591                &ALPHA_INDEX_DIGEST,
4592                5,
4593                &Directive::new(Precision::BestEffort, Fortitude::Polite)
4594            ));
4595            // entry info check
4596            // new instance added for raise commit
4597            let alpha_entry_info =
4598                EntryMap::get((STAKING, ALPHA_INDEX_DIGEST, ALPHA_ENTRY_DIGEST, ALICE)).unwrap();
4599            let alpha_entries = alpha_entry_info.commits();
4600            let commit = alpha_entries.get(1).unwrap();
4601            assert_eq!(receipt_deposit_value(commit).unwrap(), 6);
4602            // raise commit instance added
4603            let commit = alpha_entries.get(2).unwrap();
4604            assert_eq!(receipt_deposit_value(commit).unwrap(), 3);
4605            // raise commit instance added
4606            let beta_entry_info =
4607                EntryMap::get((STAKING, ALPHA_INDEX_DIGEST, BETA_ENTRY_DIGEST, ALICE)).unwrap();
4608            let beta_entries = beta_entry_info.commits();
4609            let commit = beta_entries.get(1).unwrap();
4610            assert_eq!(receipt_deposit_value(commit).unwrap(), 4);
4611            // raise commit instance added
4612            let beta_entry_info =
4613                EntryMap::get((STAKING, ALPHA_INDEX_DIGEST, BETA_ENTRY_DIGEST, ALICE)).unwrap();
4614            let beta_entries = beta_entry_info.commits();
4615            let commit = beta_entries.get(2).unwrap();
4616            assert_eq!(receipt_deposit_value(commit).unwrap(), 2);
4617            // since, the max commits allowed is set to 3, making an another raise commit will cause error
4618            assert_err!(
4619                CommitHelper::raise_index_commit(
4620                    &ALICE,
4621                    &STAKING,
4622                    &ALPHA_INDEX_DIGEST,
4623                    10,
4624                    &Directive::new(Precision::BestEffort, Fortitude::Polite)
4625                ),
4626                Error::MaxCommitsReached
4627            );
4628        })
4629    }
4630
4631    #[test]
4632    fn raise_pool_commit_success() {
4633        commit_test_ext().execute_with(|| {
4634            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, 60).unwrap();
4635            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
4636            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
4637            Pallet::place_commit(
4638                &BOB,
4639                &STAKING,
4640                &ALPHA_ENTRY_DIGEST,
4641                LARGE_VALUE,
4642                &Directive::new(Precision::BestEffort, Fortitude::Polite),
4643            )
4644            .unwrap();
4645            Pallet::place_commit(
4646                &CHARLIE,
4647                &STAKING,
4648                &BETA_ENTRY_DIGEST,
4649                STANDARD_VALUE,
4650                &Directive::new(Precision::BestEffort, Fortitude::Polite),
4651            )
4652            .unwrap();
4653            let entries = vec![(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)];
4654            prepare_and_initiate_pool(
4655                ALICE,
4656                STAKING,
4657                &entries,
4658                ALPHA_INDEX_DIGEST,
4659                ALPHA_POOL_DIGEST,
4660                COMMISSION_ONE,
4661            )
4662            .unwrap();
4663            // alice balance inspect
4664            assert_eq!(AssetOf::balance(&ALICE), 20);
4665            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 60);
4666            Pallet::place_commit(
4667                &ALICE,
4668                &STAKING,
4669                &ALPHA_POOL_DIGEST,
4670                35,
4671                &Directive::new(Precision::BestEffort, Fortitude::Polite),
4672            )
4673            .unwrap();
4674            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 25);
4675            // Before raising the pool commit value
4676            let pool_info = PoolMap::get((STAKING, ALPHA_POOL_DIGEST)).unwrap();
4677            let pool_balance_of = pool_info.balance();
4678            assert!(
4679                has_deposits(&pool_balance_of, &Default::default(), &ALPHA_POOL_DIGEST).is_ok()
4680            );
4681            assert_eq!(
4682                balance_total(&pool_balance_of, &Default::default(), &ALPHA_POOL_DIGEST).unwrap(),
4683                35
4684            );
4685            let actual_slots_value = Pallet::get_slots_value(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
4686            let expected_slots_value = vec![(ALPHA_ENTRY_DIGEST, 14), (BETA_ENTRY_DIGEST, 21)];
4687            assert_eq!(actual_slots_value, expected_slots_value);
4688            let reason_value = ReasonValue::get(STAKING).unwrap();
4689            assert_eq!(reason_value, 65); // 20 + 10 + 35
4690
4691            // Raise commit value
4692            assert_ok!(CommitHelper::raise_pool_commit(
4693                &ALICE,
4694                &STAKING,
4695                &ALPHA_POOL_DIGEST,
4696                20,
4697                &Directive::new(Precision::BestEffort, Fortitude::Polite)
4698            ));
4699            // // After raising the pool commit value
4700            let pool_info = PoolMap::get((STAKING, ALPHA_POOL_DIGEST)).unwrap();
4701            let pool_balance_of = pool_info.balance();
4702            assert!(
4703                has_deposits(&pool_balance_of, &Default::default(), &ALPHA_POOL_DIGEST).is_ok()
4704            );
4705            assert_eq!(
4706                balance_total(&pool_balance_of, &Default::default(), &ALPHA_POOL_DIGEST).unwrap(),
4707                55
4708            );
4709            let pool_capital = pool_info.capital();
4710            assert_eq!(pool_capital, 100);
4711            let actual_slots_value = Pallet::get_slots_value(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
4712            let expected_slots_value = vec![(ALPHA_ENTRY_DIGEST, 22), (BETA_ENTRY_DIGEST, 33)];
4713            assert_eq!(actual_slots_value, expected_slots_value);
4714            let reason_value = ReasonValue::get(STAKING).unwrap();
4715            assert_eq!(reason_value, 85);
4716            // new commit instance added
4717            let commit_info = CommitMap::get((ALICE, STAKING)).unwrap();
4718            let commits = commit_info.commits();
4719            let commit = commits.get(0).unwrap();
4720            assert_eq!(receipt_deposit_value(commit).unwrap(), 35);
4721            // raise commit instance is added
4722            let raise_commit = commits.get(1).unwrap();
4723            assert_eq!(receipt_deposit_value(raise_commit).unwrap(), 20);
4724        })
4725    }
4726
4727    #[test]
4728    fn raise_pool_commit_err_max_commits_reached() {
4729        commit_test_ext().execute_with(|| {
4730            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, 60).unwrap();
4731            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
4732            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
4733            Pallet::place_commit(
4734                &BOB,
4735                &STAKING,
4736                &ALPHA_ENTRY_DIGEST,
4737                LARGE_VALUE,
4738                &Directive::new(Precision::BestEffort, Fortitude::Polite),
4739            )
4740            .unwrap();
4741            Pallet::place_commit(
4742                &CHARLIE,
4743                &STAKING,
4744                &BETA_ENTRY_DIGEST,
4745                STANDARD_VALUE,
4746                &Directive::new(Precision::BestEffort, Fortitude::Polite),
4747            )
4748            .unwrap();
4749            let entries = vec![(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)];
4750            prepare_and_initiate_pool(
4751                ALICE,
4752                STAKING,
4753                &entries,
4754                ALPHA_INDEX_DIGEST,
4755                ALPHA_POOL_DIGEST,
4756                COMMISSION_ONE,
4757            )
4758            .unwrap();
4759            Pallet::place_commit(
4760                &ALICE,
4761                &STAKING,
4762                &ALPHA_POOL_DIGEST,
4763                35,
4764                &Directive::new(Precision::BestEffort, Fortitude::Polite),
4765            )
4766            .unwrap();
4767            // Raise commit value
4768            assert_ok!(CommitHelper::raise_pool_commit(
4769                &ALICE,
4770                &STAKING,
4771                &ALPHA_POOL_DIGEST,
4772                20,
4773                &Directive::new(Precision::BestEffort, Fortitude::Polite)
4774            ));
4775            assert_ok!(CommitHelper::raise_pool_commit(
4776                &ALICE,
4777                &STAKING,
4778                &ALPHA_POOL_DIGEST,
4779                5,
4780                &Directive::new(Precision::BestEffort, Fortitude::Polite)
4781            ));
4782            // new commit instance added
4783            let commit_info = CommitMap::get((ALICE, STAKING)).unwrap();
4784            let commits = commit_info.commits();
4785            let commit = commits.get(0).unwrap();
4786            assert_eq!(receipt_deposit_value(commit).unwrap(), 35);
4787            // raise commit instance is added
4788            let raise_commit = commits.get(1).unwrap();
4789            assert_eq!(receipt_deposit_value(raise_commit).unwrap(), 20);
4790            // raise commit instance is added
4791            let raise_commit = commits.get(2).unwrap();
4792            assert_eq!(receipt_deposit_value(raise_commit).unwrap(), 5);
4793            // since, the max commits allowed is set to 3, making an another raise commit will cause error
4794            assert_err!(
4795                CommitHelper::raise_pool_commit(
4796                    &ALICE,
4797                    &STAKING,
4798                    &ALPHA_POOL_DIGEST,
4799                    10,
4800                    &Directive::new(Precision::BestEffort, Fortitude::Force)
4801                ),
4802                Error::MaxCommitsReached
4803            );
4804        })
4805    }
4806
4807    #[test]
4808    fn resolve_commit_of_success_for_direct_digest_model() {
4809        commit_test_ext().execute_with(|| {
4810            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, STANDARD_VALUE).unwrap();
4811            Pallet::place_commit(
4812                &ALICE,
4813                &STAKING,
4814                &ALPHA_DIGEST,
4815                STANDARD_VALUE,
4816                &Directive::new(Precision::BestEffort, Fortitude::Polite),
4817            )
4818            .unwrap();
4819            // before resolving the commit
4820            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 0);
4821            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), STANDARD_VALUE);
4822            assert_eq!(AssetOf::balance(&ALICE), 20);
4823            let commit_value = Pallet::get_commit_value(&ALICE, &STAKING).unwrap();
4824            assert_eq!(commit_value, STANDARD_VALUE);
4825            let total_value = Pallet::get_total_value(&STAKING);
4826            assert_eq!(total_value, STANDARD_VALUE);
4827            // resolve commit
4828            assert_ok!(CommitHelper::resolve_commit_of(
4829                &ALICE,
4830                &STAKING,
4831                &DigestVariant::Direct(ALPHA_DIGEST)
4832            ));
4833            // after resolving the commit
4834            assert_eq!(AssetOf::balance(&ALICE), 30);
4835            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), 0);
4836            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 0);
4837            assert_err!(
4838                Pallet::commit_exists(&ALICE, &STAKING),
4839                Error::CommitNotFound
4840            );
4841            let digets_value = Pallet::get_digest_value(&STAKING, &ALPHA_DIGEST).unwrap();
4842            assert_eq!(digets_value, 0);
4843            let total_value = Pallet::get_total_value(&STAKING);
4844            assert_eq!(total_value, 0);
4845        })
4846    }
4847
4848    #[test]
4849    fn resolve_commit_of_success_for_index_digest_model() {
4850        commit_test_ext().execute_with(|| {
4851            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, 40).unwrap();
4852            initiate_digest_with_default_balance(STAKING, ALPHA_ENTRY_DIGEST).unwrap();
4853            initiate_digest_with_default_balance(STAKING, BETA_ENTRY_DIGEST).unwrap();
4854            prepare_and_initiate_index(
4855                ALICE,
4856                STAKING,
4857                &[(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)],
4858                ALPHA_INDEX_DIGEST,
4859            )
4860            .unwrap();
4861            Pallet::place_commit(
4862                &ALICE,
4863                &STAKING,
4864                &ALPHA_INDEX_DIGEST,
4865                35,
4866                &Directive::new(Precision::BestEffort, Fortitude::Polite),
4867            )
4868            .unwrap();
4869            assert_eq!(Pallet::get_commit_value(&ALICE, &STAKING), Ok(35));
4870            // before resolving the commit
4871            assert_eq!(
4872                Pallet::get_index_value(&STAKING, &ALPHA_INDEX_DIGEST),
4873                Ok(35)
4874            );
4875            let actual_entries_value =
4876                Pallet::get_entries_value(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
4877            let expected_entries_value = vec![(ALPHA_ENTRY_DIGEST, 14), (BETA_ENTRY_DIGEST, 21)];
4878            assert_eq!(actual_entries_value, expected_entries_value);
4879            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 5);
4880            assert_eq!(AssetOf::balance(&ALICE), LARGE_VALUE);
4881            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), 35);
4882            // resolve commit
4883            assert_ok!(CommitHelper::resolve_commit_of(
4884                &ALICE,
4885                &STAKING,
4886                &DigestVariant::Index(ALPHA_INDEX_DIGEST)
4887            ));
4888            // after resolving the commit
4889            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), 0);
4890            assert_eq!(AssetOf::balance(&ALICE), 55); // existing balance + resolved balance -> 20 + 35 = 55
4891            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 5);
4892            assert_err!(
4893                Pallet::commit_exists(&ALICE, &STAKING),
4894                Error::CommitNotFound
4895            );
4896            assert_eq!(
4897                Pallet::get_index_value(&STAKING, &ALPHA_INDEX_DIGEST),
4898                Ok(0)
4899            );
4900            let actual_entries_value =
4901                Pallet::get_entries_value(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
4902            let expected_entries_value = vec![(ALPHA_ENTRY_DIGEST, 0), (BETA_ENTRY_DIGEST, 0)];
4903            assert_eq!(actual_entries_value, expected_entries_value);
4904        })
4905    }
4906
4907    #[test]
4908    fn resolve_commit_of_success_for_pool_digest_model() {
4909        commit_test_ext().execute_with(|| {
4910            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, 40).unwrap();
4911            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
4912            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
4913            Pallet::place_commit(
4914                &BOB,
4915                &STAKING,
4916                &ALPHA_ENTRY_DIGEST,
4917                LARGE_VALUE,
4918                &Directive::new(Precision::BestEffort, Fortitude::Polite),
4919            )
4920            .unwrap();
4921            Pallet::place_commit(
4922                &CHARLIE,
4923                &STAKING,
4924                &BETA_ENTRY_DIGEST,
4925                STANDARD_VALUE,
4926                &Directive::new(Precision::BestEffort, Fortitude::Polite),
4927            )
4928            .unwrap();
4929            let entries = vec![(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)];
4930            prepare_and_initiate_pool(
4931                ALICE,
4932                STAKING,
4933                &entries,
4934                ALPHA_INDEX_DIGEST,
4935                ALPHA_POOL_DIGEST,
4936                COMMISSION_ZERO,
4937            )
4938            .unwrap();
4939            Pallet::place_commit(
4940                &ALICE,
4941                &STAKING,
4942                &ALPHA_POOL_DIGEST,
4943                30,
4944                &Directive::new(Precision::BestEffort, Fortitude::Polite),
4945            )
4946            .unwrap();
4947            // Before resolving the commit
4948            let pool_info = PoolMap::get((STAKING, ALPHA_POOL_DIGEST)).unwrap();
4949            let pool_balance_of = pool_info.balance();
4950            assert!(
4951                has_deposits(&pool_balance_of, &Default::default(), &ALPHA_POOL_DIGEST).is_ok()
4952            );
4953            assert_eq!(
4954                balance_total(&pool_balance_of, &Default::default(), &ALPHA_POOL_DIGEST).unwrap(),
4955                30
4956            );
4957            let pool_capital = pool_info.capital();
4958            assert_eq!(pool_capital, 100);
4959            let alpha_digets_balance =
4960                Pallet::get_slot_value(&STAKING, &ALPHA_POOL_DIGEST, &ALPHA_ENTRY_DIGEST).unwrap();
4961            assert_eq!(alpha_digets_balance, 12);
4962            let beta_digets_balance =
4963                Pallet::get_slot_value(&STAKING, &ALPHA_POOL_DIGEST, &BETA_ENTRY_DIGEST).unwrap();
4964            assert_eq!(beta_digets_balance, 18);
4965            let reason_value = ReasonValue::get(STAKING).unwrap();
4966            assert_eq!(reason_value, 60);
4967            // resolve the commit
4968            assert_ok!(CommitHelper::resolve_commit_of(
4969                &ALICE,
4970                &STAKING,
4971                &DigestVariant::Pool(ALPHA_POOL_DIGEST)
4972            ));
4973            // After resolving the commit
4974            let pool_info = PoolMap::get((STAKING, ALPHA_POOL_DIGEST)).unwrap();
4975            let pool_balance_of = pool_info.balance();
4976            assert!(
4977                has_deposits(&pool_balance_of, &Default::default(), &ALPHA_POOL_DIGEST).is_err()
4978            );
4979            assert_eq!(
4980                balance_total(&pool_balance_of, &Default::default(), &ALPHA_POOL_DIGEST).unwrap(),
4981                0
4982            );
4983            let pool_capital = pool_info.capital();
4984            assert_eq!(pool_capital, 100);
4985            let alpha_digets_balance =
4986                Pallet::get_slot_value(&STAKING, &ALPHA_POOL_DIGEST, &ALPHA_ENTRY_DIGEST).unwrap();
4987            assert_eq!(alpha_digets_balance, 0);
4988            let beta_digets_balance =
4989                Pallet::get_slot_value(&STAKING, &ALPHA_POOL_DIGEST, &BETA_ENTRY_DIGEST).unwrap();
4990            assert_eq!(beta_digets_balance, 0);
4991            let reason_value = ReasonValue::get(STAKING).unwrap();
4992            assert_eq!(reason_value, 30);
4993        })
4994    }
4995
4996    #[test]
4997    fn resolve_digest_commit_success() {
4998        commit_test_ext().execute_with(|| {
4999            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, STANDARD_VALUE).unwrap();
5000            Pallet::place_commit(
5001                &ALICE,
5002                &STAKING,
5003                &ALPHA_DIGEST,
5004                STANDARD_VALUE,
5005                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5006            )
5007            .unwrap();
5008            // before resolving the commit
5009            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 0);
5010            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), STANDARD_VALUE);
5011            assert_eq!(AssetOf::balance(&ALICE), 20);
5012            let commit_value = Pallet::get_commit_value(&ALICE, &STAKING).unwrap();
5013            assert_eq!(commit_value, STANDARD_VALUE);
5014            let total_value = Pallet::get_total_value(&STAKING);
5015            assert_eq!(total_value, STANDARD_VALUE);
5016            // resolve commit
5017            assert_ok!(CommitHelper::resolve_digest_commit(
5018                &ALICE,
5019                &STAKING,
5020                &ALPHA_DIGEST
5021            ));
5022            // after resolving the commit
5023            assert_eq!(AssetOf::balance(&ALICE), 30);
5024            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), 0);
5025            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 0);
5026            assert_err!(
5027                Pallet::commit_exists(&ALICE, &STAKING),
5028                Error::CommitNotFound
5029            );
5030            let digets_value = Pallet::get_digest_value(&STAKING, &ALPHA_DIGEST).unwrap();
5031            assert_eq!(digets_value, 0);
5032            let total_value = Pallet::get_total_value(&STAKING);
5033            assert_eq!(total_value, 0);
5034        })
5035    }
5036
5037    #[test]
5038    fn resolve_index_commit_success() {
5039        commit_test_ext().execute_with(|| {
5040            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, 40).unwrap();
5041            initiate_digest_with_default_balance(STAKING, ALPHA_ENTRY_DIGEST).unwrap();
5042            initiate_digest_with_default_balance(STAKING, BETA_ENTRY_DIGEST).unwrap();
5043            prepare_and_initiate_index(
5044                ALICE,
5045                STAKING,
5046                &[(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)],
5047                ALPHA_INDEX_DIGEST,
5048            )
5049            .unwrap();
5050            Pallet::place_commit(
5051                &ALICE,
5052                &STAKING,
5053                &ALPHA_INDEX_DIGEST,
5054                35,
5055                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5056            )
5057            .unwrap();
5058            assert_eq!(Pallet::get_commit_value(&ALICE, &STAKING), Ok(35));
5059            // before resolving the commit
5060            assert_eq!(
5061                Pallet::get_index_value(&STAKING, &ALPHA_INDEX_DIGEST),
5062                Ok(35)
5063            );
5064            let actual_entries_value =
5065                Pallet::get_entries_value(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
5066            let expected_entries_value = vec![(ALPHA_ENTRY_DIGEST, 14), (BETA_ENTRY_DIGEST, 21)];
5067            assert_eq!(actual_entries_value, expected_entries_value);
5068            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 5);
5069            assert_eq!(AssetOf::balance(&ALICE), LARGE_VALUE);
5070            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), 35);
5071            // resolve commit
5072            assert_ok!(CommitHelper::resolve_index_commit(
5073                &ALICE,
5074                &STAKING,
5075                &ALPHA_INDEX_DIGEST
5076            ));
5077            // after resolving the commit
5078            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), 0);
5079            assert_eq!(AssetOf::balance(&ALICE), 55); // existing balance + resolved balance -> 20 + 35 = 55
5080            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 5);
5081            assert_err!(
5082                Pallet::commit_exists(&ALICE, &STAKING),
5083                Error::CommitNotFound
5084            );
5085            assert_eq!(
5086                Pallet::get_index_value(&STAKING, &ALPHA_INDEX_DIGEST),
5087                Ok(0)
5088            );
5089            let actual_entries_value =
5090                Pallet::get_entries_value(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
5091            let expected_entries_value = vec![(ALPHA_ENTRY_DIGEST, 0), (BETA_ENTRY_DIGEST, 0)];
5092            assert_eq!(actual_entries_value, expected_entries_value);
5093        })
5094    }
5095
5096    #[test]
5097    fn resolve_pool_commit_success() {
5098        commit_test_ext().execute_with(|| {
5099            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, 40).unwrap();
5100            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
5101            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
5102            Pallet::place_commit(
5103                &BOB,
5104                &STAKING,
5105                &ALPHA_ENTRY_DIGEST,
5106                LARGE_VALUE,
5107                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5108            )
5109            .unwrap();
5110            Pallet::place_commit(
5111                &CHARLIE,
5112                &STAKING,
5113                &BETA_ENTRY_DIGEST,
5114                STANDARD_VALUE,
5115                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5116            )
5117            .unwrap();
5118            let entries = vec![(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)];
5119            prepare_and_initiate_pool(
5120                ALICE,
5121                STAKING,
5122                &entries,
5123                ALPHA_INDEX_DIGEST,
5124                ALPHA_POOL_DIGEST,
5125                COMMISSION_ZERO,
5126            )
5127            .unwrap();
5128            Pallet::place_commit(
5129                &ALICE,
5130                &STAKING,
5131                &ALPHA_POOL_DIGEST,
5132                30,
5133                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5134            )
5135            .unwrap();
5136            // Before resolving the commit
5137            let pool_info = PoolMap::get((STAKING, ALPHA_POOL_DIGEST)).unwrap();
5138            let pool_balance_of = pool_info.balance();
5139            assert!(
5140                has_deposits(&pool_balance_of, &Default::default(), &ALPHA_POOL_DIGEST).is_ok()
5141            );
5142            assert_eq!(
5143                balance_total(&pool_balance_of, &Default::default(), &ALPHA_POOL_DIGEST).unwrap(),
5144                30
5145            );
5146            let pool_capital = pool_info.capital();
5147            assert_eq!(pool_capital, 100);
5148            let alpha_digets_balance =
5149                Pallet::get_slot_value(&STAKING, &ALPHA_POOL_DIGEST, &ALPHA_ENTRY_DIGEST).unwrap();
5150            assert_eq!(alpha_digets_balance, 12);
5151            let beta_digets_balance =
5152                Pallet::get_slot_value(&STAKING, &ALPHA_POOL_DIGEST, &BETA_ENTRY_DIGEST).unwrap();
5153            assert_eq!(beta_digets_balance, 18);
5154            let reason_value = ReasonValue::get(STAKING).unwrap();
5155            assert_eq!(reason_value, 60);
5156            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), 30);
5157            assert_eq!(AssetOf::balance(&ALICE), 20); // existing balance + resolved balance -> 20 + 30 = 50
5158            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 10);
5159            // resolve the commit
5160            assert_ok!(CommitHelper::resolve_pool_commit(
5161                &ALICE,
5162                &STAKING,
5163                &ALPHA_POOL_DIGEST
5164            ));
5165            // After resolving the commit
5166            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), 0);
5167            assert_eq!(AssetOf::balance(&ALICE), 50); // existing balance + resolved balance -> 20 + 30 = 50
5168            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 10);
5169            let pool_info = PoolMap::get((STAKING, ALPHA_POOL_DIGEST)).unwrap();
5170            let pool_balance_of = pool_info.balance();
5171            assert!(
5172                has_deposits(&pool_balance_of, &Default::default(), &ALPHA_POOL_DIGEST).is_err()
5173            );
5174            assert_eq!(
5175                balance_total(&pool_balance_of, &Default::default(), &ALPHA_POOL_DIGEST).unwrap(),
5176                0
5177            );
5178            let pool_capital = pool_info.capital();
5179            assert_eq!(pool_capital, 100);
5180            let alpha_digets_balance =
5181                Pallet::get_slot_value(&STAKING, &ALPHA_POOL_DIGEST, &ALPHA_ENTRY_DIGEST).unwrap();
5182            assert_eq!(alpha_digets_balance, 0);
5183            let beta_digets_balance =
5184                Pallet::get_slot_value(&STAKING, &ALPHA_POOL_DIGEST, &BETA_ENTRY_DIGEST).unwrap();
5185            assert_eq!(beta_digets_balance, 0);
5186            let reason_value = ReasonValue::get(STAKING).unwrap();
5187            assert_eq!(reason_value, 30);
5188        })
5189    }
5190
5191    #[test]
5192    fn set_total_value_works() {
5193        commit_test_ext().execute_with(|| {
5194            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, STANDARD_VALUE).unwrap();
5195            Pallet::place_commit(
5196                &ALICE,
5197                &STAKING,
5198                &ALPHA_DIGEST,
5199                STANDARD_VALUE,
5200                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5201            )
5202            .unwrap();
5203
5204            let current_total_value = ReasonValue::get(STAKING).unwrap();
5205            assert_eq!(current_total_value, STANDARD_VALUE);
5206            // set new total value for staking reason
5207            let new_total_value = 40;
5208            CommitHelper::set_total_value(&STAKING, new_total_value);
5209            let current_total_value = ReasonValue::get(STAKING).unwrap();
5210            assert_eq!(current_total_value, new_total_value);
5211        })
5212    }
5213
5214    // ===============================================================================
5215    // ```````````````````````````````` COMMIT INSPECT ```````````````````````````````
5216    // ===============================================================================
5217
5218    #[test]
5219    fn commit_value_of_success_for_direct_digest_model() {
5220        commit_test_ext().execute_with(|| {
5221            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5222            Pallet::place_commit(
5223                &ALICE,
5224                &STAKING,
5225                &ALPHA_DIGEST,
5226                STANDARD_VALUE,
5227                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5228            )
5229            .unwrap();
5230            let digest_commit_value =
5231                CommitHelper::digest_commit_value(&ALICE, &STAKING, &ALPHA_DIGEST).unwrap();
5232            assert_eq!(digest_commit_value, STANDARD_VALUE);
5233            Pallet::raise_commit(
5234                &ALICE,
5235                &STAKING,
5236                STANDARD_VALUE,
5237                &Directive::new(Precision::BestEffort, Fortitude::Force),
5238            )
5239            .unwrap();
5240            // updated digest value after raise commit
5241            let digest_commit_value = CommitHelper::commit_value_of(
5242                &ALICE,
5243                &STAKING,
5244                &DigestVariant::Direct(ALPHA_DIGEST),
5245            )
5246            .unwrap();
5247            assert_eq!(digest_commit_value, 20);
5248        })
5249    }
5250
5251    #[test]
5252    fn commit_value_of_success_for_index_digest_model() {
5253        commit_test_ext().execute_with(|| {
5254            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, 30).unwrap();
5255            initiate_digest_with_default_balance(STAKING, ALPHA_ENTRY_DIGEST).unwrap();
5256            prepare_and_initiate_index(
5257                ALICE,
5258                STAKING,
5259                &[(ALPHA_ENTRY_DIGEST, 40)],
5260                ALPHA_INDEX_DIGEST,
5261            )
5262            .unwrap();
5263            assert_ok!(Pallet::index_exists(&STAKING, &ALPHA_INDEX_DIGEST));
5264            // Place commit to an index
5265            Pallet::place_commit(
5266                &ALICE,
5267                &STAKING,
5268                &ALPHA_INDEX_DIGEST,
5269                LARGE_VALUE,
5270                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5271            )
5272            .unwrap();
5273            let index_commit_value =
5274                CommitHelper::index_commit_value(&ALICE, &STAKING, &ALPHA_INDEX_DIGEST).unwrap();
5275            assert_eq!(index_commit_value, LARGE_VALUE);
5276            Pallet::raise_commit(
5277                &ALICE,
5278                &STAKING,
5279                STANDARD_VALUE,
5280                &Directive::new(Precision::BestEffort, Fortitude::Force),
5281            )
5282            .unwrap();
5283            // updated digest value after raise commit
5284            let index_commit_value =
5285                CommitHelper::index_commit_value(&ALICE, &STAKING, &ALPHA_INDEX_DIGEST).unwrap();
5286            assert_eq!(index_commit_value, 30);
5287        })
5288    }
5289
5290    #[test]
5291    fn commit_value_of_success_for_pool_digest_model() {
5292        commit_test_ext().execute_with(|| {
5293            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, 40).unwrap();
5294            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
5295            Pallet::place_commit(
5296                &BOB,
5297                &STAKING,
5298                &ALPHA_ENTRY_DIGEST,
5299                LARGE_VALUE,
5300                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5301            )
5302            .unwrap();
5303            let entries = vec![(ALPHA_ENTRY_DIGEST, 40)];
5304            prepare_and_initiate_pool(
5305                ALICE,
5306                STAKING,
5307                &entries,
5308                ALPHA_INDEX_DIGEST,
5309                ALPHA_POOL_DIGEST,
5310                COMMISSION_ZERO,
5311            )
5312            .unwrap();
5313            Pallet::place_commit(
5314                &ALICE,
5315                &STAKING,
5316                &ALPHA_POOL_DIGEST,
5317                30,
5318                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5319            )
5320            .unwrap();
5321            let pool_commit_value =
5322                CommitHelper::pool_commit_value(&ALICE, &STAKING, &ALPHA_POOL_DIGEST).unwrap();
5323            assert_eq!(pool_commit_value, 30);
5324            Pallet::raise_commit(
5325                &ALICE,
5326                &STAKING,
5327                10,
5328                &Directive::new(Precision::BestEffort, Fortitude::Force),
5329            )
5330            .unwrap();
5331            // updated pool commit value after raise commit
5332            let pool_commit_value =
5333                CommitHelper::pool_commit_value(&ALICE, &STAKING, &ALPHA_POOL_DIGEST).unwrap();
5334            assert_eq!(pool_commit_value, 40);
5335        })
5336    }
5337
5338    #[test]
5339    fn digest_commit_value_success() {
5340        commit_test_ext().execute_with(|| {
5341            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5342            Pallet::place_commit(
5343                &ALICE,
5344                &STAKING,
5345                &ALPHA_DIGEST,
5346                STANDARD_VALUE,
5347                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5348            )
5349            .unwrap();
5350            let digest_commit_value =
5351                CommitHelper::digest_commit_value(&ALICE, &STAKING, &ALPHA_DIGEST).unwrap();
5352            assert_eq!(digest_commit_value, STANDARD_VALUE);
5353            Pallet::raise_commit(
5354                &ALICE,
5355                &STAKING,
5356                STANDARD_VALUE,
5357                &Directive::new(Precision::BestEffort, Fortitude::Force),
5358            )
5359            .unwrap();
5360            // updated digest value after raise commit
5361            let digest_commit_value =
5362                CommitHelper::digest_commit_value(&ALICE, &STAKING, &ALPHA_DIGEST).unwrap();
5363            assert_eq!(digest_commit_value, 20);
5364        })
5365    }
5366
5367    #[test]
5368    fn digest_commit_value_err_digest_not_found() {
5369        commit_test_ext().execute_with(|| {
5370            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5371            Pallet::place_commit(
5372                &ALICE,
5373                &STAKING,
5374                &ALPHA_DIGEST,
5375                STANDARD_VALUE,
5376                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5377            )
5378            .unwrap();
5379            assert_err!(
5380                CommitHelper::digest_commit_value(&ALICE, &STAKING, &BETA_DIGEST,),
5381                Error::DigestNotFound
5382            );
5383        })
5384    }
5385
5386    #[test]
5387    fn digest_commit_value_err_commit_not_found() {
5388        commit_test_ext().execute_with(|| {
5389            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5390            Pallet::place_commit(
5391                &ALICE,
5392                &STAKING,
5393                &ALPHA_DIGEST,
5394                STANDARD_VALUE,
5395                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5396            )
5397            .unwrap();
5398            assert_err!(
5399                CommitHelper::digest_commit_value(&BOB, &STAKING, &ALPHA_DIGEST,),
5400                Error::CommitNotFound
5401            );
5402        })
5403    }
5404
5405    #[test]
5406    fn index_commit_value_success() {
5407        commit_test_ext().execute_with(|| {
5408            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, 30).unwrap();
5409            initiate_digest_with_default_balance(STAKING, ALPHA_ENTRY_DIGEST).unwrap();
5410            prepare_and_initiate_index(
5411                ALICE,
5412                STAKING,
5413                &[(ALPHA_ENTRY_DIGEST, 40)],
5414                ALPHA_INDEX_DIGEST,
5415            )
5416            .unwrap();
5417            assert_ok!(Pallet::index_exists(&STAKING, &ALPHA_INDEX_DIGEST));
5418            // Place commit to an index
5419            Pallet::place_commit(
5420                &ALICE,
5421                &STAKING,
5422                &ALPHA_INDEX_DIGEST,
5423                LARGE_VALUE,
5424                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5425            )
5426            .unwrap();
5427            let index_commit_value =
5428                CommitHelper::index_commit_value(&ALICE, &STAKING, &ALPHA_INDEX_DIGEST).unwrap();
5429            assert_eq!(index_commit_value, LARGE_VALUE);
5430            Pallet::raise_commit(
5431                &ALICE,
5432                &STAKING,
5433                STANDARD_VALUE,
5434                &Directive::new(Precision::BestEffort, Fortitude::Force),
5435            )
5436            .unwrap();
5437            // updated digest value after raise commit
5438            let index_commit_value =
5439                CommitHelper::index_commit_value(&ALICE, &STAKING, &ALPHA_INDEX_DIGEST).unwrap();
5440            assert_eq!(index_commit_value, 30);
5441        })
5442    }
5443
5444    #[test]
5445    fn index_commit_value_err_commit_not_found() {
5446        commit_test_ext().execute_with(|| {
5447            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, 30).unwrap();
5448            initiate_digest_with_default_balance(STAKING, ALPHA_ENTRY_DIGEST).unwrap();
5449            prepare_and_initiate_index(
5450                ALICE,
5451                STAKING,
5452                &[(ALPHA_ENTRY_DIGEST, 40)],
5453                ALPHA_INDEX_DIGEST,
5454            )
5455            .unwrap();
5456            assert_ok!(Pallet::index_exists(&STAKING, &ALPHA_INDEX_DIGEST));
5457            // Place commit to an index
5458            Pallet::place_commit(
5459                &ALICE,
5460                &STAKING,
5461                &ALPHA_INDEX_DIGEST,
5462                LARGE_VALUE,
5463                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5464            )
5465            .unwrap();
5466            assert_err!(
5467                CommitHelper::index_commit_value(&BOB, &STAKING, &ALPHA_INDEX_DIGEST,),
5468                Error::CommitNotFoundForEntry
5469            );
5470        })
5471    }
5472
5473    #[test]
5474    fn index_entry_commit_value_success() {
5475        commit_test_ext().execute_with(|| {
5476            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5477            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
5478            initiate_digest_with_default_balance(STAKING, ALPHA_ENTRY_DIGEST).unwrap();
5479            initiate_digest_with_default_balance(STAKING, BETA_ENTRY_DIGEST).unwrap();
5480            prepare_and_initiate_index(
5481                ALICE,
5482                STAKING,
5483                &[(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)],
5484                ALPHA_INDEX_DIGEST,
5485            )
5486            .unwrap();
5487            assert_ok!(Pallet::index_exists(&STAKING, &ALPHA_INDEX_DIGEST));
5488            // Place commit to an index
5489            Pallet::place_commit(
5490                &ALICE,
5491                &STAKING,
5492                &ALPHA_INDEX_DIGEST,
5493                LARGE_VALUE,
5494                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5495            )
5496            .unwrap();
5497            Pallet::place_commit(
5498                &BOB,
5499                &STAKING,
5500                &ALPHA_INDEX_DIGEST,
5501                STANDARD_VALUE,
5502                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5503            )
5504            .unwrap();
5505            // alice index entry commit value inspect
5506            let entry_alpha_value = CommitHelper::index_entry_commit_value(
5507                &ALICE,
5508                &STAKING,
5509                &ALPHA_INDEX_DIGEST,
5510                &ALPHA_ENTRY_DIGEST,
5511            )
5512            .unwrap();
5513            let entry_beta_value = CommitHelper::index_entry_commit_value(
5514                &ALICE,
5515                &STAKING,
5516                &ALPHA_INDEX_DIGEST,
5517                &BETA_ENTRY_DIGEST,
5518            )
5519            .unwrap();
5520            assert_eq!(entry_alpha_value, 8);
5521            assert_eq!(entry_beta_value, 12);
5522
5523            // bob index entry commit value inspect
5524            let entry_alpha_value = CommitHelper::index_entry_commit_value(
5525                &BOB,
5526                &STAKING,
5527                &ALPHA_INDEX_DIGEST,
5528                &ALPHA_ENTRY_DIGEST,
5529            )
5530            .unwrap();
5531            let entry_beta_value = CommitHelper::index_entry_commit_value(
5532                &BOB,
5533                &STAKING,
5534                &ALPHA_INDEX_DIGEST,
5535                &BETA_ENTRY_DIGEST,
5536            )
5537            .unwrap();
5538            assert_eq!(entry_alpha_value, 4);
5539            assert_eq!(entry_beta_value, 6);
5540        })
5541    }
5542
5543    #[test]
5544    fn index_entry_commit_value_err_entry_not_found() {
5545        commit_test_ext().execute_with(|| {
5546            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5547            initiate_digest_with_default_balance(STAKING, ALPHA_ENTRY_DIGEST).unwrap();
5548            initiate_digest_with_default_balance(STAKING, BETA_ENTRY_DIGEST).unwrap();
5549            prepare_and_initiate_index(
5550                ALICE,
5551                STAKING,
5552                &[(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)],
5553                ALPHA_INDEX_DIGEST,
5554            )
5555            .unwrap();
5556            assert_ok!(Pallet::index_exists(&STAKING, &ALPHA_INDEX_DIGEST));
5557            // Place commit to an index
5558            Pallet::place_commit(
5559                &ALICE,
5560                &STAKING,
5561                &ALPHA_INDEX_DIGEST,
5562                LARGE_VALUE,
5563                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5564            )
5565            .unwrap();
5566            assert_err!(
5567                CommitHelper::index_entry_commit_value(
5568                    &ALICE,
5569                    &STAKING,
5570                    &ALPHA_INDEX_DIGEST,
5571                    &GAMMA_ENTRY_DIGEST,
5572                ),
5573                Error::EntryOfIndexNotFound
5574            );
5575        })
5576    }
5577
5578    #[test]
5579    fn index_entry_commit_value_err_commit_not_found_for_entry() {
5580        commit_test_ext().execute_with(|| {
5581            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5582            initiate_digest_with_default_balance(STAKING, ALPHA_ENTRY_DIGEST).unwrap();
5583            initiate_digest_with_default_balance(STAKING, BETA_ENTRY_DIGEST).unwrap();
5584            prepare_and_initiate_index(
5585                ALICE,
5586                STAKING,
5587                &[(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)],
5588                ALPHA_INDEX_DIGEST,
5589            )
5590            .unwrap();
5591            assert_ok!(Pallet::index_exists(&STAKING, &ALPHA_INDEX_DIGEST));
5592            // Place commit to an index
5593            Pallet::place_commit(
5594                &ALICE,
5595                &STAKING,
5596                &ALPHA_INDEX_DIGEST,
5597                LARGE_VALUE,
5598                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5599            )
5600            .unwrap();
5601            assert_err!(
5602                CommitHelper::index_entry_commit_value(
5603                    &BOB,
5604                    &STAKING,
5605                    &ALPHA_INDEX_DIGEST,
5606                    &ALPHA_ENTRY_DIGEST,
5607                ),
5608                Error::CommitNotFoundForEntry
5609            );
5610        })
5611    }
5612
5613    #[test]
5614    fn pool_commit_value_success() {
5615        commit_test_ext().execute_with(|| {
5616            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, 40).unwrap();
5617            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
5618            Pallet::place_commit(
5619                &BOB,
5620                &STAKING,
5621                &ALPHA_ENTRY_DIGEST,
5622                LARGE_VALUE,
5623                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5624            )
5625            .unwrap();
5626            let entries = vec![(ALPHA_ENTRY_DIGEST, 40)];
5627            prepare_and_initiate_pool(
5628                ALICE,
5629                STAKING,
5630                &entries,
5631                ALPHA_INDEX_DIGEST,
5632                ALPHA_POOL_DIGEST,
5633                COMMISSION_ZERO,
5634            )
5635            .unwrap();
5636            Pallet::place_commit(
5637                &ALICE,
5638                &STAKING,
5639                &ALPHA_POOL_DIGEST,
5640                30,
5641                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5642            )
5643            .unwrap();
5644            let pool_commit_value =
5645                CommitHelper::pool_commit_value(&ALICE, &STAKING, &ALPHA_POOL_DIGEST).unwrap();
5646            assert_eq!(pool_commit_value, 30);
5647            Pallet::raise_commit(
5648                &ALICE,
5649                &STAKING,
5650                10,
5651                &Directive::new(Precision::BestEffort, Fortitude::Force),
5652            )
5653            .unwrap();
5654            // updated pool commit value after raise commit
5655            let pool_commit_value =
5656                CommitHelper::pool_commit_value(&ALICE, &STAKING, &ALPHA_POOL_DIGEST).unwrap();
5657            assert_eq!(pool_commit_value, 40);
5658        })
5659    }
5660
5661    #[test]
5662    fn pool_commit_value_err_pool_not_found() {
5663        commit_test_ext().execute_with(|| {
5664            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, 40).unwrap();
5665            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
5666            Pallet::place_commit(
5667                &BOB,
5668                &STAKING,
5669                &ALPHA_ENTRY_DIGEST,
5670                LARGE_VALUE,
5671                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5672            )
5673            .unwrap();
5674            let entries = vec![(ALPHA_ENTRY_DIGEST, 40)];
5675            prepare_and_initiate_pool(
5676                ALICE,
5677                STAKING,
5678                &entries,
5679                ALPHA_INDEX_DIGEST,
5680                ALPHA_POOL_DIGEST,
5681                COMMISSION_ZERO,
5682            )
5683            .unwrap();
5684            Pallet::place_commit(
5685                &ALICE,
5686                &STAKING,
5687                &ALPHA_POOL_DIGEST,
5688                30,
5689                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5690            )
5691            .unwrap();
5692            assert_err!(
5693                CommitHelper::pool_commit_value(&ALICE, &STAKING, &BETA_POOL_DIGEST,),
5694                Error::PoolNotFound
5695            );
5696        })
5697    }
5698
5699    #[test]
5700    fn pool_commit_value_err_commit_not_found() {
5701        commit_test_ext().execute_with(|| {
5702            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, 40).unwrap();
5703            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
5704            Pallet::place_commit(
5705                &BOB,
5706                &STAKING,
5707                &ALPHA_ENTRY_DIGEST,
5708                LARGE_VALUE,
5709                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5710            )
5711            .unwrap();
5712            let entries = vec![(ALPHA_ENTRY_DIGEST, 40)];
5713            prepare_and_initiate_pool(
5714                ALICE,
5715                STAKING,
5716                &entries,
5717                ALPHA_INDEX_DIGEST,
5718                ALPHA_POOL_DIGEST,
5719                COMMISSION_ZERO,
5720            )
5721            .unwrap();
5722            Pallet::place_commit(
5723                &ALICE,
5724                &STAKING,
5725                &ALPHA_POOL_DIGEST,
5726                30,
5727                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5728            )
5729            .unwrap();
5730            assert_err!(
5731                CommitHelper::pool_commit_value(&ALICE, &GOVERNANCE, &ALPHA_POOL_DIGEST,),
5732                // new reason
5733                Error::PoolNotFound
5734            );
5735            assert_err!(
5736                CommitHelper::pool_commit_value(&BOB, &STAKING, &ALPHA_POOL_DIGEST,),
5737                Error::CommitNotFoundForPool
5738            );
5739        })
5740    }
5741
5742    #[test]
5743    fn pool_slot_value_success() {
5744        commit_test_ext().execute_with(|| {
5745            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, 40).unwrap();
5746            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
5747            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
5748            Pallet::place_commit(
5749                &BOB,
5750                &STAKING,
5751                &ALPHA_ENTRY_DIGEST,
5752                LARGE_VALUE,
5753                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5754            )
5755            .unwrap();
5756            Pallet::place_commit(
5757                &CHARLIE,
5758                &STAKING,
5759                &BETA_ENTRY_DIGEST,
5760                STANDARD_VALUE,
5761                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5762            )
5763            .unwrap();
5764            let entries = vec![(ALPHA_ENTRY_DIGEST, 30), (BETA_ENTRY_DIGEST, 70)];
5765            prepare_and_initiate_pool(
5766                ALICE,
5767                STAKING,
5768                &entries,
5769                ALPHA_INDEX_DIGEST,
5770                ALPHA_POOL_DIGEST,
5771                COMMISSION_ZERO,
5772            )
5773            .unwrap();
5774            Pallet::place_commit(
5775                &ALICE,
5776                &STAKING,
5777                &ALPHA_POOL_DIGEST,
5778                30,
5779                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5780            )
5781            .unwrap();
5782            // slot value inspect
5783            let slot_alpha_value =
5784                Pallet::get_slot_value(&STAKING, &ALPHA_POOL_DIGEST, &ALPHA_ENTRY_DIGEST).unwrap();
5785            let slot_beta_value =
5786                Pallet::get_slot_value(&STAKING, &ALPHA_POOL_DIGEST, &BETA_ENTRY_DIGEST).unwrap();
5787            assert_eq!(slot_alpha_value, 9);
5788            assert_eq!(slot_beta_value, 21);
5789        })
5790    }
5791
5792    #[test]
5793    fn pool_slot_value_err_slot_not_found() {
5794        commit_test_ext().execute_with(|| {
5795            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, 40).unwrap();
5796            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
5797            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
5798            Pallet::place_commit(
5799                &BOB,
5800                &STAKING,
5801                &ALPHA_ENTRY_DIGEST,
5802                LARGE_VALUE,
5803                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5804            )
5805            .unwrap();
5806            Pallet::place_commit(
5807                &CHARLIE,
5808                &STAKING,
5809                &BETA_ENTRY_DIGEST,
5810                STANDARD_VALUE,
5811                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5812            )
5813            .unwrap();
5814            let entries = vec![(ALPHA_ENTRY_DIGEST, 30), (BETA_ENTRY_DIGEST, 70)];
5815            prepare_and_initiate_pool(
5816                ALICE,
5817                STAKING,
5818                &entries,
5819                ALPHA_INDEX_DIGEST,
5820                ALPHA_POOL_DIGEST,
5821                COMMISSION_ZERO,
5822            )
5823            .unwrap();
5824            Pallet::place_commit(
5825                &ALICE,
5826                &STAKING,
5827                &ALPHA_POOL_DIGEST,
5828                30,
5829                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5830            )
5831            .unwrap();
5832            assert_err!(
5833                Pallet::get_slot_value(&STAKING, &ALPHA_POOL_DIGEST, &GAMMA_ENTRY_DIGEST,),
5834                Error::SlotOfPoolNotFound
5835            );
5836        })
5837    }
5838
5839    #[test]
5840    fn pool_slot_value_of_success() {
5841        commit_test_ext().execute_with(|| {
5842            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, 40).unwrap();
5843            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
5844            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
5845            initiate_key_and_set_balance_and_hold(MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
5846            Pallet::place_commit(
5847                &BOB,
5848                &STAKING,
5849                &ALPHA_ENTRY_DIGEST,
5850                LARGE_VALUE,
5851                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5852            )
5853            .unwrap();
5854            Pallet::place_commit(
5855                &CHARLIE,
5856                &STAKING,
5857                &BETA_ENTRY_DIGEST,
5858                STANDARD_VALUE,
5859                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5860            )
5861            .unwrap();
5862            let entries = vec![(ALPHA_ENTRY_DIGEST, 30), (BETA_ENTRY_DIGEST, 70)];
5863            prepare_and_initiate_pool(
5864                ALICE,
5865                STAKING,
5866                &entries,
5867                ALPHA_INDEX_DIGEST,
5868                ALPHA_POOL_DIGEST,
5869                COMMISSION_ZERO,
5870            )
5871            .unwrap();
5872            // place commits to pool
5873            Pallet::place_commit(
5874                &ALICE,
5875                &STAKING,
5876                &ALPHA_POOL_DIGEST,
5877                30,
5878                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5879            )
5880            .unwrap();
5881            Pallet::place_commit(
5882                &MIKE,
5883                &STAKING,
5884                &ALPHA_POOL_DIGEST,
5885                20,
5886                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5887            )
5888            .unwrap();
5889            // alice pool slots value
5890            let slot_alpha_value = CommitHelper::pool_slot_commit_value(
5891                &ALICE,
5892                &STAKING,
5893                &ALPHA_POOL_DIGEST,
5894                &ALPHA_ENTRY_DIGEST,
5895            )
5896            .unwrap();
5897            assert_eq!(slot_alpha_value, 9);
5898            let slot_beta_value = CommitHelper::pool_slot_commit_value(
5899                &ALICE,
5900                &STAKING,
5901                &ALPHA_POOL_DIGEST,
5902                &BETA_ENTRY_DIGEST,
5903            )
5904            .unwrap();
5905            assert_eq!(slot_beta_value, 21);
5906            // bob pool slots value
5907            let slot_alpha_value = CommitHelper::pool_slot_commit_value(
5908                &MIKE,
5909                &STAKING,
5910                &ALPHA_POOL_DIGEST,
5911                &ALPHA_ENTRY_DIGEST,
5912            )
5913            .unwrap();
5914            assert_eq!(slot_alpha_value, 6);
5915            let slot_beta_value = CommitHelper::pool_slot_commit_value(
5916                &MIKE,
5917                &STAKING,
5918                &ALPHA_POOL_DIGEST,
5919                &BETA_ENTRY_DIGEST,
5920            )
5921            .unwrap();
5922            assert_eq!(slot_beta_value, 14);
5923        })
5924    }
5925
5926    #[test]
5927    fn pool_slot_value_of_err_slot_not_found() {
5928        commit_test_ext().execute_with(|| {
5929            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, 40).unwrap();
5930            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
5931            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
5932            initiate_key_and_set_balance_and_hold(MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
5933            Pallet::place_commit(
5934                &BOB,
5935                &STAKING,
5936                &ALPHA_ENTRY_DIGEST,
5937                LARGE_VALUE,
5938                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5939            )
5940            .unwrap();
5941            Pallet::place_commit(
5942                &CHARLIE,
5943                &STAKING,
5944                &BETA_ENTRY_DIGEST,
5945                STANDARD_VALUE,
5946                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5947            )
5948            .unwrap();
5949            let entries = vec![(ALPHA_ENTRY_DIGEST, 30), (BETA_ENTRY_DIGEST, 70)];
5950            prepare_and_initiate_pool(
5951                ALICE,
5952                STAKING,
5953                &entries,
5954                ALPHA_INDEX_DIGEST,
5955                ALPHA_POOL_DIGEST,
5956                COMMISSION_ZERO,
5957            )
5958            .unwrap();
5959            // place commits to pool
5960            Pallet::place_commit(
5961                &ALICE,
5962                &STAKING,
5963                &ALPHA_POOL_DIGEST,
5964                30,
5965                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5966            )
5967            .unwrap();
5968            assert_err!(
5969                CommitHelper::pool_slot_commit_value(
5970                    &BOB,
5971                    &STAKING,
5972                    &ALPHA_POOL_DIGEST,
5973                    &GAMMA_ENTRY_DIGEST,
5974                ),
5975                Error::CommitNotFoundForPool
5976            );
5977            assert_err!(
5978                CommitHelper::pool_slot_commit_value(
5979                    &ALICE,
5980                    &STAKING,
5981                    &ALPHA_POOL_DIGEST,
5982                    &GAMMA_ENTRY_DIGEST,
5983                ),
5984                Error::SlotOfPoolNotFound
5985            );
5986        })
5987    }
5988
5989    #[test]
5990    fn value_of_success_for_reason() {
5991        commit_test_ext().execute_with(|| {
5992            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5993            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, 50).unwrap();
5994            initiate_digest_with_default_balance(STAKING, ALPHA_DIGEST).unwrap();
5995            initiate_digest_with_default_balance(STAKING, BETA_DIGEST).unwrap();
5996            initiate_digest_with_default_balance(GOVERNANCE, ALPHA_INDEX_DIGEST).unwrap();
5997            Pallet::place_commit(
5998                &ALICE,
5999                &STAKING,
6000                &ALPHA_DIGEST,
6001                10,
6002                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6003            )
6004            .unwrap();
6005            Pallet::place_commit(
6006                &ALICE,
6007                &GOVERNANCE,
6008                &ALPHA_INDEX_DIGEST,
6009                10,
6010                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6011            )
6012            .unwrap();
6013            Pallet::place_commit(
6014                &BOB,
6015                &STAKING,
6016                &BETA_INDEX_DIGEST,
6017                20,
6018                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6019            )
6020            .unwrap();
6021            // retrieve the total value of a reason
6022            let value_of_staking = CommitHelper::value_of(None, &STAKING).unwrap();
6023            let value_of_reason_bet = CommitHelper::value_of(None, &GOVERNANCE).unwrap();
6024            assert_eq!(value_of_staking, 30);
6025            assert_eq!(value_of_reason_bet, 10);
6026            Pallet::place_commit(
6027                &BOB,
6028                &GOVERNANCE,
6029                &BETA_INDEX_DIGEST,
6030                30,
6031                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6032            )
6033            .unwrap();
6034            // updated total value of a reason
6035            let value_of_reason_bet = CommitHelper::value_of(None, &GOVERNANCE).unwrap();
6036            assert_eq!(value_of_reason_bet, 40);
6037        })
6038    }
6039
6040    #[test]
6041    fn value_of_success_for_direct_digest_model() {
6042        commit_test_ext().execute_with(|| {
6043            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
6044            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
6045            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
6046            Pallet::place_commit_of_variant(
6047                &ALICE,
6048                &STAKING,
6049                &ALPHA_DIGEST,
6050                15,
6051                &Position::default(),
6052                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6053            )
6054            .unwrap();
6055            Pallet::place_commit_of_variant(
6056                &ALICE,
6057                &GOVERNANCE,
6058                &ALPHA_DIGEST,
6059                10,
6060                &Position::position_of(1).unwrap(),
6061                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6062            )
6063            .unwrap();
6064            Pallet::place_commit_of_variant(
6065                &CHARLIE,
6066                &STAKING,
6067                &ALPHA_DIGEST,
6068                5,
6069                &Position::default(),
6070                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6071            )
6072            .unwrap();
6073            // value of direct digest with staking reason
6074            let actual_direct_staking_value_of =
6075                CommitHelper::value_of(Some(&DigestVariant::Direct(ALPHA_DIGEST)), &STAKING)
6076                    .unwrap();
6077            let expected_direct_staking_value_of = 20; // 15 + 5
6078            assert_eq!(
6079                actual_direct_staking_value_of,
6080                expected_direct_staking_value_of
6081            );
6082            // value of direct digest with governance reason
6083            let actual_direct_bet_value_of =
6084                CommitHelper::value_of(Some(&DigestVariant::Direct(ALPHA_DIGEST)), &GOVERNANCE)
6085                    .unwrap();
6086            let expected_direct_bet_value_of = 10; // 10
6087            assert_eq!(actual_direct_bet_value_of, expected_direct_bet_value_of);
6088        })
6089    }
6090
6091    #[test]
6092    fn value_of_success_for_index_digest_model() {
6093        commit_test_ext().execute_with(|| {
6094            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, 40).unwrap();
6095            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, 50).unwrap();
6096            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, 30).unwrap();
6097            initiate_digest_with_default_balance(STAKING, ALPHA_ENTRY_DIGEST).unwrap();
6098            initiate_digest_with_default_balance(STAKING, BETA_ENTRY_DIGEST).unwrap();
6099            prepare_and_initiate_index(
6100                ALICE,
6101                STAKING,
6102                &[(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)],
6103                ALPHA_INDEX_DIGEST,
6104            )
6105            .unwrap();
6106            Pallet::place_commit(
6107                &ALICE,
6108                &STAKING,
6109                &ALPHA_INDEX_DIGEST,
6110                25,
6111                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6112            )
6113            .unwrap();
6114
6115            Pallet::place_commit(
6116                &BOB,
6117                &STAKING,
6118                &ALPHA_INDEX_DIGEST,
6119                35,
6120                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6121            )
6122            .unwrap();
6123
6124            Pallet::place_commit(
6125                &CHARLIE,
6126                &STAKING,
6127                &ALPHA_INDEX_DIGEST,
6128                25,
6129                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6130            )
6131            .unwrap();
6132
6133            // value of index digest with staking reason
6134            let actual_index_staking_value_of =
6135                CommitHelper::value_of(Some(&DigestVariant::Index(ALPHA_INDEX_DIGEST)), &STAKING)
6136                    .unwrap();
6137            let expected_index_staking_value_of = 85; // 25 + 35 + 25 -> 85
6138            assert_eq!(
6139                actual_index_staking_value_of,
6140                expected_index_staking_value_of
6141            );
6142        })
6143    }
6144
6145    #[test]
6146    fn value_of_success_for_pool_digest_model() {
6147        commit_test_ext().execute_with(|| {
6148            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, 40).unwrap();
6149            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
6150            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
6151            initiate_key_and_set_balance_and_hold(MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
6152            Pallet::place_commit(
6153                &BOB,
6154                &STAKING,
6155                &ALPHA_ENTRY_DIGEST,
6156                LARGE_VALUE,
6157                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6158            )
6159            .unwrap();
6160            let entries = vec![(ALPHA_ENTRY_DIGEST, 30)];
6161            prepare_and_initiate_pool(
6162                ALICE,
6163                STAKING,
6164                &entries,
6165                ALPHA_INDEX_DIGEST,
6166                ALPHA_POOL_DIGEST,
6167                COMMISSION_ZERO,
6168            )
6169            .unwrap();
6170            // place commits to pool
6171            Pallet::place_commit(
6172                &ALICE,
6173                &STAKING,
6174                &ALPHA_POOL_DIGEST,
6175                30,
6176                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6177            )
6178            .unwrap();
6179            Pallet::place_commit(
6180                &MIKE,
6181                &STAKING,
6182                &ALPHA_POOL_DIGEST,
6183                20,
6184                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6185            )
6186            .unwrap();
6187            Pallet::place_commit(
6188                &CHARLIE,
6189                &STAKING,
6190                &ALPHA_POOL_DIGEST,
6191                15,
6192                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6193            )
6194            .unwrap();
6195
6196            // value of pool digest with staking reason
6197            let actual_index_staking_value_of =
6198                CommitHelper::value_of(Some(&DigestVariant::Pool(ALPHA_POOL_DIGEST)), &STAKING)
6199                    .unwrap();
6200            let expected_index_staking_value_of = 65; // 30 + 20 + 15 -> 65
6201            assert_eq!(
6202                actual_index_staking_value_of,
6203                expected_index_staking_value_of
6204            );
6205        })
6206    }
6207
6208    // ===============================================================================
6209    // ```````````````````````````````` POOL OPERATIONS ``````````````````````````````
6210    // ===============================================================================
6211
6212    #[test]
6213    fn release_pool_success() {
6214        commit_test_ext().execute_with(|| {
6215            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, 40).unwrap();
6216            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
6217            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
6218            Pallet::place_commit(
6219                &BOB,
6220                &STAKING,
6221                &ALPHA_ENTRY_DIGEST,
6222                LARGE_VALUE,
6223                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6224            )
6225            .unwrap();
6226            Pallet::place_commit(
6227                &CHARLIE,
6228                &STAKING,
6229                &BETA_ENTRY_DIGEST,
6230                STANDARD_VALUE,
6231                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6232            )
6233            .unwrap();
6234            let entries = vec![(ALPHA_ENTRY_DIGEST, 30), (BETA_ENTRY_DIGEST, 70)];
6235            prepare_and_initiate_pool(
6236                ALICE,
6237                STAKING,
6238                &entries,
6239                ALPHA_INDEX_DIGEST,
6240                ALPHA_POOL_DIGEST,
6241                COMMISSION_ZERO,
6242            )
6243            .unwrap();
6244            Pallet::place_commit(
6245                &ALICE,
6246                &STAKING,
6247                &ALPHA_POOL_DIGEST,
6248                30,
6249                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6250            )
6251            .unwrap();
6252            // Balance inspect before releasing the pool
6253            let pool_info = PoolMap::get((STAKING, ALPHA_POOL_DIGEST)).unwrap();
6254            let pool_balance = pool_info.balance();
6255            assert!(has_deposits(&pool_balance, &Default::default(), &ALPHA_POOL_DIGEST).is_ok());
6256            assert_eq!(
6257                balance_total(&pool_balance, &Default::default(), &ALPHA_POOL_DIGEST).unwrap(),
6258                30
6259            );
6260            let actual_slots_balance_before =
6261                Pallet::get_slots_value(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
6262            let expected_slots_balance_before =
6263                vec![(ALPHA_ENTRY_DIGEST, 9), (BETA_ENTRY_DIGEST, 21)];
6264            assert_eq!(actual_slots_balance_before, expected_slots_balance_before);
6265            // Releasing the pool
6266            let released_pool_balance =
6267                CommitHelper::release_pool(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
6268
6269            // Released LazyBalance inspect
6270            assert!(has_deposits(
6271                &released_pool_balance,
6272                &Default::default(),
6273                &ALPHA_POOL_DIGEST
6274            )
6275            .is_ok());
6276            assert_eq!(
6277                balance_total(
6278                    &released_pool_balance,
6279                    &Default::default(),
6280                    &ALPHA_POOL_DIGEST
6281                )
6282                .unwrap(),
6283                30
6284            );
6285
6286            // Balance inspect after releasing the pool
6287            let pool_info = PoolMap::get((STAKING, ALPHA_POOL_DIGEST)).unwrap();
6288            let pool_balance = pool_info.balance();
6289            assert!(has_deposits(&pool_balance, &Default::default(), &ALPHA_POOL_DIGEST).is_err());
6290            assert_eq!(
6291                balance_total(&pool_balance, &Default::default(), &ALPHA_POOL_DIGEST).unwrap(),
6292                0
6293            );
6294            let actual_slots_balance_after =
6295                Pallet::get_slots_value(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
6296            let expected_slots_balance_after =
6297                vec![(ALPHA_ENTRY_DIGEST, 0), (BETA_ENTRY_DIGEST, 0)];
6298            assert_eq!(actual_slots_balance_after, expected_slots_balance_after);
6299        })
6300    }
6301
6302    #[test]
6303    fn release_pool_success_with_default_balance() {
6304        commit_test_ext().execute_with(|| {
6305            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, 40).unwrap();
6306            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
6307            Pallet::place_commit(
6308                &BOB,
6309                &STAKING,
6310                &ALPHA_ENTRY_DIGEST,
6311                LARGE_VALUE,
6312                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6313            )
6314            .unwrap();
6315            let try_zeroed_entries = vec![(ALPHA_ENTRY_DIGEST, 0)];
6316            let actual_entries = vec![(ALPHA_ENTRY_DIGEST, 15)];
6317            // Shares cannot be zero else rejected and error returned
6318            assert!(prepare_and_initiate_pool(
6319                ALICE,
6320                STAKING,
6321                &try_zeroed_entries,
6322                ALPHA_INDEX_DIGEST,
6323                ALPHA_POOL_DIGEST,
6324                COMMISSION_ZERO,
6325            )
6326            .is_err());
6327            prepare_and_initiate_pool(
6328                ALICE,
6329                STAKING,
6330                &actual_entries,
6331                ALPHA_INDEX_DIGEST,
6332                ALPHA_POOL_DIGEST,
6333                COMMISSION_ZERO,
6334            )
6335            .unwrap();
6336            // Releasing the pool returns the default LazyBalanceOf, since no commits to the pool yet.
6337            let pool_released_balance_of =
6338                CommitHelper::release_pool(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
6339            assert_eq!(LazyBalance::default(), pool_released_balance_of);
6340        })
6341    }
6342
6343    #[test]
6344    fn release_pool_err_pool_not_found() {
6345        commit_test_ext().execute_with(|| {
6346            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, 40).unwrap();
6347            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
6348            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
6349            Pallet::place_commit(
6350                &BOB,
6351                &STAKING,
6352                &ALPHA_ENTRY_DIGEST,
6353                LARGE_VALUE,
6354                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6355            )
6356            .unwrap();
6357            Pallet::place_commit(
6358                &CHARLIE,
6359                &STAKING,
6360                &BETA_ENTRY_DIGEST,
6361                STANDARD_VALUE,
6362                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6363            )
6364            .unwrap();
6365            let entries = vec![(ALPHA_ENTRY_DIGEST, 30), (BETA_ENTRY_DIGEST, 70)];
6366            prepare_and_initiate_pool(
6367                ALICE,
6368                STAKING,
6369                &entries,
6370                ALPHA_INDEX_DIGEST,
6371                ALPHA_POOL_DIGEST,
6372                COMMISSION_ZERO,
6373            )
6374            .unwrap();
6375            Pallet::place_commit(
6376                &ALICE,
6377                &STAKING,
6378                &ALPHA_POOL_DIGEST,
6379                30,
6380                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6381            )
6382            .unwrap();
6383            assert_err!(
6384                CommitHelper::release_pool(&STAKING, &BETA_POOL_DIGEST),
6385                Error::PoolNotFound
6386            );
6387        })
6388    }
6389
6390    #[test]
6391    fn recover_pool_success() {
6392        commit_test_ext().execute_with(|| {
6393            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
6394            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
6395            Pallet::place_commit(
6396                &ALICE,
6397                &STAKING,
6398                &ALPHA_ENTRY_DIGEST,
6399                LARGE_VALUE,
6400                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6401            )
6402            .unwrap();
6403            Pallet::place_commit(
6404                &BOB,
6405                &STAKING,
6406                &BETA_ENTRY_DIGEST,
6407                LARGE_VALUE,
6408                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6409            )
6410            .unwrap();
6411            let entries = vec![(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)];
6412            prepare_and_initiate_pool(
6413                ALICE,
6414                STAKING,
6415                &entries,
6416                ALPHA_INDEX_DIGEST,
6417                ALPHA_POOL_DIGEST,
6418                COMMISSION_ZERO,
6419            )
6420            .unwrap();
6421            let pool_info = PoolMap::get((STAKING, ALPHA_POOL_DIGEST)).unwrap();
6422            let pool_balance = pool_info.balance();
6423            assert!(has_deposits(&pool_balance, &Default::default(), &ALPHA_POOL_DIGEST).is_err());
6424            assert_eq!(
6425                balance_total(&pool_balance, &Default::default(), &ALPHA_POOL_DIGEST).unwrap(),
6426                0
6427            );
6428            assert_eq!(pool_balance, LazyBalance::default());
6429
6430            let mut balance = LazyBalance::default();
6431            let (_, receipt) = deposit(
6432                &mut balance,
6433                &Default::default(),
6434                &ALPHA_POOL_DIGEST,
6435                &LARGE_VALUE,
6436                &Default::default(),
6437            )
6438            .unwrap();
6439            assert_eq!(receipt_deposit_value(&receipt).unwrap(), LARGE_VALUE);
6440            assert!(has_deposits(&balance, &Default::default(), &ALPHA_POOL_DIGEST).is_ok());
6441            assert_eq!(
6442                balance_total(&balance, &Default::default(), &ALPHA_POOL_DIGEST).unwrap(),
6443                20
6444            );
6445
6446            // Recover the pool with the defined LazyBalance
6447            assert_ok!(CommitHelper::recover_pool(
6448                &STAKING,
6449                &ALPHA_POOL_DIGEST,
6450                &balance
6451            ));
6452
6453            // balance is recovered
6454            let pool_info = PoolMap::get((STAKING, ALPHA_POOL_DIGEST)).unwrap();
6455            let pool_balance = pool_info.balance();
6456            assert!(has_deposits(&pool_balance, &Default::default(), &ALPHA_POOL_DIGEST).is_ok());
6457            assert_eq!(
6458                balance_total(&pool_balance, &Default::default(), &ALPHA_POOL_DIGEST).unwrap(),
6459                20
6460            );
6461            assert_eq!(pool_balance, balance);
6462        })
6463    }
6464
6465    #[test]
6466    fn recover_pool_err_pool_not_found() {
6467        commit_test_ext().execute_with(|| {
6468            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
6469            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
6470            Pallet::place_commit(
6471                &ALICE,
6472                &STAKING,
6473                &ALPHA_ENTRY_DIGEST,
6474                LARGE_VALUE,
6475                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6476            )
6477            .unwrap();
6478            Pallet::place_commit(
6479                &BOB,
6480                &STAKING,
6481                &BETA_ENTRY_DIGEST,
6482                LARGE_VALUE,
6483                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6484            )
6485            .unwrap();
6486            let entries = vec![(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)];
6487            prepare_and_initiate_pool(
6488                ALICE,
6489                STAKING,
6490                &entries,
6491                ALPHA_INDEX_DIGEST,
6492                ALPHA_POOL_DIGEST,
6493                COMMISSION_ZERO,
6494            )
6495            .unwrap();
6496            let pool_info = PoolMap::get((STAKING, ALPHA_POOL_DIGEST)).unwrap();
6497            let pool_balance = pool_info.balance();
6498            assert!(has_deposits(&pool_balance, &Default::default(), &ALPHA_POOL_DIGEST).is_err());
6499            assert_eq!(
6500                balance_total(&pool_balance, &Default::default(), &ALPHA_POOL_DIGEST).unwrap(),
6501                0
6502            );
6503            assert_eq!(pool_balance, LazyBalance::default());
6504
6505            let mut balance = LazyBalance::default();
6506            let (_, receipt) = deposit(
6507                &mut balance,
6508                &Default::default(),
6509                &ALPHA_POOL_DIGEST,
6510                &LARGE_VALUE,
6511                &Default::default(),
6512            )
6513            .unwrap();
6514            assert_eq!(receipt_deposit_value(&receipt).unwrap(), LARGE_VALUE);
6515            assert!(has_deposits(&balance, &Default::default(), &ALPHA_POOL_DIGEST).is_ok());
6516            assert_eq!(
6517                balance_total(&balance, &Default::default(), &ALPHA_POOL_DIGEST).unwrap(),
6518                20
6519            );
6520
6521            assert_err!(
6522                CommitHelper::recover_pool(&STAKING, &BETA_POOL_DIGEST, &balance),
6523                Error::PoolNotFound
6524            );
6525        })
6526    }
6527
6528    #[test]
6529    fn recover_pool_err_release_pool_to_recover() {
6530        commit_test_ext().execute_with(|| {
6531            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
6532            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
6533            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
6534            Pallet::place_commit(
6535                &ALICE,
6536                &STAKING,
6537                &ALPHA_ENTRY_DIGEST,
6538                LARGE_VALUE,
6539                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6540            )
6541            .unwrap();
6542            Pallet::place_commit(
6543                &BOB,
6544                &STAKING,
6545                &BETA_ENTRY_DIGEST,
6546                LARGE_VALUE,
6547                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6548            )
6549            .unwrap();
6550            let entries = vec![(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)];
6551            prepare_and_initiate_pool(
6552                ALICE,
6553                STAKING,
6554                &entries,
6555                ALPHA_INDEX_DIGEST,
6556                ALPHA_POOL_DIGEST,
6557                COMMISSION_ZERO,
6558            )
6559            .unwrap();
6560            Pallet::place_commit(
6561                &CHARLIE,
6562                &STAKING,
6563                &ALPHA_POOL_DIGEST,
6564                LARGE_VALUE,
6565                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6566            )
6567            .unwrap();
6568            let pool_info = PoolMap::get((STAKING, ALPHA_POOL_DIGEST)).unwrap();
6569            let pool_balance = pool_info.balance();
6570            assert!(has_deposits(&pool_balance, &Default::default(), &ALPHA_POOL_DIGEST).is_ok());
6571            assert_eq!(
6572                balance_total(&pool_balance, &Default::default(), &ALPHA_POOL_DIGEST).unwrap(),
6573                20
6574            );
6575            assert_ne!(pool_balance, LazyBalance::default());
6576
6577            let mut balance = LazyBalance::default();
6578            let (_, receipt) = deposit(
6579                &mut balance,
6580                &Default::default(),
6581                &ALPHA_POOL_DIGEST,
6582                &LARGE_VALUE,
6583                &Default::default(),
6584            )
6585            .unwrap();
6586            assert_eq!(receipt_deposit_value(&receipt).unwrap(), LARGE_VALUE);
6587            assert!(has_deposits(&balance, &Default::default(), &ALPHA_POOL_DIGEST).is_ok());
6588            assert_eq!(
6589                balance_total(&balance, &Default::default(), &ALPHA_POOL_DIGEST).unwrap(),
6590                20
6591            );
6592
6593            assert_debug_panic_or_err!(
6594                CommitHelper::recover_pool(&STAKING, &ALPHA_POOL_DIGEST, &balance,),
6595                Error::ReleasePoolToRecover
6596            )
6597        })
6598    }
6599
6600    #[test]
6601    fn remove_pool_slot_success() {
6602        commit_test_ext().execute_with(|| {
6603            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
6604            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
6605            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, STANDARD_VALUE).unwrap();
6606            Pallet::place_commit(
6607                &ALICE,
6608                &STAKING,
6609                &ALPHA_ENTRY_DIGEST,
6610                LARGE_VALUE,
6611                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6612            )
6613            .unwrap();
6614            Pallet::place_commit(
6615                &BOB,
6616                &STAKING,
6617                &BETA_ENTRY_DIGEST,
6618                LARGE_VALUE,
6619                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6620            )
6621            .unwrap();
6622            let entries = vec![(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)];
6623            prepare_and_initiate_pool(
6624                ALICE,
6625                STAKING,
6626                &entries,
6627                ALPHA_INDEX_DIGEST,
6628                ALPHA_POOL_DIGEST,
6629                COMMISSION_ZERO,
6630            )
6631            .unwrap();
6632            Pallet::place_commit(
6633                &CHARLIE,
6634                &STAKING,
6635                &ALPHA_POOL_DIGEST,
6636                20,
6637                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6638            )
6639            .unwrap();
6640            // Inspecting the pool stots before removal of a slot
6641            let pool_slots_before = Pallet::get_slots_value(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
6642            let expected_pool_slots_before = vec![(ALPHA_ENTRY_DIGEST, 8), (BETA_ENTRY_DIGEST, 12)];
6643            assert_eq!(expected_pool_slots_before, pool_slots_before);
6644            // Remove a slot
6645            assert_ok!(CommitHelper::remove_pool_slot(
6646                &CHARLIE,
6647                &STAKING,
6648                &ALPHA_POOL_DIGEST,
6649                &ALPHA_ENTRY_DIGEST
6650            ));
6651            // Inspecting the pool stots after removal of a slot
6652            let pool_slots_before = Pallet::get_slots_value(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
6653            let expected_pool_slots_before = vec![(BETA_ENTRY_DIGEST, 20)];
6654            assert_eq!(expected_pool_slots_before, pool_slots_before);
6655        })
6656    }
6657
6658    #[test]
6659    fn remove_pool_slot_err_pool_not_found() {
6660        commit_test_ext().execute_with(|| {
6661            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
6662            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
6663            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, STANDARD_VALUE).unwrap();
6664            Pallet::place_commit(
6665                &ALICE,
6666                &STAKING,
6667                &ALPHA_ENTRY_DIGEST,
6668                LARGE_VALUE,
6669                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6670            )
6671            .unwrap();
6672            Pallet::place_commit(
6673                &BOB,
6674                &STAKING,
6675                &BETA_ENTRY_DIGEST,
6676                LARGE_VALUE,
6677                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6678            )
6679            .unwrap();
6680            let entries = vec![(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)];
6681            prepare_and_initiate_pool(
6682                ALICE,
6683                STAKING,
6684                &entries,
6685                ALPHA_INDEX_DIGEST,
6686                ALPHA_POOL_DIGEST,
6687                COMMISSION_ZERO,
6688            )
6689            .unwrap();
6690            Pallet::place_commit(
6691                &CHARLIE,
6692                &STAKING,
6693                &ALPHA_POOL_DIGEST,
6694                20,
6695                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6696            )
6697            .unwrap();
6698
6699            assert_err!(
6700                CommitHelper::remove_pool_slot(
6701                    &CHARLIE,
6702                    &STAKING,
6703                    &BETA_POOL_DIGEST,
6704                    &ALPHA_ENTRY_DIGEST
6705                ),
6706                Error::PoolNotFound
6707            );
6708        })
6709    }
6710
6711    #[test]
6712    fn set_pool_slot_success_mutating() {
6713        commit_test_ext().execute_with(|| {
6714            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
6715            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
6716            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, STANDARD_VALUE).unwrap();
6717            Pallet::place_commit(
6718                &ALICE,
6719                &STAKING,
6720                &ALPHA_ENTRY_DIGEST,
6721                LARGE_VALUE,
6722                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6723            )
6724            .unwrap();
6725            Pallet::place_commit(
6726                &BOB,
6727                &STAKING,
6728                &BETA_ENTRY_DIGEST,
6729                LARGE_VALUE,
6730                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6731            )
6732            .unwrap();
6733            let entries = vec![(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)];
6734            prepare_and_initiate_pool(
6735                ALICE,
6736                STAKING,
6737                &entries,
6738                ALPHA_INDEX_DIGEST,
6739                ALPHA_POOL_DIGEST,
6740                COMMISSION_ZERO,
6741            )
6742            .unwrap();
6743            Pallet::place_commit(
6744                &CHARLIE,
6745                &STAKING,
6746                &ALPHA_POOL_DIGEST,
6747                20,
6748                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6749            )
6750            .unwrap();
6751            // Inspecting the pool stots before mutating a pool slots
6752            let actual_slots_shares_before =
6753                Pallet::get_slots_shares(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
6754            let expected_slots_shares_before =
6755                vec![(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)];
6756            assert_eq!(actual_slots_shares_before, expected_slots_shares_before);
6757            let actual_slots_value_before =
6758                Pallet::get_slots_value(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
6759            let expected_slots_value_before =
6760                vec![(ALPHA_ENTRY_DIGEST, 8), (BETA_ENTRY_DIGEST, 12)];
6761            assert_eq!(actual_slots_value_before, expected_slots_value_before);
6762            let alpha_slot_variant =
6763                Pallet::get_slot_variant(&STAKING, &ALPHA_POOL_DIGEST, &ALPHA_ENTRY_DIGEST)
6764                    .unwrap();
6765            assert_eq!(alpha_slot_variant, Position::default());
6766            // Mutating the pool slot shares and variant
6767            assert_ok!(CommitHelper::set_pool_slot(
6768                &CHARLIE,
6769                &STAKING,
6770                &ALPHA_POOL_DIGEST,
6771                &ALPHA_ENTRY_DIGEST,
6772                60,
6773                &Position::position_of(1).unwrap()
6774            ));
6775            // Inspecting the pool stots after mutating a pool slots
6776            let actual_slots_shares_after =
6777                Pallet::get_slots_shares(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
6778            let expected_slots_shares_after =
6779                vec![(BETA_ENTRY_DIGEST, 60), (ALPHA_ENTRY_DIGEST, 60)];
6780            assert_eq!(actual_slots_shares_after, expected_slots_shares_after);
6781            let actual_slots_value_after =
6782                Pallet::get_slots_value(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
6783            let expected_slots_value_after =
6784                vec![(BETA_ENTRY_DIGEST, 10), (ALPHA_ENTRY_DIGEST, 10)];
6785            assert_eq!(actual_slots_value_after, expected_slots_value_after);
6786            let alpha_slot_variant =
6787                Pallet::get_slot_variant(&STAKING, &ALPHA_POOL_DIGEST, &ALPHA_ENTRY_DIGEST)
6788                    .unwrap();
6789            assert_eq!(alpha_slot_variant, Position::position_of(1).unwrap());
6790        })
6791    }
6792
6793    #[test]
6794    fn set_pool_slot_success_inserting() {
6795        commit_test_ext().execute_with(|| {
6796            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
6797            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
6798            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, STANDARD_VALUE).unwrap();
6799            initiate_key_and_set_balance_and_hold(MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
6800            Pallet::place_commit(
6801                &ALICE,
6802                &STAKING,
6803                &ALPHA_ENTRY_DIGEST,
6804                LARGE_VALUE,
6805                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6806            )
6807            .unwrap();
6808            Pallet::place_commit(
6809                &BOB,
6810                &STAKING,
6811                &BETA_ENTRY_DIGEST,
6812                LARGE_VALUE,
6813                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6814            )
6815            .unwrap();
6816            Pallet::place_commit(
6817                &MIKE,
6818                &STAKING,
6819                &GAMMA_ENTRY_DIGEST,
6820                STANDARD_VALUE,
6821                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6822            )
6823            .unwrap();
6824            let entries = vec![(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)];
6825            prepare_and_initiate_pool(
6826                ALICE,
6827                STAKING,
6828                &entries,
6829                ALPHA_INDEX_DIGEST,
6830                ALPHA_POOL_DIGEST,
6831                COMMISSION_ZERO,
6832            )
6833            .unwrap();
6834            Pallet::place_commit(
6835                &CHARLIE,
6836                &STAKING,
6837                &ALPHA_POOL_DIGEST,
6838                20,
6839                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6840            )
6841            .unwrap();
6842            // Inspecting the pool stots before mutating a pool slots
6843            let actual_slots_shares_before =
6844                Pallet::get_slots_shares(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
6845            let expected_slots_shares_before =
6846                vec![(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)];
6847            assert_eq!(actual_slots_shares_before, expected_slots_shares_before);
6848            let actual_slots_value_before =
6849                Pallet::get_slots_value(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
6850            let expected_slots_value_before =
6851                vec![(ALPHA_ENTRY_DIGEST, 8), (BETA_ENTRY_DIGEST, 12)];
6852            assert_eq!(actual_slots_value_before, expected_slots_value_before);
6853            let alpha_slot_variant =
6854                Pallet::get_slot_variant(&STAKING, &ALPHA_POOL_DIGEST, &ALPHA_ENTRY_DIGEST)
6855                    .unwrap();
6856            assert_eq!(alpha_slot_variant, Position::default());
6857            // Inserting a new slot
6858            assert_ok!(CommitHelper::set_pool_slot(
6859                &CHARLIE,
6860                &STAKING,
6861                &ALPHA_POOL_DIGEST,
6862                &GAMMA_ENTRY_DIGEST,
6863                20,
6864                &Position::position_of(1).unwrap()
6865            ));
6866            // Inspecting the pool stots after mutating a pool slots
6867            let actual_slots_shares_after =
6868                Pallet::get_slots_shares(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
6869            let expected_slots_shares_after = vec![
6870                (ALPHA_ENTRY_DIGEST, 40),
6871                (BETA_ENTRY_DIGEST, 60),
6872                (GAMMA_ENTRY_DIGEST, 20),
6873            ];
6874            assert_eq!(actual_slots_shares_after, expected_slots_shares_after);
6875            let actual_slots_value_after =
6876                Pallet::get_slots_value(&STAKING, &ALPHA_POOL_DIGEST).unwrap();
6877            let expected_slots_value_after = vec![
6878                (ALPHA_ENTRY_DIGEST, 6),
6879                (BETA_ENTRY_DIGEST, 10),
6880                (GAMMA_ENTRY_DIGEST, 3),
6881            ];
6882            assert_eq!(actual_slots_value_after, expected_slots_value_after);
6883        })
6884    }
6885
6886    #[test]
6887    fn set_pool_slot_err_pool_not_found() {
6888        commit_test_ext().execute_with(|| {
6889            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
6890            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
6891            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, STANDARD_VALUE).unwrap();
6892            Pallet::place_commit(
6893                &ALICE,
6894                &STAKING,
6895                &ALPHA_ENTRY_DIGEST,
6896                LARGE_VALUE,
6897                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6898            )
6899            .unwrap();
6900            Pallet::place_commit(
6901                &BOB,
6902                &STAKING,
6903                &BETA_ENTRY_DIGEST,
6904                LARGE_VALUE,
6905                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6906            )
6907            .unwrap();
6908            let entries = vec![(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)];
6909            prepare_and_initiate_pool(
6910                ALICE,
6911                STAKING,
6912                &entries,
6913                ALPHA_INDEX_DIGEST,
6914                ALPHA_POOL_DIGEST,
6915                COMMISSION_ZERO,
6916            )
6917            .unwrap();
6918            Pallet::place_commit(
6919                &CHARLIE,
6920                &STAKING,
6921                &ALPHA_POOL_DIGEST,
6922                20,
6923                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6924            )
6925            .unwrap();
6926
6927            assert_err!(
6928                CommitHelper::set_pool_slot(
6929                    &CHARLIE,
6930                    &STAKING,
6931                    &BETA_POOL_DIGEST,
6932                    &GAMMA_ENTRY_DIGEST,
6933                    20,
6934                    &Position::position_of(1).unwrap()
6935                ),
6936                Error::PoolNotFound
6937            );
6938        })
6939    }
6940
6941    #[test]
6942    fn set_pool_slot_err_max_slots_reached() {
6943        commit_test_ext().execute_with(|| {
6944            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
6945            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
6946            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, STANDARD_VALUE).unwrap();
6947            initiate_key_and_set_balance_and_hold(MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
6948            Pallet::place_commit(
6949                &ALICE,
6950                &STAKING,
6951                &ALPHA_ENTRY_DIGEST,
6952                LARGE_VALUE,
6953                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6954            )
6955            .unwrap();
6956            Pallet::place_commit(
6957                &BOB,
6958                &STAKING,
6959                &BETA_ENTRY_DIGEST,
6960                LARGE_VALUE,
6961                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6962            )
6963            .unwrap();
6964            Pallet::place_commit(
6965                &MIKE,
6966                &STAKING,
6967                &GAMMA_ENTRY_DIGEST,
6968                STANDARD_VALUE,
6969                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6970            )
6971            .unwrap();
6972            let entries = vec![
6973                (ALPHA_ENTRY_DIGEST, 20),
6974                (BETA_ENTRY_DIGEST, 60),
6975                (GAMMA_ENTRY_DIGEST, 40),
6976            ];
6977            prepare_and_initiate_pool(
6978                ALICE,
6979                STAKING,
6980                &entries,
6981                ALPHA_INDEX_DIGEST,
6982                ALPHA_POOL_DIGEST,
6983                COMMISSION_ZERO,
6984            )
6985            .unwrap();
6986            Pallet::place_commit(
6987                &CHARLIE,
6988                &STAKING,
6989                &ALPHA_POOL_DIGEST,
6990                20,
6991                &Directive::new(Precision::BestEffort, Fortitude::Polite),
6992            )
6993            .unwrap();
6994
6995            assert_err!(
6996                CommitHelper::set_pool_slot(
6997                    &CHARLIE,
6998                    &STAKING,
6999                    &ALPHA_POOL_DIGEST,
7000                    &DELTA_ENTRY_DIGEST,
7001                    20,
7002                    &Position::position_of(1).unwrap()
7003                ),
7004                Error::MaxSlotsReached
7005            );
7006        })
7007    }
7008
7009    // ===============================================================================
7010    // ``````````````````````````````` INDEX OPERATIONS ``````````````````````````````
7011    // ===============================================================================
7012
7013    #[test]
7014    fn remove_index_entry_success() {
7015        commit_test_ext().execute_with(|| {
7016            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
7017            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
7018            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
7019            Pallet::place_commit(
7020                &ALICE,
7021                &STAKING,
7022                &ALPHA_ENTRY_DIGEST,
7023                LARGE_VALUE,
7024                &Directive::new(Precision::BestEffort, Fortitude::Polite),
7025            )
7026            .unwrap();
7027            Pallet::place_commit(
7028                &BOB,
7029                &STAKING,
7030                &BETA_ENTRY_DIGEST,
7031                STANDARD_VALUE,
7032                &Directive::new(Precision::BestEffort, Fortitude::Polite),
7033            )
7034            .unwrap();
7035            prepare_and_initiate_index(
7036                CHARLIE,
7037                STAKING,
7038                &[(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)],
7039                ALPHA_INDEX_DIGEST,
7040            )
7041            .unwrap();
7042            // Inspecting the index entries before removing an entry
7043            let index_entries_before =
7044                Pallet::get_entries_shares(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
7045            let expected_index_entries_before =
7046                vec![(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)];
7047            assert_eq!(expected_index_entries_before, index_entries_before);
7048            // Removing an entry
7049            let new_index_digest = CommitHelper::remove_index_entry(
7050                &CHARLIE,
7051                &STAKING,
7052                &ALPHA_INDEX_DIGEST,
7053                &BETA_ENTRY_DIGEST,
7054            )
7055            .unwrap();
7056            // Inspecting the old index entries after removing an entry which remains unchanged
7057            let index_entries_before =
7058                Pallet::get_entries_shares(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
7059            let expected_index_entries_before =
7060                vec![(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)];
7061            assert_eq!(expected_index_entries_before, index_entries_before);
7062            // Inspecting the new generated index entries after removing an entry
7063            let index_entries_before =
7064                Pallet::get_entries_shares(&STAKING, &new_index_digest).unwrap();
7065            let expected_index_entries_before = vec![(ALPHA_ENTRY_DIGEST, 40)];
7066            assert_eq!(expected_index_entries_before, index_entries_before);
7067        })
7068    }
7069
7070    #[test]
7071    fn set_index_entry_success_mutating() {
7072        commit_test_ext().execute_with(|| {
7073            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
7074            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
7075            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
7076            Pallet::place_commit(
7077                &ALICE,
7078                &STAKING,
7079                &ALPHA_ENTRY_DIGEST,
7080                LARGE_VALUE,
7081                &Directive::new(Precision::BestEffort, Fortitude::Polite),
7082            )
7083            .unwrap();
7084            Pallet::place_commit(
7085                &BOB,
7086                &STAKING,
7087                &BETA_ENTRY_DIGEST,
7088                STANDARD_VALUE,
7089                &Directive::new(Precision::BestEffort, Fortitude::Polite),
7090            )
7091            .unwrap();
7092            prepare_and_initiate_index(
7093                CHARLIE,
7094                STAKING,
7095                &[(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)],
7096                ALPHA_INDEX_DIGEST,
7097            )
7098            .unwrap();
7099            Pallet::place_commit(
7100                &CHARLIE,
7101                &STAKING,
7102                &ALPHA_INDEX_DIGEST,
7103                LARGE_VALUE,
7104                &Directive::new(Precision::BestEffort, Fortitude::Polite),
7105            )
7106            .unwrap();
7107            // Inspecting the index entries before removing an entry
7108            let index_entries_shares_before =
7109                Pallet::get_entries_shares(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
7110            let expected_index_entries_shares_before =
7111                vec![(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)];
7112            let index_entries_value_before =
7113                Pallet::get_entries_value(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
7114            let expected_index_entries_value_before =
7115                vec![(ALPHA_ENTRY_DIGEST, 8), (BETA_ENTRY_DIGEST, 12)];
7116            assert_eq!(
7117                expected_index_entries_value_before,
7118                index_entries_value_before
7119            );
7120            assert_eq!(
7121                expected_index_entries_shares_before,
7122                index_entries_shares_before
7123            );
7124            let entry_alpha_variant =
7125                Pallet::get_entry_variant(&STAKING, &ALPHA_INDEX_DIGEST, &ALPHA_ENTRY_DIGEST)
7126                    .unwrap();
7127            assert_eq!(entry_alpha_variant, Position::default());
7128            // Mutating the index entry shares and variant
7129            let new_index_digest = CommitHelper::set_index_entry(
7130                &CHARLIE,
7131                &STAKING,
7132                &ALPHA_INDEX_DIGEST,
7133                &ALPHA_ENTRY_DIGEST,
7134                60,
7135                &Position::position_of(1).unwrap(),
7136            )
7137            .unwrap();
7138            // Inspecting old index entries after removing an entry which remains unchanged
7139            let index_entries_shares_before =
7140                Pallet::get_entries_shares(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
7141            let expected_index_entries_shares_before =
7142                vec![(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)];
7143            let index_entries_value_before =
7144                Pallet::get_entries_value(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
7145            let expected_index_entries_value_before =
7146                vec![(ALPHA_ENTRY_DIGEST, 8), (BETA_ENTRY_DIGEST, 12)];
7147            assert_eq!(
7148                expected_index_entries_value_before,
7149                index_entries_value_before
7150            );
7151            assert_eq!(
7152                expected_index_entries_shares_before,
7153                index_entries_shares_before
7154            );
7155            let entry_alpha_variant =
7156                Pallet::get_entry_variant(&STAKING, &ALPHA_INDEX_DIGEST, &ALPHA_ENTRY_DIGEST)
7157                    .unwrap();
7158            assert_eq!(entry_alpha_variant, Position::default());
7159            // Inspecting new generated index entries after removing an entry
7160            let index_entries_shares_before =
7161                Pallet::get_entries_shares(&STAKING, &new_index_digest).unwrap();
7162            let expected_index_entries_shares_before =
7163                vec![(BETA_ENTRY_DIGEST, 60), (ALPHA_ENTRY_DIGEST, 60)];
7164            let index_entries_value_before =
7165                Pallet::get_entries_value(&STAKING, &new_index_digest).unwrap();
7166            // fresh entries with no balance
7167            let expected_index_entries_value_before =
7168                vec![(BETA_ENTRY_DIGEST, 0), (ALPHA_ENTRY_DIGEST, 0)];
7169            assert_eq!(
7170                expected_index_entries_value_before,
7171                index_entries_value_before
7172            );
7173            assert_eq!(
7174                expected_index_entries_shares_before,
7175                index_entries_shares_before
7176            );
7177            let entry_alpha_variant =
7178                Pallet::get_entry_variant(&STAKING, &new_index_digest, &ALPHA_ENTRY_DIGEST)
7179                    .unwrap();
7180            assert_eq!(entry_alpha_variant, Position::position_of(1).unwrap());
7181        })
7182    }
7183
7184    #[test]
7185    fn set_index_entry_success_inserting() {
7186        commit_test_ext().execute_with(|| {
7187            initiate_key_and_set_balance_and_hold(ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
7188            initiate_key_and_set_balance_and_hold(BOB, LARGE_VALUE, STANDARD_VALUE).unwrap();
7189            initiate_key_and_set_balance_and_hold(CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
7190            Pallet::place_commit(
7191                &ALICE,
7192                &STAKING,
7193                &ALPHA_ENTRY_DIGEST,
7194                LARGE_VALUE,
7195                &Directive::new(Precision::BestEffort, Fortitude::Polite),
7196            )
7197            .unwrap();
7198            Pallet::place_commit(
7199                &BOB,
7200                &STAKING,
7201                &BETA_ENTRY_DIGEST,
7202                STANDARD_VALUE,
7203                &Directive::new(Precision::BestEffort, Fortitude::Polite),
7204            )
7205            .unwrap();
7206            prepare_and_initiate_index(
7207                CHARLIE,
7208                STAKING,
7209                &[(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)],
7210                ALPHA_INDEX_DIGEST,
7211            )
7212            .unwrap();
7213            Pallet::place_commit(
7214                &CHARLIE,
7215                &STAKING,
7216                &ALPHA_INDEX_DIGEST,
7217                LARGE_VALUE,
7218                &Directive::new(Precision::BestEffort, Fortitude::Polite),
7219            )
7220            .unwrap();
7221            // Inspecting the index entries before removing an entry
7222            let index_entries_shares_before =
7223                Pallet::get_entries_shares(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
7224            let expected_index_entries_shares_before =
7225                vec![(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)];
7226            let index_entries_value_before =
7227                Pallet::get_entries_value(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
7228            let expected_index_entries_value_before =
7229                vec![(ALPHA_ENTRY_DIGEST, 8), (BETA_ENTRY_DIGEST, 12)];
7230            assert_eq!(
7231                expected_index_entries_value_before,
7232                index_entries_value_before
7233            );
7234            assert_eq!(
7235                expected_index_entries_shares_before,
7236                index_entries_shares_before
7237            );
7238            let entry_alpha_variant =
7239                Pallet::get_entry_variant(&STAKING, &ALPHA_INDEX_DIGEST, &ALPHA_ENTRY_DIGEST)
7240                    .unwrap();
7241            assert_eq!(entry_alpha_variant, Position::default());
7242            // Inserting a new entry
7243            let new_index_digest = CommitHelper::set_index_entry(
7244                &CHARLIE,
7245                &STAKING,
7246                &ALPHA_INDEX_DIGEST,
7247                &GAMMA_ENTRY_DIGEST,
7248                20,
7249                &Position::position_of(1).unwrap(),
7250            )
7251            .unwrap();
7252            // Inspecting old index entries after removing an entry which remains unchanged
7253            let index_entries_shares_before =
7254                Pallet::get_entries_shares(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
7255            let expected_index_entries_shares_before =
7256                vec![(ALPHA_ENTRY_DIGEST, 40), (BETA_ENTRY_DIGEST, 60)];
7257            let index_entries_value_before =
7258                Pallet::get_entries_value(&STAKING, &ALPHA_INDEX_DIGEST).unwrap();
7259            let expected_index_entries_value_before =
7260                vec![(ALPHA_ENTRY_DIGEST, 8), (BETA_ENTRY_DIGEST, 12)];
7261            assert_eq!(
7262                expected_index_entries_value_before,
7263                index_entries_value_before
7264            );
7265            assert_eq!(
7266                expected_index_entries_shares_before,
7267                index_entries_shares_before
7268            );
7269            let entry_alpha_variant =
7270                Pallet::get_entry_variant(&STAKING, &ALPHA_INDEX_DIGEST, &ALPHA_ENTRY_DIGEST)
7271                    .unwrap();
7272            assert_eq!(entry_alpha_variant, Position::default());
7273            // Inspecting new generated index entries after removing an entry
7274            let index_entries_shares_before =
7275                Pallet::get_entries_shares(&STAKING, &new_index_digest).unwrap();
7276            let expected_index_entries_shares_before = vec![
7277                (ALPHA_ENTRY_DIGEST, 40),
7278                (BETA_ENTRY_DIGEST, 60),
7279                (GAMMA_ENTRY_DIGEST, 20),
7280            ];
7281            let index_entries_value_before =
7282                Pallet::get_entries_value(&STAKING, &new_index_digest).unwrap();
7283            // fresh entries with no balance
7284            let expected_index_entries_value_before = vec![
7285                (ALPHA_ENTRY_DIGEST, 0),
7286                (BETA_ENTRY_DIGEST, 0),
7287                (GAMMA_ENTRY_DIGEST, 0),
7288            ];
7289            assert_eq!(
7290                expected_index_entries_value_before,
7291                index_entries_value_before
7292            );
7293            assert_eq!(
7294                expected_index_entries_shares_before,
7295                index_entries_shares_before
7296            );
7297        })
7298    }
7299}