1use crate::types::*;
66use crate::*;
67
68use frame_suite::{commitment::*, roles::*, Directive, Extent};
70
71use frame_support::{
73 dispatch::DispatchResult,
74 ensure,
75 traits::tokens::{Fortitude, Precision},
76};
77
78use frame_system::pallet_prelude::*;
80
81use sp_core::Get;
83use sp_runtime::{
84 traits::{Bounded, CheckedAdd, Saturating, Zero},
85 DispatchError, PerThing, Perbill, Vec,
86};
87
88impl<T: Config> RoleManager<Author<T>> for Pallet<T> {
97 type Status = AuthorStatus;
107
108 type Meta = AuthorInfo<T>;
110
111 type Asset = AuthorAsset<T>;
113
114 type TimeStamp = BlockNumberFor<T>;
116
117 fn role_exists(who: &Author<T>) -> DispatchResult {
123 ensure!(
124 AuthorsMap::<T>::contains_key(who),
125 Error::<T>::AuthorNotFound
126 );
127 Ok(())
128 }
129
130 fn get_meta(who: &Author<T>) -> Result<Self::Meta, DispatchError> {
136 let info = AuthorsMap::<T>::get(who).ok_or(Error::<T>::AuthorNotFound)?;
137 Ok(info)
138 }
139
140 fn get_collateral(who: &Author<T>) -> Result<Self::Asset, DispatchError> {
153 let reason = &FreezeReason::AuthorCollateral.into();
154 let value = T::CommitmentAdapter::get_commit_value(who, reason)?;
155 Ok(value)
156 }
157
158 fn total_collateral() -> Self::Asset {
163 let reason = &FreezeReason::AuthorCollateral.into();
164 T::CommitmentAdapter::get_total_value(reason)
165 }
166
167 fn enroll_since(who: &Author<T>) -> Result<Self::TimeStamp, DispatchError> {
171 let info = Self::get_meta(who)?;
172 Ok(info.since)
173 }
174
175 fn get_status(who: &Author<T>) -> Result<Self::Status, DispatchError> {
184 let info = Self::get_meta(who)?;
185 Ok(info.status)
186 }
187
188 fn status_since(who: &Author<T>) -> Result<Self::TimeStamp, DispatchError> {
195 let info = Self::get_meta(who)?;
196 return Ok(info.status_since);
197 }
198
199 fn set_status(who: &Author<T>, status: Self::Status) -> DispatchResult {
205 let info = Self::get_meta(who)?;
206 let current_status = info.status;
207 match current_status {
208 AuthorStatus::Active => match status {
210 AuthorStatus::Active => {}
212 AuthorStatus::Probation => {
214 Self::revoke_permanence(who)?;
215 }
216 AuthorStatus::Resigned => {
218 Self::resign(who)?;
222 }
223 },
224 AuthorStatus::Probation => match status {
226 AuthorStatus::Probation => {}
228 AuthorStatus::Resigned => return Err(Error::<T>::AuthorInProbation.into()),
230 AuthorStatus::Active => {
231 Self::set_permanence(who)?;
232 }
233 },
234 AuthorStatus::Resigned => match status {
236 AuthorStatus::Active | AuthorStatus::Probation => {
237 return Err(Error::<T>::AuthorResigned.into());
240 }
241 AuthorStatus::Resigned => {}
243 },
244 }
245 Self::on_status_update(who, &status);
246 Ok(())
247 }
248
249 fn can_enroll(who: &Author<T>, collateral: Self::Asset) -> DispatchResult {
259 if Self::role_exists(who).is_ok() {
261 let status = Self::get_status(who);
262 debug_assert!(
263 status.is_ok(),
264 "author {:?} role-exists but status unavailable",
265 who
266 );
267 match status? {
268 AuthorStatus::Resigned => {
269 debug_assert!(
271 Self::has_penalty(who).is_err(),
272 "author {:?} resigned with penalty and attempting re-enrollment",
273 who
274 );
275
276 if Self::has_reward(who).is_ok() {
281 return Err(Error::<T>::AuthorHasRewards.into());
282 }
283 }
284 AuthorStatus::Active | AuthorStatus::Probation => {
285 return Err(Error::<T>::AlreadyEnrolled.into())
286 }
287 }
288 }
289 let min_collateral = MinCollateral::<T>::get();
290 debug_assert!(
291 !min_collateral.is_zero(),
292 "`MinCollateral` must be greater than zero"
293 );
294 let available = T::CommitmentAdapter::available_funds(who);
295 ensure!(!(available < collateral), Error::<T>::InadequateFunds);
297 ensure!(
299 !(collateral < min_collateral),
300 Error::<T>::InadequateCollateral
301 );
302 Ok(())
303 }
304
305 fn enroll(
329 who: &Author<T>,
330 collateral: Self::Asset,
331 force: Fortitude,
332 ) -> Result<Self::Asset, DispatchError> {
333 Self::can_enroll(who, collateral)?;
336
337 let (meta, digest) = match Self::role_exists(who).is_ok() {
339 true => {
340 let meta = Self::get_meta(who);
341 debug_assert!(
342 meta.is_ok(),
343 "author {:?} role-exists but meta unavailable",
344 who
345 );
346 let meta = meta?;
347 debug_assert!(
348 AuthorStatus::Resigned == meta.status,
349 "re-enroll tried for non-resigned author {:?}",
350 who
351 );
352 let info = AuthorInfo::<T>::re_enroll(&meta);
353 debug_assert!(
356 meta.digest == info.digest,
357 "resigned author {:?} re-enroll tried with new commit digest",
358 who
359 );
360 let digest = meta.digest;
361 (info, digest)
362 }
363 false => {
364 let digest = T::CommitmentAdapter::gen_digest(who)
366 .map_err(|_| Error::<T>::CannotGenerateCommitDigest)?;
367 let info = AuthorInfo::<T>::new(digest.clone());
368 (info, digest)
369 }
370 };
371
372 let reason = &FreezeReason::AuthorCollateral.into();
373
374 let limits = T::CommitmentAdapter::place_commit_limits(
375 who,
376 reason,
377 &digest,
378 &Directive::new(
379 Precision::Exact, force,
381 ),
382 )?;
383
384 let actual = match limits.contains(collateral) {
385 true => {
386 T::CommitmentAdapter::place_commit(
388 who,
389 reason,
390 &digest,
391 collateral,
392 &Directive::new(
393 Precision::Exact, force,
395 ),
396 )?
397 }
398 false => {
399 T::CommitmentAdapter::place_commit(
401 who,
402 reason,
403 &digest,
404 MinCollateral::<T>::get(), &Directive::new(Precision::Exact, force),
406 )?
407 }
408 };
409
410 AuthorsMap::<T>::insert(who, &meta);
412
413 AuthorsDigest::<T>::insert(&digest, who);
414
415 Self::on_enroll(who, collateral);
416
417 Ok(actual)
419 }
420
421 fn can_resign(who: &Author<T>) -> DispatchResult {
435 let status = Self::get_status(who)?;
436 match status {
438 AuthorStatus::Probation => return Err(Error::<T>::AuthorInProbation.into()),
439 AuthorStatus::Resigned => return Err(Error::<T>::RedundantResignation.into()),
440 AuthorStatus::Active => {}
441 }
442 if Self::has_penalty(who).is_ok() {
444 return Err(Error::<T>::AuthorHasPenalties.into());
445 }
446 if let Err(a) = T::ActivityProvider::is_idle(who) {
448 return Err(a.into());
449 };
450
451 Ok(())
452 }
453
454 fn resign(who: &Author<T>) -> Result<Self::Asset, DispatchError> {
467 Self::can_resign(who)?;
469
470 AuthorsMap::<T>::mutate(who, |author| -> DispatchResult {
472 let info = author.as_mut();
473 debug_assert!(
474 info.is_some(),
475 "author {:?} can-resign without its author-info",
476 who
477 );
478 let info = info.ok_or(Error::<T>::AuthorNotFound)?;
479 let status = &mut info.status;
480 *status = AuthorStatus::Resigned;
481 Ok(())
482 })?;
483
484 let reason = &FreezeReason::AuthorCollateral.into();
487
488 let refund = T::CommitmentAdapter::resolve_commit(who, reason)?;
490
491 Self::on_resign(who, refund);
492 Ok(refund)
493 }
494
495 fn add_collateral(
507 who: &Author<T>,
508 collateral: Self::Asset,
509 force: Fortitude,
510 ) -> Result<Self::Asset, DispatchError> {
511 let exist_collateral = Self::get_collateral(who)?;
512 let reason = &FreezeReason::AuthorCollateral.into();
513 let minimum = MinCollateral::<T>::get();
514 debug_assert!(
515 !minimum.is_zero(),
516 "`MinCollateral` must be greater than zero"
517 );
518 let raised = match exist_collateral < minimum {
519 true => T::CommitmentAdapter::raise_commit(
520 who,
521 reason,
522 collateral,
523 &Directive::new(Precision::Exact, force),
524 )?,
525 false => T::CommitmentAdapter::raise_commit(
526 who,
527 reason,
528 collateral,
529 &Directive::new(Precision::BestEffort, force),
530 )?,
531 };
532 Self::on_add_collateral(who, raised);
533 Ok(raised)
534 }
535
536 fn is_available(who: &Author<T>) -> DispatchResult {
542 let status = Self::get_status(who)?;
543 if status == AuthorStatus::Resigned {
544 return Err(Error::<T>::AuthorResigned.into());
545 }
546 let collateral = Self::get_collateral(who);
547 debug_assert!(
548 collateral.is_ok(),
549 "author {:?} with status exist without a collateral",
550 who
551 );
552 let min_collateral = MinCollateral::<T>::get();
553 debug_assert!(
554 !min_collateral.is_zero(),
555 "`MinCollateral` must be greater than zero"
556 );
557 if collateral? < min_collateral {
558 return Err(Error::<T>::AuthorNeedsMoreCollateral.into());
559 }
560 Ok(())
561 }
562
563 fn on_enroll(who: &Author<T>, collateral: Self::Asset) {
567 if T::EmitEvents::get() {
568 Self::deposit_event(Event::<T>::AuthorEnlisted {
569 author: who.clone(),
570 collateral,
571 });
572 }
573 }
574
575 fn on_resign(who: &Author<T>, released: Self::Asset) {
579 if T::EmitEvents::get() {
580 Self::deposit_event(Event::<T>::AuthorResigned {
581 author: who.clone(),
582 released,
583 });
584 }
585 }
586
587 fn on_add_collateral(who: &Author<T>, raised: Self::Asset) {
591 if T::EmitEvents::get() {
592 Self::deposit_event(Event::<T>::AuthorCollateralRaised {
593 author: who.clone(),
594 raised,
595 });
596 }
597 }
598
599 fn on_status_update(who: &Author<T>, status: &Self::Status) {
603 if T::EmitEvents::get() {
604 Self::deposit_event(Event::<T>::AuthorStatus {
605 author: who.clone(),
606 status: status.clone(),
607 });
608 }
609 }
610}
611
612impl<T: Config> FundRoles<Author<T>> for Pallet<T> {
621 type Backer = Funder<T>;
628
629 fn has_funds(who: &Author<T>) -> DispatchResult {
633 let Some(_) = AuthorFunders::<T>::iter_prefix((who,)).next() else {
634 return Err(Error::<T>::FundDoesNotExist.into());
635 };
636 Ok(())
637 }
638
639 fn max_exposure(
654 by: &Self::Backer,
655 to: &Author<T>,
656 precision: Precision,
657 force: Fortitude,
658 ) -> Result<Self::Asset, DispatchError> {
659 let info = Self::get_meta(to)?;
660 let global = MaxExposure::<T>::get();
661
662 debug_assert!(
663 global >= MinFund::<T>::get(),
664 "`MaxExposure` must be greater than or equal to `MinFund`"
665 );
666
667 let local = info.max_fund.unwrap_or(global);
669
670 let base_max = local.min(global);
671
672 let Funder::Direct(funder) = by else {
673 return Ok(base_max);
674 };
675
676 let reason = &FreezeReason::AuthorFunding.into();
679 let directive = &Directive::new(precision, force);
680
681 let author_digest = &info.digest;
682
683 let commit_exists = T::CommitmentAdapter::commit_exists(funder, reason).is_ok();
684
685 let limits = match commit_exists {
686 true => {
687 let exist_digest = T::CommitmentAdapter::get_commit_digest(funder, reason)?;
688 ensure!(
689 exist_digest == *author_digest,
690 Error::<T>::FundedToAnotherDigest
691 );
692 T::CommitmentAdapter::raise_commit_limits(funder, reason, directive)?
693 }
694 false => {
695 T::CommitmentAdapter::place_commit_limits(funder, reason, author_digest, directive)?
696 }
697 };
698
699 let commit_max = limits.maximum().unwrap_or(Bounded::max_value());
700
701 Ok(base_max.min(commit_max))
703 }
704
705 fn min_fund(
720 by: &Self::Backer,
721 to: &Author<T>,
722 precision: Precision,
723 force: Fortitude,
724 ) -> Result<Self::Asset, DispatchError> {
725 let info = Self::get_meta(to)?;
726 let global = MinFund::<T>::get();
727 debug_assert!(!global.is_zero(), "`MinFund` must be greater than zero");
728 debug_assert!(
729 global <= MaxExposure::<T>::get(),
730 "`MinFund` must be smaller than or equal to `MaxExposure`"
731 );
732
733 let local = info.min_fund.unwrap_or(global);
735
736 let base_min = local.max(global);
737
738 let Funder::Direct(funder) = by else {
739 return Ok(base_min);
740 };
741
742 let reason = &FreezeReason::AuthorFunding.into();
745 let directive = &Directive::new(precision, force);
746
747 let author_digest = &info.digest;
748
749 let commit_exists = T::CommitmentAdapter::commit_exists(funder, reason).is_ok();
750
751 let limits = match commit_exists {
752 true => {
753 let exist_digest = T::CommitmentAdapter::get_commit_digest(funder, reason)?;
754 ensure!(
755 exist_digest == *author_digest,
756 Error::<T>::FundedToAnotherDigest
757 );
758 T::CommitmentAdapter::raise_commit_limits(funder, reason, directive)?
759 }
760 false => {
761 T::CommitmentAdapter::place_commit_limits(funder, reason, author_digest, directive)?
762 }
763 };
764
765 let commit_min = limits.minimum().unwrap_or(Zero::zero());
766
767 Ok(base_min.max(commit_min))
769 }
770
771 fn backed_value(who: &Author<T>) -> Result<Self::Asset, DispatchError> {
775 let info = Self::get_meta(who)?;
776 let reason = &FreezeReason::AuthorFunding.into();
777 let value = T::CommitmentAdapter::get_digest_value(reason, &info.digest)?;
778 Ok(value)
779 }
780
781 fn total_backing() -> Self::Asset {
785 let reason = &FreezeReason::AuthorFunding.into();
786 T::CommitmentAdapter::get_total_value(reason)
787 }
788
789 fn can_fund(
793 by: &Self::Backer,
794 to: &Author<T>,
795 value: Self::Asset,
796 precision: Precision,
797 force: Fortitude,
798 ) -> DispatchResult {
799 Self::is_available(to)?;
801
802 let info = Self::get_meta(to);
803 debug_assert!(
804 info.is_ok(),
805 "author {:?} is-available without its meta",
806 to
807 );
808 let info = info?;
809 let author_digest = &info.digest;
810 let reason = &FreezeReason::AuthorFunding.into();
811
812 let (funder, towards) = match by {
813 Funder::Direct(backer) => {
814 ensure!(
816 value >= Self::min_fund(by, to, precision, force)?,
817 Error::<T>::BelowMinimumFund
818 );
819 ensure!(
820 value <= Self::max_exposure(by, to, precision, force)?,
821 Error::<T>::AboveMaximumExposure
822 );
823 (backer, author_digest)
824 }
825 Funder::Index { digest, backer } => {
826 ensure!(value >= MinFund::<T>::get(), Error::<T>::BelowMinimumFund);
828 ensure!(
829 value <= MaxExposure::<T>::get(),
830 Error::<T>::AboveMaximumExposure
831 );
832 T::CommitmentAdapter::entry_exists(reason, digest, author_digest)?;
834 (backer, digest)
835 }
836 Funder::Pool { digest, backer } => {
837 ensure!(value >= MinFund::<T>::get(), Error::<T>::BelowMinimumFund);
839 ensure!(
840 value <= MaxExposure::<T>::get(),
841 Error::<T>::AboveMaximumExposure
842 );
843 T::CommitmentAdapter::slot_exists(reason, digest, author_digest)?;
845 (backer, digest)
846 }
847 };
848
849 if T::CommitmentAdapter::commit_exists(funder, reason).is_ok() {
851 let exist_digest = T::CommitmentAdapter::get_commit_digest(funder, reason)?;
852 ensure!(exist_digest == *towards, Error::<T>::FundedToAnotherDigest);
853 }
854 Ok(())
855 }
856
857 fn fund(
878 to: &Author<T>,
879 by: &Self::Backer,
880 value: Self::Asset,
881 precision: Precision,
882 force: Fortitude,
883 ) -> Result<Self::Asset, DispatchError> {
884 Self::can_fund(by, to, value, precision, force)?;
886
887 let reason = &FreezeReason::AuthorFunding.into();
889
890 let info = Self::get_meta(to);
891 debug_assert!(
892 info.is_ok(),
893 "backer can-fund but given author's {:?} meta not available",
894 to
895 );
896 let info = info?;
897 let author_digest = &info.digest;
898
899 let (funder, towards) = match by {
901 Funder::Direct(backer) => (backer, author_digest),
902 Funder::Index { digest, backer } => (backer, digest),
903 Funder::Pool { digest, backer } => (backer, digest),
904 };
905
906 let actual;
908 match T::CommitmentAdapter::commit_exists(funder, reason) {
909 Ok(_) => {
910 actual = T::CommitmentAdapter::raise_commit(
911 funder,
912 reason,
913 value,
914 &Directive::new(precision, force),
915 )?;
916 }
917 Err(_) => {
918 actual = T::CommitmentAdapter::place_commit(
919 funder,
920 reason,
921 towards,
922 value,
923 &Directive::new(precision, force),
924 )?;
925 }
926 }
927
928 match by {
931 Funder::Direct(_) => {
932 AuthorFunders::<T>::insert((to, funder), &by);
933 }
934 Funder::Index { digest, backer: _ } => {
935 let entries = T::CommitmentAdapter::get_entries_shares(reason, digest)?;
936 for (entry, _) in entries {
937 let author = AuthorsDigest::<T>::get(&entry);
938 let author = author.ok_or(Error::<T>::AuthorDigestNotFound)?;
939 AuthorFunders::<T>::insert((&author, funder), by);
940 }
941 }
942 Funder::Pool { digest, backer: _ } => {
943 let slots = T::CommitmentAdapter::get_slots_shares(reason, digest)?;
944 for (slot, _) in slots {
945 let author = AuthorsDigest::<T>::get(&slot);
946 let author = author.ok_or(Error::<T>::AuthorDigestNotFound)?;
947 AuthorFunders::<T>::insert((&author, funder), by);
948 }
949 }
950 }
951 Self::on_funded(to, by, actual);
952 Ok(actual)
953 }
954
955 fn can_draw(by: &Self::Backer, from: &Author<T>) -> DispatchResult {
968 let info = Self::get_meta(from)?;
969 let author_digest = &info.digest;
970 let reason = &FreezeReason::AuthorFunding.into();
971
972 let (funder, towards) = match by {
973 Funder::Direct(backer) => (backer, author_digest),
974 Funder::Index { digest, backer } => {
975 T::CommitmentAdapter::entry_exists(reason, digest, author_digest)?;
977 (backer, digest)
978 }
979 Funder::Pool { digest, backer } => {
980 T::CommitmentAdapter::slot_exists(reason, digest, author_digest)?;
982 (backer, digest)
983 }
984 };
985 T::CommitmentAdapter::commit_exists(funder, reason)?;
987 let exist_digest = T::CommitmentAdapter::get_commit_digest(funder, reason)?;
988 ensure!(exist_digest == *towards, Error::<T>::FundedToAnotherDigest);
990 Ok(())
991 }
992
993 fn draw(from: &Author<T>, by: &Self::Backer) -> Result<Self::Asset, DispatchError> {
1004 Self::can_draw(by, from)?;
1006
1007 let reason = &FreezeReason::AuthorFunding.into();
1009
1010 let funder = match by {
1012 Funder::Direct(backer)
1013 | Funder::Index { digest: _, backer }
1014 | Funder::Pool { digest: _, backer } => backer,
1015 };
1016
1017 let actual = T::CommitmentAdapter::resolve_commit(funder, reason)?;
1019
1020 match by {
1023 Funder::Direct(_) => {
1024 AuthorFunders::<T>::remove((from, funder));
1025 }
1026 Funder::Index { digest, backer: _ } => {
1027 let entries = T::CommitmentAdapter::get_entries_shares(reason, digest)?;
1028 for (entry, _) in entries {
1029 let author = AuthorsDigest::<T>::get(&entry);
1030 let author = author.ok_or(Error::<T>::AuthorDigestNotFound)?;
1031 AuthorFunders::<T>::remove((author, funder));
1032 }
1033 }
1034 Funder::Pool { digest, backer: _ } => {
1035 let slots = T::CommitmentAdapter::get_slots_shares(reason, digest)?;
1036 for (slot, _) in slots {
1037 let author = AuthorsDigest::<T>::get(&slot);
1038 let author = author.ok_or(Error::<T>::AuthorDigestNotFound)?;
1039 AuthorFunders::<T>::remove((author, funder));
1040 }
1041 }
1042 }
1043 Self::on_drawn(from, by, actual);
1044 Ok(actual)
1045 }
1046
1047 fn backers_of(who: &Author<T>) -> Result<Vec<(Self::Backer, Self::Asset)>, DispatchError> {
1058 let info = Self::get_meta(who)?;
1059 let mut result: Vec<(Self::Backer, Self::Asset)> = Default::default();
1060 let reason = &FreezeReason::AuthorFunding.into();
1061 let iter = AuthorFunders::<T>::iter_prefix((who,));
1062 for (_, funder) in iter {
1063 match &funder {
1064 Funder::Direct(direct) => {
1065 let value = T::CommitmentAdapter::get_commit_value(direct, reason)?;
1066 result.push((funder, value));
1067 }
1068 Funder::Index { digest, backer } => {
1069 let value = T::CommitmentAdapter::get_entry_value_for(
1071 backer,
1072 reason,
1073 digest,
1074 &info.digest,
1075 )?;
1076 result.push((funder, value));
1077 }
1078 Funder::Pool { digest, backer } => {
1079 let value = T::CommitmentAdapter::get_slot_value_for(
1081 backer,
1082 reason,
1083 digest,
1084 &info.digest,
1085 )?;
1086 result.push((funder, value));
1087 }
1088 }
1089 }
1090
1091 Ok(result)
1092 }
1093
1094 fn backed_for(by: &Self::Backer) -> Result<Vec<(Author<T>, Self::Asset)>, DispatchError> {
1109 let mut result: Vec<(Author<T>, Self::Asset)> = Default::default();
1110 let mut pre_return: Vec<(AuthorDigest<T>, Self::Asset)> = Default::default();
1111 let reason = &FreezeReason::AuthorFunding.into();
1112 match by {
1113 Funder::Direct(funder) => {
1114 let to = T::CommitmentAdapter::get_commit_digest(funder, reason)?;
1116 let value = T::CommitmentAdapter::get_commit_value(funder, reason)?;
1117 pre_return.push((to, value))
1118 }
1119 Funder::Index { digest, backer } => {
1120 pre_return = T::CommitmentAdapter::get_entries_value_for(backer, reason, digest)?;
1122 }
1123 Funder::Pool { digest, backer } => {
1124 pre_return = T::CommitmentAdapter::get_slots_value_for(backer, reason, digest)?;
1126 }
1127 }
1128
1129 for (digest, value) in pre_return {
1131 let author = AuthorsDigest::<T>::get(&digest);
1132 let author = author.ok_or(Error::<T>::AuthorDigestNotFound)?;
1133 result.push((author, value))
1134 }
1135
1136 Ok(result)
1137 }
1138
1139 fn get_fund(who: &Author<T>, by: &Self::Backer) -> Result<Self::Asset, DispatchError> {
1148 let info = Self::get_meta(who)?;
1149 let reason = &FreezeReason::AuthorFunding.into();
1150
1151 match by {
1152 Funder::Direct(direct) => {
1153 let digest = T::CommitmentAdapter::get_commit_digest(direct, reason)?;
1155 let is_author =
1156 AuthorsDigest::<T>::get(digest).ok_or(Error::<T>::AuthorDigestNotFound)?;
1157 ensure!(is_author == *who, Error::<T>::FundedToAnotherDigest,);
1158 T::CommitmentAdapter::get_commit_value(direct, reason)
1159 }
1160 Funder::Index { digest, backer } => {
1161 T::CommitmentAdapter::get_entry_value_for(backer, reason, digest, &info.digest)
1163 }
1164 Funder::Pool { digest, backer } => {
1165 T::CommitmentAdapter::get_slot_value_for(backer, reason, digest, &info.digest)
1167 }
1168 }
1169 }
1170
1171 fn on_drawn(who: &Author<T>, by: &Self::Backer, amount: Self::Asset) {
1182 if T::EmitEvents::get() {
1183 match by {
1184 Funder::Direct(backer) => {
1185 Self::deposit_event(Event::<T>::AuthorDrawn {
1186 author: who.clone(),
1187 backer: backer.clone(),
1188 amount,
1189 });
1190 }
1191 Funder::Index { digest, backer } => {
1192 Self::deposit_event(Event::<T>::IndexDrawn {
1193 index: digest.clone(),
1194 backer: backer.clone(),
1195 amount,
1196 });
1197 }
1198 Funder::Pool { digest, backer } => {
1199 Self::deposit_event(Event::<T>::PoolDrawn {
1200 pool: digest.clone(),
1201 backer: backer.clone(),
1202 amount,
1203 });
1204 }
1205 }
1206 }
1207 }
1208
1209 fn on_funded(who: &Author<T>, by: &Self::Backer, amount: Self::Asset) {
1219 if T::EmitEvents::get() {
1220 match by {
1221 Funder::Direct(backer) => {
1222 Self::deposit_event(Event::<T>::AuthorFunded {
1223 author: who.clone(),
1224 backer: backer.clone(),
1225 amount,
1226 });
1227 }
1228 Funder::Index { digest, backer } => {
1229 Self::deposit_event(Event::<T>::IndexFunded {
1230 index: digest.clone(),
1231 backer: backer.clone(),
1232 amount,
1233 });
1234 }
1235 Funder::Pool { digest, backer } => {
1236 Self::deposit_event(Event::<T>::PoolFunded {
1237 pool: digest.clone(),
1238 backer: backer.clone(),
1239 amount,
1240 });
1241 }
1242 }
1243 }
1244 }
1245}
1246
1247impl<T: Config> CompensateRoles<Author<T>> for Pallet<T> {
1256 type Ratio = Perbill;
1265
1266 fn has_reward(who: &Author<T>) -> DispatchResult {
1274 Self::role_exists(who)?;
1276
1277 let mut start_block = frame_system::Pallet::<T>::block_number().saturating_add(1u32.into());
1279
1280 let last_reward_block = RewardsUntil::<T>::get();
1282
1283 while start_block <= last_reward_block {
1285 if AuthorRewards::<T>::contains_key((start_block, who)) {
1287 return Ok(());
1288 }
1289 start_block = start_block.saturating_add(1u32.into())
1291 }
1292
1293 Err(Error::<T>::RewardNotFound.into())
1295 }
1296
1297 fn has_penalty(who: &Author<T>) -> DispatchResult {
1305 Self::role_exists(who)?;
1307
1308 let mut start_block = frame_system::Pallet::<T>::block_number().saturating_add(1u32.into());
1310
1311 let last_penalty_block = PenaltiesUntil::<T>::get();
1313
1314 while start_block <= last_penalty_block {
1316 if AuthorPenalties::<T>::contains_key((start_block, who)) {
1317 return Ok(());
1318 }
1319 start_block = start_block.saturating_add(1u32.into())
1320 }
1321 Err(Error::<T>::PenaltyNotFound.into())
1323 }
1324
1325 fn get_rewards_of(
1335 who: &Author<T>,
1336 ) -> Result<Vec<(Self::TimeStamp, Self::Asset)>, DispatchError> {
1337 Self::role_exists(who)?;
1339
1340 let mut result: Vec<(Self::TimeStamp, Self::Asset)> = Default::default();
1342
1343 let mut start_block = frame_system::Pallet::<T>::block_number().saturating_add(1u32.into());
1345
1346 let last_reward_block = RewardsUntil::<T>::get();
1348
1349 while start_block <= last_reward_block {
1351 if let Some(value) = AuthorRewards::<T>::get((start_block, who)) {
1352 result.push((start_block, value))
1354 }
1355 start_block = start_block.saturating_add(1u32.into())
1356 }
1357 Ok(result)
1358 }
1359
1360 fn get_penalties_of(
1370 who: &Author<T>,
1371 ) -> Result<Vec<(Self::TimeStamp, Self::Ratio)>, DispatchError> {
1372 Self::role_exists(who)?;
1374
1375 let mut result: Vec<(Self::TimeStamp, Self::Ratio)> = Default::default();
1377
1378 let mut start_block = frame_system::Pallet::<T>::block_number().saturating_add(1u32.into());
1380
1381 let last_penalty_block = PenaltiesUntil::<T>::get();
1383
1384 while start_block <= last_penalty_block {
1386 if let Some(factor) = AuthorPenalties::<T>::get((start_block, who)) {
1387 result.push((start_block, factor))
1388 }
1389 start_block = start_block.saturating_add(1u32.into())
1390 }
1391 Ok(result)
1392 }
1393
1394 fn get_hold(who: &Author<T>) -> Result<Self::Asset, DispatchError> {
1402 let info = Self::get_meta(who)?;
1403
1404 let funding_reason = &FreezeReason::AuthorFunding.into();
1406 let funding = T::CommitmentAdapter::get_digest_value(funding_reason, &info.digest)?;
1407 let collateral_reason = &FreezeReason::AuthorCollateral.into();
1409 let collateral = T::CommitmentAdapter::get_digest_value(collateral_reason, &info.digest)?;
1410
1411 let hold = funding.checked_add(&collateral);
1413
1414 debug_assert!(
1415 hold.is_some(),
1416 "exhausted the asset type's max bound value by the author {:?}
1417 via funding {:?} + collateral {:?}, if non-issuance asset ignore
1418 this, else requires strict action",
1419 who,
1420 funding,
1421 collateral
1422 );
1423
1424 let hold = hold.ok_or(Error::<T>::AuthorTotalHoldExhausted)?;
1425
1426 Ok(hold)
1427 }
1428
1429 fn get_rewards_on(
1442 time_stamp: Self::TimeStamp,
1443 ) -> Result<Vec<(Author<T>, Self::Asset)>, DispatchError> {
1444 if time_stamp <= frame_system::Pallet::<T>::block_number() {
1446 return Err(Error::<T>::FinalizedObligations.into());
1447 }
1448
1449 let mut result: Vec<(Author<T>, Self::Asset)> = Default::default();
1450 let iter = AuthorRewards::<T>::iter_prefix((time_stamp,));
1451 for (author, reward) in iter {
1453 result.push((author, reward))
1455 }
1456 Ok(result)
1457 }
1458
1459 fn get_penalties_on(
1472 time_stamp: Self::TimeStamp,
1473 ) -> Result<Vec<(Author<T>, Self::Ratio)>, DispatchError> {
1474 if time_stamp <= frame_system::Pallet::<T>::block_number() {
1476 return Err(Error::<T>::FinalizedObligations.into());
1477 }
1478 let mut result: Vec<(Author<T>, Self::Ratio)> = Default::default();
1479 let iter = AuthorPenalties::<T>::iter_prefix((time_stamp,));
1480 for (author, factor) in iter {
1482 result.push((author, factor))
1483 }
1484 Ok(result)
1485 }
1486
1487 fn set_hold(
1500 who: &Author<T>,
1501 value: Self::Asset,
1502 precision: Precision,
1503 force: Fortitude,
1504 ) -> DispatchResult {
1505 let info = Self::get_meta(who)?;
1506
1507 let funding_reason = &FreezeReason::AuthorFunding.into();
1509 let funding = T::CommitmentAdapter::get_digest_value(funding_reason, &info.digest)?;
1510
1511 let collateral_reason = &FreezeReason::AuthorCollateral.into();
1513 let collateral = T::CommitmentAdapter::get_digest_value(collateral_reason, &info.digest)?;
1514
1515 let hold = funding.checked_add(&collateral);
1517
1518 debug_assert!(
1519 hold.is_some(),
1520 "exhausted the asset type's max bound value by the author {:?}
1521 via funding {:?} + collateral {:?}, if non-issuance asset ignore
1522 this, else requires strict action",
1523 who,
1524 funding,
1525 collateral
1526 );
1527
1528 let hold = hold.ok_or(Error::<T>::AuthorTotalHoldExhausted)?;
1529
1530 let funding_ratio = <Self::Ratio as PerThing>::from_rational(funding, hold);
1531
1532 let funding_value = funding_ratio.mul_ceil(value);
1535 let collateral_value = value.saturating_sub(funding_value);
1536
1537 let qualifier = <<T::CommitmentAdapter as Commitment<Author<T>>>::Intent as Directive>::new(
1539 precision, force,
1540 );
1541 T::CommitmentAdapter::set_digest_value(
1542 funding_reason,
1543 &info.digest,
1544 funding_value,
1545 &qualifier.clone(),
1546 )?;
1547 T::CommitmentAdapter::set_digest_value(
1548 collateral_reason,
1549 &info.digest,
1550 collateral_value,
1551 &qualifier,
1552 )?;
1553 Self::on_set_hold(who, value);
1554 Ok(())
1555 }
1556
1557 fn penalize(who: &Author<T>, factor: Self::Ratio) -> Result<Self::TimeStamp, DispatchError> {
1575 if factor.is_zero() {
1577 return Err(Error::<T>::ZeroPenaltyFound.into());
1578 }
1579
1580 let status = Self::get_status(who)?;
1581
1582 match status {
1583 AuthorStatus::Active => {
1585 let result = Self::risk_permanence(who);
1586 debug_assert!(
1587 result.is_ok(),
1588 "author {:?} active status available but cannot risk their permanance",
1589 who
1590 );
1591 result?;
1592 if Self::can_revoke_permanence(who).is_ok() {
1593 Self::revoke_permanence(who)?;
1594 }
1595 }
1596 AuthorStatus::Probation => {
1598 let result = Self::risk_probation(who);
1599 debug_assert!(
1600 result.is_ok(),
1601 "author {:?} probation status available but cannot risk their probation",
1602 who
1603 );
1604 result?
1605 }
1606 AuthorStatus::Resigned => {
1608 return Err(Error::<T>::AuthorResigned.into());
1609 }
1610 }
1611
1612 let mut block =
1614 frame_system::Pallet::<T>::block_number().saturating_add(PenaltiesBuffer::<T>::get());
1615
1616 loop {
1619 if !AuthorPenalties::<T>::contains_key((block, who)) {
1620 AuthorPenalties::<T>::insert((block, who), &factor);
1621 break;
1622 }
1623 block = block.saturating_add(1u32.into());
1625 }
1626
1627 if block > PenaltiesUntil::<T>::get() {
1629 PenaltiesUntil::<T>::put(block);
1630 }
1631
1632 Self::on_penalize(who, factor, block);
1633 Ok(block)
1635 }
1636
1637 fn forgive(who: &Author<T>, from: Self::TimeStamp) -> Result<Self::Ratio, DispatchError> {
1651 let status = Self::get_status(who)?;
1652
1653 if from <= frame_system::Pallet::<T>::block_number() {
1655 return Err(Error::<T>::FinalizedObligations.into());
1656 }
1657
1658 if status == AuthorStatus::Resigned {
1659 return Err(Error::<T>::AuthorResigned.into());
1660 }
1661
1662 let factor = AuthorPenalties::<T>::get((from, who)).ok_or(Error::<T>::PenaltyNotFound)?;
1664 AuthorPenalties::<T>::remove((from, who));
1666 let result = Self::secure_permanence(who);
1668 debug_assert!(
1669 result.is_ok(),
1670 "author {:?} is-available (not resigned) but cannot secure permanance",
1671 who
1672 );
1673 result?;
1674
1675 Self::on_forgive(who, factor);
1676 Ok(factor)
1678 }
1679
1680 fn reward(
1695 who: &Author<T>,
1696 value: Self::Asset,
1697 _precision: Precision,
1698 ) -> Result<Self::TimeStamp, DispatchError> {
1699 let status = Self::get_status(who)?;
1700
1701 match status {
1704 AuthorStatus::Active | AuthorStatus::Probation => {
1705 let result = Self::secure_permanence(who);
1707 debug_assert!(
1708 result.is_ok(),
1709 "author {:?} is-available (not resigned) but cannot secure permanance",
1710 who
1711 );
1712 result?;
1713 }
1714 AuthorStatus::Resigned => return Err(Error::<T>::AuthorResigned.into()),
1715 }
1716
1717 let mut block =
1719 frame_system::Pallet::<T>::block_number().saturating_add(RewardsBuffer::<T>::get());
1720
1721 loop {
1724 if !AuthorRewards::<T>::contains_key((block, who)) {
1725 AuthorRewards::<T>::insert((block, who), &value);
1726 break;
1727 }
1728 block = block.saturating_add(1u32.into());
1730 }
1731
1732 if block > RewardsUntil::<T>::get() {
1734 RewardsUntil::<T>::put(block);
1735 }
1736
1737 Self::on_reward(who, value, block);
1738 Ok(block)
1740 }
1741
1742 fn reclaim(who: &Author<T>, from: Self::TimeStamp) -> Result<Self::Asset, DispatchError> {
1755 Self::role_exists(who)?;
1756
1757 if from <= frame_system::Pallet::<T>::block_number() {
1759 return Err(Error::<T>::FinalizedObligations.into());
1760 }
1761
1762 let value = AuthorRewards::<T>::get((from, who)).ok_or(Error::<T>::RewardNotFound)?;
1764 AuthorRewards::<T>::remove((from, who));
1766
1767 Self::on_reclaim(who, value);
1768 Ok(value)
1770 }
1771
1772 fn on_reward(who: &Author<T>, amount: Self::Asset, at: Self::TimeStamp) {
1776 if T::EmitEvents::get() {
1777 Self::deposit_event(Event::<T>::AuthorRewardScheduled {
1778 author: who.clone(),
1779 amount: amount,
1780 at: at,
1781 });
1782 }
1783 }
1784
1785 fn on_reclaim(who: &Author<T>, amount: Self::Asset) {
1789 if T::EmitEvents::get() {
1790 Self::deposit_event(Event::<T>::AuthorRewardReclaimed {
1791 author: who.clone(),
1792 amount,
1793 });
1794 }
1795 }
1796
1797 fn on_set_hold(who: &Author<T>, value: Self::Asset) {
1801 if T::EmitEvents::get() {
1802 Self::deposit_event(Event::<T>::AuthorTotalHold {
1803 author: who.clone(),
1804 value: value,
1805 });
1806 }
1807 }
1808
1809 fn on_forgive(who: &Author<T>, factor: Self::Ratio) {
1813 if T::EmitEvents::get() {
1814 Self::deposit_event(Event::<T>::AuthorPenaltyForgiven {
1815 author: who.clone(),
1816 factor,
1817 });
1818 }
1819 }
1820
1821 fn on_penalize(who: &Author<T>, factor: Self::Ratio, at: Self::TimeStamp) {
1825 if T::EmitEvents::get() {
1826 Self::deposit_event(Event::<T>::AuthorPenaltyScheduled {
1827 author: who.clone(),
1828 factor,
1829 at: at,
1830 });
1831 }
1832 }
1833}
1834
1835impl<T: Config> RoleProbation<Author<T>> for Pallet<T> {
1844 fn is_on_probation(who: &Author<T>) -> DispatchResult {
1849 let status = Self::get_status(who)?;
1850 match status {
1851 AuthorStatus::Active => Err(Error::<T>::AuthorIsActive.into()),
1852 AuthorStatus::Probation => Ok(()),
1853 AuthorStatus::Resigned => Err(Error::<T>::AuthorResigned.into()),
1854 }
1855 }
1856
1857 fn is_permanent(who: &Author<T>) -> DispatchResult {
1862 let status = Self::get_status(who)?;
1863 match status {
1864 AuthorStatus::Active => Ok(()),
1865 AuthorStatus::Probation => Err(Error::<T>::AuthorInProbation.into()),
1866 AuthorStatus::Resigned => Err(Error::<T>::AuthorResigned.into()),
1867 }
1868 }
1869
1870 fn can_be_permanent(who: &Author<T>) -> DispatchResult {
1877 let info = Self::get_meta(who)?;
1878 let status = &info.status;
1879
1880 match status {
1882 AuthorStatus::Active => return Err(Error::<T>::AuthorIsActive.into()),
1884 AuthorStatus::Resigned => return Err(Error::<T>::AuthorResigned.into()),
1886 AuthorStatus::Probation => {}
1888 }
1889
1890 let current_block = frame_system::Pallet::<T>::block_number();
1891 let status_since = info.status_since;
1892
1893 if status_since.saturating_add(ProbationPeriod::<T>::get()) > current_block {
1895 return Err(Error::<T>::AuthorInProbation.into());
1897 }
1898
1899 let risk_until = info.risk_until;
1901 if risk_until > current_block {
1902 return Err(Error::<T>::AuthorIsUnsafe.into());
1903 }
1904 Ok(())
1905 }
1906
1907 fn set_permanence(who: &Author<T>) -> Result<Self::Status, DispatchError> {
1911 Self::can_be_permanent(who)?;
1913
1914 let active = AuthorStatus::Active;
1915
1916 AuthorsMap::<T>::mutate(who, |author| -> DispatchResult {
1917 let info = author.as_mut();
1918 debug_assert!(
1919 info.is_some(),
1920 "author {:?} can-be-permanent but cannot mutate status",
1921 who
1922 );
1923 let info = info.ok_or(Error::<T>::AuthorNotFound)?;
1924 let status = &mut info.status;
1925
1926 *status = active.clone();
1928
1929 Ok(())
1930 })?;
1931 Self::on_set_permance(who);
1932 Ok(active)
1933 }
1934
1935 fn can_revoke_permanence(who: &Author<T>) -> DispatchResult {
1942 let meta = Self::get_meta(who)?;
1943 let status = meta.status;
1944 let risk_until = meta.risk_until;
1945 let current_block = frame_system::Pallet::<T>::block_number();
1946
1947 match status {
1949 AuthorStatus::Probation => return Err(Error::<T>::AuthorInProbation.into()),
1951 AuthorStatus::Resigned => return Err(Error::<T>::AuthorResigned.into()),
1953 AuthorStatus::Active => {}
1955 }
1956
1957 if risk_until <= current_block.saturating_add(ProbationPeriod::<T>::get()) {
1958 return Err(Error::<T>::RiskWithinThreshold.into());
1959 }
1960 Ok(())
1961 }
1962
1963 fn revoke_permanence(who: &Author<T>) -> Result<Self::Status, DispatchError> {
1967 Self::can_revoke_permanence(who)?;
1969
1970 let probation = AuthorStatus::Probation;
1971 let current_block = frame_system::Pallet::<T>::block_number();
1972
1973 AuthorsMap::<T>::mutate(who, |author| -> DispatchResult {
1974 let info = author.as_mut();
1975 debug_assert!(
1976 info.is_some(),
1977 "author {:?} can-revoke-permanence but cannot mutate status",
1978 who
1979 );
1980 let info = info.ok_or(Error::<T>::AuthorNotFound)?;
1981 let status = &mut info.status;
1982 let status_since = &mut info.status_since;
1983 *status = probation.clone();
1985 *status_since = current_block;
1987
1988 Ok(())
1989 })?;
1990 Self::on_revoke_permanence(who);
1991 Ok(probation)
1992 }
1993
1994 fn risk_probation(who: &Author<T>) -> DispatchResult {
1998 AuthorsMap::<T>::mutate(who, |author| -> DispatchResult {
1999 let info = author.as_mut().ok_or(Error::<T>::AuthorNotFound)?;
2000
2001 let status = &mut info.status;
2002
2003 match status {
2005 AuthorStatus::Active => return Err(Error::<T>::AuthorIsActive.into()),
2007 AuthorStatus::Resigned => return Err(Error::<T>::AuthorResigned.into()),
2009 AuthorStatus::Probation => {}
2011 }
2012
2013 let current_block = frame_system::Pallet::<T>::block_number();
2014 let risk_until = &mut info.risk_until;
2015
2016 if *risk_until < current_block {
2018 *risk_until = current_block.saturating_add(IncreaseProbationBy::<T>::get());
2019 return Ok(());
2020 }
2021 *risk_until = risk_until.saturating_add(IncreaseProbationBy::<T>::get());
2022
2023 Ok(())
2024 })?;
2025 Self::on_risk_probation(who);
2026 Ok(())
2027 }
2028
2029 fn risk_permanence(who: &Author<T>) -> DispatchResult {
2033 AuthorsMap::<T>::mutate(who, |author| -> DispatchResult {
2034 let info = author.as_mut().ok_or(Error::<T>::AuthorNotFound)?;
2036
2037 let status = &mut info.status;
2038
2039 match status {
2041 AuthorStatus::Active => {}
2043 AuthorStatus::Resigned => return Err(Error::<T>::AuthorResigned.into()),
2045 AuthorStatus::Probation => return Err(Error::<T>::AuthorInProbation.into()),
2047 }
2048
2049 let current_block = frame_system::Pallet::<T>::block_number();
2050 let risk_until = &mut info.risk_until;
2051
2052 if *risk_until < current_block {
2054 *risk_until = current_block.saturating_add(IncreaseProbationBy::<T>::get());
2055 return Ok(());
2056 }
2057 *risk_until = risk_until.saturating_add(IncreaseProbationBy::<T>::get());
2058 Ok(())
2059 })?;
2060 Self::on_risk_permanence(who);
2061 Ok(())
2062 }
2063
2064 fn secure_permanence(who: &Author<T>) -> DispatchResult {
2068 AuthorsMap::<T>::mutate(who, |author| -> DispatchResult {
2069 let info = author.as_mut().ok_or(Error::<T>::AuthorNotFound)?;
2070
2071 let status = &mut info.status;
2072
2073 match status {
2075 AuthorStatus::Active => {}
2077 AuthorStatus::Resigned => return Err(Error::<T>::AuthorResigned.into()),
2079 AuthorStatus::Probation => {}
2081 }
2082 let risk_until = &mut info.risk_until;
2083 let current_block = frame_system::Pallet::<T>::block_number();
2084
2085 if *risk_until > current_block {
2087 *risk_until = risk_until.saturating_sub(ReduceProbationBy::<T>::get());
2088 return Ok(());
2089 }
2090 Ok(())
2091 })?;
2092 Self::on_secure_permanence(who);
2093 Ok(())
2094 }
2095
2096 fn on_set_permance(who: &Author<T>) {
2100 if T::EmitEvents::get() {
2101 Self::deposit_event(Event::AuthorStatus {
2102 author: who.clone(),
2103 status: AuthorStatus::Active,
2104 });
2105 }
2106 }
2107
2108 fn on_revoke_permanence(who: &Author<T>) {
2112 if T::EmitEvents::get() {
2113 Self::deposit_event(Event::AuthorStatus {
2114 author: who.clone(),
2115 status: AuthorStatus::Probation,
2116 });
2117 }
2118 }
2119
2120 fn on_risk_permanence(who: &Author<T>) {
2125 if T::EmitEvents::get() {
2126 let Ok(meta) = Self::get_meta(who) else {
2127 return;
2128 };
2129 Self::deposit_event(Event::<T>::AuthorAtRisk {
2130 author: who.clone(),
2131 status: AuthorStatus::Active,
2132 until: meta.risk_until,
2133 });
2134 }
2135 }
2136
2137 fn on_risk_probation(who: &Author<T>) {
2142 if T::EmitEvents::get() {
2143 let Ok(meta) = Self::get_meta(who) else {
2144 return;
2145 };
2146 Self::deposit_event(Event::<T>::AuthorAtRisk {
2147 author: who.clone(),
2148 status: AuthorStatus::Probation,
2149 until: meta.risk_until,
2150 });
2151 }
2152 }
2153
2154 fn on_secure_permanence(who: &Author<T>) {
2159 if T::EmitEvents::get() {
2160 let Ok(meta) = Self::get_meta(who) else {
2161 return;
2162 };
2163 Self::deposit_event(Event::<T>::AuthorAtRisk {
2164 author: who.clone(),
2165 status: AuthorStatus::Probation,
2166 until: meta.risk_until,
2167 });
2168 }
2169 }
2170}
2171
2172#[cfg(test)]
2177mod tests {
2178 use crate::mock::*;
2184 use crate::{
2185 types::{AuthorStatus, Funder},
2186 Event::*,
2187 };
2188
2189 use frame_suite::{commitment::*, roles::*};
2191
2192 use frame_support::{
2194 assert_err, assert_ok,
2195 traits::{
2196 fungible::InspectFreeze,
2197 tokens::{Fortitude, Precision},
2198 },
2199 };
2200
2201 use sp_runtime::{DispatchError, Perbill};
2203
2204 #[test]
2209 fn enroll_success() {
2210 authors_test_ext().execute_with(|| {
2211 System::set_block_number(10);
2212 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2213 assert_err!(Pallet::role_exists(&ALICE), Error::AuthorNotFound);
2214 let collateral_locked = Pallet::enroll(&ALICE, LARGE_VALUE, Fortitude::Force).unwrap();
2216 assert_ok!(CommitAdapter::commit_exists(&ALICE, &COLLATERAL.into()));
2217 assert_eq!(
2218 AuthorAsset::balance_frozen(&COLLATERAL.into(), &ALICE),
2219 collateral_locked
2220 );
2221 assert_ok!(Pallet::role_exists(&ALICE));
2223 let author_digest = gen_author_digest(&ALICE).unwrap();
2224 assert_eq!(AuthorsDigest::get(author_digest), Some(ALICE));
2225 System::assert_last_event(Event::AuthorEnlisted { author: ALICE, collateral: collateral_locked }.into());
2226 })
2227 }
2228
2229 #[test]
2230 fn role_exists_success() {
2231 authors_test_ext().execute_with(|| {
2232 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2233 Pallet::enroll(&ALICE, LARGE_VALUE, Fortitude::Force).unwrap();
2234 assert_ok!(Pallet::role_exists(&ALICE));
2235 })
2236 }
2237
2238 #[test]
2239 fn role_exists_err_author_not_found() {
2240 authors_test_ext().execute_with(|| {
2241 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2242 Pallet::enroll(&ALICE, LARGE_VALUE, Fortitude::Force).unwrap();
2243 assert_err!(Pallet::role_exists(&BOB), Error::AuthorNotFound);
2245 })
2246 }
2247
2248 #[test]
2249 fn get_meta_success() {
2250 authors_test_ext().execute_with(|| {
2251 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2252 System::set_block_number(6);
2253 Pallet::enroll(&ALICE, LARGE_VALUE, Fortitude::Force).unwrap();
2254 let author_digest = gen_author_digest(&ALICE).unwrap();
2255 let meta = Pallet::get_meta(&ALICE).unwrap();
2256 assert_eq!(meta.digest, author_digest);
2257 assert_eq!(meta.since, 6);
2258 assert_eq!(meta.status, AuthorStatus::Probation);
2259 assert_eq!(meta.status_since, 6);
2260 assert_eq!(meta.risk_until, 6);
2261 assert_eq!(meta.max_fund, None);
2262 assert_eq!(meta.min_fund, None);
2263 })
2264 }
2265
2266 #[test]
2267 fn get_meta_err_author_not_found() {
2268 authors_test_ext().execute_with(|| {
2269 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2270 System::set_block_number(6);
2271 Pallet::enroll(&ALICE, LARGE_VALUE, Fortitude::Force).unwrap();
2272 assert_err!(Pallet::get_meta(&BOB), Error::AuthorNotFound);
2274 })
2275 }
2276
2277 #[test]
2278 fn can_enroll_success() {
2279 authors_test_ext().execute_with(|| {
2280 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2281 assert_ok!(Pallet::can_enroll(&ALICE, LARGE_VALUE));
2282 })
2283 }
2284
2285 #[test]
2286 fn can_enroll_err_already_enrolled() {
2287 authors_test_ext().execute_with(|| {
2288 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2289 System::set_block_number(6);
2290 Pallet::enroll(&ALICE, LARGE_VALUE, Fortitude::Force).unwrap();
2291 assert_err!(
2292 Pallet::can_enroll(&ALICE, LARGE_VALUE),
2293 Error::AlreadyEnrolled
2294 );
2295 })
2296 }
2297
2298 #[test]
2299 fn can_enroll_err_inadequate_collateral() {
2300 authors_test_ext().execute_with(|| {
2301 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2302 assert_err!(
2303 Pallet::can_enroll(&ALICE, SMALL_VALUE),
2304 Error::InadequateCollateral
2305 );
2306 })
2307 }
2308
2309 #[test]
2310 fn can_enroll_err_inadequate_funds() {
2311 authors_test_ext().execute_with(|| {
2312 initiate_key_and_set_balance_and_hold(&ALICE, MIN_VALUE, MIN_VALUE).unwrap();
2313 assert_err!(
2314 Pallet::can_enroll(&ALICE, LARGE_VALUE),
2315 Error::InadequateFunds
2316 );
2317 })
2318 }
2319
2320 #[should_panic]
2321 #[test]
2322 fn can_enroll_panic_author_resigned_with_penalty() {
2323 authors_test_ext().execute_with(|| {
2324 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2325
2326 System::set_block_number(6);
2327 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
2328
2329 System::set_block_number(10);
2330 Pallet::penalize(&ALICE, Perbill::from_percent(5)).unwrap();
2331
2332 AuthorsMap::mutate(ALICE, |author| {
2333 let info = author.as_mut().unwrap();
2334 let status = &mut info.status;
2335 *status = AuthorStatus::Resigned
2336 });
2337
2338 Pallet::can_enroll(&ALICE, STANDARD_VALUE).unwrap();
2340 })
2341 }
2342
2343 #[test]
2344 fn can_enroll_err_author_has_rewards() {
2345 authors_test_ext().execute_with(|| {
2346 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2347
2348 System::set_block_number(6);
2349 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
2350
2351 System::set_block_number(10);
2352 Pallet::reward(&ALICE, 5, Precision::BestEffort).unwrap();
2353
2354 AuthorsMap::mutate(ALICE, |author| {
2355 let info = author.as_mut().unwrap();
2356 let status = &mut info.status;
2357 *status = AuthorStatus::Resigned
2358 });
2359
2360 assert_err!(
2362 Pallet::can_enroll(&ALICE, STANDARD_VALUE),
2363 Error::AuthorHasRewards
2364 );
2365 })
2366 }
2367
2368 #[test]
2369 fn can_resign_success() {
2370 authors_test_ext().execute_with(|| {
2371 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2372 System::set_block_number(6);
2373 Pallet::enroll(&ALICE, LARGE_VALUE, Fortitude::Force).unwrap();
2374
2375 AuthorsMap::mutate(ALICE, |author| {
2376 let info = author.as_mut().unwrap();
2377 let status = &mut info.status;
2378 *status = AuthorStatus::Active
2379 });
2380
2381 set_activity_state(false);
2383
2384 assert_ok! {
2385 Pallet::can_resign(&ALICE)
2386 };
2387 })
2388 }
2389
2390 #[test]
2391 fn can_resign_err_author_in_probation() {
2392 authors_test_ext().execute_with(|| {
2393 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2394 System::set_block_number(6);
2395 Pallet::enroll(&ALICE, LARGE_VALUE, Fortitude::Force).unwrap();
2396
2397 assert_err! {
2398 Pallet::can_resign(
2399 &ALICE,
2400 ), Error::AuthorInProbation
2401 };
2402 })
2403 }
2404
2405 #[test]
2406 fn can_resign_err_redundant_resignation() {
2407 authors_test_ext().execute_with(|| {
2408 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2409 System::set_block_number(6);
2410 Pallet::enroll(&ALICE, LARGE_VALUE, Fortitude::Force).unwrap();
2411
2412 AuthorsMap::mutate(ALICE, |author| {
2413 let info = author.as_mut().unwrap();
2414 let status = &mut info.status;
2415 *status = AuthorStatus::Resigned
2416 });
2417
2418 assert_err! {
2419 Pallet::can_resign(&ALICE),
2420 Error::RedundantResignation
2421 };
2422 })
2423 }
2424
2425 #[test]
2426 fn can_resign_err_author_has_penalties() {
2427 authors_test_ext().execute_with(|| {
2428 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2429
2430 System::set_block_number(6);
2431 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
2432
2433 System::set_block_number(10);
2434 Pallet::penalize(&ALICE, Perbill::from_percent(5)).unwrap();
2435
2436 AuthorsMap::mutate(ALICE, |author| {
2437 let info = author.as_mut().unwrap();
2438 let status = &mut info.status;
2439 *status = AuthorStatus::Active
2440 });
2441
2442 set_activity_state(false);
2443 assert_err!(Pallet::can_resign(&ALICE), Error::AuthorHasPenalties);
2445 })
2446 }
2447
2448 #[test]
2449 fn can_resign_err_author_is_active() {
2450 authors_test_ext().execute_with(|| {
2451 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2452 System::set_block_number(6);
2453 Pallet::enroll(&ALICE, LARGE_VALUE, Fortitude::Force).unwrap();
2454
2455 AuthorsMap::mutate(ALICE, |author| {
2456 let info = author.as_mut().unwrap();
2457 let status = &mut info.status;
2458 *status = AuthorStatus::Active
2459 });
2460
2461 set_activity_state(true);
2463
2464 assert_err! {
2465 Pallet::can_resign(&ALICE),
2466 DispatchError::Other("AuthorIsActive")
2467 };
2468 })
2469 }
2470
2471 #[test]
2472 fn get_collateral_success() {
2473 authors_test_ext().execute_with(|| {
2474 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2475 System::set_block_number(6);
2476 Pallet::enroll(&ALICE, LARGE_VALUE, Fortitude::Force).unwrap();
2477
2478 let actual_collateral = Pallet::get_collateral(&ALICE).unwrap();
2479
2480 assert_eq!(actual_collateral, LARGE_VALUE);
2481 })
2482 }
2483
2484 #[test]
2485 fn total_collateral_success() {
2486 authors_test_ext().execute_with(|| {
2487 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2488 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
2489 System::set_block_number(6);
2490 Pallet::enroll(&ALICE, LARGE_VALUE, Fortitude::Force).unwrap();
2491
2492 let total_collateral = Pallet::total_collateral();
2493 assert_eq!(total_collateral, 100); System::set_block_number(10);
2496 Pallet::enroll(&BOB, STANDARD_VALUE, Fortitude::Force).unwrap();
2497
2498 let total_collateral = Pallet::total_collateral();
2499 assert_eq!(total_collateral, 150); })
2501 }
2502
2503 #[test]
2504 fn enroll_since_success() {
2505 authors_test_ext().execute_with(|| {
2506 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2507 System::set_block_number(6);
2508 Pallet::enroll(&ALICE, LARGE_VALUE, Fortitude::Force).unwrap();
2509
2510 assert_eq!(Pallet::enroll_since(&ALICE), Ok(6));
2511 })
2512 }
2513
2514 #[test]
2515 fn get_status_success() {
2516 authors_test_ext().execute_with(|| {
2517 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2518 System::set_block_number(6);
2519 Pallet::enroll(&ALICE, LARGE_VALUE, Fortitude::Force).unwrap();
2520
2521 assert_eq!(Pallet::get_status(&ALICE), Ok(AuthorStatus::Probation));
2522 })
2523 }
2524
2525 #[test]
2526 fn status_since_success() {
2527 authors_test_ext().execute_with(|| {
2528 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2529 System::set_block_number(6);
2530 Pallet::enroll(&ALICE, LARGE_VALUE, Fortitude::Force).unwrap();
2531
2532 assert_eq!(Pallet::status_since(&ALICE), Ok(6));
2533 })
2534 }
2535
2536 #[test]
2537 fn set_status_success_from_probation() {
2538 authors_test_ext().execute_with(|| {
2539 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2540 System::set_block_number(6);
2541 Pallet::enroll(&ALICE, LARGE_VALUE, Fortitude::Force).unwrap();
2542
2543 let current_status = Pallet::get_status(&ALICE).unwrap();
2544
2545 assert_eq!(current_status, AuthorStatus::Probation);
2546
2547 assert_ok! {
2549 Pallet::set_status(
2550 &ALICE,
2551 AuthorStatus::Probation
2552 )};
2553
2554 assert_err! {
2557 Pallet::set_status(
2558 &ALICE,
2559 AuthorStatus::Resigned
2560 ),
2561 Error::AuthorInProbation
2562 };
2563
2564 System::set_block_number(14);
2565 assert_err! {
2568 Pallet::set_status(
2569 &ALICE,
2570 AuthorStatus::Active
2571 ), Error::AuthorInProbation
2572 };
2573
2574 System::set_block_number(20);
2575 assert_ok!(Pallet::set_status(&ALICE, AuthorStatus::Active));
2577
2578 let current_status = Pallet::get_status(&ALICE).unwrap();
2579
2580 assert_eq!(current_status, AuthorStatus::Active);
2581
2582 System::assert_last_event(Event::AuthorStatus {
2583 author: ALICE,
2584 status: AuthorStatus::Active
2585 }
2586 .into()
2587 );
2588 })
2589 }
2590
2591 #[test]
2592 fn set_status_success_from_active() {
2593 authors_test_ext().execute_with(|| {
2594 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2595 System::set_block_number(6);
2596 Pallet::enroll(&ALICE, LARGE_VALUE, Fortitude::Force).unwrap();
2597
2598 System::set_block_number(20);
2599 assert_ok!(Pallet::set_status(&ALICE, AuthorStatus::Active));
2601
2602 let current_status = Pallet::get_status(&ALICE).unwrap();
2603 assert_eq!(current_status, AuthorStatus::Active);
2604
2605 AuthorsMap::mutate(ALICE, |author| {
2606 let info = author.as_mut().unwrap();
2607 let risk = &mut info.risk_until;
2608 *risk = 32
2609 });
2610 assert_ok!(Pallet::set_status(&ALICE, AuthorStatus::Probation));
2613
2614 System::set_block_number(42);
2615 assert_ok!(Pallet::set_status(&ALICE, AuthorStatus::Active));
2618 let current_status = Pallet::get_status(&ALICE).unwrap();
2619 assert_eq!(current_status, AuthorStatus::Active);
2620
2621 System::set_block_number(45);
2622 assert_ok!(Pallet::set_status(&ALICE, AuthorStatus::Resigned));
2625 let current_status = Pallet::get_status(&ALICE).unwrap();
2626 assert_eq!(current_status, AuthorStatus::Resigned);
2627 })
2628 }
2629
2630 #[test]
2631 fn set_status_success_from_resigned() {
2632 authors_test_ext().execute_with(|| {
2633 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2634 System::set_block_number(6);
2635 Pallet::enroll(&ALICE, LARGE_VALUE, Fortitude::Force).unwrap();
2636
2637 AuthorsMap::mutate(ALICE, |author| {
2638 let info = author.as_mut().unwrap();
2639 let status = &mut info.status;
2640 *status = AuthorStatus::Resigned
2641 });
2642
2643 let current_status = Pallet::get_status(&ALICE).unwrap();
2644
2645 assert_eq!(current_status, AuthorStatus::Resigned);
2646
2647 assert_err! {
2650 Pallet::set_status(
2651 &ALICE,
2652 AuthorStatus::Probation
2653 ), Error::AuthorResigned
2654 };
2655
2656 assert_err! {
2659 Pallet::set_status(
2660 &ALICE,
2661 AuthorStatus::Active
2662 ), Error::AuthorResigned
2663 };
2664
2665 assert_ok! {
2667 Pallet::set_status(
2668 &ALICE,
2669 AuthorStatus::Resigned
2670 )};
2671 })
2672 }
2673
2674 #[test]
2675 fn resign_success() {
2676 authors_test_ext().execute_with(|| {
2677 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2678 System::set_block_number(6);
2679 Pallet::enroll(&ALICE, LARGE_VALUE, Fortitude::Force).unwrap();
2680
2681 AuthorsMap::mutate(ALICE, |author| {
2682 let info = author.as_mut().unwrap();
2683 let status = &mut info.status;
2684 *status = AuthorStatus::Active
2685 });
2686
2687 let current_collateral = Pallet::get_collateral(&ALICE).unwrap();
2688 assert_eq!(current_collateral, LARGE_VALUE);
2689
2690 let author_bal = get_user_balance(&ALICE);
2691 assert_eq!(author_bal, 100);
2692
2693 set_activity_state(false);
2695 assert_ok!(Pallet::resign(&ALICE));
2696
2697 assert_eq!(Pallet::get_status(&ALICE), Ok(AuthorStatus::Resigned));
2698
2699 let author_bal = get_user_balance(&ALICE);
2700 assert_eq!(author_bal, 200); System::assert_last_event(Event::AuthorResigned { author: ALICE, released: 100 }.into());
2702 })
2703 }
2704
2705 #[test]
2706 fn add_collateral_success() {
2707 authors_test_ext().execute_with(|| {
2708 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2709 System::set_block_number(6);
2710 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
2711 let current_collateral = Pallet::get_collateral(&ALICE).unwrap();
2712 assert_eq!(current_collateral, 50);
2713
2714 assert_ok!(Pallet::add_collateral(
2715 &ALICE,
2716 STANDARD_VALUE,
2717 Fortitude::Force
2718 ));
2719 let current_collateral = Pallet::get_collateral(&ALICE).unwrap();
2721 assert_eq!(current_collateral, 100);
2722 System::assert_last_event(Event::AuthorCollateralRaised { author: ALICE, raised: STANDARD_VALUE }.into());
2723 })
2724 }
2725
2726 #[test]
2727 fn is_available_success() {
2728 authors_test_ext().execute_with(|| {
2729 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2730 System::set_block_number(6);
2731 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
2732
2733 assert_ok!(Pallet::is_available(&ALICE));
2734 })
2735 }
2736
2737 #[test]
2738 fn is_available_err_author_needs_more_collateral() {
2739 authors_test_ext().execute_with(|| {
2740 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2741 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
2742
2743 System::set_block_number(6);
2744 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
2745 Pallet::fund(
2746 &ALICE,
2747 &Funder::Direct(BOB),
2748 25,
2749 Precision::BestEffort,
2750 Fortitude::Force,
2751 )
2752 .unwrap();
2753
2754 Pallet::set_hold(&ALICE, 15, Precision::Exact, Fortitude::Force).unwrap();
2755
2756 assert_err!(
2757 Pallet::is_available(&ALICE),
2758 Error::AuthorNeedsMoreCollateral
2759 );
2760 })
2761 }
2762
2763 #[test]
2764 fn is_available_err_author_resigned() {
2765 authors_test_ext().execute_with(|| {
2766 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2767 System::set_block_number(6);
2768 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
2769
2770 AuthorsMap::mutate(ALICE, |author| {
2771 let info = author.as_mut().unwrap();
2772 let status = &mut info.status;
2773 *status = AuthorStatus::Resigned
2774 });
2775
2776 assert_err!(Pallet::is_available(&ALICE), Error::AuthorResigned);
2777 })
2778 }
2779
2780 #[test]
2781 fn on_enroll_emit_event_success() {
2782 authors_test_ext().execute_with(|| {
2783 System::set_block_number(10);
2784 let collateral = LARGE_VALUE;
2785 Pallet::on_enroll(&ALICE, collateral);
2786
2787 System::assert_last_event(
2788 Event::AuthorEnlisted {
2789 author: ALICE,
2790 collateral,
2791 }
2792 .into(),
2793 );
2794 })
2795 }
2796
2797 #[test]
2798 fn on_resign_emit_event_suucess() {
2799 authors_test_ext().execute_with(|| {
2800 System::set_block_number(10);
2801 let released = LARGE_VALUE;
2802 Pallet::on_resign(&ALICE, released);
2803
2804 System::assert_last_event(
2805 Event::AuthorResigned {
2806 author: ALICE,
2807 released,
2808 }
2809 .into(),
2810 );
2811 })
2812 }
2813
2814 #[test]
2815 fn on_add_collateral_emit_event_suucess() {
2816 authors_test_ext().execute_with(|| {
2817 System::set_block_number(10);
2818 let raised = LARGE_VALUE;
2819 Pallet::on_add_collateral(&ALICE, raised);
2820
2821 System::assert_last_event(
2822 Event::AuthorCollateralRaised {
2823 author: ALICE,
2824 raised,
2825 }
2826 .into(),
2827 );
2828 })
2829 }
2830
2831 #[test]
2832 fn on_status_update_emit_event_suucess() {
2833 authors_test_ext().execute_with(|| {
2834 System::set_block_number(10);
2835 let status = AuthorStatus::Active;
2836 Pallet::on_status_update(&ALICE, &status);
2837
2838 System::assert_last_event(
2839 Event::AuthorStatus {
2840 author: ALICE,
2841 status,
2842 }
2843 .into(),
2844 );
2845 })
2846 }
2847
2848 #[test]
2853 fn has_funds_success() {
2854 authors_test_ext().execute_with(|| {
2855 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2856 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
2857 System::set_block_number(6);
2858 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
2859
2860 Pallet::fund(
2861 &ALICE,
2862 &Funder::Direct(BOB),
2863 STANDARD_VALUE,
2864 Precision::BestEffort,
2865 Fortitude::Force,
2866 )
2867 .unwrap();
2868
2869 assert_ok!(Pallet::has_funds(&ALICE));
2870 })
2871 }
2872
2873 #[test]
2874 fn has_funds_err_fund_does_not_exist() {
2875 authors_test_ext().execute_with(|| {
2876 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2877 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
2878 System::set_block_number(6);
2879 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
2880
2881 assert_err!(Pallet::has_funds(&ALICE), Error::FundDoesNotExist);
2882 })
2883 }
2884
2885 #[test]
2886 fn can_fund_success() {
2887 authors_test_ext().execute_with(|| {
2888 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2889 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
2890 System::set_block_number(6);
2891 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
2892
2893 assert_ok!(Pallet::can_fund(
2894 &Funder::Direct(BOB),
2895 &ALICE,
2896 STANDARD_VALUE,
2897 Precision::Exact,
2898 Fortitude::Force
2899 ));
2900 })
2901 }
2902
2903 #[test]
2904 fn can_fund_err_below_minimum_fund() {
2905 authors_test_ext().execute_with(|| {
2906 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2907 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
2908 System::set_block_number(6);
2909 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
2910
2911 assert_err!(
2912 Pallet::can_fund(
2913 &Funder::Direct(BOB),
2914 &ALICE,
2915 MIN_VALUE,
2916 Precision::Exact,
2917 Fortitude::Force
2918 ),
2919 Error::BelowMinimumFund
2920 );
2921 })
2922 }
2923
2924 #[test]
2925 fn can_fund_err_above_maximum_exposure() {
2926 authors_test_ext().execute_with(|| {
2927 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2928 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
2929 System::set_block_number(6);
2930 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
2931
2932 assert_err!(
2933 Pallet::can_fund(
2934 &Funder::Direct(BOB),
2935 &ALICE,
2936 1100, Precision::Exact,
2939 Fortitude::Force
2940 ),
2941 Error::AboveMaximumExposure
2942 );
2943 })
2944 }
2945
2946 #[test]
2947 fn can_fund_err_fund_to_another_digest() {
2948 authors_test_ext().execute_with(|| {
2949 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2950 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
2951 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
2952 System::set_block_number(6);
2953 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
2954 Pallet::enroll(&BOB, STANDARD_VALUE, Fortitude::Force).unwrap();
2955 Pallet::fund(
2956 &ALICE,
2957 &Funder::Direct(CHARLIE),
2958 SMALL_VALUE,
2959 Precision::BestEffort,
2960 Fortitude::Force,
2961 )
2962 .unwrap();
2963
2964 assert_err!(
2965 Pallet::can_fund(
2966 &Funder::Direct(CHARLIE),
2967 &BOB,
2968 LARGE_VALUE,
2969 Precision::Exact,
2970 Fortitude::Force
2971 ),
2972 Error::FundedToAnotherDigest
2973 );
2974 })
2975 }
2976
2977 #[test]
2978 fn can_draw_success() {
2979 authors_test_ext().execute_with(|| {
2980 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2981 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
2982 System::set_block_number(6);
2983 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
2984
2985 Pallet::fund(
2986 &ALICE,
2987 &Funder::Direct(BOB),
2988 SMALL_VALUE,
2989 Precision::BestEffort,
2990 Fortitude::Force,
2991 )
2992 .unwrap();
2993
2994 assert_ok!(Pallet::can_draw(&Funder::Direct(BOB), &ALICE,));
2995 })
2996 }
2997
2998 #[test]
2999 fn can_draw_err_fund_to_another_digest() {
3000 authors_test_ext().execute_with(|| {
3001 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3002 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
3003 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
3004 System::set_block_number(6);
3005 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
3006 Pallet::enroll(&BOB, STANDARD_VALUE, Fortitude::Force).unwrap();
3007 Pallet::fund(
3008 &ALICE,
3009 &Funder::Direct(CHARLIE),
3010 SMALL_VALUE,
3011 Precision::BestEffort,
3012 Fortitude::Force,
3013 )
3014 .unwrap();
3015
3016 assert_err!(
3017 Pallet::can_draw(&Funder::Direct(CHARLIE), &BOB),
3018 Error::FundedToAnotherDigest
3019 );
3020 })
3021 }
3022
3023 #[test]
3024 fn max_exposure_success() {
3025 authors_test_ext().execute_with(|| {
3026 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3027 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
3028 System::set_block_number(6);
3029 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
3030
3031 let max_exposure = Pallet::max_exposure(
3032 &Funder::Direct(BOB),
3033 &ALICE,
3034 Precision::Exact,
3035 Fortitude::Force,
3036 )
3037 .unwrap();
3038 assert_eq!(MaxExposure::get(), max_exposure);
3039 })
3040 }
3041
3042 #[test]
3043 fn min_fund_success() {
3044 authors_test_ext().execute_with(|| {
3045 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3046 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
3047 System::set_block_number(6);
3048 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
3049
3050 let min_fund = Pallet::min_fund(
3051 &Funder::Direct(BOB),
3052 &ALICE,
3053 Precision::Exact,
3054 Fortitude::Force,
3055 )
3056 .unwrap();
3057 assert_eq!(MinFund::get(), min_fund);
3058 })
3059 }
3060
3061 #[test]
3062 fn backed_value_success() {
3063 authors_test_ext().execute_with(|| {
3064 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3065 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
3066 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
3067 System::set_block_number(6);
3068 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
3069
3070 Pallet::fund(
3072 &ALICE,
3073 &Funder::Direct(BOB),
3074 STANDARD_VALUE,
3075 Precision::BestEffort,
3076 Fortitude::Force,
3077 )
3078 .unwrap();
3079
3080 let current_backed_val = Pallet::backed_value(&ALICE).unwrap();
3081 assert_eq!(current_backed_val, 50);
3082
3083 Pallet::fund(
3085 &ALICE,
3086 &Funder::Direct(CHARLIE),
3087 SMALL_VALUE,
3088 Precision::BestEffort,
3089 Fortitude::Force,
3090 )
3091 .unwrap();
3092
3093 let current_backed_val = Pallet::backed_value(&ALICE).unwrap();
3094 assert_eq!(current_backed_val, 75); })
3096 }
3097
3098 #[test]
3099 fn total_backing_sucess() {
3100 authors_test_ext().execute_with(|| {
3101 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3102 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
3103 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
3104 initiate_key_and_set_balance_and_hold(&MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
3105 System::set_block_number(6);
3106 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
3107
3108 System::set_block_number(10);
3109 Pallet::enroll(&MIKE, STANDARD_VALUE, Fortitude::Force).unwrap();
3110
3111 Pallet::fund(
3113 &ALICE,
3114 &Funder::Direct(BOB),
3115 STANDARD_VALUE,
3116 Precision::BestEffort,
3117 Fortitude::Force,
3118 )
3119 .unwrap();
3120
3121 let current_total_backed_val = Pallet::total_backing();
3122 assert_eq!(current_total_backed_val, 50);
3123
3124 Pallet::fund(
3126 &MIKE,
3127 &Funder::Direct(CHARLIE),
3128 LARGE_VALUE,
3129 Precision::BestEffort,
3130 Fortitude::Force,
3131 )
3132 .unwrap();
3133
3134 Pallet::fund(
3136 &ALICE,
3137 &Funder::Direct(BOB),
3138 SMALL_VALUE,
3139 Precision::BestEffort,
3140 Fortitude::Force,
3141 )
3142 .unwrap();
3143
3144 let current_total_backed_val = Pallet::total_backing();
3145 assert_eq!(current_total_backed_val, 175); })
3147 }
3148
3149 #[test]
3150 fn backers_of_success_for_direct() {
3151 authors_test_ext().execute_with(|| {
3152 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3153 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
3154 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
3155 initiate_key_and_set_balance_and_hold(&MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
3156 System::set_block_number(6);
3157 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
3158
3159 System::set_block_number(10);
3160 Pallet::enroll(&MIKE, STANDARD_VALUE, Fortitude::Force).unwrap();
3161
3162 Pallet::fund(
3164 &ALICE,
3165 &Funder::Direct(BOB),
3166 STANDARD_VALUE,
3167 Precision::BestEffort,
3168 Fortitude::Force,
3169 )
3170 .unwrap();
3171
3172 Pallet::fund(
3174 &ALICE,
3175 &Funder::Direct(CHARLIE),
3176 LARGE_VALUE,
3177 Precision::BestEffort,
3178 Fortitude::Force,
3179 )
3180 .unwrap();
3181
3182 Pallet::fund(
3184 &ALICE,
3185 &Funder::Direct(MIKE),
3186 SMALL_VALUE,
3187 Precision::BestEffort,
3188 Fortitude::Force,
3189 )
3190 .unwrap();
3191
3192 let actual_backers_of = Pallet::backers_of(&ALICE).unwrap();
3193 let expected_backers_of = vec![
3194 (Funder::Direct(BOB), 50),
3195 (Funder::Direct(MIKE), 25),
3196 (Funder::Direct(CHARLIE), 100),
3197 ];
3198 assert_eq!(actual_backers_of, expected_backers_of);
3199 })
3200 }
3201
3202 #[test]
3203 fn backers_of_success_for_index() {
3204 authors_test_ext().execute_with(|| {
3205 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3206 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
3207 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
3208 initiate_key_and_set_balance_and_hold(&MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
3209 initiate_key_and_set_balance_and_hold(&ALAN, LARGE_VALUE, LARGE_VALUE).unwrap();
3210
3211 System::set_block_number(6);
3212 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
3213
3214 Pallet::enroll(&BOB, STANDARD_VALUE, Fortitude::Force).unwrap();
3215
3216 Pallet::fund(
3217 &ALICE,
3218 &Funder::Direct(CHARLIE),
3219 STANDARD_VALUE,
3220 Precision::Exact,
3221 Fortitude::Force,
3222 )
3223 .unwrap();
3224
3225 Pallet::fund(
3226 &BOB,
3227 &Funder::Direct(ALAN),
3228 LARGE_VALUE,
3229 Precision::Exact,
3230 Fortitude::Force,
3231 )
3232 .unwrap();
3233
3234 let alice_digest = gen_author_digest(&ALICE).unwrap();
3235 let bob_digest = gen_author_digest(&BOB).unwrap();
3236 let entries = vec![(alice_digest.clone(), 60), (bob_digest.clone(), 40)];
3237
3238 prepare_and_initiate_index(MIKE, FUNDING.into(), &entries, INDEX_DIGEST).unwrap();
3239
3240 let by = Funder::Index {
3241 digest: INDEX_DIGEST,
3242 backer: MIKE,
3243 };
3244 Pallet::fund(&ALICE, &by, LARGE_VALUE, Precision::Exact, Fortitude::Force).unwrap();
3245
3246 let backers_of_alice = Pallet::backers_of(&ALICE).unwrap();
3247 let expected_backers_of_alice = vec![(by.clone(), 60), (Funder::Direct(CHARLIE), 50)];
3248 assert_eq!(backers_of_alice, expected_backers_of_alice);
3249
3250 let backers_of_bob = Pallet::backers_of(&BOB).unwrap();
3251 let expected_backers_of_bob = vec![(by, 40), (Funder::Direct(ALAN), 100)];
3252 assert_eq!(backers_of_bob, expected_backers_of_bob);
3253 })
3254 }
3255
3256 #[test]
3257 fn backers_of_success_for_pool() {
3258 authors_test_ext().execute_with(|| {
3259 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3260 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
3261 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
3262 initiate_key_and_set_balance_and_hold(&MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
3263 initiate_key_and_set_balance_and_hold(&ALAN, LARGE_VALUE, LARGE_VALUE).unwrap();
3264
3265 System::set_block_number(6);
3266 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
3267
3268 Pallet::enroll(&BOB, STANDARD_VALUE, Fortitude::Force).unwrap();
3269
3270 Pallet::fund(
3271 &ALICE,
3272 &Funder::Direct(CHARLIE),
3273 STANDARD_VALUE,
3274 Precision::Exact,
3275 Fortitude::Force,
3276 )
3277 .unwrap();
3278
3279 Pallet::fund(
3280 &BOB,
3281 &Funder::Direct(ALAN),
3282 LARGE_VALUE,
3283 Precision::Exact,
3284 Fortitude::Force,
3285 )
3286 .unwrap();
3287
3288 let alice_digest = gen_author_digest(&ALICE).unwrap();
3289 let bob_digest = gen_author_digest(&BOB).unwrap();
3290 let entries = vec![(alice_digest.clone(), 60), (bob_digest.clone(), 40)];
3291
3292 prepare_and_initiate_pool(
3293 MIKE,
3294 FUNDING.into(),
3295 &entries,
3296 INDEX_DIGEST,
3297 POOL_DIGEST,
3298 Perbill::from_percent(5),
3299 )
3300 .unwrap();
3301
3302 let by = Funder::Pool {
3303 digest: POOL_DIGEST,
3304 backer: MIKE,
3305 };
3306
3307 Pallet::fund(&ALICE, &by, LARGE_VALUE, Precision::Exact, Fortitude::Force).unwrap();
3308
3309 let backers_of_alice = Pallet::backers_of(&ALICE).unwrap();
3310 let expected_backers_of_alice = vec![(by.clone(), 60), (Funder::Direct(CHARLIE), 50)];
3311 assert_eq!(backers_of_alice, expected_backers_of_alice);
3312
3313 let backers_of_bob = Pallet::backers_of(&BOB).unwrap();
3314 let expected_backers_of_bob = vec![(by, 40), (Funder::Direct(ALAN), 100)];
3315 assert_eq!(backers_of_bob, expected_backers_of_bob);
3316 })
3317 }
3318
3319 #[test]
3320 fn backed_for_success_for_direct() {
3321 authors_test_ext().execute_with(|| {
3322 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3323 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
3324 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
3325 initiate_key_and_set_balance_and_hold(&MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
3326 System::set_block_number(6);
3327 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
3328
3329 System::set_block_number(10);
3330 Pallet::enroll(&MIKE, STANDARD_VALUE, Fortitude::Force).unwrap();
3331
3332 Pallet::fund(
3334 &ALICE,
3335 &Funder::Direct(BOB),
3336 STANDARD_VALUE,
3337 Precision::BestEffort,
3338 Fortitude::Force,
3339 )
3340 .unwrap();
3341
3342 let current_total_backed_val = Pallet::total_backing();
3343 assert_eq!(current_total_backed_val, 50);
3344
3345 Pallet::fund(
3347 &MIKE,
3348 &Funder::Direct(CHARLIE),
3349 LARGE_VALUE,
3350 Precision::BestEffort,
3351 Fortitude::Force,
3352 )
3353 .unwrap();
3354
3355 let bob_backed_for = Pallet::backed_for(&Funder::Direct(BOB)).unwrap();
3356 let expected_author = vec![(ALICE, 50)];
3357 assert_eq!(bob_backed_for, expected_author);
3358
3359 let charlie_backed_for = Pallet::backed_for(&Funder::Direct(CHARLIE)).unwrap();
3360 let expected_author = vec![(MIKE, 100)];
3361 assert_eq!(charlie_backed_for, expected_author);
3362 })
3363 }
3364
3365 #[test]
3366 fn backed_for_success_for_index() {
3367 authors_test_ext().execute_with(|| {
3368 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3369 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
3370 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
3371 initiate_key_and_set_balance_and_hold(&MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
3372 initiate_key_and_set_balance_and_hold(&ALAN, LARGE_VALUE, LARGE_VALUE).unwrap();
3373
3374 System::set_block_number(6);
3375 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
3376
3377 Pallet::enroll(&BOB, STANDARD_VALUE, Fortitude::Force).unwrap();
3378
3379 Pallet::fund(
3380 &ALICE,
3381 &Funder::Direct(CHARLIE),
3382 STANDARD_VALUE,
3383 Precision::Exact,
3384 Fortitude::Force,
3385 )
3386 .unwrap();
3387
3388 Pallet::fund(
3389 &BOB,
3390 &Funder::Direct(ALAN),
3391 LARGE_VALUE,
3392 Precision::Exact,
3393 Fortitude::Force,
3394 )
3395 .unwrap();
3396
3397 let alice_digest = gen_author_digest(&ALICE).unwrap();
3398 let bob_digest = gen_author_digest(&BOB).unwrap();
3399 let entries = vec![(alice_digest.clone(), 60), (bob_digest.clone(), 40)];
3400
3401 prepare_and_initiate_index(MIKE, FUNDING.into(), &entries, INDEX_DIGEST).unwrap();
3402
3403 let by = Funder::Index {
3404 digest: INDEX_DIGEST,
3405 backer: MIKE,
3406 };
3407 Pallet::fund(&ALICE, &by, LARGE_VALUE, Precision::Exact, Fortitude::Force).unwrap();
3408
3409 let backed_for = Pallet::backed_for(&by).unwrap();
3410 let expected_backed_for = vec![(ALICE, 60), (BOB, 40)];
3411 assert_eq!(backed_for, expected_backed_for);
3412 })
3413 }
3414
3415 #[test]
3416 fn backed_for_success_for_pool() {
3417 authors_test_ext().execute_with(|| {
3418 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3419 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
3420 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
3421 initiate_key_and_set_balance_and_hold(&MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
3422 initiate_key_and_set_balance_and_hold(&ALAN, LARGE_VALUE, LARGE_VALUE).unwrap();
3423
3424 System::set_block_number(6);
3425 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
3426
3427 Pallet::enroll(&BOB, STANDARD_VALUE, Fortitude::Force).unwrap();
3428
3429 Pallet::fund(
3430 &ALICE,
3431 &Funder::Direct(CHARLIE),
3432 STANDARD_VALUE,
3433 Precision::Exact,
3434 Fortitude::Force,
3435 )
3436 .unwrap();
3437
3438 Pallet::fund(
3439 &BOB,
3440 &Funder::Direct(ALAN),
3441 LARGE_VALUE,
3442 Precision::Exact,
3443 Fortitude::Force,
3444 )
3445 .unwrap();
3446
3447 let alice_digest = gen_author_digest(&ALICE).unwrap();
3448 let bob_digest = gen_author_digest(&BOB).unwrap();
3449 let entries = vec![(alice_digest.clone(), 60), (bob_digest.clone(), 40)];
3450
3451 prepare_and_initiate_pool(
3452 MIKE,
3453 FUNDING.into(),
3454 &entries,
3455 INDEX_DIGEST,
3456 POOL_DIGEST,
3457 Perbill::from_percent(5),
3458 )
3459 .unwrap();
3460
3461 let by = Funder::Pool {
3462 digest: POOL_DIGEST,
3463 backer: MIKE,
3464 };
3465 Pallet::fund(&ALICE, &by, LARGE_VALUE, Precision::Exact, Fortitude::Force).unwrap();
3466
3467 let backed_for = Pallet::backed_for(&by).unwrap();
3468 let expected_backed_for = vec![(ALICE, 60), (BOB, 40)];
3469 assert_eq!(backed_for, expected_backed_for);
3470 })
3471 }
3472
3473 #[test]
3474 fn get_fund_success_for_direct() {
3475 authors_test_ext().execute_with(|| {
3476 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3477 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
3478 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
3479 initiate_key_and_set_balance_and_hold(&MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
3480 initiate_key_and_set_balance_and_hold(&ALAN, LARGE_VALUE, LARGE_VALUE).unwrap();
3481 System::set_block_number(6);
3482 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
3483
3484 System::set_block_number(10);
3485 Pallet::enroll(&MIKE, STANDARD_VALUE, Fortitude::Force).unwrap();
3486
3487 Pallet::fund(
3489 &ALICE,
3490 &Funder::Direct(BOB),
3491 STANDARD_VALUE,
3492 Precision::BestEffort,
3493 Fortitude::Force,
3494 )
3495 .unwrap();
3496
3497 let current_total_backed_val = Pallet::total_backing();
3498 assert_eq!(current_total_backed_val, 50);
3499
3500 Pallet::fund(
3502 &MIKE,
3503 &Funder::Direct(CHARLIE),
3504 LARGE_VALUE,
3505 Precision::BestEffort,
3506 Fortitude::Force,
3507 )
3508 .unwrap();
3509
3510 Pallet::fund(
3512 &ALICE,
3513 &Funder::Direct(BOB),
3514 SMALL_VALUE,
3515 Precision::BestEffort,
3516 Fortitude::Force,
3517 )
3518 .unwrap();
3519
3520 let bobs_fund_to_alice = Pallet::get_fund(&ALICE, &Funder::Direct(BOB)).unwrap();
3521 assert_eq!(bobs_fund_to_alice, 75); let charlies_fund_to_mike = Pallet::get_fund(&MIKE, &Funder::Direct(CHARLIE)).unwrap();
3524 assert_eq!(charlies_fund_to_mike, 100);
3525 })
3526 }
3527
3528 #[test]
3529 fn get_fund_err_author_not_found() {
3530 authors_test_ext().execute_with(|| {
3531 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3532 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
3533 initiate_key_and_set_balance_and_hold(&ALAN, LARGE_VALUE, LARGE_VALUE).unwrap();
3534
3535 System::set_block_number(6);
3536 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
3537
3538 System::set_block_number(10);
3539 Pallet::enroll(&ALAN, STANDARD_VALUE, Fortitude::Force).unwrap();
3540
3541 Pallet::fund(
3542 &ALICE,
3543 &Funder::Direct(BOB),
3544 LARGE_VALUE,
3545 Precision::BestEffort,
3546 Fortitude::Force,
3547 )
3548 .unwrap();
3549
3550 assert_err!(
3551 Pallet::get_fund(&ALAN, &Funder::Direct(BOB)),
3552 Error::FundedToAnotherDigest
3553 );
3554 })
3555 }
3556
3557 #[test]
3558 fn get_fund_success_for_index() {
3559 authors_test_ext().execute_with(|| {
3560 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3561 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
3562 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
3563 initiate_key_and_set_balance_and_hold(&MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
3564 initiate_key_and_set_balance_and_hold(&ALAN, LARGE_VALUE, LARGE_VALUE).unwrap();
3565 System::set_block_number(6);
3566 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
3567
3568 System::set_block_number(10);
3569 Pallet::enroll(&MIKE, STANDARD_VALUE, Fortitude::Force).unwrap();
3570
3571 Pallet::fund(
3573 &ALICE,
3574 &Funder::Direct(BOB),
3575 STANDARD_VALUE,
3576 Precision::BestEffort,
3577 Fortitude::Force,
3578 )
3579 .unwrap();
3580
3581 let current_total_backed_val = Pallet::total_backing();
3582 assert_eq!(current_total_backed_val, 50);
3583
3584 Pallet::fund(
3586 &MIKE,
3587 &Funder::Direct(CHARLIE),
3588 LARGE_VALUE,
3589 Precision::BestEffort,
3590 Fortitude::Force,
3591 )
3592 .unwrap();
3593
3594 let alice_digest = gen_author_digest(&ALICE).unwrap();
3595 let mike_digest = gen_author_digest(&MIKE).unwrap();
3596 let entries = vec![(alice_digest.clone(), 60), (mike_digest.clone(), 40)];
3597
3598 prepare_and_initiate_index(ALAN, FUNDING.into(), &entries, INDEX_DIGEST).unwrap();
3600
3601 let by = Funder::Index {
3602 digest: INDEX_DIGEST,
3603 backer: ALAN,
3604 };
3605 Pallet::fund(&ALICE, &by, LARGE_VALUE, Precision::Exact, Fortitude::Force).unwrap();
3606
3607 let bobs_fund_to_index_alice = Pallet::get_fund(&ALICE, &by).unwrap();
3608 assert_eq!(bobs_fund_to_index_alice, 60);
3609 let bobs_fund_to_index_bob = Pallet::get_fund(&MIKE, &by).unwrap();
3610 assert_eq!(bobs_fund_to_index_bob, 40);
3611 })
3612 }
3613
3614 #[test]
3615 fn get_fund_success_for_pool() {
3616 authors_test_ext().execute_with(|| {
3617 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3618 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
3619 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
3620 initiate_key_and_set_balance_and_hold(&MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
3621 initiate_key_and_set_balance_and_hold(&ALAN, LARGE_VALUE, LARGE_VALUE).unwrap();
3622
3623 System::set_block_number(6);
3624 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
3625
3626 Pallet::enroll(&BOB, STANDARD_VALUE, Fortitude::Force).unwrap();
3627
3628 Pallet::fund(
3629 &ALICE,
3630 &Funder::Direct(CHARLIE),
3631 STANDARD_VALUE,
3632 Precision::Exact,
3633 Fortitude::Force,
3634 )
3635 .unwrap();
3636
3637 Pallet::fund(
3638 &BOB,
3639 &Funder::Direct(ALAN),
3640 LARGE_VALUE,
3641 Precision::Exact,
3642 Fortitude::Force,
3643 )
3644 .unwrap();
3645
3646 let alice_digest = gen_author_digest(&ALICE).unwrap();
3647 let bob_digest = gen_author_digest(&BOB).unwrap();
3648 let entries = vec![(alice_digest.clone(), 60), (bob_digest.clone(), 40)];
3649
3650 prepare_and_initiate_pool(
3651 MIKE,
3652 FUNDING.into(),
3653 &entries,
3654 INDEX_DIGEST,
3655 POOL_DIGEST,
3656 Perbill::from_percent(5),
3657 )
3658 .unwrap();
3659
3660 let by = Funder::Pool {
3661 digest: POOL_DIGEST,
3662 backer: MIKE,
3663 };
3664
3665 Pallet::fund(&ALICE, &by, LARGE_VALUE, Precision::Exact, Fortitude::Force).unwrap();
3666
3667 let bobs_fund_to_index_alice = Pallet::get_fund(&ALICE, &by).unwrap();
3668 assert_eq!(bobs_fund_to_index_alice, 60);
3669 let bobs_fund_to_index_bob = Pallet::get_fund(&BOB, &by).unwrap();
3670 assert_eq!(bobs_fund_to_index_bob, 40);
3671 })
3672 }
3673
3674 #[test]
3675 fn fund_success() {
3676 authors_test_ext().execute_with(|| {
3677 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3678 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
3679 System::set_block_number(6);
3680 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
3681
3682 assert_ok!(Pallet::fund(
3684 &ALICE,
3685 &Funder::Direct(BOB),
3686 STANDARD_VALUE,
3687 Precision::BestEffort,
3688 Fortitude::Force,
3689 ));
3690
3691 let funds_backed = Pallet::get_fund(&ALICE, &Funder::Direct(BOB)).unwrap();
3692 assert_eq!(funds_backed, STANDARD_VALUE);
3693
3694 assert_ok!(Pallet::fund(
3696 &ALICE,
3697 &Funder::Direct(BOB),
3698 SMALL_VALUE,
3699 Precision::BestEffort,
3700 Fortitude::Force,
3701 ));
3702
3703 let funds_backed = Pallet::get_fund(&ALICE, &Funder::Direct(BOB)).unwrap();
3704 assert_eq!(funds_backed, 75); let author_funders = AuthorFunders::get((ALICE, BOB)).unwrap();
3707 assert_eq!(author_funders, Funder::Direct(BOB));
3708 System::assert_last_event(Event::AuthorFunded { author: ALICE, backer: BOB, amount: SMALL_VALUE }.into());
3709 })
3710 }
3711
3712 #[test]
3713 fn fund_success_for_index() {
3714 authors_test_ext().execute_with(|| {
3715 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3716 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
3717 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
3718 initiate_key_and_set_balance_and_hold(&MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
3719 initiate_key_and_set_balance_and_hold(&ALAN, LARGE_VALUE, LARGE_VALUE).unwrap();
3720
3721 System::set_block_number(6);
3722 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
3723
3724 System::set_block_number(8);
3725 Pallet::fund(
3726 &ALICE,
3727 &Funder::Direct(CHARLIE),
3728 STANDARD_VALUE,
3729 Precision::Exact,
3730 Fortitude::Force,
3731 )
3732 .unwrap();
3733
3734 System::set_block_number(12);
3735 Pallet::enroll(&BOB, STANDARD_VALUE, Fortitude::Force).unwrap();
3736
3737 System::set_block_number(15);
3738 Pallet::fund(
3739 &BOB,
3740 &Funder::Direct(ALAN),
3741 LARGE_VALUE,
3742 Precision::Exact,
3743 Fortitude::Force,
3744 )
3745 .unwrap();
3746
3747 let total_backing = Pallet::total_backing();
3748 assert_eq!(total_backing, 150);
3749 let alice_backed_value = Pallet::backed_value(&ALICE).unwrap();
3750 assert_eq!(alice_backed_value, 50);
3751 let bob_backed_value = Pallet::backed_value(&BOB).unwrap();
3752 assert_eq!(bob_backed_value, 100);
3753
3754 let alice_digest = gen_author_digest(&ALICE).unwrap();
3755 let bob_digest = gen_author_digest(&BOB).unwrap();
3756 let entries = vec![(alice_digest.clone(), 60), (bob_digest.clone(), 40)];
3757
3758 let alice_current_hold = Pallet::get_hold(&ALICE).unwrap();
3759 assert_eq!(alice_current_hold, 100);
3760 let bob_current_hold = Pallet::get_hold(&BOB).unwrap();
3761 assert_eq!(bob_current_hold, 150);
3762
3763 prepare_and_initiate_index(MIKE, FUNDING.into(), &entries, INDEX_DIGEST).unwrap();
3764
3765 let by = Funder::Index {
3766 digest: INDEX_DIGEST,
3767 backer: MIKE,
3768 };
3769
3770 assert_ok!(Pallet::fund(
3771 &ALICE,
3772 &by,
3773 LARGE_VALUE,
3774 Precision::Exact,
3775 Fortitude::Force,
3776 ));
3777
3778 let total_backing = Pallet::total_backing();
3779 assert_eq!(total_backing, 250);
3780 let alice_backed_value = Pallet::backed_value(&ALICE).unwrap();
3781 assert_eq!(alice_backed_value, 110); let bob_backed_value = Pallet::backed_value(&BOB).unwrap();
3783 assert_eq!(bob_backed_value, 140); let author_funders = AuthorFunders::get((ALICE, MIKE)).unwrap();
3786 assert_eq!(author_funders, by);
3787
3788 let alice_current_hold = Pallet::get_hold(&ALICE).unwrap();
3789 assert_eq!(alice_current_hold, 160);
3790 let bob_current_hold = Pallet::get_hold(&BOB).unwrap();
3791 assert_eq!(bob_current_hold, 190);
3792 System::assert_last_event(Event::IndexFunded { index: INDEX_DIGEST, backer: MIKE, amount: LARGE_VALUE }.into());
3793 })
3794 }
3795
3796 #[test]
3797 fn fund_success_for_pool() {
3798 authors_test_ext().execute_with(|| {
3799 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3800 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
3801 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
3802 initiate_key_and_set_balance_and_hold(&MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
3803 initiate_key_and_set_balance_and_hold(&ALAN, LARGE_VALUE, LARGE_VALUE).unwrap();
3804
3805 System::set_block_number(6);
3806 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
3807
3808 System::set_block_number(8);
3809 Pallet::fund(
3810 &ALICE,
3811 &Funder::Direct(CHARLIE),
3812 STANDARD_VALUE,
3813 Precision::Exact,
3814 Fortitude::Force,
3815 )
3816 .unwrap();
3817
3818 System::set_block_number(12);
3819 Pallet::enroll(&BOB, STANDARD_VALUE, Fortitude::Force).unwrap();
3820
3821 System::set_block_number(15);
3822 Pallet::fund(
3823 &BOB,
3824 &Funder::Direct(ALAN),
3825 LARGE_VALUE,
3826 Precision::Exact,
3827 Fortitude::Force,
3828 )
3829 .unwrap();
3830
3831 let total_backing = Pallet::total_backing();
3832 assert_eq!(total_backing, 150);
3833 let alice_backed_value = Pallet::backed_value(&ALICE).unwrap();
3834 assert_eq!(alice_backed_value, 50);
3835 let bob_backed_value = Pallet::backed_value(&BOB).unwrap();
3836 assert_eq!(bob_backed_value, 100);
3837
3838 let alice_digest = gen_author_digest(&ALICE).unwrap();
3839 let bob_digest = gen_author_digest(&BOB).unwrap();
3840 let entries = vec![(alice_digest.clone(), 60), (bob_digest.clone(), 40)];
3841
3842 let alice_current_hold = Pallet::get_hold(&ALICE).unwrap();
3843 assert_eq!(alice_current_hold, 100);
3844 let bob_current_hold = Pallet::get_hold(&BOB).unwrap();
3845 assert_eq!(bob_current_hold, 150);
3846
3847 prepare_and_initiate_pool(
3848 ALAN,
3849 FUNDING.into(),
3850 &entries,
3851 INDEX_DIGEST,
3852 POOL_DIGEST,
3853 Perbill::from_percent(5),
3854 )
3855 .unwrap();
3856
3857 let by = Funder::Pool {
3858 digest: POOL_DIGEST,
3859 backer: MIKE,
3860 };
3861
3862 assert_ok!(Pallet::fund(
3863 &ALICE,
3864 &by,
3865 LARGE_VALUE,
3866 Precision::Exact,
3867 Fortitude::Force,
3868 ));
3869
3870 let total_backing = Pallet::total_backing();
3871 assert_eq!(total_backing, 250);
3872 let alice_backed_value = Pallet::backed_value(&ALICE).unwrap();
3873 assert_eq!(alice_backed_value, 110); let bob_backed_value = Pallet::backed_value(&BOB).unwrap();
3875 assert_eq!(bob_backed_value, 140); let author_funders = AuthorFunders::get((ALICE, MIKE)).unwrap();
3878 assert_eq!(author_funders, by);
3879
3880 let alice_current_hold = Pallet::get_hold(&ALICE).unwrap();
3881 assert_eq!(alice_current_hold, 160);
3882 let bob_current_hold = Pallet::get_hold(&BOB).unwrap();
3883 assert_eq!(bob_current_hold, 190);
3884 System::assert_last_event(Event::PoolFunded { pool: POOL_DIGEST, backer: MIKE, amount: LARGE_VALUE }.into());
3885 })
3886 }
3887
3888 #[test]
3889 fn draw_success_for_direct() {
3890 authors_test_ext().execute_with(|| {
3891 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3892 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
3893 System::set_block_number(6);
3894 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
3895
3896 assert_ok!(Pallet::fund(
3898 &ALICE,
3899 &Funder::Direct(BOB),
3900 STANDARD_VALUE,
3901 Precision::BestEffort,
3902 Fortitude::Force,
3903 ));
3904
3905 let current_backed_value = Pallet::backed_value(&ALICE).unwrap();
3906 assert_eq!(current_backed_value, STANDARD_VALUE);
3907
3908 let alice_backers = Pallet::backers_of(&ALICE).unwrap();
3909 let expected_backers = vec![(Funder::Direct(BOB), STANDARD_VALUE)];
3910 assert_eq!(alice_backers, expected_backers);
3911
3912 assert_ok!(Pallet::draw(&ALICE, &Funder::Direct(BOB)));
3914
3915 let current_backed_value = Pallet::backed_value(&ALICE).unwrap();
3916 assert_eq!(current_backed_value, 0);
3917
3918 let alice_backers = Pallet::backers_of(&ALICE).unwrap();
3919 let expected_backers = vec![];
3920 assert_eq!(alice_backers, expected_backers);
3921 assert!(!AuthorFunders::contains_key((ALICE, BOB)));
3922 System::assert_last_event(Event::AuthorDrawn { author: ALICE, backer: BOB, amount: STANDARD_VALUE }.into());
3923 })
3924 }
3925
3926 #[test]
3927 fn draw_success_for_index() {
3928 authors_test_ext().execute_with(|| {
3929 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3930 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
3931 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
3932 initiate_key_and_set_balance_and_hold(&MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
3933 initiate_key_and_set_balance_and_hold(&ALAN, LARGE_VALUE, LARGE_VALUE).unwrap();
3934
3935 System::set_block_number(6);
3936 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
3937
3938 System::set_block_number(8);
3939 Pallet::fund(
3940 &ALICE,
3941 &Funder::Direct(CHARLIE),
3942 STANDARD_VALUE,
3943 Precision::Exact,
3944 Fortitude::Force,
3945 )
3946 .unwrap();
3947
3948 System::set_block_number(12);
3949 Pallet::enroll(&BOB, STANDARD_VALUE, Fortitude::Force).unwrap();
3950
3951 System::set_block_number(15);
3952 Pallet::fund(
3953 &BOB,
3954 &Funder::Direct(ALAN),
3955 LARGE_VALUE,
3956 Precision::Exact,
3957 Fortitude::Force,
3958 )
3959 .unwrap();
3960
3961 let alice_digest = gen_author_digest(&ALICE).unwrap();
3962 let bob_digest = gen_author_digest(&BOB).unwrap();
3963 let entries = vec![(alice_digest.clone(), 60), (bob_digest.clone(), 40)];
3964
3965 prepare_and_initiate_index(MIKE, FUNDING.into(), &entries, INDEX_DIGEST).unwrap();
3966
3967 let by = Funder::Index {
3968 digest: INDEX_DIGEST,
3969 backer: MIKE,
3970 };
3971
3972 Pallet::fund(&ALICE, &by, LARGE_VALUE, Precision::Exact, Fortitude::Force).unwrap();
3973
3974 let total_backing = Pallet::total_backing();
3975 assert_eq!(total_backing, 250);
3976 let alice_backed_value = Pallet::backed_value(&ALICE).unwrap();
3977 assert_eq!(alice_backed_value, 110); let bob_backed_value = Pallet::backed_value(&BOB).unwrap();
3979 assert_eq!(bob_backed_value, 140); let author_funders = AuthorFunders::get((ALICE, MIKE)).unwrap();
3982 assert_eq!(author_funders, by);
3983
3984 assert_ok!(Pallet::draw(&ALICE, &by));
3985
3986 let total_backing = Pallet::total_backing();
3987 assert_eq!(total_backing, 150);
3988 let alice_backed_value = Pallet::backed_value(&ALICE).unwrap();
3989 assert_eq!(alice_backed_value, 50); let bob_backed_value = Pallet::backed_value(&BOB).unwrap();
3991 assert_eq!(bob_backed_value, 100); assert!(!AuthorFunders::contains_key((ALICE, MIKE)));
3994
3995 let mike_balance = get_user_balance(&MIKE);
3996 assert_eq!(mike_balance, 200);
3997 System::assert_last_event(Event::IndexDrawn { index: INDEX_DIGEST, backer: MIKE, amount: LARGE_VALUE }.into());
3998 })
3999 }
4000
4001 #[test]
4002 fn draw_success_for_pool() {
4003 authors_test_ext().execute_with(|| {
4004 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4005 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
4006 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
4007 initiate_key_and_set_balance_and_hold(&MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
4008 initiate_key_and_set_balance_and_hold(&ALAN, LARGE_VALUE, LARGE_VALUE).unwrap();
4009
4010 System::set_block_number(6);
4011 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4012
4013 System::set_block_number(8);
4014 Pallet::fund(
4015 &ALICE,
4016 &Funder::Direct(CHARLIE),
4017 STANDARD_VALUE,
4018 Precision::Exact,
4019 Fortitude::Force,
4020 )
4021 .unwrap();
4022
4023 System::set_block_number(12);
4024 Pallet::enroll(&BOB, STANDARD_VALUE, Fortitude::Force).unwrap();
4025
4026 System::set_block_number(15);
4027 Pallet::fund(
4028 &BOB,
4029 &Funder::Direct(ALAN),
4030 LARGE_VALUE,
4031 Precision::Exact,
4032 Fortitude::Force,
4033 )
4034 .unwrap();
4035
4036 let alice_digest = gen_author_digest(&ALICE).unwrap();
4037 let bob_digest = gen_author_digest(&BOB).unwrap();
4038 let entries = vec![(alice_digest.clone(), 60), (bob_digest.clone(), 40)];
4039
4040 prepare_and_initiate_pool(
4041 ALAN,
4042 FUNDING.into(),
4043 &entries,
4044 INDEX_DIGEST,
4045 POOL_DIGEST,
4046 Perbill::from_percent(5),
4047 )
4048 .unwrap();
4049
4050 let by = Funder::Pool {
4051 digest: POOL_DIGEST,
4052 backer: MIKE,
4053 };
4054
4055 Pallet::fund(&ALICE, &by, LARGE_VALUE, Precision::Exact, Fortitude::Force).unwrap();
4056
4057 let total_backing = Pallet::total_backing();
4058 assert_eq!(total_backing, 250);
4059 let alice_backed_value = Pallet::backed_value(&ALICE).unwrap();
4060 assert_eq!(alice_backed_value, 110); let bob_backed_value = Pallet::backed_value(&BOB).unwrap();
4062 assert_eq!(bob_backed_value, 140); let author_funders = AuthorFunders::get((ALICE, MIKE)).unwrap();
4065 assert_eq!(author_funders, by);
4066 let author_funders = AuthorFunders::get((BOB, MIKE)).unwrap();
4067 assert_eq!(author_funders, by);
4068
4069 assert_ok!(Pallet::draw(&ALICE, &by));
4070
4071 let total_backing = Pallet::total_backing();
4072 assert_eq!(total_backing, 150);
4073 let alice_backed_value = Pallet::backed_value(&ALICE).unwrap();
4074 assert_eq!(alice_backed_value, 50); let bob_backed_value = Pallet::backed_value(&BOB).unwrap();
4076 assert_eq!(bob_backed_value, 100); assert!(!AuthorFunders::contains_key((ALICE, MIKE)));
4079
4080 let mike_balance = get_user_balance(&MIKE);
4081 assert_eq!(mike_balance, 195); let alan_balance = get_user_balance(&ALAN);
4083 assert_eq!(alan_balance, 105); System::assert_last_event(Event::PoolDrawn { pool: POOL_DIGEST, backer: MIKE, amount: 95 }.into());
4085 })
4086 }
4087
4088 #[test]
4089 fn on_drawn_direct_success() {
4090 authors_test_ext().execute_with(|| {
4091 System::set_block_number(10);
4092 let draw_amount = STANDARD_VALUE;
4093 let by = Funder::<Test>::Direct(ALICE);
4094 Pallet::on_drawn(&ALAN, &by, draw_amount);
4095
4096 System::assert_last_event(
4097 Event::AuthorDrawn {
4098 author: ALAN,
4099 backer: ALICE,
4100 amount: draw_amount,
4101 }
4102 .into(),
4103 );
4104 })
4105 }
4106
4107 #[test]
4108 fn on_drawn_index_success() {
4109 authors_test_ext().execute_with(|| {
4110 System::set_block_number(10);
4111 let draw_amount = STANDARD_VALUE;
4112 let by = Funder::<Test>::Index {
4113 digest: INDEX_DIGEST,
4114 backer: ALICE,
4115 };
4116 Pallet::on_drawn(&ALAN, &by, draw_amount);
4117
4118 System::assert_last_event(
4119 Event::IndexDrawn {
4120 index: INDEX_DIGEST,
4121 backer: ALICE,
4122 amount: draw_amount,
4123 }
4124 .into(),
4125 );
4126 })
4127 }
4128
4129 #[test]
4130 fn on_drawn_pool_success() {
4131 authors_test_ext().execute_with(|| {
4132 System::set_block_number(10);
4133 let draw_amount = STANDARD_VALUE;
4134 let by = Funder::<Test>::Pool {
4135 digest: POOL_DIGEST,
4136 backer: ALICE,
4137 };
4138 Pallet::on_drawn(&ALAN, &by, draw_amount);
4139
4140 System::assert_last_event(
4141 Event::PoolDrawn {
4142 pool: POOL_DIGEST,
4143 backer: ALICE,
4144 amount: draw_amount,
4145 }
4146 .into(),
4147 );
4148 })
4149 }
4150
4151 #[test]
4152 fn on_funded_direct_success() {
4153 authors_test_ext().execute_with(|| {
4154 System::set_block_number(10);
4155 let fund_amount = STANDARD_VALUE;
4156 let by = Funder::<Test>::Direct(ALICE);
4157 Pallet::on_funded(&ALAN, &by, fund_amount);
4158
4159 System::assert_last_event(
4160 Event::AuthorFunded {
4161 author: ALAN,
4162 backer: ALICE,
4163 amount: fund_amount,
4164 }
4165 .into(),
4166 );
4167 })
4168 }
4169
4170 #[test]
4171 fn on_funded_index_success() {
4172 authors_test_ext().execute_with(|| {
4173 System::set_block_number(10);
4174 let draw_amount = STANDARD_VALUE;
4175 let by = Funder::<Test>::Index {
4176 digest: INDEX_DIGEST,
4177 backer: ALICE,
4178 };
4179 Pallet::on_funded(&ALAN, &by, draw_amount);
4180
4181 System::assert_last_event(
4182 Event::IndexFunded {
4183 index: INDEX_DIGEST,
4184 backer: ALICE,
4185 amount: draw_amount,
4186 }
4187 .into(),
4188 );
4189 })
4190 }
4191
4192 #[test]
4193 fn on_funded_pool_success() {
4194 authors_test_ext().execute_with(|| {
4195 System::set_block_number(10);
4196 let draw_amount = STANDARD_VALUE;
4197 let by = Funder::<Test>::Pool {
4198 digest: POOL_DIGEST,
4199 backer: ALICE,
4200 };
4201 Pallet::on_funded(&ALAN, &by, draw_amount);
4202
4203 System::assert_last_event(
4204 Event::PoolFunded {
4205 pool: POOL_DIGEST,
4206 backer: ALICE,
4207 amount: draw_amount,
4208 }
4209 .into(),
4210 );
4211 })
4212 }
4213
4214 #[test]
4219 fn reward_success() {
4220 authors_test_ext().execute_with(|| {
4221 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4222
4223 System::set_block_number(6);
4224 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4225
4226 System::set_block_number(10);
4227 let reward_units = 5;
4228 let reward_block = Pallet::reward(&ALICE, reward_units, Precision::BestEffort).unwrap();
4229 assert_eq!(reward_block, 12);
4231 let reward_scheduled = AuthorRewards::get((12, ALICE)).unwrap();
4232 assert_eq!(reward_scheduled, 5);
4233
4234 let reward_units = 10;
4238 let reward_block = Pallet::reward(&ALICE, reward_units, Precision::BestEffort).unwrap();
4239
4240 assert_eq!(reward_block, 13);
4242 let reward_scheduled = AuthorRewards::get((13, ALICE)).unwrap();
4243 assert_eq!(reward_scheduled, 10);
4244 System::assert_last_event(Event::AuthorRewardScheduled { author: ALICE, amount: reward_units, at: reward_block }.into());
4245 })
4246 }
4247
4248 #[test]
4249 fn reward_err_author_resigned() {
4250 authors_test_ext().execute_with(|| {
4251 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4252
4253 System::set_block_number(6);
4254 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4255
4256 AuthorsMap::mutate(ALICE, |author| {
4257 let info = author.as_mut().unwrap();
4258 let status = &mut info.status;
4259 *status = AuthorStatus::Resigned;
4260 });
4261
4262 let reward_unit = 5;
4263 assert_err!(
4264 Pallet::reward(&ALICE, reward_unit, Precision::BestEffort,),
4265 Error::AuthorResigned
4266 );
4267 })
4268 }
4269
4270 #[test]
4271 fn reclaim_success() {
4272 authors_test_ext().execute_with(|| {
4273 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4274
4275 System::set_block_number(6);
4276 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4277
4278 System::set_block_number(10);
4279 let reward_units = 5;
4280 let reward_block = Pallet::reward(&ALICE, reward_units, Precision::BestEffort).unwrap();
4281 assert_eq!(reward_block, 12);
4283 let reward_scheduled = AuthorRewards::get((12, ALICE)).unwrap();
4284 assert_eq!(reward_scheduled, 5);
4285
4286 System::set_block_number(11);
4287 assert_ok!(Pallet::reclaim(&ALICE, 12));
4288 assert!(!AuthorRewards::contains_key((12, ALICE)));
4289 System::assert_last_event(Event::AuthorRewardReclaimed { author: ALICE, amount: reward_units}.into());
4290 })
4291 }
4292
4293 #[test]
4294 fn reclaim_err_finalized_obligations() {
4295 authors_test_ext().execute_with(|| {
4296 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4297
4298 System::set_block_number(6);
4299 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4300
4301 System::set_block_number(10);
4302 let reward_units = 5;
4303 let reward_block = Pallet::reward(&ALICE, reward_units, Precision::BestEffort).unwrap();
4304 assert_eq!(reward_block, 12);
4305
4306 System::set_block_number(12);
4307 assert_err!(Pallet::reclaim(&ALICE, 12), Error::FinalizedObligations);
4308 })
4309 }
4310
4311 #[test]
4312 fn reclaim_err_rewards_not_founds() {
4313 authors_test_ext().execute_with(|| {
4314 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4315
4316 System::set_block_number(6);
4317 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4318
4319 System::set_block_number(10);
4320 assert_err!(Pallet::reclaim(&ALICE, 12), Error::RewardNotFound);
4321 })
4322 }
4323
4324 #[test]
4325 fn penalize_success() {
4326 authors_test_ext().execute_with(|| {
4327 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4328
4329 System::set_block_number(6);
4330 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4331
4332 let meta = Pallet::get_meta(&ALICE).unwrap();
4333 assert_eq!(meta.risk_until, 6);
4334
4335 System::set_block_number(10);
4336 let penalty_block = Pallet::penalize(&ALICE, Perbill::from_percent(5)).unwrap();
4337 assert_eq!(penalty_block, 14);
4339 let penalty_scheduled = AuthorPenalties::get((14, ALICE)).unwrap();
4340 assert_eq!(penalty_scheduled, Perbill::from_percent(5));
4341 let meta = Pallet::get_meta(&ALICE).unwrap();
4343 assert_eq!(meta.risk_until, 11);
4344
4345 let penalty_block = Pallet::penalize(&ALICE, Perbill::from_percent(10)).unwrap();
4349 assert_eq!(penalty_block, 15);
4351 let penalty_scheduled = AuthorPenalties::get((15, ALICE)).unwrap();
4352 assert_eq!(penalty_scheduled, Perbill::from_percent(10));
4353 let meta = Pallet::get_meta(&ALICE).unwrap();
4355 assert_eq!(meta.risk_until, 12);
4356 System::assert_last_event(Event::AuthorPenaltyScheduled { author: ALICE, factor: penalty_scheduled, at: 15 }.into());
4357 })
4358 }
4359
4360 #[test]
4361 fn penalize_err_zero_penalty_found() {
4362 authors_test_ext().execute_with(|| {
4363 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4364
4365 System::set_block_number(6);
4366 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4367
4368 System::set_block_number(10);
4369 assert_err!(
4370 Pallet::penalize(&ALICE, Perbill::from_percent(0)),
4371 Error::ZeroPenaltyFound
4372 );
4373 })
4374 }
4375
4376 #[test]
4377 fn penalize_err_author_resigned() {
4378 authors_test_ext().execute_with(|| {
4379 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4380
4381 System::set_block_number(6);
4382 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4383
4384 AuthorsMap::mutate(ALICE, |author| {
4385 let info = author.as_mut().unwrap();
4386 let status = &mut info.status;
4387 *status = AuthorStatus::Resigned;
4388 });
4389
4390 System::set_block_number(10);
4391 assert_err!(
4392 Pallet::penalize(&ALICE, Perbill::from_percent(5)),
4393 Error::AuthorResigned
4394 );
4395 })
4396 }
4397
4398 #[test]
4399 fn forgive_success() {
4400 authors_test_ext().execute_with(|| {
4401 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4402
4403 System::set_block_number(6);
4404 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4405
4406 System::set_block_number(10);
4407 let penalty_factor = Perbill::from_percent(5);
4408 let penalty_block = Pallet::penalize(&ALICE, penalty_factor).unwrap();
4409
4410 assert_eq!(penalty_block, 14);
4411 let penalty_scheduled = AuthorPenalties::get((14, ALICE)).unwrap();
4412 assert_eq!(penalty_scheduled, penalty_factor);
4413
4414 let meta = Pallet::get_meta(&ALICE).unwrap();
4415 assert_eq!(meta.risk_until, 11);
4416
4417 assert_ok!(Pallet::forgive(&ALICE, 14));
4418
4419 assert!(!AuthorPenalties::contains_key((14, ALICE)));
4420
4421 let meta = Pallet::get_meta(&ALICE).unwrap();
4422 assert_eq!(meta.risk_until, 10);
4423 System::assert_last_event(Event::AuthorPenaltyForgiven { author: ALICE, factor: penalty_scheduled }.into());
4424 })
4425 }
4426
4427 #[test]
4428 fn forgive_err_finalized_obligations() {
4429 authors_test_ext().execute_with(|| {
4430 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4431
4432 System::set_block_number(6);
4433 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4434
4435 System::set_block_number(10);
4436 let penalty_factor = Perbill::from_percent(5);
4437 let penalty_block = Pallet::penalize(&ALICE, penalty_factor).unwrap();
4438
4439 assert_eq!(penalty_block, 14);
4440 let penalty_scheduled = AuthorPenalties::get((14, ALICE)).unwrap();
4441 assert_eq!(penalty_scheduled, penalty_factor);
4442
4443 System::set_block_number(14);
4444 assert_err!(Pallet::forgive(&ALICE, 14), Error::FinalizedObligations);
4445 })
4446 }
4447
4448 #[test]
4449 fn forgive_err_rewards_not_founds() {
4450 authors_test_ext().execute_with(|| {
4451 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4452
4453 System::set_block_number(6);
4454 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4455
4456 System::set_block_number(10);
4457 assert_err!(Pallet::forgive(&ALICE, 14), Error::PenaltyNotFound);
4458 })
4459 }
4460
4461 #[test]
4462 fn has_reward_success() {
4463 authors_test_ext().execute_with(|| {
4464 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4465
4466 System::set_block_number(6);
4467 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4468
4469 System::set_block_number(10);
4470 let reward_units = 5;
4471 Pallet::reward(&ALICE, reward_units, Precision::BestEffort).unwrap();
4472
4473 assert_ok!(Pallet::has_reward(&ALICE));
4474 })
4475 }
4476
4477 #[test]
4478 fn has_reward_err_reward_not_found() {
4479 authors_test_ext().execute_with(|| {
4480 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4481
4482 System::set_block_number(6);
4483 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4484
4485 assert_err!(Pallet::has_reward(&ALICE), Error::RewardNotFound);
4486 })
4487 }
4488
4489 #[test]
4490 fn has_penalty_success() {
4491 authors_test_ext().execute_with(|| {
4492 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4493
4494 System::set_block_number(6);
4495 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4496
4497 System::set_block_number(10);
4498 Pallet::penalize(&ALICE, Perbill::from_percent(5)).unwrap();
4499
4500 assert_ok!(Pallet::has_penalty(&ALICE));
4501 })
4502 }
4503
4504 #[test]
4505 fn has_penalty_penalty_not_found() {
4506 authors_test_ext().execute_with(|| {
4507 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4508
4509 System::set_block_number(6);
4510 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4511
4512 assert_err!(Pallet::has_penalty(&ALICE), Error::PenaltyNotFound);
4513 })
4514 }
4515
4516 #[test]
4517 fn get_rewards_of_success() {
4518 authors_test_ext().execute_with(|| {
4519 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4520
4521 System::set_block_number(6);
4522 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4523
4524 System::set_block_number(10);
4525 let reward_units = 5;
4526 Pallet::reward(&ALICE, reward_units, Precision::BestEffort).unwrap();
4527
4528 System::set_block_number(11);
4529 let reward_units = 10;
4530 Pallet::reward(&ALICE, reward_units, Precision::BestEffort).unwrap();
4531
4532 let reward_units = 8;
4533 Pallet::reward(&ALICE, reward_units, Precision::BestEffort).unwrap();
4534
4535 let rewards_of = Pallet::get_rewards_of(&ALICE).unwrap();
4536 let expected_rewards_of = vec![(12, 5), (13, 10), (14, 8)];
4537 assert_eq!(rewards_of, expected_rewards_of);
4538 })
4539 }
4540
4541 #[test]
4542 fn get_rewards_of_success_with_empty_vec_when_no_rewards() {
4543 authors_test_ext().execute_with(|| {
4544 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4545
4546 System::set_block_number(6);
4547 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4548
4549 let rewards_of = Pallet::get_rewards_of(&ALICE).unwrap();
4550 assert_eq!(rewards_of, vec![]);
4551 })
4552 }
4553
4554 #[test]
4555 fn get_penalties_of_success() {
4556 authors_test_ext().execute_with(|| {
4557 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4558
4559 System::set_block_number(6);
4560 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4561
4562 System::set_block_number(10);
4563 let penalty_factor = Perbill::from_percent(5);
4564 Pallet::penalize(&ALICE, penalty_factor).unwrap();
4565
4566 System::set_block_number(11);
4567 let penalty_factor = Perbill::from_percent(10);
4568 Pallet::penalize(&ALICE, penalty_factor).unwrap();
4569
4570 System::set_block_number(12);
4571 let penalty_factor = Perbill::from_percent(8);
4572 Pallet::penalize(&ALICE, penalty_factor).unwrap();
4573
4574 let penalties_of = Pallet::get_penalties_of(&ALICE).unwrap();
4575 let expected_penalties_of = vec![
4576 (14, Perbill::from_percent(5)),
4577 (15, Perbill::from_percent(10)),
4578 (16, Perbill::from_percent(8)),
4579 ];
4580 assert_eq!(penalties_of, expected_penalties_of);
4581 })
4582 }
4583
4584 #[test]
4585 fn get_penalties_of_success_with_empty_vec_when_no_penalty() {
4586 authors_test_ext().execute_with(|| {
4587 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4588
4589 System::set_block_number(6);
4590 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4591
4592 let penalties_of = Pallet::get_penalties_of(&ALICE).unwrap();
4593 assert_eq!(penalties_of, vec![]);
4594 })
4595 }
4596
4597 #[test]
4598 fn get_rewards_on_success() {
4599 authors_test_ext().execute_with(|| {
4600 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4601
4602 System::set_block_number(6);
4603 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4604
4605 System::set_block_number(10);
4606 let reward_units = 5;
4607 Pallet::reward(&ALICE, reward_units, Precision::BestEffort).unwrap();
4608
4609 System::set_block_number(11);
4610 let reward_units = 10;
4611 Pallet::reward(&ALICE, reward_units, Precision::BestEffort).unwrap();
4612
4613 let reward_on_12 = Pallet::get_rewards_on(12).unwrap();
4614 let expected_reward_on_12 = vec![(ALICE, 5)];
4615 assert_eq!(reward_on_12, expected_reward_on_12);
4616
4617 let reward_on_13 = Pallet::get_rewards_on(13).unwrap();
4618 let expected_reward_on_13 = vec![(ALICE, 10)];
4619 assert_eq!(reward_on_13, expected_reward_on_13);
4620 })
4621 }
4622
4623 #[test]
4624 fn get_rewards_on_err_finalize_obligations() {
4625 authors_test_ext().execute_with(|| {
4626 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4627
4628 System::set_block_number(6);
4629 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4630
4631 System::set_block_number(10);
4632 let reward_units = 5;
4633 Pallet::reward(&ALICE, reward_units, Precision::BestEffort).unwrap();
4634
4635 System::set_block_number(11);
4636 let reward_units = 10;
4637 Pallet::reward(&ALICE, reward_units, Precision::BestEffort).unwrap();
4638
4639 System::set_block_number(15);
4640 assert_err!(Pallet::get_rewards_on(12), Error::FinalizedObligations);
4641 })
4642 }
4643
4644 #[test]
4645 fn get_rewards_on_err_contains_no_rewards() {
4646 authors_test_ext().execute_with(|| {
4647 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4648
4649 System::set_block_number(6);
4650 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4651
4652 System::set_block_number(10);
4653 let reward_units = 5;
4654 Pallet::reward(&ALICE, reward_units, Precision::BestEffort).unwrap();
4655
4656 let rewards_on = Pallet::get_rewards_on(13).unwrap();
4657 assert_eq!(rewards_on, vec![]);
4658 })
4659 }
4660
4661 #[test]
4662 fn get_penalties_on_success() {
4663 authors_test_ext().execute_with(|| {
4664 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4665
4666 System::set_block_number(6);
4667 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4668
4669 System::set_block_number(10);
4670 let penalty_factor = Perbill::from_percent(5);
4671 Pallet::penalize(&ALICE, penalty_factor).unwrap();
4672
4673 System::set_block_number(11);
4674 let penalty_factor = Perbill::from_percent(10);
4675 Pallet::penalize(&ALICE, penalty_factor).unwrap();
4676
4677 let penalty_on_12 = Pallet::get_penalties_on(14).unwrap();
4678 let expected_penalty_on_12 = vec![(ALICE, Perbill::from_percent(5))];
4679 assert_eq!(penalty_on_12, expected_penalty_on_12);
4680
4681 let penalty_on_13 = Pallet::get_penalties_on(15).unwrap();
4682 let expected_penalty_on_13 = vec![(ALICE, Perbill::from_percent(10))];
4683 assert_eq!(penalty_on_13, expected_penalty_on_13);
4684 })
4685 }
4686
4687 #[test]
4688 fn get_penalties_on_err_finalized_obligations() {
4689 authors_test_ext().execute_with(|| {
4690 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4691
4692 System::set_block_number(6);
4693 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4694
4695 System::set_block_number(10);
4696 let penalty_factor = Perbill::from_percent(5);
4697 Pallet::penalize(&ALICE, penalty_factor).unwrap();
4698
4699 System::set_block_number(11);
4700 let penalty_factor = Perbill::from_percent(10);
4701 Pallet::penalize(&ALICE, penalty_factor).unwrap();
4702
4703 System::set_block_number(15);
4704 assert_err!(Pallet::get_penalties_on(14), Error::FinalizedObligations);
4705 })
4706 }
4707
4708 #[test]
4709 fn get_penalties_on_success_with_empty_vec_when_no_penalty() {
4710 authors_test_ext().execute_with(|| {
4711 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4712
4713 System::set_block_number(6);
4714 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4715
4716 System::set_block_number(10);
4717 let penalty_factor = Perbill::from_percent(5);
4718 Pallet::penalize(&ALICE, penalty_factor).unwrap();
4719
4720 let penalties_on = Pallet::get_penalties_on(15).unwrap();
4721 assert_eq!(penalties_on, vec![]);
4722 })
4723 }
4724
4725 #[test]
4726 fn get_hold_success() {
4727 authors_test_ext().execute_with(|| {
4728 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4729 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
4730 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
4731
4732 System::set_block_number(6);
4733 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4734
4735 Pallet::fund(
4736 &ALICE,
4737 &Funder::Direct(BOB),
4738 LARGE_VALUE,
4739 Precision::BestEffort,
4740 Fortitude::Force,
4741 )
4742 .unwrap();
4743
4744 let actual_hold = Pallet::get_hold(&ALICE).unwrap();
4745 let expected_hold = 150; assert_eq!(actual_hold, expected_hold);
4747
4748 Pallet::fund(
4749 &ALICE,
4750 &Funder::Direct(CHARLIE),
4751 SMALL_VALUE,
4752 Precision::BestEffort,
4753 Fortitude::Force,
4754 )
4755 .unwrap();
4756
4757 let actual_hold = Pallet::get_hold(&ALICE).unwrap();
4758 let expected_hold = 175; assert_eq!(actual_hold, expected_hold);
4760 })
4761 }
4762
4763 #[test]
4764 fn set_hold_success() {
4765 authors_test_ext().execute_with(|| {
4766 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4767 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
4768 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
4769
4770 System::set_block_number(6);
4771 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4772
4773 Pallet::fund(
4774 &ALICE,
4775 &Funder::Direct(BOB),
4776 LARGE_VALUE,
4777 Precision::BestEffort,
4778 Fortitude::Force,
4779 )
4780 .unwrap();
4781
4782 Pallet::fund(
4783 &ALICE,
4784 &Funder::Direct(CHARLIE),
4785 SMALL_VALUE,
4786 Precision::BestEffort,
4787 Fortitude::Force,
4788 )
4789 .unwrap();
4790
4791 let actual_hold = Pallet::get_hold(&ALICE).unwrap();
4792 let expected_hold = 175; assert_eq!(actual_hold, expected_hold);
4794
4795 let collateral_value = Pallet::get_collateral(&ALICE).unwrap();
4796 let funding_value = Pallet::total_backing();
4797 assert_eq!(collateral_value, 50);
4798 assert_eq!(funding_value, 125);
4799
4800 assert_ok!(Pallet::set_hold(
4801 &ALICE,
4802 250,
4803 Precision::Exact,
4804 Fortitude::Force
4805 ));
4806
4807 let actual_hold = Pallet::get_hold(&ALICE).unwrap();
4808 let expected_hold = 250;
4809 assert_eq!(actual_hold, expected_hold);
4811
4812 let collateral_value = Pallet::get_collateral(&ALICE).unwrap();
4814 let funding_value = Pallet::total_backing();
4815 assert_eq!(collateral_value, 71);
4816 assert_eq!(funding_value, 179);
4817 System::assert_last_event(Event::AuthorTotalHold { author: ALICE, value: 250 }.into());
4818 })
4819 }
4820
4821 #[test]
4822 fn on_reward_event_emmission_success() {
4823 authors_test_ext().execute_with(|| {
4824 System::set_block_number(10);
4825 let at = System::block_number();
4826 let amount = LARGE_VALUE;
4827 Pallet::on_reward(&ALICE, amount, at);
4828
4829 System::assert_last_event(
4830 AuthorRewardScheduled {
4831 author: ALICE,
4832 amount,
4833 at,
4834 }
4835 .into(),
4836 )
4837 })
4838 }
4839
4840 #[test]
4841 fn on_reclaim_event_emmission_success() {
4842 authors_test_ext().execute_with(|| {
4843 System::set_block_number(10);
4844 let amount = LARGE_VALUE;
4845 Pallet::on_reclaim(&ALICE, amount);
4846
4847 System::assert_last_event(
4848 AuthorRewardReclaimed {
4849 author: ALICE,
4850 amount,
4851 }
4852 .into(),
4853 )
4854 })
4855 }
4856
4857 #[test]
4858 fn on_set_hold_event_emmission_success() {
4859 authors_test_ext().execute_with(|| {
4860 System::set_block_number(10);
4861 let value = LARGE_VALUE;
4862 Pallet::on_set_hold(&ALICE, value);
4863
4864 System::assert_last_event(
4865 AuthorTotalHold {
4866 author: ALICE,
4867 value,
4868 }
4869 .into(),
4870 )
4871 })
4872 }
4873
4874 #[test]
4875 fn on_forgive_event_emmission_success() {
4876 authors_test_ext().execute_with(|| {
4877 System::set_block_number(10);
4878 let factor = Perbill::from_percent(10);
4879 Pallet::on_forgive(&ALICE, factor);
4880
4881 System::assert_last_event(
4882 AuthorPenaltyForgiven {
4883 author: ALICE,
4884 factor,
4885 }
4886 .into(),
4887 )
4888 })
4889 }
4890
4891 #[test]
4892 fn on_penalize_event_emmission_success() {
4893 authors_test_ext().execute_with(|| {
4894 System::set_block_number(10);
4895 let at = System::block_number();
4896 let factor = Perbill::from_percent(10);
4897 Pallet::on_penalize(&ALICE, factor, at);
4898
4899 System::assert_last_event(
4900 AuthorPenaltyScheduled {
4901 author: ALICE,
4902 factor,
4903 at,
4904 }
4905 .into(),
4906 )
4907 })
4908 }
4909
4910 #[test]
4915 fn is_on_probation_success() {
4916 authors_test_ext().execute_with(|| {
4917 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4918
4919 System::set_block_number(6);
4920 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4921
4922 assert_ok!(Pallet::is_on_probation(&ALICE));
4923 })
4924 }
4925
4926 #[test]
4927 fn is_on_probation_err_author_is_active() {
4928 authors_test_ext().execute_with(|| {
4929 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4930
4931 System::set_block_number(6);
4932 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4933
4934 AuthorsMap::mutate(ALICE, |author| {
4935 let info = author.as_mut().unwrap();
4936 let status = &mut info.status;
4937 *status = AuthorStatus::Active;
4938 });
4939
4940 assert_err!(Pallet::is_on_probation(&ALICE), Error::AuthorIsActive);
4941 })
4942 }
4943
4944 #[test]
4945 fn is_on_probation_err_author_is_resigned() {
4946 authors_test_ext().execute_with(|| {
4947 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4948
4949 System::set_block_number(6);
4950 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4951
4952 AuthorsMap::mutate(ALICE, |author| {
4953 let info = author.as_mut().unwrap();
4954 let status = &mut info.status;
4955 *status = AuthorStatus::Resigned;
4956 });
4957
4958 assert_err!(Pallet::is_on_probation(&ALICE), Error::AuthorResigned);
4959 })
4960 }
4961
4962 #[test]
4963 fn is_permanent_success() {
4964 authors_test_ext().execute_with(|| {
4965 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4966
4967 System::set_block_number(6);
4968 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4969
4970 AuthorsMap::mutate(ALICE, |author| {
4971 let info = author.as_mut().unwrap();
4972 let status = &mut info.status;
4973 *status = AuthorStatus::Active;
4974 });
4975
4976 assert_ok!(Pallet::is_permanent(&ALICE));
4977 })
4978 }
4979
4980 #[test]
4981 fn is_permanent_err_author_in_probation() {
4982 authors_test_ext().execute_with(|| {
4983 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4984
4985 System::set_block_number(6);
4986 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4987
4988 assert_err!(Pallet::is_permanent(&ALICE), Error::AuthorInProbation);
4989 })
4990 }
4991
4992 #[test]
4993 fn is_permanent_err_author_resigned() {
4994 authors_test_ext().execute_with(|| {
4995 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
4996
4997 System::set_block_number(6);
4998 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
4999
5000 AuthorsMap::mutate(ALICE, |author| {
5001 let info = author.as_mut().unwrap();
5002 let status = &mut info.status;
5003 *status = AuthorStatus::Resigned;
5004 });
5005
5006 assert_err!(Pallet::is_permanent(&ALICE), Error::AuthorResigned);
5007 })
5008 }
5009
5010 #[test]
5011 fn can_be_permament_success() {
5012 authors_test_ext().execute_with(|| {
5013 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5014
5015 System::set_block_number(6);
5016 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5017
5018 System::set_block_number(14);
5019 assert_err!(Pallet::can_be_permanent(&ALICE), Error::AuthorInProbation);
5020
5021 System::set_block_number(16);
5022 assert_ok!(Pallet::can_be_permanent(&ALICE));
5023 })
5024 }
5025
5026 #[test]
5027 fn can_be_permament_err_author_is_active() {
5028 authors_test_ext().execute_with(|| {
5029 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5030
5031 System::set_block_number(6);
5032 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5033
5034 AuthorsMap::mutate(ALICE, |author| {
5035 let info = author.as_mut().unwrap();
5036 let status = &mut info.status;
5037 *status = AuthorStatus::Active;
5038 });
5039
5040 System::set_block_number(16);
5041 assert_err!(Pallet::can_be_permanent(&ALICE), Error::AuthorIsActive);
5042 })
5043 }
5044
5045 #[test]
5046 fn can_be_permament_err_author_resigned() {
5047 authors_test_ext().execute_with(|| {
5048 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5049
5050 System::set_block_number(6);
5051 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5052
5053 AuthorsMap::mutate(ALICE, |author| {
5054 let info = author.as_mut().unwrap();
5055 let status = &mut info.status;
5056 *status = AuthorStatus::Resigned;
5057 });
5058
5059 System::set_block_number(16);
5060 assert_err!(Pallet::can_be_permanent(&ALICE), Error::AuthorResigned);
5061 })
5062 }
5063
5064 #[test]
5065 fn can_be_permament_err_author_not_found() {
5066 authors_test_ext().execute_with(|| {
5067 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5068
5069 System::set_block_number(6);
5070 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5071
5072 System::set_block_number(16);
5073 assert_err!(Pallet::can_be_permanent(&BOB), Error::AuthorNotFound);
5074 })
5075 }
5076
5077 #[test]
5078 fn can_be_permament_err_author_is_unsafe() {
5079 authors_test_ext().execute_with(|| {
5080 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5081
5082 System::set_block_number(6);
5083 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5084
5085 AuthorsMap::mutate(ALICE, |author| {
5086 let info = author.as_mut().unwrap();
5087 let risk = &mut info.risk_until;
5088 *risk = 18;
5089 });
5090
5091 System::set_block_number(16);
5092 assert_err!(Pallet::can_be_permanent(&ALICE), Error::AuthorIsUnsafe);
5093 })
5094 }
5095
5096 #[test]
5097 fn risk_probation_success() {
5098 authors_test_ext().execute_with(|| {
5099 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5100
5101 System::set_block_number(6);
5102 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5103
5104 let meta = Pallet::get_meta(&ALICE).unwrap();
5105 assert_eq!(meta.risk_until, 6);
5106
5107 System::set_block_number(10);
5108 Pallet::risk_probation(&ALICE).unwrap();
5109
5110 let meta = Pallet::get_meta(&ALICE).unwrap();
5111 assert_eq!(meta.risk_until, 11);
5112
5113 Pallet::risk_probation(&ALICE).unwrap();
5114
5115 let meta = Pallet::get_meta(&ALICE).unwrap();
5116 assert_eq!(meta.risk_until, 12);
5117
5118 System::set_block_number(15);
5119 Pallet::risk_probation(&ALICE).unwrap();
5120
5121 let meta = Pallet::get_meta(&ALICE).unwrap();
5122 assert_eq!(meta.risk_until, 16);
5123 System::assert_last_event(Event::AuthorAtRisk { author: ALICE, status: AuthorStatus::Probation, until: meta.risk_until }.into());
5124 })
5125 }
5126
5127 #[test]
5128 fn risk_probation_err_author_not_found() {
5129 authors_test_ext().execute_with(|| {
5130 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5131
5132 System::set_block_number(6);
5133 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5134
5135 System::set_block_number(10);
5136 assert_err!(Pallet::risk_probation(&BOB), Error::AuthorNotFound);
5137 })
5138 }
5139
5140 #[test]
5141 fn risk_probation_err_author_is_active() {
5142 authors_test_ext().execute_with(|| {
5143 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5144
5145 System::set_block_number(6);
5146 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5147
5148 AuthorsMap::mutate(ALICE, |author| {
5149 let info = author.as_mut().unwrap();
5150 let status = &mut info.status;
5151 *status = AuthorStatus::Active;
5152 });
5153
5154 System::set_block_number(10);
5155 assert_err!(Pallet::risk_probation(&ALICE), Error::AuthorIsActive);
5156 })
5157 }
5158
5159 #[test]
5160 fn risk_probation_err_author_resigned() {
5161 authors_test_ext().execute_with(|| {
5162 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5163
5164 System::set_block_number(6);
5165 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5166
5167 AuthorsMap::mutate(ALICE, |author| {
5168 let info = author.as_mut().unwrap();
5169 let status = &mut info.status;
5170 *status = AuthorStatus::Resigned;
5171 });
5172
5173 System::set_block_number(10);
5174 assert_err!(Pallet::risk_probation(&ALICE), Error::AuthorResigned);
5175 })
5176 }
5177
5178 #[test]
5179 fn risk_permanence_success() {
5180 authors_test_ext().execute_with(|| {
5181 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5182
5183 System::set_block_number(6);
5184 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5185
5186 let meta = Pallet::get_meta(&ALICE).unwrap();
5187 assert_eq!(meta.risk_until, 6);
5188
5189 AuthorsMap::mutate(ALICE, |author| {
5190 let info = author.as_mut().unwrap();
5191 let status = &mut info.status;
5192 *status = AuthorStatus::Active;
5193 });
5194
5195 System::set_block_number(20);
5196 Pallet::risk_permanence(&ALICE).unwrap();
5197
5198 let meta = Pallet::get_meta(&ALICE).unwrap();
5199 assert_eq!(meta.risk_until, 21);
5200
5201 Pallet::risk_permanence(&ALICE).unwrap();
5202
5203 let meta = Pallet::get_meta(&ALICE).unwrap();
5204 assert_eq!(meta.risk_until, 22);
5205
5206 System::set_block_number(25);
5207 Pallet::risk_permanence(&ALICE).unwrap();
5208
5209 let meta = Pallet::get_meta(&ALICE).unwrap();
5210 assert_eq!(meta.risk_until, 26);
5211 System::assert_last_event(Event::AuthorAtRisk { author: ALICE, status: AuthorStatus::Active, until: meta.risk_until }.into());
5212 })
5213 }
5214
5215 #[test]
5216 fn risk_permanence_success_revoking_permanence() {
5217 authors_test_ext().execute_with(|| {
5218 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5219
5220 System::set_block_number(6);
5221 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5222
5223 let meta = Pallet::get_meta(&ALICE).unwrap();
5224 assert_eq!(meta.risk_until, 6);
5225
5226 AuthorsMap::mutate(ALICE, |author| {
5227 let info = author.as_mut().unwrap();
5228 let status = &mut info.status;
5229 let risk_until = &mut info.risk_until;
5230 *status = AuthorStatus::Active;
5231 *risk_until = 31;
5232 });
5233
5234 let meta = Pallet::get_meta(&ALICE).unwrap();
5235 assert_eq!(meta.status, AuthorStatus::Active);
5236 assert_eq!(meta.risk_until, 31);
5237
5238 System::set_block_number(20);
5239 Pallet::risk_permanence(&ALICE).unwrap();
5240
5241 let meta = Pallet::get_meta(&ALICE).unwrap();
5242 assert_eq!(meta.status, AuthorStatus::Active);
5243 assert_eq!(meta.risk_until, 32);
5244 })
5245 }
5246
5247 #[test]
5248 fn risk_permanence_err_author_in_probation() {
5249 authors_test_ext().execute_with(|| {
5250 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5251
5252 System::set_block_number(6);
5253 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5254
5255 System::set_block_number(10);
5256 assert_err!(Pallet::risk_permanence(&ALICE), Error::AuthorInProbation);
5257 })
5258 }
5259
5260 #[test]
5261 fn risk_permanence_err_author_resigned() {
5262 authors_test_ext().execute_with(|| {
5263 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5264
5265 System::set_block_number(6);
5266 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5267
5268 AuthorsMap::mutate(ALICE, |author| {
5269 let info = author.as_mut().unwrap();
5270 let status = &mut info.status;
5271 *status = AuthorStatus::Resigned;
5272 });
5273
5274 System::set_block_number(35);
5275 assert_err!(Pallet::risk_permanence(&ALICE), Error::AuthorResigned);
5276 })
5277 }
5278
5279 #[test]
5280 fn risk_permanence_err_author_not_found() {
5281 authors_test_ext().execute_with(|| {
5282 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5283
5284 System::set_block_number(6);
5285 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5286
5287 System::set_block_number(10);
5288 assert_err!(Pallet::risk_permanence(&BOB), Error::AuthorNotFound);
5289 })
5290 }
5291
5292 #[test]
5293 fn secure_permanence_success() {
5294 authors_test_ext().execute_with(|| {
5295 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5296
5297 System::set_block_number(6);
5298 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5299
5300 let meta = Pallet::get_meta(&ALICE).unwrap();
5301 assert_eq!(meta.risk_until, 6);
5302
5303 System::set_block_number(10);
5304 Pallet::risk_probation(&ALICE).unwrap();
5305
5306 let meta = Pallet::get_meta(&ALICE).unwrap();
5307 assert_eq!(meta.risk_until, 11);
5308
5309 assert_ok!(Pallet::secure_permanence(&ALICE));
5310 let meta = Pallet::get_meta(&ALICE).unwrap();
5312 assert_eq!(meta.risk_until, 10);
5313
5314 System::set_block_number(20);
5315 AuthorsMap::mutate(ALICE, |author| {
5316 let info = author.as_mut().unwrap();
5317 let status = &mut info.status;
5318 *status = AuthorStatus::Active;
5319 });
5320
5321 Pallet::risk_permanence(&ALICE).unwrap();
5322
5323 let meta = Pallet::get_meta(&ALICE).unwrap();
5324 assert_eq!(meta.risk_until, 21);
5325
5326 assert_ok!(Pallet::secure_permanence(&ALICE));
5327 let meta = Pallet::get_meta(&ALICE).unwrap();
5329 assert_eq!(meta.risk_until, 20);
5330 System::assert_last_event(Event::AuthorAtRisk { author: ALICE, status: AuthorStatus::Probation, until: meta.risk_until }.into());
5331 })
5332 }
5333
5334 #[test]
5335 fn secure_permanence_err_author_resigned() {
5336 authors_test_ext().execute_with(|| {
5337 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5338
5339 System::set_block_number(6);
5340 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5341
5342 AuthorsMap::mutate(ALICE, |author| {
5343 let info = author.as_mut().unwrap();
5344 let status = &mut info.status;
5345 *status = AuthorStatus::Resigned;
5346 });
5347
5348 System::set_block_number(35);
5349 assert_err!(Pallet::secure_permanence(&ALICE), Error::AuthorResigned);
5350 })
5351 }
5352
5353 #[test]
5354 fn set_permanence_success() {
5355 authors_test_ext().execute_with(|| {
5356 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5357
5358 System::set_block_number(6);
5359 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5360
5361 let meta = Pallet::get_meta(&ALICE).unwrap();
5362 assert_eq!(meta.status, AuthorStatus::Probation);
5363
5364 System::set_block_number(18);
5365 assert_ok!(Pallet::set_permanence(&ALICE));
5366
5367 let meta = Pallet::get_meta(&ALICE).unwrap();
5368 assert_eq!(meta.status, AuthorStatus::Active);
5369 System::assert_last_event(Event::AuthorStatus { author: ALICE, status: AuthorStatus::Active }.into());
5370 })
5371 }
5372
5373 #[test]
5374 fn set_permanence_author_not_found() {
5375 authors_test_ext().execute_with(|| {
5376 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5377
5378 System::set_block_number(6);
5379 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5380
5381 System::set_block_number(18);
5382 assert_err!(Pallet::set_permanence(&BOB), Error::AuthorNotFound);
5383 })
5384 }
5385
5386 #[test]
5387 fn revoke_permanance_success() {
5388 authors_test_ext().execute_with(|| {
5389 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5390
5391 System::set_block_number(6);
5392 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5393
5394 System::set_block_number(16);
5395 Pallet::set_permanence(&ALICE).unwrap();
5396
5397 let meta = Pallet::get_meta(&ALICE).unwrap();
5398 assert_eq!(meta.status, AuthorStatus::Active);
5399
5400 System::set_block_number(20);
5401 Pallet::risk_permanence(&ALICE).unwrap();
5402 Pallet::risk_permanence(&ALICE).unwrap();
5403 Pallet::risk_permanence(&ALICE).unwrap();
5404 Pallet::risk_permanence(&ALICE).unwrap();
5405 Pallet::risk_permanence(&ALICE).unwrap();
5406 Pallet::risk_permanence(&ALICE).unwrap();
5407 Pallet::risk_permanence(&ALICE).unwrap();
5408 Pallet::risk_permanence(&ALICE).unwrap();
5409 Pallet::risk_permanence(&ALICE).unwrap();
5410 Pallet::risk_permanence(&ALICE).unwrap();
5411 Pallet::risk_permanence(&ALICE).unwrap();
5412
5413 let meta = Pallet::get_meta(&ALICE).unwrap();
5414 assert_eq!(meta.risk_until, 31);
5415
5416 assert_ok!(Pallet::revoke_permanence(&ALICE));
5417
5418 let meta = Pallet::get_meta(&ALICE).unwrap();
5419 assert_eq!(meta.status, AuthorStatus::Probation);
5420 System::assert_last_event(Event::AuthorStatus { author: ALICE, status: AuthorStatus::Probation }.into());
5421 })
5422 }
5423
5424 #[test]
5425 fn revoke_permanance_err_author_not_found() {
5426 authors_test_ext().execute_with(|| {
5427 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5428
5429 System::set_block_number(6);
5430 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5431
5432 System::set_block_number(16);
5433 Pallet::set_permanence(&ALICE).unwrap();
5434
5435 let meta = Pallet::get_meta(&ALICE).unwrap();
5436 assert_eq!(meta.status, AuthorStatus::Active);
5437
5438 assert_err!(Pallet::revoke_permanence(&BOB), Error::AuthorNotFound);
5439 })
5440 }
5441
5442 #[test]
5443 fn can_revoke_permanence_success() {
5444 authors_test_ext().execute_with(|| {
5445 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5446
5447 System::set_block_number(6);
5448 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5449
5450 AuthorsMap::mutate(ALICE, |author| {
5451 let info = author.as_mut().unwrap();
5452 let status = &mut info.status;
5453 let risk_until = &mut info.risk_until;
5454 *status = AuthorStatus::Active;
5455 *risk_until = 31;
5456 });
5457
5458 System::set_block_number(20);
5459 assert_ok!(Pallet::can_revoke_permanence(&ALICE));
5460 })
5461 }
5462
5463 #[test]
5464 fn can_revoke_permanence_err_risk_within_threshold() {
5465 authors_test_ext().execute_with(|| {
5466 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5467
5468 System::set_block_number(6);
5469 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5470
5471 AuthorsMap::mutate(ALICE, |author| {
5472 let info = author.as_mut().unwrap();
5473 let status = &mut info.status;
5474 let risk_until = &mut info.risk_until;
5475 *status = AuthorStatus::Active;
5476 *risk_until = 31;
5477 });
5478
5479 System::set_block_number(21);
5480 assert_err!(
5481 Pallet::can_revoke_permanence(&ALICE),
5482 Error::RiskWithinThreshold
5483 );
5484
5485 System::set_block_number(25);
5486 assert_err!(
5487 Pallet::can_revoke_permanence(&ALICE),
5488 Error::RiskWithinThreshold
5489 );
5490 })
5491 }
5492
5493 #[test]
5494 fn can_revoke_permanence_err_author_resigned() {
5495 authors_test_ext().execute_with(|| {
5496 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5497
5498 System::set_block_number(6);
5499 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5500
5501 AuthorsMap::mutate(ALICE, |author| {
5502 let info = author.as_mut().unwrap();
5503 let status = &mut info.status;
5504 *status = AuthorStatus::Resigned;
5505 });
5506
5507 System::set_block_number(21);
5508 assert_err!(Pallet::can_revoke_permanence(&ALICE), Error::AuthorResigned);
5509 })
5510 }
5511
5512 #[test]
5513 fn can_revoke_permanence_err_author_in_probation() {
5514 authors_test_ext().execute_with(|| {
5515 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5516
5517 System::set_block_number(6);
5518 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5519
5520 AuthorsMap::mutate(ALICE, |author| {
5521 let info = author.as_mut().unwrap();
5522 let status = &mut info.status;
5523 *status = AuthorStatus::Probation;
5524 });
5525
5526 System::set_block_number(21);
5527 assert_err!(
5528 Pallet::can_revoke_permanence(&ALICE),
5529 Error::AuthorInProbation
5530 );
5531 })
5532 }
5533
5534 #[test]
5535 fn on_set_permance_event_emmisison_success() {
5536 authors_test_ext().execute_with(|| {
5537 System::set_block_number(10);
5538 Pallet::on_set_permance(&ALICE);
5539
5540 let status = AuthorStatus::Active;
5541 System::assert_last_event(
5542 Event::AuthorStatus {
5543 author: ALICE,
5544 status,
5545 }
5546 .into(),
5547 );
5548 })
5549 }
5550
5551 #[test]
5552 fn on_revoke_permanence_event_emmisison_success() {
5553 authors_test_ext().execute_with(|| {
5554 System::set_block_number(10);
5555 Pallet::on_revoke_permanence(&ALICE);
5556
5557 let status = AuthorStatus::Probation;
5558 System::assert_last_event(
5559 Event::AuthorStatus {
5560 author: ALICE,
5561 status,
5562 }
5563 .into(),
5564 );
5565 })
5566 }
5567
5568 #[test]
5569 fn on_risk_permanence_event_emmisison_success() {
5570 authors_test_ext().execute_with(|| {
5571 System::set_block_number(10);
5572 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, STANDARD_HOLD).unwrap();
5573 Pallet::enroll(&ALICE, 100, Fortitude::Force).unwrap();
5574
5575 Pallet::on_risk_permanence(&ALICE);
5576
5577 let status = AuthorStatus::Active;
5578 System::assert_last_event(
5579 Event::AuthorAtRisk {
5580 author: ALICE,
5581 status,
5582 until: 10,
5583 }
5584 .into(),
5585 );
5586 })
5587 }
5588
5589 #[test]
5590 fn on_risk_probation_event_emmisison_success() {
5591 authors_test_ext().execute_with(|| {
5592 System::set_block_number(10);
5593 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, STANDARD_HOLD).unwrap();
5594 Pallet::enroll(&ALICE, 100, Fortitude::Force).unwrap();
5595
5596 Pallet::on_risk_probation(&ALICE);
5597
5598 let status = AuthorStatus::Probation;
5599 System::assert_last_event(
5600 Event::AuthorAtRisk {
5601 author: ALICE,
5602 status,
5603 until: 10,
5604 }
5605 .into(),
5606 );
5607 })
5608 }
5609
5610 #[test]
5611 fn on_secure_permanence_event_emmisison_success() {
5612 authors_test_ext().execute_with(|| {
5613 System::set_block_number(10);
5614 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, STANDARD_HOLD).unwrap();
5615 Pallet::enroll(&ALICE, 100, Fortitude::Force).unwrap();
5616
5617 Pallet::on_secure_permanence(&ALICE);
5618
5619 let status = AuthorStatus::Probation;
5620 System::assert_last_event(
5621 Event::AuthorAtRisk {
5622 author: ALICE,
5623 status,
5624 until: 10,
5625 }
5626 .into(),
5627 );
5628 })
5629 }
5630}