1use crate::{
37 types::{LockReason, ReserveReason, XpId, XpValue},
38 Config, Error, Pallet, XpOf,
39};
40
41use frame_suite::xp::{XpLock, XpMutate, XpReserve, XpSystem};
43
44use frame_support::{
46 ensure,
47 traits::{
48 fungible::{
49 Dust, Inspect, InspectFreeze, InspectHold, Mutate, MutateFreeze, MutateHold,
50 Unbalanced, UnbalancedHold,
51 },
52 tokens::{
53 DepositConsequence, Fortitude, Precision, Preservation, Provenance, WithdrawConsequence,
54 },
55 },
56};
57
58use sp_runtime::{
60 traits::{CheckedAdd, CheckedSub, Saturating, Zero},
61 DispatchError, DispatchResult, TokenError,
62};
63
64impl<T: Config<I>, I: 'static> Inspect<XpId<T>> for Pallet<T, I> {
69 type Balance = XpValue<T, I>;
70
71 fn total_issuance() -> Self::Balance {
86 panic!("Cannot determine total_issuance if Fungible methods are derived from Xp");
87 }
88
89 fn minimum_balance() -> Self::Balance {
104 Self::Balance::zero()
105 }
106
107 fn total_balance(who: &XpId<T>) -> Self::Balance {
122 let Ok(total_balance) = <Pallet<T, I>>::get_usable_xp(who) else {
123 return Self::Balance::zero();
124 };
125 total_balance
126 }
127
128 fn balance(who: &XpId<T>) -> Self::Balance {
142 let Ok(balance) = Self::get_liquid_xp(who) else {
143 return Self::Balance::zero();
144 };
145 balance
146 }
147
148 #[inline]
161 fn reducible_balance(
162 who: &XpId<T>,
163 _preservation: Preservation,
164 _force: Fortitude,
165 ) -> Self::Balance {
166 Self::balance(who)
167 }
168
169 fn can_deposit(
186 who: &XpId<T>,
187 amount: Self::Balance,
188 provenance: Provenance,
189 ) -> DepositConsequence {
190 if Self::xp_exists(who).is_err() {
191 return DepositConsequence::UnknownAsset;
192 }
193 if amount.is_zero() {
194 return DepositConsequence::Success;
195 }
196 if provenance == Provenance::Minted {
197 return DepositConsequence::Blocked;
198 }
199 let balance = Self::balance(who);
200 if balance.checked_add(&amount).is_none() {
201 return DepositConsequence::Overflow;
202 }
203 DepositConsequence::Success
204 }
205
206 fn can_withdraw(who: &XpId<T>, amount: Self::Balance) -> WithdrawConsequence<Self::Balance> {
216 if Self::xp_exists(who).is_err() {
217 return WithdrawConsequence::UnknownAsset;
218 }
219 if amount.is_zero() {
220 return WithdrawConsequence::Success;
221 }
222 let balance = Self::balance(who);
223 if amount > balance {
224 return WithdrawConsequence::BalanceLow;
225 }
226 WithdrawConsequence::Success
227 }
228
229 fn active_issuance() -> Self::Balance {
243 panic!("Cannot determine active_issuance if Fungible methods are derived from Xp");
244 }
245}
246
247impl<T: Config<I>, I: 'static> Unbalanced<XpId<T>> for Pallet<T, I> {
252 fn handle_dust(_dust: Dust<XpId<T>, Self>) {}
258
259 fn write_balance(
265 who: &XpId<T>,
266 amount: Self::Balance,
267 ) -> Result<Option<Self::Balance>, DispatchError> {
268 Self::set_xp(who, amount)?;
269 Ok(None)
270 }
271
272 fn set_total_issuance(_amount: Self::Balance) {}
276
277 fn handle_raw_dust(_amount: Self::Balance) {}
280
281 fn increase_balance(
289 who: &XpId<T>,
290 amount: Self::Balance,
291 precision: Precision,
292 ) -> Result<Self::Balance, DispatchError> {
293 Self::xp_exists(who)?;
294 let current_balance = Self::balance(who);
295 let increased_balance = match precision {
296 Precision::BestEffort => current_balance.saturating_add(amount),
297 Precision::Exact => current_balance
298 .checked_add(&amount)
299 .ok_or(Error::<T, I>::XpCapOverflowed)?,
300 };
301 let result = Self::write_balance(who, increased_balance);
302 debug_assert!(
303 result.is_ok(),
304 "xp-key {who:?} exists but fungible's increase balance
305 throws error, for writing balance {increased_balance:?}, where current balance {current_balance:?}"
306 );
307 result?;
308 let imbalance = increased_balance.saturating_sub(current_balance);
309 Ok(imbalance)
310 }
311
312 fn decrease_balance(
322 who: &XpId<T>,
323 mut amount: Self::Balance,
324 precision: Precision,
325 preservation: Preservation,
326 force: Fortitude,
327 ) -> Result<Self::Balance, DispatchError> {
328 Self::xp_exists(who)?;
329 let reducible_balance = Self::reducible_balance(who, preservation, force);
330 let decreased_balance = match precision {
331 Precision::BestEffort => {
332 amount = amount.min(reducible_balance);
333 reducible_balance.saturating_sub(amount)
334 }
335 Precision::Exact => reducible_balance
336 .checked_sub(&amount)
337 .ok_or(Error::<T, I>::XpCapUnderflowed)?,
338 };
339 let result = Self::write_balance(who, decreased_balance);
340 debug_assert!(
341 result.is_ok(),
342 "xp-key {who:?} exists but fungible's decrease balance
343 throws error, for writing balance {decreased_balance:?}, where reducible balance {reducible_balance:?}"
344 );
345 result?;
346 let imbalance = reducible_balance.saturating_sub(decreased_balance);
347 Ok(imbalance)
348 }
349
350 fn deactivate(_: Self::Balance) {}
353
354 fn reactivate(_: Self::Balance) {}
357}
358
359impl<T: Config<I>, I: 'static> Mutate<XpId<T>> for Pallet<T, I> {
364 fn mint_into(who: &XpId<T>, amount: Self::Balance) -> Result<Self::Balance, DispatchError> {
377 let actual = Self::increase_balance(who, amount, Precision::Exact)?;
378 Self::done_mint_into(who, amount);
379 Ok(actual)
380 }
381
382 fn burn_from(
389 who: &XpId<T>,
390 amount: Self::Balance,
391 preservation: Preservation,
392 precision: Precision,
393 force: Fortitude,
394 ) -> Result<Self::Balance, DispatchError> {
395 let actual = Self::reducible_balance(who, preservation, force).min(amount);
396 ensure!(
397 actual == amount || precision == Precision::BestEffort,
398 TokenError::FundsUnavailable
399 );
400 let actual =
401 Self::decrease_balance(who, actual, Precision::BestEffort, preservation, force);
402 debug_assert!(
403 actual.is_ok(),
404 "xp-key {who:?} tried burning {amount:?} from reducible balance {actual:?} with
405 BestEffort precision, yet-failed"
406 );
407 let actual = actual?;
408 Self::done_burn_from(who, actual);
409 Ok(actual)
410 }
411
412 fn shelve(who: &XpId<T>, amount: Self::Balance) -> Result<Self::Balance, DispatchError> {
417 let actual =
418 Self::reducible_balance(who, Preservation::Expendable, Fortitude::Polite).min(amount);
419 frame_support::ensure!(actual == amount, TokenError::FundsUnavailable);
420 let actual = Self::decrease_balance(
421 who,
422 actual,
423 Precision::BestEffort,
424 Preservation::Expendable,
425 Fortitude::Polite,
426 );
427 debug_assert!(
428 actual.is_ok(),
429 "xp-key {who:?} tried shelving (burning) {amount:?} from reducible balance {actual:?} with
430 BestEffort precision, yet-failed"
431 );
432 let actual = actual?;
433 Ok(actual)
434 }
435
436 fn restore(who: &XpId<T>, amount: Self::Balance) -> Result<Self::Balance, DispatchError> {
442 let actual = Self::increase_balance(who, amount, Precision::Exact)?;
443 Ok(actual)
444 }
445
446 fn transfer(
450 _source: &XpId<T>,
451 _dest: &XpId<T>,
452 _amount: Self::Balance,
453 _preservation: Preservation,
454 ) -> Result<Self::Balance, DispatchError> {
455 Err(Error::<T, I>::CannotTransferXp.into())
456 }
457
458 fn set_balance(who: &XpId<T>, amount: Self::Balance) -> Self::Balance {
463 if Self::xp_exists(who).is_err() {
464 return Self::Balance::zero();
465 }
466 let _ = XpOf::<T, I>::mutate(who, |result| -> DispatchResult {
467 let value = result.as_mut();
468 debug_assert!(
469 value.is_some(),
470 "xp-key {who:?} exists but meta unaccesssible for
471 setting new liquid balance {amount:?}"
472 );
473
474 let value = value.ok_or(Error::<T, I>::XpNotFound)?;
475 value.free = amount;
476 Ok(())
477 });
478 Self::balance(who)
479 }
480
481 #[inline]
485 fn done_burn_from(who: &XpId<T>, amount: Self::Balance) {
486 Self::on_xp_update(who, amount);
487 }
488
489 #[inline]
493 fn done_mint_into(who: &XpId<T>, amount: Self::Balance) {
494 Self::on_xp_update(who, amount);
495 }
496
497 #[inline]
501 fn done_restore(who: &XpId<T>, amount: Self::Balance) {
502 Self::on_xp_update(who, amount);
503 }
504
505 #[inline]
509 fn done_shelve(who: &XpId<T>, amount: Self::Balance) {
510 Self::on_xp_update(who, amount);
511 }
512
513 fn done_transfer(_source: &XpId<T>, _dest: &XpId<T>, _amount: Self::Balance) {}
515}
516
517impl<T: Config<I>, I: 'static> InspectHold<XpId<T>> for Pallet<T, I> {
522 type Reason = ReserveReason<T, I>;
524
525 fn total_balance_on_hold(who: &XpId<T>) -> Self::Balance {
533 if Self::has_reserve(who).is_err() {
534 return Self::Balance::zero();
535 }
536 let total_reserved = Self::total_reserved(who);
537 debug_assert!(
538 total_reserved.is_ok(),
539 "xp-key {who:?} has reserves but cannot get its total-reserve"
540 );
541 let Ok(on_hold) = total_reserved else {
542 return Self::Balance::zero();
543 };
544 on_hold
545 }
546
547 fn balance_on_hold(reason: &Self::Reason, who: &XpId<T>) -> Self::Balance {
556 if Self::reserve_exists(who, reason).is_err() {
557 return Self::Balance::zero();
558 }
559 let reserve_of = Self::get_reserve_xp(who, reason);
560 debug_assert!(
561 reserve_of.is_ok(),
562 "xp-key {who:?} reserve of reason {reason:?} exists but cannot get its value"
563 );
564 let Ok(on_hold) = reserve_of else {
565 return Self::Balance::zero();
566 };
567 on_hold
568 }
569}
570
571impl<T: Config<I>, I: 'static> InspectFreeze<XpId<T>> for Pallet<T, I> {
576 type Id = LockReason<T, I>;
577
578 fn balance_frozen(id: &Self::Id, who: &XpId<T>) -> Self::Balance {
582 if Self::lock_exists(who, id).is_err() {
583 return Self::Balance::zero();
584 }
585 let lock_of = Self::get_lock_xp(who, id);
586 debug_assert!(
587 lock_of.is_ok(),
588 "xp-key {who:?} lock of reason {id:?} exists but cannot get its value"
589 );
590 let Ok(frozen) = lock_of else {
591 return Self::Balance::zero();
592 };
593 frozen
594 }
595
596 fn can_freeze(id: &Self::Id, who: &XpId<T>) -> bool {
604 if Self::xp_exists(who).is_err() {
605 return false;
606 }
607 if Self::lock_exists(who, id).is_ok() {
608 return false;
609 }
610 true
611 }
612}
613
614impl<T: Config<I>, I: 'static> UnbalancedHold<XpId<T>> for Pallet<T, I> {
619 fn set_balance_on_hold(
630 reason: &Self::Reason,
631 who: &XpId<T>,
632 amount: Self::Balance,
633 ) -> DispatchResult {
634 if Self::reserve_exists(who, reason).is_err() && amount.is_zero() {
635 return Ok(());
636 }
637 Self::set_reserve(who, reason, amount)?;
640 Ok(())
641 }
642}
643
644impl<T: Config<I>, I: 'static> MutateFreeze<XpId<T>> for Pallet<T, I> {
649 fn set_freeze(id: &Self::Id, who: &XpId<T>, amount: Self::Balance) -> DispatchResult {
660 if Self::lock_exists(who, id).is_ok() && amount.is_zero() {
661 Self::thaw(id, who)?;
662 return Ok(());
663 }
664 Self::set_lock(who, id, amount)?;
667 Ok(())
668 }
669
670 fn extend_freeze(id: &Self::Id, who: &XpId<T>, amount: Self::Balance) -> DispatchResult {
678 if amount.is_zero() {
679 return Ok(());
680 }
681 let freeze_balance = Self::get_lock_xp(who, id)?;
682 let extend_amount = freeze_balance.max(amount);
683
684 Self::set_lock(who, id, extend_amount)?;
687 Ok(())
688 }
689
690 fn thaw(id: &Self::Id, who: &XpId<T>) -> DispatchResult {
697 Self::xp_exists(who)?;
698 Self::burn_lock(who, id)?;
699 Ok(())
700 }
701
702 fn increase_frozen(id: &Self::Id, who: &XpId<T>, amount: Self::Balance) -> DispatchResult {
705 let a = Self::balance_frozen(id, who)
706 .checked_add(&amount)
707 .ok_or(Error::<T, I>::XpCapOverflowed)?;
708 Self::set_frozen(id, who, a, Fortitude::Force)
709 }
710}
711
712impl<T: Config<I>, I: 'static> MutateHold<XpId<T>> for Pallet<T, I> {}
717
718#[cfg(test)]
725pub mod tests {
726
727 use crate::mock::*;
733
734 use frame_suite::xp::{XpLock, XpMutate, XpReserve, XpSystem};
736
737 use frame_support::{
739 assert_err, assert_ok,
740 traits::{
741 fungible::{
742 Inspect, InspectFreeze, InspectHold, Mutate, MutateFreeze, Unbalanced,
743 UnbalancedHold,
744 },
745 tokens::{
746 DepositConsequence, Fortitude, Precision, Preservation, Provenance,
747 WithdrawConsequence,
748 },
749 },
750 };
751
752 use sp_runtime::TokenError;
754
755 #[test]
760 #[should_panic]
761 fn total_issuance_panic() {
762 xp_test_ext().execute_with(|| {
763 Pallet::total_issuance();
764 });
765 }
766
767 #[test]
768 fn minimum_balance_success() {
769 xp_test_ext().execute_with(|| {
770 let actual = Pallet::minimum_balance();
771 let expected = 0;
772 assert_eq!(expected, actual);
773 });
774 }
775
776 #[test]
777 fn total_balance_fail_uninitalized_xp() {
778 xp_test_ext().execute_with(|| {
779 let actual = Pallet::total_balance(&ALICE);
780 let expected = 0;
781 assert_eq!(expected, actual);
782 });
783 }
784
785 #[test]
786 fn total_balance_success() {
787 xp_test_ext().execute_with(|| {
788 Pallet::new_xp(&ALICE, &XP_ALPHA);
789 Pallet::set_reserve(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
790 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
791 let expected_total_balance = xp.free + xp.reserve;
792 let actual_total_balance = Pallet::total_balance(&XP_ALPHA);
793 assert_eq!(expected_total_balance, actual_total_balance);
794 });
795 }
796
797 #[test]
798 fn balance_success() {
799 xp_test_ext().execute_with(|| {
800 Pallet::new_xp(&ALICE, &XP_ALPHA);
801 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
802 let expected_balance = xp.free;
803 let actual_balance = Pallet::balance(&XP_ALPHA);
804 assert_eq!(expected_balance, actual_balance);
805 });
806 }
807
808 #[test]
809 fn balance_fail_uninitialized() {
810 xp_test_ext().execute_with(|| {
811 let actual = Pallet::balance(&ALICE);
812 let expected = 0;
813 assert_eq!(expected, actual);
814 });
815 }
816
817 #[test]
818 fn reducible_balance_success() {
819 xp_test_ext().execute_with(|| {
820 Pallet::new_xp(&ALICE, &XP_ALPHA);
821 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
822 let expected_liquid = xp.free;
823 let actual_reducible =
824 Pallet::reducible_balance(&XP_ALPHA, Preservation::Expendable, Fortitude::Polite);
825 assert_eq!(expected_liquid, actual_reducible);
826 });
827 }
828
829 #[test]
830 fn reducible_balance_fail_uninitialized() {
831 xp_test_ext().execute_with(|| {
832 let actual_reducible =
833 Pallet::reducible_balance(&ALICE, Preservation::Expendable, Fortitude::Polite);
834 let expected_liquid = 0;
835 assert_eq!(expected_liquid, actual_reducible);
836 });
837 }
838
839 #[test]
840 fn can_deposit_success() {
841 xp_test_ext().execute_with(|| {
842 Pallet::new_xp(&ALICE, &XP_ALPHA);
843 assert_eq!(
844 Pallet::can_deposit(&ALICE, DEFAULT_POINTS, Provenance::Extant),
845 DepositConsequence::Success
846 )
847 });
848 }
849
850 #[test]
851 fn can_deposit_success_with_zero() {
852 xp_test_ext().execute_with(|| {
853 Pallet::new_xp(&ALICE, &XP_ALPHA);
854 assert_eq!(
855 Pallet::can_deposit(&ALICE, INVALID_POINTS, Provenance::Extant),
856 DepositConsequence::Success
857 )
858 });
859 }
860
861 #[test]
862 fn can_deposit_fail_uninitialized_xp() {
863 xp_test_ext().execute_with(|| {
864 assert_eq!(
865 Pallet::can_deposit(&ALICE, DEFAULT_POINTS, Provenance::Extant),
866 DepositConsequence::UnknownAsset
867 )
868 });
869 }
870
871 #[test]
872 fn can_deposit_fail_overflow() {
873 xp_test_ext().execute_with(|| {
874 Pallet::new_xp(&ALICE, &XP_ALPHA);
875 assert_eq!(
876 Pallet::can_deposit(&ALICE, SATURATED_MAX, Provenance::Extant),
877 DepositConsequence::Overflow
878 )
879 });
880 }
881
882 #[test]
883 fn can_deposit_fail_minted() {
884 xp_test_ext().execute_with(|| {
885 Pallet::new_xp(&ALICE, &XP_ALPHA);
886 assert_eq!(
887 Pallet::can_deposit(&ALICE, DEFAULT_POINTS, Provenance::Minted),
888 DepositConsequence::Blocked
889 )
890 });
891 }
892
893 #[test]
894 fn can_withdraw_success() {
895 xp_test_ext().execute_with(|| {
896 Pallet::new_xp(&ALICE, &XP_ALPHA);
897 assert_eq!(
898 Pallet::can_withdraw(&ALICE, DEFAULT_POINTS),
899 WithdrawConsequence::Success
900 )
901 });
902 }
903
904 #[test]
905 fn can_withdraw_success_with_zero() {
906 xp_test_ext().execute_with(|| {
907 Pallet::new_xp(&ALICE, &XP_ALPHA);
908 assert_eq!(
909 Pallet::can_withdraw(&ALICE, INVALID_POINTS),
910 WithdrawConsequence::Success
911 )
912 });
913 }
914
915 #[test]
916 fn can_withdraw_fail_uninitialized_xp() {
917 xp_test_ext().execute_with(|| {
918 assert_eq!(
919 Pallet::can_withdraw(&ALICE, DEFAULT_POINTS),
920 WithdrawConsequence::UnknownAsset
921 )
922 });
923 }
924
925 #[test]
926 fn can_withdraw_fail_low_balance() {
927 xp_test_ext().execute_with(|| {
928 Pallet::new_xp(&ALICE, &XP_ALPHA);
929 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
930 let available_liquid = xp.free;
931 assert_eq!(available_liquid, DEFAULT_POINTS);
932 let withdraw_amount = 20;
933 assert_eq!(
934 Pallet::can_withdraw(&ALICE, withdraw_amount),
935 WithdrawConsequence::BalanceLow
936 )
937 });
938 }
939
940 #[test]
941 #[should_panic]
942 fn active_issuance_panic() {
943 xp_test_ext().execute_with(|| {
944 Pallet::active_issuance();
945 });
946 }
947
948 #[test]
953 fn write_balance_success() {
954 xp_test_ext().execute_with(|| {
955 Pallet::new_xp(&ALICE, &XP_ALPHA);
956 let xp = Pallet::get_xp(&ALICE).unwrap();
957 let free_before = xp.free;
958 assert_eq!(free_before, 10);
959 let new_balance = 50;
960 assert_ok!(Pallet::write_balance(&ALICE, new_balance));
961 let xp = Pallet::get_xp(&ALICE).unwrap();
962 let free_after = xp.free;
963 assert_eq!(free_after, 50);
964 });
965 }
966
967 #[test]
968 fn write_balance_fail_uninitalized_xp() {
969 xp_test_ext().execute_with(|| {
970 assert_err!(
971 Pallet::write_balance(&ALICE, DEFAULT_POINTS),
972 Error::XpNotFound
973 )
974 });
975 }
976
977 #[test]
978 fn increase_balance_success_besteffort() {
979 xp_test_ext().execute_with(|| {
980 Pallet::new_xp(&ALICE, &XP_ALPHA);
981 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
982 let balance_before = xp.free;
983 assert_eq!(balance_before, 10);
984 let increment_amount = 20;
985 let imbalance =
986 Pallet::increase_balance(&XP_ALPHA, increment_amount, Precision::BestEffort)
987 .unwrap();
988 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
989 let balance_after = xp.free;
990 let expected_balace = balance_before.saturating_add(increment_amount);
991 let expected_imbalance = balance_after.saturating_sub(balance_before);
992 assert_eq!(expected_imbalance, imbalance);
993 assert_eq!(expected_balace, balance_after);
994 });
995 }
996
997 #[test]
998 fn increase_balance_success_exact() {
999 xp_test_ext().execute_with(|| {
1000 Pallet::new_xp(&ALICE, &XP_ALPHA);
1001 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
1002 let balance_before = xp.free;
1003 assert_eq!(balance_before, 10);
1004 let increment_amount = 20;
1005 let imbalance =
1006 Pallet::increase_balance(&XP_ALPHA, increment_amount, Precision::Exact).unwrap();
1007 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
1008 let balance_after = xp.free;
1009 let expected_balace = balance_before.saturating_add(increment_amount);
1010 let expected_imbalance = balance_after.saturating_sub(balance_before);
1011 assert_eq!(expected_imbalance, imbalance);
1012 assert_eq!(expected_balace, balance_after);
1013 });
1014 }
1015
1016 #[test]
1017 fn increase_balance_handle_exact_overflow() {
1018 xp_test_ext().execute_with(|| {
1019 Pallet::new_xp(&ALICE, &XP_ALPHA);
1020 assert_err!(
1021 Pallet::increase_balance(&XP_ALPHA, SATURATED_MAX, Precision::Exact),
1022 Error::XpCapOverflowed
1023 )
1024 });
1025 }
1026
1027 #[test]
1028 fn increase_balance_handle_besteffort_saturating() {
1029 xp_test_ext().execute_with(|| {
1030 Pallet::new_xp(&ALICE, &XP_ALPHA);
1031 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
1032 let balance_before = xp.free;
1033 assert_eq!(balance_before, 10);
1034 let imbalance =
1035 Pallet::increase_balance(&XP_ALPHA, SATURATED_MAX, Precision::BestEffort).unwrap();
1036 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
1037 let balance_after = xp.free;
1038 let expected_imbalance = balance_after.saturating_sub(balance_before);
1039 assert_eq!(expected_imbalance, imbalance);
1040 assert_eq!(balance_after, SATURATED_MAX);
1041 });
1042 }
1043
1044 #[test]
1045 fn increase_balance_fail_uninitialized_xp() {
1046 xp_test_ext().execute_with(|| {
1047 assert_err!(
1048 Pallet::increase_balance(&XP_ALPHA, DEFAULT_POINTS, Precision::Exact),
1049 Error::XpNotFound
1050 )
1051 });
1052 }
1053
1054 #[test]
1055 fn decrease_balance_success_besteffort() {
1056 xp_test_ext().execute_with(|| {
1057 Pallet::new_xp(&ALICE, &XP_ALPHA);
1058 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
1059 let balance_before = xp.free;
1060 assert_eq!(balance_before, 10);
1061 let decrement_amount = 5;
1062 let imbalance = Pallet::decrease_balance(
1063 &XP_ALPHA,
1064 decrement_amount,
1065 Precision::BestEffort,
1066 Preservation::Expendable,
1067 Fortitude::Polite,
1068 )
1069 .unwrap();
1070 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
1071 let balance_after = xp.free;
1072 let expected_balace = balance_before.saturating_sub(decrement_amount);
1073 let expected_imbalance = balance_before.saturating_sub(balance_after);
1074 assert_eq!(expected_imbalance, imbalance);
1075 assert_eq!(expected_balace, balance_after);
1076 });
1077 }
1078
1079 #[test]
1080 fn decrease_balance_success_exact() {
1081 xp_test_ext().execute_with(|| {
1082 Pallet::new_xp(&ALICE, &XP_ALPHA);
1083 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
1084 let balance_before = xp.free;
1085 assert_eq!(balance_before, 10);
1086 let decrement_amount = 5;
1087 let imbalance = Pallet::decrease_balance(
1088 &XP_ALPHA,
1089 decrement_amount,
1090 Precision::Exact,
1091 Preservation::Expendable,
1092 Fortitude::Polite,
1093 )
1094 .unwrap();
1095 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
1096 let balance_after = xp.free;
1097 let expected_balace = balance_before.saturating_sub(decrement_amount);
1098 let expected_imbalance = balance_before.saturating_sub(balance_after);
1099 assert_eq!(expected_imbalance, imbalance);
1100 assert_eq!(expected_balace, balance_after);
1101 });
1102 }
1103
1104 #[test]
1105 fn decrease_balance_handle_exact_underflow() {
1106 xp_test_ext().execute_with(|| {
1107 Pallet::new_xp(&ALICE, &XP_ALPHA);
1108 assert_err!(
1109 Pallet::decrease_balance(
1110 &XP_ALPHA,
1111 SATURATED_MAX,
1112 Precision::Exact,
1113 Preservation::Expendable,
1114 Fortitude::Polite
1115 ),
1116 Error::XpCapUnderflowed
1117 )
1118 });
1119 }
1120
1121 #[test]
1122 fn decrease_balance_handle_besteffort_saturating() {
1123 xp_test_ext().execute_with(|| {
1124 Pallet::new_xp(&ALICE, &XP_ALPHA);
1125 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
1126 let balance_before = xp.free;
1127 assert_eq!(balance_before, 10);
1128 let imbalance = Pallet::decrease_balance(
1129 &XP_ALPHA,
1130 SATURATED_MAX,
1131 Precision::BestEffort,
1132 Preservation::Expendable,
1133 Fortitude::Polite,
1134 )
1135 .unwrap();
1136 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
1137 let balance_after = xp.free;
1138 let expected_imbalance = balance_before.saturating_sub(balance_after);
1139 assert_eq!(expected_imbalance, imbalance);
1140 assert_eq!(balance_after, 0);
1141 });
1142 }
1143
1144 #[test]
1145 fn decrease_balance_fail_uninitialized_xp() {
1146 xp_test_ext().execute_with(|| {
1147 assert_err!(
1148 Pallet::decrease_balance(
1149 &XP_ALPHA,
1150 DEFAULT_POINTS,
1151 Precision::Exact,
1152 Preservation::Expendable,
1153 Fortitude::Polite
1154 ),
1155 Error::XpNotFound
1156 )
1157 });
1158 }
1159
1160 #[test]
1165 fn mint_into_success() {
1166 xp_test_ext().execute_with(|| {
1167 Pallet::new_xp(&ALICE, &XP_ALPHA);
1168 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
1169 let balance_before = xp.free;
1170 System::set_block_number(2);
1171 let minted = Pallet::mint_into(&XP_ALPHA, DEFAULT_POINTS).unwrap();
1172 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
1173 let balance_after = xp.free;
1174 let balance_expected = balance_before.saturating_add(DEFAULT_POINTS);
1175 let expected_minted = balance_after.saturating_sub(balance_before);
1176 assert_eq!(balance_expected, balance_after);
1177 assert_eq!(expected_minted, minted);
1178 System::assert_last_event(
1179 Event::Xp {
1180 id: XP_ALPHA,
1181 xp: minted,
1182 }
1183 .into(),
1184 );
1185 });
1186 }
1187
1188 #[test]
1189 fn mint_into_uninitialized_xp() {
1190 xp_test_ext().execute_with(|| {
1191 assert_err!(
1192 Pallet::mint_into(&XP_ALPHA, DEFAULT_POINTS),
1193 Error::XpNotFound
1194 );
1195 });
1196 }
1197
1198 #[test]
1199 fn mint_into_fail_overflow() {
1200 xp_test_ext().execute_with(|| {
1201 Pallet::new_xp(&ALICE, &XP_ALPHA);
1202 assert_err!(
1203 Pallet::mint_into(&XP_ALPHA, SATURATED_MAX),
1204 Error::XpCapOverflowed
1205 )
1206 });
1207 }
1208
1209 #[test]
1210 fn burn_from_success() {
1211 xp_test_ext().execute_with(|| {
1212 Pallet::new_xp(&ALICE, &XP_ALPHA);
1213 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
1214 let balance_before = xp.free;
1215 System::set_block_number(2);
1216 let burn_amount = 5;
1217 let burned = Pallet::burn_from(
1218 &XP_ALPHA,
1219 burn_amount,
1220 Preservation::Expendable,
1221 Precision::BestEffort,
1222 Fortitude::Polite,
1223 )
1224 .unwrap();
1225 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
1226 let balance_after = xp.free;
1227 let expected_balance = balance_before.saturating_sub(balance_after);
1228 assert_eq!(expected_balance, balance_after);
1229 assert_eq!(burned, burn_amount);
1230 System::assert_last_event(
1231 Event::Xp {
1232 id: XP_ALPHA,
1233 xp: burned,
1234 }
1235 .into(),
1236 );
1237 });
1238 }
1239
1240 #[test]
1241 fn burn_from_fail_funds_unavailable() {
1242 xp_test_ext().execute_with(|| {
1243 Pallet::new_xp(&ALICE, &XP_ALPHA);
1244 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
1245 let balance_before = xp.free;
1246 assert_eq!(balance_before, 10);
1247 System::set_block_number(2);
1248 let burn_amount = 20;
1249 assert_err!(
1250 Pallet::burn_from(
1251 &XP_ALPHA,
1252 burn_amount,
1253 Preservation::Expendable,
1254 Precision::Exact,
1255 Fortitude::Polite
1256 ),
1257 TokenError::FundsUnavailable
1258 )
1259 });
1260 }
1261
1262 #[test]
1263 fn shelve_success() {
1264 xp_test_ext().execute_with(|| {
1265 Pallet::new_xp(&ALICE, &XP_ALPHA);
1266 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
1267 let balance_before = xp.free;
1268 let shelve_amount = 5;
1269 let shelved = Pallet::shelve(&XP_ALPHA, shelve_amount).unwrap();
1270 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
1271 let balance_after = xp.free;
1272 let expected_balance = balance_before.saturating_sub(balance_after);
1273 assert_eq!(expected_balance, balance_after);
1274 assert_eq!(shelve_amount, shelved);
1275 });
1276 }
1277
1278 #[test]
1279 fn shelve_fail_funds_unavailable() {
1280 xp_test_ext().execute_with(|| {
1281 Pallet::new_xp(&ALICE, &XP_ALPHA);
1282 let shelve_amount = 20;
1283 assert_err!(
1284 Pallet::shelve(&XP_ALPHA, shelve_amount),
1285 TokenError::FundsUnavailable
1286 );
1287 });
1288 }
1289
1290 #[test]
1291 fn restore_success() {
1292 xp_test_ext().execute_with(|| {
1293 Pallet::new_xp(&ALICE, &XP_ALPHA);
1294 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
1295 let balance_before = xp.free;
1296 let restore_amount = 15;
1297 let restored = Pallet::restore(&XP_ALPHA, restore_amount).unwrap();
1298 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
1299 let balance_after = xp.free;
1300 let expected_balance = balance_before.saturating_add(restore_amount);
1301 assert_eq!(expected_balance, balance_after);
1302 assert_eq!(restore_amount, restored);
1303 });
1304 }
1305
1306 #[test]
1307 fn restore_fail_uninitalized_xp() {
1308 xp_test_ext().execute_with(|| {
1309 assert_err!(
1310 Pallet::restore(&XP_ALPHA, DEFAULT_POINTS),
1311 Error::XpNotFound
1312 )
1313 });
1314 }
1315
1316 #[test]
1317 fn restore_fail_overflow() {
1318 xp_test_ext().execute_with(|| {
1319 Pallet::new_xp(&ALICE, &XP_ALPHA);
1320 assert_err!(
1321 Pallet::restore(&XP_ALPHA, SATURATED_MAX),
1322 Error::XpCapOverflowed
1323 )
1324 });
1325 }
1326
1327 #[test]
1328 fn transfer_failure_success() {
1329 xp_test_ext().execute_with(|| {
1330 assert_err!(
1331 Pallet::transfer(
1332 &XP_ALPHA,
1333 &XP_BETA,
1334 DEFAULT_POINTS,
1335 Preservation::Expendable
1336 ),
1337 Error::CannotTransferXp
1338 )
1339 });
1340 }
1341
1342 #[test]
1343 fn set_balance_success() {
1344 xp_test_ext().execute_with(|| {
1345 Pallet::new_xp(&ALICE, &XP_ALPHA);
1346 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
1347 let balance_before = xp.free;
1348 assert_eq!(balance_before, 10);
1349 let set_amount = 50;
1350 let new_balance = Pallet::set_balance(&XP_ALPHA, set_amount);
1351 let xp = Pallet::get_xp(&XP_ALPHA).unwrap();
1352 let balance_after = xp.free;
1353 assert_eq!(balance_after, set_amount);
1354 assert_eq!(balance_after, new_balance);
1355 });
1356 }
1357
1358 #[test]
1359 fn set_balance_uninitialized_xp() {
1360 xp_test_ext().execute_with(|| {
1361 let new_balance = Pallet::set_balance(&XP_ALPHA, DEFAULT_POINTS);
1362 let expected_balance = 0;
1363 assert_eq!(expected_balance, new_balance);
1364 });
1365 }
1366
1367 #[test]
1368 fn done_burn_from_success() {
1369 xp_test_ext().execute_with(|| {
1370 System::set_block_number(2);
1371 Pallet::done_burn_from(&XP_ALPHA, DEFAULT_POINTS);
1372 System::assert_last_event(
1373 Event::Xp {
1374 id: XP_ALPHA,
1375 xp: DEFAULT_POINTS,
1376 }
1377 .into(),
1378 );
1379 });
1380 }
1381
1382 #[test]
1383 fn done_mint_into_success() {
1384 xp_test_ext().execute_with(|| {
1385 System::set_block_number(2);
1386 Pallet::done_mint_into(&XP_ALPHA, DEFAULT_POINTS);
1387 System::assert_last_event(
1388 Event::Xp {
1389 id: XP_ALPHA,
1390 xp: DEFAULT_POINTS,
1391 }
1392 .into(),
1393 );
1394 });
1395 }
1396
1397 #[test]
1398 fn done_restore_success() {
1399 xp_test_ext().execute_with(|| {
1400 System::set_block_number(2);
1401 Pallet::done_restore(&XP_ALPHA, DEFAULT_POINTS);
1402 System::assert_last_event(
1403 Event::Xp {
1404 id: XP_ALPHA,
1405 xp: DEFAULT_POINTS,
1406 }
1407 .into(),
1408 );
1409 });
1410 }
1411
1412 #[test]
1413 fn done_shelve() {
1414 xp_test_ext().execute_with(|| {
1415 System::set_block_number(2);
1416 Pallet::done_shelve(&XP_ALPHA, DEFAULT_POINTS);
1417 System::assert_last_event(
1418 Event::Xp {
1419 id: XP_ALPHA,
1420 xp: DEFAULT_POINTS,
1421 }
1422 .into(),
1423 );
1424 });
1425 }
1426
1427 #[test]
1432 fn total_balance_on_hold_success() {
1433 xp_test_ext().execute_with(|| {
1434 Pallet::new_xp(&ALICE, &XP_ALPHA);
1435 let reserve_points_1 = 20;
1436 Pallet::set_reserve(&XP_ALPHA, &STAKING, reserve_points_1).unwrap();
1437 let reserve_points_2 = 30;
1438 Pallet::set_reserve(&XP_ALPHA, &GOVERNANCE, reserve_points_2).unwrap();
1439 let actual_total_hold = Pallet::total_balance_on_hold(&XP_ALPHA);
1440 let expected_total_hold = reserve_points_1 + reserve_points_2;
1441 assert_eq!(expected_total_hold, actual_total_hold);
1442 });
1443 }
1444
1445 #[test]
1446 fn total_balance_on_hold_uninitialized_xp() {
1447 xp_test_ext().execute_with(|| {
1448 let expected_hold = 0;
1449 assert_eq!(Pallet::total_balance_on_hold(&XP_ALPHA), expected_hold);
1450 });
1451 }
1452
1453 #[test]
1454 fn total_balance_on_hold_no_reserve() {
1455 xp_test_ext().execute_with(|| {
1456 Pallet::new_xp(&ALICE, &XP_ALPHA);
1457 let expected_hold = 0;
1458 assert_eq!(Pallet::total_balance_on_hold(&XP_ALPHA), expected_hold);
1459 });
1460 }
1461
1462 #[test]
1463 fn balance_on_hold_success() {
1464 xp_test_ext().execute_with(|| {
1465 Pallet::new_xp(&ALICE, &XP_ALPHA);
1466 let reserve_points = 30;
1467 Pallet::set_reserve(&XP_ALPHA, &STAKING, reserve_points).unwrap();
1468 let actual_hold = Pallet::balance_on_hold(&STAKING, &XP_ALPHA);
1469 let expected_hold = reserve_points;
1470 assert_eq!(expected_hold, actual_hold);
1471 });
1472 }
1473
1474 #[test]
1475 fn balance_on_hold_uninitialized_xp() {
1476 xp_test_ext().execute_with(|| {
1477 let expected_hold = 0;
1478 assert_eq!(Pallet::balance_on_hold(&STAKING, &XP_ALPHA), expected_hold);
1479 });
1480 }
1481
1482 #[test]
1483 fn balance_on_hold_no_reserve() {
1484 xp_test_ext().execute_with(|| {
1485 Pallet::new_xp(&ALICE, &XP_ALPHA);
1486 let expected_hold = 0;
1487 assert_eq!(Pallet::balance_on_hold(&STAKING, &XP_ALPHA), expected_hold);
1488 });
1489 }
1490
1491 #[test]
1496 fn balance_frozen_success() {
1497 xp_test_ext().execute_with(|| {
1498 Pallet::new_xp(&ALICE, &XP_ALPHA);
1499 let lock_points = 40;
1500 Pallet::set_lock(&XP_ALPHA, &STAKING, lock_points).unwrap();
1501 let frozen = Pallet::balance_frozen(&STAKING, &XP_ALPHA);
1502 assert_eq!(frozen, lock_points);
1503 });
1504 }
1505
1506 #[test]
1507 fn balance_frozen_uninitialized_xp() {
1508 xp_test_ext().execute_with(|| {
1509 let frozen = Pallet::balance_frozen(&STAKING, &XP_ALPHA);
1510 let expected_frozen = 0;
1511 assert_eq!(expected_frozen, frozen);
1512 });
1513 }
1514
1515 #[test]
1516 fn balance_frozen_no_lock() {
1517 xp_test_ext().execute_with(|| {
1518 Pallet::new_xp(&ALICE, &XP_ALPHA);
1519 let frozen = Pallet::balance_frozen(&STAKING, &XP_ALPHA);
1520 let expected_frozen = 0;
1521 assert_eq!(expected_frozen, frozen);
1522 });
1523 }
1524
1525 #[test]
1526 fn can_freeze_success() {
1527 xp_test_ext().execute_with(|| {
1528 Pallet::new_xp(&ALICE, &XP_ALPHA);
1529 assert!(Pallet::can_freeze(&STAKING, &XP_ALPHA));
1530 });
1531 }
1532
1533 #[test]
1534 fn can_freeze_fail_uninitialized_xp() {
1535 xp_test_ext().execute_with(|| {
1536 assert!(!Pallet::can_freeze(&STAKING, &XP_ALPHA));
1537 });
1538 }
1539
1540 #[test]
1541 fn can_freeze_fail_lock_exist() {
1542 xp_test_ext().execute_with(|| {
1543 Pallet::new_xp(&ALICE, &XP_ALPHA);
1544 Pallet::set_lock(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
1545 assert!(!Pallet::can_freeze(&STAKING, &XP_ALPHA));
1546 });
1547 }
1548
1549 #[test]
1554 fn set_balance_on_hold_success_on_zero() {
1555 xp_test_ext().execute_with(|| {
1556 Pallet::new_xp(&ALICE, &XP_ALPHA);
1557 let reserve_points = 0;
1558 assert_ok!(Pallet::set_balance_on_hold(
1559 &STAKING,
1560 &XP_ALPHA,
1561 reserve_points
1562 ));
1563 assert_err!(
1564 Pallet::reserve_exists(&XP_ALPHA, &STAKING),
1565 Error::XpReserveNotFound
1566 );
1567 });
1568 }
1569
1570 #[test]
1571 fn set_balance_on_hold_success_new() {
1572 xp_test_ext().execute_with(|| {
1573 Pallet::new_xp(&ALICE, &XP_ALPHA);
1574 let reserve_points = 40;
1575 Pallet::set_balance_on_hold(&STAKING, &XP_ALPHA, reserve_points).unwrap();
1576 let reserved = Pallet::get_reserve_xp(&XP_ALPHA, &STAKING).unwrap();
1577 assert_eq!(reserved, reserve_points);
1578 });
1579 }
1580
1581 #[test]
1582 fn set_balance_on_hold_success_mutate() {
1583 xp_test_ext().execute_with(|| {
1584 Pallet::new_xp(&ALICE, &XP_ALPHA);
1585 Pallet::set_reserve(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
1586 let existing_reserve_points = Pallet::get_reserve_xp(&XP_ALPHA, &STAKING).unwrap();
1587 assert_eq!(existing_reserve_points, 10);
1588 let new_reserve_points = 40;
1589 Pallet::set_balance_on_hold(&STAKING, &XP_ALPHA, new_reserve_points).unwrap();
1590 let new_reserved = Pallet::get_reserve_xp(&XP_ALPHA, &STAKING).unwrap();
1591 assert_eq!(new_reserved, new_reserve_points);
1592 });
1593 }
1594
1595 #[test]
1596 fn set_balance_on_hold_fail_mutate_overflow() {
1597 xp_test_ext().execute_with(|| {
1598 Pallet::new_xp(&ALICE, &XP_ALPHA);
1599 Pallet::set_reserve(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
1600 Pallet::set_reserve(&XP_ALPHA, &REASON_TREASURY, DEFAULT_POINTS).unwrap();
1601 assert_err!(
1602 Pallet::set_balance_on_hold(&STAKING, &XP_ALPHA, SATURATED_MAX),
1603 Error::XpReserveCapOverflowed
1604 )
1605 });
1606 }
1607
1608 #[test]
1609 fn set_balance_on_hold_fail_uninitialized_xp() {
1610 xp_test_ext().execute_with(|| {
1611 assert_err!(
1612 Pallet::set_balance_on_hold(&STAKING, &XP_ALPHA, DEFAULT_POINTS),
1613 Error::XpNotFound
1614 )
1615 });
1616 }
1617
1618 #[test]
1623 fn set_freeze_thaw_on_zero() {
1624 xp_test_ext().execute_with(|| {
1625 Pallet::new_xp(&ALICE, &XP_ALPHA);
1626 Pallet::set_lock(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
1627 assert_ok!(Pallet::lock_exists(&XP_ALPHA, &STAKING));
1628 let lock_points = 0;
1629 Pallet::set_freeze(&STAKING, &XP_ALPHA, lock_points).unwrap();
1630 assert_err!(
1631 Pallet::lock_exists(&XP_ALPHA, &STAKING),
1632 Error::XpLockNotFound
1633 );
1634 });
1635 }
1636
1637 #[test]
1638 fn set_freeze_fail_on_zero() {
1639 xp_test_ext().execute_with(|| {
1640 Pallet::new_xp(&ALICE, &XP_ALPHA);
1641 assert_err!(
1642 Pallet::set_freeze(&STAKING, &XP_ALPHA, INVALID_POINTS),
1643 Error::CannotLockZero,
1644 );
1645 assert_err!(
1646 Pallet::lock_exists(&XP_ALPHA, &STAKING),
1647 Error::XpLockNotFound
1648 );
1649 });
1650 }
1651
1652 #[test]
1653 fn set_freeze_success_new() {
1654 xp_test_ext().execute_with(|| {
1655 Pallet::new_xp(&ALICE, &XP_ALPHA);
1656 let lock_points = 40;
1657 Pallet::set_freeze(&STAKING, &XP_ALPHA, lock_points).unwrap();
1658 let locked = Pallet::get_lock_xp(&XP_ALPHA, &STAKING).unwrap();
1659 assert_eq!(locked, lock_points);
1660 });
1661 }
1662
1663 #[test]
1664 fn set_freeze_success_mutate() {
1665 xp_test_ext().execute_with(|| {
1666 Pallet::new_xp(&ALICE, &XP_ALPHA);
1667 Pallet::set_lock(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
1668 let existing_lock_points = Pallet::get_lock_xp(&XP_ALPHA, &STAKING).unwrap();
1669 assert_eq!(existing_lock_points, 10);
1670 let new_lock_points = 40;
1671 Pallet::set_freeze(&STAKING, &XP_ALPHA, new_lock_points).unwrap();
1672 let new_locked = Pallet::get_lock_xp(&XP_ALPHA, &STAKING).unwrap();
1673 assert_eq!(new_locked, new_lock_points);
1674 });
1675 }
1676
1677 #[test]
1678 fn set_freeze_fail_mutate_overflow() {
1679 xp_test_ext().execute_with(|| {
1680 Pallet::new_xp(&ALICE, &XP_ALPHA);
1681 Pallet::set_lock(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
1682 Pallet::set_lock(&XP_ALPHA, &REASON_TREASURY, DEFAULT_POINTS).unwrap();
1683 assert_err!(
1684 Pallet::set_freeze(&STAKING, &XP_ALPHA, SATURATED_MAX),
1685 Error::XpLockCapOverflowed
1686 )
1687 });
1688 }
1689
1690 #[test]
1691 fn set_freeze_fail_uninitialized_xp() {
1692 xp_test_ext().execute_with(|| {
1693 assert_err!(
1694 Pallet::set_freeze(&STAKING, &XP_ALPHA, DEFAULT_POINTS),
1695 Error::XpNotFound
1696 )
1697 });
1698 }
1699
1700 #[test]
1701 fn thaw_success() {
1702 xp_test_ext().execute_with(|| {
1703 Pallet::new_xp(&ALICE, &XP_ALPHA);
1704 Pallet::set_lock(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
1705 assert_ok!(Pallet::thaw(&STAKING, &XP_ALPHA));
1706 assert_err!(
1707 Pallet::lock_exists(&XP_ALPHA, &STAKING),
1708 Error::XpLockNotFound
1709 );
1710 });
1711 }
1712
1713 #[test]
1714 fn thaw_fail_uninitialized_xp() {
1715 xp_test_ext().execute_with(|| {
1716 assert_err!(Pallet::thaw(&STAKING, &XP_ALPHA), Error::XpNotFound);
1717 });
1718 }
1719
1720 #[test]
1721 fn thaw_fail_no_lock() {
1722 xp_test_ext().execute_with(|| {
1723 Pallet::new_xp(&ALICE, &XP_ALPHA);
1724 assert_err!(Pallet::thaw(&STAKING, &XP_ALPHA), Error::XpLockNotFound);
1725 });
1726 }
1727
1728 #[test]
1729 fn extend_freeze_success_on_zero() {
1730 xp_test_ext().execute_with(|| {
1731 Pallet::new_xp(&ALICE, &XP_ALPHA);
1732 Pallet::set_lock(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
1733 assert_ok!(Pallet::extend_freeze(&STAKING, &XP_ALPHA, INVALID_POINTS));
1734 });
1735 }
1736
1737 #[test]
1738 fn extend_freeze_success() {
1739 xp_test_ext().execute_with(|| {
1740 Pallet::new_xp(&ALICE, &XP_ALPHA);
1741 Pallet::set_lock(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
1742 let extend_points = 40;
1743 Pallet::extend_freeze(&STAKING, &XP_ALPHA, extend_points).unwrap();
1744 let extended_freez = Pallet::get_lock_xp(&XP_ALPHA, &STAKING).unwrap();
1745 assert_eq!(extended_freez, extend_points)
1746 });
1747 }
1748
1749 #[test]
1750 fn extend_freeze_low_amount() {
1751 xp_test_ext().execute_with(|| {
1752 Pallet::new_xp(&ALICE, &XP_ALPHA);
1753 Pallet::set_lock(&XP_ALPHA, &STAKING, DEFAULT_POINTS).unwrap();
1754 let extend_points = 9;
1755 Pallet::extend_freeze(&STAKING, &XP_ALPHA, extend_points).unwrap();
1756 let extended_freez = Pallet::get_lock_xp(&XP_ALPHA, &STAKING).unwrap();
1757 assert_eq!(extended_freez, DEFAULT_POINTS)
1758 });
1759 }
1760
1761 #[test]
1762 fn extend_freeze_fail_no_lock() {
1763 xp_test_ext().execute_with(|| {
1764 Pallet::new_xp(&ALICE, &XP_ALPHA);
1765 assert_err!(
1766 Pallet::extend_freeze(&STAKING, &XP_ALPHA, DEFAULT_POINTS),
1767 Error::XpLockNotFound
1768 )
1769 });
1770 }
1771}