Skip to main content

pallet_commitment/
commitment.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// ```````````````````````````` COMMITMENT TRAITS IMPL ```````````````````````````
14// ===============================================================================
15
16//! Implementation module of the [`Commitment Family`](frame_suite::commitment)
17//! traits, where we utilize indexes, pools, and variants to create a flexible and
18//! semantic commitment system.
19//!
20//! Low-level helper traits are defined in [`crate::traits`] within this crate. These
21//! helpers provide fundamental functions that can be reused by other implementations
22//! to offer a similar commitment system.
23//!
24//! The asset type is defined as the fungible trait's balance - i.e., a unit with
25//! fungible behaviours. See the required trait bounds of [`Config::Asset`] to
26//! understand which methods this system utilizes.
27//!
28//! Notably, this commitment system does not rely on standard balanced (safe) fungible methods.
29//! Instead, it uses its own safe models via low-level methods provided by fungible traits.
30//! Therefore, it does not query the total asset in circulation, as its scope is limited
31//! to commitments for the particular asset holder.
32//!
33//! [`Pallet`] implements:
34//! - [`InspectAsset`]
35//! - [`DigestModel`]
36//! - [`Commitment`]
37//! - [`CommitIndex`]
38//! - [`CommitPool`]
39//! - [`CommitVariant`]
40//! - [`IndexVariant`]
41//! - [`PoolVariant`]
42//! - and other helper traits include
43//!     - [`CommitErrorHandler`]
44//!
45//! Local Tests for these traits are covered in `tests`.
46
47// ===============================================================================
48// ``````````````````````````````````` IMPORTS ```````````````````````````````````
49// ===============================================================================
50
51// --- Local crate imports ---
52use crate::{
53    balance::*, traits::*, types::*, AssetToIssue, AssetToReap, CommitHelpers, CommitMap, Config,
54    DigestMap, EntryMap, Error, Event, HoldReason, IndexMap, Pallet, PoolManager, PoolMap,
55};
56
57// --- Core ---
58use core::cmp::Ordering;
59
60// --- FRAME Suite ---
61use frame_suite::{commitment::*, keys::*, misc::Extent};
62
63// --- FRAME Support ---
64use frame_support::{
65    ensure,
66    traits::{
67        fungible::{Inspect, InspectHold},
68        tokens::{Fortitude, Preservation},
69    },
70};
71
72// --- Substrate primitives ---
73use sp_core::Get;
74use sp_runtime::{
75    traits::{CheckedAdd, Saturating, Zero},
76    DispatchError, DispatchResult, Vec,
77};
78
79// ===============================================================================
80// ```````````````````````````````` INSPECT ASSET ````````````````````````````````
81// ===============================================================================
82
83/// Implements [`InspectAsset`] for the pallet, allowing the
84/// commitment pallet to inspect a user's available funds
85/// for commitment.
86impl<T: Config<I>, I: 'static> InspectAsset<Proprietor<T>> for Pallet<T, I> {
87    /// The asset type used in commitments, taken from the fungible `Inspect` trait.
88    ///
89    /// This allows any fungible implementation to be used as the commitment asset,
90    /// providing flexibility in the type of value being committed while ensuring
91    /// compatibility with the broader Substrate fungible ecosystem.
92    type Asset = AssetOf<T, I>;
93
94    /// Retrieves the total available funds for commitment for a given proprietor.
95    ///
96    /// Aggregates two balance sources:
97    /// - Funds held under [`HoldReason::PrepareForCommit`] reason
98    /// - Liquid balance reducible under [`Preservation::Preserve`] and
99    /// [`Fortitude::Polite`] rules
100    ///
101    /// This aggregated view is used by commitment validation logic to determine whether
102    /// a proprietor has sufficient funds to place, raise, or modify commitments.
103    ///
104    /// ## Returns
105    /// `Asset` containing the total available balance
106    fn available_funds(who: &Proprietor<T>) -> Self::Asset {
107        let hold_reason: T::AssetHold = HoldReason::PrepareForCommit.into();
108
109        // Funds specifically held for this commitment purpose.
110        let held_balance = T::Asset::balance_on_hold(&hold_reason, who);
111
112        // Liquid balance available for commitment.
113        // We do not want the account to be dusted/killed/reaped.
114        let liquid_balance =
115            T::Asset::reducible_balance(who, Preservation::Preserve, Fortitude::Polite);
116
117        held_balance.saturating_add(liquid_balance)
118    }
119}
120
121// ===============================================================================
122// ```````````````````````````````` DIGEST MODEL `````````````````````````````````
123// ===============================================================================
124
125/// Implements [`DigestModel`] for the pallet, allowing the system to
126/// determine the specific model variant of a given digest.
127///
128/// Since all digests share the same base type, we need a wrapper
129/// i.e., [`DigestVariant`] to distinguish between models such as Direct, Index, and Pool.
130impl<T: Config<I>, I: 'static> DigestModel<Proprietor<T>> for Pallet<T, I> {
131    /// The digest model type, wrapping the digest with its variant classification.
132    ///
133    /// This type distinguishes between three commitment models:
134    /// - **Direct**: A standalone commitment to a specific digest
135    /// - **Index**: A commitment distributed across multiple entries with weighted shares
136    /// - **Pool**: A managed commitment structure with dynamic slot allocation and commission
137    type Model = DigestVariant<T, I>;
138
139    /// Determines which digest model a given digest belongs to.
140    ///
141    /// This method checks if the digest exists in each model variant in order:
142    /// 1. Direct
143    /// 2. Index
144    /// 3. Pool
145    ///
146    /// If a matching model is found, it returns the wrapped variant.
147    /// Otherwise, a DispatchError.
148    ///
149    /// Note: This method is **not suitable** for creating new digests (not
150    /// registered in the system).
151    ///
152    /// New digests should be manually wrapped to avoid incorrect determination.
153    fn determine_digest(
154        digest: &Self::Digest,
155        reason: &Self::Reason,
156    ) -> Result<Self::Model, DispatchError> {
157        if Self::digest_exists(reason, digest).is_ok() {
158            return Ok(DigestVariant::Direct(digest.clone()));
159        }
160
161        if Self::index_exists(reason, digest).is_ok() {
162            return Ok(DigestVariant::Index(digest.clone()));
163        }
164
165        if Self::pool_exists(reason, digest).is_ok() {
166            return Ok(DigestVariant::Pool(digest.clone()));
167        }
168
169        Err(Error::<T, I>::DigestNotFoundToDetermine.into())
170    }
171}
172
173// ===============================================================================
174// ````````````````````````````````` COMMITMENT ``````````````````````````````````
175// ===============================================================================
176
177/// Implements the base [`Commitment`] trait for the pallet.
178impl<T: Config<I>, I: 'static> Commitment<Proprietor<T>> for Pallet<T, I> {
179    /// The source of a digest, used to determine the concrete digest.
180    ///  
181    /// In this implementation, the digest source is the the calling source
182    /// i.e., [`frame_system::Config::AccountId`]. Must be using its account
183    /// nonce for deterministic-randomness.
184    ///
185    /// This means all digests - whether direct, index, or pool - have a
186    /// deterministic account ID generated by [`Commitment::gen_digest`] and similar
187    /// methods.
188    ///
189    /// Internally, the methods enforces generating the [`Commitment::Digest`] same
190    /// as the source type.
191    type DigestSource = DigestSource<T>;
192
193    /// The digest type used in this pallet, based on account ID type
194    /// (from [`frame_system::Config::AccountId`]).
195    ///
196    /// This ensures all digests are tied to a consistent, predictable
197    /// identity, same as every accounts. Much alike contract addresses.
198    type Digest = Digest<T>;
199
200    /// The reason associated with a commitment.
201    ///
202    /// This type is linked to the `Id` type of the `InspectFreeze` fungible trait,
203    /// typically a composite enum constructed at runtime from all pallets
204    /// that use fungible properties.
205    ///
206    /// Declaring `Reason` as the top-level key:
207    /// - Encourages compile-time reasons for commitments.
208    /// - Prevents creating new reasons at runtime without explicit intent.
209    /// - Ensures other pallets adopt this commitment structure for consistent behavior.
210    type Reason = CommitReason<T, I>;
211
212    /// Commitment operation top level configuration.
213    ///
214    /// Enforces exactness and forcefullness towards a commit operation.
215    type Intent = DispatchPolicy;
216
217    /// Type representing the derived limits used for commitment validations.
218    ///
219    /// Encapsulates bounds (e.g. minimum, maximum, optimal) computed by the
220    /// underlying balance model for deposit, mint, and reap operations.
221    type Limits = LimitsProduct<T, I>;
222
223    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
224    // ``````````````````````````````````` CHECKERS ``````````````````````````````````
225    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
226
227    /// Checks whether a commitment exists for the given proprietor and reason.
228    ///
229    /// ## Returns
230    /// - `Ok(())` if a commitment exists
231    /// - `Err(DispatchError)` if no commitment exists
232    fn commit_exists(who: &Proprietor<T>, reason: &Self::Reason) -> DispatchResult {
233        ensure!(
234            CommitMap::<T, I>::contains_key((who, reason)),
235            Error::<T, I>::CommitNotFound
236        );
237        Ok(())
238    }
239
240    /// Checks whether a direct-digest exists for the given reason.
241    ///
242    /// This doesn't ensures existence for index or pool digests, as callers
243    /// should use [`CommitIndex::index_exists`] or [`CommitPool::pool_exists`]
244    ///
245    /// ## Returns
246    /// - `Ok(())` if the digest exists
247    /// - `Err(DispatchError)` if the digest does not exist
248    fn digest_exists(reason: &Self::Reason, digest: &Self::Digest) -> DispatchResult {
249        ensure!(
250            DigestMap::<T, I>::contains_key((reason, digest)),
251            Error::<T, I>::DigestNotFound
252        );
253        Ok(())
254    }
255
256    /// Validates whether a new commitment can be placed with the
257    /// variant's [`Config::Position`] default.
258    ///
259    /// This is a thin wrapper over [`Self::can_place_commit_of_variant`],
260    /// using the default [`Config::Position`] for non-variant commitments.
261    ///
262    /// ## Returns
263    /// - `Ok(())` if validation succeeds
264    /// - `Err(DispatchError)` if validation fails
265    #[inline]
266    fn can_place_commit(
267        who: &Proprietor<T>,
268        reason: &Self::Reason,
269        digest: &Self::Digest,
270        value: Self::Asset,
271        qualifier: &Self::Intent,
272    ) -> DispatchResult {
273        Self::can_place_commit_of_variant(
274            who,
275            reason,
276            digest,
277            &Default::default(),
278            value,
279            qualifier,
280        )
281    }
282
283    /// Validates whether an existing commitment can be increased (raised).
284    ///
285    /// Same as the default trait validation, but extended with an additional
286    /// check against the underlying balance model to ensure the deposit can
287    /// actually be applied.
288    ///
289    /// In the lazy balance model, raising is equivalent to performing an
290    /// additional deposit and the underlying system does not distinguish between
291    /// placing and raising.
292    ///
293    /// ## Returns
294    /// - `Ok(())` if validation succeeds
295    /// - `Err(DispatchError)` if any constraint is violated
296    fn can_raise_commit(
297        who: &Proprietor<T>,
298        reason: &Self::Reason,
299        value: Self::Asset,
300        qualifier: &Self::Intent,
301    ) -> DispatchResult {
302        let digest = &Self::get_commit_digest(who, reason)?;
303        let max = Self::available_funds(who);
304        ensure!(max >= value, Error::<T, I>::InsufficientFunds);
305        let variant = &Self::get_commit_variant(who, reason)?;
306        // debug_assert!()
307        let balance = DigestMap::<T, I>::get((reason, digest))
308            .and_then(|digest_info| digest_info.get_balance(&variant).cloned())
309            .unwrap_or_default();
310        let limits = deposit_limits_of(&balance, &variant, digest, qualifier)?;
311        ensure!(
312            <Self::Limits as Extent>::contains(&limits, value),
313            Error::<T, I>::PlacingOffLimits
314        );
315        can_deposit(&balance, variant, digest, &value, qualifier)
316    }
317
318    /// Validates whether a commitment can be resolved.
319    ///
320    /// Extends the default trait behavior by additionally validating that all
321    /// underlying balances can support the required withdrawals.
322    ///
323    /// Since each digest model maintains balances differently:
324    /// - **Direct / Index**: withdrawals are validated directly against their balances
325    /// - **Pool**: validation is performed against the pool's current (unadjusted)
326    ///   aggregate balance, without applying intermediate slot updates
327    ///
328    /// This is a lightweight validation step; full consistency (including pool
329    /// rebalancing) is enforced during the actual resolution operation.
330    ///
331    /// ## Returns
332    /// - `Ok(())` if all withdrawals are valid
333    /// - `Err(DispatchError)` if any withdrawal is invalid
334    fn can_resolve_commit(who: &Proprietor<T>, reason: &Self::Reason) -> DispatchResult {
335        let digest = &Self::get_commit_digest(who, reason)?;
336        let digest_model = &Self::determine_digest(digest, reason)?;
337        // debug_assert!()
338        match digest_model {
339            DigestVariant::Direct(direct) => {
340                let variant = &Self::get_commit_variant(who, reason)?;
341                // debug_assert!()
342                let digest_info = DigestMap::<T, I>::get((reason, direct))
343                    .ok_or(Error::<T, I>::DigestNotFound)?;
344                // debug_assert!()
345                let balance = digest_info
346                    .get_balance(variant)
347                    // debug_assert!()
348                    .ok_or(Error::<T, I>::DigestVariantBalanceNotFound)?;
349                let commit_info =
350                    CommitMap::<T, I>::get((who, reason)).ok_or(Error::<T, I>::CommitNotFound)?;
351                // debug_assert!()
352                for commit in commit_info.commits() {
353                    can_withdraw(&balance, variant, digest, &commit)?;
354                }
355            }
356            DigestVariant::Index(index) => {
357                let index_info = Self::get_index(reason, index)?;
358                // debug_assert!()
359                for entry in index_info.entries() {
360                    let digest = &entry.digest();
361                    let Some(commits) = EntryMap::<T, I>::get((reason, index, digest, who)) else {
362                        // If Zero Amount Depositted due to low shares
363                        continue;
364                    };
365                    let variant = &entry.variant();
366                    let digest_info = DigestMap::<T, I>::get((reason, digest))
367                        // debug_assert!()
368                        .ok_or(Error::<T, I>::EntryDigestNotFound)?;
369                    let balance = digest_info
370                        .get_balance(variant)
371                        // debug_assert!()
372                        .ok_or(Error::<T, I>::DigestVariantBalanceNotFound)?;
373                    for commit in commits.commits() {
374                        can_withdraw(&balance, variant, digest, &commit)?;
375                    }
376                }
377            }
378            DigestVariant::Pool(pool) => {
379                let pool_info = Self::get_pool(reason, pool)?;
380                // debug_assert!()
381                let balance = pool_info.balance();
382                let commit_info =
383                    CommitMap::<T, I>::get((who, reason)).ok_or(Error::<T, I>::CommitNotFound)?;
384                // debug_assert!()
385                for commit in commit_info.commits() {
386                    can_withdraw(&balance, &Default::default(), pool, &commit)?;
387                }
388            }
389            _ => {
390                debug_assert!(
391                    false,
392                    "digest-model marker variants {:?} are constructed, 
393                    captured during can withdraw validation proprietor {:?} 
394                    of reason {:?} are explicitly dis-allowed",
395                    digest_model, who, reason
396                );
397                return Err(Error::<T, I>::InvalidDigestModel.into());
398            }
399        }
400        Ok(())
401    }
402
403    /// Validates whether a digest's value can be set using the default variant.
404    ///
405    /// This is a thin wrapper over [`Self::can_set_digest_variant_value`],
406    /// using the default [`Config::Position`] for single non-variant commitments.
407    ///
408    /// ## Returns
409    /// - `Ok(())` if validation succeeds
410    /// - `Err(DispatchError)` if validation fails
411    #[inline]
412    fn can_set_digest_value(
413        reason: &Self::Reason,
414        digest: &Self::Digest,
415        value: Self::Asset,
416        qualifier: &Self::Intent,
417    ) -> DispatchResult {
418        Self::can_set_digest_variant_value(reason, digest, value, &Default::default(), qualifier)
419    }
420
421    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
422    // ``````````````````````````````````` GETTERS ```````````````````````````````````
423    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
424
425    /// Retrieves the digest associated with a proprietor's commitment.
426    ///
427    /// Since [`Commitment::Digest`] is opaque to identify as direct or index
428    /// or pool. This function can return any digest model which later can be
429    /// determined using [`DigestModel::determine_digest`].
430    ///
431    /// Since each reason can only have one active digest per proprietor,
432    /// this directly returns the commitment's digest.
433    ///
434    /// ## Returns
435    /// - `Ok(Digest)` containing the commitment's digest
436    /// - `Err(DispatchError)` if no commitment exists
437    fn get_commit_digest(
438        who: &Proprietor<T>,
439        reason: &Self::Reason,
440    ) -> Result<Self::Digest, DispatchError> {
441        let commit_info =
442            CommitMap::<T, I>::get((who, reason)).ok_or(Error::<T, I>::CommitNotFound)?;
443        let digest = commit_info.digest();
444        debug_assert!(
445            // cannot do `digest_exists` as this can get called by any digest model
446            // `determine_digest` holds all checks
447            Self::determine_digest(&digest, reason).is_ok(),
448            "commit-exists for reason {:?} of digest {:?} for proprietor {:?}, 
449            but internally digest doesn't really exist",
450            reason,
451            digest,
452            who
453        );
454        Ok(digest)
455    }
456
457    /// Retrieves the total committed value across all proprietors for a reason.
458    ///
459    /// ## Returns
460    /// - `Asset` containing the total committed value, or zero if unavailable
461    fn get_total_value(reason: &Self::Reason) -> Self::Asset {
462        CommitHelpers::<T, I>::value_of(None, reason).unwrap_or(Zero::zero())
463    }
464
465    /// Retrieves the real-time committed value for a specific proprietor and reason.
466    ///
467    /// This value reflects the current state including any applied rewards or penalties.
468    /// Since each proprietor can only have one active digest per reason, this returns
469    /// the aggregate value across all commitment instances for that digest.
470    ///
471    /// Internally, raising commits doesn't mutate an existing commitment-balance but
472    /// instead accmulate new immutable balances as commit-instances which will be
473    /// aggregated.
474    ///
475    /// ## Returns
476    /// - `Ok(Asset)` containing the proprietor's current committed value
477    /// - `Err(DispatchError)` if no commitment exists
478    fn get_commit_value(
479        who: &Proprietor<T>,
480        reason: &Self::Reason,
481    ) -> Result<Self::Asset, DispatchError> {
482        let digest = Self::get_commit_digest(who, reason)?;
483        let digest_model = Self::determine_digest(&digest, reason);
484        debug_assert!(
485            digest_model.is_ok(),
486            "proprietor {:?} commit-exists in digest {:?} for reason {:?}, 
487            but its model cannot be determined",
488            who,
489            digest,
490            reason
491        );
492        let digest_model = digest_model?;
493        CommitHelpers::<T, I>::commit_value_of(who, reason, &digest_model)
494    }
495
496    /// Retrieves the real-time total value of a specific direct-digest's
497    /// default variant of [`Config::Position`] for a given reason.
498    ///
499    /// This doesn't provides value for index or pool digests, as callers
500    /// should use [`CommitIndex::get_index_value`] or [`CommitPool::get_pool_value`]
501    ///
502    /// Aggregates all commitments across all proprietors who committed
503    /// funds to this digest's default variant.
504    ///
505    /// This method delagates itself to [`CommitVariant::get_digest_variant_value`]
506    /// with the default position variant.
507    ///
508    /// ## Returns
509    /// - `Ok(Asset)` containing the digest's total value
510    /// - `Err(DispatchError)` if the digest does not exist
511    #[inline]
512    fn get_digest_value(
513        reason: &Self::Reason,
514        digest: &Self::Digest,
515    ) -> Result<Self::Asset, DispatchError> {
516        Self::get_digest_variant_value(reason, digest, &T::Position::default())
517    }
518
519    /// Derives place commit limits for the given params of the
520    /// default commit-variant.
521    ///
522    /// This is a convenience wrapper over [`Self::place_commit_limits_of_variant`],
523    /// using the default [`Config::Position`] for non-variant commitments.
524    ///
525    /// ## Returns
526    /// - `Ok(Limits)` containing the derived constraints
527    /// - `Err(DispatchError)` if the derivation fails
528    #[inline]
529    fn place_commit_limits(
530        who: &Proprietor<T>,
531        reason: &Self::Reason,
532        digest: &Self::Digest,
533        qualifier: &Self::Intent,
534    ) -> Result<Self::Limits, DispatchError> {
535        Self::place_commit_limits_of_variant(who, reason, digest, &Default::default(), qualifier)
536    }
537
538    /// Derives limits for increasing (raising) an existing commitment under
539    /// the default commit-variant.
540    ///
541    /// Resolves the commit's associated digest and variant for the given
542    /// proprietor and reason, then delegates to
543    /// [`Self::place_commit_limits_of_variant`].
544    ///
545    /// In the lazy balance model, raising is equivalent to performing an
546    /// additional deposit on an existing commitment, so the same limit
547    /// derivation logic applies.
548    ///
549    /// The `qualifier` influences how limits are derived.
550    ///
551    /// ## Returns
552    /// - `Ok(Limits)` containing the derived constraints
553    /// - `Err(DispatchError)` if the commitment does not exist or derivation fails
554    fn raise_commit_limits(
555        who: &Proprietor<T>,
556        reason: &Self::Reason,
557        qualifier: &Self::Intent,
558    ) -> Result<Self::Limits, DispatchError> {
559        let digest = Self::get_commit_digest(who, reason)?;
560        let variant = Self::get_commit_variant(who, reason)?;
561        // debug_assert!()
562        Self::place_commit_limits_of_variant(who, reason, &digest, &variant, qualifier)
563    }
564
565    /// Derives minting limits for a digest using the default variant.
566    ///
567    /// This is a convenience wrapper over [`Self::digest_mint_limits_of_variant`],
568    /// using the default [`Config::Position`] for single non-variant digests.
569    ///
570    /// The `qualifier` influences how limits are derived (e.g. strict vs relaxed).
571    ///
572    /// ## Returns
573    /// - `Ok(Limits)` containing the derived minting constraints
574    /// - `Err(DispatchError)` if the derivation fails
575    #[inline]
576    fn digest_mint_limits(
577        digest: &Self::Digest,
578        reason: &Self::Reason,
579        qualifier: &Self::Intent,
580    ) -> Result<Self::Limits, DispatchError> {
581        Self::digest_mint_limits_of_variant(digest, reason, &Default::default(), qualifier)
582    }
583
584    /// Derives reaping limits for a digest using the default variant.
585    ///
586    /// This is a convenience wrapper over [`Self::digest_reap_limits_of_variant`],
587    /// using the default [`Config::Position`] for single non-variant digests.
588    ///
589    /// The `qualifier` influences how limits are derived (e.g. strict vs relaxed).
590    ///
591    /// ## Returns
592    /// - `Ok(Limits)` containing the derived reaping constraints
593    /// - `Err(DispatchError)` if the derivation fails
594    #[inline]
595    fn digest_reap_limits(
596        digest: &Self::Digest,
597        reason: &Self::Reason,
598        qualifier: &Self::Intent,
599    ) -> Result<Self::Limits, DispatchError> {
600        Self::digest_reap_limits_of_variant(digest, reason, &Default::default(), qualifier)
601    }
602
603    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
604    // ````````````````````````````````` CONSTRUCTORS ````````````````````````````````
605    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
606
607    /// Generates a unique digest identifier from the given source.
608    ///
609    /// Uses the account nonce as a salt to ensure uniqueness across multiple
610    /// digest generations for the same source.
611    ///
612    /// Utilizes [`KeyGenFor`] trait implementation via [`KeySeedFor`]
613    ///
614    /// ## Returns
615    /// - `Ok(Digest)` containing the generated digest
616    /// - `Err(DispatchError)` if digest generation fails
617    fn gen_digest(source: &DigestSource<T>) -> Result<Self::Digest, DispatchError> {
618        let target = Into::<&Self::Digest>::into(source);
619
620        // Retrieve account nonce from the system pallet as a salt
621        let salt = frame_system::Pallet::<T>::account_nonce(source);
622
623        // Generate a digest key with salt
624        let key =
625            KeySeedFor::<Self::Digest, (), T::Nonce, T::Hashing, T>::gen_key(target, &(), salt)
626                .ok_or(Error::<T, I>::CannotGenerateDigest)?;
627
628        Ok(key)
629    }
630
631    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
632    // ``````````````````````````````````` MUTATORS ``````````````````````````````````
633    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
634
635    /// Places a commitment with the variant's [`Config::Position`] default.
636    ///
637    /// This method delagates itself to [`CommitVariant::place_commit_of_variant`]
638    /// with the default position variant.
639    ///
640    /// For detailed information on how placing a commitment works, refer to the
641    /// called implemented method [`CommitVariant::place_commit_of_variant`].
642    ///
643    /// ## Returns
644    /// - `Ok(Asset)` containing the actual committed amount
645    /// - `Err(DispatchError)` if placement fails
646    fn place_commit(
647        who: &Proprietor<T>,
648        reason: &Self::Reason,
649        digest: &Self::Digest,
650        value: Self::Asset,
651        qualifier: &Self::Intent,
652    ) -> Result<Self::Asset, DispatchError> {
653        Self::place_commit_of_variant(
654            who,
655            reason,
656            digest,
657            value,
658            &T::Position::default(),
659            qualifier,
660        )
661    }
662
663    /// Resolves and withdraws a commitment for the given proprietor and reason.
664    ///
665    /// Calculates the final value including any rewards or penalties, unfreezes
666    /// the committed assets, and returns them to the owner (authorized-caller).
667    ///
668    /// The commitment record is removed upon successful resolution.
669    ///
670    /// ## Returns
671    /// - `Ok(Asset)` containing the resolved amount returned to the proprietor
672    /// - `Err(DispatchError)` if no commitment exists or resolution fails
673    fn resolve_commit(
674        who: &Proprietor<T>,
675        reason: &Self::Reason,
676    ) -> Result<Self::Asset, DispatchError> {
677        let digest = Self::get_commit_digest(who, reason)?;
678        let digest_model = Self::determine_digest(&digest, reason);
679        debug_assert!(
680            digest_model.is_ok(),
681            "proprietor {:?} commit-exists in digest {:?} of reason {:?}, 
682            but its model cannot be determined",
683            who,
684            digest,
685            reason
686        );
687        let digest_model = digest_model?;
688        let resolved = CommitHelpers::<T, I>::resolve_commit_of(who, reason, &digest_model)?;
689        Self::on_commit_resolve(who, reason, &digest, resolved);
690        Ok(resolved)
691    }
692
693    /// Raises a commitment for the given proprietor and reason.
694    ///
695    /// Enforces that the proprietor must already have an active
696    /// commitment for the given reason.
697    ///
698    /// Does not allow zero-value marker commitments.
699    ///
700    /// ## Returns
701    /// - `Ok(Asset)` containing the raised amount
702    /// - `Err(DispatchError)` if no existing commitment is found or funds are insufficient
703    fn raise_commit(
704        who: &Proprietor<T>,
705        reason: &Self::Reason,
706        value: Self::Asset,
707        qualifier: &Self::Intent,
708    ) -> Result<Self::Asset, DispatchError> {
709        Self::commit_exists(who, reason)?;
710        ensure!(!value.is_zero(), Error::<T, I>::MarkerCommitNotAllowed);
711        let digest = Self::get_commit_digest(who, reason)?;
712        let digest_model = Self::determine_digest(&digest, reason);
713        debug_assert!(
714            digest_model.is_ok(),
715            "proprietor {:?} commit-exists in digest {:?} for reason {:?}, 
716            but its model cannot be determined",
717            who,
718            digest,
719            reason
720        );
721        let digest_model = digest_model?;
722        let raised =
723            CommitHelpers::<T, I>::raise_commit_of(who, reason, &digest_model, value, qualifier)?;
724        Self::on_commit_raise(who, reason, &digest, raised);
725        Ok(raised)
726    }
727
728    /// Sets a direct value on a digest, typically for applying rewards/inflation or
729    /// penalties/deflation.
730    ///
731    /// **Note**: This function operates at the low-level commitment for a direct-digest. It
732    /// cannot be used to directly apply rewards or penalties to indexes or pools, because
733    /// those maintain their balances at a higher level through their entries and slots digests.
734    ///
735    /// Any value adjustment for indexes or pools should propagate via their underlying
736    /// sub-systems if applicable.
737    ///
738    /// Internally calls [`CommitVariant::set_digest_variant_value`] with the default
739    /// variant of [`Config::Position`].
740    ///
741    /// The `qualifier` influences how the adjustment (via the given direction which
742    /// could be increase or decrease from current digest value) is applied and may
743    /// affect the final value that is actually set.
744    ///
745    /// ## Returns
746    /// - `Ok(Asset)` containing the resulting value of the digest after update
747    /// - `Err(DispatchError)` if the operation fails
748    #[inline]
749    fn set_digest_value(
750        reason: &Self::Reason,
751        digest: &Self::Digest,
752        value: Self::Asset,
753        qualifier: &Self::Intent,
754    ) -> Result<Self::Asset, DispatchError> {
755        Self::set_digest_variant_value(reason, digest, value, &T::Position::default(), qualifier)
756    }
757
758    /// Removes a digest from storage after ensuring it contains no active deposits.
759    ///
760    /// This operation is only allowed when the digest's balance has no remaining
761    /// deposits (i.e., no claimable commitments exist).
762    ///
763    /// **Note**: This function operates for direct digests only. It cannot be used
764    /// to reap indexes or pools.
765    ///
766    /// Any residual value ("dust") left after all deposits are withdrawn is treated
767    /// as unclaimable and reaped-accounted in [`AssetToReap`], deducted from total
768    /// committed value [`crate::ReasonValue`], and considered effectively dead.
769    ///
770    /// The digest itself can be recreated later if a new deposit is made via
771    /// [`CommitDeposit::deposit_to_digest`].
772    ///
773    /// ## Returns
774    /// - `Ok(())` if the digest is successfully removed
775    /// - `Err(DispatchError)` with `DigestHasFunds` if active deposits still exist
776    fn reap_digest(digest: &Self::Digest, reason: &Self::Reason) -> DispatchResult {
777        let digest_info =
778            DigestMap::<T, I>::get((reason, digest)).ok_or(Error::<T, I>::DigestNotFound)?;
779        let balances = digest_info.balances()?;
780        let mut reap = true;
781        let mut remaining = Zero::zero();
782        for (variant, balance) in &balances {
783            if has_deposits(balance, variant, digest).is_ok() {
784                reap = false;
785                break;
786            }
787            remaining = balance_total(balance, variant, digest)?;
788        }
789        // Cannot reap a digest with remaining funds
790        ensure!(reap, Error::<T, I>::DigestHasFunds);
791
792        // If unerlying balance system allows residue/dust after
793        // full-withdrawal due to rounding/precision and other drifts.
794        if !remaining.is_zero() {
795            // Residue as it will never be claimed, but maintained for equillibrium
796            // Considered dead inside commitment system, and never will be able to
797            // resolved in the underlying asset (fungible) system
798            AssetToReap::<T, I>::mutate(|total_to_reap| -> DispatchResult {
799                *total_to_reap = total_to_reap
800                    .checked_add(&remaining)
801                    .ok_or(Error::<T, I>::MaxAssetReaped)?;
802                Ok(())
803            })?;
804            // Subtract reason's total committed value since value is deflated
805            CommitHelpers::<T, I>::sub_from_total_value(reason, remaining)?;
806        }
807
808        // Called earlier to determine reaped digest model.
809        Self::on_reap_digest(digest, reason, remaining);
810
811        // Remove the digest from storage
812        DigestMap::<T, I>::remove((reason, digest));
813        Ok(())
814    }
815
816    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
817    // ```````````````````````````````````` HOOKS ````````````````````````````````````
818    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
819
820    /// Hook called when a commitment is placed.
821    ///
822    /// Delagates itself to [`CommitVariant::on_place_commit_on_variant`]
823    /// with the default position variant.
824    #[inline]
825    fn on_commit_place(
826        who: &Proprietor<T>,
827        reason: &Self::Reason,
828        digest: &Self::Digest,
829        value: Self::Asset,
830    ) {
831        Self::on_place_commit_on_variant(who, reason, digest, value, &Default::default());
832    }
833
834    /// Hook called when a commitment is raised.
835    ///
836    /// The digest is verified and classified using
837    /// [`DigestModel::determine_digest`].
838    ///
839    /// Emits [`Event::CommitRaised`] event if
840    /// [`Config::EmitEvents`] is `true`.
841    fn on_commit_raise(
842        who: &Proprietor<T>,
843        reason: &Self::Reason,
844        digest: &Self::Digest,
845        value: Self::Asset,
846    ) {
847        if T::EmitEvents::get() {
848            #[cfg(any(feature = "dev", feature = "runtime-benchmarks"))]
849            {
850                let Ok(digest_model) = Self::determine_digest(digest, reason) else {
851                    return;
852                };
853                Self::deposit_event(Event::<T, I>::CommitRaised {
854                    who: who.clone(),
855                    reason: *reason,
856                    model: digest_model,
857                    value,
858                });
859            }
860
861            #[cfg(not(any(feature = "dev", feature = "runtime-benchmarks")))]
862            {
863                Self::deposit_event(Event::<T, I>::CommitRaised {
864                    who: who.clone(),
865                    reason: *reason,
866                    digest: digest.clone(),
867                    value,
868                });
869            }
870        }
871    }
872
873    /// Hook called when a commitment is resolved.
874    ///
875    /// The digest is verified and classified using
876    /// [`DigestModel::determine_digest`].
877    ///
878    /// Emits [`Event::CommitResolved`] event if
879    /// [`Config::EmitEvents`] is `true`.
880    fn on_commit_resolve(
881        who: &Proprietor<T>,
882        reason: &Self::Reason,
883        digest: &Self::Digest,
884        value: Self::Asset,
885    ) {
886        if T::EmitEvents::get() {
887            #[cfg(any(feature = "dev", feature = "runtime-benchmarks"))]
888            {
889                let Ok(digest_model) = Self::determine_digest(digest, reason) else {
890                    return;
891                };
892                Self::deposit_event(Event::<T, I>::CommitResolved {
893                    who: who.clone(),
894                    reason: *reason,
895                    model: digest_model,
896                    value,
897                });
898            }
899
900            #[cfg(not(any(feature = "dev", feature = "runtime-benchmarks")))]
901            {
902                Self::deposit_event(Event::<T, I>::CommitResolved {
903                    who: who.clone(),
904                    reason: *reason,
905                    digest: digest.clone(),
906                    value,
907                });
908            }
909        }
910    }
911
912    /// Hook called when a digest value is updated.
913    ///
914    /// This method delagates itself to [`CommitVariant::on_set_digest_variant`]
915    /// with the default position variant.
916    #[inline]
917    fn on_digest_update(digest: &Self::Digest, reason: &Self::Reason, value: Self::Asset) {
918        Self::on_set_digest_variant(digest, reason, value, &Default::default());
919    }
920
921    /// Hook called when a digest is successfully reaped.
922    ///
923    /// Emits [`Event::DigestReaped`] event if [`Config::EmitEvents`] is `true`.
924    fn on_reap_digest(digest: &Self::Digest, reason: &Self::Reason, dust: Self::Asset) {
925        if T::EmitEvents::get() {
926            // Emit the DigestReaped event
927            Self::deposit_event(Event::<T, I>::DigestReaped {
928                digest: digest.clone(),
929                reason: *reason,
930                dust,
931            });
932        }
933    }
934}
935
936// ===============================================================================
937// ```````````````````````````````` COMMIT INDEX `````````````````````````````````
938// ===============================================================================
939
940/// Implements [`CommitIndex`] for the pallet
941impl<T: Config<I>, I: 'static> CommitIndex<Proprietor<T>> for Pallet<T, I> {
942    /// Index struct representing an index's internal structure.
943    ///
944    /// This type holds all entries and their associated shares, used for commitment
945    /// calculations and value aggregations within the index.
946    type Index = IndexInfo<T, I>;
947
948    /// Shares unit defining an entry's proportional weight within the index.
949    ///
950    /// Shares represent each entry's relative contribution to the index capital,
951    /// used for calculating value distributions and reward/penalty allocations.
952    type Shares = T::Shares;
953
954    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
955    // ``````````````````````````````````` CHECKERS ``````````````````````````````````
956    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
957
958    /// Checks whether a specific index exists for the given reason.
959    ///
960    /// ## Returns
961    /// - `Ok(())` if the index exists
962    /// - `Err(DispatchError)` if the index does not exist
963    fn index_exists(reason: &Self::Reason, index_of: &Self::Digest) -> DispatchResult {
964        ensure!(
965            IndexMap::<T, I>::contains_key((reason, index_of)),
966            Error::<T, I>::IndexNotFound
967        );
968        Ok(())
969    }
970
971    /// Checks whether a specific entry exists within a given index.
972    ///
973    /// ## Returns
974    /// - `Ok(())` if the entry exists
975    /// - `Err(DispatchError)` if the entry does not exist
976    fn entry_exists(
977        reason: &Self::Reason,
978        index_of: &Self::Digest,
979        entry_of: &Self::Digest,
980    ) -> DispatchResult {
981        let index = Self::get_index(reason, index_of)?;
982        for entry in index.entries() {
983            if *entry_of == entry.digest() {
984                return Ok(());
985            }
986        }
987        Err(Error::<T, I>::EntryOfIndexNotFound.into())
988    }
989
990    /// Checks whether any index exists for the given reason.
991    ///
992    /// ## Returns
993    /// - `Ok(())` if at least one index exists
994    /// - `Err(DispatchError)` if no indexes exist
995    fn has_index(reason: &Self::Reason) -> DispatchResult {
996        ensure!(
997            IndexMap::<T, I>::iter_prefix((reason,)).next().is_some(),
998            Error::<T, I>::IndexNotFound
999        );
1000        Ok(())
1001    }
1002
1003    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1004    // ``````````````````````````````````` GETTERS ```````````````````````````````````
1005    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1006
1007    /// Retrieves the index information (meta-struct) for a given
1008    /// reason and index digest.
1009    ///
1010    /// ## Returns
1011    /// - `Ok(Index)` containing the index structure
1012    /// - `Err(DispatchError)`if the index does not exist
1013    fn get_index(
1014        reason: &Self::Reason,
1015        index_of: &Self::Digest,
1016    ) -> Result<Self::Index, DispatchError> {
1017        let index =
1018            IndexMap::<T, I>::get((reason, index_of)).ok_or(Error::<T, I>::IndexNotFound)?;
1019        Ok(index)
1020    }
1021
1022    /// Retrieves all entry digests and their shares for a specific index.
1023    ///
1024    /// ## Returns
1025    /// - `Ok(Vec<(Digest, Shares)>)` containing each entry's digest and shares
1026    /// - `Err(DispatchError)` if the index does not exist
1027    fn get_entries_shares(
1028        reason: &Self::Reason,
1029        index_of: &Self::Digest,
1030    ) -> Result<Vec<(Self::Digest, Self::Shares)>, DispatchError> {
1031        let mut vec = Vec::new();
1032        let index = Self::get_index(reason, index_of)?;
1033        for entry in index.entries() {
1034            let shares = entry.shares();
1035            vec.push((entry.digest(), shares));
1036        }
1037        Ok(vec)
1038    }
1039
1040    /// Computes the aggregated real-time value of a specific entry
1041    /// across all proprietors.
1042    ///
1043    /// Only includes commitments made via this index, not direct commitments
1044    /// to the entry digest.
1045    ///
1046    /// ## Returns
1047    /// - `Ok(Asset)` containing the total committed value for the entry
1048    /// - `Err(DispatchError)` if the entry does not exist
1049    fn get_entry_value(
1050        reason: &Self::Reason,
1051        index_of: &Self::Digest,
1052        entry_of: &Self::Digest,
1053    ) -> Result<Self::Asset, DispatchError> {
1054        Self::entry_exists(reason, index_of, entry_of)?;
1055        let iter = EntryMap::<T, I>::iter_prefix((reason, index_of, entry_of));
1056        let mut actual = Self::Asset::zero();
1057        for (who, _) in iter {
1058            let value =
1059                CommitHelpers::<T, I>::index_entry_commit_value(&who, reason, index_of, entry_of)?;
1060            actual = actual.saturating_add(value);
1061        }
1062        Ok(actual)
1063    }
1064
1065    /// Retrieves the real-time committed value of a specific entry
1066    /// for a given proprietor via an index.
1067    ///
1068    /// ## Returns
1069    /// - `Ok(Asset)` containing the proprietor's committed value for the entry
1070    /// - `Err(DispatchError)` if the entry does not exist
1071    fn get_entry_value_for(
1072        who: &Proprietor<T>,
1073        reason: &Self::Reason,
1074        index_of: &Self::Digest,
1075        entry_of: &Self::Digest,
1076    ) -> Result<Self::Asset, DispatchError> {
1077        let digest = Self::get_commit_digest(who, reason)?;
1078        Self::entry_exists(reason, index_of, entry_of)?;
1079        ensure!(digest == *index_of, Error::<T, I>::CommitNotFoundForEntry);
1080        let value =
1081            CommitHelpers::<T, I>::index_entry_commit_value(who, reason, index_of, entry_of)?;
1082        Ok(value)
1083    }
1084
1085    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1086    // ````````````````````````````````` CONSTRUCTORS ````````````````````````````````
1087    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1088
1089    /// Generates a unique digest for the given index using the proprietor and reason.
1090    ///
1091    /// ## Returns
1092    /// - `Ok(Digest)` with the newly generated digest.
1093    /// - `Err(DispatchError)` if digest generation fails
1094    fn gen_index_digest(
1095        from: &Proprietor<T>,
1096        reason: &Self::Reason,
1097        index: &Self::Index,
1098    ) -> Result<Self::Digest, DispatchError> {
1099        let target = from;
1100        let salt = frame_system::Pallet::<T>::account_nonce(from);
1101        let key_gen_item = IndexOfReason::<T, I>::new(*reason, index.clone());
1102
1103        let key =
1104            KeySeedFor::<Self::Digest, IndexOfReason<T, I>, T::Nonce, T::Hashing, T>::gen_key(
1105                target,
1106                &key_gen_item,
1107                salt,
1108            )
1109            .ok_or(Error::<T, I>::CannotGenerateDigest)?;
1110
1111        Ok(key)
1112    }
1113
1114    /// Prepares a new index instance from a list of entry digests and
1115    /// their corresponding shares.
1116    ///
1117    /// This function does **not** associate the index with a specific reason or
1118    /// proprietor internally. The caller is responsible for ensuring the index
1119    /// is correctly attached to a reason and, optionally, the creator.
1120    ///
1121    /// Entries with zero shares are silently ignored, as they carry no
1122    /// semantic contribution to the index.
1123    /// 
1124    /// Each entry digest must already be initiated (present in [`DigestMap`]
1125    /// under `reason`) before it can be added here, or it's rejected with
1126    /// `DigestNotFound` up front rather than failing later at commit-time.
1127    ///
1128    /// Future work: allow uninitiated digests and defer their initiation to 
1129    /// first deposit via the index, as [`CommitDeposit::place_digest_commit`]
1130    /// does for direct commitments today.
1131    ///
1132    /// Entry digests are not validated to be direct digests. If a commitment
1133    /// is placed on the index, each entry digest will be funded accordingly
1134    /// through the normal deposit routing.
1135    ///
1136    /// Nested cases-such as index entries referencing other indexes or pools-
1137    /// are not supported and may be treated as new direct digests when routed
1138    /// through [`CommitDeposit::deposit_to_digest`]. Callers are responsible
1139    /// for validating such cases if required.
1140    ///
1141    /// - `who`: The proprietor creating the index.
1142    /// - `reason`: The reason under which the index is being prepared.
1143    ///
1144    /// ## Returns
1145    /// - `Ok(Index)` containing the prepared index
1146    /// - `Err(DispatchError)` if preparation fails
1147    fn prepare_index(
1148        _who: &Proprietor<T>,
1149        reason: &Self::Reason,
1150        entries: &[(Self::Digest, Self::Shares)],
1151    ) -> Result<Self::Index, DispatchError> {
1152        // Initialize a new Entries collection for the index
1153        let mut entries_of = Vec::new();
1154        for (digest, shares) in entries {
1155            // Silently ignore non-share allocated entries
1156            if shares.is_zero() {
1157                continue;
1158            }
1159            // Reject uninitiated digests early instead of failing later at commit-time
1160            ensure!(
1161                DigestMap::<T, I>::contains_key((reason, &digest)),
1162                Error::<T,I>::EntryDigestNotInitiated
1163            );
1164            // Create a new entry with the given variant
1165            let entry_info = EntryInfo::<T, I>::new(digest.clone(), *shares, Default::default())?;
1166            // Add entry to the index, checking for maximum capacity
1167            entries_of.push(entry_info);
1168        }
1169        // Construct the final IndexInfo object
1170        let index_info = IndexInfo::<T, I>::new(&mut Entries::<T, I>::new(entries_of)?)?;
1171        Ok(index_info)
1172    }
1173
1174    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1175    // ``````````````````````````````````` MUTATORS ``````````````````````````````````
1176    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1177
1178    /// Sets a new index for the given digest at the given reason.
1179    ///
1180    /// - The caller must ensure that the provided digest is **unique** i.e.,
1181    /// generated via [`CommitIndex::gen_index_digest`] and does not collide
1182    /// with existing indexes in the system.
1183    /// - This function is intended **only** for creating new indexes.  
1184    /// - Mutations to existing indexes are **not supported** here.  
1185    /// - For updating an index, a new index digest should be generated via
1186    /// [`CommitIndex::set_entry_shares`]
1187    ///
1188    /// ## Returns
1189    /// - `Ok(())` if the index was successfully inserted
1190    /// - `Err(DispatchError)` with `IndexDigestTaken` if the digest already exists
1191    fn set_index(
1192        who: &Proprietor<T>,
1193        reason: &Self::Reason,
1194        index: &Self::Index,
1195        digest: &Self::Digest,
1196    ) -> DispatchResult {
1197        // Ensure the digest does not already exist
1198        ensure!(
1199            !Self::index_exists(reason, digest).is_ok(),
1200            Error::<T, I>::IndexDigestTaken
1201        );
1202        // Insert the new index into the storage map
1203        IndexMap::<T, I>::insert((reason, digest), index);
1204        Self::on_set_index(who, digest, reason, index);
1205        Ok(())
1206    }
1207
1208    /// Updates or sets the shares for a specific entry of
1209    /// an index, producing a new index.
1210    ///
1211    /// - If the entry already exists in the index:
1212    ///   - If `shares` is zero, the entry is removed.
1213    ///   - Otherwise, the entry's shares are updated while preserving its existing variant.
1214    /// - If the entry does not exist:
1215    ///   - If `shares` is zero, the operation is a no-op and the original index is returned.
1216    ///   - Otherwise, a new entry is added with the default [`Config::Position`] variant.
1217    ///
1218    /// A newly added entry digest must already be initiated (present in [`DigestMap`]
1219    /// under `reason`), or it's rejected with `DigestNotFound` up front rather than
1220    /// failing later at commit-time.
1221    /// 
1222    /// The newly added entry digest is not validated to be a direct digest and is
1223    /// accepted as provided through this function. If a commitment is placed on the
1224    /// index, it will be funded accordingly through normal deposit routing.
1225    ///
1226    /// Nested cases-such as entries referencing other indexes or pools-
1227    /// are not supported and may be treated as new direct digests when routed
1228    /// through [`CommitDeposit::deposit_to_digest`]. Callers are responsible
1229    /// for validating such cases if required.
1230    ///
1231    /// ## Returns
1232    /// - `Ok(Digest)` containing the resulting index digest (may be unchanged if no-op)
1233    /// - `Err(DispatchError)` if the operation fails
1234    fn set_entry_shares(
1235        who: &Proprietor<T>,
1236        reason: &Self::Reason,
1237        index_of: &Self::Digest,
1238        entry_of: &Self::Digest,
1239        shares: Self::Shares,
1240    ) -> Result<Self::Digest, DispatchError> {
1241        match Self::entry_exists(reason, index_of, entry_of).is_ok() {
1242            true => {
1243                if shares.is_zero() {
1244                    return CommitHelpers::<T, I>::remove_index_entry(
1245                        who, reason, index_of, entry_of,
1246                    );
1247                }
1248                let variant = &Self::get_entry_variant(reason, index_of, entry_of)?;
1249                // debug_assert!()
1250                CommitHelpers::<T, I>::set_index_entry(
1251                    who, reason, index_of, entry_of, shares, variant,
1252                )
1253            }
1254            false => {
1255                if shares.is_zero() {
1256                    return Ok(index_of.clone());
1257                }
1258                // Reject uninitiated digests early instead of failing later at commit-time
1259                ensure!(
1260                    DigestMap::<T, I>::contains_key((reason, &entry_of)),
1261                    Error::<T,I>::EntryDigestNotInitiated
1262                );
1263                CommitHelpers::<T, I>::set_index_entry(
1264                    who,
1265                    reason,
1266                    index_of,
1267                    entry_of,
1268                    shares,
1269                    &Default::default(),
1270                )
1271            }
1272        }
1273    }
1274
1275    /// Removes an index if all entries have no committed funds.
1276    ///
1277    /// ## Returns
1278    /// - `Ok(())` if the index was successfully removed
1279    /// - `Err(DispatchError)` with `IndexHasFunds` if any entry still has commitments
1280    fn reap_index(reason: &Self::Reason, index_of: &Self::Digest) -> DispatchResult {
1281        let index = Self::get_index(reason, index_of)?;
1282
1283        ensure!(index.principal().is_zero(), Error::<T, I>::IndexHasFunds);
1284
1285        // Check that all entries are empty; otherwise, cannot reap
1286        for entry in index.entries() {
1287            let digest = &entry.digest();
1288            let mut iter = EntryMap::<T, I>::iter_prefix((reason, index_of, digest));
1289            if let Some((_, _)) = iter.next() {
1290                debug_assert!(
1291                    false,
1292                    "index {:?} of reason {:?} top-level principal 
1293                    does not have deposits but its entry-map has commits 
1294                    for entry {:?} found during reap-index attempt",
1295                    index_of, reason, digest
1296                );
1297                return Err(Error::<T, I>::IndexHasFunds.into());
1298            }
1299        }
1300
1301        // Remove the index after all checks pass
1302        IndexMap::<T, I>::remove((reason, index_of));
1303
1304        // Clean removal since entry-digests are funded as direct-digests
1305        // Just that commits are stored in a different layout
1306        Self::on_reap_index(index_of, reason, Zero::zero());
1307        Ok(())
1308    }
1309
1310    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1311    // ```````````````````````````````````` HOOKS ````````````````````````````````````
1312    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1313
1314    /// Emits an event when an index is created.
1315    ///
1316    /// - Records the index digest, reason, and entry-share mappings.
1317    /// - Emits [`Event::IndexInitialized`] or [`Event::IndexInitialized`]
1318    ///   depending on whether multiple variants are supported by [`Config::Position`]
1319    /// - Emits these events only if [`Config::EmitEvents`] is `true`.
1320    fn on_set_index(
1321        _who: &Proprietor<T>,
1322        index_of: &Self::Digest,
1323        reason: &Self::Reason,
1324        _index: &Self::Index,
1325    ) {
1326        if T::EmitEvents::get() {
1327            #[cfg(any(feature = "dev", feature = "runtime-benchmarks"))]
1328            {
1329                let index = _index;
1330                let mut entries = Vec::new();
1331                for entry in index.entries() {
1332                    let digest = entry.digest().clone();
1333                    let shares = entry.shares();
1334                    let variant = &entry.variant();
1335                    entries.push((digest, shares, variant.clone()));
1336                }
1337
1338                Self::deposit_event(Event::<T, I>::IndexInitialized {
1339                    index_of: index_of.clone(),
1340                    reason: *reason,
1341                    entries,
1342                })
1343            }
1344
1345            #[cfg(not(any(feature = "dev", feature = "runtime-benchmarks")))]
1346            {
1347                Self::deposit_event(Event::<T, I>::IndexInitialized {
1348                    index_of: index_of.clone(),
1349                    reason: *reason,
1350                })
1351            }
1352        }
1353    }
1354
1355    /// Emits an event when an index is successfully reaped.
1356    ///
1357    /// Emits a [`Event::IndexReaped`] event if [`Config::EmitEvents`] is `true`.
1358    fn on_reap_index(index_of: &Self::Digest, reason: &Self::Reason, dust: Self::Asset) {
1359        debug_assert!(
1360            dust.is_zero(),
1361            "index digest {:?} of reason {:?} reaped with non-zero dust {:?}",
1362            index_of,
1363            reason,
1364            dust
1365        );
1366        if T::EmitEvents::get() {
1367            Self::deposit_event(Event::<T, I>::IndexReaped {
1368                index_of: index_of.clone(),
1369                reason: *reason,
1370            });
1371        }
1372    }
1373}
1374
1375// ===============================================================================
1376// ````````````````````````````````` COMMIT POOL `````````````````````````````````
1377// ===============================================================================
1378
1379/// Implements [`CommitPool`] for the pallet
1380impl<T: Config<I>, I: 'static> CommitPool<Proprietor<T>> for Pallet<T, I> {
1381    /// Pool struct representing a pool's internal structure.
1382    ///
1383    /// Contains the pool's balance, capital, slots, commission rate, and other
1384    /// metadata required for pool operations and value calculations.
1385    type Pool = PoolInfo<T, I>;
1386
1387    /// Commission rate for the pool.
1388    ///
1389    /// Represents the fraction of withdrawals collected by the pool manager
1390    /// as compensation for managing the pool.
1391    type Commission = T::Commission;
1392
1393    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1394    // ``````````````````````````````````` CHECKERS ``````````````````````````````````
1395    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1396
1397    /// Checks whether a pool exists for the given reason and digest.
1398    ///
1399    /// ## Returns
1400    /// - `Ok(())` if the pool exists
1401    /// - `Err(DispatchError)` if the pool does not exist
1402    fn pool_exists(reason: &Self::Reason, pool_of: &Self::Digest) -> DispatchResult {
1403        ensure!(
1404            PoolMap::<T, I>::contains_key((reason, pool_of)),
1405            Error::<T, I>::PoolNotFound
1406        );
1407        Ok(())
1408    }
1409
1410    /// Checks whether a specific slot exists within a given pool.
1411    ///
1412    /// ## Returns
1413    /// - `Ok(())` if the slot exists
1414    /// - `Err(DispatchError)` with `SlotOfPoolNotFound` if the slot does not exist
1415    fn slot_exists(
1416        reason: &Self::Reason,
1417        pool_of: &Self::Digest,
1418        slot_of: &Self::Digest,
1419    ) -> DispatchResult {
1420        let pool = Self::get_pool(reason, pool_of)?;
1421        for slot in pool.slots() {
1422            if slot.digest() == *slot_of {
1423                return Ok(());
1424            }
1425        }
1426        Err(Error::<T, I>::SlotOfPoolNotFound.into())
1427    }
1428
1429    /// Checks whether at least one pool exists for the given reason.
1430    ///
1431    /// ## Returns
1432    /// - `Ok(())` if at least one pool exists
1433    /// - `Err(DispatchError)` with `PoolNotFound` if no pools exist
1434    fn has_pool(reason: &Self::Reason) -> DispatchResult {
1435        ensure!(
1436            PoolMap::<T, I>::iter_prefix((reason,)).next().is_some(),
1437            Error::<T, I>::PoolNotFound
1438        );
1439        Ok(())
1440    }
1441
1442    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1443    // ``````````````````````````````````` GETTERS ```````````````````````````````````
1444    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1445
1446    /// Retrieves the manager of a given pool.
1447    ///
1448    /// Invariant enforced that every valid pool, must have a
1449    /// valid manager. For unmanaged distribution of commitments,
1450    /// [`CommitIndex`] exists.
1451    ///
1452    /// ## Returns
1453    /// - `Ok(Proprietor)` containing the pool manager's account id
1454    /// - `Err(DispatchError)` with `PoolManagerNotFound` if no manager is set
1455    fn get_manager(
1456        reason: &Self::Reason,
1457        pool_of: &Self::Digest,
1458    ) -> Result<Proprietor<T>, DispatchError> {
1459        Self::pool_exists(reason, pool_of)?;
1460        let pool_manager = PoolManager::<T, I>::get((reason, pool_of));
1461        debug_assert!(
1462            pool_manager.is_some(),
1463            "pool {:?} of reason {:?} exists but manager is not",
1464            pool_of,
1465            reason
1466        );
1467        let pool_manager = pool_manager.ok_or(Error::<T, I>::PoolManagerNotFound)?;
1468        Ok(pool_manager)
1469    }
1470
1471    /// Retrieves the commission rate of a given pool.
1472    ///
1473    /// ## Returns
1474    /// - `Ok(Commission)` containing the pool's commission rate
1475    /// - `Err(DispatchError)` with `PoolNotFound` if the pool does not exist
1476    fn get_commission(
1477        reason: &Self::Reason,
1478        pool_of: &Self::Digest,
1479    ) -> Result<Self::Commission, DispatchError> {
1480        let pool = Self::get_pool(reason, pool_of)?;
1481        Ok(pool.commission())
1482    }
1483
1484    /// Retrieves the pool information for a given reason and digest.
1485    ///
1486    /// ## Returns
1487    /// - `Ok(Pool)` containing the pool structure
1488    /// - `Err(DispatchError)` with `PoolNotFound` if the pool does not exist
1489    fn get_pool(
1490        reason: &Self::Reason,
1491        pool_of: &Self::Digest,
1492    ) -> Result<Self::Pool, DispatchError> {
1493        let pool = PoolMap::<T, I>::get((reason, pool_of)).ok_or(Error::<T, I>::PoolNotFound)?;
1494        Ok(pool)
1495    }
1496
1497    /// Retrieves all slot digests of a pool along with their respective shares.
1498    ///
1499    /// ## Returns
1500    /// - `Ok(Vec<(Digest, Shares)>)` containing each slot's digest and shares
1501    /// - `Err(DispatchError)` if the pool does not exist
1502    fn get_slots_shares(
1503        reason: &Self::Reason,
1504        pool_of: &Self::Digest,
1505    ) -> Result<Vec<(Self::Digest, Self::Shares)>, DispatchError> {
1506        let pool = Self::get_pool(reason, pool_of)?;
1507        let mut vec = Vec::new();
1508        for slot in pool.slots() {
1509            let slot_digest = &slot.digest();
1510            let shares = slot.shares();
1511            vec.push((slot_digest.clone(), shares))
1512        }
1513        Ok(vec)
1514    }
1515
1516    /// Computes the real-time value of a specific slot digest in a pool across all proprietors.
1517    ///
1518    /// ## Returns
1519    /// - `Ok(Asset)`containing the aggregated slot value
1520    /// - `Err(DispatchError)` if the slot does not exist
1521    fn get_slot_value(
1522        reason: &Self::Reason,
1523        pool_of: &Self::Digest,
1524        slot_of: &Self::Digest,
1525    ) -> Result<Self::Asset, DispatchError> {
1526        // Ensure the slot exists
1527        Pallet::<T, I>::slot_exists(reason, pool_of, slot_of)?;
1528
1529        // Retrieve pool info
1530        let pool_info = Pallet::<T, I>::get_pool(reason, pool_of)?;
1531        let slots = &pool_info.slots();
1532
1533        // Locate the entry within the index
1534        let mut slot_idx = None;
1535        for (i, slot) in slots.iter().enumerate() {
1536            if slot.digest() == *slot_of {
1537                slot_idx = Some(i);
1538            }
1539        }
1540        let Some(slot_idx) = slot_idx else {
1541            return Err(Error::<T, I>::SlotOfPoolNotFound.into());
1542        };
1543
1544        // Get the entry object and its variant
1545        let slot = slots.get(slot_idx);
1546
1547        debug_assert!(
1548            slot.is_some(),
1549            "pool {:?} of reason {:?} slot {:?} is found 
1550            during iteration, but vector get failed",
1551            pool_of,
1552            reason,
1553            slot_of
1554        );
1555        let slot = slot.ok_or(Error::<T, I>::SlotOfPoolNotFound)?;
1556        let digest = &slot.digest();
1557        let variant = &slot.variant();
1558
1559        let digest_info =
1560            DigestMap::<T, I>::get((reason, digest)).ok_or(Error::<T, I>::SlotDigestNotFound)?;
1561
1562        let balance = digest_info.get_balance(variant);
1563        debug_assert!(
1564            balance.is_some(),
1565            "pool-digest {:?} of reason {:?} slot {:?} variant {:?} balance 
1566            was not initiated properly in the balance vector 
1567            properly during slot-value retrieval",
1568            pool_of,
1569            reason,
1570            slot_of,
1571            variant,
1572        );
1573        let balance = balance.ok_or(Error::<T, I>::DigestVariantBalanceNotFound)?;
1574        let slot_commit = &slot.commit();
1575
1576        if *slot_commit == Default::default() {
1577            return Ok(Zero::zero());
1578        }
1579
1580        let take = receipt_active_value(balance, variant, digest, &slot.commit())?;
1581
1582        Ok(take)
1583    }
1584
1585    /// Computes the real-time value of a specific slot digest in a pool for a given proprietor.
1586    ///
1587    /// ## Returns
1588    /// - `Ok(Asset)` containing the proprietor's slot value
1589    /// - `Err(DispatchError)` if the slot does not exist
1590    fn get_slot_value_for(
1591        who: &Proprietor<T>,
1592        reason: &Self::Reason,
1593        pool_of: &Self::Digest,
1594        slot_of: &Self::Digest,
1595    ) -> Result<Self::Asset, DispatchError> {
1596        let digest = Self::get_commit_digest(who, reason)?;
1597        Self::slot_exists(reason, pool_of, slot_of)?;
1598        ensure!(digest == *pool_of, Error::<T, I>::CommitNotFoundForSlot);
1599        CommitHelpers::<T, I>::pool_slot_commit_value(who, reason, pool_of, slot_of)
1600    }
1601
1602    /// Computes the real-time value of a pool-commit for a given proprietor.
1603    ///
1604    /// ## Returns
1605    /// - `Ok(Asset)` containing the proprietor's pool value
1606    /// - `Err(DispatchError)` if the slot does not exist
1607    fn get_pool_value_for(
1608        who: &Proprietor<T>,
1609        reason: &Self::Reason,
1610        pool_of: &Self::Digest,
1611    ) -> Result<Self::Asset, DispatchError> {
1612        let digest = Self::get_commit_digest(who, reason)?;
1613        Self::pool_exists(reason, pool_of)?;
1614        ensure!(digest == *pool_of, Error::<T, I>::CommitNotFoundForSlot);
1615        CommitHelpers::<T, I>::pool_commit_value(who, reason, pool_of)
1616    }
1617
1618    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1619    // ````````````````````````````````` CONSTRUCTORS ````````````````````````````````
1620    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1621
1622    /// Generates a unique digest for a pool derived from a given index.
1623    ///
1624    /// Pools are created from indexes, and each pool digest must be unique. This function
1625    /// deterministically derives a digest using:
1626    /// - The caller (`who`) as the target
1627    /// - The `reason` under which the pool is created
1628    /// - The pool's internal entries and specified `commission`
1629    /// - The caller's account nonce as a salt
1630    ///
1631    /// This digest can then be used to create or reference the pool in the system.
1632    ///
1633    /// ## Returns
1634    /// - `Ok(Digest)` containing the unique pool digest
1635    /// - `Err(DispatchError)` if digest generation fails
1636    fn gen_pool_digest(
1637        who: &Proprietor<T>,
1638        reason: &Self::Reason,
1639        index_of: &Self::Digest,
1640        commission: Self::Commission,
1641    ) -> Result<Self::Digest, DispatchError> {
1642        let pool_index = Self::get_index(reason, index_of)?;
1643        let actual_pool = PoolInfo::<T, I>::new(pool_index.reveal_entries(), commission);
1644        // Since the function only accumulates capital and straight conversion
1645        // It should pass, unless some commission checks are implied inside
1646        debug_assert!(
1647            actual_pool.is_ok(),
1648            "pool-info construction for reason {:?}
1649            from a already valid index {:?} entries and commission {:?} has failed",
1650            reason,
1651            index_of,
1652            commission
1653        );
1654        let actual_pool = actual_pool?;
1655        let target = who;
1656        let salt = frame_system::Pallet::<T>::account_nonce(who);
1657        let key_gen_item = PoolOfReason::<T, I>::new(*reason, actual_pool.clone());
1658        let key = KeySeedFor::<Self::Digest, PoolOfReason<T, I>, T::Nonce, T::Hashing, T>::gen_key(
1659            target,
1660            &key_gen_item,
1661            salt,
1662        )
1663        .ok_or(Error::<T, I>::CannotGenerateDigest)?;
1664        Ok(key)
1665    }
1666
1667    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1668    // ``````````````````````````````````` MUTATORS ``````````````````````````````````
1669    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1670
1671    /// Creates a new pool based on an existing index with a specified commission rate.
1672    ///
1673    /// Pools are immutable with respect to their commission. Any changes to entries
1674    /// require modifying slots directly or creating a new pool.
1675    ///
1676    /// - Retrieves the index information to populate the pool slots.
1677    /// - Converts each index entry into a pool slot, preserving the shares.
1678    /// - Sets the caller as the manager of the new pool.
1679    ///
1680    /// ## Returns
1681    /// - `Ok(())` if the pool was successfully created
1682    /// - `Err(DispatchError)` with `PoolDigestTaken` if a pool with this digest already exists
1683    fn set_pool(
1684        who: &Proprietor<T>,
1685        reason: &Self::Reason,
1686        pool_of: &Self::Digest,
1687        index_of: &Self::Digest,
1688        commission: Self::Commission,
1689    ) -> DispatchResult {
1690        // Check if the pool already exists
1691        ensure!(
1692            Self::pool_exists(reason, pool_of).is_err(),
1693            Error::<T, I>::PoolDigestTaken
1694        );
1695
1696        // Retrieve index information to initialize the pool slots
1697        let index_info = Self::get_index(reason, index_of)?;
1698
1699        // Create a new pool object from index entries and the specified commission
1700        let pool_info = PoolInfo::<T, I>::new(index_info.reveal_entries(), commission);
1701
1702        // Since the function only accumulates capital and straight conversion
1703        // It should pass, unless some commission checks are implied inside
1704        debug_assert!(
1705            pool_info.is_ok(),
1706            "pool-info construction for new pool {:?} of reason {:?}
1707            from a already valid index {:?} entries and commission {:?} has failed",
1708            pool_of,
1709            reason,
1710            index_of,
1711            commission
1712        );
1713
1714        let pool_info = pool_info?;
1715
1716        // Insert the new pool into storage
1717        PoolMap::<T, I>::insert((reason, pool_of), &pool_info);
1718
1719        // Assign the caller as the manager of the pool
1720        let result = Self::set_pool_manager(reason, pool_of, who);
1721
1722        debug_assert!(
1723            result.is_ok(),
1724            "recently created pool {:?} info inserted but 
1725            later logic set poolmanager {:?} failed",
1726            pool_of,
1727            who
1728        );
1729
1730        result?;
1731
1732        Self::on_set_pool(who, pool_of, reason, &pool_info);
1733        Ok(())
1734    }
1735
1736    /// Sets or updates the manager for a specific pool.
1737    ///
1738    /// The manager is responsible for handeling pool operations including risk management,
1739    /// applying strategies on behalf of pool participants, and earning commission
1740    /// based on the pool's rules.
1741    ///
1742    /// ### Returns
1743    /// - `Ok(())` if the manager was successfully set
1744    /// - `Err(DispatchError)` if the pool does not exist
1745    fn set_pool_manager(
1746        reason: &Self::Reason,
1747        pool_of: &Self::Digest,
1748        manager: &Proprietor<T>,
1749    ) -> DispatchResult {
1750        Self::pool_exists(reason, pool_of)?;
1751        PoolManager::<T, I>::insert((reason, pool_of), manager);
1752        Self::on_set_manager(pool_of, reason, manager);
1753        Ok(())
1754    }
1755
1756    /// Sets or updates the shares of a specific slot within a pool.
1757    ///
1758    /// Unlike indexes, pools are mutable and managed internally, so modifying a slot
1759    /// does **not** produce a new digest. Each mutation releases and recovers the pool
1760    /// to maintain real-time balances.
1761    ///
1762    /// If the slot already exists:
1763    /// - A zero share value removes the slot from the pool.
1764    /// - A non-zero share value updates the slot's shares while keeping its variant.
1765    ///
1766    /// A newly added slot digest must already be initiated (present in [`DigestMap`]
1767    /// under `reason`), or it's rejected with `DigestNotFound` up front rather than
1768    /// failing later at commit-time.
1769    /// 
1770    /// Nested cases-such as pool slots referencing other pools or indexes
1771    /// are not supported and may be treated as new direct digests when routed
1772    /// through [`CommitDeposit::deposit_to_digest`]. Callers are responsible for
1773    /// validating such cases if required.
1774    ///
1775    /// If the slot does not exist:
1776    /// - A zero share value returns early without any changes.
1777    /// - A non-zero share value creates a new slot with the default variant.
1778    ///
1779    /// DispatchError if fails
1780    fn set_slot_shares(
1781        who: &Proprietor<T>,
1782        reason: &Self::Reason,
1783        pool_of: &Self::Digest,
1784        slot_of: &Self::Digest,
1785        shares: Self::Shares,
1786    ) -> DispatchResult {
1787        match Self::slot_exists(reason, pool_of, slot_of).is_ok() {
1788            true => {
1789                let variant = Self::get_slot_variant(reason, pool_of, slot_of);
1790                debug_assert!(
1791                    variant.is_ok(),
1792                    "slot {:?} exists for pool {:?} of reason {:?} 
1793                    but its variant (must-required) is unavailable",
1794                    slot_of,
1795                    pool_of,
1796                    reason
1797                );
1798
1799                let variant = variant?;
1800
1801                match shares.is_zero() {
1802                    true => CommitHelpers::<T, I>::remove_pool_slot(who, reason, pool_of, slot_of)?,
1803                    false => CommitHelpers::<T, I>::set_pool_slot(
1804                        who, reason, pool_of, slot_of, shares, &variant,
1805                    )?,
1806                }
1807            }
1808            false => {
1809                if shares.is_zero() {
1810                    return Ok(());
1811                }
1812                // Reject uninitiated digests early instead of failing later at commit-time
1813                ensure!(
1814                    DigestMap::<T, I>::contains_key((reason, &slot_of)),
1815                    Error::<T,I>::SlotDigestNotInitiated
1816                );
1817                CommitHelpers::<T, I>::set_pool_slot(
1818                    who,
1819                    reason,
1820                    pool_of,
1821                    slot_of,
1822                    shares,
1823                    &T::Position::default(),
1824                )?
1825            }
1826        }
1827        Self::on_set_slot_shares(pool_of, reason, slot_of, shares);
1828        Ok(())
1829    }
1830
1831    /// Removes a pool from the system if all deposits have been withdrawn.
1832    ///
1833    /// Any residual funds (dust) remaining in the pool are automatically refunded
1834    /// to the pool manager.
1835    ///
1836    /// This function doesn't ensures the pool's current manager as it should be
1837    /// validated elsewhere if required.
1838    ///
1839    /// ## Returns
1840    /// - `Ok(())` if the pool was successfully removed
1841    /// - `Err(DispatchError)` otherwise
1842    fn reap_pool(reason: &Self::Reason, pool_of: &Self::Digest) -> DispatchResult {
1843        let pool = Self::get_pool(reason, pool_of)?;
1844        let balance = &pool.balance();
1845
1846        // Cannot reap a pool if deposits still exist
1847        if has_deposits(balance, &Default::default(), pool_of).is_ok() {
1848            return Err(Error::<T, I>::PoolHasFunds.into());
1849        }
1850
1851        // Refund any leftover effective balance to the manager
1852        let effective = balance_total(balance, &Default::default(), pool_of)?;
1853        if !effective.is_zero() {
1854            let imbalance = AssetDelta::<T, I> {
1855                deposit: Zero::zero(),
1856                withdraw: effective,
1857            };
1858            let manager = Self::get_manager(reason, pool_of);
1859            debug_assert!(
1860                manager.is_ok(),
1861                "pool {:?} for reason {:?} exists but manager is not",
1862                pool_of,
1863                reason
1864            );
1865            let manager = manager?;
1866            let dust_retn = CommitHelpers::<T, I>::resolve_imbalance(&manager, imbalance)?;
1867            CommitHelpers::<T, I>::sub_from_total_value(reason, dust_retn)?;
1868        }
1869        // Remove pool and its manager from storage
1870        PoolMap::<T, I>::remove((reason, pool_of));
1871        PoolManager::<T, I>::remove((reason, pool_of));
1872
1873        // Managers are redunded with remaining dust unlike digests which
1874        // doesn't have any informal nominee
1875        Self::on_reap_pool(pool_of, reason, Zero::zero());
1876        Ok(())
1877    }
1878
1879    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1880    // ```````````````````````````````````` HOOKS ````````````````````````````````````
1881    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1882
1883    /// Emits an event when a new pool is created or initialized.
1884    ///
1885    /// - Includes all underlying slots and the commission set for the pool manager.
1886    ///
1887    /// - Emits [`Event::PoolInitialized`] or [`Event::PoolInitialized`]
1888    ///   depending on whether multiple variants are supported by [`Config::Position`].
1889    /// - Emits these events only if [`Config::EmitEvents`] is `true`.
1890    fn on_set_pool(
1891        _who: &Proprietor<T>,
1892        pool_of: &Self::Digest,
1893        reason: &Self::Reason,
1894        pool: &Self::Pool,
1895    ) {
1896        if T::EmitEvents::get() {
1897            #[cfg(any(feature = "dev", feature = "runtime-benchmarks"))]
1898            {
1899                let mut slots = Vec::new();
1900                for slot in pool.slots() {
1901                    let slot_digest = slot.digest().clone();
1902                    let shares = slot.shares();
1903                    let variant = &slot.variant();
1904                    slots.push((slot_digest, shares, variant.clone()));
1905                }
1906                let commission = pool.commission();
1907                Self::deposit_event(Event::<T, I>::PoolInitialized {
1908                    pool_of: pool_of.clone(),
1909                    reason: *reason,
1910                    commission,
1911                    slots,
1912                });
1913            }
1914
1915            #[cfg(not(any(feature = "dev", feature = "runtime-benchmarks")))]
1916            {
1917                let commission = pool.commission();
1918                Self::deposit_event(Event::<T, I>::PoolInitialized {
1919                    pool_of: pool_of.clone(),
1920                    reason: *reason,
1921                    commission,
1922                });
1923            }
1924        }
1925    }
1926
1927    /// Emits an event when the manager of a pool is set or updated.
1928    ///
1929    /// Emits a [`Event::PoolManager`] event if [`Config::EmitEvents`] is `true`.
1930    fn on_set_manager(pool_of: &Self::Digest, reason: &Self::Reason, manager: &Proprietor<T>) {
1931        if T::EmitEvents::get() {
1932            Self::deposit_event(Event::<T, I>::PoolManager {
1933                pool_of: pool_of.clone(),
1934                reason: *reason,
1935                manager: manager.clone(),
1936            });
1937        }
1938    }
1939
1940    /// Emits an event when the shares of a specific slot in a pool are updated.
1941    ///
1942    /// This method delagates itself to [`PoolVariant::on_set_slot_of_variant`]
1943    /// with the default position variant.
1944    #[inline]
1945    fn on_set_slot_shares(
1946        pool_of: &Self::Digest,
1947        reason: &Self::Reason,
1948        slot_of: &Self::Digest,
1949        shares: Self::Shares,
1950    ) {
1951        Self::on_set_slot_of_variant(pool_of, reason, slot_of, Some(shares), &Default::default());
1952    }
1953
1954    /// Emits an event when a pool is reaped (removed).
1955    ///
1956    /// Emits a [`Event::PoolReaped`] event if [`Config::EmitEvents`] is `true`.
1957    fn on_reap_pool(pool_of: &Self::Digest, reason: &Self::Reason, dust: Self::Asset) {
1958        debug_assert!(
1959            dust.is_zero(),
1960            "pool digest {:?} of reason {:?} reaped with non-zero dust {:?}",
1961            pool_of,
1962            reason,
1963            dust
1964        );
1965        if T::EmitEvents::get() {
1966            Self::deposit_event(Event::<T, I>::PoolReaped {
1967                pool_of: pool_of.clone(),
1968                reason: *reason,
1969            });
1970        }
1971    }
1972}
1973
1974// ===============================================================================
1975// ```````````````````````````````` COMMIT VARIANT ```````````````````````````````
1976// ===============================================================================
1977
1978/// Implements [`CommitVariant`] for the pallet
1979impl<T: Config<I>, I: 'static> CommitVariant<Proprietor<T>> for Pallet<T, I> {
1980    /// Defines the commitment position variant type for a proprietor.
1981    ///
1982    /// Acts as the logical "stance" or directional disposition of a commitment.
1983    type Position = T::Position;
1984
1985    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1986    // ``````````````````````````````````` CHECKERS ``````````````````````````````````
1987    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1988
1989    /// Validates whether a digest-variant value can be set.
1990    ///
1991    /// Same as the default trait validation, but extended with additional
1992    /// checks against the underlying balance model to ensure minting or
1993    /// reaping can actually be applied.
1994    ///
1995    /// In the lazy balance model, value updates are interpreted as:
1996    /// - Increase -> mint
1997    /// - Decrease -> reap
1998    ///
1999    /// Missing digest or variant state is treated as a default
2000    /// (fresh) balance, but validation still depends on the underlying
2001    /// lazy balance model and may fail.
2002    ///
2003    /// ## Returns
2004    /// - `Ok(())` if validation succeeds
2005    /// - `Err(DispatchError)` if any constraint is violated
2006    fn can_set_digest_variant_value(
2007        reason: &Self::Reason,
2008        digest: &Self::Digest,
2009        value: Self::Asset,
2010        variant: &Self::Position,
2011        qualifier: &Self::Intent,
2012    ) -> DispatchResult {
2013        let current = Self::get_digest_variant_value(reason, digest, variant)?;
2014        match current.cmp(&value) {
2015            Ordering::Less => {
2016                // Mint path (increase)
2017                let balance = DigestMap::<T, I>::get((reason, digest))
2018                    .and_then(|digest_info| digest_info.get_balance(variant).cloned())
2019                    .unwrap_or_default();
2020                let limits = mint_limits_of(&balance, variant, digest, qualifier)?;
2021                let mintable = value.saturating_sub(current);
2022                ensure!(
2023                    <Self::Limits as Extent>::contains(&limits, mintable),
2024                    Error::<T, I>::MintingOffLimits,
2025                );
2026                can_mint(&balance, variant, digest, &mintable, qualifier)?;
2027            }
2028            Ordering::Greater => {
2029                // Reap path (decrease)
2030                let balance = DigestMap::<T, I>::get((reason, digest))
2031                    .and_then(|digest_info| digest_info.get_balance(variant).cloned())
2032                    .unwrap_or_default();
2033                let limits = reap_limits_of(&balance, variant, digest, qualifier)?;
2034                let reapable = current.saturating_sub(value);
2035                ensure!(
2036                    <Self::Limits as Extent>::contains(&limits, reapable),
2037                    Error::<T, I>::ReapingOffLimits,
2038                );
2039                can_reap(&balance, variant, digest, &reapable, qualifier)?;
2040            }
2041            Ordering::Equal => {
2042                // No-op
2043            }
2044        }
2045        Ok(())
2046    }
2047
2048    /// Validates whether a new commitment can be placed for a specific variant.
2049    ///
2050    /// Same as the default trait validation, but extended with an additional
2051    /// check against the underlying balance model to ensure the deposit can
2052    /// actually be applied.
2053    ///
2054    /// Missing digest or variant state is treated as a fresh balance; in such
2055    /// cases, a default balance is used to derive limits and validate the deposit.
2056    ///
2057    /// ## Returns
2058    /// - `Ok(())` if validation succeeds
2059    /// - `Err(DispatchError)` if any constraint is violated
2060    fn can_place_commit_of_variant(
2061        who: &Proprietor<T>,
2062        reason: &Self::Reason,
2063        digest: &Self::Digest,
2064        variant: &Self::Position,
2065        value: Self::Asset,
2066        qualifier: &Self::Intent,
2067    ) -> DispatchResult {
2068        ensure!(
2069            Self::commit_exists(who, reason).is_err(),
2070            Error::<T, I>::CommitAlreadyExists
2071        );
2072        let max = Self::available_funds(who);
2073        ensure!(max >= value, Error::<T, I>::InsufficientFunds);
2074        let balance = DigestMap::<T, I>::get((reason, digest))
2075            .and_then(|digest_info| digest_info.get_balance(variant).cloned())
2076            .unwrap_or_default();
2077
2078        let limits = deposit_limits_of(&balance, variant, digest, qualifier)?;
2079        ensure!(
2080            <Self::Limits as Extent>::contains(&limits, value),
2081            Error::<T, I>::PlacingOffLimits
2082        );
2083        can_deposit(&balance, variant, digest, &value, qualifier)
2084    }
2085
2086    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2087    // ``````````````````````````````````` GETTERS ```````````````````````````````````
2088    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2089
2090    /// Retrieves the current commitment variant for a
2091    /// proprietor and reason.
2092    ///
2093    /// In-case of indexes and pools its always the default variant of
2094    /// [`Config::Position`] since its entries and slots carry the actual
2095    /// variants for which this commit is distributed.
2096    ///
2097    /// ## Returns
2098    /// - `Ok(Position)` containing the commitment's variant
2099    /// - `Err(DispatchError)`  with `CommitNotFound` if no commitment exists
2100    fn get_commit_variant(
2101        who: &Proprietor<T>,
2102        reason: &Self::Reason,
2103    ) -> Result<Self::Position, DispatchError> {
2104        let Some(commit_info) = CommitMap::<T, I>::get((who, reason)) else {
2105            return Err(Error::<T, I>::CommitNotFound.into());
2106        };
2107        Ok(commit_info.variant())
2108    }
2109
2110    /// Retrieves the real-time effective value of a specific digest
2111    /// variant for a given reason.
2112    ///
2113    /// ## Returns
2114    /// - `Ok(Asset)` containing the variant's effective value,
2115    /// or zero if the variant does not exist
2116    /// - `Err(DispatchError)` with `DigestNotFound` if the digest
2117    /// does not exist
2118    fn get_digest_variant_value(
2119        reason: &Self::Reason,
2120        digest: &Self::Digest,
2121        variant: &Self::Position,
2122    ) -> Result<Self::Asset, DispatchError> {
2123        let digest_info =
2124            DigestMap::<T, I>::get((reason, digest)).ok_or(Error::<T, I>::DigestNotFound)?;
2125        // Return effective balance if present, otherwise zero
2126        let Some(balance) = digest_info.get_balance(variant) else {
2127            return balance_total::<T, I>(&Default::default(), variant, digest);
2128        };
2129
2130        balance_total(balance, variant, digest)
2131    }
2132
2133    /// Derives minting limits for a specific digest variant.
2134    ///
2135    /// Fetches the current lazy balance of the given `(reason, digest, variant)`
2136    /// and computes the applicable minting limits using the underlying balance model.
2137    ///
2138    /// If the digest not exists nor the variant has an initialized balance,
2139    /// the limits are derived using a default (empty) balance.
2140    ///
2141    /// ## Returns
2142    /// - `Ok(Limits)` containing the derived minting constraints
2143    /// - `Err(DispatchError)` if the limit derivation fails
2144    fn digest_mint_limits_of_variant(
2145        digest: &Self::Digest,
2146        reason: &Self::Reason,
2147        variant: &Self::Position,
2148        qualifier: &Self::Intent,
2149    ) -> Result<Self::Limits, DispatchError> {
2150        let balance = DigestMap::<T, I>::get((reason, digest))
2151            .and_then(|digest_info| digest_info.get_balance(variant).cloned())
2152            .unwrap_or_default();
2153        let limits = mint_limits_of(&balance, variant, digest, qualifier)?;
2154        Ok(limits)
2155    }
2156
2157    /// Derives reaping limits for a specific digest variant.
2158    ///
2159    /// Fetches the current lazy balance of the given `(reason, digest, variant)`
2160    /// and computes the applicable reaping limits using the underlying balance model.
2161    ///
2162    /// If the digest does not exists nor the variant has a initialized balance,
2163    /// limits are derived using a default (empty) balance.
2164    ///
2165    /// ## Returns
2166    /// - `Ok(Limits)` containing the derived reaping constraints
2167    /// - `Err(DispatchError)` if the limit derivation fails
2168    fn digest_reap_limits_of_variant(
2169        digest: &Self::Digest,
2170        reason: &Self::Reason,
2171        variant: &Self::Position,
2172        qualifier: &Self::Intent,
2173    ) -> Result<Self::Limits, DispatchError> {
2174        let balance = DigestMap::<T, I>::get((reason, digest))
2175            .and_then(|digest_info| digest_info.get_balance(variant).cloned())
2176            .unwrap_or_default();
2177
2178        let limits = reap_limits_of(&balance, variant, digest, qualifier)?;
2179        Ok(limits)
2180    }
2181
2182    /// Derives the place commit limits for the given commitment-params.
2183    ///
2184    /// Fetches the current lazy balance of the given `(reason, digest, variant)`
2185    /// and computes the applicable deposit limits using the underlying
2186    /// balance model.
2187    ///
2188    /// - For **Direct digests**, limits are derived based on existing digest balance.
2189    /// - For **Index or Pool digests**, no digest-level balance info exists,
2190    ///   hence limits are treated as **unbounded**.
2191    ///
2192    /// If the direct digest does not exist or the variant has no initialized balance,
2193    /// limits are derived using a default (empty) balance.
2194    ///
2195    /// ## Returns
2196    /// - `Ok(Limits)` containing the derived placement constraints
2197    /// - `Err(DispatchError)` if the limit derivation fails
2198    fn place_commit_limits_of_variant(
2199        _who: &Proprietor<T>,
2200        reason: &Self::Reason,
2201        digest: &Self::Digest,
2202        variant: &Self::Position,
2203        qualifier: &Self::Intent,
2204    ) -> Result<Self::Limits, DispatchError> {
2205        let balance = DigestMap::<T, I>::get((reason, digest))
2206            .and_then(|digest_info| digest_info.get_balance(variant).cloned())
2207            .unwrap_or_default();
2208
2209        let limits = deposit_limits_of(&balance, variant, digest, qualifier)?;
2210        Ok(limits)
2211    }
2212
2213    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2214    // ``````````````````````````````````` MUTATORS ``````````````````````````````````
2215    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2216
2217    /// Sets the effective value of a specific digest variant for a given reason.
2218    ///
2219    /// It is expected that the variant is initiated via a commitment before setting it.
2220    ///
2221    /// Automatically handles minting (for increases) or reaping (for decreases) of assets,
2222    /// and updates the total reason value accordingly. This operation directly modifies
2223    /// the low-level digest variant balance without affecting other variants.
2224    ///
2225    /// The `qualifier` influences how minting/reaping is applied and may affect the
2226    /// final value that is actually set.
2227    ///
2228    /// ## Returns
2229    /// - `Ok(Asset)` containing the resulting value of the digest-variant after update
2230    /// - `Err(DispatchError)` if the operation fails
2231    fn set_digest_variant_value(
2232        reason: &Self::Reason,
2233        digest: &Self::Digest,
2234        value: Self::Asset,
2235        variant: &Self::Position,
2236        qualifier: &Self::Intent,
2237    ) -> Result<Self::Asset, DispatchError> {
2238        let new =
2239            DigestMap::<T, I>::mutate((reason, digest), |result| -> Result<_, DispatchError> {
2240                let digest_info = result.as_mut().ok_or(Error::<T, I>::DigestNotFound)?;
2241                // Get the balance of the variant via its index
2242                let digest_of = digest_info
2243                    .mut_balance(variant)
2244                    // A deposit is required for setting, else it will be unfair to reward a digest
2245                    .ok_or(Error::<T, I>::DigestVariantBalanceNotFound)?;
2246                let current = balance_total(digest_of, variant, digest)?;
2247                let new = match current.cmp(&value) {
2248                    Ordering::Less => {
2249                        // Increase value: mint additional assets
2250                        // Determine value to mint accurately
2251                        let try_actual = value.saturating_sub(current);
2252                        // Via the mutable lazy-balance, mint the required value
2253                        let actual = mint(digest_of, variant, digest, &try_actual, qualifier)?;
2254                        // Asset is inflated via commitment-system so reflect via `AssetToIssue`
2255                        // Later when commitments in this inflated variant balance is resolved this will
2256                        // will minted to its underlying fungible system.
2257                        AssetToIssue::<T, I>::mutate(|total_issued| -> DispatchResult {
2258                            *total_issued = total_issued
2259                                .checked_add(&actual)
2260                                .ok_or(Error::<T, I>::MaxAssetIssued)?;
2261                            Ok(())
2262                        })?;
2263                        // Add to reason's total committed value since value is inflated
2264                        CommitHelpers::<T, I>::add_to_total_value(reason, actual)?;
2265                        current.saturating_add(actual)
2266                    }
2267                    Ordering::Greater => {
2268                        // Decrease value: reap excess assets
2269                        // Determine value to reap accurately
2270                        let try_actual = current.saturating_sub(value);
2271                        // Via the mutable lazy-balance, reap the required value
2272                        let actual = reap(digest_of, variant, digest, &try_actual, qualifier)?;
2273                        // Asset is deflated (burned) via commitment-system so reflect via `AssetToReap`
2274                        // Later when commitments in this deflated variant balance is resolved this will
2275                        // will reap the burned balance from its underlying fungible system.
2276                        AssetToReap::<T, I>::mutate(|total_to_reap| -> DispatchResult {
2277                            *total_to_reap = total_to_reap
2278                                .checked_add(&actual)
2279                                .ok_or(Error::<T, I>::MaxAssetReaped)?;
2280                            Ok(())
2281                        })?;
2282                        // Subtract reason's total committed value since value is deflated
2283                        CommitHelpers::<T, I>::sub_from_total_value(reason, actual)?;
2284                        current.saturating_sub(actual)
2285                    }
2286                    core::cmp::Ordering::Equal => {
2287                        // No change needed
2288                        current
2289                    }
2290                };
2291                Self::on_set_digest_variant(digest, reason, new, variant);
2292                Ok(new)
2293            })?;
2294        Ok(new)
2295    }
2296
2297    /// Places a commitment with a specific variant to a digest.
2298    ///
2299    /// This function validates the commitment eligibility, determines the digest model
2300    /// (Direct, Index, or Pool), and registers the commitment with the specified variant
2301    /// and amount according to the provided precision and fortitude parameters.
2302    ///
2303    /// Zero-value (marker) commitments are not allowed and will be rejected.
2304    ///
2305    /// If the digest does not yet exist in the system, this function assumes it to
2306    /// be a **direct digest** (since indexes and pools require prior initialization)
2307    /// and initializes the commitment accordingly.
2308    ///
2309    /// Callers must ensure that such digests are valid within their intended
2310    /// commitment context and agreement.
2311    ///
2312    /// ## Returns
2313    /// - `Ok(Asset)` containing the actual committed amount
2314    /// - `Err(DispatchError)` if placement fails
2315    fn place_commit_of_variant(
2316        who: &Proprietor<T>,
2317        reason: &Self::Reason,
2318        digest: &Self::Digest,
2319        value: Self::Asset,
2320        variant: &Self::Position,
2321        qualifier: &Self::Intent,
2322    ) -> Result<Self::Asset, DispatchError> {
2323        ensure!(
2324            Self::commit_exists(who, reason).is_err(),
2325            Error::<T, I>::CommitAlreadyExists
2326        );
2327        ensure!(!value.is_zero(), Error::<T, I>::MarkerCommitNotAllowed);
2328        let digest_model =
2329            Self::determine_digest(digest, reason).unwrap_or(DigestVariant::Direct(digest.clone()));
2330        let actual = CommitHelpers::<T, I>::place_commit_of(
2331            who,
2332            reason,
2333            &digest_model,
2334            value,
2335            variant,
2336            qualifier,
2337        )?;
2338        Self::on_place_commit_on_variant(who, reason, digest, actual, variant);
2339        Ok(actual)
2340    }
2341
2342    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2343    // ```````````````````````````````````` HOOKS ````````````````````````````````````
2344    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2345
2346    /// Emits an event indicating that a commitment has been placed
2347    /// for a specific digest variant and proprietor.
2348    ///
2349    /// The digest is verified and classified using
2350    /// [`DigestModel::determine_digest`].
2351    ///
2352    /// Emits [`Event::CommitPlaced`] event if [`Config::EmitEvents`] is `true`.
2353    fn on_place_commit_on_variant(
2354        who: &Proprietor<T>,
2355        reason: &Self::Reason,
2356        digest: &Self::Digest,
2357        value: Self::Asset,
2358        variant: &Self::Position,
2359    ) {
2360        if T::EmitEvents::get() {
2361            #[cfg(any(feature = "dev", feature = "runtime-benchmarks"))]
2362            {
2363                let Ok(digest_model) = Self::determine_digest(digest, reason) else {
2364                    return;
2365                };
2366                Self::deposit_event(Event::<T, I>::CommitPlaced {
2367                    who: who.clone(),
2368                    reason: *reason,
2369                    model: digest_model,
2370                    value: value,
2371                    variant: variant.clone(),
2372                })
2373            }
2374
2375            #[cfg(not(any(feature = "dev", feature = "runtime-benchmarks")))]
2376            {
2377                Self::deposit_event(Event::<T, I>::CommitPlaced {
2378                    who: who.clone(),
2379                    reason: *reason,
2380                    digest: digest.clone(),
2381                    value: value,
2382                    variant: variant.clone(),
2383                })
2384            }
2385        }
2386    }
2387
2388    /// Emits an event when a commit for a specific digest
2389    /// variant is updated.
2390    ///
2391    /// This method delagates itself to [`CommitVariant::on_place_commit_on_variant`]
2392    /// with the default position variant.
2393    ///
2394    /// [`Self::set_commit_variant`] is semantically similar to resolving and
2395    /// placing a new-commitment on a different variant internally.
2396    #[inline]
2397    fn on_set_commit_variant(
2398        who: &Proprietor<T>,
2399        reason: &Self::Reason,
2400        digest: &Self::Digest,
2401        value: Self::Asset,
2402        variant: &Self::Position,
2403    ) {
2404        Self::on_place_commit_on_variant(who, reason, digest, value, variant)
2405    }
2406
2407    /// Emits an event when a digest variant's effective value is updated.
2408    ///
2409    /// This is typically triggered after a reward, penalty, or manual
2410    /// adjustment applied directly to a digest variant.
2411    ///
2412    /// Emits [`Event::DigestInfo`] event if [`Config::EmitEvents`] is `true`.
2413    fn on_set_digest_variant(
2414        digest: &Self::Digest,
2415        reason: &Self::Reason,
2416        value: Self::Asset,
2417        variant: &Self::Position,
2418    ) {
2419        if T::EmitEvents::get() {
2420            Self::deposit_event(Event::<T, I>::DigestInfo {
2421                digest: digest.clone(),
2422                reason: *reason,
2423                value: value,
2424                variant: variant.clone(),
2425            });
2426        }
2427    }
2428}
2429
2430// ===============================================================================
2431// ```````````````````````````````` INDEX VARIANT ````````````````````````````````
2432// ===============================================================================
2433
2434/// Implements [`IndexVariant`] for the pallet
2435impl<T: Config<I>, I: 'static> IndexVariant<Proprietor<T>> for Pallet<T, I> {
2436    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2437    // ````````````````````````````````` CONSTRUCTORS ````````````````````````````````
2438    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2439
2440    /// Prepares a new index object from a list of entry digests, their shares,
2441    /// and variants.
2442    ///
2443    /// This function does **not** associate the index with a specific reason or
2444    /// proprietor internally. The caller is responsible for ensuring the index
2445    /// is correctly attached to a reason via [`CommitIndex::set_index`] and,
2446    /// optionally, the creator (for reap reasons since index should not have a
2447    /// manager).
2448    ///
2449    /// Entries with zero shares are silently ignored, as they carry no
2450    /// semantic contribution to the index.
2451    /// 
2452    /// Each entry digest must already be initiated (present in [`DigestMap`]
2453    /// under `reason`) before it can be added here, or it's rejected with
2454    /// `DigestNotFound` up front rather than failing later at commit-time.
2455    ///
2456    /// Future work: allow uninitiated digests and defer their initiation to 
2457    /// first deposit via the index, as [`CommitDeposit::place_digest_commit`]
2458    /// does for direct commitments today.
2459    ///
2460    /// - `who`: The proprietor creating the index.
2461    /// - `reason`: The reason under which the index is being prepared (not used internally).
2462    /// - `entries`: A vector of tuples containing:
2463    ///     - `Digest`: The entry digest
2464    ///     - `Shares`: The number of shares assigned to the entry
2465    ///     - `Position`: The variant/disposition of the entry
2466    ///
2467    /// ## Returns
2468    /// - `Ok(Index)` containing the prepared index
2469    /// - `Err(DispatchError)` if preparation fails
2470    fn prepare_index_of_variants(
2471        _who: &Proprietor<T>,
2472        reason: &Self::Reason,
2473        entries: Vec<(Self::Digest, Self::Shares, Self::Position)>,
2474    ) -> Result<Self::Index, DispatchError> {
2475        // Initialize a new Entries collection for the index
2476        let mut entries_of = Vec::new();
2477        for (digest, shares, variant) in entries {
2478            // Silently ignore non-share allocated entries
2479            if shares.is_zero() {
2480                continue;
2481            }
2482            // Reject uninitiated digests early instead of failing later at commit-time
2483            ensure!(
2484                DigestMap::<T, I>::contains_key((reason, &digest)),
2485                Error::<T,I>::EntryDigestNotInitiated
2486            );
2487            // Create a new entry with the given variant
2488            let entry_info = EntryInfo::<T, I>::new(digest, shares, variant)?;
2489            // Add entry to the index, checking for maximum capacity
2490            entries_of.push(entry_info);
2491        }
2492        // Construct the final IndexInfo object
2493        let index_info = IndexInfo::<T, I>::new(&mut Entries::<T, I>::new(entries_of)?)?;
2494
2495        Ok(index_info)
2496    }
2497
2498    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2499    // ``````````````````````````````````` GETTERS ```````````````````````````````````
2500    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2501
2502    /// Retrieves the variant associated with a specific entry in an index.
2503    ///
2504    /// ## Returns
2505    /// - `Ok(Position)` containing the entry's variant
2506    /// - `Err(DispatchError)` otherwise
2507    fn get_entry_variant(
2508        reason: &Self::Reason,
2509        index_of: &Self::Digest,
2510        entry_of: &Self::Digest,
2511    ) -> Result<Self::Position, DispatchError> {
2512        let index_info = Self::get_index(reason, index_of)?;
2513        let entries = &index_info.entries();
2514
2515        let mut idx = None;
2516
2517        // Locate the entry by digest
2518        for (i, entry) in entries.iter().enumerate() {
2519            if entry.digest() == *entry_of {
2520                idx = Some(i);
2521            }
2522        }
2523
2524        let entry_info = match idx {
2525            Some(i) => {
2526                let entry = entries.get(i);
2527                debug_assert!(
2528                    entry.is_some(),
2529                    "entry {:?} of index {:?} found by iterating over index, 
2530                    but retrieval via vector index {:?} get failed",
2531                    entry_of,
2532                    index_of,
2533                    i
2534                );
2535                entry.ok_or(Error::<T, I>::EntryOfIndexNotFound)?
2536            }
2537            None => return Err(Error::<T, I>::EntryOfIndexNotFound.into()),
2538        };
2539        let variant = entry_info.variant().clone();
2540
2541        Ok(variant)
2542    }
2543
2544    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2545    // ``````````````````````````````````` MUTATORS ``````````````````````````````````
2546    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2547
2548    /// Sets or updates the variant (position/disposition) of a specific entry
2549    /// of an index, producing a new index.
2550    ///
2551    /// This function handles both existing and new entries:
2552    /// - If the entry exists:
2553    ///   - If `shares` is `Some(zero)`, the entry is removed.
2554    ///   - If `shares` is `Some`, both shares and variant are updated.
2555    ///   - If `shares` is `None`, only the variant is updated while retaining existing shares.
2556    /// - If the entry does not exist:
2557    ///   - If `shares` is `Some(zero)` or `None`, the operation is a no-op and the original index is returned.
2558    ///   - Otherwise, a new entry is added with the provided variant and shares.
2559    ///
2560    /// A newly added entry digest must already be initiated (present in [`DigestMap`]
2561    /// under `reason`), or it's rejected with `DigestNotFound` up front rather than
2562    /// failing later at commit-time.
2563    /// 
2564    /// The entry digest is not validated to be a direct digest and is accepted as provided.
2565    /// If a commitment is placed on the index, the entry will be funded through normal deposit routing.
2566    ///
2567    /// ## Returns
2568    /// - `Ok(Digest)` containing the resulting index digest (may be unchanged if no-op)
2569    /// - `Err(DispatchError)` if the operation fails
2570    fn set_entry_of_variant(
2571        who: &Proprietor<T>,
2572        reason: &Self::Reason,
2573        index_of: &Self::Digest,
2574        entry_of: &Self::Digest,
2575        variant: Self::Position,
2576        shares: Option<Self::Shares>,
2577    ) -> Result<Self::Digest, DispatchError> {
2578        match Self::entry_exists(reason, index_of, entry_of).is_ok() {
2579            true => {
2580                // Entry exists
2581                match shares {
2582                    Some(s) => {
2583                        if s.is_zero() {
2584                            return CommitHelpers::<T, I>::remove_index_entry(
2585                                who, reason, index_of, entry_of,
2586                            );
2587                        }
2588                        // Update entry with new shares and variant
2589                        CommitHelpers::<T, I>::set_index_entry(
2590                            who, reason, index_of, entry_of, s, &variant,
2591                        )
2592                    }
2593                    None => {
2594                        // Retain existing shares
2595                        let entries = Self::get_entries_shares(reason, index_of);
2596                        debug_assert!(
2597                            entries.is_ok(),
2598                            "entry {:?} of index {:?} of reason {:?} exists but cannot get 
2599                            all entries shares of the index",
2600                            entry_of,
2601                            index_of,
2602                            reason
2603                        );
2604                        let entries = entries?;
2605                        let mut current_shares = None;
2606                        for (entry_digest, share) in entries {
2607                            if entry_digest == *entry_of {
2608                                current_shares = Some(share);
2609                            }
2610                        }
2611                        let current_shares =
2612                            current_shares.ok_or(Error::<T, I>::EntryOfIndexNotFound)?;
2613                        CommitHelpers::<T, I>::set_index_entry(
2614                            who,
2615                            reason,
2616                            index_of,
2617                            entry_of,
2618                            current_shares,
2619                            &variant,
2620                        )
2621                    }
2622                }
2623            }
2624            false => {
2625                // Entry does not exist
2626                if let Some(s) = shares {
2627                    if s.is_zero() {
2628                        return Ok(index_of.clone());
2629                    }
2630                    // Reject uninitiated digests early instead of failing later at commit-time
2631                    ensure!(
2632                        DigestMap::<T, I>::contains_key((reason, &entry_of)),
2633                        Error::<T,I>::EntryDigestNotInitiated
2634                    );
2635                    CommitHelpers::<T, I>::set_index_entry(
2636                        who, reason, index_of, entry_of, s, &variant,
2637                    )
2638                } else {
2639                    // Cannot create a new entry without shares
2640                    Ok(index_of.clone())
2641                }
2642            }
2643        }
2644    }
2645}
2646
2647// ===============================================================================
2648// ````````````````````````````````` POOL VARIANT ````````````````````````````````
2649// ===============================================================================
2650
2651/// Implements [`PoolVariant`] for the pallet
2652impl<T: Config<I>, I: 'static> PoolVariant<Proprietor<T>> for Pallet<T, I> {
2653    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2654    // ``````````````````````````````````` GETTERS ```````````````````````````````````
2655    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2656
2657    /// Retrieves the variant associated with a specific slot in a pool.
2658    ///
2659    /// ## Returns
2660    /// - `Ok(Position)` containing the slot's variant
2661    /// - `Err(DispatchError)`if the slot does not exist
2662    fn get_slot_variant(
2663        reason: &Self::Reason,
2664        pool_of: &Self::Digest,
2665        slot_of: &Self::Digest,
2666    ) -> Result<Self::Position, DispatchError> {
2667        // Fetch the pool information
2668        let pool_info = Self::get_pool(reason, pool_of)?;
2669        let slots = &pool_info.slots();
2670
2671        // Find the index of the requested slot
2672        let mut idx = None;
2673        for (i, slot) in slots.iter().enumerate() {
2674            if slot.digest() == *slot_of {
2675                idx = Some(i);
2676            }
2677        }
2678
2679        let slot_info = match idx {
2680            Some(i) => {
2681                let slot = slots.get(i);
2682                debug_assert!(
2683                    slot.is_some(),
2684                    "slot {:?} of pool {:?} of reason {:?} found by iterating over 
2685                    pool, but later retrieval via vector index {:?} get failed",
2686                    slot_of,
2687                    pool_of,
2688                    reason,
2689                    i
2690                );
2691                slot.ok_or(Error::<T, I>::SlotOfPoolNotFound)?
2692            }
2693            None => return Err(Error::<T, I>::SlotOfPoolNotFound.into()),
2694        };
2695
2696        let variant = slot_info.variant().clone();
2697        Ok(variant)
2698    }
2699
2700    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2701    // ``````````````````````````````````` MUTATORS ``````````````````````````````````
2702    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2703
2704    /// Sets or updates the variant of a specific slot within a pool.
2705    ///
2706    /// Unlike indexes, pools are mutable, so this operation modifies the
2707    /// pool in place without creating a new pool digest. The pool is released
2708    /// and recovered to maintain real-time balances after the mutation.
2709    ///
2710    /// This function handles both existing and new slots:
2711    /// - If the slot exists:
2712    ///   - Updates its variant.
2713    ///   - Updates shares if provided.
2714    ///   - Removes the slot if provided shares are zero.
2715    ///   - Retains existing shares if `shares` is `None`.
2716    /// - If the slot does not exist:
2717    ///   - Creates a new slot if non-zero `shares` is provided.
2718    ///   - Does nothing if `shares` is zero.
2719    ///   - Returns an error if `shares` is `None` (no slot to update and no data to create).
2720    ///
2721    /// A newly added slot digest must already be initiated (present in [`DigestMap`]
2722    /// under `reason`), or it's rejected with `DigestNotFound` up front rather than
2723    /// failing later at commit-time.
2724    /// 
2725    /// ## Returns
2726    /// - `Ok(())` if the operation completes successfully
2727    /// - `Err(DispatchError)` if the slot is not found and cannot be created,
2728    ///   or if the operation fails
2729    fn set_slot_of_variant(
2730        who: &Proprietor<T>,
2731        reason: &Self::Reason,
2732        pool_of: &Self::Digest,
2733        slot_of: &Self::Digest,
2734        variant: Self::Position,
2735        shares: Option<Self::Shares>,
2736    ) -> DispatchResult {
2737        match Self::slot_exists(reason, pool_of, slot_of).is_ok() {
2738            true => {
2739                // Slot exists, determine shares to use
2740                let actual_shares = if let Some(shares) = shares {
2741                    if shares.is_zero() {
2742                        return CommitHelpers::<T, I>::remove_pool_slot(
2743                            who, reason, pool_of, slot_of,
2744                        );
2745                    }
2746                    shares
2747                } else {
2748                    let slots = Self::get_slots_shares(reason, pool_of);
2749                    debug_assert!(
2750                        slots.is_ok(),
2751                        "slot {:?} of pool {:?} of reason {:?} exists 
2752                        but cannot get all slots shares of the pool",
2753                        slot_of,
2754                        pool_of,
2755                        reason
2756                    );
2757                    let slots = slots?;
2758                    let mut found_shares = None;
2759                    for (slot_digest, share) in slots {
2760                        if slot_digest == *slot_of {
2761                            found_shares = Some(share);
2762                        }
2763                    }
2764                    found_shares.ok_or(Error::<T, I>::SlotOfPoolNotFound)?
2765                };
2766                CommitHelpers::<T, I>::set_pool_slot(
2767                    who,
2768                    reason,
2769                    pool_of,
2770                    slot_of,
2771                    actual_shares,
2772                    &variant,
2773                )
2774            }
2775            false => {
2776                // Slot does not exist
2777                if let Some(shares) = shares {
2778                    if shares.is_zero() {
2779                        return Ok(());
2780                    }
2781                    // Reject uninitiated digests early instead of failing later at commit-time
2782                    ensure!(
2783                        DigestMap::<T, I>::contains_key((reason, &slot_of)),
2784                        Error::<T,I>::SlotDigestNotInitiated
2785                    );
2786                    CommitHelpers::<T, I>::set_pool_slot(
2787                        who, reason, pool_of, slot_of, shares, &variant,
2788                    )
2789                } else {
2790                    // No shares provided, No Slot Found, No Variant to Set.
2791                    return Err(Error::<T, I>::SlotOfPoolNotFound.into());
2792                }
2793            }
2794        }
2795    }
2796
2797    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2798    // ```````````````````````````````````` HOOKS ````````````````````````````````````
2799    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2800
2801    /// Emits an event when a slot's variant or shares within a pool is updated.
2802    ///
2803    /// Records the pool digest, reason, slot digest, new variant, and shares (either
2804    /// provided or retrieved from current state).
2805    ///
2806    /// If the slot cannot be found, the function silently returns.
2807    ///
2808    /// Emits:
2809    /// - [`Event::PoolSlot`] if `shares > 0`
2810    /// - [`Event::PoolSlotRemoved`] if `shares == 0`
2811    ///
2812    /// Events are emitted only if [`Config::EmitEvents`] is `true`.
2813    fn on_set_slot_of_variant(
2814        pool_of: &Self::Digest,
2815        reason: &Self::Reason,
2816        slot_of: &Self::Digest,
2817        shares: Option<Self::Shares>,
2818        variant: &Self::Position,
2819    ) {
2820        if T::EmitEvents::get() {
2821            let shares = match shares {
2822                Some(shares) => shares,
2823                None => {
2824                    // Fallback: look up existing slot shares from the pool
2825                    let slots = match Self::get_slots_shares(reason, pool_of) {
2826                        Ok(slots) => slots,
2827                        Err(_) => return,
2828                    };
2829
2830                    match slots
2831                        .into_iter()
2832                        .find(|(slot_digest, _)| slot_digest == slot_of)
2833                    {
2834                        Some((_, share)) => share,
2835                        None => return,
2836                    }
2837                }
2838            };
2839
2840            match shares.is_zero() {
2841                true => Self::deposit_event(Event::<T, I>::PoolSlotRemoved {
2842                    pool_of: pool_of.clone(),
2843                    reason: *reason,
2844                    slot_of: slot_of.clone(),
2845                    variant: variant.clone(),
2846                }),
2847                false => Self::deposit_event(Event::<T, I>::PoolSlot {
2848                    pool_of: pool_of.clone(),
2849                    reason: *reason,
2850                    slot_of: slot_of.clone(),
2851                    variant: variant.clone(),
2852                    shares,
2853                }),
2854            }
2855        }
2856    }
2857}
2858
2859// ===============================================================================
2860// ```````````````````````````` COMMIT ERROR HANDLER `````````````````````````````
2861// ===============================================================================
2862
2863impl<T: Config<I>, I: 'static> CommitErrorHandler for Pallet<T, I> {
2864    type Error = Error<T, I>;
2865
2866    fn from_commit_error(e: CommitError) -> Self::Error {
2867        match e {
2868            CommitError::CommitAlreadyExists => Error::<T, I>::CommitAlreadyExists,
2869            CommitError::InsufficientFunds => Error::<T, I>::InsufficientFunds,
2870            CommitError::MintingOffLimits => Error::<T, I>::MintingOffLimits,
2871            CommitError::ReapingOffLimits => Error::<T, I>::ReapingOffLimits,
2872            CommitError::PlacingOffLimits => Error::<T, I>::PlacingOffLimits,
2873            CommitError::RaisingOffLimits => Error::<T, I>::RaisingOffLimits,
2874        }
2875    }
2876}
2877
2878// ===============================================================================
2879// `````````````````````````````````` UNIT TESTS `````````````````````````````````
2880// ===============================================================================
2881
2882/// Unit tests for [`commitment`](frame_suite::commitment) trait
2883/// implementations over [`Pallet`].
2884#[cfg(test)]
2885mod tests {
2886
2887    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2888    // ```````````````````````````````````` IMPORTS ``````````````````````````````````
2889    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2890
2891    use std::vec;
2892
2893    // --- Local crate imports ---
2894    use crate::{balance::*, mock::*};
2895
2896    // --- FRAME Suite ---
2897    use frame_suite::{
2898        commitment::*,
2899        misc::{Directive, PositionIndex, Disposition},
2900    };
2901
2902    // --- FRAME Support ---
2903    use frame_support::{
2904        assert_err, assert_ok,
2905        traits::{
2906            fungible::{Inspect, InspectFreeze, InspectHold},
2907            tokens::{Fortitude, Precision},
2908        },
2909    };
2910
2911    // --- Substrate Primitives ---
2912    use sp_runtime::traits::Zero;
2913
2914    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2915    // ```````````````````````````````` INSPECT ASSET ````````````````````````````````
2916    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2917
2918    #[test]
2919    fn available_funds_success() {
2920        commit_test_ext().execute_with(|| {
2921            set_default_user_balance_and_standard_hold(ALICE).unwrap();
2922            let liquid_balance = AssetOf::balance(&ALICE);
2923            let hold_balance = AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE);
2924            assert_eq!(liquid_balance, INITIAL_BALANCE);
2925            assert_eq!(hold_balance, STANDARD_HOLD);
2926            let expected_available_funds = liquid_balance + hold_balance;
2927            let actual_available_funds = Pallet::available_funds(&ALICE);
2928            assert_eq!(actual_available_funds, expected_available_funds);
2929        })
2930    }
2931
2932    #[test]
2933    fn available_funds_success_with_zero_for_uninitialized_user() {
2934        commit_test_ext().execute_with(|| {
2935            // since, NIX is uninitialized expected funds is 0
2936            let expected_available_funds = ZERO_VALUE;
2937            let actual_available_funds = Pallet::available_funds(&AMY);
2938            assert_eq!(actual_available_funds, expected_available_funds);
2939        })
2940    }
2941
2942    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2943    // ```````````````````````````````` DIGEST MODEL `````````````````````````````````
2944    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2945
2946    #[test]
2947    fn determine_digest_success_for_direct_digest_model() {
2948        commit_test_ext().execute_with(|| {
2949            set_default_user_balance_and_standard_hold(ALICE).unwrap();
2950            Pallet::place_commit(
2951                &ALICE,
2952                &ESCROW,
2953                &CONTRACT_FREELANCE,
2954                STANDARD_COMMIT,
2955                &Directive::new(Precision::Exact, Fortitude::Force),
2956            )
2957            .unwrap();
2958            assert_eq!(
2959                Pallet::determine_digest(&CONTRACT_FREELANCE, &ESCROW),
2960                Ok(DigestVariant::Direct(CONTRACT_FREELANCE))
2961            );
2962        })
2963    }
2964
2965    #[test]
2966    fn determine_digest_success_for_index_model() {
2967        commit_test_ext().execute_with(|| {
2968            set_default_user_balance_and_standard_hold(ALICE).unwrap();
2969            set_default_user_balance_and_standard_hold(BOB).unwrap();
2970            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
2971            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
2972            let entries = vec![
2973                (VALIDATOR_ALPHA, SHARE_EQUAL),
2974                (VALIDATOR_BETA, SHARE_EQUAL),
2975            ];
2976            prepare_and_initiate_index(BOB, STAKING, &entries, INDEX_BALANCED_STAKING).unwrap();
2977            Pallet::place_commit(
2978                &ALICE,
2979                &STAKING,
2980                &INDEX_BALANCED_STAKING,
2981                STANDARD_COMMIT,
2982                &Directive::new(Precision::Exact, Fortitude::Force),
2983            )
2984            .unwrap();
2985            assert_eq!(
2986                Pallet::determine_digest(&INDEX_BALANCED_STAKING, &STAKING),
2987                Ok(DigestVariant::Index(INDEX_BALANCED_STAKING))
2988            );
2989        })
2990    }
2991
2992    #[test]
2993    fn determine_digest_success_for_pool_model() {
2994        commit_test_ext().execute_with(|| {
2995            set_default_user_balance_and_standard_hold(ALICE).unwrap();
2996            set_default_user_balance_and_standard_hold(BOB).unwrap();
2997            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
2998            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
2999            let entries = vec![
3000                (VALIDATOR_ALPHA, SHARE_DOMINANT),
3001                (VALIDATOR_BETA, SHARE_MAJOR),
3002            ];
3003            prepare_and_initiate_pool(
3004                BOB,
3005                STAKING,
3006                &entries,
3007                INDEX_OPTIMIZED_STAKING,
3008                POOL_MANAGED_STAKING,
3009                COMMISSION_LOW,
3010            )
3011            .unwrap();
3012            Pallet::place_commit(
3013                &ALICE,
3014                &STAKING,
3015                &INDEX_OPTIMIZED_STAKING,
3016                STANDARD_COMMIT,
3017                &Directive::new(Precision::BestEffort, Fortitude::Force),
3018            )
3019            .unwrap();
3020            assert_eq!(
3021                Pallet::determine_digest(&POOL_MANAGED_STAKING, &STAKING),
3022                Ok(DigestVariant::Pool(POOL_MANAGED_STAKING))
3023            );
3024        })
3025    }
3026
3027    #[test]
3028    fn determine_digest_err_digest_not_found_to_determine() {
3029        commit_test_ext().execute_with(|| {
3030            set_default_user_balance_and_standard_hold(ALICE).unwrap();
3031            Pallet::place_commit(
3032                &ALICE,
3033                &GOVERNANCE,
3034                &PROPOSAL_TREASURY_SPEND,
3035                STANDARD_COMMIT,
3036                &Directive::new(Precision::Exact, Fortitude::Force),
3037            )
3038            .unwrap();
3039            assert_err!(
3040                Pallet::determine_digest(&PROPOSAL_RUNTIME_UPGRADE, &GOVERNANCE),
3041                Error::DigestNotFoundToDetermine
3042            );
3043        })
3044    }
3045
3046    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3047    // ````````````````````````````````` COMMITMENT ``````````````````````````````````
3048    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3049
3050    #[test]
3051    fn place_commmit_success_for_digest() {
3052        commit_test_ext().execute_with(|| {
3053            set_default_user_balance_and_standard_hold(ALICE).unwrap();
3054            assert_err!(
3055                Pallet::commit_exists(&ALICE, &GOVERNANCE),
3056                Error::CommitNotFound
3057            );
3058            assert_err!(
3059                Pallet::digest_exists(&GOVERNANCE, &PROPOSAL_TREASURY_SPEND),
3060                Error::DigestNotFound
3061            );
3062            assert_ok!(Pallet::place_commit(
3063                &ALICE,
3064                &GOVERNANCE,
3065                &PROPOSAL_TREASURY_SPEND,
3066                STANDARD_COMMIT,
3067                &Directive::new(Precision::Exact, Fortitude::Force)
3068            ));
3069            // Commit and digest enquirey
3070            assert_ok!(Pallet::commit_exists(&ALICE, &GOVERNANCE));
3071            assert_ok!(Pallet::digest_exists(&GOVERNANCE, &PROPOSAL_TREASURY_SPEND));
3072            // Balance and freeze enquirey
3073            let balace_after = AssetOf::balance(&ALICE);
3074            let hold_balance_after = AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE);
3075            let expected_balance_after = INITIAL_BALANCE;
3076            let expected_hold_balance_after = 250;
3077            assert_eq!(expected_balance_after, balace_after);
3078            assert_eq!(expected_hold_balance_after, hold_balance_after);
3079            assert_eq!(
3080                AssetOf::balance_frozen(&GOVERNANCE, &ALICE),
3081                STANDARD_COMMIT
3082            );
3083            // Digest info enquiry
3084            let digest_info = DigestMap::get((GOVERNANCE, PROPOSAL_TREASURY_SPEND)).unwrap();
3085            let digests = digest_info.reveal();
3086            let digest_of = digests.get(0).unwrap();
3087            let effective =
3088                balance_total(digest_of, &Default::default(), &PROPOSAL_TREASURY_SPEND).unwrap();
3089            assert_eq!(effective, 250);
3090            // Commit info enquiry
3091            let commit_info = CommitMap::get((ALICE, GOVERNANCE)).unwrap();
3092            assert_eq!(commit_info.digest(), PROPOSAL_TREASURY_SPEND);
3093            let commits = commit_info.commits();
3094            let commit = commits.get(0).unwrap();
3095            let principal = receipt_active_value(
3096                digest_of,
3097                &Default::default(),
3098                &PROPOSAL_TREASURY_SPEND,
3099                commit,
3100            )
3101            .unwrap();
3102            assert_eq!(principal, STANDARD_COMMIT);
3103            // Total value enquiry
3104            let reason_value = ReasonValue::get(GOVERNANCE).unwrap();
3105            assert_eq!(reason_value, 250);
3106        })
3107    }
3108
3109    #[test]
3110    fn place_commit_success_for_index() {
3111        commit_test_ext().execute_with(|| {
3112            set_default_user_balance_and_standard_hold(ALICE).unwrap();
3113            set_default_user_balance_and_standard_hold(BOB).unwrap();
3114            set_default_user_balance_and_standard_hold(CHARLIE).unwrap();
3115
3116            Pallet::place_commit(
3117                &ALICE,
3118                &STAKING,
3119                &VALIDATOR_ALPHA,
3120                STANDARD_COMMIT,
3121                &Directive::new(Precision::Exact, Fortitude::Force),
3122            )
3123            .unwrap();
3124            Pallet::place_commit(
3125                &BOB,
3126                &STAKING,
3127                &VALIDATOR_BETA,
3128                STANDARD_COMMIT,
3129                &Directive::new(Precision::Exact, Fortitude::Force),
3130            )
3131            .unwrap();
3132            prepare_and_initiate_index(
3133                MIKE,
3134                STAKING,
3135                &[
3136                    (VALIDATOR_ALPHA, SHARE_MAJOR),
3137                    (VALIDATOR_BETA, SHARE_DOMINANT),
3138                ],
3139                INDEX_OPTIMIZED_STAKING,
3140            )
3141            .unwrap();
3142            assert_ok!(Pallet::index_exists(&STAKING, &INDEX_OPTIMIZED_STAKING));
3143            // Before placing a commit to the index
3144            let index_info = Pallet::get_index(&STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
3145            assert_eq!(index_info.capital(), 100);
3146            assert_eq!(index_info.principal(), ZERO_VALUE);
3147            let actual_entries_value =
3148                Pallet::get_entries_value(&STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
3149            let expected_entries_value = vec![(VALIDATOR_ALPHA, 0), (VALIDATOR_BETA, 0)];
3150            assert_eq!(actual_entries_value, expected_entries_value);
3151
3152            let reason_value = ReasonValue::get(STAKING).unwrap();
3153            assert_eq!(reason_value, 500);
3154
3155            // Place commit to an index
3156            assert_ok!(Pallet::place_commit(
3157                &CHARLIE,
3158                &STAKING,
3159                &INDEX_OPTIMIZED_STAKING,
3160                STANDARD_COMMIT,
3161                &Directive::new(Precision::Exact, Fortitude::Force)
3162            ));
3163            // After placing a commit to the index
3164            let index_value = Pallet::get_index_value(&STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
3165            assert_eq!(index_value, 250);
3166            let actual_entries_value =
3167                Pallet::get_entries_value(&STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
3168            let expected_entries_value = vec![(VALIDATOR_ALPHA, 100), (VALIDATOR_BETA, 150)];
3169            assert_eq!(actual_entries_value, expected_entries_value);
3170            // Entry info
3171            let entry_info_alpha =
3172                EntryMap::get((STAKING, INDEX_OPTIMIZED_STAKING, VALIDATOR_ALPHA, CHARLIE))
3173                    .unwrap();
3174            let alpha_commits = entry_info_alpha.commits();
3175            let alpha_derived_bal = alpha_commits.get(0).unwrap();
3176            assert_eq!(receipt_deposit_value(alpha_derived_bal).unwrap(), 100);
3177            let entry_info_beta =
3178                EntryMap::get((STAKING, INDEX_OPTIMIZED_STAKING, VALIDATOR_BETA, CHARLIE)).unwrap();
3179            let beta_commits = entry_info_beta.commits();
3180            let alpha_derived_bal = beta_commits.get(0).unwrap();
3181            assert_eq!(receipt_deposit_value(alpha_derived_bal).unwrap(), 150);
3182            // Total reason value
3183            let reason_value = ReasonValue::get(STAKING).unwrap();
3184            assert_eq!(reason_value, 750);
3185            // Balance and freeze enquirey
3186            let balace_after = AssetOf::balance(&CHARLIE);
3187            let hold_balance_after = AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &CHARLIE);
3188            let expected_balance_after = INITIAL_BALANCE;
3189            let expected_hold_balance_after = 250;
3190            assert_eq!(expected_balance_after, balace_after);
3191            assert_eq!(expected_hold_balance_after, hold_balance_after);
3192            assert_eq!(AssetOf::balance_frozen(&STAKING, &CHARLIE), STANDARD_COMMIT);
3193        })
3194    }
3195
3196    #[test]
3197    fn place_commit_success_for_pool() {
3198        commit_test_ext().execute_with(|| {
3199            set_default_user_balance_and_standard_hold(ALICE).unwrap();
3200            set_default_user_balance_and_standard_hold(BOB).unwrap();
3201            set_default_user_balance_and_standard_hold(CHARLIE).unwrap();
3202            Pallet::place_commit(
3203                &ALICE,
3204                &STAKING,
3205                &VALIDATOR_ALPHA,
3206                STANDARD_COMMIT,
3207                &Directive::new(Precision::Exact, Fortitude::Force),
3208            )
3209            .unwrap();
3210            Pallet::place_commit(
3211                &BOB,
3212                &STAKING,
3213                &VALIDATOR_BETA,
3214                STANDARD_COMMIT,
3215                &Directive::new(Precision::Exact, Fortitude::Force),
3216            )
3217            .unwrap();
3218            let entries = vec![
3219                (VALIDATOR_ALPHA, SHARE_MAJOR),
3220                (VALIDATOR_BETA, SHARE_DOMINANT),
3221            ];
3222            prepare_and_initiate_pool(
3223                MIKE,
3224                STAKING,
3225                &entries,
3226                INDEX_OPTIMIZED_STAKING,
3227                POOL_MANAGED_STAKING,
3228                COMMISSION_LOW,
3229            )
3230            .unwrap();
3231            // Before placing commit to pool
3232            assert_eq!(
3233                Pallet::get_manager(&STAKING, &POOL_MANAGED_STAKING),
3234                Ok(MIKE)
3235            );
3236            let pool_info = PoolMap::get((STAKING, POOL_MANAGED_STAKING)).unwrap();
3237            let pool_balance_of = pool_info.balance();
3238            assert_eq!(
3239                balance_total(&pool_balance_of, &Default::default(), &POOL_MANAGED_STAKING)
3240                    .unwrap(),
3241                0
3242            );
3243            assert!(
3244                has_deposits(&pool_balance_of, &Default::default(), &POOL_MANAGED_STAKING).is_err()
3245            );
3246            let pool_capital = pool_info.capital();
3247            assert_eq!(pool_capital, 100);
3248            let actual_slots_value =
3249                Pallet::get_slots_value(&STAKING, &POOL_MANAGED_STAKING).unwrap();
3250            let expected_slots_value = vec![(VALIDATOR_ALPHA, 0), (VALIDATOR_BETA, 0)];
3251            assert_eq!(actual_slots_value, expected_slots_value);
3252            let reason_value = ReasonValue::get(STAKING).unwrap();
3253            assert_eq!(reason_value, 500);
3254            // Placing commit to pool
3255            assert_ok!(Pallet::place_commit(
3256                &CHARLIE,
3257                &STAKING,
3258                &POOL_MANAGED_STAKING,
3259                STANDARD_COMMIT,
3260                &Directive::new(Precision::Exact, Fortitude::Force)
3261            ));
3262            // After placing commit to pool
3263            let pool_info = PoolMap::get((STAKING, POOL_MANAGED_STAKING)).unwrap();
3264            let pool_balance_of = pool_info.balance();
3265            assert_eq!(
3266                balance_total(&pool_balance_of, &Default::default(), &POOL_MANAGED_STAKING)
3267                    .unwrap(),
3268                250
3269            );
3270            assert!(
3271                has_deposits(&pool_balance_of, &Default::default(), &POOL_MANAGED_STAKING).is_ok()
3272            );
3273            let actual_slots_value =
3274                Pallet::get_slots_value(&STAKING, &POOL_MANAGED_STAKING).unwrap();
3275            let expected_slots_value = vec![(VALIDATOR_ALPHA, 100), (VALIDATOR_BETA, 150)];
3276            assert_eq!(actual_slots_value, expected_slots_value);
3277
3278            let reason_value = ReasonValue::get(STAKING).unwrap();
3279            assert_eq!(reason_value, 750);
3280            // Balance and freeze enquirey
3281            let balace_after = AssetOf::balance(&CHARLIE);
3282            let hold_balance_after = AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &CHARLIE);
3283            let expected_balance_after = INITIAL_BALANCE;
3284            let expected_hold_balance_after = 250;
3285            assert_eq!(expected_balance_after, balace_after);
3286            assert_eq!(expected_hold_balance_after, hold_balance_after);
3287            assert_eq!(AssetOf::balance_frozen(&STAKING, &CHARLIE), STANDARD_COMMIT);
3288        })
3289    }
3290
3291    #[test]
3292    fn place_commit_marker_error_for_value_zero() {
3293        commit_test_ext().execute_with(|| {
3294            set_default_user_balance_and_standard_hold(ALICE).unwrap();
3295            assert_err!(
3296                Pallet::place_commit(
3297                    &ALICE,
3298                    &STAKING,
3299                    &VALIDATOR_ALPHA,
3300                    ZERO_VALUE,
3301                    &Directive::new(Precision::BestEffort, Fortitude::Force)
3302                ),
3303                Error::MarkerCommitNotAllowed
3304            );
3305            // Commit and digest enquirey
3306            assert_err!(
3307                Pallet::commit_exists(&ALICE, &STAKING),
3308                Error::CommitNotFound
3309            );
3310            assert_err!(
3311                Pallet::digest_exists(&STAKING, &VALIDATOR_ALPHA),
3312                Error::DigestNotFound
3313            );
3314        })
3315    }
3316
3317    #[test]
3318    fn place_commit_err_commit_already_exists_for_reason() {
3319        commit_test_ext().execute_with(|| {
3320            let commit_info = CommitInfo::new(
3321                CONTRACT_FREELANCE,
3322                CommitInstance::default(),
3323                Default::default(),
3324            )
3325            .unwrap();
3326            CommitMap::insert((&ALICE, &ESCROW), commit_info);
3327            assert_err!(
3328                Pallet::place_commit(
3329                    &ALICE,
3330                    &ESCROW,
3331                    &CONTRACT_SUPPLY_CHAIN,
3332                    STANDARD_COMMIT,
3333                    &Directive::new(Precision::BestEffort, Fortitude::Polite)
3334                ),
3335                Error::CommitAlreadyExists
3336            );
3337        })
3338    }
3339
3340    #[test]
3341    fn place_commit_err_insufficient_funds() {
3342        commit_test_ext().execute_with(|| {
3343            set_default_user_balance_and_standard_hold(ALICE).unwrap();
3344            assert_eq!(AssetOf::total_balance(&ALICE), 1500);
3345            let insufficient_commit = 1600;
3346            assert_err!(
3347                Pallet::place_commit(
3348                    &ALICE,
3349                    &ESCROW,
3350                    &CONTRACT_SUPPLY_CHAIN,
3351                    insufficient_commit,
3352                    &Directive::new(Precision::Exact, Fortitude::Force)
3353                ),
3354                Error::InsufficientFunds
3355            );
3356        })
3357    }
3358
3359    #[test]
3360    fn raise_commit_success_for_direct() {
3361        commit_test_ext().execute_with(|| {
3362            System::set_block_number(10);
3363            set_default_user_balance_and_standard_hold(ALICE).unwrap();
3364            Pallet::place_commit(
3365                &ALICE,
3366                &STAKING,
3367                &VALIDATOR_ALPHA,
3368                STANDARD_COMMIT,
3369                &Directive::new(Precision::Exact, Fortitude::Force),
3370            )
3371            .unwrap();
3372            let commit_value_before = Pallet::get_commit_value(&ALICE, &STAKING).unwrap();
3373            assert_eq!(commit_value_before, STANDARD_COMMIT);
3374            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), STANDARD_COMMIT);
3375            let reason_value = Pallet::get_total_value(&STAKING);
3376            assert_eq!(reason_value, 250);
3377            assert_ok!(Pallet::raise_commit(
3378                &ALICE,
3379                &STAKING,
3380                SMALL_COMMIT,
3381                &Directive::new(Precision::Exact, Fortitude::Force)
3382            ));
3383            let commit_value_after = Pallet::get_commit_value(&ALICE, &STAKING).unwrap();
3384            assert_eq!(commit_value_after, 350);
3385            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), 350);
3386            let reason_value = Pallet::get_total_value(&STAKING);
3387            assert_eq!(reason_value, 350);
3388            // new commit instance added for raise commit
3389            let commit_info = CommitMap::get((ALICE, STAKING)).unwrap();
3390            let commits = commit_info.commits();
3391            let commit = commits.get(1).unwrap();
3392            assert_eq!(receipt_deposit_value(commit).unwrap(), SMALL_COMMIT);
3393
3394            #[cfg(not(feature = "dev"))]
3395            System::assert_last_event(Event::CommitRaised {
3396                 who: ALICE, 
3397                 reason: STAKING, 
3398                 digest: VALIDATOR_ALPHA, 
3399                 value: SMALL_COMMIT
3400                }
3401                .into()
3402            );
3403
3404            #[cfg(feature = "dev")]
3405            System::assert_last_event(Event::CommitRaised {
3406                 who: ALICE, 
3407                 reason: STAKING, 
3408                 model: DigestVariant::Direct(VALIDATOR_ALPHA), 
3409                 value: SMALL_COMMIT
3410                }
3411                .into()
3412            );            
3413        })
3414    }
3415
3416    #[test]
3417    fn raise_commit_success_for_index() {
3418        commit_test_ext().execute_with(|| {
3419            System::set_block_number(10);
3420            set_default_user_balance_and_standard_hold(ALICE).unwrap();
3421            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
3422            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
3423            prepare_and_initiate_index(
3424                MIKE,
3425                STAKING,
3426                &[
3427                    (VALIDATOR_ALPHA, SHARE_EQUAL),
3428                    (VALIDATOR_BETA, SHARE_EQUAL),
3429                ],
3430                INDEX_BALANCED_STAKING,
3431            )
3432            .unwrap();
3433
3434            Pallet::place_commit(
3435                &ALICE,
3436                &STAKING,
3437                &INDEX_BALANCED_STAKING,
3438                STANDARD_COMMIT,
3439                &Directive::new(Precision::Exact, Fortitude::Force),
3440            )
3441            .unwrap();
3442            // Before raising the index commit value
3443            let index_info = Pallet::get_index(&STAKING, &INDEX_BALANCED_STAKING).unwrap();
3444            assert_eq!(index_info.capital(), 200);
3445            assert_eq!(index_info.principal(), 250);
3446            let actual_entries_value =
3447                Pallet::get_entries_value(&STAKING, &INDEX_BALANCED_STAKING).unwrap();
3448            let expected_entries_value = vec![(VALIDATOR_ALPHA, 125), (VALIDATOR_BETA, 125)];
3449            assert_eq!(actual_entries_value, expected_entries_value);
3450            let reason_value = ReasonValue::get(STAKING).unwrap();
3451            assert_eq!(reason_value, 250);
3452            // alice balance inspect
3453            assert_eq!(AssetOf::balance(&ALICE), INITIAL_BALANCE);
3454            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 250);
3455            // Raise commit value
3456            assert_ok!(Pallet::raise_commit(
3457                &ALICE,
3458                &STAKING,
3459                SMALL_COMMIT,
3460                &Directive::new(Precision::Exact, Fortitude::Force)
3461            ));
3462            // After placing a raise commit to the index
3463            let index_value = Pallet::get_index_value(&STAKING, &INDEX_BALANCED_STAKING).unwrap();
3464            assert_eq!(index_value, 350);
3465            let actual_entries_value =
3466                Pallet::get_entries_value(&STAKING, &INDEX_BALANCED_STAKING).unwrap();
3467            let expected_entries_value = vec![(VALIDATOR_ALPHA, 175), (VALIDATOR_BETA, 175)];
3468            assert_eq!(actual_entries_value, expected_entries_value);
3469
3470            let reason_value = ReasonValue::get(STAKING).unwrap();
3471            assert_eq!(reason_value, 350);
3472            // New commit instances added for raise commit
3473            // Commit info check
3474            let commit_info = CommitMap::get((ALICE, STAKING)).unwrap();
3475            let commits = commit_info.commits();
3476            // The raise commit instance should be at index 1, but a placeholder only for index commits
3477            // EntryMap only holds all individual entries commits, so querying value via this
3478            // returns error due to default receipt - i.e., invalid
3479            let raise_commit = commits.get(1).unwrap();
3480            assert!(receipt_deposit_value(raise_commit).is_err(),);
3481
3482            // Entry info check
3483            // For VALIDATOR_ALPHA entry
3484            let alpha_entry_info =
3485                EntryMap::get((STAKING, INDEX_BALANCED_STAKING, VALIDATOR_ALPHA, ALICE)).unwrap();
3486            let alpha_commits = alpha_entry_info.commits();
3487            let commit = alpha_commits.get(1).unwrap();
3488            assert_eq!(receipt_deposit_value(commit).unwrap(), 50);
3489            // For VALIDATOR_BETA entry
3490            let beta_entry_info =
3491                EntryMap::get((STAKING, INDEX_BALANCED_STAKING, VALIDATOR_BETA, ALICE)).unwrap();
3492            let beta_commits = beta_entry_info.commits();
3493            let commit = beta_commits.get(1).unwrap();
3494            assert_eq!(receipt_deposit_value(commit).unwrap(), 50);
3495            // Balance and freeze enquirey
3496            let actual_balance = AssetOf::balance(&ALICE);
3497            let actual_hold_balance = AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE);
3498            let expected_balance = INITIAL_BALANCE;
3499            let expected_hold_balance = 150;
3500            assert_eq!(actual_balance, expected_balance);
3501            assert_eq!(actual_hold_balance, expected_hold_balance);
3502            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), 350);
3503
3504            #[cfg(not(feature = "dev"))]
3505            System::assert_last_event(Event::CommitRaised {
3506                 who: ALICE, 
3507                 reason: STAKING, 
3508                 digest: INDEX_BALANCED_STAKING, 
3509                 value: SMALL_COMMIT
3510                }
3511                .into()
3512            );
3513
3514            #[cfg(feature = "dev")]
3515            System::assert_last_event(Event::CommitRaised {
3516                 who: ALICE, 
3517                 reason: STAKING, 
3518                 model: DigestVariant::Index(INDEX_BALANCED_STAKING), 
3519                 value: SMALL_COMMIT
3520                }
3521                .into()
3522            );  
3523        })
3524    }
3525
3526    #[test]
3527    fn raise_commit_success_for_pool() {
3528        commit_test_ext().execute_with(|| {
3529            System::set_block_number(10);
3530            set_default_user_balance_and_standard_hold(ALICE).unwrap();
3531            set_default_user_balance_and_standard_hold(BOB).unwrap();
3532            set_default_user_balance_and_standard_hold(CHARLIE).unwrap();
3533            Pallet::place_commit(
3534                &BOB,
3535                &STAKING,
3536                &VALIDATOR_ALPHA,
3537                STANDARD_COMMIT,
3538                &Directive::new(Precision::Exact, Fortitude::Force),
3539            )
3540            .unwrap();
3541            Pallet::place_commit(
3542                &CHARLIE,
3543                &STAKING,
3544                &VALIDATOR_BETA,
3545                STANDARD_COMMIT,
3546                &Directive::new(Precision::Exact, Fortitude::Force),
3547            )
3548            .unwrap();
3549            let entries = vec![
3550                (VALIDATOR_ALPHA, SHARE_MAJOR),
3551                (VALIDATOR_BETA, SHARE_DOMINANT),
3552            ];
3553            prepare_and_initiate_pool(
3554                MIKE,
3555                STAKING,
3556                &entries,
3557                INDEX_OPTIMIZED_STAKING,
3558                POOL_MANAGED_STAKING,
3559                COMMISSION_ZERO,
3560            )
3561            .unwrap();
3562
3563            Pallet::place_commit(
3564                &ALICE,
3565                &STAKING,
3566                &POOL_MANAGED_STAKING,
3567                STANDARD_COMMIT,
3568                &Directive::new(Precision::Exact, Fortitude::Force),
3569            )
3570            .unwrap();
3571            // Before raising the pool commit value
3572            let pool_info = PoolMap::get((STAKING, POOL_MANAGED_STAKING)).unwrap();
3573            let pool_balance_of = pool_info.balance();
3574            assert_ok!(has_deposits(
3575                &pool_balance_of,
3576                &Default::default(),
3577                &POOL_MANAGED_STAKING
3578            ));
3579            assert_eq!(
3580                balance_total(&pool_balance_of, &Default::default(), &POOL_MANAGED_STAKING)
3581                    .unwrap(),
3582                250
3583            );
3584            let pool_capital = pool_info.capital();
3585            assert_eq!(pool_capital, 100);
3586            let actual_slots_value =
3587                Pallet::get_slots_value(&STAKING, &POOL_MANAGED_STAKING).unwrap();
3588            let expected_slots_value = vec![(VALIDATOR_ALPHA, 100), (VALIDATOR_BETA, 150)];
3589            assert_eq!(actual_slots_value, expected_slots_value);
3590            let reason_value = ReasonValue::get(STAKING).unwrap();
3591            assert_eq!(reason_value, 750);
3592            // Raise commit value
3593            assert_ok!(Pallet::raise_commit(
3594                &ALICE,
3595                &STAKING,
3596                SMALL_COMMIT,
3597                &Directive::new(Precision::Exact, Fortitude::Force)
3598            ));
3599            // After raising the pool commit value
3600            let pool_info = PoolMap::get((STAKING, POOL_MANAGED_STAKING)).unwrap();
3601            let pool_balance_of = pool_info.balance();
3602            assert_ok!(has_deposits(
3603                &pool_balance_of,
3604                &Default::default(),
3605                &POOL_MANAGED_STAKING
3606            ));
3607            assert_eq!(
3608                balance_total(&pool_balance_of, &Default::default(), &POOL_MANAGED_STAKING)
3609                    .unwrap(),
3610                350
3611            );
3612            let actual_slots_value =
3613                Pallet::get_slots_value(&STAKING, &POOL_MANAGED_STAKING).unwrap();
3614            let expected_slots_value = vec![(VALIDATOR_ALPHA, 140), (VALIDATOR_BETA, 210)];
3615            assert_eq!(actual_slots_value, expected_slots_value);
3616            let reason_value = ReasonValue::get(STAKING).unwrap();
3617            assert_eq!(reason_value, 850);
3618            // New commit instances added for raise commit
3619            // Commit info check
3620            let commit_info = CommitMap::get((ALICE, STAKING)).unwrap();
3621            let commits = commit_info.commits();
3622            // The initial commit instance should be at index 0
3623            let initial_commit = commits.get(0).unwrap();
3624            assert_eq!(
3625                receipt_deposit_value(initial_commit).unwrap(),
3626                STANDARD_COMMIT
3627            );
3628            // The raise commit instance should be at index 1
3629            let raise_commit = commits.get(1).unwrap();
3630            assert_eq!(receipt_deposit_value(raise_commit).unwrap(), SMALL_COMMIT);
3631
3632            #[cfg(not(feature = "dev"))]
3633            System::assert_last_event(Event::CommitRaised {
3634                 who: ALICE, 
3635                 reason: STAKING, 
3636                 digest: POOL_MANAGED_STAKING, 
3637                 value: SMALL_COMMIT
3638                }
3639                .into()
3640            );
3641
3642            #[cfg(feature = "dev")]
3643            System::assert_last_event(Event::CommitRaised {
3644                 who: ALICE, 
3645                 reason: STAKING, 
3646                 model: DigestVariant::Pool(POOL_MANAGED_STAKING), 
3647                 value: SMALL_COMMIT
3648                }
3649                .into()
3650            );  
3651        })
3652    }
3653
3654    #[test]
3655    fn raise_commit_err_commit_not_found() {
3656        commit_test_ext().execute_with(|| {
3657            set_default_user_balance_and_standard_hold(ALICE).unwrap();
3658            Pallet::place_commit(
3659                &ALICE,
3660                &STAKING,
3661                &VALIDATOR_ALPHA,
3662                STANDARD_COMMIT,
3663                &Directive::new(Precision::Exact, Fortitude::Force),
3664            )
3665            .unwrap();
3666            assert_err!(
3667                Pallet::raise_commit(
3668                    &ALICE,
3669                    &ESCROW,
3670                    SMALL_COMMIT,
3671                    &Directive::new(Precision::Exact, Fortitude::Force)
3672                ),
3673                Error::CommitNotFound
3674            );
3675        });
3676    }
3677
3678    #[test]
3679    fn raise_commit_err_insifficient_funds() {
3680        commit_test_ext().execute_with(|| {
3681            set_default_user_balance_and_standard_hold(ALICE).unwrap();
3682            Pallet::place_commit(
3683                &ALICE,
3684                &STAKING,
3685                &VALIDATOR_ALPHA,
3686                LARGE_COMMIT,
3687                &Directive::new(Precision::Exact, Fortitude::Force),
3688            )
3689            .unwrap();
3690            let insufficient_commit = SMALL_COMMIT;
3691            assert_err!(
3692                Pallet::raise_commit(
3693                    &ALICE,
3694                    &STAKING,
3695                    insufficient_commit,
3696                    &Directive::new(Precision::Exact, Fortitude::Polite)
3697                ),
3698                Error::InsufficientFunds
3699            );
3700        })
3701    }
3702
3703    #[test]
3704    fn raise_commit_err_marker_commit_not_allowed() {
3705        commit_test_ext().execute_with(|| {
3706            set_default_user_balance_and_standard_hold(ALICE).unwrap();
3707            Pallet::place_commit(
3708                &ALICE,
3709                &STAKING,
3710                &VALIDATOR_ALPHA,
3711                STANDARD_COMMIT,
3712                &Directive::new(Precision::Exact, Fortitude::Force),
3713            )
3714            .unwrap();
3715            let invalid_commit_val = ZERO_VALUE;
3716            assert_err!(
3717                Pallet::raise_commit(
3718                    &ALICE,
3719                    &STAKING,
3720                    invalid_commit_val,
3721                    &Directive::new(Precision::Exact, Fortitude::Polite)
3722                ),
3723                Error::MarkerCommitNotAllowed
3724            );
3725        })
3726    }
3727
3728    #[test]
3729    fn resolve_commit_success_for_direct() {
3730        commit_test_ext().execute_with(|| {
3731            System::set_block_number(10);
3732            set_default_user_balance_and_standard_hold(ALICE).unwrap();
3733            Pallet::place_commit(
3734                &ALICE,
3735                &GOVERNANCE,
3736                &PROPOSAL_RUNTIME_UPGRADE,
3737                STANDARD_COMMIT,
3738                &Directive::new(Precision::Exact, Fortitude::Force),
3739            )
3740            .unwrap();
3741            // Before resolving the commit
3742            assert_eq!(
3743                AssetOf::balance_frozen(&GOVERNANCE, &ALICE),
3744                STANDARD_COMMIT
3745            );
3746            assert_eq!(AssetOf::balance(&ALICE), INITIAL_BALANCE);
3747            let commit_value = Pallet::get_commit_value(&ALICE, &GOVERNANCE).unwrap();
3748            assert_eq!(commit_value, STANDARD_COMMIT);
3749
3750            let reason_value = Pallet::get_total_value(&GOVERNANCE);
3751            assert_eq!(reason_value, 250);
3752            // Resolve commit
3753            assert_ok!(Pallet::resolve_commit(&ALICE, &GOVERNANCE));
3754            // After resolving the commit
3755            assert_eq!(AssetOf::balance(&ALICE), 1250);
3756            assert_eq!(AssetOf::balance_frozen(&GOVERNANCE, &ALICE), ZERO_VALUE);
3757            assert_err!(
3758                Pallet::commit_exists(&ALICE, &GOVERNANCE),
3759                Error::CommitNotFound
3760            );
3761            let digets_value =
3762                Pallet::get_digest_value(&GOVERNANCE, &PROPOSAL_RUNTIME_UPGRADE).unwrap();
3763            assert_eq!(digets_value, ZERO_VALUE);
3764
3765            let reason_value = Pallet::get_total_value(&GOVERNANCE);
3766            assert_eq!(reason_value, ZERO_VALUE);
3767
3768            #[cfg(not(feature = "dev"))]
3769            System::assert_last_event(Event::CommitResolved { 
3770                who: ALICE, 
3771                reason: GOVERNANCE, 
3772                digest: PROPOSAL_RUNTIME_UPGRADE, 
3773                value: 250
3774                }
3775                .into()
3776            );
3777
3778            #[cfg(feature = "dev")]
3779            System::assert_last_event(Event::CommitResolved { 
3780                who: ALICE, 
3781                reason: GOVERNANCE, 
3782                model: DigestVariant::Direct(PROPOSAL_RUNTIME_UPGRADE), 
3783                value: 250
3784                }
3785                .into()
3786            );
3787        })
3788    }
3789
3790    #[test]
3791    fn resolve_commit_for_direct_success_with_reward() {
3792        commit_test_ext().execute_with(|| {
3793            set_default_user_balance_and_standard_hold(ALICE).unwrap();
3794            Pallet::place_commit(
3795                &ALICE,
3796                &STAKING,
3797                &VALIDATOR_ALPHA,
3798                STANDARD_COMMIT,
3799                &Directive::new(Precision::Exact, Fortitude::Force),
3800            )
3801            .unwrap();
3802            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), STANDARD_COMMIT);
3803            assert_eq!(
3804                Pallet::get_commit_value(&ALICE, &STAKING),
3805                Ok(STANDARD_COMMIT)
3806            );
3807            assert_eq!(
3808                Pallet::get_digest_value(&STAKING, &VALIDATOR_ALPHA,),
3809                Ok(STANDARD_COMMIT)
3810            );
3811            // Reward manupulation
3812            let new_reward_value = STANDARD_COMMIT + STANDARD_REWARD; // 250 + 50 -> 300
3813            Pallet::set_digest_value(
3814                &STAKING,
3815                &VALIDATOR_ALPHA,
3816                new_reward_value,
3817                &Default::default(),
3818            )
3819            .unwrap();
3820            assert_eq!(
3821                Pallet::get_digest_value(&STAKING, &VALIDATOR_ALPHA,),
3822                Ok(new_reward_value)
3823            );
3824            assert_eq!(Pallet::get_commit_value(&ALICE, &STAKING), Ok(300));
3825
3826            // Resolving the commit after reward accumulation
3827            assert_ok!(Pallet::resolve_commit(&ALICE, &STAKING));
3828
3829            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), ZERO_VALUE);
3830            assert_eq!(AssetOf::balance(&ALICE), 1300); // existing balance + deposit + reward = 1000 + 250 + 50 = 1300
3831            assert_err!(
3832                Pallet::commit_exists(&ALICE, &STAKING),
3833                Error::CommitNotFound
3834            );
3835            assert_eq!(Pallet::get_digest_value(&STAKING, &VALIDATOR_ALPHA), Ok(0));
3836        });
3837    }
3838
3839    #[test]
3840    fn resolve_commit_withdraw_direct_with_penalty_success() {
3841        commit_test_ext().execute_with(|| {
3842            set_default_user_balance_and_standard_hold(ALICE).unwrap();
3843            Pallet::place_commit(
3844                &ALICE,
3845                &STAKING,
3846                &VALIDATOR_ALPHA,
3847                STANDARD_COMMIT,
3848                &Directive::new(Precision::Exact, Fortitude::Force),
3849            )
3850            .unwrap();
3851
3852            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), STANDARD_COMMIT);
3853            assert_eq!(
3854                Pallet::get_commit_value(&ALICE, &STAKING),
3855                Ok(STANDARD_COMMIT)
3856            );
3857            let digest_value = Pallet::get_digest_value(&STAKING, &VALIDATOR_ALPHA).unwrap();
3858            // Penalty manupulation
3859            let new_penalty_value = digest_value - STANDARD_PENALTY; // 250 - 100 -> 150;
3860            Pallet::set_digest_value(
3861                &STAKING,
3862                &VALIDATOR_ALPHA,
3863                new_penalty_value,
3864                &Default::default(),
3865            )
3866            .unwrap();
3867            assert_eq!(Pallet::get_commit_value(&ALICE, &STAKING), Ok(150));
3868            // Resolving the commit after penalty
3869            assert_ok!(Pallet::resolve_commit(&ALICE, &STAKING));
3870
3871            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), ZERO_VALUE);
3872            assert_eq!(AssetOf::balance(&ALICE), 1150); // existing balance + deposit - penalty = 1000 + 250 - 100 = 1150
3873            assert_err!(
3874                Pallet::commit_exists(&ALICE, &STAKING),
3875                Error::CommitNotFound
3876            );
3877            assert_eq!(
3878                Pallet::get_digest_value(&STAKING, &VALIDATOR_ALPHA),
3879                Ok(ZERO_VALUE)
3880            );
3881        });
3882    }
3883
3884    #[test]
3885    fn resolve_direct_commit_with_penalty_and_reward_by_entry_time() {
3886        commit_test_ext().execute_with(|| {
3887            set_user_balance_and_hold(ALICE, 10000, 5000).unwrap();
3888            set_user_balance_and_hold(BOB, 10000, 5000).unwrap();
3889            set_user_balance_and_hold(CHARLIE, 10000, 5000).unwrap();
3890
3891            Pallet::place_commit(
3892                &ALICE,
3893                &STAKING,
3894                &VALIDATOR_ALPHA,
3895                1000,
3896                &Directive::new(Precision::Exact, Fortitude::Polite),
3897            )
3898            .unwrap();
3899
3900            Pallet::place_commit(
3901                &CHARLIE,
3902                &STAKING,
3903                &VALIDATOR_ALPHA,
3904                1000,
3905                &Directive::new(Precision::Exact, Fortitude::Polite),
3906            )
3907            .unwrap();
3908
3909            // Penalty manupulation
3910            Pallet::set_digest_value(&STAKING, &VALIDATOR_ALPHA, 900, &Default::default()).unwrap();
3911
3912            Pallet::place_commit(
3913                &BOB,
3914                &STAKING,
3915                &VALIDATOR_ALPHA,
3916                400,
3917                &Directive::new(Precision::Exact, Fortitude::Polite),
3918            )
3919            .unwrap();
3920
3921            // Reward manupulation
3922            Pallet::set_digest_value(&STAKING, &VALIDATOR_ALPHA, 1500, &Default::default())
3923                .unwrap();
3924
3925            // Both, alice and charlie absorbed the penalty and reward shock according to their weight
3926            let alice_resolved = Pallet::resolve_commit(&ALICE, &STAKING).unwrap();
3927            assert_eq!(alice_resolved, 519);
3928
3929            let charlie_resolved = Pallet::resolve_commit(&CHARLIE, &STAKING).unwrap();
3930            assert_eq!(charlie_resolved, 519);
3931
3932            // Since, bob placed a commit after the penalty he dosen't
3933            // absorbed the penalty shock but absorbs reward shock.
3934            let bob_resolved = Pallet::resolve_commit(&BOB, &STAKING).unwrap();
3935            assert_eq!(bob_resolved, 462);
3936        });
3937    }
3938
3939    #[test]
3940    fn resolve_commit_success_for_index() {
3941        commit_test_ext().execute_with(|| {
3942            System::set_block_number(10);
3943            set_default_user_balance_and_standard_hold(ALICE).unwrap();
3944            set_default_user_balance_and_standard_hold(CHARLIE).unwrap();
3945            set_default_user_balance_and_standard_hold(BOB).unwrap();
3946            Pallet::place_commit(
3947                &CHARLIE,
3948                &STAKING,
3949                &VALIDATOR_ALPHA,
3950                STANDARD_COMMIT,
3951                &Directive::new(Precision::Exact, Fortitude::Force),
3952            )
3953            .unwrap();
3954            Pallet::place_commit(
3955                &BOB,
3956                &STAKING,
3957                &VALIDATOR_BETA,
3958                STANDARD_COMMIT,
3959                &Directive::new(Precision::Exact, Fortitude::Force),
3960            )
3961            .unwrap();
3962            prepare_and_initiate_index(
3963                MIKE,
3964                STAKING,
3965                &[
3966                    (VALIDATOR_ALPHA, SHARE_MAJOR),
3967                    (VALIDATOR_BETA, SHARE_DOMINANT),
3968                ],
3969                INDEX_OPTIMIZED_STAKING,
3970            )
3971            .unwrap();
3972            Pallet::place_commit(
3973                &ALICE,
3974                &STAKING,
3975                &INDEX_OPTIMIZED_STAKING,
3976                LARGE_COMMIT,
3977                &Directive::new(Precision::Exact, Fortitude::Force),
3978            )
3979            .unwrap();
3980            // Alice balance state before resolving
3981            assert_eq!(AssetOf::balance(&ALICE), INITIAL_BALANCE);
3982            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), 500);
3983            assert_eq!(Pallet::get_commit_value(&ALICE, &STAKING), Ok(500));
3984            let actual_entries_value =
3985                Pallet::get_entries_value(&STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
3986            let expected_entries_value = vec![(VALIDATOR_ALPHA, 200), (VALIDATOR_BETA, 300)];
3987            assert_eq!(actual_entries_value, expected_entries_value);
3988
3989            assert_ok!(Pallet::resolve_commit(&ALICE, &STAKING));
3990            // alice's balance state after resolving
3991            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), ZERO_VALUE);
3992            assert_eq!(AssetOf::balance(&ALICE), 1500); // existing balance + resolved balance -> 1000 + 500 = 1500
3993            assert_err!(
3994                Pallet::commit_exists(&ALICE, &STAKING),
3995                Error::CommitNotFound
3996            );
3997            assert_eq!(
3998                Pallet::get_index_value(&STAKING, &INDEX_OPTIMIZED_STAKING),
3999                Ok(ZERO_VALUE)
4000            );
4001            let actual_entries_value =
4002                Pallet::get_entries_value(&STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
4003            let expected_entries_value =
4004                vec![(VALIDATOR_ALPHA, ZERO_VALUE), (VALIDATOR_BETA, ZERO_VALUE)];
4005            assert_eq!(actual_entries_value, expected_entries_value);
4006
4007            #[cfg(not(feature = "dev"))]
4008            System::assert_last_event(Event::CommitResolved { 
4009                who: ALICE, 
4010                reason: STAKING, 
4011                digest: INDEX_OPTIMIZED_STAKING, 
4012                value: 500
4013                }
4014                .into()
4015            );
4016
4017            #[cfg(feature = "dev")]
4018            System::assert_last_event(Event::CommitResolved { 
4019                who: ALICE, 
4020                reason: STAKING, 
4021                model: DigestVariant::Index(INDEX_OPTIMIZED_STAKING), 
4022                value: 500
4023                }
4024                .into()
4025            );
4026        })
4027    }
4028
4029    #[test]
4030    fn resolve_commit_index_with_rewards() {
4031        commit_test_ext().execute_with(|| {
4032            set_default_user_balance_and_standard_hold(ALICE).unwrap();
4033            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
4034            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
4035            prepare_and_initiate_index(
4036                ALICE,
4037                STAKING,
4038                &[
4039                    (VALIDATOR_ALPHA, SHARE_MAJOR),
4040                    (VALIDATOR_BETA, SHARE_DOMINANT),
4041                ],
4042                INDEX_OPTIMIZED_STAKING,
4043            )
4044            .unwrap();
4045            Pallet::place_commit(
4046                &ALICE,
4047                &STAKING,
4048                &INDEX_OPTIMIZED_STAKING,
4049                350,
4050                &Directive::new(Precision::BestEffort, Fortitude::Polite),
4051            )
4052            .unwrap();
4053            assert_eq!(AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE), 150);
4054            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), 350);
4055            assert_eq!(Pallet::get_commit_value(&ALICE, &STAKING), Ok(350));
4056            // index balance
4057            assert_eq!(
4058                Pallet::get_index_value(&STAKING, &INDEX_OPTIMIZED_STAKING),
4059                Ok(350)
4060            );
4061            let actual_entries_value =
4062                Pallet::get_entries_value(&STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
4063            let expected_entries_value = vec![(VALIDATOR_ALPHA, 140), (VALIDATOR_BETA, 210)];
4064            assert_eq!(actual_entries_value, expected_entries_value);
4065            // Stimulating reward senario
4066            // Apply rewards: Alpha 14 -> 18 (+4), Beta 21 -> 27 (+6)
4067            let new_alpha_reward_value = 180;
4068            Pallet::set_digest_value(
4069                &STAKING,
4070                &VALIDATOR_ALPHA,
4071                new_alpha_reward_value,
4072                &Default::default(),
4073            )
4074            .unwrap();
4075            let new_beta_reward_value = 270;
4076            Pallet::set_digest_value(
4077                &STAKING,
4078                &VALIDATOR_BETA,
4079                new_beta_reward_value,
4080                &Default::default(),
4081            )
4082            .unwrap();
4083            // Expected index value: 180 + 270 = 450
4084            assert_eq!(
4085                Pallet::get_index_value(&STAKING, &INDEX_OPTIMIZED_STAKING),
4086                Ok(450)
4087            );
4088
4089            let actual_entries_value =
4090                Pallet::get_entries_value(&STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
4091            let expected_entries_value = vec![(VALIDATOR_ALPHA, 180), (VALIDATOR_BETA, 270)];
4092            assert_eq!(actual_entries_value, expected_entries_value);
4093            // Alice resolves commitment and gets 450 tokens
4094            assert_ok!(Pallet::resolve_commit(&ALICE, &STAKING));
4095            // Final balance: 1000 (existing) + 450 (resolved with precision loss) = 1450
4096            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), 0);
4097            assert_eq!(AssetOf::balance(&ALICE), 1450);
4098            assert_err!(
4099                Pallet::commit_exists(&ALICE, &STAKING),
4100                Error::CommitNotFound
4101            );
4102            assert_eq!(Pallet::get_digest_value(&STAKING, &VALIDATOR_ALPHA), Ok(0));
4103            assert_eq!(Pallet::get_digest_value(&STAKING, &VALIDATOR_BETA), Ok(0));
4104        });
4105    }
4106
4107    #[test]
4108    fn resolve_commit_withdraw_index_with_reward_success() {
4109        commit_test_ext().execute_with(|| {
4110            set_default_user_balance_and_standard_hold(ALICE).unwrap();
4111            set_default_user_balance_and_standard_hold(CHARLIE).unwrap();
4112            set_default_user_balance_and_standard_hold(BOB).unwrap();
4113            Pallet::place_commit(
4114                &CHARLIE,
4115                &STAKING,
4116                &VALIDATOR_ALPHA,
4117                STANDARD_COMMIT,
4118                &Directive::new(Precision::Exact, Fortitude::Force),
4119            )
4120            .unwrap();
4121            Pallet::place_commit(
4122                &BOB,
4123                &STAKING,
4124                &VALIDATOR_BETA,
4125                STANDARD_COMMIT,
4126                &Directive::new(Precision::Exact, Fortitude::Force),
4127            )
4128            .unwrap();
4129            prepare_and_initiate_index(
4130                MIKE,
4131                STAKING,
4132                &[
4133                    (VALIDATOR_ALPHA, SHARE_MAJOR),
4134                    (VALIDATOR_BETA, SHARE_DOMINANT),
4135                ],
4136                INDEX_OPTIMIZED_STAKING,
4137            )
4138            .unwrap();
4139            Pallet::place_commit(
4140                &ALICE,
4141                &STAKING,
4142                &INDEX_OPTIMIZED_STAKING,
4143                LARGE_COMMIT,
4144                &Directive::new(Precision::BestEffort, Fortitude::Polite),
4145            )
4146            .unwrap();
4147            // Alice balance state before resolvig
4148            assert_eq!(
4149                AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE),
4150                ZERO_VALUE
4151            );
4152            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), LARGE_COMMIT);
4153            assert_eq!(Pallet::get_commit_value(&ALICE, &STAKING), Ok(LARGE_COMMIT));
4154            assert_eq!(
4155                Pallet::get_index_value(&STAKING, &INDEX_OPTIMIZED_STAKING),
4156                Ok(500)
4157            );
4158            let actual_entries_value =
4159                Pallet::get_entries_value(&STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
4160            let expected_entries_value = vec![(VALIDATOR_ALPHA, 200), (VALIDATOR_BETA, 300)];
4161            assert_eq!(actual_entries_value, expected_entries_value);
4162            // Stimulating reward senario
4163            let alpha_digest_value = Pallet::get_digest_value(&STAKING, &VALIDATOR_ALPHA).unwrap();
4164            assert_eq!(alpha_digest_value, 450);
4165            let new_alpha_reward_value = alpha_digest_value + STANDARD_REWARD;
4166            Pallet::set_digest_value(
4167                &STAKING,
4168                &VALIDATOR_ALPHA,
4169                new_alpha_reward_value,
4170                &Default::default(),
4171            )
4172            .unwrap();
4173            let beta_digest_value = Pallet::get_digest_value(&STAKING, &VALIDATOR_BETA).unwrap();
4174            assert_eq!(beta_digest_value, 550);
4175            let new_beta_reward_value = beta_digest_value + STANDARD_REWARD;
4176            Pallet::set_digest_value(
4177                &STAKING,
4178                &VALIDATOR_BETA,
4179                new_beta_reward_value,
4180                &Default::default(),
4181            )
4182            .unwrap();
4183            // Index value after reward application
4184            // Note: There might be slight precision loss due to fixed-point bias arithmetic
4185            // Alice's portion should reflect proportional rewards
4186            // VALIDATOR_ALPHA bias: 500/450 ~= 1.111, VALIDATOR_BETA bias: 600/550 ~= 1.091
4187            // Alice's new value: (200 * 1.111) + (300 * 1.091) ~= 222 + 327 = 549
4188            assert_eq!(
4189                Pallet::get_index_value(&STAKING, &INDEX_OPTIMIZED_STAKING),
4190                Ok(549)
4191            );
4192            let actual_entries_value =
4193                Pallet::get_entries_value(&STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
4194            let expected_entries_value = vec![(VALIDATOR_ALPHA, 222), (VALIDATOR_BETA, 327)];
4195            assert_eq!(actual_entries_value, expected_entries_value);
4196            // Alice resolves commitment
4197            assert_ok!(Pallet::resolve_commit(&ALICE, &STAKING));
4198            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), ZERO_VALUE);
4199            // Final balance = 1000 (existing) + 549 (resolved with precision loss) = 1549
4200            assert_eq!(AssetOf::balance(&ALICE), 1549);
4201            assert_err!(
4202                Pallet::commit_exists(&ALICE, &STAKING),
4203                Error::CommitNotFound
4204            );
4205            // Remaining digest balances after alice withdrawal
4206            assert_eq!(
4207                Pallet::get_digest_value(&STAKING, &VALIDATOR_ALPHA),
4208                Ok(278)
4209            );
4210            assert_eq!(Pallet::get_digest_value(&STAKING, &VALIDATOR_BETA), Ok(273));
4211        });
4212    }
4213
4214    #[test]
4215    fn resolve_commit_withdraw_index_with_penalty_success() {
4216        commit_test_ext().execute_with(|| {
4217            set_default_user_balance_and_standard_hold(ALICE).unwrap();
4218            set_default_user_balance_and_standard_hold(CHARLIE).unwrap();
4219            set_default_user_balance_and_standard_hold(BOB).unwrap();
4220            Pallet::place_commit(
4221                &CHARLIE,
4222                &STAKING,
4223                &VALIDATOR_ALPHA,
4224                STANDARD_COMMIT,
4225                &Directive::new(Precision::Exact, Fortitude::Force),
4226            )
4227            .unwrap();
4228            Pallet::place_commit(
4229                &BOB,
4230                &STAKING,
4231                &VALIDATOR_BETA,
4232                STANDARD_COMMIT,
4233                &Directive::new(Precision::Exact, Fortitude::Force),
4234            )
4235            .unwrap();
4236            prepare_and_initiate_index(
4237                MIKE,
4238                STAKING,
4239                &[
4240                    (VALIDATOR_ALPHA, SHARE_MAJOR),
4241                    (VALIDATOR_BETA, SHARE_DOMINANT),
4242                ],
4243                INDEX_OPTIMIZED_STAKING,
4244            )
4245            .unwrap();
4246            Pallet::place_commit(
4247                &ALICE,
4248                &STAKING,
4249                &INDEX_OPTIMIZED_STAKING,
4250                LARGE_COMMIT,
4251                &Directive::new(Precision::Exact, Fortitude::Force),
4252            )
4253            .unwrap();
4254            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), LARGE_COMMIT);
4255            assert_eq!(Pallet::get_commit_value(&ALICE, &STAKING), Ok(LARGE_COMMIT));
4256            assert_eq!(
4257                Pallet::get_index_value(&STAKING, &INDEX_OPTIMIZED_STAKING),
4258                Ok(500)
4259            );
4260            let actual_entries_value =
4261                Pallet::get_entries_value(&STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
4262            let expected_entries_value = vec![(VALIDATOR_ALPHA, 200), (VALIDATOR_BETA, 300)];
4263            assert_eq!(actual_entries_value, expected_entries_value);
4264            // Stimulating penalty senario
4265            let alpha_digest_value = Pallet::get_digest_value(&STAKING, &VALIDATOR_ALPHA).unwrap();
4266            assert_eq!(alpha_digest_value, 450);
4267            let new_alpha_penalty_value = alpha_digest_value - STANDARD_PENALTY;
4268            Pallet::set_digest_value(
4269                &STAKING,
4270                &VALIDATOR_ALPHA,
4271                new_alpha_penalty_value,
4272                &Default::default(),
4273            )
4274            .unwrap();
4275            let beta_digest_value = Pallet::get_digest_value(&STAKING, &VALIDATOR_BETA).unwrap();
4276            assert_eq!(beta_digest_value, 550);
4277            let new_beta_penalty_value = beta_digest_value - STANDARD_PENALTY;
4278            Pallet::set_digest_value(
4279                &STAKING,
4280                &VALIDATOR_BETA,
4281                new_beta_penalty_value,
4282                &Default::default(),
4283            )
4284            .unwrap();
4285            // Index value after penalty application
4286            // Note: There might be slight precision loss due to fixed-point bias arithmetic
4287            // Alice's portion should reflect proportional penalty suffer
4288            assert_eq!(
4289                Pallet::get_index_value(&STAKING, &INDEX_OPTIMIZED_STAKING),
4290                Ok(400)
4291            );
4292            let actual_entries_value =
4293                Pallet::get_entries_value(&STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
4294            let expected_entries_value = vec![(VALIDATOR_ALPHA, 155), (VALIDATOR_BETA, 245)];
4295            assert_eq!(actual_entries_value, expected_entries_value);
4296            // Alice resolves commitment
4297            assert_ok!(Pallet::resolve_commit(&ALICE, &STAKING));
4298            // Final balance = 1000 (existing) + 400 (resolved) = 1400
4299            assert_eq!(AssetOf::balance(&ALICE), 1400);
4300            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), ZERO_VALUE);
4301            assert_err!(
4302                Pallet::commit_exists(&ALICE, &STAKING),
4303                Error::CommitNotFound
4304            );
4305            // Remaining digest balances after alice withdrawal
4306            assert_eq!(
4307                Pallet::get_digest_value(&STAKING, &VALIDATOR_ALPHA),
4308                Ok(195)
4309            );
4310            assert_eq!(Pallet::get_digest_value(&STAKING, &VALIDATOR_BETA), Ok(205));
4311        });
4312    }
4313
4314    #[test]
4315    fn resolve_index_commit_with_penalty_and_reward_distribution_by_entry_time() {
4316        commit_test_ext().execute_with(|| {
4317            set_default_user_balance_and_standard_hold(ALICE).unwrap();
4318            set_default_user_balance_and_standard_hold(CHARLIE).unwrap();
4319            set_default_user_balance_and_standard_hold(BOB).unwrap();
4320            set_default_user_balance_and_standard_hold(ALAN).unwrap();
4321            set_default_user_balance_and_standard_hold(NIX).unwrap();
4322            set_default_user_balance_and_standard_hold(MIKE).unwrap();
4323            Pallet::place_commit(
4324                &CHARLIE,
4325                &STAKING,
4326                &VALIDATOR_ALPHA,
4327                STANDARD_COMMIT,
4328                &Directive::new(Precision::Exact, Fortitude::Force),
4329            )
4330            .unwrap();
4331            Pallet::place_commit(
4332                &BOB,
4333                &STAKING,
4334                &VALIDATOR_BETA,
4335                STANDARD_COMMIT,
4336                &Directive::new(Precision::Exact, Fortitude::Force),
4337            )
4338            .unwrap();
4339            prepare_and_initiate_index(
4340                MIKE,
4341                STAKING,
4342                &[
4343                    (VALIDATOR_ALPHA, SHARE_MAJOR),
4344                    (VALIDATOR_BETA, SHARE_DOMINANT),
4345                ],
4346                INDEX_OPTIMIZED_STAKING,
4347            )
4348            .unwrap();
4349
4350            Pallet::place_commit(
4351                &ALAN,
4352                &STAKING,
4353                &INDEX_OPTIMIZED_STAKING,
4354                LARGE_COMMIT,
4355                &Directive::new(Precision::Exact, Fortitude::Force),
4356            )
4357            .unwrap();
4358
4359            Pallet::place_commit(
4360                &MIKE,
4361                &STAKING,
4362                &INDEX_OPTIMIZED_STAKING,
4363                STANDARD_COMMIT,
4364                &Directive::new(Precision::Exact, Fortitude::Force),
4365            )
4366            .unwrap();
4367
4368            let alan_entries_value =
4369                Pallet::get_entries_value_for(&ALAN, &STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
4370            let mike_entries_value =
4371                Pallet::get_entries_value_for(&MIKE, &STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
4372            let expected_alan_entries_value = vec![(VALIDATOR_ALPHA, 200), (VALIDATOR_BETA, 300)];
4373            let expected_mike_entries_value = vec![(VALIDATOR_ALPHA, 100), (VALIDATOR_BETA, 150)];
4374            assert_eq!(expected_alan_entries_value, alan_entries_value);
4375            assert_eq!(expected_mike_entries_value, mike_entries_value);
4376
4377            // Penalty manupulation
4378            Pallet::set_digest_value(&STAKING, &VALIDATOR_ALPHA, 500, &Default::default()).unwrap();
4379
4380            let alan_entries_value =
4381                Pallet::get_entries_value_for(&ALAN, &STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
4382            let mike_entries_value =
4383                Pallet::get_entries_value_for(&MIKE, &STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
4384            let expected_alan_entries_value = vec![(VALIDATOR_ALPHA, 181), (VALIDATOR_BETA, 300)];
4385            let expected_mike_entries_value = vec![(VALIDATOR_ALPHA, 90), (VALIDATOR_BETA, 150)];
4386            assert_eq!(expected_alan_entries_value, alan_entries_value);
4387            assert_eq!(expected_mike_entries_value, mike_entries_value);
4388
4389            let charlie_digest_value = Pallet::get_commit_value(&CHARLIE, &STAKING).unwrap();
4390            let expected_charlie_digest_value = 227;
4391            assert_eq!(expected_charlie_digest_value, charlie_digest_value);
4392
4393            Pallet::place_commit(
4394                &NIX,
4395                &STAKING,
4396                &INDEX_OPTIMIZED_STAKING,
4397                STANDARD_COMMIT,
4398                &Directive::new(Precision::Exact, Fortitude::Force),
4399            )
4400            .unwrap();
4401
4402            let nix_entries_value =
4403                Pallet::get_entries_value_for(&NIX, &STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
4404            let expected_nix_entries_value = vec![(VALIDATOR_ALPHA, 99), (VALIDATOR_BETA, 150)];
4405            assert_eq!(expected_nix_entries_value, nix_entries_value);
4406
4407            // Reward manupulation
4408            Pallet::set_digest_value(&STAKING, &VALIDATOR_ALPHA, 1000, &Default::default())
4409                .unwrap();
4410
4411            let alan_entries_value =
4412                Pallet::get_entries_value_for(&ALAN, &STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
4413            let mike_entries_value =
4414                Pallet::get_entries_value_for(&MIKE, &STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
4415            let nix_entries_value =
4416                Pallet::get_entries_value_for(&NIX, &STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
4417            let expected_alan_entries_value = vec![(VALIDATOR_ALPHA, 303), (VALIDATOR_BETA, 300)];
4418            let expected_mike_entries_value = vec![(VALIDATOR_ALPHA, 151), (VALIDATOR_BETA, 150)];
4419            let expected_nix_entries_value = vec![(VALIDATOR_ALPHA, 166), (VALIDATOR_BETA, 150)];
4420            assert_eq!(expected_alan_entries_value, alan_entries_value);
4421            assert_eq!(expected_mike_entries_value, mike_entries_value);
4422            assert_eq!(expected_nix_entries_value, nix_entries_value);
4423
4424            let charlie_digest_value = Pallet::get_commit_value(&CHARLIE, &STAKING).unwrap();
4425            let expected_charlie_digest_value = 378;
4426            assert_eq!(expected_charlie_digest_value, charlie_digest_value);
4427
4428            // Both, mike and alan absorbed the penalty and reward shock according to their weight
4429            let mike_resolved = Pallet::resolve_commit(&MIKE, &STAKING).unwrap();
4430            assert_eq!(mike_resolved, 301);
4431
4432            let alan_resolved = Pallet::resolve_commit(&ALAN, &STAKING).unwrap();
4433            assert_eq!(alan_resolved, 603);
4434
4435            // Since, nix placed a commit after the penalty he dosen't
4436            // absorbed the penalty shock but absorbs reward shock.
4437            let nix_resolved = Pallet::resolve_commit(&NIX, &STAKING).unwrap();
4438            assert_eq!(nix_resolved, 316);
4439
4440            // Charlie, as the last withdrawer, receives the remaining dust from rounding.
4441            let charlie_resolved = Pallet::resolve_commit(&CHARLIE, &STAKING).unwrap();
4442            assert_eq!(charlie_resolved, 380);
4443        })
4444    }
4445
4446    #[test]
4447    fn resolve_commit_success_for_pool() {
4448        commit_test_ext().execute_with(|| {
4449            System::set_block_number(10);
4450            set_default_user_balance_and_standard_hold(ALICE).unwrap();
4451            set_default_user_balance_and_standard_hold(BOB).unwrap();
4452            set_default_user_balance_and_standard_hold(CHARLIE).unwrap();
4453            set_default_user_balance_and_standard_hold(MIKE).unwrap();
4454
4455            Pallet::place_commit(
4456                &BOB,
4457                &STAKING,
4458                &VALIDATOR_ALPHA,
4459                STANDARD_COMMIT,
4460                &Directive::new(Precision::Exact, Fortitude::Force),
4461            )
4462            .unwrap();
4463            Pallet::place_commit(
4464                &CHARLIE,
4465                &STAKING,
4466                &VALIDATOR_BETA,
4467                STANDARD_COMMIT,
4468                &Directive::new(Precision::Exact, Fortitude::Force),
4469            )
4470            .unwrap();
4471            let entries = vec![
4472                (VALIDATOR_ALPHA, SHARE_MAJOR),
4473                (VALIDATOR_BETA, SHARE_DOMINANT),
4474            ];
4475            prepare_and_initiate_pool(
4476                MIKE,
4477                STAKING,
4478                &entries,
4479                INDEX_OPTIMIZED_STAKING,
4480                POOL_MANAGED_STAKING,
4481                COMMISSION_STANDARD,
4482            )
4483            .unwrap();
4484
4485            Pallet::place_commit(
4486                &ALICE,
4487                &STAKING,
4488                &POOL_MANAGED_STAKING,
4489                STANDARD_COMMIT,
4490                &Directive::new(Precision::Exact, Fortitude::Force),
4491            )
4492            .unwrap();
4493            // Before resolving the commit
4494            let pool_info = PoolMap::get((STAKING, POOL_MANAGED_STAKING)).unwrap();
4495            let pool_balance_of = pool_info.balance();
4496            assert_ok!(has_deposits(
4497                &pool_balance_of,
4498                &Default::default(),
4499                &POOL_MANAGED_STAKING
4500            ));
4501            assert_eq!(
4502                balance_total(&pool_balance_of, &Default::default(), &POOL_MANAGED_STAKING)
4503                    .unwrap(),
4504                STANDARD_COMMIT
4505            );
4506            let pool_capital = pool_info.capital();
4507            assert_eq!(pool_capital, 100);
4508            let actual_slots_value =
4509                Pallet::get_slots_value(&STAKING, &POOL_MANAGED_STAKING).unwrap();
4510            let expected_slots_value = vec![(VALIDATOR_ALPHA, 100), (VALIDATOR_BETA, 150)];
4511            assert_eq!(actual_slots_value, expected_slots_value);
4512
4513            let reason_value = ReasonValue::get(STAKING).unwrap();
4514            assert_eq!(reason_value, 750);
4515            // resolve the commit
4516            assert_ok!(Pallet::resolve_commit(&ALICE, &STAKING));
4517            // After resolving the commit
4518            let pool_info = PoolMap::get((STAKING, POOL_MANAGED_STAKING)).unwrap();
4519            let pool_balance_of = pool_info.balance();
4520            assert!(
4521                has_deposits(&pool_balance_of, &Default::default(), &POOL_MANAGED_STAKING).is_err()
4522            );
4523            assert_eq!(
4524                balance_total(&pool_balance_of, &Default::default(), &POOL_MANAGED_STAKING)
4525                    .unwrap(),
4526                ZERO_VALUE,
4527            );
4528            let pool_capital = pool_info.capital();
4529            assert_eq!(pool_capital, 100);
4530            let actual_slots_value =
4531                Pallet::get_slots_value(&STAKING, &POOL_MANAGED_STAKING).unwrap();
4532            let expected_slots_value =
4533                vec![(VALIDATOR_ALPHA, ZERO_VALUE), (VALIDATOR_BETA, ZERO_VALUE)];
4534            assert_eq!(actual_slots_value, expected_slots_value);
4535            let reason_value = ReasonValue::get(STAKING).unwrap();
4536            assert_eq!(reason_value, 500);
4537            // Alice Balance check
4538            // Final balance = 1000(initial) + 250(commit) - 10%(commission) -> 1225
4539            let expected_balance =
4540                INITIAL_BALANCE + STANDARD_COMMIT - (COMMISSION_STANDARD * STANDARD_COMMIT);
4541            dbg!(expected_balance);
4542            let actual_balance = AssetOf::balance(&ALICE);
4543            assert_eq!(actual_balance, expected_balance);
4544            assert_eq!(AssetOf::balance_frozen(&STAKING, &ALICE), ZERO_VALUE);
4545            // Mike Balnce check
4546            // Final balance = 1000(initial) + 10%(commission) -> 1025
4547            let expected_balance = INITIAL_BALANCE + (COMMISSION_STANDARD * STANDARD_COMMIT);
4548            let actual_balance = AssetOf::balance(&MIKE);
4549            assert_eq!(actual_balance, expected_balance);
4550
4551            #[cfg(not(feature = "dev"))]
4552            System::assert_last_event(Event::CommitResolved { 
4553                who: ALICE, 
4554                reason: STAKING, 
4555                digest: POOL_MANAGED_STAKING, 
4556                value: 225
4557                }
4558                .into()
4559            );
4560
4561            #[cfg(feature = "dev")]
4562            System::assert_last_event(Event::CommitResolved { 
4563                who: ALICE, 
4564                reason: STAKING, 
4565                model: DigestVariant::Pool(POOL_MANAGED_STAKING), 
4566                value: 225
4567                }
4568                .into()
4569            );
4570        })
4571    }
4572
4573    #[test]
4574    fn resolve_commit_withdraw_pool_with_reward_success() {
4575        commit_test_ext().execute_with(|| {
4576            set_default_user_balance_and_standard_hold(ALICE).unwrap();
4577            set_default_user_balance_and_standard_hold(BOB).unwrap();
4578            set_default_user_balance_and_standard_hold(CHARLIE).unwrap();
4579            set_default_user_balance_and_standard_hold(ALAN).unwrap();
4580            set_default_user_balance_and_standard_hold(MIKE).unwrap();
4581
4582            Pallet::place_commit(
4583                &ALICE,
4584                &STAKING,
4585                &VALIDATOR_ALPHA,
4586                STANDARD_COMMIT,
4587                &Directive::new(Precision::Exact, Fortitude::Force),
4588            )
4589            .unwrap();
4590            Pallet::place_commit(
4591                &BOB,
4592                &STAKING,
4593                &VALIDATOR_BETA,
4594                STANDARD_COMMIT,
4595                &Directive::new(Precision::Exact, Fortitude::Force),
4596            )
4597            .unwrap();
4598            let entries = vec![
4599                (VALIDATOR_ALPHA, SHARE_MAJOR),
4600                (VALIDATOR_BETA, SHARE_DOMINANT),
4601            ];
4602            prepare_and_initiate_pool(
4603                MIKE,
4604                STAKING,
4605                &entries,
4606                INDEX_OPTIMIZED_STAKING,
4607                POOL_MANAGED_STAKING,
4608                COMMISSION_STANDARD,
4609            )
4610            .unwrap();
4611            Pallet::place_commit(
4612                &CHARLIE,
4613                &STAKING,
4614                &POOL_MANAGED_STAKING,
4615                LARGE_COMMIT,
4616                &Directive::new(Precision::Exact, Fortitude::Force),
4617            )
4618            .unwrap();
4619            // Before resolving the commit
4620            let actual_pool_balance =
4621                Pallet::get_pool_value(&STAKING, &POOL_MANAGED_STAKING).unwrap();
4622            assert_eq!(actual_pool_balance, LARGE_COMMIT);
4623            let actual_slots_value =
4624                Pallet::get_slots_value(&STAKING, &POOL_MANAGED_STAKING).unwrap();
4625            let expected_slots_value = vec![(VALIDATOR_ALPHA, 200), (VALIDATOR_BETA, 300)];
4626            assert_eq!(actual_slots_value, expected_slots_value);
4627
4628            let reason_value = ReasonValue::get(STAKING).unwrap();
4629            assert_eq!(reason_value, 1000);
4630            // Simulating reward senario
4631            let alpha_digest_value = Pallet::get_digest_value(&STAKING, &VALIDATOR_ALPHA).unwrap();
4632            assert_eq!(alpha_digest_value, 450);
4633            let new_alpha_reward_value = alpha_digest_value + STANDARD_REWARD; //450 + 50(reward) -> 500
4634            Pallet::set_digest_value(
4635                &STAKING,
4636                &VALIDATOR_ALPHA,
4637                new_alpha_reward_value,
4638                &Default::default(),
4639            )
4640            .unwrap();
4641            let beta_digest_value = Pallet::get_digest_value(&STAKING, &VALIDATOR_BETA).unwrap();
4642            assert_eq!(beta_digest_value, 550);
4643            let new_beta_reward_value = beta_digest_value + STANDARD_REWARD; //550 + 50(reward) -> 600
4644            Pallet::set_digest_value(
4645                &STAKING,
4646                &VALIDATOR_BETA,
4647                new_beta_reward_value,
4648                &Default::default(),
4649            )
4650            .unwrap();
4651            // Underlying digests value after reward senario
4652            let alpha_digest_value = Pallet::get_digest_value(&STAKING, &VALIDATOR_ALPHA).unwrap();
4653            assert_eq!(alpha_digest_value, 500);
4654            let beta_digest_value = Pallet::get_digest_value(&STAKING, &VALIDATOR_BETA).unwrap();
4655            assert_eq!(beta_digest_value, 600);
4656            // Pool value updated
4657            let pool_value = Pallet::get_pool_value(&STAKING, &POOL_MANAGED_STAKING).unwrap();
4658            // precision loss catered
4659            assert_eq!(pool_value, 549);
4660            let actual_slots_value =
4661                Pallet::get_slots_value(&STAKING, &POOL_MANAGED_STAKING).unwrap();
4662            let expected_slots_value = vec![(VALIDATOR_ALPHA, 222), (VALIDATOR_BETA, 327)];
4663            assert_eq!(actual_slots_value, expected_slots_value);
4664
4665            // resolve the commit
4666            assert_ok!(Pallet::resolve_commit(&CHARLIE, &STAKING));
4667
4668            // After resolving the commit
4669            let pool_info = PoolMap::get((STAKING, POOL_MANAGED_STAKING)).unwrap();
4670            let pool_balance_of = pool_info.balance();
4671            assert!(
4672                has_deposits(&pool_balance_of, &Default::default(), &POOL_MANAGED_STAKING).is_err()
4673            );
4674            assert_eq!(
4675                balance_total(&pool_balance_of, &Default::default(), &POOL_MANAGED_STAKING)
4676                    .unwrap(),
4677                0,
4678            );
4679
4680            let actual_slots_value =
4681                Pallet::get_slots_value(&STAKING, &POOL_MANAGED_STAKING).unwrap();
4682            let expected_slots_value = vec![(VALIDATOR_ALPHA, 0), (VALIDATOR_BETA, 0)];
4683            assert_eq!(actual_slots_value, expected_slots_value);
4684
4685            // Underlying digests value after resolving pool commit
4686            let alpha_digest_value = Pallet::get_digest_value(&STAKING, &VALIDATOR_ALPHA).unwrap();
4687            assert_eq!(alpha_digest_value, 278);
4688            let beta_digest_value = Pallet::get_digest_value(&STAKING, &VALIDATOR_BETA).unwrap();
4689            assert_eq!(beta_digest_value, 273);
4690
4691            let reason_value = ReasonValue::get(STAKING).unwrap();
4692            assert_eq!(reason_value, 551);
4693
4694            // Charlies balance check
4695            let actual_balance = AssetOf::balance(&CHARLIE);
4696            let expected_balance = INITIAL_BALANCE + 495; // initial_balance + resolved_blance with commission deduction
4697
4698            assert_eq!(actual_balance, expected_balance);
4699            let actual_freeze_balance = AssetOf::balance_frozen(&STAKING, &CHARLIE);
4700            assert_eq!(actual_freeze_balance, ZERO_VALUE);
4701
4702            // Mike balance check for commison settlement
4703            let actual_balance = AssetOf::balance(&MIKE);
4704            let expected_balance = INITIAL_BALANCE + 54; // initial_balance + commission for the resolved commit
4705            assert_eq!(actual_balance, expected_balance);
4706        });
4707    }
4708
4709    #[test]
4710    fn resolve_commit_withdraw_pool_with_penalty_success() {
4711        commit_test_ext().execute_with(|| {
4712            set_default_user_balance_and_standard_hold(ALICE).unwrap();
4713            set_default_user_balance_and_standard_hold(BOB).unwrap();
4714            set_default_user_balance_and_standard_hold(CHARLIE).unwrap();
4715            set_default_user_balance_and_standard_hold(ALAN).unwrap();
4716            set_default_user_balance_and_standard_hold(MIKE).unwrap();
4717
4718            Pallet::place_commit(
4719                &ALICE,
4720                &STAKING,
4721                &VALIDATOR_ALPHA,
4722                STANDARD_COMMIT,
4723                &Directive::new(Precision::Exact, Fortitude::Force),
4724            )
4725            .unwrap();
4726            Pallet::place_commit(
4727                &BOB,
4728                &STAKING,
4729                &VALIDATOR_BETA,
4730                STANDARD_COMMIT,
4731                &Directive::new(Precision::Exact, Fortitude::Force),
4732            )
4733            .unwrap();
4734            let entries = vec![
4735                (VALIDATOR_ALPHA, SHARE_MAJOR),
4736                (VALIDATOR_BETA, SHARE_DOMINANT),
4737            ];
4738            prepare_and_initiate_pool(
4739                MIKE,
4740                STAKING,
4741                &entries,
4742                INDEX_OPTIMIZED_STAKING,
4743                POOL_MANAGED_STAKING,
4744                COMMISSION_STANDARD,
4745            )
4746            .unwrap();
4747            Pallet::place_commit(
4748                &CHARLIE,
4749                &STAKING,
4750                &POOL_MANAGED_STAKING,
4751                LARGE_COMMIT,
4752                &Directive::new(Precision::Exact, Fortitude::Force),
4753            )
4754            .unwrap();
4755            // Before resolving the commit
4756            let actual_pool_balance =
4757                Pallet::get_pool_value(&STAKING, &POOL_MANAGED_STAKING).unwrap();
4758            assert_eq!(actual_pool_balance, LARGE_COMMIT);
4759            let actual_slots_value =
4760                Pallet::get_slots_value(&STAKING, &POOL_MANAGED_STAKING).unwrap();
4761            let expected_slots_value = vec![(VALIDATOR_ALPHA, 200), (VALIDATOR_BETA, 300)];
4762            assert_eq!(actual_slots_value, expected_slots_value);
4763
4764            let reason_value = ReasonValue::get(STAKING).unwrap();
4765            assert_eq!(reason_value, 1000);
4766            // Simulating penalty senario
4767            let alpha_digest_value = Pallet::get_digest_value(&STAKING, &VALIDATOR_ALPHA).unwrap();
4768            assert_eq!(alpha_digest_value, 450);
4769            let new_alpha_reward_value = alpha_digest_value - STANDARD_PENALTY; //450 - 100(penalty) -> 350
4770            Pallet::set_digest_value(
4771                &STAKING,
4772                &VALIDATOR_ALPHA,
4773                new_alpha_reward_value,
4774                &Default::default(),
4775            )
4776            .unwrap();
4777            let beta_digest_value = Pallet::get_digest_value(&STAKING, &VALIDATOR_BETA).unwrap();
4778            assert_eq!(beta_digest_value, 550);
4779            let new_beta_reward_value = beta_digest_value - SMALL_PENALTY; //550 - 10(reward) -> 540
4780            Pallet::set_digest_value(
4781                &STAKING,
4782                &VALIDATOR_BETA,
4783                new_beta_reward_value,
4784                &Default::default(),
4785            )
4786            .unwrap();
4787            // Underlying digests value after penalty senario
4788            let alpha_digest_value = Pallet::get_digest_value(&STAKING, &VALIDATOR_ALPHA).unwrap();
4789            assert_eq!(alpha_digest_value, 350);
4790            let beta_digest_value = Pallet::get_digest_value(&STAKING, &VALIDATOR_BETA).unwrap();
4791            assert_eq!(beta_digest_value, 540);
4792            // Pool value updated
4793            let pool_value = Pallet::get_pool_value(&STAKING, &POOL_MANAGED_STAKING).unwrap();
4794            assert_eq!(pool_value, 449);
4795            let actual_slots_value =
4796                Pallet::get_slots_value(&STAKING, &POOL_MANAGED_STAKING).unwrap();
4797            let expected_slots_value = vec![(VALIDATOR_ALPHA, 155), (VALIDATOR_BETA, 294)];
4798            assert_eq!(actual_slots_value, expected_slots_value);
4799
4800            // resolve the commit
4801            assert_ok!(Pallet::resolve_commit(&CHARLIE, &STAKING));
4802
4803            // After resolving the commit
4804            let pool_info = PoolMap::get((STAKING, POOL_MANAGED_STAKING)).unwrap();
4805            let pool_balance_of = pool_info.balance();
4806            assert!(
4807                has_deposits(&pool_balance_of, &Default::default(), &POOL_MANAGED_STAKING).is_err()
4808            );
4809            assert_eq!(
4810                balance_total(&pool_balance_of, &Default::default(), &POOL_MANAGED_STAKING)
4811                    .unwrap(),
4812                0,
4813            );
4814
4815            let actual_slots_value =
4816                Pallet::get_slots_value(&STAKING, &POOL_MANAGED_STAKING).unwrap();
4817            let expected_slots_value = vec![(VALIDATOR_ALPHA, 0), (VALIDATOR_BETA, 0)];
4818            assert_eq!(actual_slots_value, expected_slots_value);
4819
4820            // Underlying digests value after resolving pool commit
4821            let alpha_digest_value = Pallet::get_digest_value(&STAKING, &VALIDATOR_ALPHA).unwrap();
4822            assert_eq!(alpha_digest_value, 195);
4823            let beta_digest_value = Pallet::get_digest_value(&STAKING, &VALIDATOR_BETA).unwrap();
4824            assert_eq!(beta_digest_value, 246);
4825
4826            let reason_value = ReasonValue::get(STAKING).unwrap();
4827            assert_eq!(reason_value, 441);
4828
4829            // Charlies balance check
4830            let actual_balance = AssetOf::balance(&CHARLIE);
4831            let expected_balance = INITIAL_BALANCE + 405; // initial_balance + resolved_blance with commission deduction
4832
4833            assert_eq!(actual_balance, expected_balance);
4834            let actual_freeze_balance = AssetOf::balance_frozen(&STAKING, &CHARLIE);
4835            assert_eq!(actual_freeze_balance, ZERO_VALUE);
4836
4837            // Mike balance check for commison settlement
4838            let actual_balance = AssetOf::balance(&MIKE);
4839            let expected_balance = INITIAL_BALANCE + 44; // initial_balance + commission for the resolved commit
4840            assert_eq!(actual_balance, expected_balance);
4841        });
4842    }
4843
4844    #[test]
4845    fn resolve_pool_commit_with_penalty_and_reward_distribution_by_entry_time() {
4846        commit_test_ext().execute_with(|| {
4847            set_default_user_balance_and_standard_hold(ALICE).unwrap();
4848            set_default_user_balance_and_standard_hold(CHARLIE).unwrap();
4849            set_default_user_balance_and_standard_hold(BOB).unwrap();
4850            set_default_user_balance_and_standard_hold(ALAN).unwrap();
4851            set_default_user_balance_and_standard_hold(NIX).unwrap();
4852            set_default_user_balance_and_standard_hold(MIKE).unwrap();
4853            set_default_user_balance_and_standard_hold(DAVE).unwrap();
4854
4855            Pallet::place_commit(
4856                &CHARLIE,
4857                &STAKING,
4858                &VALIDATOR_ALPHA,
4859                STANDARD_COMMIT,
4860                &Directive::new(Precision::Exact, Fortitude::Force),
4861            )
4862            .unwrap();
4863            Pallet::place_commit(
4864                &BOB,
4865                &STAKING,
4866                &VALIDATOR_BETA,
4867                STANDARD_COMMIT,
4868                &Directive::new(Precision::Exact, Fortitude::Force),
4869            )
4870            .unwrap();
4871
4872            prepare_and_initiate_pool(
4873                DAVE,
4874                STAKING,
4875                &[
4876                    (VALIDATOR_ALPHA, SHARE_MAJOR),
4877                    (VALIDATOR_BETA, SHARE_DOMINANT),
4878                ],
4879                INDEX_OPTIMIZED_STAKING,
4880                POOL_MANAGED_STAKING,
4881                COMMISSION_STANDARD,
4882            )
4883            .unwrap();
4884
4885            Pallet::place_commit(
4886                &ALAN,
4887                &STAKING,
4888                &POOL_MANAGED_STAKING,
4889                LARGE_COMMIT,
4890                &Directive::new(Precision::Exact, Fortitude::Force),
4891            )
4892            .unwrap();
4893
4894            Pallet::place_commit(
4895                &MIKE,
4896                &STAKING,
4897                &POOL_MANAGED_STAKING,
4898                STANDARD_COMMIT,
4899                &Directive::new(Precision::Exact, Fortitude::Force),
4900            )
4901            .unwrap();
4902
4903            let pool_value = Pallet::get_pool_value(&STAKING, &POOL_MANAGED_STAKING).unwrap();
4904            assert_eq!(pool_value, 750);
4905            let alan_slots_value =
4906                Pallet::get_slots_value_for(&ALAN, &STAKING, &POOL_MANAGED_STAKING).unwrap();
4907            let mike_slots_value =
4908                Pallet::get_slots_value_for(&MIKE, &STAKING, &POOL_MANAGED_STAKING).unwrap();
4909            let expected_alan_slots_value = vec![(VALIDATOR_ALPHA, 200), (VALIDATOR_BETA, 300)];
4910            let expected_mike_slots_value = vec![(VALIDATOR_ALPHA, 100), (VALIDATOR_BETA, 150)];
4911            assert_eq!(expected_alan_slots_value, alan_slots_value);
4912            assert_eq!(expected_mike_slots_value, mike_slots_value);
4913
4914            // Penalty manupulation
4915            Pallet::set_digest_value(&STAKING, &VALIDATOR_ALPHA, 500, &Default::default()).unwrap();
4916
4917            let pool_value = Pallet::get_pool_value(&STAKING, &POOL_MANAGED_STAKING).unwrap();
4918            assert_eq!(pool_value, 722);
4919
4920            let alan_slots_value =
4921                Pallet::get_slots_value_for(&ALAN, &STAKING, &POOL_MANAGED_STAKING).unwrap();
4922            let mike_slots_value =
4923                Pallet::get_slots_value_for(&MIKE, &STAKING, &POOL_MANAGED_STAKING).unwrap();
4924            let expected_alan_slots_value = vec![(VALIDATOR_ALPHA, 192), (VALIDATOR_BETA, 288)];
4925            let expected_mike_slots_value = vec![(VALIDATOR_ALPHA, 96), (VALIDATOR_BETA, 144)];
4926            assert_eq!(expected_alan_slots_value, alan_slots_value);
4927            assert_eq!(expected_mike_slots_value, mike_slots_value);
4928
4929            let charlie_digest_value = Pallet::get_commit_value(&CHARLIE, &STAKING).unwrap();
4930            let expected_charlie_digest_value = 227;
4931            assert_eq!(expected_charlie_digest_value, charlie_digest_value);
4932
4933            Pallet::place_commit(
4934                &NIX,
4935                &STAKING,
4936                &POOL_MANAGED_STAKING,
4937                STANDARD_COMMIT,
4938                &Directive::new(Precision::Exact, Fortitude::Force),
4939            )
4940            .unwrap();
4941
4942            let nix_slots_value =
4943                Pallet::get_slots_value_for(&NIX, &STAKING, &POOL_MANAGED_STAKING).unwrap();
4944            let expected_nix_slots_value = vec![(VALIDATOR_ALPHA, 99), (VALIDATOR_BETA, 148)];
4945            assert_eq!(expected_nix_slots_value, nix_slots_value);
4946
4947            // Reward manupulation
4948            Pallet::set_digest_value(&STAKING, &VALIDATOR_ALPHA, 1000, &Default::default())
4949                .unwrap();
4950
4951            let pool_value = Pallet::get_pool_value(&STAKING, &POOL_MANAGED_STAKING).unwrap();
4952            assert_eq!(pool_value, 1213);
4953            let alan_slots_value =
4954                Pallet::get_slots_value_for(&ALAN, &STAKING, &POOL_MANAGED_STAKING).unwrap();
4955            let mike_slots_value =
4956                Pallet::get_slots_value_for(&MIKE, &STAKING, &POOL_MANAGED_STAKING).unwrap();
4957            let nix_slots_value =
4958                Pallet::get_slots_value_for(&NIX, &STAKING, &POOL_MANAGED_STAKING).unwrap();
4959            let expected_alan_slots_value = vec![(VALIDATOR_ALPHA, 240), (VALIDATOR_BETA, 360)];
4960            let expected_mike_slots_value = vec![(VALIDATOR_ALPHA, 120), (VALIDATOR_BETA, 180)];
4961            let expected_nix_slots_value = vec![(VALIDATOR_ALPHA, 124), (VALIDATOR_BETA, 186)];
4962            assert_eq!(expected_alan_slots_value, alan_slots_value);
4963            assert_eq!(expected_mike_slots_value, mike_slots_value);
4964            assert_eq!(expected_nix_slots_value, nix_slots_value);
4965
4966            let charlie_digest_value = Pallet::get_commit_value(&CHARLIE, &STAKING).unwrap();
4967            let expected_charlie_digest_value = 369;
4968            assert_eq!(expected_charlie_digest_value, charlie_digest_value);
4969
4970            // Both, mike and alan absorbed the penalty and reward shock according to their weight
4971            let mike_resolved = Pallet::resolve_commit(&MIKE, &STAKING).unwrap();
4972            assert_eq!(mike_resolved, 270);
4973
4974            let alan_resolved = Pallet::resolve_commit(&ALAN, &STAKING).unwrap();
4975            assert_eq!(alan_resolved, 540);
4976
4977            // Since, nix placed a commit after the penalty he dosen't
4978            // absorbed the penalty shock but absorbs reward shock.
4979            let nix_resolved = Pallet::resolve_commit(&NIX, &STAKING).unwrap();
4980            assert_eq!(nix_resolved, 278);
4981
4982            // Charlie, as the last withdrawer, receives the remaining dust from rounding.
4983            let charlie_resolved = Pallet::resolve_commit(&CHARLIE, &STAKING).unwrap();
4984            assert_eq!(charlie_resolved, 374);
4985
4986            // dev gets his commission from all above resolutions
4987            let dev_balance = AssetOf::balance(&DAVE);
4988            assert_eq!(dev_balance, 1122); // 1000 -> 1122 (commission)
4989        })
4990    }
4991
4992    #[test]
4993    fn resolve_commit_withdraw_pool_with_hundred_percent_commisison() {
4994        commit_test_ext().execute_with(|| {
4995            set_default_user_balance_and_standard_hold(ALICE).unwrap();
4996            set_default_user_balance_and_standard_hold(BOB).unwrap();
4997            set_default_user_balance_and_standard_hold(CHARLIE).unwrap();
4998            set_default_user_balance_and_standard_hold(ALAN).unwrap();
4999            set_default_user_balance_and_standard_hold(MIKE).unwrap();
5000
5001            Pallet::place_commit(
5002                &ALICE,
5003                &STAKING,
5004                &VALIDATOR_ALPHA,
5005                STANDARD_COMMIT,
5006                &Directive::new(Precision::Exact, Fortitude::Force),
5007            )
5008            .unwrap();
5009            Pallet::place_commit(
5010                &BOB,
5011                &STAKING,
5012                &VALIDATOR_BETA,
5013                STANDARD_COMMIT,
5014                &Directive::new(Precision::Exact, Fortitude::Force),
5015            )
5016            .unwrap();
5017            let entries = vec![
5018                (VALIDATOR_ALPHA, SHARE_MAJOR),
5019                (VALIDATOR_BETA, SHARE_DOMINANT),
5020            ];
5021            prepare_and_initiate_pool(
5022                MIKE,
5023                STAKING,
5024                &entries,
5025                INDEX_OPTIMIZED_STAKING,
5026                POOL_MANAGED_STAKING,
5027                COMMISSION_MAX,
5028            )
5029            .unwrap();
5030            Pallet::place_commit(
5031                &CHARLIE,
5032                &STAKING,
5033                &POOL_MANAGED_STAKING,
5034                LARGE_COMMIT,
5035                &Directive::new(Precision::Exact, Fortitude::Force),
5036            )
5037            .unwrap();
5038            // Before resolving the commit
5039            let actual_pool_balance =
5040                Pallet::get_pool_value(&STAKING, &POOL_MANAGED_STAKING).unwrap();
5041            assert_eq!(actual_pool_balance, LARGE_COMMIT);
5042            let actual_slots_value =
5043                Pallet::get_slots_value(&STAKING, &POOL_MANAGED_STAKING).unwrap();
5044            let expected_slots_value = vec![(VALIDATOR_ALPHA, 200), (VALIDATOR_BETA, 300)];
5045            assert_eq!(actual_slots_value, expected_slots_value);
5046
5047            let reason_value = ReasonValue::get(STAKING).unwrap();
5048            assert_eq!(reason_value, 1000);
5049
5050            // resolve the commit
5051            assert_ok!(Pallet::resolve_commit(&CHARLIE, &STAKING));
5052
5053            // After resolving the commit
5054            let pool_info = PoolMap::get((STAKING, POOL_MANAGED_STAKING)).unwrap();
5055            let pool_balance_of = pool_info.balance();
5056            assert!(
5057                has_deposits(&pool_balance_of, &Default::default(), &POOL_MANAGED_STAKING).is_err()
5058            );
5059            assert_eq!(
5060                balance_total(&pool_balance_of, &Default::default(), &POOL_MANAGED_STAKING)
5061                    .unwrap(),
5062                0,
5063            );
5064
5065            let actual_slots_value =
5066                Pallet::get_slots_value(&STAKING, &POOL_MANAGED_STAKING).unwrap();
5067            let expected_slots_value = vec![(VALIDATOR_ALPHA, 0), (VALIDATOR_BETA, 0)];
5068            assert_eq!(actual_slots_value, expected_slots_value);
5069
5070            // Underlying digests value after resolving pool commit
5071            let alpha_digest_value = Pallet::get_digest_value(&STAKING, &VALIDATOR_ALPHA).unwrap();
5072            assert_eq!(alpha_digest_value, 250);
5073            let beta_digest_value = Pallet::get_digest_value(&STAKING, &VALIDATOR_BETA).unwrap();
5074            assert_eq!(beta_digest_value, 250);
5075
5076            let reason_value = ReasonValue::get(STAKING).unwrap();
5077            assert_eq!(reason_value, 500);
5078
5079            // Charlies balance check (resolving balance = 0, since the commisison is 100% of the total resolved balance)
5080            let actual_balance = AssetOf::balance(&CHARLIE);
5081            let expected_balance = INITIAL_BALANCE + 0; // initial_balance + resolved_blance with commission deduction
5082
5083            assert_eq!(actual_balance, expected_balance);
5084            let actual_freeze_balance = AssetOf::balance_frozen(&STAKING, &CHARLIE);
5085            assert_eq!(actual_freeze_balance, ZERO_VALUE);
5086
5087            // Mike balance check for commison settlement (100% commission)
5088            let actual_balance = AssetOf::balance(&MIKE);
5089            let expected_balance = INITIAL_BALANCE + 500; // initial_balance + commission for the resolved commit
5090            assert_eq!(actual_balance, expected_balance);
5091        });
5092    }
5093
5094    #[test]
5095    fn resolve_commit_err_commit_not_found() {
5096        commit_test_ext().execute_with(|| {
5097            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5098            Pallet::place_commit(
5099                &ALICE,
5100                &GOVERNANCE,
5101                &PROPOSAL_RUNTIME_UPGRADE,
5102                STANDARD_COMMIT,
5103                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5104            )
5105            .unwrap();
5106            assert_err!(
5107                Pallet::resolve_commit(&ALICE, &ESCROW,),
5108                Error::CommitNotFound
5109            );
5110        })
5111    }
5112
5113    #[test]
5114    fn gen_digest_success() {
5115        commit_test_ext().execute_with(|| {
5116            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5117            set_default_user_balance_and_standard_hold(BOB).unwrap();
5118            let gen_digest_1 = Pallet::gen_digest(&ALICE);
5119            assert!(gen_digest_1.is_ok());
5120            let gen_digest_2 = Pallet::gen_digest(&ALICE);
5121            assert!(gen_digest_2.is_ok());
5122            assert_eq!(gen_digest_1, gen_digest_2); // deterministic key generation
5123
5124            // manual mutation of account nonce
5125            Account::mutate(&ALICE, |info| {
5126                info.nonce = 2;
5127            });
5128            let gen_digest_3 = Pallet::gen_digest(&ALICE);
5129            assert!(gen_digest_3.is_ok());
5130            assert_ne!(gen_digest_2, gen_digest_3); // unique key generation accross different nonce
5131
5132            // manual mutation of account nonce
5133            Account::mutate(&ALICE, |info| {
5134                info.nonce = 4;
5135            });
5136            let gen_digest_4 = Pallet::gen_digest(&ALICE);
5137            assert!(gen_digest_4.is_ok());
5138            assert_ne!(gen_digest_3, gen_digest_4); // unique key generation accross same source with different nonce
5139            let gen_digest_5 = Pallet::gen_digest(&BOB);
5140            assert!(gen_digest_5.is_ok());
5141            assert_ne!(gen_digest_5, gen_digest_4); // unique key generation accross different source
5142            let gen_digest_6 = Pallet::gen_digest(&CHARLIE);
5143            assert!(gen_digest_6.is_ok());
5144            assert_ne!(gen_digest_5, gen_digest_6); // unique key generation accross different source with same nonce
5145        })
5146    }
5147
5148    #[test]
5149    fn commit_exists_ok() {
5150        commit_test_ext().execute_with(|| {
5151            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5152            Pallet::place_commit(
5153                &ALICE,
5154                &STAKING,
5155                &VALIDATOR_ALPHA,
5156                STANDARD_COMMIT,
5157                &Directive::new(Precision::Exact, Fortitude::Force),
5158            )
5159            .unwrap();
5160            assert_ok!(Pallet::commit_exists(&ALICE, &STAKING));
5161        })
5162    }
5163
5164    #[test]
5165    fn commit_exists_err_commit_not_found() {
5166        commit_test_ext().execute_with(|| {
5167            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5168            Pallet::place_commit(
5169                &ALICE,
5170                &STAKING,
5171                &VALIDATOR_ALPHA,
5172                STANDARD_COMMIT,
5173                &Directive::new(Precision::BestEffort, Fortitude::Force),
5174            )
5175            .unwrap();
5176            assert_err!(
5177                Pallet::commit_exists(&ALICE, &GOVERNANCE),
5178                Error::CommitNotFound
5179            );
5180        })
5181    }
5182
5183    #[test]
5184    fn digest_exists_ok() {
5185        commit_test_ext().execute_with(|| {
5186            initiate_digest_with_default_balance(GOVERNANCE, PROPOSAL_RUNTIME_UPGRADE).unwrap();
5187            assert_ok!(Pallet::digest_exists(
5188                &GOVERNANCE,
5189                &PROPOSAL_RUNTIME_UPGRADE,
5190            ));
5191        });
5192    }
5193
5194    #[test]
5195    fn digest_exists_err_digest_not_found() {
5196        commit_test_ext().execute_with(|| {
5197            initiate_digest_with_default_balance(GOVERNANCE, PROPOSAL_RUNTIME_UPGRADE).unwrap();
5198            assert_err!(
5199                Pallet::digest_exists(&GOVERNANCE, &PROPOSAL_TREASURY_SPEND),
5200                Error::DigestNotFound
5201            );
5202        })
5203    }
5204
5205    #[test]
5206    fn get_commit_digest_success() {
5207        commit_test_ext().execute_with(|| {
5208            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5209            Pallet::place_commit(
5210                &ALICE,
5211                &ESCROW,
5212                &CONTRACT_FREELANCE,
5213                STANDARD_COMMIT,
5214                &Directive::new(Precision::Exact, Fortitude::Force),
5215            )
5216            .unwrap();
5217            let commit_digest = Pallet::get_commit_digest(&ALICE, &ESCROW).unwrap();
5218            assert_eq!(commit_digest, CONTRACT_FREELANCE);
5219        })
5220    }
5221
5222    #[test]
5223    fn get_commit_digest_err_commit_not_found() {
5224        commit_test_ext().execute_with(|| {
5225            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5226            Pallet::place_commit(
5227                &ALICE,
5228                &ESCROW,
5229                &CONTRACT_FREELANCE,
5230                STANDARD_COMMIT,
5231                &Directive::new(Precision::Exact, Fortitude::Force),
5232            )
5233            .unwrap();
5234            assert_err!(
5235                Pallet::get_commit_digest(&ALICE, &STAKING),
5236                Error::CommitNotFound
5237            );
5238        })
5239    }
5240
5241    #[test]
5242    fn get_total_value_works() {
5243        commit_test_ext().execute_with(|| {
5244            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5245            set_default_user_balance_and_standard_hold(BOB).unwrap();
5246            set_default_user_balance_and_standard_hold(CHARLIE).unwrap();
5247
5248            Pallet::place_commit(
5249                &ALICE,
5250                &STAKING,
5251                &VALIDATOR_ALPHA,
5252                STANDARD_COMMIT,
5253                &Directive::new(Precision::Exact, Fortitude::Force),
5254            )
5255            .unwrap();
5256            let total_value = Pallet::get_total_value(&STAKING);
5257            assert_eq!(total_value, 250);
5258            Pallet::place_commit(
5259                &BOB,
5260                &STAKING,
5261                &VALIDATOR_BETA,
5262                LARGE_COMMIT,
5263                &Directive::new(Precision::Exact, Fortitude::Force),
5264            )
5265            .unwrap();
5266            // total commited value for staking reason
5267            let total_value = Pallet::get_total_value(&STAKING);
5268            assert_eq!(total_value, 750); // 250 + 500 -> 750
5269
5270            // total commited value for bet reason
5271            let total_value = Pallet::get_total_value(&ESCROW);
5272            assert_eq!(total_value, 0); // no commits for escrow reason yet
5273            Pallet::place_commit(
5274                &BOB,
5275                &ESCROW,
5276                &CONTRACT_FREELANCE,
5277                LARGE_COMMIT,
5278                &Directive::new(Precision::Exact, Fortitude::Force),
5279            )
5280            .unwrap();
5281            // total commited value for escrow reason
5282            let total_value = Pallet::get_total_value(&ESCROW);
5283            assert_eq!(total_value, 500);
5284        })
5285    }
5286
5287    #[test]
5288    fn get_commit_value_for_direct_success() {
5289        commit_test_ext().execute_with(|| {
5290            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5291            Pallet::place_commit(
5292                &ALICE,
5293                &STAKING,
5294                &VALIDATOR_ALPHA,
5295                STANDARD_COMMIT,
5296                &Directive::new(Precision::Exact, Fortitude::Force),
5297            )
5298            .unwrap();
5299            let commit_value = Pallet::get_commit_value(&ALICE, &STAKING).unwrap();
5300            assert_eq!(commit_value, STANDARD_COMMIT);
5301        })
5302    }
5303
5304    #[test]
5305    fn get_commit_value_for_index_success() {
5306        commit_test_ext().execute_with(|| {
5307            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5308            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
5309            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
5310            prepare_and_initiate_index(
5311                MIKE,
5312                STAKING,
5313                &[
5314                    (VALIDATOR_ALPHA, SHARE_EQUAL),
5315                    (VALIDATOR_BETA, SHARE_EQUAL),
5316                ],
5317                INDEX_BALANCED_STAKING,
5318            )
5319            .unwrap();
5320            assert_ok!(Pallet::index_exists(&STAKING, &INDEX_BALANCED_STAKING));
5321            // Place commit to an index
5322            Pallet::place_commit(
5323                &ALICE,
5324                &STAKING,
5325                &INDEX_BALANCED_STAKING,
5326                STANDARD_COMMIT,
5327                &Directive::new(Precision::Exact, Fortitude::Force),
5328            )
5329            .unwrap();
5330            let actual_commit_value = Pallet::get_commit_value(&ALICE, &STAKING).unwrap();
5331            assert_eq!(actual_commit_value, STANDARD_COMMIT);
5332        })
5333    }
5334
5335    #[test]
5336    fn get_commit_value_for_pool_success() {
5337        commit_test_ext().execute_with(|| {
5338            set_default_user_balance_and_standard_hold(BOB).unwrap();
5339            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
5340            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
5341            let entries = vec![
5342                (VALIDATOR_ALPHA, SHARE_EQUAL),
5343                (VALIDATOR_BETA, SHARE_EQUAL),
5344            ];
5345            prepare_and_initiate_pool(
5346                MIKE,
5347                STAKING,
5348                &entries,
5349                INDEX_BALANCED_STAKING,
5350                POOL_MANAGED_STAKING,
5351                COMMISSION_LOW,
5352            )
5353            .unwrap();
5354            Pallet::place_commit(
5355                &BOB,
5356                &STAKING,
5357                &POOL_MANAGED_STAKING,
5358                LARGE_COMMIT,
5359                &Directive::new(Precision::Exact, Fortitude::Force),
5360            )
5361            .unwrap();
5362            let actual_commit_value = Pallet::get_commit_value(&BOB, &STAKING).unwrap();
5363            assert_eq!(actual_commit_value, LARGE_COMMIT);
5364        })
5365    }
5366
5367    #[test]
5368    fn get_digets_value_success() {
5369        commit_test_ext().execute_with(|| {
5370            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5371            set_default_user_balance_and_standard_hold(BOB).unwrap();
5372
5373            Pallet::place_commit(
5374                &ALICE,
5375                &ESCROW,
5376                &CONTRACT_FREELANCE,
5377                STANDARD_COMMIT,
5378                &Directive::new(Precision::Exact, Fortitude::Force),
5379            )
5380            .unwrap();
5381            let digets_value = Pallet::get_digest_value(&ESCROW, &CONTRACT_FREELANCE).unwrap();
5382            assert_eq!(digets_value, STANDARD_COMMIT);
5383            Pallet::place_commit(
5384                &BOB,
5385                &ESCROW,
5386                &CONTRACT_FREELANCE,
5387                SMALL_COMMIT,
5388                &Directive::new(Precision::Exact, Fortitude::Force),
5389            )
5390            .unwrap();
5391            let digets_value = Pallet::get_digest_value(&ESCROW, &CONTRACT_FREELANCE).unwrap();
5392            assert_eq!(digets_value, 350); // 250 (alice's commit) + 100 (bob's commit) -> 350
5393        })
5394    }
5395
5396    #[test]
5397    fn set_digest_value_mint_ok() {
5398        commit_test_ext().execute_with(|| {
5399            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5400            Pallet::place_commit(
5401                &ALICE,
5402                &ESCROW,
5403                &CONTRACT_FREELANCE,
5404                SMALL_COMMIT,
5405                &Directive::new(Precision::Exact, Fortitude::Polite),
5406            )
5407            .unwrap();
5408            // before set_digest_value
5409            assert_eq!(
5410                Pallet::get_digest_value(&ESCROW, &CONTRACT_FREELANCE),
5411                Ok(SMALL_COMMIT)
5412            );
5413            let asset_to_issue = AssetToIssue::get();
5414            assert_eq!(asset_to_issue, ZERO_VALUE);
5415            let reason_value = Pallet::get_total_value(&ESCROW);
5416            assert_eq!(reason_value, 100);
5417            // setting a new digest value > current digest value
5418            assert_ok!(Pallet::set_digest_value(
5419                &ESCROW,
5420                &CONTRACT_FREELANCE,
5421                STANDARD_COMMIT,
5422                &Default::default(),
5423            ));
5424            // after set_digest_value (minting senario)
5425            let asset_to_issue = AssetToIssue::get();
5426            assert_eq!(asset_to_issue, 150);
5427            let reason_value = Pallet::get_total_value(&ESCROW);
5428            assert_eq!(reason_value, 250);
5429            assert_eq!(
5430                Pallet::get_digest_value(&ESCROW, &CONTRACT_FREELANCE),
5431                Ok(250)
5432            );
5433        })
5434    }
5435
5436    #[test]
5437    fn set_digest_value_equal_ok() {
5438        commit_test_ext().execute_with(|| {
5439            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5440            Pallet::place_commit(
5441                &ALICE,
5442                &ESCROW,
5443                &CONTRACT_FREELANCE,
5444                STANDARD_COMMIT,
5445                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5446            )
5447            .unwrap();
5448            // before set_digest_value
5449            assert_eq!(
5450                Pallet::get_digest_value(&ESCROW, &CONTRACT_FREELANCE),
5451                Ok(STANDARD_COMMIT)
5452            );
5453            let asset_to_reap = AssetToReap::get();
5454            assert_eq!(asset_to_reap, ZERO_VALUE);
5455            let reason_value = Pallet::get_total_value(&ESCROW);
5456            assert_eq!(reason_value, 250);
5457            // setting a new digest value == current digest value
5458            assert_ok!(Pallet::set_digest_value(
5459                &ESCROW,
5460                &CONTRACT_FREELANCE,
5461                STANDARD_COMMIT,
5462                &Default::default(),
5463            ));
5464            // after set_digest_value (no changes)
5465            let asset_to_reap = AssetToReap::get();
5466            assert_eq!(asset_to_reap, ZERO_VALUE);
5467            let reason_value = Pallet::get_total_value(&ESCROW);
5468            assert_eq!(reason_value, 250);
5469            assert_eq!(
5470                Pallet::get_digest_value(&ESCROW, &CONTRACT_FREELANCE),
5471                Ok(STANDARD_COMMIT)
5472            );
5473        })
5474    }
5475
5476    #[test]
5477    fn set_digest_value_reap_ok() {
5478        commit_test_ext().execute_with(|| {
5479            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5480            Pallet::place_commit(
5481                &ALICE,
5482                &ESCROW,
5483                &CONTRACT_FREELANCE,
5484                STANDARD_COMMIT,
5485                &Directive::new(Precision::Exact, Fortitude::Force),
5486            )
5487            .unwrap();
5488            // before set_digest_value
5489            assert_eq!(
5490                Pallet::get_digest_value(&ESCROW, &CONTRACT_FREELANCE),
5491                Ok(STANDARD_COMMIT)
5492            );
5493            let asset_to_reap = AssetToReap::get();
5494            assert_eq!(asset_to_reap, ZERO_VALUE);
5495            let reason_value = Pallet::get_total_value(&ESCROW);
5496            assert_eq!(reason_value, 250);
5497            // setting a new digest value < current digest value
5498            assert_ok!(Pallet::set_digest_value(
5499                &ESCROW,
5500                &CONTRACT_FREELANCE,
5501                SMALL_COMMIT,
5502                &Default::default(),
5503            ));
5504            // after set_digest_value (reaping senario)
5505            let asset_to_reap = AssetToReap::get();
5506            assert_eq!(asset_to_reap, 150);
5507            let reason_value = Pallet::get_total_value(&ESCROW);
5508            assert_eq!(reason_value, 100);
5509            assert_eq!(
5510                Pallet::get_digest_value(&ESCROW, &CONTRACT_FREELANCE),
5511                Ok(100)
5512            );
5513        })
5514    }
5515
5516    #[test]
5517    fn on_commit_place_event_emmission_success() {
5518        commit_test_ext().execute_with(|| {
5519            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5520            System::set_block_number(BLOCK_EARLY);
5521            Pallet::place_commit(
5522                &ALICE,
5523                &GOVERNANCE,
5524                &PROPOSAL_RUNTIME_UPGRADE,
5525                STANDARD_COMMIT,
5526                &Directive::new(Precision::Exact, Fortitude::Force),
5527            )
5528            .unwrap();
5529            // event emmitted
5530            System::assert_last_event(
5531                Event::CommitPlaced {
5532                    who: ALICE,
5533                    reason: GOVERNANCE,
5534                    #[cfg(feature = "dev")]
5535                    model: DigestVariant::Direct(PROPOSAL_RUNTIME_UPGRADE),
5536                    #[cfg(not(feature = "dev"))]
5537                    digest: PROPOSAL_RUNTIME_UPGRADE,
5538                    value: STANDARD_COMMIT,
5539                    variant: Position::default(),
5540                }
5541                .into(),
5542            );
5543        })
5544    }
5545
5546    #[test]
5547    fn on_commit_raise_event_emmission_success() {
5548        commit_test_ext().execute_with(|| {
5549            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5550            System::set_block_number(2);
5551            Pallet::place_commit(
5552                &ALICE,
5553                &STAKING,
5554                &VALIDATOR_ALPHA,
5555                STANDARD_COMMIT,
5556                &Directive::new(Precision::Exact, Fortitude::Force),
5557            )
5558            .unwrap();
5559            Pallet::raise_commit(
5560                &ALICE,
5561                &STAKING,
5562                SMALL_COMMIT,
5563                &Directive::new(Precision::Exact, Fortitude::Force),
5564            )
5565            .unwrap();
5566            System::assert_last_event(
5567                Event::CommitRaised {
5568                    who: ALICE,
5569                    reason: STAKING,
5570                    #[cfg(feature = "dev")]
5571                    model: DigestVariant::Direct(VALIDATOR_ALPHA),
5572                    #[cfg(not(feature = "dev"))]
5573                    digest: VALIDATOR_ALPHA,
5574                    value: SMALL_COMMIT,
5575                }
5576                .into(),
5577            );
5578        })
5579    }
5580
5581    #[test]
5582    fn on_commit_resolve_event_emmission_success() {
5583        commit_test_ext().execute_with(|| {
5584            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5585            System::set_block_number(2);
5586            Pallet::place_commit(
5587                &ALICE,
5588                &STAKING,
5589                &VALIDATOR_ALPHA,
5590                STANDARD_COMMIT,
5591                &Directive::new(Precision::Exact, Fortitude::Force),
5592            )
5593            .unwrap();
5594            System::set_block_number(3);
5595            Pallet::resolve_commit(&ALICE, &STAKING).unwrap();
5596            // event emmitted
5597            System::assert_last_event(
5598                Event::CommitResolved {
5599                    who: ALICE,
5600                    reason: STAKING,
5601                    #[cfg(feature = "dev")]
5602                    model: DigestVariant::Direct(VALIDATOR_ALPHA),
5603                    #[cfg(not(feature = "dev"))]
5604                    digest: VALIDATOR_ALPHA,
5605                    value: STANDARD_COMMIT,
5606                }
5607                .into(),
5608            );
5609        })
5610    }
5611
5612    #[test]
5613    fn on_digest_update_event_emmission_success() {
5614        commit_test_ext().execute_with(|| {
5615            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5616            System::set_block_number(2);
5617            Pallet::place_commit(
5618                &ALICE,
5619                &STAKING,
5620                &VALIDATOR_ALPHA,
5621                STANDARD_COMMIT,
5622                &Directive::new(Precision::Exact, Fortitude::Force),
5623            )
5624            .unwrap();
5625            System::set_block_number(3);
5626            Pallet::set_digest_value(
5627                &STAKING,
5628                &VALIDATOR_ALPHA,
5629                LARGE_COMMIT,
5630                &Directive::new(Precision::Exact, Fortitude::Force),
5631            )
5632            .unwrap();
5633            // event emmitted
5634            System::assert_last_event(
5635                Event::DigestInfo {
5636                    digest: VALIDATOR_ALPHA,
5637                    reason: STAKING,
5638                    value: LARGE_COMMIT,
5639                    variant: Position::default(),
5640                }
5641                .into(),
5642            );
5643        })
5644    }
5645
5646    #[test]
5647    fn reap_digest_ok() {
5648        commit_test_ext().execute_with(|| {
5649            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5650            System::set_block_number(2);
5651            Pallet::place_commit(
5652                &ALICE,
5653                &ESCROW,
5654                &CONTRACT_FREELANCE,
5655                STANDARD_COMMIT,
5656                &Directive::new(Precision::Exact, Fortitude::Force),
5657            )
5658            .unwrap();
5659            Pallet::resolve_commit(&ALICE, &ESCROW).unwrap();
5660            // before reaping
5661            assert_ok!(Pallet::digest_exists(&ESCROW, &CONTRACT_FREELANCE));
5662            // reaping the digest which has no funds
5663            assert_ok!(Pallet::reap_digest(&CONTRACT_FREELANCE, &ESCROW));
5664            // after reaping
5665            assert_err!(
5666                Pallet::digest_exists(&ESCROW, &CONTRACT_FREELANCE),
5667                Error::DigestNotFound
5668            )
5669        })
5670    }
5671
5672    #[test]
5673    fn reap_digest_err_digest_has_funds() {
5674        commit_test_ext().execute_with(|| {
5675            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5676            System::set_block_number(2);
5677            Pallet::place_commit(
5678                &ALICE,
5679                &ESCROW,
5680                &CONTRACT_FREELANCE,
5681                STANDARD_COMMIT,
5682                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5683            )
5684            .unwrap();
5685            assert_ok!(Pallet::digest_exists(&ESCROW, &CONTRACT_FREELANCE));
5686            // since, digest has a commited funds, it cannot be reaped
5687            assert_err!(
5688                Pallet::reap_digest(&CONTRACT_FREELANCE, &ESCROW),
5689                Error::DigestHasFunds
5690            );
5691        })
5692    }
5693
5694    #[test]
5695    fn on_reap_digest_event_emmission_success() {
5696        commit_test_ext().execute_with(|| {
5697            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5698            System::set_block_number(2);
5699            Pallet::place_commit(
5700                &ALICE,
5701                &ESCROW,
5702                &CONTRACT_FREELANCE,
5703                STANDARD_COMMIT,
5704                &Directive::new(Precision::Exact, Fortitude::Force),
5705            )
5706            .unwrap();
5707            System::set_block_number(3);
5708            Pallet::resolve_commit(&ALICE, &ESCROW).unwrap();
5709            System::set_block_number(4);
5710            Pallet::reap_digest(&CONTRACT_FREELANCE, &ESCROW).unwrap();
5711            System::assert_last_event(
5712                Event::DigestReaped {
5713                    digest: CONTRACT_FREELANCE,
5714                    reason: ESCROW,
5715                    dust: Zero::zero(),
5716                }
5717                .into(),
5718            );
5719        })
5720    }
5721
5722    #[test]
5723    fn can_place_commit_ok() {
5724        commit_test_ext().execute_with(|| {
5725            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5726            assert_ok!(Pallet::can_place_commit(
5727                &ALICE,
5728                &ESCROW,
5729                &ALPHA_DIGEST,
5730                STANDARD_COMMIT,
5731                &Default::default()
5732            ));
5733        })
5734    }
5735
5736    #[test]
5737    fn can_place_commit_err_commit_already_exists_for_reason() {
5738        commit_test_ext().execute_with(|| {
5739            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5740            Pallet::place_commit(
5741                &ALICE,
5742                &STAKING,
5743                &VALIDATOR_ALPHA,
5744                STANDARD_COMMIT,
5745                &Directive::new(Precision::Exact, Fortitude::Force),
5746            )
5747            .unwrap();
5748            assert_err!(
5749                Pallet::can_place_commit(
5750                    &ALICE,
5751                    &STAKING,
5752                    &VALIDATOR_ALPHA,
5753                    SMALL_COMMIT,
5754                    &Directive::new(Precision::Exact, Fortitude::Force)
5755                ),
5756                Error::CommitAlreadyExists
5757            );
5758        })
5759    }
5760
5761    #[test]
5762    fn can_place_commit_err_insufficient_funds() {
5763        commit_test_ext().execute_with(|| {
5764            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5765            assert_err!(
5766                Pallet::can_place_commit(
5767                    &ALICE,
5768                    &GOVERNANCE,
5769                    &ALPHA_DIGEST,
5770                    1600,
5771                    &Default::default()
5772                ),
5773                Error::InsufficientFunds
5774            );
5775        })
5776    }
5777
5778    #[test]
5779    fn can_raise_commit_ok() {
5780        commit_test_ext().execute_with(|| {
5781            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5782            Pallet::place_commit(
5783                &ALICE,
5784                &STAKING,
5785                &VALIDATOR_ALPHA,
5786                STANDARD_COMMIT,
5787                &Directive::new(Precision::Exact, Fortitude::Force),
5788            )
5789            .unwrap();
5790            assert_ok!(Pallet::can_raise_commit(
5791                &ALICE,
5792                &STAKING,
5793                SMALL_COMMIT,
5794                &Default::default()
5795            ));
5796        })
5797    }
5798
5799    #[test]
5800    fn can_raise_commit_err_insufficient_funds() {
5801        commit_test_ext().execute_with(|| {
5802            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5803            Pallet::place_commit(
5804                &ALICE,
5805                &ESCROW,
5806                &CONTRACT_SUPPLY_CHAIN,
5807                LARGE_COMMIT,
5808                &Directive::new(Precision::Exact, Fortitude::Force),
5809            )
5810            .unwrap();
5811            assert_err!(
5812                Pallet::can_raise_commit(&ALICE, &ESCROW, 1200, &Default::default()),
5813                Error::InsufficientFunds
5814            );
5815        })
5816    }
5817
5818    #[test]
5819    fn can_resolve_commit_ok() {
5820        commit_test_ext().execute_with(|| {
5821            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5822            Pallet::place_commit(
5823                &ALICE,
5824                &GOVERNANCE,
5825                &PROPOSAL_TREASURY_SPEND,
5826                STANDARD_COMMIT,
5827                &Directive::new(Precision::Exact, Fortitude::Force),
5828            )
5829            .unwrap();
5830            assert_ok!(Pallet::can_resolve_commit(&ALICE, &GOVERNANCE));
5831        })
5832    }
5833
5834    #[test]
5835    fn can_resolve_commit_index_ok() {
5836        commit_test_ext().execute_with(|| {
5837            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5838            set_default_user_balance_and_standard_hold(BOB).unwrap();
5839            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
5840            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
5841            prepare_and_initiate_index(
5842                BOB,
5843                STAKING,
5844                &[
5845                    (VALIDATOR_ALPHA, SHARE_EQUAL),
5846                    (VALIDATOR_BETA, SHARE_EQUAL),
5847                ],
5848                INDEX_BALANCED_STAKING,
5849            )
5850            .unwrap();
5851            Pallet::place_commit(
5852                &ALICE,
5853                &STAKING,
5854                &INDEX_BALANCED_STAKING,
5855                STANDARD_COMMIT,
5856                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5857            )
5858            .unwrap();
5859            assert_ok!(Pallet::can_resolve_commit(&ALICE, &STAKING));
5860        })
5861    }
5862
5863    #[test]
5864    fn can_resolve_commit_pool_ok() {
5865        commit_test_ext().execute_with(|| {
5866            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5867            set_default_user_balance_and_standard_hold(BOB).unwrap();
5868            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
5869            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
5870            let entries = vec![
5871                (VALIDATOR_ALPHA, SHARE_DOMINANT),
5872                (VALIDATOR_BETA, SHARE_MAJOR),
5873            ];
5874            prepare_and_initiate_pool(
5875                BOB,
5876                STAKING,
5877                &entries,
5878                INDEX_OPTIMIZED_STAKING,
5879                POOL_MANAGED_STAKING,
5880                COMMISSION_LOW,
5881            )
5882            .unwrap();
5883            Pallet::place_commit(
5884                &ALICE,
5885                &STAKING,
5886                &POOL_MANAGED_STAKING,
5887                STANDARD_COMMIT,
5888                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5889            )
5890            .unwrap();
5891            assert_ok!(Pallet::can_resolve_commit(&ALICE, &STAKING));
5892        })
5893    }
5894
5895    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5896    // ```````````````````````````````` COMMIT VARIANT `````````````````````````````````
5897    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5898
5899    #[test]
5900    fn get_commit_variant_success() {
5901        commit_test_ext().execute_with(|| {
5902            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5903            Pallet::place_commit_of_variant(
5904                &ALICE,
5905                &GOVERNANCE,
5906                &PROPOSAL_TREASURY_SPEND,
5907                STANDARD_COMMIT,
5908                &Position::position_of(2).unwrap(),
5909                &Directive::new(Precision::Exact, Fortitude::Force),
5910            )
5911            .unwrap();
5912            let actual_commit_variant = Pallet::get_commit_variant(&ALICE, &GOVERNANCE).unwrap();
5913            let expected_commit_variant = Position::position_of(2).unwrap();
5914            assert_eq!(actual_commit_variant, expected_commit_variant);
5915        })
5916    }
5917
5918    #[test]
5919    fn get_commit_variant_fail_commit_not_found() {
5920        commit_test_ext().execute_with(|| {
5921            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5922            Pallet::place_commit(
5923                &ALICE,
5924                &GOVERNANCE,
5925                &PROPOSAL_TREASURY_SPEND,
5926                STANDARD_COMMIT,
5927                &Directive::new(Precision::Exact, Fortitude::Force),
5928            )
5929            .unwrap();
5930            assert_err!(
5931                Pallet::get_commit_variant(&ALICE, &ESCROW),
5932                Error::CommitNotFound
5933            );
5934        })
5935    }
5936
5937    #[test]
5938    fn get_digest_variant_value_success() {
5939        commit_test_ext().execute_with(|| {
5940            set_default_user_balance_and_standard_hold(ALICE).unwrap();
5941            set_default_user_balance_and_standard_hold(BOB).unwrap();
5942            Pallet::place_commit(
5943                &ALICE,
5944                &GOVERNANCE,
5945                &PROPOSAL_RUNTIME_UPGRADE,
5946                STANDARD_COMMIT,
5947                &Directive::new(Precision::Exact, Fortitude::Force),
5948            )
5949            .unwrap();
5950            let digest_variant_value = Pallet::get_digest_variant_value(
5951                &GOVERNANCE,
5952                &PROPOSAL_RUNTIME_UPGRADE,
5953                &Position::default(),
5954            )
5955            .unwrap();
5956            assert_eq!(digest_variant_value, STANDARD_COMMIT);
5957            // zero returned when variant does not exists
5958            let digest_variant_value = Pallet::get_digest_variant_value(
5959                &GOVERNANCE,
5960                &PROPOSAL_RUNTIME_UPGRADE,
5961                &Position::position_of(1).unwrap(),
5962            )
5963            .unwrap();
5964            assert_eq!(digest_variant_value, ZERO_VALUE);
5965            Pallet::place_commit_of_variant(
5966                &BOB,
5967                &GOVERNANCE,
5968                &PROPOSAL_TREASURY_SPEND,
5969                LARGE_COMMIT,
5970                &Position::position_of(2).unwrap(),
5971                &Directive::new(Precision::BestEffort, Fortitude::Polite),
5972            )
5973            .unwrap();
5974            let digest_variant_value = Pallet::get_digest_variant_value(
5975                &GOVERNANCE,
5976                &PROPOSAL_TREASURY_SPEND,
5977                &Position::position_of(2).unwrap(),
5978            )
5979            .unwrap();
5980            assert_eq!(digest_variant_value, LARGE_COMMIT);
5981            // raising the commit value of commit with variant Affirmative
5982            Pallet::raise_commit(
5983                &ALICE,
5984                &GOVERNANCE,
5985                SMALL_COMMIT,
5986                &Directive::new(Precision::BestEffort, Fortitude::Force),
5987            )
5988            .unwrap();
5989            // raised value refected in the digets variant
5990            let digest_variant_value = Pallet::get_digest_variant_value(
5991                &GOVERNANCE,
5992                &PROPOSAL_RUNTIME_UPGRADE,
5993                &Position::default(),
5994            )
5995            .unwrap();
5996            let raised_value = STANDARD_COMMIT + SMALL_COMMIT;
5997            assert_eq!(digest_variant_value, raised_value);
5998        })
5999    }
6000
6001    #[test]
6002    fn get_digest_variant_value_fail_digest_not_found() {
6003        commit_test_ext().execute_with(|| {
6004            set_default_user_balance_and_standard_hold(ALICE).unwrap();
6005            Pallet::place_commit(
6006                &ALICE,
6007                &GOVERNANCE,
6008                &PROPOSAL_RUNTIME_UPGRADE,
6009                STANDARD_COMMIT,
6010                &Directive::new(Precision::Exact, Fortitude::Force),
6011            )
6012            .unwrap();
6013            assert_err!(
6014                Pallet::get_digest_variant_value(
6015                    &GOVERNANCE,
6016                    &PROPOSAL_TREASURY_SPEND,
6017                    &Position::default(),
6018                ),
6019                Error::DigestNotFound
6020            );
6021        })
6022    }
6023
6024    #[test]
6025    fn set_digest_variant_value_mint_ok() {
6026        commit_test_ext().execute_with(|| {
6027            System::set_block_number(10);
6028            set_default_user_balance_and_standard_hold(ALICE).unwrap();
6029            Pallet::place_commit(
6030                &ALICE,
6031                &GOVERNANCE,
6032                &PROPOSAL_TREASURY_SPEND,
6033                STANDARD_COMMIT,
6034                &Directive::new(Precision::Exact, Fortitude::Force),
6035            )
6036            .unwrap();
6037            // before set_digest_variant_value
6038            assert_eq!(
6039                Pallet::get_digest_value(&GOVERNANCE, &PROPOSAL_TREASURY_SPEND),
6040                Ok(STANDARD_COMMIT)
6041            );
6042            let asset_to_issue = AssetToIssue::get();
6043            assert_eq!(asset_to_issue, ZERO_VALUE);
6044            let total_value = Pallet::get_total_value(&GOVERNANCE);
6045            assert_eq!(total_value, 250);
6046            // setting a new digest value with specific variant > current digest value
6047            assert_ok!(Pallet::set_digest_variant_value(
6048                &GOVERNANCE,
6049                &PROPOSAL_TREASURY_SPEND,
6050                LARGE_COMMIT,
6051                &Position::default(),
6052                &Default::default(),
6053            ));
6054            // after set_digest_variant_value (minting senario)
6055            let asset_to_issue = AssetToIssue::get();
6056            assert_eq!(asset_to_issue, 250);
6057            let total_value = Pallet::get_total_value(&GOVERNANCE);
6058            assert_eq!(total_value, 500);
6059            assert_eq!(
6060                Pallet::get_digest_value(&GOVERNANCE, &PROPOSAL_TREASURY_SPEND),
6061                Ok(LARGE_COMMIT)
6062            );
6063
6064            System::assert_last_event(Event::DigestInfo { 
6065                    digest: PROPOSAL_TREASURY_SPEND, 
6066                    reason: GOVERNANCE, 
6067                    value: total_value, 
6068                    variant: Disposition::default() 
6069                }
6070                .into()
6071            );
6072        })
6073    }
6074
6075    #[test]
6076    fn set_digest_variant_value_equal_ok() {
6077        commit_test_ext().execute_with(|| {
6078            set_default_user_balance_and_standard_hold(ALICE).unwrap();
6079            Pallet::place_commit(
6080                &ALICE,
6081                &GOVERNANCE,
6082                &PROPOSAL_TREASURY_SPEND,
6083                STANDARD_COMMIT,
6084                &Directive::new(Precision::Exact, Fortitude::Force),
6085            )
6086            .unwrap();
6087            // before set_digest_variant_value
6088            assert_eq!(
6089                Pallet::get_digest_value(&GOVERNANCE, &PROPOSAL_TREASURY_SPEND),
6090                Ok(STANDARD_COMMIT)
6091            );
6092            let asset_to_reap = AssetToReap::get();
6093            assert_eq!(asset_to_reap, ZERO_VALUE);
6094            let total_value = Pallet::get_total_value(&GOVERNANCE);
6095            assert_eq!(total_value, 250);
6096            // setting a new digest value with specific variant == current digest value
6097            assert_ok!(Pallet::set_digest_variant_value(
6098                &GOVERNANCE,
6099                &PROPOSAL_TREASURY_SPEND,
6100                STANDARD_COMMIT,
6101                &Position::default(),
6102                &Default::default(),
6103            ));
6104            // after set_digest_variant_value (no changes)
6105            let asset_to_reap = AssetToReap::get();
6106            assert_eq!(asset_to_reap, ZERO_VALUE);
6107            let total_value = Pallet::get_total_value(&GOVERNANCE);
6108            assert_eq!(total_value, 250);
6109            assert_eq!(
6110                Pallet::get_digest_value(&GOVERNANCE, &PROPOSAL_TREASURY_SPEND),
6111                Ok(STANDARD_COMMIT)
6112            );
6113        })
6114    }
6115
6116    #[test]
6117    fn set_digest_variant_value_reap_ok() {
6118        commit_test_ext().execute_with(|| {
6119            set_default_user_balance_and_standard_hold(ALICE).unwrap();
6120            Pallet::place_commit(
6121                &ALICE,
6122                &GOVERNANCE,
6123                &PROPOSAL_TREASURY_SPEND,
6124                STANDARD_COMMIT,
6125                &Directive::new(Precision::Exact, Fortitude::Force),
6126            )
6127            .unwrap();
6128            // before set_digest_variant_value
6129            assert_eq!(
6130                Pallet::get_digest_value(&GOVERNANCE, &PROPOSAL_TREASURY_SPEND),
6131                Ok(STANDARD_COMMIT)
6132            );
6133            let asset_to_reap = AssetToReap::get();
6134            assert_eq!(asset_to_reap, ZERO_VALUE);
6135            let total_value = Pallet::get_total_value(&GOVERNANCE);
6136            assert_eq!(total_value, 250);
6137            // setting a new digest value with specific variant < current digest value
6138            assert_ok!(Pallet::set_digest_variant_value(
6139                &GOVERNANCE,
6140                &PROPOSAL_TREASURY_SPEND,
6141                SMALL_COMMIT,
6142                &Position::default(),
6143                &Default::default(),
6144            ));
6145            // after set_digest_variant_value (reaping senario)
6146            let asset_to_reap = AssetToReap::get();
6147            assert_eq!(asset_to_reap, 150);
6148            let total_value = Pallet::get_total_value(&GOVERNANCE);
6149            assert_eq!(total_value, 100);
6150            assert_eq!(
6151                Pallet::get_digest_value(&GOVERNANCE, &PROPOSAL_TREASURY_SPEND),
6152                Ok(SMALL_COMMIT)
6153            );
6154        })
6155    }
6156
6157    #[test]
6158    fn set_digest_variant_value_err_cannot_mint_asset() {
6159        commit_test_ext().execute_with(|| {
6160            set_default_user_balance_and_standard_hold(ALICE).unwrap();
6161            Pallet::place_commit(
6162                &ALICE,
6163                &GOVERNANCE,
6164                &PROPOSAL_TREASURY_SPEND,
6165                STANDARD_COMMIT,
6166                &Directive::new(Precision::Exact, Fortitude::Force),
6167            )
6168            .unwrap();
6169            AssetToIssue::put(MAX_VALUE);
6170            assert_err!(
6171                Pallet::set_digest_variant_value(
6172                    &GOVERNANCE,
6173                    &PROPOSAL_TREASURY_SPEND,
6174                    LARGE_COMMIT,
6175                    &Position::default(),
6176                    &Default::default(),
6177                ),
6178                Error::MaxAssetIssued
6179            );
6180        });
6181    }
6182
6183    #[test]
6184    fn set_digest_variant_value_err_cannot_reap_asset() {
6185        commit_test_ext().execute_with(|| {
6186            set_default_user_balance_and_standard_hold(ALICE).unwrap();
6187            Pallet::place_commit(
6188                &ALICE,
6189                &GOVERNANCE,
6190                &PROPOSAL_TREASURY_SPEND,
6191                STANDARD_COMMIT,
6192                &Directive::new(Precision::Exact, Fortitude::Force),
6193            )
6194            .unwrap();
6195            AssetToReap::put(MAX_VALUE);
6196            assert_err!(
6197                Pallet::set_digest_variant_value(
6198                    &GOVERNANCE,
6199                    &PROPOSAL_TREASURY_SPEND,
6200                    SMALL_COMMIT,
6201                    &Position::default(),
6202                    &Default::default(),
6203                ),
6204                Error::MaxAssetReaped
6205            );
6206        });
6207    }
6208
6209    #[test]
6210    fn set_digest_variant_value_err_digest_not_found() {
6211        commit_test_ext().execute_with(|| {
6212            set_default_user_balance_and_standard_hold(ALICE).unwrap();
6213            Pallet::place_commit(
6214                &ALICE,
6215                &GOVERNANCE,
6216                &PROPOSAL_TREASURY_SPEND,
6217                STANDARD_COMMIT,
6218                &Directive::new(Precision::Exact, Fortitude::Force),
6219            )
6220            .unwrap();
6221            assert_err!(
6222                Pallet::set_digest_variant_value(
6223                    &GOVERNANCE,
6224                    &PROPOSAL_RUNTIME_UPGRADE,
6225                    SMALL_COMMIT,
6226                    &Position::default(),
6227                    &Default::default(),
6228                ),
6229                Error::DigestNotFound
6230            );
6231        });
6232    }
6233
6234    #[test]
6235    fn place_commit_of_variant_success_for_digest() {
6236        commit_test_ext().execute_with(|| {
6237            System::set_block_number(10);
6238            set_default_user_balance_and_standard_hold(ALICE).unwrap();
6239            assert_err!(
6240                Pallet::commit_exists(&ALICE, &GOVERNANCE),
6241                Error::CommitNotFound
6242            );
6243            assert_err!(
6244                Pallet::digest_exists(&GOVERNANCE, &PROPOSAL_TREASURY_SPEND),
6245                Error::DigestNotFound
6246            );
6247            assert_ok!(Pallet::place_commit_of_variant(
6248                &ALICE,
6249                &GOVERNANCE,
6250                &PROPOSAL_TREASURY_SPEND,
6251                STANDARD_COMMIT,
6252                &Position::position_of(1).unwrap(),
6253                &Directive::new(Precision::Exact, Fortitude::Force)
6254            ));
6255            // Variant enquiry
6256            let actual_variant = Pallet::get_commit_variant(&ALICE, &GOVERNANCE).unwrap();
6257            let expected_variant = Position::position_of(1).unwrap();
6258            assert_eq!(expected_variant, actual_variant);
6259            let actual_varinat_value = Pallet::get_digest_variant_value(
6260                &GOVERNANCE,
6261                &PROPOSAL_TREASURY_SPEND,
6262                &Position::position_of(1).unwrap(),
6263            )
6264            .unwrap();
6265            assert_eq!(actual_varinat_value, STANDARD_COMMIT);
6266            // Commit and digest enquirey
6267            assert_ok!(Pallet::commit_exists(&ALICE, &GOVERNANCE));
6268            assert_ok!(Pallet::digest_exists(&GOVERNANCE, &PROPOSAL_TREASURY_SPEND));
6269            // Balance and freeze enquirey
6270            let balace_after = AssetOf::balance(&ALICE);
6271            let hold_balance_after = AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &ALICE);
6272            let expected_balance_after = INITIAL_BALANCE;
6273            let expected_hold_balance_after = 250;
6274            assert_eq!(expected_balance_after, balace_after);
6275            assert_eq!(expected_hold_balance_after, hold_balance_after);
6276            assert_eq!(
6277                AssetOf::balance_frozen(&GOVERNANCE, &ALICE),
6278                STANDARD_COMMIT
6279            );
6280            // Commit info enquiry
6281            let commit_info = CommitMap::get((ALICE, GOVERNANCE)).unwrap();
6282            assert_eq!(commit_info.digest(), PROPOSAL_TREASURY_SPEND);
6283            let variant = commit_info.variant();
6284            let index = variant.index();
6285            let commits = commit_info.commits();
6286            let commit = commits.get(0).unwrap();
6287            assert_eq!(receipt_deposit_value(commit).unwrap(), STANDARD_COMMIT);
6288            // Digest info enquiry
6289            let digest_info = DigestMap::get((GOVERNANCE, PROPOSAL_TREASURY_SPEND)).unwrap();
6290            let digests = digest_info.reveal();
6291            let digest_of = digests.get(index).unwrap();
6292            assert_ok!(has_deposits(digest_of, &variant, &PROPOSAL_TREASURY_SPEND));
6293            assert_eq!(
6294                balance_total(digest_of, &variant, &PROPOSAL_TREASURY_SPEND).unwrap(),
6295                STANDARD_COMMIT,
6296            );
6297            // Total value enquiry
6298            let reason_value = ReasonValue::get(GOVERNANCE).unwrap();
6299            assert_eq!(reason_value, 250);
6300
6301            #[cfg(not(feature = "dev"))]
6302            System::assert_last_event(Event::CommitPlaced { 
6303                    who: ALICE, 
6304                    reason: GOVERNANCE, 
6305                    digest: PROPOSAL_TREASURY_SPEND, 
6306                    value: STANDARD_COMMIT, 
6307                    variant: Position::position_of(1).unwrap() 
6308                }
6309                .into()
6310            );
6311
6312            #[cfg(feature = "dev")]
6313            System::assert_last_event(Event::CommitPlaced { 
6314                    who: ALICE, 
6315                    reason: GOVERNANCE, 
6316                    model: DigestVariant::Direct(PROPOSAL_TREASURY_SPEND), 
6317                    value: STANDARD_COMMIT, 
6318                    variant: Position::position_of(1).unwrap() 
6319                }
6320                .into()
6321            );
6322        })
6323    }
6324
6325    #[test]
6326    fn place_commit_of_variant_marker_error_for_value_zero() {
6327        commit_test_ext().execute_with(|| {
6328            set_default_user_balance_and_standard_hold(ALICE).unwrap();
6329            assert_err!(
6330                Pallet::place_commit_of_variant(
6331                    &ALICE,
6332                    &GOVERNANCE,
6333                    &PROPOSAL_RUNTIME_UPGRADE,
6334                    ZERO_VALUE,
6335                    &Position::default(),
6336                    &Directive::new(Precision::Exact, Fortitude::Force)
6337                ),
6338                Error::MarkerCommitNotAllowed
6339            );
6340            // Commit and digest enquirey
6341            assert_err!(
6342                Pallet::commit_exists(&ALICE, &GOVERNANCE),
6343                Error::CommitNotFound
6344            );
6345            assert_err!(
6346                Pallet::digest_exists(&GOVERNANCE, &PROPOSAL_RUNTIME_UPGRADE),
6347                Error::DigestNotFound
6348            );
6349        })
6350    }
6351
6352    #[test]
6353    fn place_commit_of_variant_success_for_index() {
6354        commit_test_ext().execute_with(|| {
6355            System::set_block_number(10);
6356            set_default_user_balance_and_standard_hold(ALICE).unwrap();
6357            set_default_user_balance_and_standard_hold(BOB).unwrap();
6358            set_default_user_balance_and_standard_hold(CHARLIE).unwrap();
6359
6360            Pallet::place_commit(
6361                &ALICE,
6362                &STAKING,
6363                &VALIDATOR_ALPHA,
6364                STANDARD_COMMIT,
6365                &Directive::new(Precision::Exact, Fortitude::Force),
6366            )
6367            .unwrap();
6368            Pallet::place_commit(
6369                &BOB,
6370                &STAKING,
6371                &VALIDATOR_BETA,
6372                STANDARD_COMMIT,
6373                &Directive::new(Precision::Exact, Fortitude::Force),
6374            )
6375            .unwrap();
6376            prepare_and_initiate_index(
6377                MIKE,
6378                STAKING,
6379                &[
6380                    (VALIDATOR_ALPHA, SHARE_MAJOR),
6381                    (VALIDATOR_BETA, SHARE_DOMINANT),
6382                ],
6383                INDEX_OPTIMIZED_STAKING,
6384            )
6385            .unwrap();
6386            assert_ok!(Pallet::index_exists(&STAKING, &INDEX_OPTIMIZED_STAKING));
6387            // Before placing a commit to the index
6388            let index_info = Pallet::get_index(&STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
6389            assert_eq!(index_info.capital(), 100);
6390            assert_eq!(index_info.principal(), ZERO_VALUE);
6391            let actual_entries_value =
6392                Pallet::get_entries_value(&STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
6393            let expected_entries_value = vec![(VALIDATOR_ALPHA, 0), (VALIDATOR_BETA, 0)];
6394            assert_eq!(actual_entries_value, expected_entries_value);
6395
6396            let reason_value = ReasonValue::get(STAKING).unwrap();
6397            assert_eq!(reason_value, 500);
6398            // Place commit to an index with variant
6399            assert_ok!(Pallet::place_commit_of_variant(
6400                &CHARLIE,
6401                &STAKING,
6402                &INDEX_OPTIMIZED_STAKING,
6403                STANDARD_COMMIT,
6404                &Position::position_of(2).unwrap(),
6405                &Directive::new(Precision::Exact, Fortitude::Force)
6406            ));
6407            // After placing a commit to the index with a variant
6408            let index_value = Pallet::get_index_value(&STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
6409            assert_eq!(index_value, 250);
6410            let actual_entries_value =
6411                Pallet::get_entries_value(&STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
6412            let expected_entries_value = vec![(VALIDATOR_ALPHA, 100), (VALIDATOR_BETA, 150)];
6413            assert_eq!(actual_entries_value, expected_entries_value);
6414
6415            let reason_value = ReasonValue::get(STAKING).unwrap();
6416            assert_eq!(reason_value, 750);
6417            // Variant check
6418            assert_eq!(
6419                Pallet::get_commit_variant(&CHARLIE, &STAKING),
6420                Ok(Position::position_of(2).unwrap())
6421            );
6422
6423            #[cfg(not(feature = "dev"))]
6424            System::assert_last_event(Event::CommitPlaced { 
6425                    who: CHARLIE, 
6426                    reason: STAKING, 
6427                    digest: INDEX_OPTIMIZED_STAKING, 
6428                    value: STANDARD_COMMIT, 
6429                    variant: Position::position_of(2).unwrap() 
6430                }
6431                .into()
6432            );
6433
6434            #[cfg(feature = "dev")]
6435            System::assert_last_event(Event::CommitPlaced { 
6436                    who: CHARLIE, 
6437                    reason: STAKING, 
6438                    model: DigestVariant::Index(INDEX_OPTIMIZED_STAKING), 
6439                    value: STANDARD_COMMIT, 
6440                    variant: Position::position_of(2).unwrap() 
6441                }
6442                .into()
6443            );
6444        })
6445    }
6446
6447    #[test]
6448    fn place_commit_of_variant_success_for_pool() {
6449        commit_test_ext().execute_with(|| {
6450            System::set_block_number(10);
6451            set_default_user_balance_and_standard_hold(ALICE).unwrap();
6452            set_default_user_balance_and_standard_hold(BOB).unwrap();
6453            set_default_user_balance_and_standard_hold(CHARLIE).unwrap();
6454            Pallet::place_commit(
6455                &ALICE,
6456                &STAKING,
6457                &VALIDATOR_ALPHA,
6458                STANDARD_COMMIT,
6459                &Directive::new(Precision::Exact, Fortitude::Force),
6460            )
6461            .unwrap();
6462            Pallet::place_commit(
6463                &BOB,
6464                &STAKING,
6465                &VALIDATOR_BETA,
6466                STANDARD_COMMIT,
6467                &Directive::new(Precision::Exact, Fortitude::Force),
6468            )
6469            .unwrap();
6470            let entries = vec![
6471                (VALIDATOR_ALPHA, SHARE_MAJOR),
6472                (VALIDATOR_BETA, SHARE_DOMINANT),
6473            ];
6474            prepare_and_initiate_pool(
6475                MIKE,
6476                STAKING,
6477                &entries,
6478                INDEX_OPTIMIZED_STAKING,
6479                POOL_MANAGED_STAKING,
6480                COMMISSION_LOW,
6481            )
6482            .unwrap();
6483            // Before placing commit to pool
6484            assert_eq!(
6485                Pallet::get_manager(&STAKING, &POOL_MANAGED_STAKING),
6486                Ok(MIKE)
6487            );
6488            let pool_info = PoolMap::get((STAKING, POOL_MANAGED_STAKING)).unwrap();
6489            let pool_balance_of = pool_info.balance();
6490            assert!(
6491                has_deposits(&pool_balance_of, &Default::default(), &POOL_MANAGED_STAKING).is_err()
6492            );
6493            assert_eq!(
6494                balance_total(&pool_balance_of, &Default::default(), &POOL_MANAGED_STAKING)
6495                    .unwrap(),
6496                0,
6497            );
6498            let pool_capital = pool_info.capital();
6499            assert_eq!(pool_capital, 100);
6500            let actual_slots_value =
6501                Pallet::get_slots_value(&STAKING, &POOL_MANAGED_STAKING).unwrap();
6502            let expected_slots_value = vec![(VALIDATOR_ALPHA, 0), (VALIDATOR_BETA, 0)];
6503            assert_eq!(actual_slots_value, expected_slots_value);
6504            let reason_value = ReasonValue::get(STAKING).unwrap();
6505            assert_eq!(reason_value, 500);
6506            // Placing commit to pool with variant
6507            assert_ok!(Pallet::place_commit_of_variant(
6508                &CHARLIE,
6509                &STAKING,
6510                &POOL_MANAGED_STAKING,
6511                STANDARD_COMMIT,
6512                &Position::position_of(1).unwrap(),
6513                &Directive::new(Precision::Exact, Fortitude::Force)
6514            ));
6515            // After placing commit to pool
6516            let pool_info = PoolMap::get((STAKING, POOL_MANAGED_STAKING)).unwrap();
6517            let pool_balance_of = pool_info.balance();
6518            assert_ok!(has_deposits(
6519                &pool_balance_of,
6520                &Default::default(),
6521                &POOL_MANAGED_STAKING
6522            ));
6523            assert_eq!(
6524                balance_total(&pool_balance_of, &Default::default(), &POOL_MANAGED_STAKING)
6525                    .unwrap(),
6526                250,
6527            );
6528            let actual_slots_value =
6529                Pallet::get_slots_value(&STAKING, &POOL_MANAGED_STAKING).unwrap();
6530            let expected_slots_value = vec![(VALIDATOR_ALPHA, 100), (VALIDATOR_BETA, 150)];
6531            assert_eq!(actual_slots_value, expected_slots_value);
6532
6533            let reason_value = ReasonValue::get(STAKING).unwrap();
6534            assert_eq!(reason_value, 750);
6535            // Balance and freeze enquirey
6536            let balace_after = AssetOf::balance(&CHARLIE);
6537            let hold_balance_after = AssetOf::balance_on_hold(&PREPARE_FOR_COMMIT, &CHARLIE);
6538            let expected_balance_after = INITIAL_BALANCE;
6539            let expected_hold_balance_after = 250;
6540            assert_eq!(expected_balance_after, balace_after);
6541            assert_eq!(expected_hold_balance_after, hold_balance_after);
6542            assert_eq!(AssetOf::balance_frozen(&STAKING, &CHARLIE), STANDARD_COMMIT);
6543            // Variant check
6544            assert_eq!(
6545                Pallet::get_commit_variant(&CHARLIE, &STAKING),
6546                Ok(Position::position_of(1).unwrap())
6547            );
6548
6549            #[cfg(not(feature = "dev"))]
6550            System::assert_last_event(Event::CommitPlaced { 
6551                    who: CHARLIE, 
6552                    reason: STAKING, 
6553                    digest: POOL_MANAGED_STAKING, 
6554                    value: STANDARD_COMMIT, 
6555                    variant: Position::position_of(1).unwrap() 
6556                }
6557                .into()
6558            );
6559
6560            #[cfg(feature = "dev")]
6561            System::assert_last_event(Event::CommitPlaced { 
6562                    who: CHARLIE, 
6563                    reason: STAKING, 
6564                    model: DigestVariant::Pool(POOL_MANAGED_STAKING), 
6565                    value: STANDARD_COMMIT, 
6566                    variant: Position::position_of(1).unwrap() 
6567                }
6568                .into()
6569            );
6570        })
6571    }
6572
6573    #[test]
6574    fn on_place_commit_on_variant_event_emmission_success() {
6575        commit_test_ext().execute_with(|| {
6576            set_default_user_balance_and_standard_hold(ALICE).unwrap();
6577            System::set_block_number(2);
6578            Pallet::place_commit(
6579                &ALICE,
6580                &GOVERNANCE,
6581                &PROPOSAL_RUNTIME_UPGRADE,
6582                STANDARD_COMMIT,
6583                &Directive::new(Precision::Exact, Fortitude::Force),
6584            )
6585            .unwrap();
6586            System::assert_last_event(
6587                Event::CommitPlaced {
6588                    who: ALICE,
6589                    reason: GOVERNANCE,
6590                    #[cfg(feature = "dev")]
6591                    model: DigestVariant::Direct(PROPOSAL_RUNTIME_UPGRADE),
6592                    #[cfg(not(feature = "dev"))]
6593                    digest: PROPOSAL_RUNTIME_UPGRADE,
6594                    value: STANDARD_COMMIT,
6595                    variant: Position::default(),
6596                }
6597                .into(),
6598            );
6599        })
6600    }
6601
6602    #[test]
6603    fn on_set_commit_variant_event_emmission_success() {
6604        commit_test_ext().execute_with(|| {
6605            set_default_user_balance_and_standard_hold(ALICE).unwrap();
6606            System::set_block_number(2);
6607            Pallet::place_commit(
6608                &ALICE,
6609                &GOVERNANCE,
6610                &PROPOSAL_RUNTIME_UPGRADE,
6611                STANDARD_COMMIT,
6612                &Directive::new(Precision::Exact, Fortitude::Force),
6613            )
6614            .unwrap();
6615            System::assert_last_event(
6616                Event::CommitPlaced {
6617                    who: ALICE,
6618                    reason: GOVERNANCE,
6619                    #[cfg(feature = "dev")]
6620                    model: DigestVariant::Direct(PROPOSAL_RUNTIME_UPGRADE),
6621                    #[cfg(not(feature = "dev"))]
6622                    digest: PROPOSAL_RUNTIME_UPGRADE,
6623                    value: STANDARD_COMMIT,
6624                    variant: Position::position_of(0).unwrap(),
6625                }
6626                .into(),
6627            );
6628        })
6629    }
6630
6631    #[test]
6632    fn on_set_digest_variant_event_emmission_success() {
6633        commit_test_ext().execute_with(|| {
6634            set_default_user_balance_and_standard_hold(ALICE).unwrap();
6635            System::set_block_number(2);
6636            Pallet::place_commit_of_variant(
6637                &ALICE,
6638                &STAKING,
6639                &PROPOSAL_RUNTIME_UPGRADE,
6640                STANDARD_COMMIT,
6641                &Position::position_of(1).unwrap(),
6642                &Directive::new(Precision::BestEffort, Fortitude::Force),
6643            )
6644            .unwrap();
6645            System::set_block_number(3);
6646            Pallet::set_digest_variant_value(
6647                &STAKING,
6648                &PROPOSAL_RUNTIME_UPGRADE,
6649                SMALL_COMMIT,
6650                &Position::position_of(1).unwrap(),
6651                &Directive::new(Precision::BestEffort, Fortitude::Force),
6652            )
6653            .unwrap();
6654            System::assert_last_event(
6655                Event::DigestInfo {
6656                    digest: PROPOSAL_RUNTIME_UPGRADE,
6657                    reason: STAKING,
6658                    value: SMALL_COMMIT,
6659                    variant: Position::position_of(1).unwrap(),
6660                }
6661                .into(),
6662            );
6663        })
6664    }
6665
6666    #[test]
6667    fn set_commit_variant_success() {
6668        commit_test_ext().execute_with(|| {
6669            set_default_user_balance_and_standard_hold(ALICE).unwrap();
6670            Pallet::place_commit(
6671                &ALICE,
6672                &GOVERNANCE,
6673                &PROPOSAL_TREASURY_SPEND,
6674                STANDARD_COMMIT,
6675                &Directive::new(Precision::Exact, Fortitude::Force),
6676            )
6677            .unwrap();
6678            let current_commit_variant = Pallet::get_commit_variant(&ALICE, &GOVERNANCE).unwrap();
6679            assert_eq!(current_commit_variant, Position::default());
6680            // setting a new variant
6681            let new_commit_variant = Position::position_of(1).unwrap();
6682            assert_ok!(Pallet::set_commit_variant(
6683                &ALICE,
6684                &GOVERNANCE,
6685                &new_commit_variant,
6686                &Default::default(),
6687            ));
6688            // new variant updated
6689            let current_commit_variant = Pallet::get_commit_variant(&ALICE, &GOVERNANCE).unwrap();
6690            assert_eq!(current_commit_variant, Position::position_of(1).unwrap());
6691        })
6692    }
6693
6694    #[test]
6695    fn set_commit_variant_same_variant_safe_return() {
6696        commit_test_ext().execute_with(|| {
6697            set_default_user_balance_and_standard_hold(ALICE).unwrap();
6698            Pallet::place_commit(
6699                &ALICE,
6700                &GOVERNANCE,
6701                &PROPOSAL_TREASURY_SPEND,
6702                STANDARD_COMMIT,
6703                &Directive::new(Precision::Exact, Fortitude::Force),
6704            )
6705            .unwrap();
6706            let current_commit_variant = Pallet::get_commit_variant(&ALICE, &GOVERNANCE).unwrap();
6707            assert_eq!(current_commit_variant, Position::default());
6708            // setting the same variant
6709            assert_ok!(Pallet::set_commit_variant(
6710                &ALICE,
6711                &GOVERNANCE,
6712                &current_commit_variant,
6713                &Default::default(),
6714            ));
6715        })
6716    }
6717
6718    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6719    // ```````````````````````````````` COMMIT INDEX `````````````````````````````````
6720    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6721
6722    #[test]
6723    fn index_exists_ok() {
6724        commit_test_ext().execute_with(|| {
6725            prepare_and_initiate_index(
6726                ALICE,
6727                STAKING,
6728                &[
6729                    (VALIDATOR_ALPHA, SHARE_EQUAL),
6730                    (VALIDATOR_BETA, SHARE_EQUAL),
6731                ],
6732                INDEX_BALANCED_STAKING,
6733            )
6734            .unwrap();
6735            assert_ok!(Pallet::index_exists(&STAKING, &INDEX_BALANCED_STAKING));
6736        })
6737    }
6738
6739    #[test]
6740    fn index_exists_err_index_not_found() {
6741        commit_test_ext().execute_with(|| {
6742            prepare_and_initiate_index(
6743                ALICE,
6744                STAKING,
6745                &[
6746                    (VALIDATOR_ALPHA, SHARE_EQUAL),
6747                    (VALIDATOR_BETA, SHARE_EQUAL),
6748                ],
6749                INDEX_BALANCED_STAKING,
6750            )
6751            .unwrap();
6752            assert_err!(
6753                Pallet::index_exists(&STAKING, &INDEX_OPTIMIZED_STAKING),
6754                Error::IndexNotFound
6755            );
6756        })
6757    }
6758
6759    #[test]
6760    fn entry_exists_ok() {
6761        commit_test_ext().execute_with(|| {
6762            prepare_and_initiate_index(
6763                ALICE,
6764                STAKING,
6765                &[
6766                    (VALIDATOR_ALPHA, SHARE_EQUAL),
6767                    (VALIDATOR_BETA, SHARE_EQUAL),
6768                ],
6769                INDEX_BALANCED_STAKING,
6770            )
6771            .unwrap();
6772            assert_ok!(Pallet::entry_exists(
6773                &STAKING,
6774                &INDEX_BALANCED_STAKING,
6775                &VALIDATOR_ALPHA
6776            ));
6777            assert_ok!(Pallet::entry_exists(
6778                &STAKING,
6779                &INDEX_BALANCED_STAKING,
6780                &VALIDATOR_BETA
6781            ));
6782        })
6783    }
6784
6785    #[test]
6786    fn entry_exists_err_entry_not_found() {
6787        commit_test_ext().execute_with(|| {
6788            prepare_and_initiate_index(
6789                ALICE,
6790                STAKING,
6791                &[
6792                    (VALIDATOR_ALPHA, SHARE_EQUAL),
6793                    (VALIDATOR_BETA, SHARE_EQUAL),
6794                ],
6795                INDEX_BALANCED_STAKING,
6796            )
6797            .unwrap();
6798            assert_err!(
6799                Pallet::entry_exists(&STAKING, &INDEX_BALANCED_STAKING, &VALIDATOR_GAMMA),
6800                Error::EntryOfIndexNotFound
6801            );
6802        })
6803    }
6804
6805    #[test]
6806    fn has_index_ok() {
6807        commit_test_ext().execute_with(|| {
6808            prepare_and_initiate_index(
6809                ALICE,
6810                STAKING,
6811                &[
6812                    (VALIDATOR_ALPHA, SHARE_EQUAL),
6813                    (VALIDATOR_BETA, SHARE_EQUAL),
6814                ],
6815                INDEX_BALANCED_STAKING,
6816            )
6817            .unwrap();
6818            assert_ok!(Pallet::has_index(&STAKING));
6819        })
6820    }
6821
6822    #[test]
6823    fn has_index_err_index_not_found() {
6824        commit_test_ext().execute_with(|| {
6825            prepare_and_initiate_index(
6826                ALICE,
6827                STAKING,
6828                &[
6829                    (VALIDATOR_ALPHA, SHARE_EQUAL),
6830                    (VALIDATOR_BETA, SHARE_EQUAL),
6831                ],
6832                INDEX_BALANCED_STAKING,
6833            )
6834            .unwrap();
6835            assert_err!(Pallet::has_index(&GOVERNANCE), Error::IndexNotFound);
6836        })
6837    }
6838
6839    #[test]
6840    fn get_index_sucess() {
6841        commit_test_ext().execute_with(|| {
6842            prepare_and_initiate_index(
6843                ALICE,
6844                STAKING,
6845                &[
6846                    (VALIDATOR_ALPHA, SHARE_EQUAL),
6847                    (VALIDATOR_BETA, SHARE_EQUAL),
6848                ],
6849                INDEX_BALANCED_STAKING,
6850            )
6851            .unwrap();
6852            let expected_index = IndexMap::get((STAKING, INDEX_BALANCED_STAKING)).unwrap();
6853            let actual_index = Pallet::get_index(&STAKING, &INDEX_BALANCED_STAKING).unwrap();
6854            assert_eq!(expected_index.principal(), actual_index.principal());
6855            assert_eq!(expected_index.capital(), actual_index.capital());
6856            assert_eq!(
6857                expected_index.entries().get(0),
6858                actual_index.entries().get(0)
6859            );
6860            assert_eq!(
6861                expected_index.entries().get(1),
6862                actual_index.entries().get(1)
6863            );
6864        })
6865    }
6866
6867    #[test]
6868    fn get_entries_shares_success() {
6869        commit_test_ext().execute_with(|| {
6870            prepare_and_initiate_index(
6871                ALICE,
6872                STAKING,
6873                &[
6874                    (VALIDATOR_ALPHA, SHARE_MAJOR),
6875                    (VALIDATOR_BETA, SHARE_DOMINANT),
6876                ],
6877                INDEX_OPTIMIZED_STAKING,
6878            )
6879            .unwrap();
6880            let expected_entries_shares = vec![
6881                (VALIDATOR_ALPHA, SHARE_MAJOR),
6882                (VALIDATOR_BETA, SHARE_DOMINANT),
6883            ];
6884            let actual_entries_shares =
6885                Pallet::get_entries_shares(&STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
6886            assert_eq!(actual_entries_shares, expected_entries_shares);
6887        })
6888    }
6889
6890    #[test]
6891    fn get_entry_value_success() {
6892        commit_test_ext().execute_with(|| {
6893            set_default_user_balance_and_standard_hold(ALICE).unwrap();
6894            set_default_user_balance_and_standard_hold(BOB).unwrap();
6895            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
6896            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
6897            prepare_and_initiate_index(
6898                ALICE,
6899                STAKING,
6900                &[
6901                    (VALIDATOR_ALPHA, SHARE_MAJOR),
6902                    (VALIDATOR_BETA, SHARE_DOMINANT),
6903                ],
6904                INDEX_OPTIMIZED_STAKING,
6905            )
6906            .unwrap();
6907            Pallet::place_commit(
6908                &ALICE,
6909                &STAKING,
6910                &INDEX_OPTIMIZED_STAKING,
6911                STANDARD_COMMIT,
6912                &Directive::new(Precision::Exact, Fortitude::Force),
6913            )
6914            .unwrap();
6915            let entry_value_alpha =
6916                Pallet::get_entry_value(&STAKING, &INDEX_OPTIMIZED_STAKING, &VALIDATOR_ALPHA)
6917                    .unwrap();
6918            let entry_value_beta =
6919                Pallet::get_entry_value(&STAKING, &INDEX_OPTIMIZED_STAKING, &VALIDATOR_BETA)
6920                    .unwrap();
6921            assert_eq!(entry_value_alpha, 100);
6922            assert_eq!(entry_value_beta, 150);
6923            // placing another commit to the same index
6924            Pallet::place_commit(
6925                &BOB,
6926                &STAKING,
6927                &INDEX_OPTIMIZED_STAKING,
6928                STANDARD_COMMIT,
6929                &Directive::new(Precision::Exact, Fortitude::Force),
6930            )
6931            .unwrap();
6932            // aggregated value of specific entries accross different proprietors
6933            let entry_value_alpha =
6934                Pallet::get_entry_value(&STAKING, &INDEX_OPTIMIZED_STAKING, &VALIDATOR_ALPHA)
6935                    .unwrap();
6936            let entry_value_beta =
6937                Pallet::get_entry_value(&STAKING, &INDEX_OPTIMIZED_STAKING, &VALIDATOR_BETA)
6938                    .unwrap();
6939            assert_eq!(entry_value_alpha, 200);
6940            assert_eq!(entry_value_beta, 300);
6941        })
6942    }
6943
6944    #[test]
6945    fn get_entry_value_for_success() {
6946        commit_test_ext().execute_with(|| {
6947            set_default_user_balance_and_standard_hold(ALICE).unwrap();
6948            set_default_user_balance_and_standard_hold(BOB).unwrap();
6949            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
6950            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
6951            prepare_and_initiate_index(
6952                ALICE,
6953                STAKING,
6954                &[
6955                    (VALIDATOR_ALPHA, SHARE_MAJOR),
6956                    (VALIDATOR_BETA, SHARE_DOMINANT),
6957                ],
6958                INDEX_OPTIMIZED_STAKING,
6959            )
6960            .unwrap();
6961            Pallet::place_commit(
6962                &ALICE,
6963                &STAKING,
6964                &INDEX_OPTIMIZED_STAKING,
6965                STANDARD_COMMIT,
6966                &Directive::new(Precision::Exact, Fortitude::Force),
6967            )
6968            .unwrap();
6969            Pallet::place_commit(
6970                &BOB,
6971                &STAKING,
6972                &INDEX_OPTIMIZED_STAKING,
6973                SMALL_COMMIT,
6974                &Directive::new(Precision::Exact, Fortitude::Force),
6975            )
6976            .unwrap();
6977            // Index entry balance of alice
6978            let alpha_entry_value = Pallet::get_entry_value_for(
6979                &ALICE,
6980                &STAKING,
6981                &INDEX_OPTIMIZED_STAKING,
6982                &VALIDATOR_ALPHA,
6983            )
6984            .unwrap();
6985            let beta_entry_value = Pallet::get_entry_value_for(
6986                &ALICE,
6987                &STAKING,
6988                &INDEX_OPTIMIZED_STAKING,
6989                &VALIDATOR_BETA,
6990            )
6991            .unwrap();
6992            assert_eq!(alpha_entry_value, 100);
6993            assert_eq!(beta_entry_value, 150);
6994            // Index entry balance of bob
6995            let alpha_entry_value = Pallet::get_entry_value_for(
6996                &BOB,
6997                &STAKING,
6998                &INDEX_OPTIMIZED_STAKING,
6999                &VALIDATOR_ALPHA,
7000            )
7001            .unwrap();
7002            let beta_entry_value = Pallet::get_entry_value_for(
7003                &BOB,
7004                &STAKING,
7005                &INDEX_OPTIMIZED_STAKING,
7006                &VALIDATOR_BETA,
7007            )
7008            .unwrap();
7009            assert_eq!(alpha_entry_value, 40);
7010            assert_eq!(beta_entry_value, 60);
7011        })
7012    }
7013
7014    #[test]
7015    fn prepare_index_success() {
7016        commit_test_ext().execute_with(|| {
7017            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
7018            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
7019            let index = Pallet::prepare_index(
7020                &ALICE,
7021                &STAKING,
7022                &[
7023                    (VALIDATOR_ALPHA, SHARE_EQUAL),
7024                    (VALIDATOR_BETA, SHARE_EQUAL),
7025                ],
7026            )
7027            .unwrap();
7028            assert_eq!(index.principal(), ZERO_VALUE);
7029            assert_eq!(index.capital(), 200);
7030            let expected_alpha_entry_info =
7031                EntryInfo::new(VALIDATOR_ALPHA, SHARE_EQUAL, Default::default()).unwrap();
7032            let expected_beta_entry_info =
7033                EntryInfo::new(VALIDATOR_BETA, SHARE_EQUAL, Default::default()).unwrap();
7034            let entries = index.entries();
7035            let actual_alice_entry_info = entries.get(0).unwrap();
7036            let actual_beta_entry_info = entries.get(1).unwrap();
7037            assert_eq!(expected_alpha_entry_info, *actual_alice_entry_info);
7038            assert_eq!(expected_beta_entry_info, *actual_beta_entry_info);
7039        })
7040    }
7041
7042    #[test]
7043    fn prepare_index_err_duplicate_entry() {
7044        commit_test_ext().execute_with(|| {
7045            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
7046            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
7047            let actual_err = Pallet::prepare_index(
7048                &ALICE,
7049                &STAKING,
7050                &[
7051                    (VALIDATOR_ALPHA, SHARE_EQUAL),
7052                    (VALIDATOR_BETA, SHARE_EQUAL),
7053                    (VALIDATOR_ALPHA, SHARE_EQUAL),
7054                ],
7055            )
7056            .unwrap_err();
7057            let expected_err = Error::DuplicateEntry.into();
7058            assert_eq!(actual_err, expected_err);
7059        })
7060    }
7061
7062    #[test]
7063    fn prepare_index_err_max_index_reached() {
7064        commit_test_ext().execute_with(|| {
7065            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
7066            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
7067            initiate_digest_with_default_balance(STAKING, VALIDATOR_GAMMA).unwrap();
7068            initiate_digest_with_default_balance(STAKING, VALIDATOR_DELTA).unwrap();
7069            let actual_err = Pallet::prepare_index(
7070                &ALICE,
7071                &STAKING,
7072                &[
7073                    (VALIDATOR_ALPHA, SHARE_EQUAL),
7074                    (VALIDATOR_BETA, SHARE_EQUAL),
7075                    (VALIDATOR_GAMMA, SHARE_EQUAL),
7076                    (VALIDATOR_DELTA, SHARE_EQUAL),
7077                ],
7078            )
7079            .unwrap_err();
7080            // since MaxEntries is set to 3, adding a fourth entry results in err
7081            assert_eq!(actual_err, Error::MaxEntriesReached.into());
7082        })
7083    }
7084
7085    #[test]
7086    fn prepare_index_rejects_uninitiated_digest() {
7087        commit_test_ext().execute_with(||{
7088            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
7089            let entries = vec![(VALIDATOR_ALPHA, 100), (VALIDATOR_BETA, 200)];
7090            assert_err!(
7091                Pallet::prepare_index(
7092                    &ALICE,
7093                    &STAKING,
7094                    &entries
7095                ),
7096                Error::EntryDigestNotInitiated
7097            );
7098        })
7099    }
7100
7101    #[test]
7102    fn set_index_ok() {
7103        commit_test_ext().execute_with(|| {
7104            System::set_block_number(10);
7105            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
7106            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
7107            let index = Pallet::prepare_index(
7108                &ALICE,
7109                &STAKING,
7110                &[
7111                    (VALIDATOR_ALPHA, SHARE_EQUAL),
7112                    (VALIDATOR_BETA, SHARE_EQUAL),
7113                ],
7114            )
7115            .unwrap();
7116            assert_err!(
7117                Pallet::index_exists(&STAKING, &INDEX_BALANCED_STAKING),
7118                Error::IndexNotFound
7119            );
7120            assert_ok!(Pallet::set_index(
7121                &ALICE,
7122                &STAKING,
7123                &index,
7124                &INDEX_BALANCED_STAKING
7125            ));
7126            assert_ok!(Pallet::index_exists(&STAKING, &INDEX_BALANCED_STAKING));
7127
7128            #[cfg(not(feature = "dev"))]
7129            System::assert_last_event(Event::IndexInitialized {
7130                    index_of: INDEX_BALANCED_STAKING, 
7131                    reason: STAKING,
7132                }
7133                .into()
7134            );
7135
7136            #[cfg(feature = "dev")]
7137            {
7138                let entries = vec![(VALIDATOR_ALPHA, SHARE_EQUAL, Disposition::default()), (VALIDATOR_BETA, SHARE_EQUAL, Disposition::default())];
7139                System::assert_last_event(Event::IndexInitialized { 
7140                        index_of: INDEX_BALANCED_STAKING, 
7141                        reason: STAKING,
7142                        entries: entries
7143                    }
7144                    .into()
7145                );  
7146            }
7147        })
7148    }
7149
7150    #[test]
7151    fn set_index_err_index_already_exists() {
7152        commit_test_ext().execute_with(|| {
7153            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
7154            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
7155            let index = Pallet::prepare_index(
7156                &ALICE,
7157                &STAKING,
7158                &[
7159                    (VALIDATOR_ALPHA, SHARE_EQUAL),
7160                    (VALIDATOR_BETA, SHARE_EQUAL),
7161                ],
7162            )
7163            .unwrap();
7164            assert_ok!(Pallet::set_index(
7165                &ALICE,
7166                &STAKING,
7167                &index,
7168                &INDEX_BALANCED_STAKING
7169            ));
7170            assert_ok!(Pallet::index_exists(&STAKING, &INDEX_BALANCED_STAKING));
7171            // Error while creating an existing index
7172            assert_err!(
7173                Pallet::set_index(&ALICE, &STAKING, &index, &INDEX_BALANCED_STAKING),
7174                Error::IndexDigestTaken
7175            );
7176        })
7177    }
7178
7179    #[test]
7180    fn set_entry_shares_success() {
7181        commit_test_ext().execute_with(|| {
7182            set_default_user_balance_and_standard_hold(ALICE).unwrap();
7183            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
7184            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
7185            prepare_and_initiate_index(
7186                ALICE,
7187                STAKING,
7188                &[
7189                    (VALIDATOR_ALPHA, SHARE_DOMINANT),
7190                    (VALIDATOR_BETA, SHARE_MAJOR),
7191                ],
7192                INDEX_OPTIMIZED_STAKING,
7193            )
7194            .unwrap();
7195            Pallet::place_commit(
7196                &ALICE,
7197                &STAKING,
7198                &INDEX_OPTIMIZED_STAKING,
7199                STANDARD_COMMIT,
7200                &Directive::new(Precision::Exact, Fortitude::Force),
7201            )
7202            .unwrap();
7203            assert_ok!(Pallet::index_exists(&STAKING, &INDEX_OPTIMIZED_STAKING));
7204            let new_shares = SHARE_MAJOR;
7205            let new_index_digest = Pallet::set_entry_shares(
7206                &ALICE,
7207                &STAKING,
7208                &INDEX_OPTIMIZED_STAKING,
7209                &VALIDATOR_ALPHA,
7210                new_shares,
7211            )
7212            .unwrap();
7213            // new index created with updated shares
7214            assert_ok!(Pallet::index_exists(&STAKING, &new_index_digest));
7215            let actual_index_entries =
7216                Pallet::get_entries_shares(&STAKING, &new_index_digest).unwrap();
7217            let expected_index_entries = vec![
7218                (VALIDATOR_BETA, SHARE_MAJOR),
7219                (VALIDATOR_ALPHA, SHARE_MAJOR),
7220            ];
7221            assert_eq!(actual_index_entries, expected_index_entries);
7222            // old index exists and unchanged
7223            assert_ok!(Pallet::index_exists(&STAKING, &INDEX_OPTIMIZED_STAKING));
7224            let actual_index_entries =
7225                Pallet::get_entries_shares(&STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
7226            let expected_index_entries = vec![
7227                (VALIDATOR_ALPHA, SHARE_DOMINANT),
7228                (VALIDATOR_BETA, SHARE_MAJOR),
7229            ];
7230            assert_eq!(actual_index_entries, expected_index_entries);
7231        })
7232    }
7233
7234    #[test]
7235    fn set_entry_shares_success_removing_entry_when_shares_set_to_zero() {
7236        commit_test_ext().execute_with(|| {
7237            set_default_user_balance_and_standard_hold(ALICE).unwrap();
7238            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
7239            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
7240            prepare_and_initiate_index(
7241                ALICE,
7242                STAKING,
7243                &[
7244                    (VALIDATOR_ALPHA, SHARE_DOMINANT),
7245                    (VALIDATOR_BETA, SHARE_MAJOR),
7246                ],
7247                INDEX_OPTIMIZED_STAKING,
7248            )
7249            .unwrap();
7250            Pallet::place_commit(
7251                &ALICE,
7252                &STAKING,
7253                &INDEX_OPTIMIZED_STAKING,
7254                STANDARD_COMMIT,
7255                &Directive::new(Precision::Exact, Fortitude::Force),
7256            )
7257            .unwrap();
7258            assert_ok!(Pallet::index_exists(&STAKING, &INDEX_OPTIMIZED_STAKING));
7259            let new_shares = ZERO_SHARE;
7260            let new_index_digest = Pallet::set_entry_shares(
7261                &ALICE,
7262                &STAKING,
7263                &INDEX_OPTIMIZED_STAKING,
7264                &VALIDATOR_ALPHA,
7265                new_shares,
7266            )
7267            .unwrap();
7268            // new index created without the entry of which shares is set to 0
7269            assert_ok!(Pallet::index_exists(&STAKING, &new_index_digest));
7270            // Entry removed
7271            assert_err!(
7272                Pallet::entry_exists(&STAKING, &new_index_digest, &VALIDATOR_ALPHA),
7273                Error::EntryOfIndexNotFound
7274            );
7275            let actual_index_entries =
7276                Pallet::get_entries_shares(&STAKING, &new_index_digest).unwrap();
7277            let expected_index_entries = vec![(VALIDATOR_BETA, SHARE_MAJOR)];
7278            assert_eq!(actual_index_entries, expected_index_entries);
7279            // old index exists and unchanged
7280            assert_ok!(Pallet::index_exists(&STAKING, &INDEX_OPTIMIZED_STAKING));
7281            let actual_index_entries =
7282                Pallet::get_entries_shares(&STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
7283            let expected_index_entries = vec![
7284                (VALIDATOR_ALPHA, SHARE_DOMINANT),
7285                (VALIDATOR_BETA, SHARE_MAJOR),
7286            ];
7287            assert_eq!(actual_index_entries, expected_index_entries);
7288        })
7289    }
7290
7291    #[test]
7292    fn set_entry_shares_success_adding_new_entry() {
7293        commit_test_ext().execute_with(|| {
7294            set_default_user_balance_and_standard_hold(ALICE).unwrap();
7295            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
7296            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
7297            initiate_digest_with_default_balance(STAKING, VALIDATOR_GAMMA).unwrap();
7298            prepare_and_initiate_index(
7299                ALICE,
7300                STAKING,
7301                &[
7302                    (VALIDATOR_ALPHA, SHARE_EQUAL),
7303                    (VALIDATOR_BETA, SHARE_EQUAL),
7304                ],
7305                INDEX_BALANCED_STAKING,
7306            )
7307            .unwrap();
7308            Pallet::place_commit(
7309                &ALICE,
7310                &STAKING,
7311                &INDEX_BALANCED_STAKING,
7312                STANDARD_COMMIT,
7313                &Directive::new(Precision::BestEffort, Fortitude::Polite),
7314            )
7315            .unwrap();
7316            assert_ok!(Pallet::index_exists(&STAKING, &INDEX_BALANCED_STAKING));
7317            let new_shares = SHARE_EQUAL;
7318            let new_index_digest = Pallet::set_entry_shares(
7319                &ALICE,
7320                &STAKING,
7321                &INDEX_BALANCED_STAKING,
7322                &VALIDATOR_GAMMA,
7323                new_shares,
7324            )
7325            .unwrap();
7326            // new index created with an addition of new entry
7327            assert_ok!(Pallet::index_exists(&STAKING, &new_index_digest));
7328            let actual_entries = Pallet::get_entries_shares(&STAKING, &new_index_digest).unwrap();
7329            let expected_entries = vec![
7330                (VALIDATOR_ALPHA, SHARE_EQUAL),
7331                (VALIDATOR_BETA, SHARE_EQUAL),
7332                (VALIDATOR_GAMMA, SHARE_EQUAL),
7333            ];
7334            assert_eq!(expected_entries, actual_entries);
7335            // old index exists and unchanged
7336            assert_ok!(Pallet::index_exists(&STAKING, &INDEX_BALANCED_STAKING));
7337            let actual_entries =
7338                Pallet::get_entries_shares(&STAKING, &INDEX_BALANCED_STAKING).unwrap();
7339            let expected_entries = vec![
7340                (VALIDATOR_ALPHA, SHARE_EQUAL),
7341                (VALIDATOR_BETA, SHARE_EQUAL),
7342            ];
7343            assert_eq!(expected_entries, actual_entries);
7344        })
7345    }
7346
7347    #[test]
7348    fn set_entry_shares_when_share_zero_for_entry() {
7349        commit_test_ext().execute_with(|| {
7350            set_default_user_balance_and_standard_hold(ALICE).unwrap();
7351            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
7352            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
7353            initiate_digest_with_default_balance(STAKING, VALIDATOR_GAMMA).unwrap();
7354            prepare_and_initiate_index(
7355                ALICE,
7356                STAKING,
7357                &[
7358                    (VALIDATOR_ALPHA, SHARE_EQUAL),
7359                    (VALIDATOR_BETA, SHARE_EQUAL),
7360                ],
7361                INDEX_BALANCED_STAKING,
7362            )
7363            .unwrap();
7364            Pallet::place_commit(
7365                &ALICE,
7366                &STAKING,
7367                &INDEX_BALANCED_STAKING,
7368                STANDARD_COMMIT,
7369                &Directive::new(Precision::BestEffort, Fortitude::Polite),
7370            )
7371            .unwrap();
7372            assert_ok!(Pallet::index_exists(&STAKING, &INDEX_BALANCED_STAKING));
7373            // Expected to pass when tried to remove a non-entry digest
7374            // by giving shares zero
7375            assert_ok!(Pallet::set_entry_shares(
7376                &ALICE,
7377                &STAKING,
7378                &INDEX_BALANCED_STAKING,
7379                &VALIDATOR_GAMMA,
7380                ZERO_SHARE,
7381            ));
7382
7383            // While success to remove a existing entry by setting share to zero
7384            Pallet::set_entry_shares(
7385                &ALICE,
7386                &STAKING,
7387                &INDEX_BALANCED_STAKING,
7388                &VALIDATOR_BETA,
7389                ZERO_SHARE,
7390            )
7391            .unwrap();
7392        })
7393    }
7394
7395    #[test]
7396    fn set_entry_shares_err_max_entries_reached() {
7397        commit_test_ext().execute_with(|| {
7398            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
7399            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
7400            initiate_digest_with_default_balance(STAKING, VALIDATOR_GAMMA).unwrap();
7401            initiate_digest_with_default_balance(STAKING, VALIDATOR_DELTA).unwrap();
7402            prepare_and_initiate_index(
7403                ALICE,
7404                STAKING,
7405                &[
7406                    (VALIDATOR_ALPHA, SHARE_EQUAL),
7407                    (VALIDATOR_BETA, SHARE_EQUAL),
7408                    (VALIDATOR_GAMMA, SHARE_EQUAL),
7409                ],
7410                INDEX_BALANCED_STAKING,
7411            )
7412            .unwrap();
7413            assert_err!(
7414                Pallet::set_entry_shares(
7415                    &ALICE,
7416                    &STAKING,
7417                    &INDEX_BALANCED_STAKING,
7418                    &VALIDATOR_DELTA,
7419                    SHARE_EQUAL
7420                ),
7421                Error::MaxEntriesReached
7422            );
7423        })
7424    }
7425
7426    #[test]
7427    fn set_entry_shares_err_entry_digest_not_initiated() {
7428        commit_test_ext().execute_with(|| {
7429            set_default_user_balance_and_standard_hold(ALICE).unwrap();
7430            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
7431            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
7432            prepare_and_initiate_index(
7433                ALICE,
7434                STAKING,
7435                &[
7436                    (VALIDATOR_ALPHA, SHARE_EQUAL),
7437                    (VALIDATOR_BETA, SHARE_EQUAL),
7438                ],
7439                INDEX_BALANCED_STAKING,
7440            )
7441            .unwrap();
7442            Pallet::place_commit(
7443                &ALICE,
7444                &STAKING,
7445                &INDEX_BALANCED_STAKING,
7446                STANDARD_COMMIT,
7447                &Directive::new(Precision::BestEffort, Fortitude::Polite),
7448            )
7449            .unwrap();
7450            assert_ok!(Pallet::index_exists(&STAKING, &INDEX_BALANCED_STAKING));
7451            // trying to insert uninitiated digest will return error
7452            assert_err!(Pallet::set_entry_shares(
7453                &ALICE,
7454                &STAKING,
7455                &INDEX_BALANCED_STAKING,
7456                &VALIDATOR_GAMMA,
7457                SHARE_MAJOR,
7458            ), Error::EntryDigestNotInitiated);
7459        })
7460    }
7461
7462    #[test]
7463    fn reap_index_ok() {
7464        commit_test_ext().execute_with(|| {
7465            System::set_block_number(10);
7466            prepare_and_initiate_index(
7467                ALICE,
7468                STAKING,
7469                &[
7470                    (VALIDATOR_ALPHA, SHARE_EQUAL),
7471                    (VALIDATOR_BETA, SHARE_EQUAL),
7472                ],
7473                INDEX_BALANCED_STAKING,
7474            )
7475            .unwrap();
7476            assert_ok!(Pallet::index_exists(&STAKING, &INDEX_BALANCED_STAKING));
7477            assert_ok!(Pallet::reap_index(&STAKING, &INDEX_BALANCED_STAKING));
7478            assert_err!(
7479                Pallet::index_exists(&STAKING, &INDEX_BALANCED_STAKING),
7480                Error::IndexNotFound
7481            );
7482
7483            System::assert_last_event(Event::IndexReaped { 
7484                    index_of: INDEX_BALANCED_STAKING, 
7485                    reason: STAKING
7486                }
7487                .into()
7488            );
7489        })
7490    }
7491
7492    #[test]
7493    fn reap_index_err_index_has_funds() {
7494        commit_test_ext().execute_with(|| {
7495            set_default_user_balance_and_standard_hold(ALICE).unwrap();
7496            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
7497            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
7498            prepare_and_initiate_index(
7499                ALICE,
7500                STAKING,
7501                &[
7502                    (VALIDATOR_ALPHA, SHARE_EQUAL),
7503                    (VALIDATOR_BETA, SHARE_EQUAL),
7504                ],
7505                INDEX_BALANCED_STAKING,
7506            )
7507            .unwrap();
7508            Pallet::place_commit(
7509                &ALICE,
7510                &STAKING,
7511                &INDEX_BALANCED_STAKING,
7512                STANDARD_COMMIT,
7513                &Directive::new(Precision::Exact, Fortitude::Force),
7514            )
7515            .unwrap();
7516            assert_ok!(Pallet::index_exists(&STAKING, &INDEX_BALANCED_STAKING));
7517            assert_err!(
7518                Pallet::reap_index(&STAKING, &INDEX_BALANCED_STAKING),
7519                Error::IndexHasFunds
7520            );
7521        })
7522    }
7523
7524    #[test]
7525    fn gen_index_digest_success() {
7526        commit_test_ext().execute_with(|| {
7527            set_default_user_balance_and_standard_hold(ALICE).unwrap();
7528            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
7529            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
7530            let index_a = Pallet::prepare_index(
7531                &ALICE,
7532                &STAKING,
7533                &[
7534                    (VALIDATOR_ALPHA, SHARE_EQUAL),
7535                    (VALIDATOR_BETA, SHARE_EQUAL),
7536                ],
7537            )
7538            .unwrap();
7539            let gen_index_digest_1 = Pallet::gen_index_digest(&ALICE, &STAKING, &index_a);
7540            assert!(gen_index_digest_1.is_ok());
7541            let gen_index_digest_2 = Pallet::gen_index_digest(&ALICE, &STAKING, &index_a);
7542            assert!(gen_index_digest_2.is_ok());
7543            assert_eq!(gen_index_digest_1, gen_index_digest_2); // deterministic key generation for same input
7544
7545            // new index with small change in shares
7546            let index_b = Pallet::prepare_index(
7547                &ALICE,
7548                &STAKING,
7549                &[
7550                    (VALIDATOR_ALPHA, SHARE_EQUAL),
7551                    (VALIDATOR_BETA, SHARE_DOMINANT),
7552                ],
7553            )
7554            .unwrap();
7555            let gen_index_digest_3 = Pallet::gen_index_digest(&ALICE, &STAKING, &index_b);
7556            assert!(gen_index_digest_3.is_ok());
7557            assert_ne!(gen_index_digest_2, gen_index_digest_3); // Unique key generation with even a small change in the input
7558
7559            // same index and propritor with different reason
7560            let gen_index_digest_4 = Pallet::gen_index_digest(&ALICE, &ESCROW, &index_b);
7561            assert!(gen_index_digest_4.is_ok());
7562            assert_ne!(gen_index_digest_2, gen_index_digest_4);
7563            assert_ne!(gen_index_digest_3, gen_index_digest_4);
7564        })
7565    }
7566
7567    #[test]
7568    fn on_create_index_event_emmision_success() {
7569        commit_test_ext().execute_with(|| {
7570            System::set_block_number(2);
7571            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
7572            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
7573            let entries = vec![
7574                (VALIDATOR_ALPHA, SHARE_MAJOR),
7575                (VALIDATOR_BETA, SHARE_DOMINANT),
7576            ];
7577            let index = Pallet::prepare_index(&ALICE, &STAKING, &entries).unwrap();
7578            Pallet::set_index(&ALICE, &STAKING, &index, &INDEX_OPTIMIZED_STAKING).unwrap();
7579            #[cfg(feature = "dev")]
7580            let entries_defaults = vec![
7581                (VALIDATOR_ALPHA, SHARE_MAJOR, Position::default()),
7582                (VALIDATOR_BETA, SHARE_DOMINANT, Position::default()),
7583            ];
7584            System::assert_last_event(
7585                Event::IndexInitialized {
7586                    index_of: INDEX_OPTIMIZED_STAKING,
7587                    reason: STAKING,
7588                    #[cfg(feature = "dev")]
7589                    entries: entries_defaults,
7590                }
7591                .into(),
7592            );
7593        })
7594    }
7595
7596    #[test]
7597    fn on_reap_index_event_emmision_success() {
7598        commit_test_ext().execute_with(|| {
7599            System::set_block_number(2);
7600            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
7601            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
7602            let entries = vec![
7603                (VALIDATOR_ALPHA, SHARE_MAJOR),
7604                (VALIDATOR_BETA, SHARE_DOMINANT),
7605            ];
7606            let index = Pallet::prepare_index(&ALICE, &STAKING, &entries).unwrap();
7607            Pallet::set_index(&ALICE, &STAKING, &index, &INDEX_OPTIMIZED_STAKING).unwrap();
7608            System::set_block_number(3);
7609            Pallet::reap_index(&STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
7610            System::assert_last_event(
7611                Event::IndexReaped {
7612                    index_of: INDEX_OPTIMIZED_STAKING,
7613                    reason: STAKING,
7614                }
7615                .into(),
7616            );
7617        })
7618    }
7619
7620    #[test]
7621    fn get_index_value_success() {
7622        commit_test_ext().execute_with(|| {
7623            set_default_user_balance_and_standard_hold(ALICE).unwrap();
7624            set_default_user_balance_and_standard_hold(BOB).unwrap();
7625            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
7626            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
7627            prepare_and_initiate_index(
7628                ALICE,
7629                STAKING,
7630                &[
7631                    (VALIDATOR_ALPHA, SHARE_MAJOR),
7632                    (VALIDATOR_BETA, SHARE_DOMINANT),
7633                ],
7634                INDEX_OPTIMIZED_STAKING,
7635            )
7636            .unwrap();
7637            Pallet::place_commit(
7638                &ALICE,
7639                &STAKING,
7640                &INDEX_OPTIMIZED_STAKING,
7641                STANDARD_COMMIT,
7642                &Directive::new(Precision::Exact, Fortitude::Force),
7643            )
7644            .unwrap();
7645            // index value after alice commited
7646            let expected_index_value = STANDARD_COMMIT;
7647            let actual_index_value =
7648                Pallet::get_index_value(&STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
7649            assert_eq!(expected_index_value, actual_index_value);
7650            Pallet::place_commit(
7651                &BOB,
7652                &STAKING,
7653                &INDEX_OPTIMIZED_STAKING,
7654                LARGE_COMMIT,
7655                &Directive::new(Precision::Exact, Fortitude::Force),
7656            )
7657            .unwrap();
7658            // index value after alice and bob commited
7659            let expected_index_value = STANDARD_COMMIT + LARGE_COMMIT;
7660            let actual_index_value =
7661                Pallet::get_index_value(&STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
7662            assert_eq!(expected_index_value, actual_index_value);
7663        })
7664    }
7665
7666    #[test]
7667    fn get_entries_value_success() {
7668        commit_test_ext().execute_with(|| {
7669            set_default_user_balance_and_standard_hold(ALICE).unwrap();
7670            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
7671            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
7672            prepare_and_initiate_index(
7673                ALICE,
7674                STAKING,
7675                &[
7676                    (VALIDATOR_ALPHA, SHARE_MAJOR),
7677                    (VALIDATOR_BETA, SHARE_DOMINANT),
7678                ],
7679                INDEX_OPTIMIZED_STAKING,
7680            )
7681            .unwrap();
7682            Pallet::place_commit(
7683                &ALICE,
7684                &STAKING,
7685                &INDEX_OPTIMIZED_STAKING,
7686                STANDARD_COMMIT,
7687                &Directive::new(Precision::Exact, Fortitude::Force),
7688            )
7689            .unwrap();
7690            let actual_entries_value =
7691                Pallet::get_entries_value(&STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
7692            let expected_entries_value = vec![(VALIDATOR_ALPHA, 100), (VALIDATOR_BETA, 150)];
7693            assert_eq!(expected_entries_value, actual_entries_value);
7694        })
7695    }
7696
7697    #[test]
7698    fn get_entries_value_for_success() {
7699        commit_test_ext().execute_with(|| {
7700            set_default_user_balance_and_standard_hold(ALICE).unwrap();
7701            set_default_user_balance_and_standard_hold(BOB).unwrap();
7702            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
7703            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
7704            prepare_and_initiate_index(
7705                ALICE,
7706                STAKING,
7707                &[
7708                    (VALIDATOR_ALPHA, SHARE_MAJOR),
7709                    (VALIDATOR_BETA, SHARE_DOMINANT),
7710                ],
7711                INDEX_OPTIMIZED_STAKING,
7712            )
7713            .unwrap();
7714            Pallet::place_commit(
7715                &ALICE,
7716                &STAKING,
7717                &INDEX_OPTIMIZED_STAKING,
7718                STANDARD_COMMIT,
7719                &Directive::new(Precision::Exact, Fortitude::Force),
7720            )
7721            .unwrap();
7722            Pallet::place_commit(
7723                &BOB,
7724                &STAKING,
7725                &INDEX_OPTIMIZED_STAKING,
7726                SMALL_COMMIT,
7727                &Directive::new(Precision::Exact, Fortitude::Force),
7728            )
7729            .unwrap();
7730            // Index entries balance of alice
7731            let actual_alice_entries_value =
7732                Pallet::get_entries_value_for(&ALICE, &STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
7733            let expected_alice_entries_value = vec![(VALIDATOR_ALPHA, 100), (VALIDATOR_BETA, 150)];
7734            assert_eq!(actual_alice_entries_value, expected_alice_entries_value);
7735            // Index entries balance of bob
7736            let actual_bob_entries_value =
7737                Pallet::get_entries_value_for(&BOB, &STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
7738            let expected_bob_entries_value = vec![(VALIDATOR_ALPHA, 40), (VALIDATOR_BETA, 60)];
7739            assert_eq!(actual_bob_entries_value, expected_bob_entries_value);
7740        })
7741    }
7742
7743    #[test]
7744    fn get_index_value_for_success() {
7745        commit_test_ext().execute_with(|| {
7746            set_default_user_balance_and_standard_hold(ALICE).unwrap();
7747            set_default_user_balance_and_standard_hold(BOB).unwrap();
7748            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
7749            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
7750            prepare_and_initiate_index(
7751                ALICE,
7752                STAKING,
7753                &[
7754                    (VALIDATOR_ALPHA, SHARE_MAJOR),
7755                    (VALIDATOR_BETA, SHARE_DOMINANT),
7756                ],
7757                INDEX_OPTIMIZED_STAKING,
7758            )
7759            .unwrap();
7760            Pallet::place_commit(
7761                &ALICE,
7762                &STAKING,
7763                &INDEX_OPTIMIZED_STAKING,
7764                STANDARD_COMMIT,
7765                &Directive::new(Precision::Exact, Fortitude::Force),
7766            )
7767            .unwrap();
7768            Pallet::place_commit(
7769                &BOB,
7770                &STAKING,
7771                &INDEX_OPTIMIZED_STAKING,
7772                SMALL_COMMIT,
7773                &Directive::new(Precision::Exact, Fortitude::Force),
7774            )
7775            .unwrap();
7776            // Index value of alice
7777            let alice_index_value =
7778                Pallet::get_index_value_for(&ALICE, &STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
7779            assert_eq!(alice_index_value, STANDARD_COMMIT);
7780            // Index value of bob
7781            let bob_index_value =
7782                Pallet::get_index_value_for(&BOB, &STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
7783            assert_eq!(bob_index_value, SMALL_COMMIT);
7784        })
7785    }
7786
7787    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7788    // ```````````````````````````````` INDEX VARIANT ````````````````````````````````
7789    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7790
7791    #[test]
7792    fn get_entry_variant_success() {
7793        commit_test_ext().execute_with(|| {
7794            set_default_user_balance_and_standard_hold(ALICE).unwrap();
7795            set_default_user_balance_and_standard_hold(BOB).unwrap();
7796            set_default_user_balance_and_standard_hold(CHARLIE).unwrap();
7797            let bob_commit_variant = Position::position_of(1).unwrap();
7798            Pallet::place_commit_of_variant(
7799                &BOB,
7800                &STAKING,
7801                &VALIDATOR_ALPHA,
7802                STANDARD_COMMIT,
7803                &bob_commit_variant,
7804                &Directive::new(Precision::Exact, Fortitude::Force),
7805            )
7806            .unwrap();
7807            let charlie_commit_varinat = Position::position_of(2).unwrap();
7808            Pallet::place_commit_of_variant(
7809                &CHARLIE,
7810                &STAKING,
7811                &VALIDATOR_BETA,
7812                STANDARD_COMMIT,
7813                &charlie_commit_varinat,
7814                &Directive::new(Precision::Exact, Fortitude::Force),
7815            )
7816            .unwrap();
7817            prepare_and_initiate_index(
7818                MIKE,
7819                STAKING,
7820                &[
7821                    (VALIDATOR_ALPHA, SHARE_MAJOR),
7822                    (VALIDATOR_BETA, SHARE_DOMINANT),
7823                ],
7824                INDEX_OPTIMIZED_STAKING,
7825            )
7826            .unwrap();
7827            Pallet::place_commit(
7828                &ALICE,
7829                &STAKING,
7830                &INDEX_OPTIMIZED_STAKING,
7831                STANDARD_COMMIT,
7832                &Directive::new(Precision::Exact, Fortitude::Force),
7833            )
7834            .unwrap();
7835            // Since all entries are initialized with the default variant (regardless of the actual commit variant),
7836            // below entries should have the default variant at this point.
7837            let default_varinat = Position::default();
7838            let alpha_entry_variant =
7839                Pallet::get_entry_variant(&STAKING, &INDEX_OPTIMIZED_STAKING, &VALIDATOR_ALPHA)
7840                    .unwrap();
7841            assert_ne!(alpha_entry_variant, bob_commit_variant);
7842            assert_eq!(alpha_entry_variant, default_varinat);
7843            let beta_entry_variant =
7844                Pallet::get_entry_variant(&STAKING, &INDEX_OPTIMIZED_STAKING, &VALIDATOR_BETA)
7845                    .unwrap();
7846            assert_ne!(beta_entry_variant, charlie_commit_varinat);
7847            assert_eq!(beta_entry_variant, default_varinat);
7848        })
7849    }
7850
7851    #[test]
7852    fn get_entry_variant_err_entry_not_found() {
7853        commit_test_ext().execute_with(|| {
7854            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
7855            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
7856            prepare_and_initiate_index(
7857                ALICE,
7858                STAKING,
7859                &[
7860                    (VALIDATOR_ALPHA, SHARE_EQUAL),
7861                    (VALIDATOR_BETA, SHARE_EQUAL),
7862                ],
7863                INDEX_BALANCED_STAKING,
7864            )
7865            .unwrap();
7866            assert_err!(
7867                Pallet::get_entry_variant(&STAKING, &INDEX_BALANCED_STAKING, &VALIDATOR_GAMMA,),
7868                Error::EntryOfIndexNotFound
7869            );
7870        })
7871    }
7872
7873    #[test]
7874    fn set_entry_of_variant_success_only_variant() {
7875        commit_test_ext().execute_with(|| {
7876            set_default_user_balance_and_standard_hold(ALICE).unwrap();
7877            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
7878            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
7879            prepare_and_initiate_index(
7880                ALICE,
7881                STAKING,
7882                &[
7883                    (VALIDATOR_ALPHA, SHARE_MAJOR),
7884                    (VALIDATOR_BETA, SHARE_DOMINANT),
7885                ],
7886                INDEX_OPTIMIZED_STAKING,
7887            )
7888            .unwrap();
7889            Pallet::place_commit(
7890                &ALICE,
7891                &STAKING,
7892                &INDEX_OPTIMIZED_STAKING,
7893                STANDARD_COMMIT,
7894                &Directive::new(Precision::Exact, Fortitude::Force),
7895            )
7896            .unwrap();
7897            let current_variant =
7898                Pallet::get_entry_variant(&STAKING, &INDEX_OPTIMIZED_STAKING, &VALIDATOR_ALPHA)
7899                    .unwrap();
7900            assert_eq!(current_variant, Position::default());
7901            // updating the variant of an existing entry
7902            let new_variant = Position::position_of(2).unwrap();
7903            let new_index_digest = Pallet::set_entry_of_variant(
7904                &ALICE,
7905                &STAKING,
7906                &INDEX_OPTIMIZED_STAKING,
7907                &VALIDATOR_ALPHA,
7908                new_variant,
7909                None,
7910            )
7911            .unwrap();
7912            assert_ne!(INDEX_OPTIMIZED_STAKING, new_index_digest);
7913            // variant updated in new index
7914            let actual_variant =
7915                Pallet::get_entry_variant(&STAKING, &new_index_digest, &VALIDATOR_ALPHA).unwrap();
7916            assert_eq!(actual_variant, new_variant);
7917            // variant unaffected in old index
7918            let actual_variant =
7919                Pallet::get_entry_variant(&STAKING, &INDEX_OPTIMIZED_STAKING, &VALIDATOR_ALPHA)
7920                    .unwrap();
7921            assert_eq!(actual_variant, current_variant);
7922        })
7923    }
7924
7925    #[test]
7926    fn set_entry_of_variant_success_variant_with_shares() {
7927        commit_test_ext().execute_with(|| {
7928            set_default_user_balance_and_standard_hold(ALICE).unwrap();
7929            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
7930            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
7931            prepare_and_initiate_index(
7932                ALICE,
7933                STAKING,
7934                &[
7935                    (VALIDATOR_ALPHA, SHARE_MAJOR),
7936                    (VALIDATOR_BETA, SHARE_DOMINANT),
7937                ],
7938                INDEX_OPTIMIZED_STAKING,
7939            )
7940            .unwrap();
7941            Pallet::place_commit(
7942                &ALICE,
7943                &STAKING,
7944                &INDEX_OPTIMIZED_STAKING,
7945                STANDARD_COMMIT,
7946                &Directive::new(Precision::Exact, Fortitude::Force),
7947            )
7948            .unwrap();
7949            let new_shares = SHARE_DOMINANT;
7950            let new_variant = Position::position_of(2).unwrap();
7951            let new_index_digest = Pallet::set_entry_of_variant(
7952                &ALICE,
7953                &STAKING,
7954                &INDEX_OPTIMIZED_STAKING,
7955                &VALIDATOR_BETA,
7956                new_variant,
7957                Some(new_shares),
7958            )
7959            .unwrap();
7960            assert_ne!(INDEX_OPTIMIZED_STAKING, new_index_digest);
7961            // variant and shares updated in new index
7962            let actual_variant =
7963                Pallet::get_entry_variant(&STAKING, &new_index_digest, &VALIDATOR_BETA).unwrap();
7964            assert_eq!(actual_variant, new_variant);
7965            let actual_shares = Pallet::get_entries_shares(&STAKING, &new_index_digest).unwrap();
7966            let expected_shares =
7967                vec![(VALIDATOR_ALPHA, SHARE_MAJOR), (VALIDATOR_BETA, new_shares)];
7968            assert_eq!(actual_shares, expected_shares);
7969            // variant and shares unaffected in old index
7970            let default_variant = Position::default();
7971            let actual_variant =
7972                Pallet::get_entry_variant(&STAKING, &INDEX_OPTIMIZED_STAKING, &VALIDATOR_BETA)
7973                    .unwrap();
7974            assert_eq!(actual_variant, default_variant);
7975            let actual_shares =
7976                Pallet::get_entries_shares(&STAKING, &INDEX_OPTIMIZED_STAKING).unwrap();
7977            let expected_shares = vec![
7978                (VALIDATOR_ALPHA, SHARE_MAJOR),
7979                (VALIDATOR_BETA, SHARE_DOMINANT),
7980            ];
7981            assert_eq!(actual_shares, expected_shares);
7982        })
7983    }
7984
7985    #[test]
7986    fn set_entry_of_variant_new_entry_shares_cannot_be_none() {
7987        commit_test_ext().execute_with(|| {
7988            set_default_user_balance_and_standard_hold(ALICE).unwrap();
7989            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
7990            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
7991            prepare_and_initiate_index(
7992                ALICE,
7993                STAKING,
7994                &[
7995                    (VALIDATOR_ALPHA, SHARE_MAJOR),
7996                    (VALIDATOR_BETA, SHARE_DOMINANT),
7997                ],
7998                INDEX_OPTIMIZED_STAKING,
7999            )
8000            .unwrap();
8001            Pallet::place_commit(
8002                &ALICE,
8003                &STAKING,
8004                &INDEX_OPTIMIZED_STAKING,
8005                STANDARD_COMMIT,
8006                &Directive::new(Precision::Exact, Fortitude::Force),
8007            )
8008            .unwrap();
8009            let new_variant = Position::position_of(2).unwrap();
8010            let new_index_digest = Pallet::set_entry_of_variant(
8011                &ALICE,
8012                &STAKING,
8013                &INDEX_OPTIMIZED_STAKING,
8014                &VALIDATOR_GAMMA,
8015                new_variant,
8016                None,
8017            )
8018            .unwrap();
8019            // Since, the new entry share is set to `None`, same index digest is returned.
8020            assert_eq!(new_index_digest, INDEX_OPTIMIZED_STAKING);
8021        })
8022    }
8023
8024    #[test]
8025    fn set_entry_of_variant_err_entry_digest_not_initiated() {
8026        commit_test_ext().execute_with(|| {
8027            set_default_user_balance_and_standard_hold(ALICE).unwrap();
8028            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
8029            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
8030            prepare_and_initiate_index(
8031                ALICE,
8032                STAKING,
8033                &[
8034                    (VALIDATOR_ALPHA, SHARE_EQUAL),
8035                    (VALIDATOR_BETA, SHARE_EQUAL),
8036                ],
8037                INDEX_BALANCED_STAKING,
8038            )
8039            .unwrap();
8040            Pallet::place_commit(
8041                &ALICE,
8042                &STAKING,
8043                &INDEX_BALANCED_STAKING,
8044                STANDARD_COMMIT,
8045                &Directive::new(Precision::BestEffort, Fortitude::Polite),
8046            )
8047            .unwrap();
8048            let new_variant = Position::position_of(2).unwrap();
8049            // trying to insert uninitiated digest will return error
8050            assert_err!(Pallet::set_entry_of_variant(
8051                &ALICE,
8052                &STAKING,
8053                &INDEX_BALANCED_STAKING,
8054                &VALIDATOR_GAMMA,
8055                new_variant,
8056                Some(SHARE_MAJOR),
8057            ), Error::EntryDigestNotInitiated);
8058        })
8059    }
8060
8061    #[test]
8062    fn prepare_index_of_variants_success() {
8063        commit_test_ext().execute_with(|| {
8064            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
8065            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
8066            let entries = vec![
8067                (
8068                    VALIDATOR_ALPHA,
8069                    SHARE_DOMINANT,
8070                    Position::position_of(2).unwrap(),
8071                ),
8072                (
8073                    VALIDATOR_BETA,
8074                    SHARE_MAJOR,
8075                    Position::position_of(1).unwrap(),
8076                ),
8077            ];
8078            let index = Pallet::prepare_index_of_variants(&ALICE, &STAKING, entries).unwrap();
8079            assert_eq!(index.principal(), ZERO_VALUE);
8080            assert_eq!(index.capital(), 100);
8081            let expected_entry_alpha = EntryInfo::new(
8082                VALIDATOR_ALPHA,
8083                SHARE_DOMINANT,
8084                Position::position_of(2).unwrap(),
8085            )
8086            .unwrap();
8087            let expected_entry_beta = EntryInfo::new(
8088                VALIDATOR_BETA,
8089                SHARE_MAJOR,
8090                Position::position_of(1).unwrap(),
8091            )
8092            .unwrap();
8093            assert_eq!(index.entries().get(0).unwrap(), &expected_entry_alpha);
8094            assert_eq!(index.entries().get(1).unwrap(), &expected_entry_beta);
8095        })
8096    }
8097
8098    #[test]
8099    fn prepare_index_of_variants_err_duplicate_entry() {
8100        commit_test_ext().execute_with(|| {
8101            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
8102            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
8103            let actual_err = Pallet::prepare_index_of_variants(
8104                &ALICE,
8105                &STAKING,
8106                vec![
8107                    (VALIDATOR_ALPHA, SHARE_EQUAL, Position::default()),
8108                    (VALIDATOR_BETA, SHARE_EQUAL, Position::default()),
8109                    (VALIDATOR_ALPHA, SHARE_EQUAL, Position::default()),
8110                ],
8111            )
8112            .unwrap_err();
8113            let expected_err = Error::DuplicateEntry.into();
8114            assert_eq!(actual_err, expected_err);
8115        })
8116    }
8117
8118    #[test]
8119    fn prepare_index_of_variants_err_max_index_reached() {
8120        commit_test_ext().execute_with(|| {
8121            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
8122            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
8123            initiate_digest_with_default_balance(STAKING, VALIDATOR_GAMMA).unwrap();
8124            initiate_digest_with_default_balance(STAKING, VALIDATOR_DELTA).unwrap();
8125            let actual_err = Pallet::prepare_index_of_variants(
8126                &ALICE,
8127                &STAKING,
8128                vec![
8129                    (VALIDATOR_ALPHA, SHARE_EQUAL, Position::default()),
8130                    (
8131                        VALIDATOR_BETA,
8132                        SHARE_EQUAL,
8133                        Position::position_of(2).unwrap(),
8134                    ),
8135                    (VALIDATOR_GAMMA, SHARE_EQUAL, Position::default()),
8136                    (VALIDATOR_DELTA, SHARE_EQUAL, Position::default()),
8137                ],
8138            )
8139            .unwrap_err();
8140            // since MaxEntries is set to 3, adding a fourth entry results in err
8141            assert_eq!(actual_err, Error::MaxEntriesReached.into());
8142        })
8143    }
8144
8145    #[test]
8146    fn prepare_index_of_variants_rejects_uninitiated_digest() {
8147        commit_test_ext().execute_with(||{
8148            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
8149            let entries = vec![
8150                (VALIDATOR_ALPHA, 100, Position::default()), 
8151                (VALIDATOR_BETA, 200, Position::default())
8152            ];
8153            assert_err!(
8154                Pallet::prepare_index_of_variants(
8155                    &ALICE,
8156                    &STAKING,
8157                    entries
8158                ),
8159                Error::EntryDigestNotInitiated
8160            );
8161        })
8162    }
8163
8164    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8165    // ````````````````````````````````` COMMIT POOL `````````````````````````````````
8166    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8167
8168    #[test]
8169    fn pool_exists_ok() {
8170        commit_test_ext().execute_with(|| {
8171            let entries = vec![
8172                (VALIDATOR_ALPHA, SHARE_EQUAL),
8173                (VALIDATOR_BETA, SHARE_EQUAL),
8174            ];
8175            prepare_and_initiate_pool(
8176                ALICE,
8177                STAKING,
8178                &entries,
8179                INDEX_BALANCED_STAKING,
8180                POOL_MANAGED_STAKING,
8181                COMMISSION_LOW,
8182            )
8183            .unwrap();
8184            assert_ok!(Pallet::pool_exists(&STAKING, &POOL_MANAGED_STAKING));
8185        })
8186    }
8187
8188    #[test]
8189    fn pool_exists_err_pool_not_found() {
8190        commit_test_ext().execute_with(|| {
8191            let entries = vec![
8192                (VALIDATOR_ALPHA, SHARE_EQUAL),
8193                (VALIDATOR_BETA, SHARE_EQUAL),
8194            ];
8195            prepare_and_initiate_pool(
8196                ALICE,
8197                STAKING,
8198                &entries,
8199                INDEX_BALANCED_STAKING,
8200                POOL_MANAGED_STAKING,
8201                COMMISSION_LOW,
8202            )
8203            .unwrap();
8204            assert_err!(
8205                Pallet::pool_exists(&ESCROW, &POOL_PROFESSIONAL_ESCROW),
8206                Error::PoolNotFound
8207            );
8208        })
8209    }
8210
8211    #[test]
8212    fn slot_exists_ok() {
8213        commit_test_ext().execute_with(|| {
8214            let entries = vec![
8215                (VALIDATOR_ALPHA, SHARE_EQUAL),
8216                (VALIDATOR_BETA, SHARE_EQUAL),
8217            ];
8218            prepare_and_initiate_pool(
8219                ALICE,
8220                STAKING,
8221                &entries,
8222                INDEX_BALANCED_STAKING,
8223                POOL_MANAGED_STAKING,
8224                COMMISSION_LOW,
8225            )
8226            .unwrap();
8227            assert_ok!(Pallet::slot_exists(
8228                &STAKING,
8229                &POOL_MANAGED_STAKING,
8230                &VALIDATOR_ALPHA
8231            ));
8232        })
8233    }
8234
8235    #[test]
8236    fn slot_exists_err_slot_not_found() {
8237        commit_test_ext().execute_with(|| {
8238            let entries = vec![
8239                (VALIDATOR_ALPHA, SHARE_EQUAL),
8240                (VALIDATOR_BETA, SHARE_EQUAL),
8241            ];
8242            prepare_and_initiate_pool(
8243                ALICE,
8244                STAKING,
8245                &entries,
8246                INDEX_BALANCED_STAKING,
8247                POOL_MANAGED_STAKING,
8248                COMMISSION_LOW,
8249            )
8250            .unwrap();
8251            assert_err!(
8252                Pallet::slot_exists(&STAKING, &POOL_MANAGED_STAKING, &VALIDATOR_GAMMA),
8253                Error::SlotOfPoolNotFound
8254            );
8255        })
8256    }
8257
8258    #[test]
8259    fn has_pool_ok() {
8260        commit_test_ext().execute_with(|| {
8261            let entries = vec![
8262                (VALIDATOR_ALPHA, SHARE_EQUAL),
8263                (VALIDATOR_BETA, SHARE_EQUAL),
8264            ];
8265            prepare_and_initiate_pool(
8266                ALICE,
8267                STAKING,
8268                &entries,
8269                INDEX_BALANCED_STAKING,
8270                POOL_MANAGED_STAKING,
8271                COMMISSION_LOW,
8272            )
8273            .unwrap();
8274            assert_ok!(Pallet::has_pool(&STAKING));
8275        })
8276    }
8277
8278    #[test]
8279    fn has_pool_err_pool_not_found() {
8280        commit_test_ext().execute_with(|| {
8281            let entries = vec![
8282                (VALIDATOR_ALPHA, SHARE_EQUAL),
8283                (VALIDATOR_BETA, SHARE_EQUAL),
8284            ];
8285            prepare_and_initiate_pool(
8286                ALICE,
8287                STAKING,
8288                &entries,
8289                INDEX_BALANCED_STAKING,
8290                POOL_MANAGED_STAKING,
8291                COMMISSION_LOW,
8292            )
8293            .unwrap();
8294            assert_err!(Pallet::has_pool(&GOVERNANCE), Error::PoolNotFound);
8295        })
8296    }
8297
8298    #[test]
8299    fn get_manager_success() {
8300        commit_test_ext().execute_with(|| {
8301            let entries = vec![
8302                (VALIDATOR_ALPHA, SHARE_EQUAL),
8303                (VALIDATOR_BETA, SHARE_EQUAL),
8304            ];
8305            prepare_and_initiate_pool(
8306                ALICE,
8307                STAKING,
8308                &entries,
8309                INDEX_BALANCED_STAKING,
8310                POOL_MANAGED_STAKING,
8311                COMMISSION_LOW,
8312            )
8313            .unwrap();
8314            assert_eq!(
8315                Pallet::get_manager(&STAKING, &POOL_MANAGED_STAKING),
8316                Ok(ALICE)
8317            );
8318        })
8319    }
8320
8321    #[test]
8322    fn get_manager_err_pool_not_found() {
8323        commit_test_ext().execute_with(|| {
8324            let entries = vec![
8325                (VALIDATOR_ALPHA, SHARE_EQUAL),
8326                (VALIDATOR_BETA, SHARE_EQUAL),
8327            ];
8328            prepare_and_initiate_pool(
8329                ALICE,
8330                STAKING,
8331                &entries,
8332                INDEX_BALANCED_STAKING,
8333                POOL_MANAGED_STAKING,
8334                COMMISSION_LOW,
8335            )
8336            .unwrap();
8337            // checks pool first
8338            assert_err!(
8339                Pallet::get_manager(&ESCROW, &POOL_PROFESSIONAL_ESCROW),
8340                Error::PoolNotFound
8341            );
8342        })
8343    }
8344
8345    #[test]
8346    fn get_pool_success() {
8347        commit_test_ext().execute_with(|| {
8348            let entries = vec![
8349                (VALIDATOR_ALPHA, SHARE_EQUAL),
8350                (VALIDATOR_BETA, SHARE_EQUAL),
8351            ];
8352            prepare_and_initiate_pool(
8353                ALICE,
8354                STAKING,
8355                &entries,
8356                INDEX_BALANCED_STAKING,
8357                POOL_MANAGED_STAKING,
8358                COMMISSION_LOW,
8359            )
8360            .unwrap();
8361            let expected_pool = PoolMap::get((STAKING, POOL_MANAGED_STAKING)).unwrap();
8362            let actual_pool = Pallet::get_pool(&STAKING, &POOL_MANAGED_STAKING).unwrap();
8363            assert_eq!(expected_pool.balance(), actual_pool.balance());
8364            assert_eq!(expected_pool.capital(), actual_pool.capital());
8365            assert_eq!(expected_pool.commission(), actual_pool.commission());
8366            assert_eq!(
8367                expected_pool.slots().get(0).unwrap(),
8368                actual_pool.slots().get(0).unwrap()
8369            );
8370            assert_eq!(
8371                expected_pool.slots().get(1).unwrap(),
8372                actual_pool.slots().get(1).unwrap()
8373            );
8374        })
8375    }
8376
8377    #[test]
8378    fn get_pool_err_pool_not_found() {
8379        commit_test_ext().execute_with(|| {
8380            let entries = vec![
8381                (VALIDATOR_ALPHA, SHARE_EQUAL),
8382                (VALIDATOR_BETA, SHARE_EQUAL),
8383            ];
8384            prepare_and_initiate_pool(
8385                ALICE,
8386                STAKING,
8387                &entries,
8388                INDEX_BALANCED_STAKING,
8389                POOL_MANAGED_STAKING,
8390                COMMISSION_LOW,
8391            )
8392            .unwrap();
8393            let err = Pallet::get_pool(&ESCROW, &POOL_PROFESSIONAL_ESCROW).unwrap_err();
8394            assert_eq!(err, Error::PoolNotFound.into());
8395        })
8396    }
8397
8398    #[test]
8399    fn get_commission_success() {
8400        commit_test_ext().execute_with(|| {
8401            let entries = vec![
8402                (VALIDATOR_ALPHA, SHARE_EQUAL),
8403                (VALIDATOR_BETA, SHARE_EQUAL),
8404            ];
8405            prepare_and_initiate_pool(
8406                ALICE,
8407                STAKING,
8408                &entries,
8409                INDEX_BALANCED_STAKING,
8410                POOL_MANAGED_STAKING,
8411                COMMISSION_STANDARD,
8412            )
8413            .unwrap();
8414            let actual_commission =
8415                Pallet::get_commission(&STAKING, &POOL_MANAGED_STAKING).unwrap();
8416            assert_eq!(actual_commission, COMMISSION_STANDARD);
8417        })
8418    }
8419
8420    #[test]
8421    fn get_commission_err_pool_not_found() {
8422        commit_test_ext().execute_with(|| {
8423            let entries = vec![
8424                (VALIDATOR_ALPHA, SHARE_EQUAL),
8425                (VALIDATOR_BETA, SHARE_EQUAL),
8426            ];
8427            prepare_and_initiate_pool(
8428                ALICE,
8429                STAKING,
8430                &entries,
8431                INDEX_BALANCED_STAKING,
8432                POOL_MANAGED_STAKING,
8433                COMMISSION_STANDARD,
8434            )
8435            .unwrap();
8436            let err = Pallet::get_commission(&GOVERNANCE, &POOL_EXPERT_GOVERNANCE).unwrap_err();
8437            assert_eq!(err, Error::PoolNotFound.into());
8438        })
8439    }
8440
8441    #[test]
8442    fn set_pool_success() {
8443        commit_test_ext().execute_with(|| {
8444            System::set_block_number(10);
8445            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
8446            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
8447            prepare_and_initiate_index(
8448                ALICE,
8449                STAKING,
8450                &[
8451                    (VALIDATOR_ALPHA, SHARE_MAJOR),
8452                    (VALIDATOR_BETA, SHARE_DOMINANT),
8453                ],
8454                INDEX_OPTIMIZED_STAKING,
8455            )
8456            .unwrap();
8457            assert_ok!(Pallet::index_exists(&STAKING, &INDEX_OPTIMIZED_STAKING));
8458            assert_err!(
8459                Pallet::pool_exists(&STAKING, &POOL_MANAGED_STAKING),
8460                Error::PoolNotFound
8461            );
8462            let commission = COMMISSION_STANDARD;
8463            Pallet::set_pool(
8464                &ALICE,
8465                &STAKING,
8466                &POOL_MANAGED_STAKING,
8467                &INDEX_OPTIMIZED_STAKING,
8468                commission,
8469            )
8470            .unwrap();
8471            assert_ok!(Pallet::pool_exists(&STAKING, &POOL_MANAGED_STAKING));
8472            let pool_info = PoolMap::get((STAKING, POOL_MANAGED_STAKING)).unwrap();
8473            assert_eq!(pool_info.capital(), 100);
8474            assert_eq!(pool_info.commission(), commission);
8475            assert_eq!(
8476                Pallet::get_manager(&STAKING, &POOL_MANAGED_STAKING),
8477                Ok(ALICE)
8478            );
8479
8480            #[cfg(not(feature = "dev"))]
8481            System::assert_last_event(Event::PoolInitialized {
8482                    pool_of: POOL_MANAGED_STAKING,
8483                    reason: STAKING,
8484                    commission: commission
8485                }
8486                .into()
8487            );
8488
8489            #[cfg(feature = "dev")]
8490            {            
8491                let slots = vec![(VALIDATOR_ALPHA, SHARE_MAJOR, Disposition::default()), (VALIDATOR_BETA, SHARE_DOMINANT, Disposition::default())];
8492                System::assert_last_event(Event::PoolInitialized {
8493                        pool_of: POOL_MANAGED_STAKING,
8494                        reason: STAKING,
8495                        commission: commission,
8496                        slots
8497                    }
8498                    .into()
8499                );
8500            }
8501        })
8502    }
8503
8504    #[test]
8505    fn set_pool_err_pool_already_exists() {
8506        commit_test_ext().execute_with(|| {
8507            let entries = vec![
8508                (VALIDATOR_ALPHA, SHARE_EQUAL),
8509                (VALIDATOR_BETA, SHARE_EQUAL),
8510            ];
8511            prepare_and_initiate_pool(
8512                ALICE,
8513                STAKING,
8514                &entries,
8515                INDEX_BALANCED_STAKING,
8516                POOL_MANAGED_STAKING,
8517                COMMISSION_LOW,
8518            )
8519            .unwrap();
8520            assert_err!(
8521                Pallet::set_pool(
8522                    &ALICE,
8523                    &STAKING,
8524                    &POOL_MANAGED_STAKING,
8525                    &INDEX_BALANCED_STAKING,
8526                    COMMISSION_STANDARD,
8527                ),
8528                Error::PoolDigestTaken
8529            );
8530        })
8531    }
8532
8533    #[test]
8534    fn set_pool_manager_ok() {
8535        commit_test_ext().execute_with(|| {
8536            let entries = vec![
8537                (VALIDATOR_ALPHA, SHARE_EQUAL),
8538                (VALIDATOR_BETA, SHARE_EQUAL),
8539            ];
8540            prepare_and_initiate_pool(
8541                ALICE,
8542                STAKING,
8543                &entries,
8544                INDEX_BALANCED_STAKING,
8545                POOL_MANAGED_STAKING,
8546                COMMISSION_LOW,
8547            )
8548            .unwrap();
8549            assert_eq!(
8550                Pallet::get_manager(&STAKING, &POOL_MANAGED_STAKING),
8551                Ok(ALICE)
8552            );
8553            // change manager from alice -> charlie
8554            assert_ok!(Pallet::set_pool_manager(
8555                &STAKING,
8556                &POOL_MANAGED_STAKING,
8557                &CHARLIE
8558            ));
8559            // manager changed
8560            assert_eq!(
8561                Pallet::get_manager(&STAKING, &POOL_MANAGED_STAKING),
8562                Ok(CHARLIE)
8563            );
8564        })
8565    }
8566
8567    #[test]
8568    fn set_slot_shares_success_updating_existing_slot_shares() {
8569        commit_test_ext().execute_with(|| {
8570            set_default_user_balance_and_standard_hold(ALICE).unwrap();
8571            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
8572            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
8573            let entries = vec![
8574                (VALIDATOR_ALPHA, SHARE_DOMINANT),
8575                (VALIDATOR_BETA, SHARE_MAJOR),
8576            ];
8577            prepare_and_initiate_pool(
8578                ALICE,
8579                STAKING,
8580                &entries,
8581                INDEX_OPTIMIZED_STAKING,
8582                POOL_MANAGED_STAKING,
8583                COMMISSION_LOW,
8584            )
8585            .unwrap();
8586            Pallet::place_commit(
8587                &ALICE,
8588                &STAKING,
8589                &INDEX_OPTIMIZED_STAKING,
8590                STANDARD_COMMIT,
8591                &Directive::new(Precision::Exact, Fortitude::Force),
8592            )
8593            .unwrap();
8594
8595            assert_ok!(Pallet::set_slot_shares(
8596                &ALICE,
8597                &STAKING,
8598                &POOL_MANAGED_STAKING,
8599                &VALIDATOR_ALPHA,
8600                SHARE_EQUAL
8601            ));
8602            assert_ok!(Pallet::set_slot_shares(
8603                &ALICE,
8604                &STAKING,
8605                &POOL_MANAGED_STAKING,
8606                &VALIDATOR_BETA,
8607                SHARE_EQUAL
8608            ));
8609            let expected_slots_shares = vec![
8610                (VALIDATOR_ALPHA, SHARE_EQUAL),
8611                (VALIDATOR_BETA, SHARE_EQUAL),
8612            ];
8613            let actual_slots_shares =
8614                Pallet::get_slots_shares(&STAKING, &POOL_MANAGED_STAKING).unwrap();
8615            assert_eq!(actual_slots_shares, expected_slots_shares)
8616        })
8617    }
8618
8619    #[test]
8620    fn set_slot_shares_success_removing_slot_with_zero_share() {
8621        commit_test_ext().execute_with(|| {
8622            set_default_user_balance_and_standard_hold(ALICE).unwrap();
8623            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
8624            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
8625            let entries = vec![
8626                (VALIDATOR_ALPHA, SHARE_DOMINANT),
8627                (VALIDATOR_BETA, SHARE_MAJOR),
8628            ];
8629            prepare_and_initiate_pool(
8630                MIKE,
8631                STAKING,
8632                &entries,
8633                INDEX_OPTIMIZED_STAKING,
8634                POOL_MANAGED_STAKING,
8635                COMMISSION_LOW,
8636            )
8637            .unwrap();
8638            Pallet::place_commit(
8639                &ALICE,
8640                &STAKING,
8641                &INDEX_OPTIMIZED_STAKING,
8642                STANDARD_COMMIT,
8643                &Directive::new(Precision::Exact, Fortitude::Force),
8644            )
8645            .unwrap();
8646
8647            assert_ok!(Pallet::set_slot_shares(
8648                &MIKE,
8649                &STAKING,
8650                &POOL_MANAGED_STAKING,
8651                &VALIDATOR_ALPHA,
8652                SHARE_EQUAL
8653            ));
8654            assert_ok!(Pallet::set_slot_shares(
8655                &MIKE,
8656                &STAKING,
8657                &POOL_MANAGED_STAKING,
8658                &VALIDATOR_BETA,
8659                ZERO_SHARE,
8660            ));
8661            // VALIDATOR_BETA is removed
8662            let expected_slots_shares = vec![(VALIDATOR_ALPHA, SHARE_EQUAL)];
8663            let actual_slots_shares =
8664                Pallet::get_slots_shares(&STAKING, &POOL_MANAGED_STAKING).unwrap();
8665            assert_eq!(actual_slots_shares, expected_slots_shares)
8666        })
8667    }
8668
8669    #[test]
8670    fn set_slot_shares_success_creating_new_slot_with_non_zero_shares() {
8671        commit_test_ext().execute_with(|| {
8672            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
8673            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
8674            initiate_digest_with_default_balance(STAKING, VALIDATOR_GAMMA).unwrap();
8675
8676            let entries = vec![
8677                (VALIDATOR_ALPHA, SHARE_EQUAL),
8678                (VALIDATOR_BETA, SHARE_EQUAL),
8679            ];
8680            prepare_and_initiate_pool(
8681                MIKE,
8682                STAKING,
8683                &entries,
8684                INDEX_BALANCED_STAKING,
8685                POOL_MANAGED_STAKING,
8686                COMMISSION_LOW,
8687            )
8688            .unwrap();
8689
8690            assert_ok!(Pallet::set_slot_shares(
8691                &MIKE,
8692                &STAKING,
8693                &POOL_MANAGED_STAKING,
8694                &VALIDATOR_GAMMA,
8695                SHARE_EQUAL
8696            ));
8697            // VALIDATOR_GAMMA is added to the existing slots
8698            let expected_slots_shares = vec![
8699                (VALIDATOR_ALPHA, SHARE_EQUAL),
8700                (VALIDATOR_BETA, SHARE_EQUAL),
8701                (VALIDATOR_GAMMA, SHARE_EQUAL),
8702            ];
8703            let actual_slots_shares =
8704                Pallet::get_slots_shares(&STAKING, &POOL_MANAGED_STAKING).unwrap();
8705            assert_eq!(actual_slots_shares, expected_slots_shares)
8706        })
8707    }
8708
8709    #[test]
8710    fn set_slot_shares_err_slot_digest_not_initiated() {
8711        commit_test_ext().execute_with(|| {
8712            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
8713            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
8714
8715            let entries = vec![
8716                (VALIDATOR_ALPHA, SHARE_EQUAL),
8717                (VALIDATOR_BETA, SHARE_EQUAL),
8718            ];
8719            prepare_and_initiate_pool(
8720                MIKE,
8721                STAKING,
8722                &entries,
8723                INDEX_BALANCED_STAKING,
8724                POOL_MANAGED_STAKING,
8725                COMMISSION_LOW,
8726            )
8727            .unwrap();
8728
8729            // tryign to add uninitiated digest returns error
8730            assert_err!(Pallet::set_slot_shares(
8731                &MIKE,
8732                &STAKING,
8733                &POOL_MANAGED_STAKING,
8734                &VALIDATOR_GAMMA,
8735                SHARE_EQUAL
8736            ), Error::SlotDigestNotInitiated);
8737        })
8738    }
8739
8740    #[test]
8741    fn gen_pool_digest_success() {
8742        commit_test_ext().execute_with(|| {
8743            set_default_user_balance_and_standard_hold(ALICE).unwrap();
8744            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
8745            initiate_digest_with_default_balance(ESCROW, CONTRACT_FREELANCE).unwrap();
8746            prepare_and_initiate_index(
8747                ALICE,
8748                STAKING,
8749                &[(VALIDATOR_ALPHA, SHARE_EQUAL)],
8750                INDEX_BALANCED_STAKING,
8751            )
8752            .unwrap();
8753            prepare_and_initiate_index(
8754                CHARLIE,
8755                ESCROW,
8756                &[(CONTRACT_FREELANCE, SHARE_EQUAL)],
8757                INDEX_ESCROW_DISTRIBUTION,
8758            )
8759            .unwrap();
8760            let gen_pool_diget_1 =
8761                Pallet::gen_pool_digest(&ALICE, &STAKING, &INDEX_BALANCED_STAKING, COMMISSION_LOW);
8762            assert!(gen_pool_diget_1.is_ok());
8763            let gen_pool_diget_2 =
8764                Pallet::gen_pool_digest(&ALICE, &STAKING, &INDEX_BALANCED_STAKING, COMMISSION_LOW);
8765            assert!(gen_pool_diget_2.is_ok());
8766            assert_eq!(gen_pool_diget_1, gen_pool_diget_2); // deterministic key generation for same inputs
8767
8768            // Different index digest, manager and reason
8769            let gen_pool_diget_3 = Pallet::gen_pool_digest(
8770                &CHARLIE,
8771                &ESCROW,
8772                &INDEX_ESCROW_DISTRIBUTION,
8773                COMMISSION_LOW,
8774            );
8775            assert!(gen_pool_diget_3.is_ok());
8776            assert_ne!(gen_pool_diget_2, gen_pool_diget_3);
8777            // Same proprietor, reason, index_digest with different commission
8778            let gen_pool_diget_4 = Pallet::gen_pool_digest(
8779                &CHARLIE,
8780                &ESCROW,
8781                &INDEX_ESCROW_DISTRIBUTION,
8782                COMMISSION_STANDARD,
8783            );
8784            assert!(gen_pool_diget_4.is_ok());
8785            assert_ne!(gen_pool_diget_3, gen_pool_diget_4);
8786            assert_ne!(gen_pool_diget_2, gen_pool_diget_4);
8787        })
8788    }
8789
8790    #[test]
8791    fn get_slot_shares_success() {
8792        commit_test_ext().execute_with(|| {
8793            let entries = vec![
8794                (VALIDATOR_ALPHA, SHARE_DOMINANT),
8795                (VALIDATOR_BETA, SHARE_MAJOR),
8796            ];
8797            prepare_and_initiate_pool(
8798                MIKE,
8799                STAKING,
8800                &entries,
8801                INDEX_OPTIMIZED_STAKING,
8802                POOL_MANAGED_STAKING,
8803                COMMISSION_LOW,
8804            )
8805            .unwrap();
8806            let expected_slots_shares = vec![
8807                (VALIDATOR_ALPHA, SHARE_DOMINANT),
8808                (VALIDATOR_BETA, SHARE_MAJOR),
8809            ];
8810            let actual_slots_shares =
8811                Pallet::get_slots_shares(&STAKING, &POOL_MANAGED_STAKING).unwrap();
8812            assert_eq!(actual_slots_shares, expected_slots_shares)
8813        })
8814    }
8815
8816    #[test]
8817    fn get_slot_value_success() {
8818        commit_test_ext().execute_with(|| {
8819            set_default_user_balance_and_standard_hold(ALICE).unwrap();
8820            set_default_user_balance_and_standard_hold(BOB).unwrap();
8821            set_default_user_balance_and_standard_hold(CHARLIE).unwrap();
8822            set_default_user_balance_and_standard_hold(ALAN).unwrap();
8823            Pallet::place_commit(
8824                &BOB,
8825                &STAKING,
8826                &VALIDATOR_ALPHA,
8827                STANDARD_COMMIT,
8828                &Directive::new(Precision::Exact, Fortitude::Force),
8829            )
8830            .unwrap();
8831            Pallet::place_commit(
8832                &ALAN,
8833                &STAKING,
8834                &VALIDATOR_BETA,
8835                STANDARD_COMMIT,
8836                &Directive::new(Precision::Exact, Fortitude::Force),
8837            )
8838            .unwrap();
8839
8840            let entries = vec![
8841                (VALIDATOR_ALPHA, SHARE_DOMINANT),
8842                (VALIDATOR_BETA, SHARE_MAJOR),
8843            ];
8844            prepare_and_initiate_pool(
8845                MIKE,
8846                STAKING,
8847                &entries,
8848                INDEX_OPTIMIZED_STAKING,
8849                POOL_MANAGED_STAKING,
8850                COMMISSION_LOW,
8851            )
8852            .unwrap();
8853            Pallet::place_commit(
8854                &ALICE,
8855                &STAKING,
8856                &POOL_MANAGED_STAKING,
8857                STANDARD_COMMIT,
8858                &Directive::new(Precision::Exact, Fortitude::Force),
8859            )
8860            .unwrap();
8861
8862            let expected_alpha_slot_value = 150;
8863            let actual_alpha_slot_value =
8864                Pallet::get_slot_value(&STAKING, &POOL_MANAGED_STAKING, &VALIDATOR_ALPHA).unwrap();
8865            assert_eq!(expected_alpha_slot_value, actual_alpha_slot_value);
8866
8867            let expected_beta_slot_value = 100;
8868            let actual_beta_slot_value =
8869                Pallet::get_slot_value(&STAKING, &POOL_MANAGED_STAKING, &VALIDATOR_BETA).unwrap();
8870            assert_eq!(expected_beta_slot_value, actual_beta_slot_value);
8871
8872            Pallet::place_commit(
8873                &CHARLIE,
8874                &STAKING,
8875                &POOL_MANAGED_STAKING,
8876                LARGE_COMMIT,
8877                &Directive::new(Precision::Exact, Fortitude::Force),
8878            )
8879            .unwrap();
8880
8881            let expected_alpha_slot_value = 450;
8882            let actual_alpha_slot_value =
8883                Pallet::get_slot_value(&STAKING, &POOL_MANAGED_STAKING, &VALIDATOR_ALPHA).unwrap();
8884            assert_eq!(expected_alpha_slot_value, actual_alpha_slot_value);
8885
8886            let expected_beta_slot_value = 300;
8887            let actual_beta_slot_value =
8888                Pallet::get_slot_value(&STAKING, &POOL_MANAGED_STAKING, &VALIDATOR_BETA).unwrap();
8889            assert_eq!(expected_beta_slot_value, actual_beta_slot_value);
8890        })
8891    }
8892
8893    #[test]
8894    fn get_slot_value_for_success() {
8895        commit_test_ext().execute_with(|| {
8896            set_default_user_balance_and_standard_hold(ALICE).unwrap();
8897            set_default_user_balance_and_standard_hold(BOB).unwrap();
8898            set_default_user_balance_and_standard_hold(CHARLIE).unwrap();
8899            set_default_user_balance_and_standard_hold(ALAN).unwrap();
8900            Pallet::place_commit(
8901                &BOB,
8902                &STAKING,
8903                &VALIDATOR_ALPHA,
8904                STANDARD_COMMIT,
8905                &Directive::new(Precision::Exact, Fortitude::Force),
8906            )
8907            .unwrap();
8908            Pallet::place_commit(
8909                &ALAN,
8910                &STAKING,
8911                &VALIDATOR_BETA,
8912                STANDARD_COMMIT,
8913                &Directive::new(Precision::Exact, Fortitude::Force),
8914            )
8915            .unwrap();
8916
8917            let entries = vec![
8918                (VALIDATOR_ALPHA, SHARE_DOMINANT),
8919                (VALIDATOR_BETA, SHARE_MAJOR),
8920            ];
8921            prepare_and_initiate_pool(
8922                MIKE,
8923                STAKING,
8924                &entries,
8925                INDEX_OPTIMIZED_STAKING,
8926                POOL_MANAGED_STAKING,
8927                COMMISSION_LOW,
8928            )
8929            .unwrap();
8930            Pallet::place_commit(
8931                &ALICE,
8932                &STAKING,
8933                &POOL_MANAGED_STAKING,
8934                STANDARD_COMMIT,
8935                &Directive::new(Precision::Exact, Fortitude::Force),
8936            )
8937            .unwrap();
8938
8939            Pallet::place_commit(
8940                &CHARLIE,
8941                &STAKING,
8942                &POOL_MANAGED_STAKING,
8943                SMALL_COMMIT,
8944                &Directive::new(Precision::Exact, Fortitude::Force),
8945            )
8946            .unwrap();
8947            // pool slot value of alice
8948            let expected_alpha_slot_value = 150;
8949            let actual_alpha_slot_value = Pallet::get_slot_value_for(
8950                &ALICE,
8951                &STAKING,
8952                &POOL_MANAGED_STAKING,
8953                &VALIDATOR_ALPHA,
8954            )
8955            .unwrap();
8956            assert_eq!(expected_alpha_slot_value, actual_alpha_slot_value);
8957
8958            let expected_beta_slot_value = 100;
8959            let actual_beta_slot_value = Pallet::get_slot_value_for(
8960                &ALICE,
8961                &STAKING,
8962                &POOL_MANAGED_STAKING,
8963                &VALIDATOR_BETA,
8964            )
8965            .unwrap();
8966            assert_eq!(expected_beta_slot_value, actual_beta_slot_value);
8967            // pool slot value of charlie
8968            let expected_alpha_slot_value = 60;
8969            let actual_alpha_slot_value = Pallet::get_slot_value_for(
8970                &CHARLIE,
8971                &STAKING,
8972                &POOL_MANAGED_STAKING,
8973                &VALIDATOR_ALPHA,
8974            )
8975            .unwrap();
8976            assert_eq!(expected_alpha_slot_value, actual_alpha_slot_value);
8977
8978            let expected_beta_slot_value = 40;
8979            let actual_beta_slot_value = Pallet::get_slot_value_for(
8980                &CHARLIE,
8981                &STAKING,
8982                &POOL_MANAGED_STAKING,
8983                &VALIDATOR_BETA,
8984            )
8985            .unwrap();
8986            assert_eq!(expected_beta_slot_value, actual_beta_slot_value);
8987        })
8988    }
8989
8990    #[test]
8991    fn reap_pool_success() {
8992        commit_test_ext().execute_with(|| {
8993            let entries = vec![
8994                (VALIDATOR_ALPHA, SHARE_MAJOR),
8995                (VALIDATOR_BETA, SHARE_DOMINANT),
8996            ];
8997            prepare_and_initiate_pool(
8998                ALICE,
8999                STAKING,
9000                &entries,
9001                INDEX_OPTIMIZED_STAKING,
9002                POOL_MANAGED_STAKING,
9003                COMMISSION_LOW,
9004            )
9005            .unwrap();
9006            assert_ok!(Pallet::pool_exists(&STAKING, &POOL_MANAGED_STAKING));
9007            assert_ok!(Pallet::reap_pool(&STAKING, &POOL_MANAGED_STAKING));
9008            assert_err!(
9009                Pallet::pool_exists(&STAKING, &POOL_MANAGED_STAKING),
9010                Error::PoolNotFound
9011            );
9012        })
9013    }
9014
9015    #[test]
9016    fn reap_pool_err_pool_has_funds() {
9017        commit_test_ext().execute_with(|| {
9018            set_default_user_balance_and_standard_hold(ALICE).unwrap();
9019            set_default_user_balance_and_standard_hold(BOB).unwrap();
9020            set_default_user_balance_and_standard_hold(CHARLIE).unwrap();
9021            Pallet::place_commit(
9022                &BOB,
9023                &STAKING,
9024                &VALIDATOR_ALPHA,
9025                STANDARD_COMMIT,
9026                &Directive::new(Precision::Exact, Fortitude::Force),
9027            )
9028            .unwrap();
9029            Pallet::place_commit(
9030                &CHARLIE,
9031                &STAKING,
9032                &VALIDATOR_BETA,
9033                STANDARD_COMMIT,
9034                &Directive::new(Precision::Exact, Fortitude::Force),
9035            )
9036            .unwrap();
9037            let entries = vec![
9038                (VALIDATOR_ALPHA, SHARE_EQUAL),
9039                (VALIDATOR_BETA, SHARE_EQUAL),
9040            ];
9041            prepare_and_initiate_pool(
9042                ALICE,
9043                STAKING,
9044                &entries,
9045                INDEX_BALANCED_STAKING,
9046                POOL_MANAGED_STAKING,
9047                COMMISSION_LOW,
9048            )
9049            .unwrap();
9050            Pallet::place_commit(
9051                &ALICE,
9052                &STAKING,
9053                &POOL_MANAGED_STAKING,
9054                STANDARD_COMMIT,
9055                &Directive::new(Precision::Exact, Fortitude::Force),
9056            )
9057            .unwrap();
9058            assert_err!(
9059                Pallet::reap_pool(&STAKING, &POOL_MANAGED_STAKING),
9060                Error::PoolHasFunds
9061            );
9062        })
9063    }
9064
9065    #[test]
9066    fn on_set_pool_event_emmission_success() {
9067        commit_test_ext().execute_with(|| {
9068            let entries = vec![
9069                (VALIDATOR_ALPHA, SHARE_EQUAL),
9070                (VALIDATOR_BETA, SHARE_EQUAL),
9071            ];
9072            System::set_block_number(BLOCK_EARLY);
9073            prepare_and_initiate_pool(
9074                ALICE,
9075                STAKING,
9076                &entries,
9077                INDEX_BALANCED_STAKING,
9078                POOL_MANAGED_STAKING,
9079                COMMISSION_LOW,
9080            )
9081            .unwrap();
9082            #[cfg(feature = "dev")]
9083            let entries_defaults = vec![
9084                (VALIDATOR_ALPHA, SHARE_EQUAL, Position::default()),
9085                (VALIDATOR_BETA, SHARE_EQUAL, Position::default()),
9086            ];
9087            System::assert_last_event(
9088                Event::PoolInitialized {
9089                    pool_of: POOL_MANAGED_STAKING,
9090                    reason: STAKING,
9091                    commission: COMMISSION_LOW,
9092                    #[cfg(feature = "dev")]
9093                    slots: entries_defaults,
9094                }
9095                .into(),
9096            );
9097        })
9098    }
9099
9100    #[test]
9101    fn on_set_manager_event_emmission_success() {
9102        commit_test_ext().execute_with(|| {
9103            let entries = vec![
9104                (VALIDATOR_ALPHA, SHARE_EQUAL),
9105                (VALIDATOR_BETA, SHARE_EQUAL),
9106            ];
9107            System::set_block_number(BLOCK_EARLY);
9108            prepare_and_initiate_pool(
9109                ALICE,
9110                STAKING,
9111                &entries,
9112                INDEX_BALANCED_STAKING,
9113                POOL_MANAGED_STAKING,
9114                COMMISSION_LOW,
9115            )
9116            .unwrap();
9117            Pallet::set_pool_manager(&STAKING, &POOL_MANAGED_STAKING, &BOB).unwrap();
9118            System::assert_last_event(
9119                Event::PoolManager {
9120                    pool_of: POOL_MANAGED_STAKING,
9121                    reason: STAKING,
9122                    manager: BOB,
9123                }
9124                .into(),
9125            );
9126        })
9127    }
9128
9129    #[test]
9130    fn on_set_slot_shares_event_emmission_success() {
9131        commit_test_ext().execute_with(|| {
9132            let entries = vec![
9133                (VALIDATOR_ALPHA, SHARE_EQUAL),
9134                (VALIDATOR_BETA, SHARE_EQUAL),
9135            ];
9136            System::set_block_number(BLOCK_EARLY);
9137            prepare_and_initiate_pool(
9138                ALICE,
9139                STAKING,
9140                &entries,
9141                INDEX_BALANCED_STAKING,
9142                POOL_MANAGED_STAKING,
9143                COMMISSION_LOW,
9144            )
9145            .unwrap();
9146            Pallet::set_slot_shares(
9147                &ALICE,
9148                &STAKING,
9149                &POOL_MANAGED_STAKING,
9150                &VALIDATOR_ALPHA,
9151                SHARE_DOMINANT,
9152            )
9153            .unwrap();
9154            System::assert_last_event(
9155                Event::PoolSlot {
9156                    pool_of: POOL_MANAGED_STAKING,
9157                    reason: STAKING,
9158                    slot_of: VALIDATOR_ALPHA,
9159                    variant: Position::default(),
9160                    shares: SHARE_DOMINANT,
9161                }
9162                .into(),
9163            );
9164        })
9165    }
9166
9167    #[test]
9168    fn on_reap_pool_event_emmission_success() {
9169        commit_test_ext().execute_with(|| {
9170            let entries = vec![
9171                (VALIDATOR_ALPHA, SHARE_EQUAL),
9172                (VALIDATOR_BETA, SHARE_EQUAL),
9173            ];
9174            System::set_block_number(2);
9175            prepare_and_initiate_pool(
9176                ALICE,
9177                STAKING,
9178                &entries,
9179                INDEX_BALANCED_STAKING,
9180                POOL_MANAGED_STAKING,
9181                COMMISSION_LOW,
9182            )
9183            .unwrap();
9184            Pallet::reap_pool(&STAKING, &POOL_MANAGED_STAKING).unwrap();
9185            System::assert_last_event(
9186                Event::PoolReaped {
9187                    pool_of: POOL_MANAGED_STAKING,
9188                    reason: STAKING,
9189                }
9190                .into(),
9191            );
9192        })
9193    }
9194
9195    #[test]
9196    fn get_pool_value_success() {
9197        commit_test_ext().execute_with(|| {
9198            set_default_user_balance_and_standard_hold(ALICE).unwrap();
9199            set_default_user_balance_and_standard_hold(BOB).unwrap();
9200            set_default_user_balance_and_standard_hold(CHARLIE).unwrap();
9201            set_default_user_balance_and_standard_hold(ALAN).unwrap();
9202            Pallet::place_commit(
9203                &BOB,
9204                &STAKING,
9205                &VALIDATOR_ALPHA,
9206                STANDARD_COMMIT,
9207                &Directive::new(Precision::Exact, Fortitude::Force),
9208            )
9209            .unwrap();
9210            Pallet::place_commit(
9211                &ALAN,
9212                &STAKING,
9213                &VALIDATOR_BETA,
9214                STANDARD_COMMIT,
9215                &Directive::new(Precision::Exact, Fortitude::Force),
9216            )
9217            .unwrap();
9218            let entries = vec![
9219                (VALIDATOR_ALPHA, SHARE_DOMINANT),
9220                (VALIDATOR_BETA, SHARE_MAJOR),
9221            ];
9222            prepare_and_initiate_pool(
9223                MIKE,
9224                STAKING,
9225                &entries,
9226                INDEX_OPTIMIZED_STAKING,
9227                POOL_MANAGED_STAKING,
9228                COMMISSION_LOW,
9229            )
9230            .unwrap();
9231            Pallet::place_commit(
9232                &ALICE,
9233                &STAKING,
9234                &POOL_MANAGED_STAKING,
9235                LARGE_COMMIT,
9236                &Directive::new(Precision::BestEffort, Fortitude::Polite),
9237            )
9238            .unwrap();
9239            let actual_pool_value =
9240                Pallet::get_pool_value(&STAKING, &POOL_MANAGED_STAKING).unwrap();
9241            assert_eq!(actual_pool_value, LARGE_COMMIT);
9242        })
9243    }
9244
9245    #[test]
9246    fn get_pool_value_for_success() {
9247        commit_test_ext().execute_with(|| {
9248            set_default_user_balance_and_standard_hold(ALICE).unwrap();
9249            set_default_user_balance_and_standard_hold(BOB).unwrap();
9250            set_default_user_balance_and_standard_hold(CHARLIE).unwrap();
9251            set_default_user_balance_and_standard_hold(ALAN).unwrap();
9252            Pallet::place_commit(
9253                &BOB,
9254                &STAKING,
9255                &VALIDATOR_ALPHA,
9256                STANDARD_COMMIT,
9257                &Directive::new(Precision::Exact, Fortitude::Force),
9258            )
9259            .unwrap();
9260            Pallet::place_commit(
9261                &ALAN,
9262                &STAKING,
9263                &VALIDATOR_BETA,
9264                STANDARD_COMMIT,
9265                &Directive::new(Precision::Exact, Fortitude::Force),
9266            )
9267            .unwrap();
9268            let entries = vec![
9269                (VALIDATOR_ALPHA, SHARE_DOMINANT),
9270                (VALIDATOR_BETA, SHARE_MAJOR),
9271            ];
9272            prepare_and_initiate_pool(
9273                MIKE,
9274                STAKING,
9275                &entries,
9276                INDEX_OPTIMIZED_STAKING,
9277                POOL_MANAGED_STAKING,
9278                COMMISSION_LOW,
9279            )
9280            .unwrap();
9281            Pallet::place_commit(
9282                &ALICE,
9283                &STAKING,
9284                &POOL_MANAGED_STAKING,
9285                LARGE_COMMIT,
9286                &Directive::new(Precision::Exact, Fortitude::Force),
9287            )
9288            .unwrap();
9289            Pallet::place_commit(
9290                &CHARLIE,
9291                &STAKING,
9292                &POOL_MANAGED_STAKING,
9293                STANDARD_COMMIT,
9294                &Directive::new(Precision::Exact, Fortitude::Force),
9295            )
9296            .unwrap();
9297            // Alice pool value
9298            let alice_pool_value =
9299                Pallet::get_pool_value_for(&ALICE, &STAKING, &POOL_MANAGED_STAKING).unwrap();
9300            assert_eq!(alice_pool_value, LARGE_COMMIT);
9301
9302            // Charlie pool value
9303            let mike_pool_value =
9304                Pallet::get_pool_value_for(&CHARLIE, &STAKING, &POOL_MANAGED_STAKING).unwrap();
9305            assert_eq!(mike_pool_value, STANDARD_COMMIT);
9306        })
9307    }
9308
9309    #[test]
9310    fn get_slots_value_success() {
9311        commit_test_ext().execute_with(|| {
9312            set_default_user_balance_and_standard_hold(ALICE).unwrap();
9313            set_default_user_balance_and_standard_hold(BOB).unwrap();
9314            set_default_user_balance_and_standard_hold(CHARLIE).unwrap();
9315            set_default_user_balance_and_standard_hold(ALAN).unwrap();
9316            Pallet::place_commit(
9317                &BOB,
9318                &STAKING,
9319                &VALIDATOR_ALPHA,
9320                STANDARD_COMMIT,
9321                &Directive::new(Precision::Exact, Fortitude::Force),
9322            )
9323            .unwrap();
9324            Pallet::place_commit(
9325                &ALAN,
9326                &STAKING,
9327                &VALIDATOR_BETA,
9328                STANDARD_COMMIT,
9329                &Directive::new(Precision::Exact, Fortitude::Force),
9330            )
9331            .unwrap();
9332            let entries = vec![
9333                (VALIDATOR_ALPHA, SHARE_DOMINANT),
9334                (VALIDATOR_BETA, SHARE_MAJOR),
9335            ];
9336            prepare_and_initiate_pool(
9337                MIKE,
9338                STAKING,
9339                &entries,
9340                INDEX_OPTIMIZED_STAKING,
9341                POOL_MANAGED_STAKING,
9342                COMMISSION_LOW,
9343            )
9344            .unwrap();
9345            Pallet::place_commit(
9346                &ALICE,
9347                &STAKING,
9348                &POOL_MANAGED_STAKING,
9349                LARGE_COMMIT,
9350                &Directive::new(Precision::Exact, Fortitude::Force),
9351            )
9352            .unwrap();
9353            let actual_pool_slots_value =
9354                Pallet::get_slots_value(&STAKING, &POOL_MANAGED_STAKING).unwrap();
9355            let expected_pool_slots_value = vec![(VALIDATOR_ALPHA, 300), (VALIDATOR_BETA, 200)];
9356            assert_eq!(actual_pool_slots_value, expected_pool_slots_value);
9357        })
9358    }
9359
9360    #[test]
9361    fn get_slots_value_for_success() {
9362        commit_test_ext().execute_with(|| {
9363            set_default_user_balance_and_standard_hold(ALICE).unwrap();
9364            set_default_user_balance_and_standard_hold(BOB).unwrap();
9365            set_default_user_balance_and_standard_hold(CHARLIE).unwrap();
9366            set_default_user_balance_and_standard_hold(ALAN).unwrap();
9367            Pallet::place_commit(
9368                &BOB,
9369                &STAKING,
9370                &VALIDATOR_ALPHA,
9371                STANDARD_COMMIT,
9372                &Directive::new(Precision::Exact, Fortitude::Force),
9373            )
9374            .unwrap();
9375            Pallet::place_commit(
9376                &ALAN,
9377                &STAKING,
9378                &VALIDATOR_BETA,
9379                STANDARD_COMMIT,
9380                &Directive::new(Precision::Exact, Fortitude::Force),
9381            )
9382            .unwrap();
9383            let entries = vec![
9384                (VALIDATOR_ALPHA, SHARE_DOMINANT),
9385                (VALIDATOR_BETA, SHARE_MAJOR),
9386            ];
9387            prepare_and_initiate_pool(
9388                MIKE,
9389                STAKING,
9390                &entries,
9391                INDEX_OPTIMIZED_STAKING,
9392                POOL_MANAGED_STAKING,
9393                COMMISSION_LOW,
9394            )
9395            .unwrap();
9396            Pallet::place_commit(
9397                &ALICE,
9398                &STAKING,
9399                &POOL_MANAGED_STAKING,
9400                LARGE_COMMIT,
9401                &Directive::new(Precision::Exact, Fortitude::Force),
9402            )
9403            .unwrap();
9404            Pallet::place_commit(
9405                &CHARLIE,
9406                &STAKING,
9407                &POOL_MANAGED_STAKING,
9408                SMALL_COMMIT,
9409                &Directive::new(Precision::Exact, Fortitude::Force),
9410            )
9411            .unwrap();
9412            // Pool slots value for alice
9413            let alice_pool_slots_value =
9414                Pallet::get_slots_value_for(&ALICE, &STAKING, &POOL_MANAGED_STAKING).unwrap();
9415            let expected_alice_pool_slots_value =
9416                vec![(VALIDATOR_ALPHA, 300), (VALIDATOR_BETA, 200)];
9417            assert_eq!(expected_alice_pool_slots_value, alice_pool_slots_value);
9418            // Pool slots value for charlie
9419            let alan_pool_slots_value =
9420                Pallet::get_slots_value_for(&CHARLIE, &STAKING, &POOL_MANAGED_STAKING).unwrap();
9421            let expected_alan_pool_slots_value = vec![(VALIDATOR_ALPHA, 60), (VALIDATOR_BETA, 40)];
9422            assert_eq!(expected_alan_pool_slots_value, alan_pool_slots_value);
9423        })
9424    }
9425
9426    #[test]
9427    fn set_commission_success() {
9428        commit_test_ext().execute_with(|| {
9429            set_default_user_balance_and_standard_hold(ALICE).unwrap();
9430            set_default_user_balance_and_standard_hold(BOB).unwrap();
9431            set_default_user_balance_and_standard_hold(CHARLIE).unwrap();
9432            set_default_user_balance_and_standard_hold(ALAN).unwrap();
9433            Pallet::place_commit(
9434                &BOB,
9435                &STAKING,
9436                &VALIDATOR_ALPHA,
9437                STANDARD_COMMIT,
9438                &Directive::new(Precision::Exact, Fortitude::Force),
9439            )
9440            .unwrap();
9441            Pallet::place_commit(
9442                &ALAN,
9443                &STAKING,
9444                &VALIDATOR_BETA,
9445                STANDARD_COMMIT,
9446                &Directive::new(Precision::Exact, Fortitude::Force),
9447            )
9448            .unwrap();
9449
9450            let commission = COMMISSION_LOW;
9451            let entries = vec![
9452                (VALIDATOR_ALPHA, SHARE_DOMINANT),
9453                (VALIDATOR_BETA, SHARE_EQUAL),
9454            ];
9455            prepare_and_initiate_pool(
9456                MIKE,
9457                STAKING,
9458                &entries,
9459                INDEX_OPTIMIZED_STAKING,
9460                POOL_MANAGED_STAKING,
9461                commission,
9462            )
9463            .unwrap();
9464
9465            // Settign a new commission which generated a new pool digest
9466            let new_commission = COMMISSION_STANDARD;
9467            let new_pool_digest =
9468                Pallet::set_commission(&ALICE, &STAKING, &INDEX_OPTIMIZED_STAKING, new_commission)
9469                    .unwrap();
9470            // new pool created with updated commission
9471            assert_ok!(Pallet::pool_exists(&STAKING, &new_pool_digest));
9472            let actual_commission = Pallet::get_commission(&STAKING, &new_pool_digest).unwrap();
9473            assert_eq!(actual_commission, new_commission);
9474            // old pool commission left unaffected
9475            let old_pool_commission =
9476                Pallet::get_commission(&STAKING, &POOL_MANAGED_STAKING).unwrap();
9477            assert_eq!(old_pool_commission, commission);
9478        })
9479    }
9480
9481    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9482    // ````````````````````````````````` POOL VARIANT ````````````````````````````````
9483    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9484
9485    #[test]
9486    fn get_slot_variant_success() {
9487        commit_test_ext().execute_with(|| {
9488            set_default_user_balance_and_standard_hold(ALICE).unwrap();
9489            set_default_user_balance_and_standard_hold(BOB).unwrap();
9490            set_default_user_balance_and_standard_hold(CHARLIE).unwrap();
9491            set_default_user_balance_and_standard_hold(ALAN).unwrap();
9492            Pallet::place_commit(
9493                &BOB,
9494                &STAKING,
9495                &VALIDATOR_ALPHA,
9496                STANDARD_COMMIT,
9497                &Directive::new(Precision::Exact, Fortitude::Force),
9498            )
9499            .unwrap();
9500            Pallet::place_commit(
9501                &ALAN,
9502                &STAKING,
9503                &VALIDATOR_BETA,
9504                STANDARD_COMMIT,
9505                &Directive::new(Precision::Exact, Fortitude::Force),
9506            )
9507            .unwrap();
9508
9509            let commission = COMMISSION_LOW;
9510            let entries = vec![
9511                (VALIDATOR_ALPHA, SHARE_DOMINANT),
9512                (VALIDATOR_BETA, SHARE_EQUAL),
9513            ];
9514            prepare_and_initiate_pool(
9515                ALICE,
9516                STAKING,
9517                &entries,
9518                INDEX_OPTIMIZED_STAKING,
9519                POOL_MANAGED_STAKING,
9520                commission,
9521            )
9522            .unwrap();
9523
9524            let expected_slot_variant = Position::default();
9525            let actual_slot_variant =
9526                Pallet::get_slot_variant(&STAKING, &POOL_MANAGED_STAKING, &VALIDATOR_ALPHA)
9527                    .unwrap();
9528            assert_eq!(expected_slot_variant, actual_slot_variant);
9529            // Affirmative -> Contrary
9530            Pallet::set_slot_of_variant(
9531                &ALICE,
9532                &STAKING,
9533                &POOL_MANAGED_STAKING,
9534                &VALIDATOR_ALPHA,
9535                Position::position_of(1).unwrap(),
9536                None,
9537            )
9538            .unwrap();
9539            let expected_slot_variant = Position::position_of(1).unwrap();
9540            let actual_slot_variant =
9541                Pallet::get_slot_variant(&STAKING, &POOL_MANAGED_STAKING, &VALIDATOR_ALPHA)
9542                    .unwrap();
9543            assert_eq!(expected_slot_variant, actual_slot_variant);
9544        })
9545    }
9546
9547    #[test]
9548    fn get_slot_variant_err_slot_not_found() {
9549        commit_test_ext().execute_with(|| {
9550            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
9551            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
9552            let entries = vec![
9553                (VALIDATOR_ALPHA, SHARE_EQUAL),
9554                (VALIDATOR_BETA, SHARE_EQUAL),
9555            ];
9556            prepare_and_initiate_pool(
9557                MIKE,
9558                STAKING,
9559                &entries,
9560                INDEX_BALANCED_STAKING,
9561                POOL_MANAGED_STAKING,
9562                COMMISSION_LOW,
9563            )
9564            .unwrap();
9565            assert_err!(
9566                Pallet::get_slot_variant(&STAKING, &POOL_MANAGED_STAKING, &VALIDATOR_GAMMA,),
9567                Error::SlotOfPoolNotFound
9568            );
9569        })
9570    }
9571
9572    #[test]
9573    fn set_slot_of_variant_success_variant_update() {
9574        commit_test_ext().execute_with(|| {
9575            commit_test_ext().execute_with(|| {
9576                set_default_user_balance_and_standard_hold(ALICE).unwrap();
9577                set_default_user_balance_and_standard_hold(BOB).unwrap();
9578                Pallet::place_commit(
9579                    &ALICE,
9580                    &STAKING,
9581                    &VALIDATOR_ALPHA,
9582                    STANDARD_COMMIT,
9583                    &Directive::new(Precision::Exact, Fortitude::Force),
9584                )
9585                .unwrap();
9586                Pallet::place_commit(
9587                    &BOB,
9588                    &STAKING,
9589                    &VALIDATOR_BETA,
9590                    STANDARD_COMMIT,
9591                    &Directive::new(Precision::Exact, Fortitude::Force),
9592                )
9593                .unwrap();
9594
9595                let entries = vec![
9596                    (VALIDATOR_ALPHA, SHARE_EQUAL),
9597                    (VALIDATOR_BETA, SHARE_EQUAL),
9598                ];
9599                prepare_and_initiate_pool(
9600                    MIKE,
9601                    STAKING,
9602                    &entries,
9603                    INDEX_BALANCED_STAKING,
9604                    POOL_MANAGED_STAKING,
9605                    COMMISSION_LOW,
9606                )
9607                .unwrap();
9608                let expected_slot_variant = Position::default();
9609                let actual_slot_variant =
9610                    Pallet::get_slot_variant(&STAKING, &POOL_MANAGED_STAKING, &VALIDATOR_ALPHA)
9611                        .unwrap();
9612                assert_eq!(expected_slot_variant, actual_slot_variant);
9613                let new_slot_variant = Position::position_of(1).unwrap();
9614                Pallet::set_slot_of_variant(
9615                    &MIKE,
9616                    &STAKING,
9617                    &POOL_MANAGED_STAKING,
9618                    &VALIDATOR_ALPHA,
9619                    new_slot_variant,
9620                    None,
9621                )
9622                .unwrap();
9623
9624                let actual_slot_variant =
9625                    Pallet::get_slot_variant(&STAKING, &POOL_MANAGED_STAKING, &VALIDATOR_ALPHA)
9626                        .unwrap();
9627                assert_eq!(actual_slot_variant, new_slot_variant);
9628            })
9629        })
9630    }
9631
9632    #[test]
9633    fn set_slot_of_variant_success_variant_and_shares_update() {
9634        commit_test_ext().execute_with(|| {
9635            commit_test_ext().execute_with(|| {
9636                set_default_user_balance_and_standard_hold(ALICE).unwrap();
9637                set_default_user_balance_and_standard_hold(BOB).unwrap();
9638                Pallet::place_commit(
9639                    &ALICE,
9640                    &STAKING,
9641                    &VALIDATOR_ALPHA,
9642                    STANDARD_COMMIT,
9643                    &Directive::new(Precision::Exact, Fortitude::Force),
9644                )
9645                .unwrap();
9646                Pallet::place_commit(
9647                    &BOB,
9648                    &STAKING,
9649                    &VALIDATOR_BETA,
9650                    STANDARD_COMMIT,
9651                    &Directive::new(Precision::Exact, Fortitude::Force),
9652                )
9653                .unwrap();
9654
9655                let entries = vec![
9656                    (VALIDATOR_ALPHA, SHARE_EQUAL),
9657                    (VALIDATOR_BETA, SHARE_EQUAL),
9658                ];
9659                prepare_and_initiate_pool(
9660                    MIKE,
9661                    STAKING,
9662                    &entries,
9663                    INDEX_BALANCED_STAKING,
9664                    POOL_MANAGED_STAKING,
9665                    COMMISSION_LOW,
9666                )
9667                .unwrap();
9668                let expected_slot_variant = Position::default();
9669                let actual_slot_variant =
9670                    Pallet::get_slot_variant(&STAKING, &POOL_MANAGED_STAKING, &VALIDATOR_ALPHA)
9671                        .unwrap();
9672                let actual_slot_shares =
9673                    Pallet::get_slots_shares(&STAKING, &POOL_MANAGED_STAKING).unwrap();
9674                let expected_slot_shares = entries;
9675                assert_eq!(expected_slot_variant, actual_slot_variant);
9676                assert_eq!(expected_slot_shares, actual_slot_shares);
9677                let new_slot_variant = Position::position_of(2).unwrap();
9678                Pallet::set_slot_of_variant(
9679                    &ALICE,
9680                    &STAKING,
9681                    &POOL_MANAGED_STAKING,
9682                    &VALIDATOR_ALPHA,
9683                    new_slot_variant,
9684                    Some(SHARE_DOMINANT),
9685                )
9686                .unwrap();
9687                let actual_slot_variant =
9688                    Pallet::get_slot_variant(&STAKING, &POOL_MANAGED_STAKING, &VALIDATOR_ALPHA)
9689                        .unwrap();
9690                let actual_slot_shares =
9691                    Pallet::get_slots_shares(&STAKING, &POOL_MANAGED_STAKING).unwrap();
9692                let expected_slot_shares = vec![
9693                    (VALIDATOR_BETA, SHARE_EQUAL),
9694                    (VALIDATOR_ALPHA, SHARE_DOMINANT),
9695                ];
9696                assert_eq!(actual_slot_variant, new_slot_variant);
9697                assert_eq!(actual_slot_shares, expected_slot_shares);
9698            })
9699        })
9700    }
9701
9702    #[test]
9703    fn set_slot_of_variant_new_slot_shares_cannot_be_none() {
9704        commit_test_ext().execute_with(|| {
9705            commit_test_ext().execute_with(|| {
9706                set_default_user_balance_and_standard_hold(ALICE).unwrap();
9707                set_default_user_balance_and_standard_hold(BOB).unwrap();
9708                set_default_user_balance_and_standard_hold(CHARLIE).unwrap();
9709                Pallet::place_commit(
9710                    &ALICE,
9711                    &STAKING,
9712                    &VALIDATOR_ALPHA,
9713                    STANDARD_COMMIT,
9714                    &Directive::new(Precision::Exact, Fortitude::Force),
9715                )
9716                .unwrap();
9717                Pallet::place_commit(
9718                    &BOB,
9719                    &STAKING,
9720                    &VALIDATOR_BETA,
9721                    STANDARD_COMMIT,
9722                    &Directive::new(Precision::Exact, Fortitude::Force),
9723                )
9724                .unwrap();
9725                let entries = vec![
9726                    (VALIDATOR_ALPHA, SHARE_EQUAL),
9727                    (VALIDATOR_BETA, SHARE_EQUAL),
9728                ];
9729                prepare_and_initiate_pool(
9730                    MIKE,
9731                    STAKING,
9732                    &entries,
9733                    INDEX_BALANCED_STAKING,
9734                    POOL_MANAGED_STAKING,
9735                    COMMISSION_LOW,
9736                )
9737                .unwrap();
9738                let expected_slot_variant = Position::default();
9739                let actual_slot_variant =
9740                    Pallet::get_slot_variant(&STAKING, &POOL_MANAGED_STAKING, &VALIDATOR_ALPHA)
9741                        .unwrap();
9742                let actual_slot_shares =
9743                    Pallet::get_slots_shares(&STAKING, &POOL_MANAGED_STAKING).unwrap();
9744                let expected_slot_shares = vec![
9745                    (VALIDATOR_ALPHA, SHARE_EQUAL),
9746                    (VALIDATOR_BETA, SHARE_EQUAL),
9747                ];
9748                assert_eq!(expected_slot_variant, actual_slot_variant);
9749                assert_eq!(expected_slot_shares, actual_slot_shares);
9750                Pallet::place_commit(
9751                    &CHARLIE,
9752                    &STAKING,
9753                    &VALIDATOR_GAMMA,
9754                    STANDARD_COMMIT,
9755                    &Directive::new(Precision::Exact, Fortitude::Force),
9756                )
9757                .unwrap();
9758                // Adding a new slot digest while shares is set to None returns Error
9759                assert_err!(
9760                    Pallet::set_slot_of_variant(
9761                        &ALICE,
9762                        &STAKING,
9763                        &POOL_MANAGED_STAKING,
9764                        &VALIDATOR_GAMMA,
9765                        Position::position_of(1).unwrap(),
9766                        None,
9767                    ),
9768                    Error::SlotOfPoolNotFound
9769                );
9770                // Nothing changes due to invalid shares
9771                let actual_slot_variant =
9772                    Pallet::get_slot_variant(&STAKING, &POOL_MANAGED_STAKING, &VALIDATOR_ALPHA)
9773                        .unwrap();
9774                let actual_slot_shares =
9775                    Pallet::get_slots_shares(&STAKING, &POOL_MANAGED_STAKING).unwrap();
9776                assert_eq!(actual_slot_variant, expected_slot_variant);
9777                assert_eq!(actual_slot_shares, expected_slot_shares);
9778            })
9779        })
9780    }
9781
9782    #[test]
9783    fn set_slot_of_variant_new_slot_digest() {
9784        commit_test_ext().execute_with(|| {
9785            commit_test_ext().execute_with(|| {
9786                set_default_user_balance_and_standard_hold(ALICE).unwrap();
9787                set_default_user_balance_and_standard_hold(BOB).unwrap();
9788                Pallet::place_commit(
9789                    &ALICE,
9790                    &STAKING,
9791                    &VALIDATOR_ALPHA,
9792                    STANDARD_COMMIT,
9793                    &Directive::new(Precision::Exact, Fortitude::Force),
9794                )
9795                .unwrap();
9796                Pallet::place_commit(
9797                    &BOB,
9798                    &STAKING,
9799                    &VALIDATOR_BETA,
9800                    STANDARD_COMMIT,
9801                    &Directive::new(Precision::Exact, Fortitude::Force),
9802                )
9803                .unwrap();
9804                let entries = vec![
9805                    (VALIDATOR_ALPHA, SHARE_EQUAL),
9806                    (VALIDATOR_BETA, SHARE_EQUAL),
9807                ];
9808                prepare_and_initiate_pool(
9809                    MIKE,
9810                    STAKING,
9811                    &entries,
9812                    INDEX_BALANCED_STAKING,
9813                    POOL_MANAGED_STAKING,
9814                    COMMISSION_LOW,
9815                )
9816                .unwrap();
9817                initiate_digest_with_default_balance(STAKING,VALIDATOR_GAMMA).unwrap();
9818                Pallet::set_slot_of_variant(
9819                    &ALICE,
9820                    &STAKING,
9821                    &POOL_MANAGED_STAKING,
9822                    &VALIDATOR_GAMMA,
9823                    Position::position_of(1).unwrap(),
9824                    Some(SHARE_EQUAL),
9825                )
9826                .unwrap();
9827
9828                assert_eq!(
9829                    Pallet::get_slot_variant(&STAKING, &POOL_MANAGED_STAKING, &VALIDATOR_GAMMA,)
9830                        .unwrap(),
9831                    Position::position_of(1).unwrap(),
9832                );
9833                // Without shares returns error to set a new-variant for a new-digest
9834                assert_err!(
9835                    Pallet::set_slot_of_variant(
9836                        &ALICE,
9837                        &STAKING,
9838                        &POOL_MANAGED_STAKING,
9839                        &VALIDATOR_DELTA,
9840                        Position::position_of(1).unwrap(),
9841                        None,
9842                    ),
9843                    Error::SlotOfPoolNotFound
9844                );
9845                assert_err!(
9846                    Pallet::get_slot_variant(&STAKING, &POOL_MANAGED_STAKING, &VALIDATOR_DELTA,),
9847                    Error::SlotOfPoolNotFound
9848                );
9849                // Since its semantically no-op if its zero shares hence its silently passes
9850                assert_ok!(Pallet::set_slot_of_variant(
9851                    &ALICE,
9852                    &STAKING,
9853                    &POOL_MANAGED_STAKING,
9854                    &VALIDATOR_DELTA,
9855                    Position::position_of(1).unwrap(),
9856                    Some(0),
9857                ));
9858            })
9859        })
9860    }
9861
9862    #[test]
9863    fn set_slot_of_variant_err_slot_digest_not_initiated() {
9864        commit_test_ext().execute_with(|| {
9865            initiate_digest_with_default_balance(STAKING, VALIDATOR_ALPHA).unwrap();
9866            initiate_digest_with_default_balance(STAKING, VALIDATOR_BETA).unwrap();
9867
9868            let entries = vec![
9869                (VALIDATOR_ALPHA, SHARE_EQUAL),
9870                (VALIDATOR_BETA, SHARE_EQUAL),
9871            ];
9872            prepare_and_initiate_pool(
9873                MIKE,
9874                STAKING,
9875                &entries,
9876                INDEX_BALANCED_STAKING,
9877                POOL_MANAGED_STAKING,
9878                COMMISSION_LOW,
9879            )
9880            .unwrap();
9881            // tryign to add uninitiated digest returns error
9882            assert_err!(Pallet::set_slot_of_variant(
9883                &ALICE,
9884                &STAKING,
9885                &POOL_MANAGED_STAKING,
9886                &VALIDATOR_GAMMA,
9887                Position::position_of(1).unwrap(),
9888                Some(SHARE_EQUAL),
9889            ), Error::SlotDigestNotInitiated);
9890        })
9891    }
9892
9893    #[test]
9894    fn on_set_slot_of_variant() {
9895        commit_test_ext().execute_with(|| {
9896            set_default_user_balance_and_standard_hold(ALICE).unwrap();
9897            Pallet::place_commit(
9898                &ALICE,
9899                &STAKING,
9900                &VALIDATOR_ALPHA,
9901                STANDARD_COMMIT,
9902                &Directive::new(Precision::Exact, Fortitude::Force),
9903            )
9904            .unwrap();
9905            let entries = vec![(VALIDATOR_ALPHA, SHARE_EQUAL)];
9906            prepare_and_initiate_pool(
9907                ALICE,
9908                STAKING,
9909                &entries,
9910                INDEX_BALANCED_STAKING,
9911                POOL_MANAGED_STAKING,
9912                COMMISSION_LOW,
9913            )
9914            .unwrap();
9915            System::set_block_number(2);
9916            let new_shares = SHARE_DOMINANT;
9917            let new_variant = Position::position_of(1).unwrap();
9918            Pallet::on_set_slot_of_variant(
9919                &POOL_MANAGED_STAKING,
9920                &STAKING,
9921                &VALIDATOR_ALPHA,
9922                Some(new_shares),
9923                &new_variant,
9924            );
9925            System::assert_last_event(
9926                Event::PoolSlot {
9927                    pool_of: POOL_MANAGED_STAKING,
9928                    reason: STAKING,
9929                    slot_of: VALIDATOR_ALPHA,
9930                    variant: new_variant,
9931                    shares: new_shares,
9932                }
9933                .into(),
9934            );
9935        })
9936    }
9937
9938    #[test]
9939    fn on_set_slot_of_variant_shares_is_zero() {
9940        commit_test_ext().execute_with(|| {
9941            set_default_user_balance_and_standard_hold(ALICE).unwrap();
9942            Pallet::place_commit(
9943                &ALICE,
9944                &STAKING,
9945                &VALIDATOR_ALPHA,
9946                STANDARD_COMMIT,
9947                &Directive::new(Precision::Exact, Fortitude::Force),
9948            )
9949            .unwrap();
9950            let entries = vec![(VALIDATOR_ALPHA, SHARE_EQUAL)];
9951            prepare_and_initiate_pool(
9952                ALICE,
9953                STAKING,
9954                &entries,
9955                INDEX_BALANCED_STAKING,
9956                POOL_MANAGED_STAKING,
9957                COMMISSION_LOW,
9958            )
9959            .unwrap();
9960            System::set_block_number(2);
9961            let new_shares = 0;
9962            let new_variant = Position::position_of(1).unwrap();
9963            Pallet::on_set_slot_of_variant(
9964                &POOL_MANAGED_STAKING,
9965                &STAKING,
9966                &VALIDATOR_ALPHA,
9967                Some(new_shares),
9968                &new_variant,
9969            );
9970            System::assert_last_event(
9971                Event::PoolSlotRemoved {
9972                    pool_of: POOL_MANAGED_STAKING,
9973                    reason: STAKING,
9974                    slot_of: VALIDATOR_ALPHA,
9975                    variant: new_variant,
9976                }
9977                .into(),
9978            );
9979        })
9980    }
9981}