1use core::cmp::Ordering;
38
39use crate::{
41 types::{Accumulator, IdXp, Stepper, Xp, XpId},
42 Config, Error, Event, InitXp, LockedXpOf, MinPulse, MinTimeStamp, Pallet, PulseFactor,
43 ReapedXp, ReservedXpOf, XpOf, XpOwners,
44};
45
46use frame_suite::{
48 accumulators::DiscreteAccumulator,
49 keys::{KeyGenFor, KeySeedFor},
50 xp::{
51 XpError, XpErrorHandler, XpLock, XpLockListener, XpMutate, XpMutateListener, XpOwner,
52 XpOwnerListener, XpReap, XpReapListener, XpReserve, XpReserveListener, XpSystem,
53 },
54};
55
56use frame_support::{dispatch::DispatchResult, ensure, traits::VariantCountOf};
58
59use frame_system::pallet_prelude::BlockNumberFor;
61
62use sp_core::Get;
64use sp_runtime::{
65 traits::{CheckedAdd, CheckedMul, CheckedSub, One, Zero},
66 BoundedVec, DispatchError, Saturating, Vec,
67};
68
69impl<T: Config<I>, I: 'static> XpSystem for Pallet<T, I> {
79 type Xp = Xp<T, I>;
85
86 type Points = T::Xp;
88
89 type XpKey = XpId<T>;
93
94 type TimeStamp = BlockNumberFor<T>;
96
97 type Extension = T::Extensions;
99
100 fn xp_exists(key: &Self::XpKey) -> DispatchResult {
109 ensure!(XpOf::<T, I>::contains_key(key), Error::<T, I>::XpNotFound);
110 Ok(())
111 }
112
113 fn get_xp(key: &Self::XpKey) -> Result<Self::Xp, DispatchError> {
123 let Some(xp) = XpOf::<T, I>::get(key) else {
124 return Err(Error::<T, I>::XpNotFound.into());
125 };
126 Ok(xp)
127 }
128
129 fn has_minimum_xp(key: &Self::XpKey) -> DispatchResult {
139 let xp = Self::get_xp(key)?;
140 ensure!(
143 xp.timestamp >= MinTimeStamp::<T, I>::get(),
144 Error::<T, I>::LowTimeStamp
145 );
146 Ok(())
147 }
148
149 fn get_liquid_xp(key: &Self::XpKey) -> Result<Self::Points, DispatchError> {
158 let xp = Self::get_xp(key)?;
159 Ok(xp.free)
160 }
161
162 fn get_usable_xp(key: &Self::XpKey) -> Result<Self::Points, DispatchError> {
172 let xp = Self::get_xp(key)?;
173 Ok(xp.free.saturating_add(xp.reserve))
174 }
175}
176
177impl<T: Config<I>, I: 'static> XpOwner for Pallet<T, I> {
189 type Owner = T::AccountId;
191
192 fn is_owner(owner: &Self::Owner, key: &Self::XpKey) -> DispatchResult {
201 ensure!(
202 XpOwners::<T, I>::contains_key((owner, key)),
203 Error::<T, I>::InvalidXpOwner
204 );
205 Ok(())
206 }
207
208 fn xp_of_owner(owner: &Self::Owner) -> Result<Vec<Self::XpKey>, DispatchError> {
214 let mut vec = Vec::new();
215 let iter = XpOwners::<T, I>::iter_prefix((owner,));
217 for (key, _) in iter {
218 vec.push(key)
219 }
220 Ok(vec)
221 }
222
223 fn set_owner(
236 owner: &Self::Owner,
237 key: &Self::XpKey,
238 new_owner: &Self::Owner,
239 ) -> DispatchResult {
240 XpOwners::<T, I>::remove((owner, key));
241 XpOwners::<T, I>::insert((new_owner, key), ());
242 Ok(())
243 }
244 fn xp_key_gen(owner: &Self::Owner, xp: &Self::Xp) -> Result<Self::XpKey, DispatchError> {
254 let target: &Self::XpKey = owner;
255 let salt = frame_system::Pallet::<T>::account_nonce(owner);
256 let Some(key) =
257 KeySeedFor::<Self::XpKey, Self::Xp, T::Nonce, T::Hashing, T>::gen_key(target, xp, salt)
258 else {
259 return Err(Error::<T, I>::CannotGenerateXpKey.into());
260 };
261 Ok(key)
262 }
263
264 fn on_xp_transfer(key: &Self::XpKey, new_owner: &Self::Owner) {
268 if T::EmitEvents::get() {
269 Self::deposit_event(Event::XpOwner {
270 id: key.clone(),
271 owner: new_owner.clone(),
272 });
273 }
274 Self::Extension::xp_transferred(key, new_owner)
275 }
276}
277
278impl<T: Config<I>, I: 'static> XpMutate for Pallet<T, I> {
286 fn init_xp() -> Self::Points {
291 InitXp::<T, I>::get()
292 }
293
294 fn new_xp(owner: &Self::Owner, key: &Self::XpKey) {
301 let xp = Xp::<T, I>::default();
302 XpOf::<T, I>::insert(key, xp);
303 XpOwners::<T, I>::insert((&owner, &key), ());
304 }
305
306 fn set_xp(key: &Self::XpKey, points: Self::Points) -> DispatchResult {
320 XpOf::<T, I>::mutate(key, |result| -> DispatchResult {
321 let value = result.as_mut().ok_or(Error::<T, I>::XpNotFound)?;
322 value.free = points;
323 Ok(())
324 })?;
325 Ok(())
326 }
327
328 fn earn_xp(key: &Self::XpKey, points: Self::Points) -> Result<Self::Points, DispatchError> {
372 let mut actual = Self::Points::zero();
374
375 XpOf::<T, I>::mutate(key, |result| -> DispatchResult {
376 let value = result.as_mut().ok_or(Error::<T, I>::XpNotFound)?;
378
379 let current_block_height = <frame_system::Pallet<T>>::block_number();
381
382 if current_block_height <= value.timestamp
392 && value.pulse.value >= MinPulse::<T, I>::get()
393 {
394 let old_points = value.free;
395
396 let new_points = old_points
397 .checked_add(&points)
398 .ok_or(Error::<T, I>::XpCapOverflowed)?;
399
400 actual = new_points.saturating_sub(old_points);
402 value.free = new_points;
403
404 return Ok(());
405 }
406
407 value.timestamp = current_block_height;
409
410 if value.pulse.value < MinPulse::<T, I>::get() {
417 <Pallet<T, I> as DiscreteAccumulator>::increment(
418 &mut value.pulse,
419 &PulseFactor::<T, I>::get(),
420 );
421 return Ok(());
422 }
423
424 let multiplied = points
430 .checked_mul(&value.pulse.value.into())
431 .ok_or(Error::<T, I>::ReputationDeriveOverflowed)?;
432
433 let new_points = multiplied
434 .checked_add(&value.free)
435 .ok_or(Error::<T, I>::XpCapOverflowed)?;
436
437 let old_points = value.free;
438
439 actual = new_points
441 .checked_sub(&old_points)
442 .ok_or(Error::<T, I>::XpComputationError)?;
443
444 value.free = new_points;
445
446 if <Self as XpLock>::has_lock(key).is_ok() {
455 <Pallet<T, I> as DiscreteAccumulator>::increment(
456 &mut value.pulse,
457 &PulseFactor::<T, I>::get(),
458 );
459 }
460
461 Ok(())
462 })?;
463 Self::on_xp_earn(key, actual);
464
465 Ok(actual)
466 }
467
468 fn quote_earn_xp(
477 key: &Self::XpKey,
478 points: Self::Points,
479 ) -> Result<Self::Points, DispatchError> {
480 let value = XpOf::<T, I>::get(key).ok_or(Error::<T, I>::XpNotFound)?;
481
482 let current_block_height = <frame_system::Pallet<T>>::block_number();
483
484 if current_block_height <= value.timestamp && value.pulse.value >= MinPulse::<T, I>::get() {
486 return Ok(points);
487 }
488
489 if value.pulse.value < MinPulse::<T, I>::get() {
491 return Ok(Self::Points::zero());
492 }
493
494 let multiplied = points
496 .checked_mul(&value.pulse.value.into())
497 .ok_or(Error::<T, I>::ReputationDeriveOverflowed)?;
498
499 Ok(multiplied)
500 }
501
502 fn on_xp_update(key: &Self::XpKey, points: Self::Points) {
509 if T::EmitEvents::get() {
510 Self::deposit_event(Event::Xp {
511 id: key.clone(),
512 xp: points,
513 });
514 }
515 Self::Extension::xp_updated(key, points)
516 }
517
518 fn on_xp_earn(key: &Self::XpKey, points: Self::Points) {
524 if T::EmitEvents::get() {
525 Self::deposit_event(Event::XpEarn {
526 id: key.clone(),
527 xp: points,
528 });
529 }
530 Self::Extension::xp_earned(key, points);
531 }
532
533 fn on_xp_create(key: &Self::XpKey, owner: &Self::Owner) {
539 if T::EmitEvents::get() {
540 Self::deposit_event(Event::XpOwner {
541 id: key.clone(),
542 owner: owner.clone(),
543 });
544 }
545 T::Extensions::xp_created(key, owner);
546 }
547
548 fn on_xp_slash(key: &Self::XpKey, slashed_points: Self::Points) {
554 if T::EmitEvents::get() {
555 Self::deposit_event(Event::XpSlash {
556 id: key.clone(),
557 xp: slashed_points,
558 });
559 }
560 T::Extensions::xp_slashed(key, slashed_points);
561 }
562}
563
564impl<T: Config<I>, I: 'static> XpReserve for Pallet<T, I> {
575 type Reserve = IdXp<T::ReserveReason, T::Xp>;
577
578 type ReserveReason = T::ReserveReason;
580
581 fn reserve_exists(key: &Self::XpKey, reason: &Self::ReserveReason) -> DispatchResult {
587 let Some(reserves) = ReservedXpOf::<T, I>::get(key) else {
588 return Err(Error::<T, I>::XpReserveNotFound.into());
589 };
590 if !(reserves.iter().any(|reserve| reserve.id == *reason)) {
591 return Err(Error::<T, I>::XpReserveNotFound.into());
592 }
593 Ok(())
594 }
595
596 fn get_reserve_xp(
605 key: &Self::XpKey,
606 reason: &Self::ReserveReason,
607 ) -> Result<Self::Points, DispatchError> {
608 let Some(reserves) = ReservedXpOf::<T, I>::get(key) else {
609 return Err(Error::<T, I>::XpReserveNotFound.into());
610 };
611 let Some(reserve) = reserves.iter().find(|reserve| reserve.id == *reason) else {
612 return Err(Error::<T, I>::XpReserveNotFound.into());
613 };
614 Ok(reserve.points)
615 }
616
617 fn total_reserved(key: &Self::XpKey) -> Result<Self::Points, DispatchError> {
626 let Some(xp) = XpOf::<T, I>::get(key) else {
627 return Err(Error::<T, I>::XpNotFound.into());
628 };
629 Ok(xp.reserve)
630 }
631
632 fn has_reserve(key: &Self::XpKey) -> DispatchResult {
641 let Some(reserve) = ReservedXpOf::<T, I>::get(key) else {
642 return Err(Error::<T, I>::XpReserveNotFound.into());
643 };
644 if reserve.is_empty() {
645 return Err(Error::<T, I>::XpReserveNotFound.into());
646 }
647 Ok(())
648 }
649
650 fn get_all_reserves(key: &Self::XpKey) -> Result<Vec<Self::ReserveReason>, DispatchError> {
659 let all_reserves = ReservedXpOf::<T, I>::get(key)
660 .map(|reserves| reserves.iter().map(|reserve| reserve.id).collect())
661 .unwrap_or_default();
662 Ok(all_reserves)
663 }
664
665 fn set_reserve(
679 key: &Self::XpKey,
680 reason: &Self::ReserveReason,
681 points: Self::Points,
682 ) -> DispatchResult {
683 if Self::reserve_exists(key, reason).is_err() {
685 Self::can_reserve_new(key, points)?;
687 let reserve = Self::Reserve::new(*reason, points);
688
689 ReservedXpOf::<T, I>::mutate(key, |result| -> DispatchResult {
690 let value = result.get_or_insert_with(|| {
691 BoundedVec::<Self::Reserve, VariantCountOf<Self::ReserveReason>>::default()
692 });
693 let result = value.try_push(reserve);
694
695 debug_assert!(
696 result.is_ok(),
697 "reserves vector already bounded by reason, hence
698 additional reserves cannot be attempted itself, inconsistency detected
699 at set new reserve of points {points:?} for xp-key {key:?} for reason {reason:?}"
700 );
701
702 result.map_err(|_| Error::<T, I>::TooManyReserves)?;
703
704 Ok(())
705 })?;
706
707 XpOf::<T, I>::mutate(key, |result| -> DispatchResult {
708 let value = result.as_mut();
709 debug_assert!(
710 value.is_some(),
711 "xp-key {key:?} reserve of reason {reason:?} newly created but Xp
712 Meta not available to update high-level storage"
713 );
714 let value = value.ok_or(Error::<T, I>::XpNotFound)?;
715 value.reserve = value
716 .reserve
717 .checked_add(&points)
718 .ok_or(Error::<T, I>::XpReserveCapOverflowed)?;
719
720 Ok(())
721 })?;
722 return Ok(());
723 }
724
725 Self::can_reserve_mutate(key, reason, points)?;
728 ReservedXpOf::<T, I>::mutate(key, |result| -> DispatchResult {
729 let value = result.as_mut();
730 debug_assert!(
731 value.is_some(),
732 "can mutate reserve of xp-key {key:?} for reason {reason:?} but
733 cannot access the specific reserve-meta"
734 );
735 let value = value.ok_or(Error::<T, I>::XpReserveNotFound)?;
736 let reserve = value
737 .iter_mut()
738 .find(|reserve| reserve.id == *reason)
739 .ok_or(Error::<T, I>::XpReserveNotFound)?;
740 let current_reserved = reserve.points;
741 reserve.points = points;
742
743 XpOf::<T, I>::mutate(key, |result| -> DispatchResult {
744 let value = result.as_mut();
745 debug_assert!(
746 value.is_some(),
747 "xp-key {key:?} reserve of reason {reason:?} recently mutated, but now Xp-meta
748 not available to mutate"
749 );
750 let value = value.ok_or(Error::<T, I>::XpNotFound)?;
751
752 let total_reserved = value.reserve;
753
754 match current_reserved.cmp(&points) {
755 Ordering::Greater => {
756 let decrease = current_reserved.saturating_sub(points);
757 value.reserve = total_reserved.saturating_sub(decrease);
758 }
759 Ordering::Less => {
760 let increase = points.saturating_sub(current_reserved);
761 value.reserve = total_reserved.saturating_add(increase);
762 }
763 Ordering::Equal => return Ok(()),
764 }
765 Ok(())
766 })?;
767 Ok(())
768 })?;
769 Ok(())
770 }
771
772 fn on_reserve_update(
778 key: &Self::XpKey,
779 reason: &Self::ReserveReason,
780 reserve_points: Self::Points,
781 ) {
782 if T::EmitEvents::get() {
783 Self::deposit_event(Event::XpReserve {
784 of: key.clone(),
785 reason: *reason,
786 xp: reserve_points,
787 });
788 }
789 Self::Extension::reserve_updated(key, reason, reserve_points);
790 }
791
792 fn on_reserve_slash(
798 key: &Self::XpKey,
799 reason: &Self::ReserveReason,
800 slashed_points: Self::Points,
801 ) {
802 if T::EmitEvents::get() {
803 Self::deposit_event(Event::XpReserveSlash {
804 of: key.clone(),
805 reason: *reason,
806 xp: slashed_points,
807 });
808 }
809 T::Extensions::reserve_slashed(key, reason, slashed_points);
810 }
811}
812
813impl<T: Config<I>, I: 'static> XpLock for Pallet<T, I> {
823 type Lock = IdXp<T::LockReason, T::Xp>;
825
826 type LockReason = T::LockReason;
828
829 fn has_lock(key: &Self::XpKey) -> DispatchResult {
838 let Some(locks) = LockedXpOf::<T, I>::get(key) else {
839 return Err(Error::<T, I>::XpLockNotFound.into());
840 };
841 if locks.len().is_zero() {
842 return Err(Error::<T, I>::XpLockNotFound.into());
843 }
844 Ok(())
845 }
846
847 fn lock_exists(key: &Self::XpKey, reason: &Self::LockReason) -> DispatchResult {
853 let Some(locks) = LockedXpOf::<T, I>::get(key) else {
854 return Err(Error::<T, I>::XpLockNotFound.into());
855 };
856 if !(locks.iter().any(|lock| lock.id == *reason)) {
857 return Err(Error::<T, I>::XpLockNotFound.into());
858 }
859 Ok(())
860 }
861
862 fn get_lock_xp(
871 key: &Self::XpKey,
872 reason: &Self::LockReason,
873 ) -> Result<Self::Points, DispatchError> {
874 let Some(locks) = LockedXpOf::<T, I>::get(key) else {
875 return Err(Error::<T, I>::XpLockNotFound.into());
876 };
877 let Some(lock) = locks.iter().find(|lock| lock.id == *reason) else {
878 return Err(Error::<T, I>::XpLockNotFound.into());
879 };
880 Ok(lock.points)
881 }
882
883 fn total_locked(key: &Self::XpKey) -> Result<Self::Points, DispatchError> {
892 let Some(xp) = XpOf::<T, I>::get(key) else {
893 return Err(Error::<T, I>::XpNotFound.into());
894 };
895 Ok(xp.lock)
896 }
897
898 fn get_all_locks(key: &Self::XpKey) -> Result<Vec<Self::LockReason>, DispatchError> {
907 let all_locks = LockedXpOf::<T, I>::get(key)
908 .map(|locks| locks.iter().map(|lock| lock.id).collect())
909 .unwrap_or_default();
910 Ok(all_locks)
911 }
912
913 fn burn_lock(key: &Self::XpKey, reason: &Self::LockReason) -> DispatchResult {
923 let locked = Self::get_lock_xp(key, reason)?;
924 LockedXpOf::<T, I>::mutate(key, |result| -> DispatchResult {
925 let value = result.as_mut().ok_or(Error::<T, I>::XpLockNotFound)?;
926 value.retain(|lock| lock.id != *reason);
927 Ok(())
928 })?;
929
930 XpOf::<T, I>::mutate(key, |result| -> DispatchResult {
931 let value = result.as_mut();
932
933 debug_assert!(
934 value.is_some(),
935 "xp-key {key:?} lock of reason {reason:?} exists where as Xp Meta doesn't"
936 );
937
938 let value = value.ok_or(Error::<T, I>::XpNotFound)?;
939
940 let total_locked = value.lock;
941 if total_locked < locked {
949 debug_assert!(
950 false,
951 "xp-key {key:?} lock of reason {reason:?} value {locked:?} is greater than xp's total lock value {total_locked:?}"
952 );
953 value.lock = Self::Points::zero();
957 return Ok(());
958 }
959 value.lock = total_locked.saturating_sub(locked);
960 Ok(())
961 })?;
962 Ok(())
963 }
964
965 fn set_lock(
979 key: &Self::XpKey,
980 reason: &Self::LockReason,
981 points: Self::Points,
982 ) -> DispatchResult {
983 if Self::lock_exists(key, reason).is_err() {
985 Self::can_lock_new(key, points)?;
987 let lock = Self::Lock::new(*reason, points);
988
989 LockedXpOf::<T, I>::mutate(key, |result| -> DispatchResult {
990 let value = result.get_or_insert_with(|| {
991 BoundedVec::<Self::Lock, VariantCountOf<T::LockReason>>::default()
992 });
993 let result = value.try_push(lock);
994
995 debug_assert!(
996 result.is_ok(),
997 "locks vector already bounded by reason, hence additional locks cannot be attempted itself,
998 inconsistency detected at set new lock of points {points:?} for xp-key {key:?} for reason {reason:?}"
999 );
1000
1001 result.map_err(|_| Error::<T, I>::TooManyLocks)?;
1002
1003 Ok(())
1004 })?;
1005
1006 XpOf::<T, I>::mutate(key, |result| -> DispatchResult {
1007 let value = result.as_mut();
1008 debug_assert!(
1009 value.is_some(),
1010 "xp-key {key:?} lock of reason {reason:?} newly created but Xp
1011 Meta not available to update high-level storage"
1012 );
1013 let value = value.ok_or(Error::<T, I>::XpNotFound)?;
1014 value.lock = value.lock.saturating_add(points);
1021
1022 Ok(())
1023 })?;
1024 return Ok(());
1025 }
1026
1027 Self::can_lock_mutate(key, reason, points)?;
1030 LockedXpOf::<T, I>::mutate(key, |result| -> DispatchResult {
1031 let value = result.as_mut();
1032 debug_assert!(
1033 value.is_some(),
1034 "can mutate lock of xp-key {key:?} for reason {reason:?} but
1035 cannot access the specific lock-meta",
1036 );
1037 let value = value.ok_or(Error::<T, I>::XpLockNotFound)?;
1038 let slice = &mut value[..];
1040 let lock = slice
1041 .iter_mut()
1042 .find(|lock| lock.id == *reason)
1043 .ok_or(Error::<T, I>::XpLockNotFound)?;
1044 let current_locked = lock.points;
1045 lock.points = points;
1046
1047 XpOf::<T, I>::mutate(key, |result| -> DispatchResult {
1048 let value = result.as_mut();
1049 debug_assert!(
1050 value.is_some(),
1051 "xp-key {key:?} lock of reason {reason:?} recently mutated, but now Xp-meta
1052 not available to mutate"
1053 );
1054 let value = value.ok_or(Error::<T, I>::XpNotFound)?;
1055
1056 let total_locked = value.lock;
1057 match current_locked.cmp(&points) {
1058 Ordering::Greater => {
1059 let decrease = current_locked.saturating_sub(points);
1060 value.lock = total_locked.saturating_sub(decrease);
1061 }
1062 Ordering::Less => {
1063 let increase = points.saturating_sub(current_locked);
1064 value.lock = total_locked.saturating_add(increase);
1065 }
1066 Ordering::Equal => return Ok(()),
1067 }
1068 Ok(())
1069 })?;
1070 Ok(())
1071 })?;
1072 Ok(())
1073 }
1074
1075 fn on_lock_update(key: &Self::XpKey, reason: &Self::LockReason, lock_points: Self::Points) {
1081 if T::EmitEvents::get() {
1082 Self::deposit_event(Event::XpLock {
1083 of: key.clone(),
1084 reason: *reason,
1085 xp: lock_points,
1086 });
1087 }
1088 Self::Extension::lock_updated(key, reason, lock_points);
1089 }
1090
1091 fn on_lock_burn(key: &Self::XpKey, reason: &Self::LockReason) {
1097 if T::EmitEvents::get() {
1098 Self::deposit_event(Event::XpLockBurn {
1099 of: key.clone(),
1100 reason: *reason,
1101 });
1102 }
1103 Self::Extension::lock_burned(key, reason);
1104 }
1105
1106 fn on_lock_slash(key: &Self::XpKey, reason: &Self::LockReason, slashed_points: Self::Points) {
1112 if T::EmitEvents::get() {
1113 Self::deposit_event(Event::XpLockSlash {
1114 of: key.clone(),
1115 reason: *reason,
1116 xp: slashed_points,
1117 });
1118 }
1119 T::Extensions::lock_slashed(key, reason, slashed_points);
1120 }
1121}
1122impl<T: Config<I>, I: 'static> XpReap for Pallet<T, I> {
1133 fn reap_xp(key: &Self::XpKey) -> Result<Self::Points, DispatchError> {
1150 let reapable = <Self as XpSystem>::get_usable_xp(key)?;
1152 if <Self as XpLock>::has_lock(key).is_ok() {
1155 return Err(Error::<T, I>::XpLockExists.into());
1156 }
1157 XpOf::<T, I>::remove(key);
1158 ReservedXpOf::<T, I>::remove(key);
1159 ReapedXp::<T, I>::insert(key, ());
1160 Ok(reapable)
1161 }
1162
1163 fn is_reaped(key: &Self::XpKey) -> DispatchResult {
1171 if !ReapedXp::<T, I>::contains_key(key) {
1172 return Err(Error::<T, I>::XpNotReaped.into());
1173 }
1174 Ok(())
1175 }
1176
1177 fn on_xp_reap(key: &Self::XpKey) {
1183 if T::EmitEvents::get() {
1184 Self::deposit_event(Event::XpReap { id: key.clone() });
1185 }
1186 Self::Extension::xp_reaped(key);
1187 }
1188}
1189
1190impl<T: Config<I>, I: 'static> DiscreteAccumulator for Pallet<T, I> {
1203 type Value = T::Pulse;
1205
1206 type Step = T::Pulse;
1208
1209 type Accumulator = Accumulator<T, I>;
1211
1212 type Stepper = Stepper<T, I>;
1214
1215 fn increment(accum: &mut Self::Accumulator, stepper: &Self::Stepper) {
1220 accum.step = accum.step.saturating_add(stepper.per_count);
1221 while accum.step >= stepper.threshold {
1222 accum.value = accum.value.saturating_add(One::one());
1223 accum.step = accum.step.saturating_sub(stepper.threshold);
1224 }
1225 }
1226
1227 fn decrement(accum: &mut Self::Accumulator, stepper: &Self::Stepper) {
1234 if accum.step >= stepper.per_count {
1235 accum.step = accum.step.saturating_sub(stepper.per_count);
1236 return;
1237 }
1238 let sub_pos = stepper.per_count.saturating_sub(accum.step);
1239 let deficit = stepper.threshold.saturating_sub(sub_pos);
1240 if accum.value.is_zero() {
1241 accum.step = Zero::zero();
1242 return;
1243 }
1244 accum.value = accum.value.saturating_sub(One::one());
1245 accum.step = deficit;
1246 }
1247
1248 fn reveal(accum: &Self::Accumulator) -> Self::Value {
1252 accum.value
1253 }
1254}
1255
1256impl<T: Config<I>, I: 'static> XpErrorHandler for Pallet<T, I> {
1261 type Error = Error<T, I>;
1262
1263 fn from_xp_error(e: XpError) -> Self::Error {
1264 match e {
1265 XpError::XpNotFound => Error::<T, I>::XpNotFound,
1266 XpError::XpReserveNotFound => Error::<T, I>::XpReserveNotFound,
1267 XpError::XpLockNotFound => Error::<T, I>::XpLockNotFound,
1268 XpError::InsufficientLiquidXp => Error::<T, I>::InsufficientLiquidXp,
1269 XpError::TooManyReserves => Error::<T, I>::TooManyReserves,
1270 XpError::TooManyLocks => Error::<T, I>::TooManyLocks,
1271 XpError::CannotLockZero => Error::<T, I>::CannotLockZero,
1272 XpError::CannotReserveZero => Error::<T, I>::CannotReserveZero,
1273 XpError::XpAlreadyReaped => Error::<T, I>::XpAlreadyReaped,
1274 XpError::XpNotDead => Error::<T, I>::XpNotDead,
1275 XpError::CannotReapLockedXp => Error::<T, I>::CannotReapLockedXp,
1276 XpError::InsufficientReserveXp => Error::<T, I>::InsufficientReserveXp,
1277 XpError::XpCapOverflowed => Error::<T, I>::XpCapOverflowed,
1278 XpError::XpCapUnderflowed => Error::<T, I>::XpCapUnderflowed,
1279 XpError::XpReserveCapOverflowed => Error::<T, I>::XpReserveCapOverflowed,
1280 XpError::XpReserveCapUnderflowed => Error::<T, I>::XpReserveCapUnderflowed,
1281 XpError::XpLockCapOverflowed => Error::<T, I>::XpLockCapOverflowed,
1282 XpError::XpLockCapUnderflowed => Error::<T, I>::XpLockCapUnderflowed,
1283 }
1284 }
1285}
1286
1287#[cfg(test)]
1292mod tests {
1294
1295 use crate::{mock::*, types::ForceGenesisConfig};
1301
1302 use frame_suite::{accumulators::*, xp::*};
1304
1305 use frame_support::{
1307 assert_err, assert_ok,
1308 traits::{tokens::Precision, VariantCount, VariantCountOf},
1309 };
1310 use sp_runtime::BoundedVec;
1311
1312 #[test]
1317 fn xp_exists_success() {
1318 xp_test_ext().execute_with(|| {
1319 Pallet::new_xp(&ALICE, &XP_ALPHA);
1320 assert_ok!(Pallet::xp_exists(&XP_ALPHA));
1321 });
1322 }
1323
1324 #[test]
1325 fn xp_exists_fail_no_xp() {
1326 xp_test_ext().execute_with(|| {
1327 assert!(!XpOf::contains_key(XP_ALPHA));
1328 });
1329 }
1330
1331 #[test]
1332 fn has_minimum_xp_success() {
1333 xp_test_ext().execute_with(|| {
1334 System::set_block_number(1);
1335 System::set_block_number(2);
1336 System::set_block_number(3);
1337 Pallet::new_xp(&ALICE, &XP_ALPHA);
1338 assert_ok!(Pallet::has_minimum_xp(&XP_ALPHA));
1339 });
1340 }
1341
1342 #[test]
1343 fn has_minimum_xp_fail_low_min_time_stamp() {
1344 xp_test_ext().execute_with(|| {
1345 MinTimeStamp::set(2);
1346 Pallet::new_xp(&ALICE, &XP_ALPHA);
1347 System::set_block_number(1);
1348 assert_err!(Pallet::has_minimum_xp(&XP_ALPHA), Error::LowTimeStamp);
1349 });
1350 }
1351
1352 #[test]
1353 fn get_xp_success() {
1354 xp_test_ext().execute_with(|| {
1355 System::set_block_number(1);
1356 assert_err!(Pallet::get_xp(&XP_ALPHA), Error::XpNotFound);
1357 System::set_block_number(2);
1358 Pallet::new_xp(&ALICE, &XP_ALPHA);
1359 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
1360 assert_eq!(xp.free, InitXp::get());
1361 assert_eq!(xp.pulse.value, 0);
1362 assert_eq!(xp.reserve, 0);
1363 assert_eq!(xp.lock, 0);
1364 assert_eq!(xp.timestamp, 2);
1365 });
1366 }
1367
1368 #[test]
1369 fn get_liquid_xp_success() {
1370 xp_test_ext().execute_with(|| {
1371 Pallet::new_xp(&ALICE, &XP_ALPHA);
1372 let liquid = Pallet::get_liquid_xp(&XP_ALPHA).unwrap();
1373 assert_eq!(liquid, InitXp::get());
1374 });
1375 }
1376
1377 #[test]
1378 fn get_liquid_xp_fail_uninitialized_xp() {
1379 xp_test_ext().execute_with(|| {
1380 assert_err!(Pallet::get_liquid_xp(&XP_ALPHA), Error::XpNotFound);
1381 });
1382 }
1383
1384 #[test]
1385 fn get_usable_xp_success() {
1386 xp_test_ext().execute_with(|| {
1387 Pallet::new_xp(&ALICE, &XP_ALPHA);
1388 let idxp = ReserveId::new(STAKING, DEFAULT_POINTS);
1389 ReservedXpOf::mutate(XP_ALPHA, |result| {
1390 let value = result.get_or_insert_with(|| {
1391 BoundedVec::<ReserveId, VariantCountOf<Reason>>::default()
1392 });
1393 value.try_push(idxp).unwrap();
1394 });
1395 XpOf::mutate(XP_ALPHA, |result| {
1396 let value = result.as_mut().unwrap();
1397 value.reserve = value.reserve.saturating_add(DEFAULT_POINTS);
1398 });
1399 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
1401 let expected = xp.free.saturating_add(xp.reserve);
1402 let actual = Pallet::get_usable_xp(&XP_ALPHA).unwrap();
1403 assert_eq!(expected, actual);
1404 });
1405 }
1406
1407 #[test]
1408 fn get_usable_xp_fail_uninitialized_xp() {
1409 xp_test_ext().execute_with(|| {
1410 assert_err!(Pallet::get_usable_xp(&XP_ALPHA), Error::XpNotFound);
1411 });
1412 }
1413
1414 #[test]
1419 fn is_owner_success() {
1420 xp_test_ext().execute_with(|| {
1421 Pallet::new_xp(&ALICE, &XP_ALPHA);
1422 assert_ok!(Pallet::is_owner(&ALICE, &XP_ALPHA));
1423 });
1424 }
1425
1426 #[test]
1427 fn is_owner_fail_not_owner() {
1428 xp_test_ext().execute_with(|| {
1429 Pallet::new_xp(&ALICE, &XP_ALPHA);
1430 assert_err!(Pallet::is_owner(&BOB, &XP_ALPHA), Error::InvalidXpOwner);
1431 });
1432 }
1433
1434 #[test]
1435 fn xp_of_owner_success() {
1436 xp_test_ext().execute_with(|| {
1437 Pallet::new_xp(&ALICE, &XP_ALPHA);
1438 Pallet::new_xp(&ALICE, &XP_BETA);
1439 Pallet::new_xp(&ALICE, &XP_GAMMA);
1440 let actual = Pallet::xp_of_owner(&ALICE).unwrap();
1441 let expected = vec![XP_GAMMA, XP_ALPHA, XP_BETA];
1442 assert_eq!(actual, expected);
1443 });
1444 }
1445
1446 #[test]
1447 fn transfer_owner_success() {
1448 xp_test_ext().execute_with(|| {
1449 Pallet::new_xp(&ALICE, &XP_ALPHA);
1450 System::set_block_number(1);
1451 Pallet::transfer_owner(&ALICE, &XP_ALPHA, &BOB).unwrap();
1452 assert_err!(Pallet::is_owner(&ALICE, &XP_ALPHA), Error::InvalidXpOwner);
1453 assert_ok!(Pallet::is_owner(&BOB, &XP_ALPHA));
1454 });
1455 }
1456
1457 #[test]
1458 fn xp_key_gen_success() {
1459 xp_test_ext().execute_with(|| {
1460 Pallet::new_xp(&ALICE, &XP_ALPHA);
1461 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
1462 Account::mutate(ALICE, |info| {
1463 info.nonce = 5;
1464 });
1465 let actual_gen_key = Pallet::xp_key_gen(&ALICE, &xp);
1466 assert!(actual_gen_key.is_ok());
1467 let actual_gen_key = actual_gen_key.unwrap();
1468 let expected_gen_key = 4150176476612258495;
1469 assert_eq!(actual_gen_key, expected_gen_key);
1470 });
1471 }
1472
1473 #[test]
1474 fn xp_key_gen_deterministic_check() {
1475 xp_test_ext().execute_with(|| {
1476 Pallet::new_xp(&ALICE, &XP_ALPHA);
1477 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
1478 Account::mutate(ALICE, |info| {
1479 info.nonce = 3;
1480 });
1481 let gen_key_first = Pallet::xp_key_gen(&ALICE, &xp).unwrap();
1482 let gen_key_second = Pallet::xp_key_gen(&ALICE, &xp).unwrap();
1483
1484 assert_eq!(gen_key_first, gen_key_second);
1485 });
1486 }
1487
1488 #[test]
1489 fn xp_key_gen_collision_check() {
1490 xp_test_ext().execute_with(|| {
1491 System::set_block_number(2);
1492 Pallet::new_xp(&ALICE, &XP_ALPHA);
1493 let xp_alpha = Pallet::get_xp(&XP_ALPHA).unwrap();
1494 Account::mutate(ALICE, |info| {
1495 info.nonce = 3;
1496 });
1497 let gen_key_alpha = Pallet::xp_key_gen(&ALICE, &xp_alpha).unwrap();
1498
1499 System::set_block_number(4);
1500 Pallet::new_xp(&BOB, &XP_BETA);
1501 let xp_beta = Pallet::get_xp(&XP_BETA).unwrap();
1502 Account::mutate(BOB, |info| {
1503 info.nonce = 1;
1504 });
1505 let gen_key_beta = Pallet::xp_key_gen(&ALICE, &xp_beta).unwrap();
1506 assert_ne!(xp_alpha, xp_beta);
1507 assert_ne!(System::account_nonce(ALICE), System::account_nonce(BOB));
1508 assert_ne!(gen_key_alpha, gen_key_beta);
1509 });
1510 }
1511
1512 #[test]
1513 fn xp_key_gen_unique_across_owners() {
1514 xp_test_ext().execute_with(|| {
1515 Pallet::new_xp(&ALICE, &XP_ALPHA);
1516 Pallet::new_xp(&BOB, &XP_BETA);
1517 let xp_alpha = Pallet::get_xp(&XP_ALPHA).unwrap();
1518 let xp_beta = Pallet::get_xp(&XP_BETA).unwrap();
1519 Account::mutate(ALICE, |info| {
1520 info.nonce = 3;
1521 });
1522 Account::mutate(BOB, |info| {
1523 info.nonce = 3;
1524 });
1525 assert_eq!(xp_alpha, xp_beta);
1526 assert_eq!(System::account_nonce(ALICE), System::account_nonce(BOB));
1527 let gen_key_alice = Pallet::xp_key_gen(&ALICE, &xp_alpha).unwrap();
1528 let gen_key_bob = Pallet::xp_key_gen(&BOB, &xp_beta).unwrap();
1529 assert_ne!(gen_key_alice, gen_key_bob);
1530 });
1531 }
1532
1533 #[test]
1534 fn xp_key_gen_unique_across_xp_struct() {
1535 xp_test_ext().execute_with(|| {
1536 System::set_block_number(2);
1537 Pallet::new_xp(&ALICE, &XP_ALPHA);
1538 let xp_1 = Pallet::get_xp(&XP_ALPHA).unwrap();
1539 Account::mutate(ALICE, |info| {
1540 info.nonce = 3;
1541 });
1542 System::set_block_number(4);
1543 Pallet::new_xp(&ALICE, &XP_ALPHA);
1544 let xp_2 = Pallet::get_xp(&XP_ALPHA).unwrap();
1545 Account::mutate(ALICE, |info| {
1546 info.nonce = 3;
1547 });
1548 assert_ne!(xp_1, xp_2);
1549 assert_eq!(System::account_nonce(ALICE), 3);
1550 let gen_key_alice_1 = Pallet::xp_key_gen(&ALICE, &xp_1).unwrap();
1551 let gen_key_alice_2 = Pallet::xp_key_gen(&ALICE, &xp_2).unwrap();
1552 assert_ne!(gen_key_alice_1, gen_key_alice_2);
1553 });
1554 }
1555
1556 #[test]
1557 fn xp_key_gen_unique_across_nonce() {
1558 xp_test_ext().execute_with(|| {
1559 Pallet::new_xp(&ALICE, &XP_ALPHA);
1560 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
1561 System::set_block_number(2);
1562 Account::mutate(ALICE, |info| {
1563 info.nonce = 3;
1564 });
1565 let gen_key_alice_1 = Pallet::xp_key_gen(&ALICE, &xp).unwrap();
1566
1567 System::set_block_number(4);
1568 Account::mutate(ALICE, |info| {
1569 info.nonce = 5;
1570 });
1571 let gen_key_alice_2 = Pallet::xp_key_gen(&ALICE, &xp).unwrap();
1572
1573 assert_ne!(gen_key_alice_1, gen_key_alice_2);
1574 });
1575 }
1576
1577 #[test]
1578 fn on_xp_transfer_success() {
1579 xp_test_ext().execute_with(|| {
1580 System::set_block_number(1);
1581 Pallet::on_xp_transfer(&XP_ALPHA, &BOB);
1582 System::assert_last_event(
1583 Event::XpOwner {
1584 id: XP_ALPHA,
1585 owner: BOB,
1586 }
1587 .into(),
1588 );
1589 })
1590 }
1591
1592 #[test]
1597 fn new_xp_success() {
1598 xp_test_ext().execute_with(|| {
1599 assert!(!XpOf::contains_key(XP_ALPHA));
1600 System::set_block_number(2);
1601 Pallet::new_xp(&ALICE, &XP_ALPHA);
1602 assert!(XpOf::contains_key(XP_ALPHA));
1603 let xp = XpOf::get(XP_ALPHA).unwrap();
1604 assert_eq!(xp.free, 10);
1605 assert_eq!(xp.pulse.value, 0);
1606 assert_eq!(xp.reserve, 0);
1607 assert_eq!(xp.lock, 0);
1608 assert_eq!(xp.timestamp, 2);
1609 assert_eq!(XpOwners::get((ALICE, XP_ALPHA)), Some(()));
1610 });
1611 }
1612
1613 #[test]
1614 fn earn_xp_success() {
1615 xp_test_ext().execute_with(|| {
1616 Pallet::new_xp(&ALICE, &XP_ALPHA);
1618 let xp = XpOf::get(XP_ALPHA).unwrap();
1619 let liquid_xp = xp.free;
1620 let pulse_xp = xp.pulse.value;
1621 assert_eq!(liquid_xp, 10);
1622 assert_eq!(pulse_xp, 0); System::set_block_number(2);
1624 Pallet::earn_xp(&XP_ALPHA, DEFAULT_POINTS).unwrap(); System::set_block_number(3);
1626 Pallet::earn_xp(&XP_ALPHA, DEFAULT_POINTS).unwrap(); System::set_block_number(4);
1628 Pallet::earn_xp(&XP_ALPHA, DEFAULT_POINTS).unwrap(); System::set_block_number(5);
1630 Pallet::earn_xp(&XP_ALPHA, DEFAULT_POINTS).unwrap(); System::set_block_number(6);
1632 Pallet::earn_xp(&XP_ALPHA, DEFAULT_POINTS).unwrap(); let xp = XpOf::get(XP_ALPHA).unwrap();
1634 let liquid_xp = xp.free;
1635 let pulse_xp = xp.pulse.value;
1636 assert_eq!(liquid_xp, 10);
1637 assert_eq!(pulse_xp, 1); System::set_block_number(7);
1639 Pallet::earn_xp(&XP_ALPHA, DEFAULT_POINTS).unwrap();
1640 let xp = XpOf::get(XP_ALPHA).unwrap();
1641 let liquid_xp_bfr = xp.free;
1642 let pulse_xp = xp.pulse.value;
1643 assert_eq!(liquid_xp_bfr, 20);
1644 assert_eq!(pulse_xp, 1);
1645 System::set_block_number(7);
1646 Pallet::earn_xp(&XP_ALPHA, DEFAULT_POINTS).unwrap();
1647 let xp = XpOf::get(XP_ALPHA).unwrap();
1648 let liquid_xp_aftr = xp.free;
1649 let pulse_xp = xp.pulse.value;
1650 assert_eq!(liquid_xp_aftr, 30);
1651 assert_eq!(pulse_xp, 1);
1652 let actual = liquid_xp_aftr - liquid_xp_bfr;
1653 assert_eq!(actual, 10);
1654 System::assert_last_event(Event::XpEarn {
1655 id: XP_ALPHA,
1656 xp: actual
1657 }
1658 .into()
1659 );
1660 });
1661 }
1662
1663 #[test]
1664 fn earn_xp_fail_uninitialized_xp() {
1665 xp_test_ext().execute_with(|| {
1666 assert_err!(
1667 Pallet::earn_xp(&XP_ALPHA, DEFAULT_POINTS),
1668 Error::XpNotFound
1669 )
1670 });
1671 }
1672
1673 #[test]
1674 fn earn_xp_success_with_lock() {
1675 xp_test_ext().execute_with(|| {
1676 Pallet::new_xp(&ALICE, &XP_ALPHA);
1677 let xp = XpOf::get(XP_ALPHA).unwrap();
1678 let liquid_xp = xp.free;
1679 let pulse_xp = xp.pulse.value;
1680 assert_eq!(liquid_xp, 10);
1681 assert_eq!(pulse_xp, 0); System::set_block_number(2);
1683 Pallet::earn_xp(&XP_ALPHA, DEFAULT_POINTS).unwrap(); System::set_block_number(3);
1685 Pallet::earn_xp(&XP_ALPHA, DEFAULT_POINTS).unwrap(); System::set_block_number(4);
1687 Pallet::earn_xp(&XP_ALPHA, DEFAULT_POINTS).unwrap(); System::set_block_number(5);
1689 Pallet::earn_xp(&XP_ALPHA, DEFAULT_POINTS).unwrap(); System::set_block_number(6);
1691 Pallet::earn_xp(&XP_ALPHA, DEFAULT_POINTS).unwrap(); let xp = XpOf::get(XP_ALPHA).unwrap();
1693 let liquid_xp = xp.free;
1694 let pulse_xp = xp.pulse.value;
1695 assert_eq!(liquid_xp, 10);
1696 assert_eq!(pulse_xp, 1); System::set_block_number(7);
1698 Pallet::earn_xp(&XP_ALPHA, DEFAULT_POINTS).unwrap();
1699 let xp = XpOf::get(XP_ALPHA).unwrap();
1700 let liquid_xp = xp.free;
1701 let pulse_xp = xp.pulse.value;
1702 assert_eq!(liquid_xp, 20);
1703 assert_eq!(pulse_xp, 1);
1704 System::set_block_number(8);
1705 let idxp = LockId::new(STAKING, DEFAULT_POINTS);
1706 LockedXpOf::mutate(XP_ALPHA, |result| {
1707 let value = result
1708 .get_or_insert_with(|| BoundedVec::<LockId, VariantCountOf<Reason>>::default());
1709 value.try_push(idxp).unwrap();
1710 });
1711 XpOf::mutate(XP_ALPHA, |result| {
1712 let value = result.as_mut().unwrap();
1713 value.lock = value.lock.saturating_add(DEFAULT_POINTS);
1714 });
1715 assert!(LockedXpOf::contains_key(XP_ALPHA));
1716 System::set_block_number(9);
1717 Pallet::earn_xp(&XP_ALPHA, DEFAULT_POINTS).unwrap(); System::set_block_number(10);
1719 Pallet::earn_xp(&XP_ALPHA, DEFAULT_POINTS).unwrap(); System::set_block_number(11);
1721 Pallet::earn_xp(&XP_ALPHA, DEFAULT_POINTS).unwrap(); System::set_block_number(12);
1723 Pallet::earn_xp(&XP_ALPHA, DEFAULT_POINTS).unwrap(); System::set_block_number(13);
1725 Pallet::earn_xp(&XP_ALPHA, DEFAULT_POINTS).unwrap(); let xp = XpOf::get(XP_ALPHA).unwrap();
1727 let liquid_xp = xp.free;
1728 let pulse_xp = xp.pulse.value;
1729 assert_eq!(liquid_xp, 70);
1730 assert_eq!(pulse_xp, 2); System::set_block_number(14);
1732 Pallet::earn_xp(&XP_ALPHA, DEFAULT_POINTS).unwrap();
1733 let xp = XpOf::get(XP_ALPHA).unwrap();
1734 let liquid_xp = xp.free;
1735 let pulse_xp = xp.pulse.value;
1736 assert_eq!(liquid_xp, 90);
1737 assert_eq!(pulse_xp, 2);
1738 });
1739 }
1740
1741 #[test]
1742 fn set_xp_success() {
1743 xp_test_ext().execute_with(|| {
1744 Pallet::new_xp(&ALICE, &XP_ALPHA);
1745 System::set_block_number(2);
1746 let xp = XpOf::get(XP_ALPHA).unwrap();
1747 let liquid_before = xp.free;
1748 assert_eq!(liquid_before, InitXp::get());
1749 System::set_block_number(3);
1750 Pallet::set_xp(&XP_ALPHA, DEFAULT_POINTS).unwrap();
1751 let xp = XpOf::get(XP_ALPHA).unwrap();
1752 let liquid_after = xp.free;
1753 assert_eq!(liquid_after, DEFAULT_POINTS);
1754 });
1755 }
1756
1757 #[test]
1758 fn set_xp_fail_uninitialized_xp() {
1759 xp_test_ext().execute_with(|| {
1760 assert_err!(Pallet::set_xp(&XP_ALPHA, DEFAULT_POINTS), Error::XpNotFound);
1761 });
1762 }
1763
1764 #[test]
1765 fn on_xp_earn_success() {
1766 xp_test_ext().execute_with(|| {
1767 System::set_block_number(2);
1768 Pallet::on_xp_earn(&XP_ALPHA, DEFAULT_POINTS);
1769 System::assert_last_event(
1770 Event::XpEarn {
1771 id: XP_ALPHA,
1772 xp: DEFAULT_POINTS,
1773 }
1774 .into(),
1775 );
1776 });
1777 }
1778
1779 #[test]
1780 fn on_xp_update_success() {
1781 xp_test_ext().execute_with(|| {
1782 System::set_block_number(2);
1783 Pallet::on_xp_update(&XP_ALPHA, DEFAULT_POINTS);
1784 System::assert_last_event(
1785 Event::Xp {
1786 id: XP_ALPHA,
1787 xp: DEFAULT_POINTS,
1788 }
1789 .into(),
1790 );
1791 });
1792 }
1793
1794 #[test]
1795 fn slash_xp_success() {
1796 xp_test_ext().execute_with(|| {
1797 Pallet::new_xp(&ALICE, &XP_ALPHA);
1798 let xp = XpOf::get(XP_ALPHA).unwrap();
1799 let liquid_before = xp.free;
1800 System::set_block_number(2);
1801 let slash_points = 5;
1802 assert_ok!(Pallet::slash_xp(&XP_ALPHA, slash_points));
1803 let xp = XpOf::get(XP_ALPHA).unwrap();
1804 let liquid_after = xp.free;
1805 let liquid_expected = liquid_before.saturating_sub(slash_points);
1806
1807 assert_eq!(liquid_after, liquid_expected);
1808 System::assert_last_event(
1809 Event::XpSlash {
1810 id: XP_ALPHA,
1811 xp: liquid_after,
1812 }
1813 .into(),
1814 );
1815 });
1816 }
1817
1818 #[test]
1819 fn slash_xp_success_burn() {
1820 xp_test_ext().execute_with(|| {
1821 Pallet::new_xp(&ALICE, &XP_ALPHA);
1822 let xp = XpOf::get(XP_ALPHA).unwrap();
1823 let liquid_before = xp.free;
1824 assert_eq!(liquid_before, 10);
1825 System::set_block_number(2);
1826 let slash_points = 20;
1828 assert_ok!(Pallet::slash_xp(&XP_ALPHA, slash_points));
1829 let xp = XpOf::get(XP_ALPHA).unwrap();
1830 let liquid_after = xp.free;
1831 let liquid_expected = 0;
1832
1833 assert_eq!(liquid_after, liquid_expected);
1834 });
1835 }
1836
1837 #[test]
1838 fn slash_xp_fail_uninitialized_xp() {
1839 xp_test_ext().execute_with(|| {
1840 assert_err!(
1841 Pallet::slash_xp(&XP_ALPHA, DEFAULT_POINTS),
1842 Error::XpNotFound
1843 );
1844 });
1845 }
1846
1847 #[test]
1848 fn reset_xp_success() {
1849 xp_test_ext().execute_with(|| {
1850 Pallet::new_xp(&ALICE, &XP_ALPHA);
1851 let xp = XpOf::get(XP_ALPHA).unwrap();
1852 let liquid_before = xp.free;
1853 let burn_points = Pallet::reset_xp(&XP_ALPHA).unwrap();
1854 let xp = XpOf::get(XP_ALPHA).unwrap();
1855 let liquid_after = xp.free;
1856 assert_eq!(liquid_before, burn_points);
1857 assert_eq!(liquid_after, 0);
1858 });
1859 }
1860
1861 #[test]
1862 fn reset_xp_fail_uninitialized_xp() {
1863 xp_test_ext().execute_with(|| {
1864 assert_err!(Pallet::reset_xp(&XP_ALPHA), Error::XpNotFound);
1865 });
1866 }
1867
1868 #[test]
1873 fn reserve_exists_success() {
1874 xp_test_ext().execute_with(|| {
1875 Pallet::new_xp(&ALICE, &XP_ALPHA);
1876 let idxp = ReserveId::new(STAKING, DEFAULT_POINTS);
1877 ReservedXpOf::mutate(XP_ALPHA, |result| {
1878 let value = result.get_or_insert_with(|| {
1879 BoundedVec::<ReserveId, VariantCountOf<Reason>>::default()
1880 });
1881 value.try_push(idxp).unwrap();
1882 });
1883 XpOf::mutate(XP_ALPHA, |result| {
1884 let value = result.as_mut().unwrap();
1885 value.reserve = value.reserve.saturating_add(DEFAULT_POINTS);
1886 });
1887 assert_ok!(Pallet::reserve_exists(&XP_ALPHA, &STAKING));
1888 });
1889 }
1890
1891 #[test]
1892 fn reserve_exists_fail() {
1893 xp_test_ext().execute_with(|| {
1894 Pallet::new_xp(&ALICE, &XP_ALPHA);
1895 assert_err!(
1896 Pallet::reserve_exists(&XP_ALPHA, &STAKING),
1897 Error::XpReserveNotFound
1898 );
1899 });
1900 }
1901
1902 #[test]
1903 fn has_reserve_success() {
1904 xp_test_ext().execute_with(|| {
1905 Pallet::new_xp(&ALICE, &XP_ALPHA);
1906 let idxp = ReserveId::new(STAKING, DEFAULT_POINTS);
1907 ReservedXpOf::mutate(XP_ALPHA, |result| {
1908 let value = result.get_or_insert_with(|| {
1909 BoundedVec::<ReserveId, VariantCountOf<Reason>>::default()
1910 });
1911 value.try_push(idxp).unwrap();
1912 });
1913 XpOf::mutate(XP_ALPHA, |result| {
1914 let value = result.as_mut().unwrap();
1915 value.reserve = value.reserve.saturating_add(DEFAULT_POINTS);
1916 });
1917 assert_ok!(Pallet::has_reserve(&XP_ALPHA));
1918 });
1919 }
1920
1921 #[test]
1922 fn has_reserve_fail_no_reserve() {
1923 xp_test_ext().execute_with(|| {
1924 Pallet::new_xp(&ALICE, &XP_ALPHA);
1925 assert_err!(Pallet::has_reserve(&XP_ALPHA), Error::XpReserveNotFound);
1926 });
1927 }
1928
1929 #[test]
1930 fn has_reserve_fail_uninitialized_key() {
1931 xp_test_ext().execute_with(|| {
1932 assert_err!(Pallet::has_reserve(&XP_ALPHA), Error::XpReserveNotFound);
1933 });
1934 }
1935
1936 #[test]
1937 fn maximum_reserves_success() {
1938 xp_test_ext().execute_with(|| {
1939 Pallet::new_xp(&ALICE, &XP_ALPHA);
1940 let max_reserves = Pallet::maximum_reserves();
1941 let expected = Reason::VARIANT_COUNT as usize;
1942 assert_eq!(max_reserves, expected);
1943 });
1944 }
1945
1946 #[test]
1947 fn get_reserve_xp_success() {
1948 xp_test_ext().execute_with(|| {
1949 Pallet::new_xp(&ALICE, &XP_ALPHA);
1950 let idxp = ReserveId::new(STAKING, DEFAULT_POINTS);
1951 ReservedXpOf::mutate(XP_ALPHA, |result| {
1952 let value = result.get_or_insert_with(|| {
1953 BoundedVec::<ReserveId, VariantCountOf<Reason>>::default()
1954 });
1955 value.try_push(idxp).unwrap();
1956 });
1957 XpOf::mutate(XP_ALPHA, |result| {
1958 let value = result.as_mut().unwrap();
1959 value.reserve = value.reserve.saturating_add(DEFAULT_POINTS);
1960 });
1961 let return_points = Pallet::get_reserve_xp(&XP_ALPHA, &STAKING).unwrap();
1962 assert_eq!(return_points, DEFAULT_POINTS);
1963 });
1964 }
1965
1966 #[test]
1967 fn get_reserve_xp_fail_no_reserve() {
1968 xp_test_ext().execute_with(|| {
1969 Pallet::new_xp(&ALICE, &XP_ALPHA);
1970 assert_err!(
1971 Pallet::get_reserve_xp(&XP_ALPHA, &STAKING),
1972 Error::XpReserveNotFound
1973 );
1974 });
1975 }
1976
1977 #[test]
1978 fn set_reserve_success_new() {
1979 xp_test_ext().execute_with(|| {
1980 Pallet::new_xp(&ALICE, &XP_ALPHA);
1981 assert_err!(Pallet::has_reserve(&XP_ALPHA), Error::XpReserveNotFound);
1983 Pallet::set_reserve(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
1984 assert_ok!(Pallet::has_reserve(&XP_ALPHA));
1985 let get_reserve_xp = Pallet::get_reserve_xp(&XP_ALPHA, &STAKING).unwrap();
1987 assert_eq!(get_reserve_xp, DEFAULT_POINTS);
1988 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
1989 let xp_reserved_points = xp.reserve;
1990 assert_eq!(DEFAULT_POINTS, xp_reserved_points);
1991 });
1992 }
1993
1994 #[test]
1995 fn set_reserve_success_mutate_existing_xp() {
1996 xp_test_ext().execute_with(|| {
1997 Pallet::new_xp(&ALICE, &XP_ALPHA);
1998 Pallet::set_reserve(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
1999 let before_mutation = Pallet::get_reserve_xp(&XP_ALPHA, &STAKING).unwrap();
2000 assert_eq!(before_mutation, DEFAULT_POINTS);
2001 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
2002 let xp_reserved_points = xp.reserve;
2003 assert_eq!(DEFAULT_POINTS, xp_reserved_points);
2004 let new_reserve_points = 25;
2006 Pallet::set_reserve(&XP_ALPHA, &STAKING, new_reserve_points).unwrap();
2007 let after_mutation = Pallet::get_reserve_xp(&XP_ALPHA, &STAKING).unwrap();
2008 assert_eq!(after_mutation, new_reserve_points);
2009
2010 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
2011 let xp_reserved_points = xp.reserve;
2012 assert_eq!(new_reserve_points, xp_reserved_points);
2013
2014 let new_reserve_points = 15;
2016 Pallet::set_reserve(&XP_ALPHA, &STAKING, new_reserve_points).unwrap();
2017 let after_mutation = Pallet::get_reserve_xp(&XP_ALPHA, &STAKING).unwrap();
2018 assert_eq!(after_mutation, new_reserve_points);
2019
2020 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
2021 let xp_reserved_points = xp.reserve;
2022 assert_eq!(new_reserve_points, xp_reserved_points);
2023 });
2024 }
2025
2026 #[test]
2027 fn set_reserve_fail_mutate_existing_xp_overflow() {
2028 xp_test_ext().execute_with(|| {
2029 Pallet::new_xp(&ALICE, &XP_ALPHA);
2030 Pallet::set_reserve(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
2031 Pallet::set_reserve(&XP_ALPHA, &REASON_TREASURY, DEFAULT_POINTS).unwrap();
2032 assert_err!(
2033 Pallet::set_reserve(&XP_ALPHA, &REASON_TREASURY, SATURATED_MAX),
2034 Error::XpReserveCapOverflowed
2035 );
2036 });
2037 }
2038
2039 #[test]
2040 fn set_reserve_fail_new_reserve_overflow() {
2041 xp_test_ext().execute_with(|| {
2042 Pallet::new_xp(&ALICE, &XP_ALPHA);
2043 Pallet::set_reserve(&XP_ALPHA, &STAKING, SATURATED_MAX).unwrap();
2044 assert_err!(
2045 Pallet::set_reserve(&XP_ALPHA, &GOVERNANCE, DEFAULT_POINTS),
2046 Error::XpReserveCapOverflowed
2047 )
2048 });
2049 }
2050
2051 #[test]
2057 fn set_reserve_fail_too_many_reserves() {
2058 xp_test_ext().execute_with(|| {
2059 Pallet::new_xp(&ALICE, &XP_ALPHA);
2060 assert_err!(Pallet::has_reserve(&XP_ALPHA), Error::XpReserveNotFound);
2061 Pallet::set_reserve(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
2062 Pallet::set_reserve(&XP_ALPHA, &REASON_TREASURY, DEFAULT_POINTS).unwrap();
2063 Pallet::set_reserve(&XP_ALPHA, &GOVERNANCE, DEFAULT_POINTS).unwrap();
2064 Pallet::set_lock(&XP_ALPHA, &GOVERNANCE, DEFAULT_POINTS).unwrap();
2066 });
2067 }
2068
2069 #[test]
2070 fn set_reserve_fail_uninitialized_xp() {
2071 xp_test_ext().execute_with(|| {
2072 assert_err!(
2073 Pallet::set_reserve(&XP_ALPHA, &STAKING, DEFAULT_POINTS),
2074 Error::XpNotFound
2075 )
2076 })
2077 }
2078
2079 #[test]
2080 fn total_reserved_success() {
2081 xp_test_ext().execute_with(|| {
2082 Pallet::new_xp(&ALICE, &XP_ALPHA);
2083 Pallet::set_reserve(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
2085 Pallet::set_reserve(&XP_ALPHA, &REASON_TREASURY, DEFAULT_POINTS).unwrap();
2086 let actual = Pallet::total_reserved(&XP_ALPHA).unwrap();
2087 let expected = DEFAULT_POINTS + DEFAULT_POINTS;
2088 assert_eq!(expected, actual);
2089 })
2090 }
2091
2092 #[test]
2093 fn total_reserved_fail_uninitialized_xp() {
2094 xp_test_ext().execute_with(|| {
2095 assert_err!(Pallet::total_reserved(&XP_ALPHA), Error::XpNotFound);
2096 })
2097 }
2098
2099 #[test]
2100 fn get_all_reserves_success() {
2101 xp_test_ext().execute_with(|| {
2102 Pallet::new_xp(&ALICE, &XP_ALPHA);
2103 Pallet::set_reserve(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
2104 Pallet::set_reserve(&XP_ALPHA, &GOVERNANCE, DEFAULT_POINTS).unwrap();
2105 Pallet::set_reserve(&XP_ALPHA, &REASON_TREASURY, DEFAULT_POINTS).unwrap();
2106 let actual = Pallet::get_all_reserves(&XP_ALPHA).unwrap();
2107 let expected = vec![STAKING, GOVERNANCE, REASON_TREASURY];
2108 assert_eq!(expected, actual);
2109 });
2110 }
2111
2112 #[test]
2113 fn on_reserve_update_success() {
2114 xp_test_ext().execute_with(|| {
2115 Pallet::new_xp(&ALICE, &XP_ALPHA);
2116 System::set_block_number(2);
2117 Pallet::on_reserve_update(&XP_ALPHA, &STAKING, DEFAULT_POINTS);
2118 System::assert_last_event(
2119 Event::XpReserve {
2120 of: XP_ALPHA,
2121 reason: STAKING,
2122 xp: DEFAULT_POINTS,
2123 }
2124 .into(),
2125 );
2126 });
2127 }
2128
2129 #[test]
2130 fn can_reserve_xp_success() {
2131 xp_test_ext().execute_with(|| {
2132 Pallet::new_xp(&ALICE, &XP_ALPHA);
2133 Pallet::set_reserve(&XP_ALPHA, &GOVERNANCE, DEFAULT_POINTS).unwrap();
2134 let reserve_points = 3;
2135 assert_ok!(Pallet::can_reserve_xp(&XP_ALPHA, reserve_points));
2136 });
2137 }
2138
2139 #[test]
2140 fn can_reserve_xp_fail_overflow() {
2141 xp_test_ext().execute_with(|| {
2142 Pallet::new_xp(&ALICE, &XP_ALPHA);
2143 Pallet::set_reserve(&XP_ALPHA, &STAKING, SATURATED_MAX).unwrap();
2144 let reserve_points = 10;
2145 assert_err!(
2146 Pallet::can_reserve_xp(&XP_ALPHA, reserve_points),
2147 Error::XpReserveCapOverflowed
2148 );
2149 });
2150 }
2151
2152 #[test]
2153 fn can_reserve_xp_fail_insufficient_liquid_xp() {
2154 xp_test_ext().execute_with(|| {
2155 Pallet::new_xp(&ALICE, &XP_ALPHA);
2156 let reserve_points = 20;
2157 assert_err!(
2158 Pallet::can_reserve_xp(&XP_ALPHA, reserve_points),
2159 Error::InsufficientLiquidXp
2160 );
2161 });
2162 }
2163
2164 #[test]
2165 fn can_reserve_xp_fail_point_value_zero() {
2166 xp_test_ext().execute_with(|| {
2167 Pallet::new_xp(&ALICE, &XP_ALPHA);
2168 assert_err!(
2169 Pallet::can_reserve_xp(&XP_ALPHA, INVALID_POINTS),
2170 Error::CannotReserveZero
2171 );
2172 });
2173 }
2174
2175 #[test]
2176 fn can_reserve_xp_fail_uninitialized_xp() {
2177 xp_test_ext().execute_with(|| {
2178 assert_err!(
2179 Pallet::can_reserve_xp(&XP_ALPHA, DEFAULT_POINTS),
2180 Error::XpNotFound
2181 );
2182 });
2183 }
2184
2185 #[test]
2186 fn can_reserve_mutate_success() {
2187 xp_test_ext().execute_with(|| {
2188 Pallet::new_xp(&ALICE, &XP_ALPHA);
2189 Pallet::set_reserve(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
2190 Pallet::set_reserve(&XP_ALPHA, &GOVERNANCE, DEFAULT_POINTS).unwrap();
2191 assert_ok!(Pallet::can_reserve_mutate(
2192 &XP_ALPHA,
2193 &STAKING,
2194 DEFAULT_POINTS
2195 ));
2196 });
2197 }
2198
2199 #[test]
2200 fn can_reserve_mutate_reserve_not_exist() {
2201 xp_test_ext().execute_with(|| {
2202 Pallet::new_xp(&ALICE, &XP_ALPHA);
2203 assert_err!(
2204 Pallet::can_reserve_mutate(&XP_ALPHA, &STAKING, DEFAULT_POINTS),
2205 Error::XpReserveNotFound
2206 );
2207 });
2208 }
2209
2210 #[test]
2211 fn can_reserve_mutate_fail_overflow() {
2212 xp_test_ext().execute_with(|| {
2213 Pallet::new_xp(&ALICE, &XP_ALPHA);
2214 Pallet::set_reserve(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
2215 Pallet::set_reserve(&XP_ALPHA, &GOVERNANCE, DEFAULT_POINTS).unwrap();
2216 assert_err!(
2217 Pallet::can_reserve_mutate(&XP_ALPHA, &STAKING, SATURATED_MAX),
2218 Error::XpReserveCapOverflowed
2219 );
2220 });
2221 }
2222
2223 #[test]
2224 fn can_reserve_new_fail_max_reserve() {
2225 xp_test_ext().execute_with(|| {
2226 Pallet::new_xp(&ALICE, &XP_ALPHA);
2227 Pallet::set_reserve(&XP_ALPHA, &GOVERNANCE, DEFAULT_POINTS).unwrap();
2228 Pallet::set_reserve(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
2229 Pallet::set_reserve(&XP_ALPHA, &REASON_TREASURY, DEFAULT_POINTS).unwrap();
2230
2231 assert_err!(
2232 Pallet::can_reserve_new(&XP_ALPHA, DEFAULT_POINTS),
2233 Error::TooManyReserves
2234 );
2235 });
2236 }
2237
2238 #[test]
2239 fn can_reserve_new_success() {
2240 xp_test_ext().execute_with(|| {
2241 Pallet::new_xp(&ALICE, &XP_ALPHA);
2242 Pallet::set_reserve(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
2243
2244 assert_ok!(Pallet::can_reserve_new(&XP_ALPHA, DEFAULT_POINTS));
2245 });
2246 }
2247
2248 #[test]
2249 fn can_reserve_new_fail_uninitialized_xp() {
2250 xp_test_ext().execute_with(|| {
2251 assert_err!(
2252 Pallet::can_reserve_new(&XP_ALPHA, DEFAULT_POINTS),
2253 Error::XpNotFound
2254 );
2255 });
2256 }
2257
2258 #[test]
2259 fn can_reserve_new_fail_overflow() {
2260 xp_test_ext().execute_with(|| {
2261 Pallet::new_xp(&ALICE, &XP_ALPHA);
2262 Pallet::set_reserve(&XP_ALPHA, &STAKING, SATURATED_MAX).unwrap();
2263 assert_err!(
2264 Pallet::can_reserve_new(&XP_ALPHA, DEFAULT_POINTS),
2265 Error::XpReserveCapOverflowed
2266 );
2267 });
2268 }
2269
2270 #[test]
2271 fn reserve_xp_success() {
2272 xp_test_ext().execute_with(|| {
2273 Pallet::new_xp(&ALICE, &XP_ALPHA);
2274 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
2275 let liquid_before = xp.free;
2276 let reserve_before = xp.reserve;
2277 assert_err!(
2279 Pallet::reserve_exists(&XP_ALPHA, &STAKING),
2280 Error::XpReserveNotFound
2281 );
2282 let reserve_points = 5;
2283 assert_ok!(Pallet::reserve_xp(&XP_ALPHA, &STAKING, reserve_points));
2284 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
2285 let liquid_after = xp.free;
2286 let reserve_after = xp.reserve;
2287 let liquid_expected = liquid_before.saturating_sub(reserve_points);
2288 let reserve_expected = reserve_before.saturating_add(reserve_points);
2289 assert_ok!(Pallet::reserve_exists(&XP_ALPHA, &STAKING));
2290 assert_eq!(liquid_after, liquid_expected);
2291 assert_eq!(reserve_after, reserve_expected)
2292 });
2293 }
2294
2295 #[test]
2296 fn reserve_xp_success_mutate() {
2297 xp_test_ext().execute_with(|| {
2298 Pallet::new_xp(&ALICE, &XP_ALPHA);
2299 Pallet::set_reserve(&ALICE, &STAKING, DEFAULT_POINTS).unwrap();
2300 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
2301 let liquid_before = xp.free;
2302 let reserve_before = xp.reserve;
2303 assert_ok!(Pallet::reserve_exists(&XP_ALPHA, &STAKING));
2304 let reserve_points = 5;
2305 assert_ok!(Pallet::reserve_xp(&XP_ALPHA, &STAKING, reserve_points));
2306 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
2307 let liquid_after = xp.free;
2308 let reserve_after = xp.reserve;
2309 let liquid_expected = liquid_before.saturating_sub(reserve_points);
2310 let reserve_expected = reserve_before.saturating_add(reserve_points);
2311 assert_eq!(liquid_after, liquid_expected);
2312 assert_eq!(reserve_after, reserve_expected)
2313 });
2314 }
2315
2316 #[test]
2317 fn reserve_xp_fail_underflow() {
2318 xp_test_ext().execute_with(|| {
2319 Pallet::new_xp(&ALICE, &XP_ALPHA);
2320 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
2321 let available_liquid = xp.free;
2322 assert_eq!(available_liquid, 10);
2323 let reserve_points = 25;
2325 assert_err!(
2326 Pallet::reserve_xp(&XP_ALPHA, &STAKING, reserve_points),
2327 Error::InsufficientLiquidXp
2328 );
2329 });
2330 }
2331
2332 #[test]
2333 fn reserve_xp_fail_uninitialized_xp() {
2334 xp_test_ext().execute_with(|| {
2335 assert_err!(
2336 Pallet::reserve_xp(&XP_ALPHA, &STAKING, DEFAULT_POINTS),
2337 Error::XpNotFound
2338 );
2339 });
2340 }
2341
2342 #[test]
2343 fn reserve_xp_fail_mutate_overflow() {
2344 xp_test_ext().execute_with(|| {
2345 Pallet::new_xp(&ALICE, &XP_ALPHA);
2346 Pallet::set_reserve(&XP_ALPHA, &GOVERNANCE, SATURATED_MAX).unwrap();
2347 assert_err!(
2348 Pallet::reserve_xp(&XP_ALPHA, &GOVERNANCE, DEFAULT_POINTS),
2349 Error::XpReserveCapOverflowed
2350 );
2351 });
2352 }
2353
2354 #[test]
2355 fn withdraw_reserve_success() {
2356 xp_test_ext().execute_with(|| {
2357 Pallet::new_xp(&ALICE, &XP_ALPHA);
2358 Pallet::set_reserve(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
2359 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
2360 let liquid_before = xp.free;
2361 let reserve_before = xp.reserve;
2362 assert_ok!(Pallet::reserve_exists(&XP_ALPHA, &STAKING));
2363 assert_ok!(Pallet::withdraw_reserve(&XP_ALPHA, &STAKING));
2364 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
2365 let liquid_after = xp.free;
2366 let reserve_after = xp.reserve;
2367 let liquid_expected = liquid_before.saturating_add(reserve_before);
2368 let reserve_expected = liquid_before.saturating_sub(DEFAULT_POINTS);
2369 assert_eq!(liquid_after, liquid_expected);
2370 assert_eq!(reserve_after, reserve_expected);
2371 });
2372 }
2373
2374 #[test]
2375 fn withdraw_reserve_fail_no_reserve_exist() {
2376 xp_test_ext().execute_with(|| {
2377 Pallet::new_xp(&ALICE, &XP_ALPHA);
2378 assert_err!(
2379 Pallet::withdraw_reserve(&XP_ALPHA, &STAKING),
2380 Error::XpReserveNotFound
2381 )
2382 });
2383 }
2384
2385 #[test]
2386 fn withdraw_reserve_fail_uninitialized_xp() {
2387 xp_test_ext().execute_with(|| {
2388 assert_err!(
2389 Pallet::withdraw_reserve(&XP_ALPHA, &STAKING),
2390 Error::XpNotFound
2391 )
2392 });
2393 }
2394
2395 #[test]
2396 fn slash_reserve_success() {
2397 xp_test_ext().execute_with(|| {
2398 Pallet::new_xp(&ALICE, &XP_ALPHA);
2399 Pallet::set_reserve(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
2400 let reserve_xp_before = Pallet::get_reserve_xp(&XP_ALPHA, &STAKING).unwrap();
2401 let slash_points = 5;
2402 assert_ok!(Pallet::slash_reserve(&XP_ALPHA, &STAKING, slash_points));
2403 let reserve_xp_after = Pallet::get_reserve_xp(&XP_ALPHA, &STAKING).unwrap();
2404 let reserve_xp_expected = reserve_xp_before.saturating_sub(slash_points);
2405
2406 assert_eq!(reserve_xp_expected, reserve_xp_after);
2407 });
2408 }
2409
2410 #[test]
2411 fn slash_reserve_success_burn() {
2412 xp_test_ext().execute_with(|| {
2413 Pallet::new_xp(&ALICE, &XP_ALPHA);
2414 Pallet::set_reserve(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
2415 let reserve_xp_before = Pallet::get_reserve_xp(&XP_ALPHA, &STAKING).unwrap();
2416 assert_ok!(Pallet::reserve_exists(&XP_ALPHA, &STAKING));
2417 let slash_points = 20;
2418 let burn_points = Pallet::slash_reserve(&XP_ALPHA, &STAKING, slash_points).unwrap();
2419
2420 assert_err!(
2421 Pallet::lock_exists(&XP_ALPHA, &STAKING),
2422 Error::XpLockNotFound
2423 );
2424 let reserve_xp_after = Pallet::get_reserve_xp(&XP_ALPHA, &STAKING).unwrap();
2425
2426 assert_eq!(reserve_xp_after, 0);
2427 assert_eq!(reserve_xp_before, burn_points);
2428 });
2429 }
2430
2431 #[test]
2432 fn withdraw_reserve_partial_success_exact() {
2433 xp_test_ext().execute_with(|| {
2434 Pallet::new_xp(&ALICE, &XP_ALPHA);
2435 Pallet::set_reserve(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
2436 let reserve_before = Pallet::get_reserve_xp(&XP_ALPHA, &STAKING).unwrap();
2437 assert_eq!(reserve_before, DEFAULT_POINTS);
2438 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
2439 let free_before = xp.free;
2440 assert_eq!(free_before, DEFAULT_POINTS);
2441 let partial_withdraw = 6;
2442 Pallet::withdraw_reserve_partial(
2443 &XP_ALPHA,
2444 &STAKING,
2445 partial_withdraw,
2446 Precision::Exact,
2447 )
2448 .unwrap();
2449 let reserve_after = Pallet::get_reserve_xp(&XP_ALPHA, &STAKING).unwrap();
2450 let expected_reserve = reserve_before.saturating_sub(partial_withdraw);
2451 assert_eq!(reserve_after, expected_reserve);
2452 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
2453 let free_after = xp.free;
2454 let expected_free = free_before.saturating_add(partial_withdraw);
2455 assert_eq!(free_after, expected_free);
2456 });
2457 }
2458
2459 #[test]
2460 fn withdraw_reserve_partial_success_besteffort() {
2461 xp_test_ext().execute_with(|| {
2462 Pallet::new_xp(&ALICE, &XP_ALPHA);
2463 Pallet::set_reserve(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
2464 let reserve_before = Pallet::get_reserve_xp(&XP_ALPHA, &STAKING).unwrap();
2465 assert_eq!(reserve_before, DEFAULT_POINTS);
2466 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
2467 let free_before = xp.free;
2468 assert_eq!(free_before, DEFAULT_POINTS);
2469 let partial_withdraw = 11;
2470 Pallet::withdraw_reserve_partial(
2471 &XP_ALPHA,
2472 &STAKING,
2473 partial_withdraw,
2474 Precision::BestEffort,
2475 )
2476 .unwrap();
2477 let reserve_after = Pallet::get_reserve_xp(&XP_ALPHA, &STAKING).unwrap();
2478 let expected_reserve = reserve_before.saturating_sub(partial_withdraw);
2479 assert_eq!(reserve_after, expected_reserve);
2480 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
2481 let free_after = xp.free;
2482 let expected_free = 20;
2483 assert_eq!(free_after, expected_free);
2484 });
2485 }
2486
2487 #[test]
2488 fn withdraw_reserve_partial_success_with_zero() {
2489 xp_test_ext().execute_with(|| {
2490 Pallet::new_xp(&ALICE, &XP_ALPHA);
2491 Pallet::set_reserve(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
2492 assert_ok!(Pallet::withdraw_reserve_partial(
2493 &XP_ALPHA,
2494 &STAKING,
2495 INVALID_POINTS,
2496 Precision::Exact
2497 ));
2498 });
2499 }
2500
2501 #[test]
2502 fn withdraw_reserve_partial_fail_exact() {
2503 xp_test_ext().execute_with(|| {
2504 Pallet::new_xp(&ALICE, &XP_ALPHA);
2505 Pallet::set_reserve(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
2506 let reserve_before = Pallet::get_reserve_xp(&XP_ALPHA, &STAKING).unwrap();
2507 assert_eq!(reserve_before, DEFAULT_POINTS);
2508 let partial_withdraw = 11;
2509 assert_err!(
2510 Pallet::withdraw_reserve_partial(
2511 &XP_ALPHA,
2512 &STAKING,
2513 partial_withdraw,
2514 Precision::Exact
2515 ),
2516 Error::InsufficientReserveXp
2517 )
2518 });
2519 }
2520
2521 #[test]
2522 fn withdraw_reserve_partial_fail_no_reserve() {
2523 xp_test_ext().execute_with(|| {
2524 Pallet::new_xp(&ALICE, &XP_ALPHA);
2525 assert_err!(
2526 Pallet::withdraw_reserve_partial(
2527 &XP_ALPHA,
2528 &STAKING,
2529 DEFAULT_POINTS,
2530 Precision::Exact
2531 ),
2532 Error::XpReserveNotFound
2533 )
2534 });
2535 }
2536
2537 #[test]
2538 fn withdraw_reserve_partial_fail_uninitialized_xp() {
2539 xp_test_ext().execute_with(|| {
2540 assert_err!(
2541 Pallet::withdraw_reserve_partial(
2542 &XP_ALPHA,
2543 &STAKING,
2544 DEFAULT_POINTS,
2545 Precision::Exact
2546 ),
2547 Error::XpNotFound
2548 )
2549 });
2550 }
2551
2552 #[test]
2553 fn slash_reserve_fail_uninitialized_xp() {
2554 xp_test_ext().execute_with(|| {
2555 assert_err!(
2556 Pallet::slash_reserve(&XP_ALPHA, &STAKING, DEFAULT_POINTS),
2557 Error::XpNotFound
2558 )
2559 });
2560 }
2561
2562 #[test]
2563 fn slash_reserve_fail_no_reserve_exist() {
2564 xp_test_ext().execute_with(|| {
2565 Pallet::new_xp(&ALICE, &XP_ALPHA);
2566 assert_err!(
2567 Pallet::slash_reserve(&XP_ALPHA, &STAKING, DEFAULT_POINTS),
2568 Error::XpReserveNotFound
2569 )
2570 });
2571 }
2572
2573 #[test]
2574 fn reset_reserve_success() {
2575 xp_test_ext().execute_with(|| {
2576 Pallet::new_xp(&ALICE, &XP_ALPHA);
2577 Pallet::set_reserve(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
2578 let reserve_xp_before = Pallet::get_reserve_xp(&XP_ALPHA, &STAKING).unwrap();
2579 assert_ok!(Pallet::reserve_exists(&XP_ALPHA, &STAKING));
2580 let burn_points = Pallet::reset_reserve(&XP_ALPHA, &STAKING).unwrap();
2581
2582 assert_err!(
2583 Pallet::lock_exists(&XP_ALPHA, &STAKING),
2584 Error::XpLockNotFound
2585 );
2586 let reserve_xp_after = Pallet::get_reserve_xp(&XP_ALPHA, &STAKING).unwrap();
2587
2588 assert_eq!(reserve_xp_after, 0);
2589 assert_eq!(reserve_xp_before, burn_points);
2590 });
2591 }
2592
2593 #[test]
2594 fn reset_reserve_fail_uninitialized_xp() {
2595 xp_test_ext().execute_with(|| {
2596 assert_err!(
2597 Pallet::reset_reserve(&XP_ALPHA, &STAKING),
2598 Error::XpNotFound
2599 )
2600 });
2601 }
2602
2603 #[test]
2604 fn reset_reserve_fail_no_reserve_exist() {
2605 xp_test_ext().execute_with(|| {
2606 Pallet::new_xp(&ALICE, &XP_ALPHA);
2607 assert_err!(
2608 Pallet::reset_reserve(&XP_ALPHA, &STAKING),
2609 Error::XpReserveNotFound
2610 )
2611 });
2612 }
2613
2614 #[test]
2619 fn has_lock_success() {
2620 xp_test_ext().execute_with(|| {
2621 Pallet::new_xp(&ALICE, &XP_ALPHA);
2622 let idxp = LockId::new(STAKING, DEFAULT_POINTS);
2623 LockedXpOf::mutate(XP_ALPHA, |result| {
2624 let value = result
2625 .get_or_insert_with(|| BoundedVec::<LockId, VariantCountOf<Reason>>::default());
2626 value.try_push(idxp).unwrap();
2627 });
2628 XpOf::mutate(XP_ALPHA, |result| {
2629 let value = result.as_mut().unwrap();
2630 value.lock = value.lock.saturating_add(DEFAULT_POINTS);
2631 });
2632 assert_ok!(Pallet::has_lock(&XP_ALPHA));
2633 });
2634 }
2635
2636 #[test]
2637 fn has_lock_fail() {
2638 xp_test_ext().execute_with(|| {
2639 Pallet::new_xp(&ALICE, &XP_ALPHA);
2640 assert_err!(Pallet::has_lock(&XP_ALPHA), Error::XpLockNotFound);
2641 });
2642 }
2643
2644 #[test]
2645 fn has_lock_fail_uninitialized_key() {
2646 xp_test_ext().execute_with(|| {
2647 assert_err!(Pallet::has_lock(&XP_ALPHA), Error::XpLockNotFound);
2648 });
2649 }
2650
2651 #[test]
2652 fn get_lock_xp_success() {
2653 xp_test_ext().execute_with(|| {
2654 Pallet::new_xp(&ALICE, &XP_ALPHA);
2655 let idxp = LockId::new(STAKING, DEFAULT_POINTS);
2656 LockedXpOf::mutate(XP_ALPHA, |result| {
2657 let value = result
2658 .get_or_insert_with(|| BoundedVec::<LockId, VariantCountOf<Reason>>::default());
2659 value.try_push(idxp).unwrap();
2660 });
2661 XpOf::mutate(XP_ALPHA, |result| {
2662 let value = result.as_mut().unwrap();
2663 value.lock = value.lock.saturating_add(DEFAULT_POINTS);
2664 });
2665 let get_lock_xp = Pallet::get_lock_xp(&XP_ALPHA, &STAKING).unwrap();
2666 assert_eq!(get_lock_xp, DEFAULT_POINTS);
2667 });
2668 }
2669
2670 #[test]
2671 fn get_lock_xp_fail_no_lock() {
2672 xp_test_ext().execute_with(|| {
2673 Pallet::new_xp(&ALICE, &XP_ALPHA);
2674 assert_err!(
2675 Pallet::get_lock_xp(&XP_ALPHA, &STAKING),
2676 Error::XpLockNotFound
2677 );
2678 });
2679 }
2680
2681 #[test]
2682 fn set_lock_success_new() {
2683 xp_test_ext().execute_with(|| {
2684 Pallet::new_xp(&ALICE, &XP_ALPHA);
2685 assert_err!(Pallet::has_lock(&XP_ALPHA), Error::XpLockNotFound);
2687 Pallet::set_lock(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
2688 assert_ok!(Pallet::has_lock(&XP_ALPHA));
2689 let get_lock_xp = Pallet::get_lock_xp(&XP_ALPHA, &STAKING).unwrap();
2691 assert_eq!(get_lock_xp, DEFAULT_POINTS);
2692 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
2693 let xp_locked_points = xp.lock;
2694 assert_eq!(DEFAULT_POINTS, xp_locked_points);
2695 });
2696 }
2697
2698 #[test]
2699 fn set_lock_success_mutate_existing_xp() {
2700 xp_test_ext().execute_with(|| {
2701 Pallet::new_xp(&ALICE, &XP_ALPHA);
2702 Pallet::set_lock(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
2703 let before_mutation = Pallet::get_lock_xp(&XP_ALPHA, &STAKING).unwrap();
2704 assert_eq!(before_mutation, DEFAULT_POINTS);
2705 let new_lock_points = 25;
2707 Pallet::set_lock(&XP_ALPHA, &STAKING, new_lock_points).unwrap();
2708 let after_mutation = Pallet::get_lock_xp(&XP_ALPHA, &STAKING).unwrap();
2709 assert_eq!(after_mutation, new_lock_points);
2710 let new_lock_points = 15;
2712 Pallet::set_lock(&XP_ALPHA, &STAKING, new_lock_points).unwrap();
2713 let after_mutation = Pallet::get_lock_xp(&XP_ALPHA, &STAKING).unwrap();
2714 assert_eq!(after_mutation, new_lock_points);
2715 });
2716 }
2717
2718 #[test]
2719 fn set_lock_fail_mutate_existing_xp_overflow() {
2720 xp_test_ext().execute_with(|| {
2721 Pallet::new_xp(&ALICE, &XP_ALPHA);
2722 Pallet::set_lock(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
2723 Pallet::set_lock(&XP_ALPHA, &REASON_TREASURY, DEFAULT_POINTS).unwrap();
2724 assert_err!(
2725 Pallet::set_lock(&XP_ALPHA, &REASON_TREASURY, SATURATED_MAX),
2726 Error::XpLockCapOverflowed
2727 );
2728 });
2729 }
2730
2731 #[test]
2732 fn set_lock_fail_new_lock_overflow() {
2733 xp_test_ext().execute_with(|| {
2734 Pallet::new_xp(&ALICE, &XP_ALPHA);
2735 Pallet::set_lock(&XP_ALPHA, &STAKING, SATURATED_MAX).unwrap();
2736 assert_err!(
2737 Pallet::set_lock(&XP_ALPHA, &GOVERNANCE, DEFAULT_POINTS),
2738 Error::XpLockCapOverflowed
2739 )
2740 });
2741 }
2742
2743 #[test]
2744 fn set_lock_fail_points_value_zero() {
2745 xp_test_ext().execute_with(|| {
2746 Pallet::new_xp(&ALICE, &XP_ALPHA);
2747 assert_err!(Pallet::has_lock(&XP_ALPHA), Error::XpLockNotFound);
2748 Pallet::set_lock(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
2749 assert_ok!(Pallet::has_lock(&XP_ALPHA));
2750 assert_err!(
2751 Pallet::set_lock(&XP_ALPHA, &STAKING, INVALID_POINTS),
2752 Error::CannotLockZero
2753 );
2754 });
2755 }
2756
2757 #[test]
2763 fn set_lock_fail_too_many_locks() {
2764 xp_test_ext().execute_with(|| {
2765 Pallet::new_xp(&ALICE, &XP_ALPHA);
2766 assert_err!(Pallet::has_lock(&XP_ALPHA), Error::XpLockNotFound);
2767 Pallet::set_lock(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
2768 Pallet::set_lock(&XP_ALPHA, &REASON_TREASURY, DEFAULT_POINTS).unwrap();
2769 Pallet::set_lock(&XP_ALPHA, &GOVERNANCE, DEFAULT_POINTS).unwrap();
2770 Pallet::set_lock(&XP_ALPHA, &GOVERNANCE, DEFAULT_POINTS).unwrap();
2771 });
2772 }
2773
2774 #[test]
2775 fn set_lock_fail_uninitialized_xp() {
2776 xp_test_ext().execute_with(|| {
2777 assert_err!(
2778 Pallet::set_lock(&XP_ALPHA, &GOVERNANCE, DEFAULT_POINTS),
2779 Error::XpNotFound
2780 );
2781 });
2782 }
2783
2784 #[test]
2785 fn lock_exists_success() {
2786 xp_test_ext().execute_with(|| {
2787 Pallet::new_xp(&ALICE, &XP_ALPHA);
2788 Pallet::set_lock(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
2790 assert_ok!(Pallet::lock_exists(&XP_ALPHA, &STAKING));
2791 });
2792 }
2793
2794 #[test]
2795 fn lock_exists_fail_no_locks() {
2796 xp_test_ext().execute_with(|| {
2797 Pallet::new_xp(&ALICE, &XP_ALPHA);
2798 assert_err!(
2799 Pallet::lock_exists(&XP_ALPHA, &STAKING),
2800 Error::XpLockNotFound
2801 );
2802 });
2803 }
2804
2805 #[test]
2806 fn maximum_locks_success() {
2807 xp_test_ext().execute_with(|| {
2808 let max_locks: usize = Pallet::maximum_locks();
2809 let expected = Reason::VARIANT_COUNT as usize;
2810 assert_eq!(max_locks, expected);
2811 });
2812 }
2813
2814 #[test]
2815 fn total_locked_success() {
2816 xp_test_ext().execute_with(|| {
2817 Pallet::new_xp(&ALICE, &XP_ALPHA);
2818 Pallet::set_lock(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
2819 Pallet::set_lock(&XP_ALPHA, &REASON_TREASURY, DEFAULT_POINTS).unwrap();
2820 let actual_locked = Pallet::total_locked(&XP_ALPHA).unwrap();
2821 let expected_locked = DEFAULT_POINTS + DEFAULT_POINTS;
2822 assert_eq!(expected_locked, actual_locked);
2823 });
2824 }
2825
2826 #[test]
2827 fn total_locked_fail_uninitialized_xp() {
2828 xp_test_ext().execute_with(|| {
2829 assert_err!(Pallet::total_locked(&XP_ALPHA), Error::XpNotFound);
2830 })
2831 }
2832
2833 #[test]
2834 fn get_all_locks_success() {
2835 xp_test_ext().execute_with(|| {
2836 Pallet::new_xp(&ALICE, &XP_ALPHA);
2837 Pallet::set_lock(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
2838 Pallet::set_lock(&XP_ALPHA, &GOVERNANCE, DEFAULT_POINTS).unwrap();
2839 Pallet::set_lock(&XP_ALPHA, &REASON_TREASURY, DEFAULT_POINTS).unwrap();
2840 let actual = Pallet::get_all_locks(&XP_ALPHA).unwrap();
2841 let expected = vec![Reason::Staking, Reason::Governance, Reason::Treasury];
2842 assert_eq!(actual, expected);
2843 });
2844 }
2845
2846 #[test]
2847 fn burn_lock_success() {
2848 xp_test_ext().execute_with(|| {
2849 Pallet::new_xp(&ALICE, &XP_ALPHA);
2850 System::set_block_number(2);
2851 Pallet::set_lock(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
2852 assert_ok!(Pallet::lock_exists(&XP_ALPHA, &STAKING));
2854 assert_ok!(Pallet::burn_lock(&XP_ALPHA, &STAKING));
2855 assert_err!(
2856 Pallet::lock_exists(&XP_ALPHA, &STAKING),
2857 Error::XpLockNotFound
2858 );
2859 });
2860 }
2861
2862 #[test]
2867 fn burn_lock_underflow() {
2868 xp_test_ext().execute_with(|| {
2869 Pallet::new_xp(&ALICE, &XP_ALPHA);
2870 Pallet::set_lock(&XP_ALPHA, &REASON_TREASURY, DEFAULT_POINTS).unwrap();
2871 let lock_xp = Pallet::get_lock_xp(&XP_ALPHA, &REASON_TREASURY).unwrap();
2872 assert_eq!(lock_xp, DEFAULT_POINTS);
2873 Pallet::burn_lock(&XP_ALPHA, &REASON_TREASURY).unwrap();
2874 assert_err!(
2876 Pallet::get_lock_xp(&XP_ALPHA, &REASON_TREASURY),
2877 Error::XpLockNotFound
2878 );
2879 });
2880 }
2881
2882 #[test]
2883 fn burn_lock_fail_no_valid_lock_id() {
2884 xp_test_ext().execute_with(|| {
2885 Pallet::new_xp(&ALICE, &XP_ALPHA);
2886 assert_err!(
2887 Pallet::burn_lock(&XP_ALPHA, &STAKING),
2888 Error::XpLockNotFound
2889 )
2890 });
2891 }
2892
2893 #[test]
2894 fn burn_lock_fail_uninitialized_xp() {
2895 xp_test_ext().execute_with(|| {
2896 assert_err!(
2897 Pallet::burn_lock(&XP_ALPHA, &STAKING),
2898 Error::XpLockNotFound
2899 )
2900 });
2901 }
2902
2903 #[test]
2904 fn on_lock_update_success() {
2905 xp_test_ext().execute_and_prove(|| {
2906 System::set_block_number(2);
2907 Pallet::on_lock_update(&XP_ALPHA, &STAKING, DEFAULT_POINTS);
2908 System::assert_last_event(
2909 Event::XpLock {
2910 of: XP_ALPHA,
2911 reason: STAKING,
2912 xp: DEFAULT_POINTS,
2913 }
2914 .into(),
2915 );
2916 });
2917 }
2918
2919 #[test]
2920 fn on_lock_burn_success() {
2921 xp_test_ext().execute_with(|| {
2922 System::set_block_number(1);
2923 Pallet::on_lock_burn(&XP_ALPHA, &STAKING);
2924 System::assert_last_event(
2925 Event::XpLockBurn {
2926 of: XP_ALPHA,
2927 reason: STAKING,
2928 }
2929 .into(),
2930 );
2931 });
2932 }
2933
2934 #[test]
2935 fn can_lock_xp_success() {
2936 xp_test_ext().execute_with(|| {
2937 Pallet::new_xp(&ALICE, &XP_ALPHA);
2938 Pallet::set_lock(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
2939 let lock_points = 3;
2940 assert_ok!(Pallet::can_lock_xp(&XP_ALPHA, lock_points));
2941 });
2942 }
2943
2944 #[test]
2945 fn can_lock_xp_fail_overflow() {
2946 xp_test_ext().execute_with(|| {
2947 Pallet::new_xp(&ALICE, &XP_ALPHA);
2948 Pallet::set_lock(&XP_ALPHA, &STAKING, SATURATED_MAX).unwrap();
2949 let lock_points = 3;
2950 assert_err!(
2951 Pallet::can_lock_xp(&XP_ALPHA, lock_points),
2952 Error::XpLockCapOverflowed
2953 );
2954 });
2955 }
2956
2957 #[test]
2958 fn can_lock_xp_fail_insufficient_liquid_xp() {
2959 xp_test_ext().execute_with(|| {
2960 Pallet::new_xp(&ALICE, &XP_ALPHA);
2961 let lock_points = 20;
2962 assert_err!(
2963 Pallet::can_lock_xp(&XP_ALPHA, lock_points),
2964 Error::InsufficientLiquidXp
2965 );
2966 });
2967 }
2968
2969 #[test]
2970 fn can_lock_xp_fail_point_value_zero() {
2971 xp_test_ext().execute_with(|| {
2972 Pallet::new_xp(&ALICE, &XP_ALPHA);
2973
2974 assert_err!(
2975 Pallet::can_lock_xp(&XP_ALPHA, INVALID_POINTS),
2976 Error::CannotLockZero
2977 );
2978 });
2979 }
2980
2981 #[test]
2982 fn can_lock_xp_fail_uninitialized_xp() {
2983 xp_test_ext().execute_with(|| {
2984 assert_err!(
2985 Pallet::can_lock_xp(&XP_ALPHA, DEFAULT_POINTS),
2986 Error::XpNotFound
2987 );
2988 });
2989 }
2990
2991 #[test]
2992 fn can_lock_mutate_success() {
2993 xp_test_ext().execute_with(|| {
2994 Pallet::new_xp(&ALICE, &XP_ALPHA);
2995 Pallet::set_lock(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
2996 Pallet::set_lock(&XP_ALPHA, &REASON_TREASURY, DEFAULT_POINTS).unwrap();
2997 assert_ok!(Pallet::can_lock_mutate(&XP_ALPHA, &STAKING, DEFAULT_POINTS));
2998 });
2999 }
3000
3001 #[test]
3002 fn can_lock_mutate_lock_not_exist() {
3003 xp_test_ext().execute_with(|| {
3004 Pallet::new_xp(&ALICE, &XP_ALPHA);
3005 assert_err!(
3006 Pallet::can_lock_mutate(&XP_ALPHA, &STAKING, DEFAULT_POINTS),
3007 Error::XpLockNotFound
3008 );
3009 });
3010 }
3011
3012 #[test]
3013 fn can_lock_mutate_fail_point_value_zero() {
3014 xp_test_ext().execute_with(|| {
3015 Pallet::new_xp(&ALICE, &XP_ALPHA);
3016 Pallet::set_lock(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
3017 assert_err!(
3018 Pallet::can_lock_mutate(&XP_ALPHA, &STAKING, INVALID_POINTS),
3019 Error::CannotLockZero
3020 );
3021 });
3022 }
3023
3024 #[test]
3025 fn can_lock_mutate_fail_overflow() {
3026 xp_test_ext().execute_with(|| {
3027 Pallet::new_xp(&ALICE, &XP_ALPHA);
3028 Pallet::set_lock(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
3029 Pallet::set_lock(&XP_ALPHA, &REASON_TREASURY, DEFAULT_POINTS).unwrap();
3030 assert_err!(
3031 Pallet::can_lock_mutate(&XP_ALPHA, &STAKING, SATURATED_MAX),
3032 Error::XpLockCapOverflowed
3033 );
3034 });
3035 }
3036
3037 #[test]
3038 fn can_lock_new_fail_max_lock() {
3039 xp_test_ext().execute_with(|| {
3040 Pallet::new_xp(&ALICE, &XP_ALPHA);
3041 Pallet::set_lock(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
3042 Pallet::set_lock(&XP_ALPHA, &REASON_TREASURY, DEFAULT_POINTS).unwrap();
3043 Pallet::set_lock(&XP_ALPHA, &GOVERNANCE, DEFAULT_POINTS).unwrap();
3044 assert_err!(
3045 Pallet::can_lock_new(&XP_ALPHA, DEFAULT_POINTS),
3046 Error::TooManyLocks
3047 );
3048 });
3049 }
3050
3051 #[test]
3052 fn can_lock_new_success() {
3053 xp_test_ext().execute_with(|| {
3054 Pallet::new_xp(&ALICE, &XP_ALPHA);
3055 Pallet::set_lock(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
3056
3057 assert_ok!(Pallet::can_lock_new(&XP_ALPHA, DEFAULT_POINTS));
3058 });
3059 }
3060
3061 #[test]
3062 fn can_lock_new_fail_uninitialized_xp() {
3063 xp_test_ext().execute_with(|| {
3064 assert_err!(
3065 Pallet::can_lock_new(&XP_ALPHA, DEFAULT_POINTS),
3066 Error::XpNotFound
3067 );
3068 });
3069 }
3070
3071 #[test]
3072 fn can_lock_new_fail_with_zero() {
3073 xp_test_ext().execute_with(|| {
3074 Pallet::new_xp(&ALICE, &XP_ALPHA);
3075 assert_err!(
3076 Pallet::can_lock_new(&XP_ALPHA, INVALID_POINTS),
3077 Error::CannotLockZero,
3078 );
3079 });
3080 }
3081
3082 #[test]
3083 fn can_lock_new_fail_overflow() {
3084 xp_test_ext().execute_with(|| {
3085 Pallet::new_xp(&ALICE, &XP_ALPHA);
3086 Pallet::set_lock(&XP_ALPHA, &STAKING, SATURATED_MAX).unwrap();
3087 assert_err!(
3088 Pallet::can_lock_new(&XP_ALPHA, DEFAULT_POINTS),
3089 Error::XpLockCapOverflowed
3090 );
3091 });
3092 }
3093
3094 #[test]
3095 fn lock_xp_success() {
3096 xp_test_ext().execute_with(|| {
3097 Pallet::new_xp(&ALICE, &XP_ALPHA);
3098 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
3099 let liquid_before = xp.free;
3100 let lock_before = xp.lock;
3101 assert_err!(
3102 Pallet::lock_exists(&XP_ALPHA, &STAKING),
3103 Error::XpLockNotFound
3104 );
3105 let lock_points = 5;
3106 assert_ok!(Pallet::lock_xp(&XP_ALPHA, &STAKING, lock_points));
3107 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
3108 let liquid_after = xp.free;
3109 let lock_after = xp.lock;
3110 let liquid_expected = liquid_before.saturating_sub(lock_points);
3111 let lock_expected = lock_before.saturating_add(lock_points);
3112 assert_ok!(Pallet::lock_exists(&XP_ALPHA, &STAKING));
3113 assert_eq!(liquid_after, liquid_expected);
3114 assert_eq!(lock_after, lock_expected)
3115 });
3116 }
3117
3118 #[test]
3119 fn lock_xp_success_mutate() {
3120 xp_test_ext().execute_with(|| {
3121 Pallet::new_xp(&ALICE, &XP_ALPHA);
3122 Pallet::set_lock(&ALICE, &STAKING, DEFAULT_POINTS).unwrap();
3123 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
3124 let liquid_before = xp.free;
3125 let lock_before = xp.lock;
3126 assert_ok!(Pallet::lock_exists(&XP_ALPHA, &STAKING));
3127 let lock_points = 5;
3128 assert_ok!(Pallet::lock_xp(&XP_ALPHA, &STAKING, lock_points));
3129 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
3130 let liquid_after = xp.free;
3131 let lock_after = xp.lock;
3132 let liquid_expected = liquid_before.saturating_sub(lock_points);
3133 let lock_expected = lock_before.saturating_add(lock_points);
3134 assert_eq!(liquid_after, liquid_expected);
3135 assert_eq!(lock_after, lock_expected);
3136 });
3137 }
3138
3139 #[test]
3140 fn lock_xp_fail_underflow() {
3141 xp_test_ext().execute_with(|| {
3142 Pallet::new_xp(&ALICE, &XP_ALPHA);
3143 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
3144 let available_liquid = xp.free;
3145 assert_eq!(available_liquid, 10);
3146 let lock_points = 25;
3148 assert_err!(
3149 Pallet::lock_xp(&XP_ALPHA, &STAKING, lock_points),
3150 Error::InsufficientLiquidXp
3151 );
3152 });
3153 }
3154
3155 #[test]
3156 fn lock_xp_fail_mutate_overflow() {
3157 xp_test_ext().execute_with(|| {
3158 Pallet::new_xp(&ALICE, &XP_ALPHA);
3159 Pallet::set_lock(&XP_ALPHA, &GOVERNANCE, SATURATED_MAX).unwrap();
3160 assert_err!(
3161 Pallet::lock_xp(&XP_ALPHA, &GOVERNANCE, DEFAULT_POINTS),
3162 Error::XpLockCapOverflowed
3163 );
3164 });
3165 }
3166
3167 #[test]
3168 fn lock_xp_fail_uninitialized_xp() {
3169 xp_test_ext().execute_with(|| {
3170 assert_err!(
3171 Pallet::lock_xp(&XP_ALPHA, &STAKING, DEFAULT_POINTS),
3172 Error::XpNotFound
3173 );
3174 });
3175 }
3176
3177 #[test]
3178 fn lock_xp_fail_points_value_zero() {
3179 xp_test_ext().execute_with(|| {
3180 Pallet::new_xp(&ALICE, &XP_ALPHA);
3181 assert_err!(
3182 Pallet::lock_xp(&XP_ALPHA, &STAKING, INVALID_POINTS),
3183 Error::CannotLockZero
3184 );
3185 });
3186 }
3187
3188 #[test]
3189 fn withdraw_lock_success() {
3190 xp_test_ext().execute_with(|| {
3191 Pallet::new_xp(&ALICE, &XP_ALPHA);
3192 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
3193 let liquid_before = xp.free;
3194 Pallet::set_lock(&ALICE, &STAKING, DEFAULT_POINTS).unwrap();
3195 assert_ok!(Pallet::lock_exists(&XP_ALPHA, &STAKING));
3196 assert_ok!(Pallet::withdraw_lock(&ALICE, &STAKING));
3197 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
3198 let liquid_after = xp.free;
3199 let liquid_expected = liquid_before.saturating_add(DEFAULT_POINTS);
3200
3201 assert_err!(
3202 Pallet::lock_exists(&XP_ALPHA, &STAKING),
3203 Error::XpLockNotFound
3204 );
3205 assert_eq!(liquid_expected, liquid_after);
3206 });
3207 }
3208
3209 #[test]
3210 fn withdraw_lock_fail_no_lock_exist() {
3211 xp_test_ext().execute_with(|| {
3212 Pallet::new_xp(&ALICE, &XP_ALPHA);
3213 assert_err!(
3214 Pallet::withdraw_lock(&XP_ALPHA, &STAKING),
3215 Error::XpLockNotFound
3216 )
3217 });
3218 }
3219
3220 #[test]
3221 fn withdraw_lock_fail_uninitialized_xp() {
3222 xp_test_ext().execute_with(|| {
3223 assert_err!(
3224 Pallet::withdraw_lock(&XP_ALPHA, &STAKING),
3225 Error::XpNotFound
3226 )
3227 });
3228 }
3229
3230 #[test]
3231 fn slash_lock_success() {
3232 xp_test_ext().execute_with(|| {
3233 Pallet::new_xp(&ALICE, &XP_ALPHA);
3234 Pallet::set_lock(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
3235 let lock_xp_before = Pallet::get_lock_xp(&XP_ALPHA, &STAKING).unwrap();
3236 let slash_points = 5;
3237 assert_ok!(Pallet::slash_lock(&XP_ALPHA, &STAKING, slash_points));
3238 let lock_xp_after = Pallet::get_lock_xp(&XP_ALPHA, &STAKING).unwrap();
3239 let lock_xp_expected = lock_xp_before.saturating_sub(slash_points);
3240
3241 assert_eq!(lock_xp_expected, lock_xp_after);
3242 });
3243 }
3244
3245 #[test]
3246 fn slash_lock_success_burn() {
3247 xp_test_ext().execute_with(|| {
3248 Pallet::new_xp(&ALICE, &XP_ALPHA);
3249 Pallet::set_lock(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
3250 let lock_xp_before = Pallet::get_lock_xp(&XP_ALPHA, &STAKING).unwrap();
3251 assert_ok!(Pallet::lock_exists(&XP_ALPHA, &STAKING));
3252 let slash_points = 20;
3253 let burn_points = Pallet::slash_lock(&XP_ALPHA, &STAKING, slash_points).unwrap();
3254
3255 assert_eq!(lock_xp_before, burn_points);
3256 assert_err!(
3257 Pallet::lock_exists(&XP_ALPHA, &STAKING),
3258 Error::XpLockNotFound
3259 );
3260 });
3261 }
3262
3263 #[test]
3264 fn slash_lock_fail_uninitialized_xp() {
3265 xp_test_ext().execute_with(|| {
3266 assert_err!(
3267 Pallet::slash_lock(&XP_ALPHA, &STAKING, DEFAULT_POINTS),
3268 Error::XpNotFound
3269 )
3270 });
3271 }
3272
3273 #[test]
3274 fn slash_lock_fail_no_lock_exist() {
3275 xp_test_ext().execute_with(|| {
3276 Pallet::new_xp(&ALICE, &XP_ALPHA);
3277 assert_err!(
3278 Pallet::slash_lock(&XP_ALPHA, &STAKING, DEFAULT_POINTS),
3279 Error::XpLockNotFound
3280 )
3281 });
3282 }
3283
3284 #[test]
3289 fn reap_xp_success() {
3290 xp_test_ext().execute_with(|| {
3291 System::set_block_number(2);
3292 Pallet::new_xp(&ALICE, &XP_ALPHA);
3293 System::set_block_number(2);
3294 let idxp = ReserveId::new(STAKING, DEFAULT_POINTS);
3295 ReservedXpOf::mutate(XP_ALPHA, |result| {
3296 let value = result.get_or_insert_with(|| {
3297 BoundedVec::<ReserveId, VariantCountOf<Reason>>::default()
3298 });
3299 value.try_push(idxp).unwrap();
3300 });
3301 XpOf::mutate(XP_ALPHA, |result| {
3302 let value = result.as_mut().unwrap();
3303 value.reserve = value.reserve.saturating_add(DEFAULT_POINTS);
3304 });
3305 assert!(ReservedXpOf::contains_key(XP_ALPHA));
3306 System::set_block_number(3);
3307 let usable_xp = Pallet::get_usable_xp(&XP_ALPHA).unwrap();
3310 let reap_points = Pallet::reap_xp(&XP_ALPHA).unwrap();
3311 assert!(!ReservedXpOf::contains_key(XP_ALPHA));
3312 assert_eq!(usable_xp, reap_points);
3313 });
3314 }
3315
3316 #[test]
3317 fn reap_xp_fail_lock_exists() {
3318 xp_test_ext().execute_with(|| {
3319 Pallet::new_xp(&ALICE, &XP_ALPHA);
3320 let idxp = ReserveId::new(STAKING, DEFAULT_POINTS);
3321 LockedXpOf::mutate(XP_ALPHA, |result| {
3322 let value = result
3323 .get_or_insert_with(|| BoundedVec::<LockId, VariantCountOf<Reason>>::default());
3324 value.try_push(idxp).unwrap();
3325 });
3326 XpOf::mutate(XP_ALPHA, |result| {
3327 let value = result.as_mut().unwrap();
3328 value.lock = value.lock.saturating_add(DEFAULT_POINTS);
3329 });
3330 assert!(LockedXpOf::contains_key(XP_ALPHA));
3331 assert_err!(Pallet::reap_xp(&XP_ALPHA), Error::XpLockExists);
3332 });
3333 }
3334
3335 #[test]
3336 fn reap_xp_fail_uninitialized_xp() {
3337 xp_test_ext().execute_with(|| {
3338 assert_err!(Pallet::xp_exists(&XP_ALPHA), Error::XpNotFound);
3341 assert_err!(Pallet::reap_xp(&XP_ALPHA), Error::XpNotFound);
3342 });
3343 }
3344
3345 #[test]
3346 fn is_reaped_success() {
3347 xp_test_ext().execute_with(|| {
3348 Pallet::new_xp(&ALICE, &XP_ALPHA);
3349 Pallet::reap_xp(&XP_ALPHA).unwrap();
3352 assert_ok!(Pallet::is_reaped(&XP_ALPHA));
3353 });
3354 }
3355
3356 #[test]
3357 fn is_reaped_fail() {
3358 xp_test_ext().execute_with(|| {
3359 Pallet::new_xp(&ALICE, &XP_ALPHA);
3360 assert_err!(Pallet::is_reaped(&XP_ALPHA), Error::XpNotReaped);
3361 });
3362 }
3363
3364 #[test]
3365 fn on_xp_reap_success() {
3366 xp_test_ext().execute_with(|| {
3367 System::set_block_number(2);
3368 Pallet::on_xp_reap(&XP_ALPHA);
3369 System::assert_last_event(Event::XpReap { id: XP_ALPHA }.into());
3370 });
3371 }
3372
3373 #[test]
3376 fn can_reap_success() {
3377 xp_test_ext().execute_with(|| {
3378 System::set_block_number(2);
3379 Pallet::new_xp(&ALICE, &XP_ALPHA);
3380 System::set_block_number(4);
3381 System::set_block_number(6);
3382 System::set_block_number(8);
3383 System::set_block_number(10);
3384 Pallet::force_genesis_config(
3385 RuntimeOrigin::root(),
3386 ForceGenesisConfig::MinTimeStamp(10),
3387 )
3388 .unwrap();
3389 System::set_block_number(12);
3390 assert_ok!(Pallet::can_reap(&XP_ALPHA));
3391 });
3392 }
3393
3394 #[test]
3395 fn can_reap_fail_uninitialized_xp() {
3396 xp_test_ext().execute_with(|| {
3397 assert_err!(Pallet::can_reap(&XP_ALPHA), Error::XpNotFound);
3398 });
3399 }
3400
3401 #[test]
3402 fn can_reap_fail_already_reaped() {
3403 xp_test_ext().execute_with(|| {
3404 System::set_block_number(2);
3405 Pallet::new_xp(&ALICE, &XP_ALPHA);
3406 Pallet::reap_xp(&XP_ALPHA).unwrap();
3407 assert_err!(Pallet::can_reap(&XP_ALPHA), Error::XpAlreadyReaped,);
3408 });
3409 }
3410
3411 #[test]
3412 fn can_reap_fail_not_dead() {
3413 xp_test_ext().execute_with(|| {
3414 System::set_block_number(2);
3415 Pallet::new_xp(&ALICE, &XP_ALPHA);
3416 assert_err!(Pallet::can_reap(&XP_ALPHA), Error::XpNotDead,);
3417 });
3418 }
3419
3420 #[test]
3421 fn can_reap_fail_lock_exists() {
3422 xp_test_ext().execute_with(|| {
3423 System::set_block_number(2);
3424 Pallet::new_xp(&ALICE, &XP_ALPHA);
3425 let idxp = ReserveId::new(STAKING, DEFAULT_POINTS);
3426 LockedXpOf::mutate(XP_ALPHA, |result| {
3427 let value = result
3428 .get_or_insert_with(|| BoundedVec::<LockId, VariantCountOf<Reason>>::default());
3429 value.try_push(idxp).unwrap();
3430 });
3431 XpOf::mutate(XP_ALPHA, |result| {
3432 let value = result.as_mut().unwrap();
3433 value.lock = value.lock.saturating_add(DEFAULT_POINTS);
3434 });
3435 assert!(LockedXpOf::contains_key(XP_ALPHA));
3436 System::set_block_number(6);
3437 System::set_block_number(10);
3438 System::set_block_number(12);
3439 Pallet::force_genesis_config(
3440 RuntimeOrigin::root(),
3441 ForceGenesisConfig::MinTimeStamp(10),
3442 )
3443 .unwrap();
3444 assert_err!(Pallet::can_reap(&XP_ALPHA), Error::CannotReapLockedXp,);
3445 });
3446 }
3447
3448 #[test]
3449 fn try_reap_success() {
3450 xp_test_ext().execute_with(|| {
3451 System::set_block_number(2);
3452 Pallet::new_xp(&ALICE, &XP_ALPHA);
3453 System::set_block_number(4);
3454 System::set_block_number(6);
3455 System::set_block_number(8);
3456 System::set_block_number(10);
3457 Pallet::force_genesis_config(
3458 RuntimeOrigin::root(),
3459 ForceGenesisConfig::MinTimeStamp(10),
3460 )
3461 .unwrap();
3462 System::set_block_number(12);
3463 assert_ok!(Pallet::try_reap(&XP_ALPHA));
3464 assert_ok!(Pallet::is_reaped(&XP_ALPHA));
3465 });
3466 }
3467
3468 #[test]
3469 fn try_reap_fail_uninitialized_xp() {
3470 xp_test_ext().execute_with(|| {
3471 assert_err!(Pallet::try_reap(&XP_ALPHA), Error::XpNotFound);
3472 });
3473 }
3474
3475 #[test]
3476 fn try_reap_fail_already_reaped() {
3477 xp_test_ext().execute_with(|| {
3478 System::set_block_number(2);
3479 Pallet::new_xp(&ALICE, &XP_ALPHA);
3480 Pallet::reap_xp(&XP_ALPHA).unwrap();
3481 assert_err!(Pallet::try_reap(&XP_ALPHA), Error::XpAlreadyReaped,);
3482 });
3483 }
3484
3485 #[test]
3486 fn try_reap_fail_not_dead() {
3487 xp_test_ext().execute_with(|| {
3488 System::set_block_number(2);
3489 Pallet::new_xp(&ALICE, &XP_ALPHA);
3490 assert_err!(Pallet::try_reap(&XP_ALPHA), Error::XpNotDead,);
3491 });
3492 }
3493
3494 #[test]
3495 fn try_reap_fail_lock_exists() {
3496 xp_test_ext().execute_with(|| {
3497 System::set_block_number(2);
3498 Pallet::new_xp(&ALICE, &XP_ALPHA);
3499 let idxp = ReserveId::new(STAKING, DEFAULT_POINTS);
3500 LockedXpOf::mutate(XP_ALPHA, |result| {
3501 let value = result
3502 .get_or_insert_with(|| BoundedVec::<LockId, VariantCountOf<Reason>>::default());
3503 value.try_push(idxp).unwrap();
3504 });
3505 XpOf::mutate(XP_ALPHA, |result| {
3506 let value = result.as_mut().unwrap();
3507 value.lock = value.lock.saturating_add(DEFAULT_POINTS);
3508 });
3509 assert!(LockedXpOf::contains_key(XP_ALPHA));
3510 System::set_block_number(6);
3511 System::set_block_number(10);
3512 System::set_block_number(12);
3513 Pallet::force_genesis_config(
3514 RuntimeOrigin::root(),
3515 ForceGenesisConfig::MinTimeStamp(10),
3516 )
3517 .unwrap();
3518 assert_err!(Pallet::try_reap(&XP_ALPHA), Error::CannotReapLockedXp,);
3519 });
3520 }
3521
3522 #[test]
3527 fn begin_xp_success_new_xp() {
3528 xp_test_ext().execute_with(|| {
3529 assert_err!(Pallet::xp_exists(&XP_ALPHA), Error::XpNotFound);
3530 Pallet::begin_xp(&ALICE, &XP_ALPHA, DEFAULT_POINTS).unwrap();
3531 assert_ok!(Pallet::xp_exists(&XP_ALPHA));
3532 });
3533 }
3534
3535 #[test]
3536 fn begin_xp_success_earn_xp() {
3537 xp_test_ext().execute_with(|| {
3538 Pallet::new_xp(&ALICE, &XP_ALPHA);
3539 assert_ok!(Pallet::begin_xp(&ALICE, &XP_ALPHA, DEFAULT_POINTS));
3540 });
3541 }
3542
3543 #[test]
3544 fn begin_xp_fail_reaped() {
3545 xp_test_ext().execute_with(|| {
3546 Pallet::new_xp(&ALICE, &XP_ALPHA);
3547 Pallet::reap_xp(&XP_ALPHA).unwrap();
3548 assert_err!(Pallet::xp_exists(&XP_ALPHA), Error::XpNotFound);
3549 assert_err!(
3550 Pallet::begin_xp(&ALICE, &XP_ALPHA, DEFAULT_POINTS),
3551 Error::XpAlreadyReaped
3552 );
3553 assert_err!(Pallet::xp_exists(&XP_ALPHA), Error::XpNotFound);
3554 });
3555 }
3556
3557 #[test]
3558 fn begin_xp_fail_already_reaped() {
3559 xp_test_ext().execute_with(|| {
3560 Pallet::new_xp(&ALICE, &XP_ALPHA);
3561 Pallet::reap_xp(&XP_ALPHA).unwrap();
3562 assert_err!(Pallet::xp_exists(&XP_ALPHA), Error::XpNotFound);
3563 Pallet::new_xp(&ALICE, &XP_ALPHA);
3564 assert_err!(
3565 Pallet::begin_xp(&ALICE, &XP_ALPHA, DEFAULT_POINTS),
3566 Error::XpAlreadyReaped
3567 );
3568 });
3569 }
3570
3571 #[test]
3576 fn increment_basic_success() {
3577 xp_test_ext().execute_with(|| {
3578 let mut accum = Accumulator::default();
3579 let stepper = Stepper::new(1000u32, 250u32).unwrap(); Pallet::increment(&mut accum, &stepper);
3581 assert_eq!(accum.value, 0);
3582 assert_eq!(accum.step, 250);
3583 Pallet::increment(&mut accum, &stepper);
3584 assert_eq!(accum.value, 0);
3585 assert_eq!(accum.step, 500);
3586 Pallet::increment(&mut accum, &stepper);
3587 assert_eq!(accum.value, 0);
3588 assert_eq!(accum.step, 750);
3589 Pallet::increment(&mut accum, &stepper);
3590 assert_eq!(accum.value, 1);
3591 assert_eq!(accum.step, 0);
3592 });
3593 }
3594
3595 #[test]
3596 fn increment_overflow_success() {
3597 xp_test_ext().execute_with(|| {
3598 let mut accum = Accumulator::default();
3599 let stepper = Stepper::new(1000u32, 350u32).unwrap();
3600 Pallet::increment(&mut accum, &stepper);
3601 assert_eq!(accum.value, 0);
3602 assert_eq!(accum.step, 350);
3603 Pallet::increment(&mut accum, &stepper);
3604 assert_eq!(accum.value, 0);
3605 assert_eq!(accum.step, 700);
3606
3607 Pallet::increment(&mut accum, &stepper);
3608 assert_eq!(accum.value, 1);
3609 assert_eq!(accum.step, 50);
3610 });
3611 }
3612
3613 #[test]
3614 fn decrement_basic_success() {
3615 xp_test_ext().execute_with(|| {
3616 let mut accum = Accumulator {
3617 value: 2,
3618 step: 300,
3619 };
3620 let stepper = Stepper::new(1000u32, 200u32).unwrap();
3621 Pallet::decrement(&mut accum, &stepper);
3622 assert_eq!(accum.value, 2);
3623 assert_eq!(accum.step, 100);
3624 });
3625 }
3626
3627 #[test]
3628 fn decrement_underflow_success() {
3629 xp_test_ext().execute_with(|| {
3630 let mut accum = Accumulator { value: 2, step: 0 };
3631 let stepper = Stepper::new(1000u32, 200u32).unwrap(); Pallet::decrement(&mut accum, &stepper);
3633 assert_eq!(accum.value, 1);
3634 assert_eq!(accum.step, 800);
3635 });
3636 }
3637
3638 #[test]
3639 fn new_frac_fail() {
3640 xp_test_ext().execute_with(|| {
3641 assert!(Stepper::new(100u32, 150u32).is_none());
3642 });
3643 }
3644}