1#![cfg_attr(not(feature = "std"), no_std)]
122
123#[cfg(feature = "runtime-benchmarks")]
128mod benchmarking;
129#[cfg(test)]
130mod mock;
131#[cfg(test)]
132mod tests;
133mod roles;
134mod election;
135pub mod types;
136pub mod weights;
137
138pub use pallet::*;
143
144#[frame_support::pallet]
145pub mod pallet {
146
147 use crate::{types::*, weights::*};
153
154 use frame_suite::{base::*, commitment::*, plugin_types, roles::*};
156
157 use core::{fmt::Debug, marker::PhantomData};
159
160 use frame_support::{
162 dispatch::DispatchResult,
163 ensure,
164 pallet_prelude::*,
165 traits::{
166 fungible::{Inspect, Mutate, UnbalancedHold},
167 tokens::{Balance, Fortitude, Precision},
168 VariantCount,
169 },
170 };
171
172 use frame_system::{
174 ensure_root, ensure_signed,
175 pallet_prelude::{BlockNumberFor, OriginFor},
176 };
177
178 use sp_runtime::{traits::Bounded, DispatchError, Saturating, Vec};
180
181 #[pallet::pallet]
204 pub struct Pallet<T>(_);
205
206 #[pallet::config]
215 pub trait Config: frame_system::Config {
216 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
223
224 type AssetFreeze: From<FreezeReason> + RuntimeEnum + Delimited + Copy + VariantCount;
229
230 type Influence: Balance + From<AuthorAsset<Self>>;
240
241 type Asset: Inspect<
257 Author<Self>,
258 Balance = <Self::CommitmentAdapter as InspectAsset<Author<Self>>>::Asset,
264 > + Mutate<Author<Self>>
265 + UnbalancedHold<Author<Self>>;
266
267 type CommitmentAdapter: Commitment<
278 Author<Self>,
279 Reason = Self::AssetFreeze,
280 DigestSource = Author<Self>,
281 Digest: Ord,
282 > + CommitIndex<Author<Self>>
283 + CommitPool<Author<Self>>
284 + InspectAsset<Author<Self>>;
285
286 type ActivityProvider: RoleActivity<Author<Self>, BlockNumberFor<Self>>;
295
296 plugin_types!(
303 input: AuthorAsset<Self>,
310
311 output: Self::Influence,
319
320 model: InfluenceModel,
339
340 context: InfluenceContext,
352 );
353
354 plugin_types!(
363 input: ElectViaInfluence<Self>,
371
372 output: ElectedAuthors<Self>,
377
378 model: FlatElectionModel,
395
396 context: FlatElectionContext,
407 );
408
409 plugin_types!(
420 input: ElectViaBacking<Self>,
426
427 output: ElectedAuthors<Self>,
432
433 model: FairElectionModel,
451
452 context: FairElectionContext,
463 );
464
465 type WeightInfo: WeightInfo;
469
470 #[pallet::constant]
473 type EmitEvents: Get<bool> + Clone + Debug;
474 }
475
476 #[pallet::composite_enum]
485 pub enum FreezeReason {
486 AuthorFunding,
491
492 AuthorCollateral,
497 }
498
499 #[pallet::genesis_config]
511 pub struct GenesisConfig<T: Config> {
512 pub min_collateral: AuthorAsset<T>,
516
517 pub max_exposure: AuthorAsset<T>,
523
524 pub min_fund: AuthorAsset<T>,
531
532 pub probation_period: BlockNumberFor<T>,
536
537 pub reduce_probation_by: BlockNumberFor<T>,
540
541 pub increase_probation_by: BlockNumberFor<T>,
544
545 pub rewards_buffer: BlockNumberFor<T>,
548
549 pub penalties_buffer: BlockNumberFor<T>,
552
553 pub max_elected: u32,
556
557 pub min_elected: u32,
560
561 pub force_max_elected: bool,
565 }
566
567 impl<T: Config> Default for GenesisConfig<T> {
568 fn default() -> Self {
569 Self {
570 min_collateral: 1u32.into(),
571 max_exposure: Bounded::max_value(),
572 min_fund: 1u32.into(),
573 probation_period: 10u32.into(),
574 reduce_probation_by: 1u32.into(),
575 increase_probation_by: 1u32.into(),
576 rewards_buffer: 2u32.into(),
577 penalties_buffer: 4u32.into(),
578 max_elected: 100u32.into(),
579 min_elected: 10u32.into(),
580 force_max_elected: false,
581 }
582 }
583 }
584
585 #[pallet::genesis_build]
586 impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
587 fn build(&self) {
588 assert!(
589 !self.min_collateral.is_zero(),
590 "GenesisConfig error: min_collateral must be greater than zero"
591 );
592 assert!(
593 !self.min_fund.is_zero(),
594 "GenesisConfig error: min_fund must be greater than zero"
595 );
596 assert!(
597 !self.min_elected.is_zero(),
598 "GenesisConfig error: min_elected must be greater than zero"
599 );
600 assert!(
601 !self.max_elected.is_zero(),
602 "GenesisConfig error: max_elected must be greater than zero"
603 );
604 assert!(
605 self.min_elected <= self.max_elected,
606 "GenesisConfig error: min_elected cannot be greater than max_elected"
607 );
608 assert!(
609 self.min_fund <= self.max_exposure,
610 "GenesisConfig error: min_fund cannot be greater than max_exposure"
611 );
612 MinCollateral::<T>::put(&self.min_collateral);
613 MaxExposure::<T>::put(&self.max_exposure);
614 MinFund::<T>::put(&self.min_fund.max(One::one()));
615 ProbationPeriod::<T>::put(&self.probation_period);
616 ReduceProbationBy::<T>::put(&self.reduce_probation_by);
617 IncreaseProbationBy::<T>::put(&self.increase_probation_by);
618 RewardsBuffer::<T>::put(&self.rewards_buffer);
619 PenaltiesBuffer::<T>::put(&self.penalties_buffer);
620 RewardsUntil::<T>::put(BlockNumberFor::<T>::zero());
621 PenaltiesUntil::<T>::put(BlockNumberFor::<T>::zero());
622 MaxElected::<T>::put(&self.max_elected);
623 MinElected::<T>::put(&self.min_elected.max(One::one()));
624 ForceMaxElected::<T>::put(&self.force_max_elected);
625 RecentElectedOn::<T>::put(BlockNumberFor::<T>::zero());
626 }
627 }
628
629 #[pallet::storage]
655 pub type AuthorsMap<T: Config> =
656 StorageMap<_, Blake2_128Concat, Author<T>, AuthorInfo<T>, OptionQuery>;
657
658 #[pallet::storage]
680 pub type AuthorsDigest<T: Config> =
681 StorageMap<_, Blake2_128Concat, AuthorDigest<T>, Author<T>, OptionQuery>;
682
683 #[pallet::storage]
692 pub type AuthorFunders<T: Config> = StorageNMap<
693 _,
694 (
695 NMapKey<Blake2_128Concat, Author<T>>,
696 NMapKey<Blake2_128Concat, Backer<T>>,
697 ),
698 Funder<T>,
699 OptionQuery,
700 >;
701
702 #[pallet::storage]
710 pub type RewardsUntil<T: Config> = StorageValue<_, BlockNumberFor<T>, ValueQuery>;
711
712 #[pallet::storage]
719 pub type PenaltiesUntil<T: Config> = StorageValue<_, BlockNumberFor<T>, ValueQuery>;
720
721 #[pallet::storage]
725 pub type RewardsBuffer<T: Config> = StorageValue<_, BlockNumberFor<T>, ValueQuery>;
726
727 #[pallet::storage]
731 pub type PenaltiesBuffer<T: Config> = StorageValue<_, BlockNumberFor<T>, ValueQuery>;
732
733 #[pallet::storage]
739 pub type AuthorRewards<T: Config> = StorageNMap<
740 _,
741 (
742 NMapKey<Blake2_128Concat, BlockNumberFor<T>>,
743 NMapKey<Blake2_128Concat, Author<T>>,
744 ),
745 AuthorAsset<T>,
746 OptionQuery,
747 >;
748
749 #[pallet::storage]
757 pub type AuthorPenalties<T: Config> = StorageNMap<
758 _,
759 (
760 NMapKey<Blake2_128Concat, BlockNumberFor<T>>,
761 NMapKey<Blake2_128Concat, Author<T>>,
762 ),
763 Ratio<T>,
764 OptionQuery,
765 >;
766
767 #[pallet::storage]
774 pub type MinCollateral<T: Config> = StorageValue<_, AuthorAsset<T>, ValueQuery>;
775
776 #[pallet::storage]
784 pub type MaxExposure<T: Config> = StorageValue<_, AuthorAsset<T>, ValueQuery>;
785
786 #[pallet::storage]
793 pub type MinFund<T: Config> = StorageValue<_, AuthorAsset<T>, ValueQuery>;
794
795 #[pallet::storage]
805 pub type ProbationPeriod<T: Config> = StorageValue<_, BlockNumberFor<T>, ValueQuery>;
806
807 #[pallet::storage]
811 pub type ReduceProbationBy<T: Config> = StorageValue<_, BlockNumberFor<T>, ValueQuery>;
812
813 #[pallet::storage]
817 pub type IncreaseProbationBy<T: Config> = StorageValue<_, BlockNumberFor<T>, ValueQuery>;
818
819 #[pallet::storage]
842 pub type Elected<T: Config> = StorageNMap<
843 _,
844 (
845 NMapKey<Blake2_128Concat, BlockNumberFor<T>>,
846 NMapKey<Blake2_128Concat, Author<T>>,
847 ),
848 (),
849 OptionQuery,
850 >;
851
852 #[pallet::storage]
866 pub type RecentElectedOn<T: Config> = StorageValue<_, BlockNumberFor<T>, ValueQuery>;
867
868 #[pallet::storage]
881 pub type MaxElected<T: Config> = StorageValue<_, u32, ValueQuery>;
882
883 #[pallet::storage]
895 pub type MinElected<T: Config> = StorageValue<_, u32, ValueQuery>;
896
897 #[pallet::storage]
916 pub type ForceMaxElected<T: Config> = StorageValue<_, bool, ValueQuery>;
917
918 #[pallet::error]
923 pub enum Error<T> {
924 AuthorNotFound,
926
927 InadequateCollateral,
929
930 InadequateFunds,
932
933 AlreadyEnrolled,
935
936 AuthorIsActive,
940
941 AuthorInProbation,
943
944 AuthorResigned,
946
947 AuthorHasPenalties,
949
950 AuthorActivated,
952
953 CannotGenerateCommitDigest,
955
956 AuthorHasRewards,
958
959 FundDoesNotExist,
961
962 AuthorDigestNotFound,
964
965 FundedToAnotherDigest,
969
970 AuthorNotInIndex,
972
973 AuthorNotInPool,
975
976 BelowMinimumFund,
978
979 AboveMaximumExposure,
981
982 CannotFundOnCollateral,
984
985 RewardNotFound,
987
988 PenaltyNotFound,
990
991 AuthorTotalHoldExhausted,
996
997 ContainsNoRewards,
999
1000 ContainsNoPenalties,
1002
1003 FinalizedObligations,
1005
1006 AuthorNeedsMoreCollateral,
1008
1009 ZeroPenaltyFound,
1011
1012 AuthorIsUnsafe,
1016
1017 RedundantResignation,
1019
1020 InadequateCandidatesToElect,
1025
1026 NoElectsFound,
1034
1035 AuthorNotElected,
1037
1038 MinElectedNotReached,
1043
1044 RiskWithinThreshold,
1054
1055 AuthorMismatch,
1060
1061 InvalidPoolManager,
1063
1064 MinCollateralZero,
1069
1070 MinGreaterThanMax,
1078
1079 NonZeroConfigRequired,
1088
1089 FundingOffLimits,
1093 }
1094
1095 #[pallet::event]
1100 #[pallet::generate_deposit(pub(super) fn deposit_event)]
1101 pub enum Event<T: Config> {
1102 AuthorEnlisted {
1105 author: Author<T>,
1106 collateral: AuthorAsset<T>,
1107 },
1108
1109 AuthorResigned {
1112 author: Author<T>,
1113 released: AuthorAsset<T>,
1114 },
1115
1116 AuthorCollateralRaised {
1119 author: Author<T>,
1120 raised: AuthorAsset<T>,
1121 },
1122
1123 AuthorTotalCollateral {
1125 author: Author<T>,
1126 collateral: AuthorAsset<T>,
1127 },
1128
1129 AuthorFunded {
1132 author: Author<T>,
1133 backer: Backer<T>,
1134 amount: AuthorAsset<T>,
1135 },
1136
1137 InspectAuthorFund {
1140 author: Author<T>,
1141 backer: Backer<T>,
1142 amount: AuthorAsset<T>,
1143 },
1144
1145 InspectFund {
1148 author: Author<T>,
1149 funder: Funder<T>,
1150 amount: AuthorAsset<T>,
1151 },
1152
1153 IndexFunded {
1156 index: IndexDigest<T>,
1157 backer: Backer<T>,
1158 amount: AuthorAsset<T>,
1159 },
1160
1161 InspectIndexFund {
1164 index: IndexDigest<T>,
1165 backer: Backer<T>,
1166 amount: AuthorAsset<T>,
1167 },
1168
1169 PoolFunded {
1172 pool: PoolDigest<T>,
1173 backer: Backer<T>,
1174 amount: AuthorAsset<T>,
1175 },
1176
1177 InspectPoolFund {
1180 pool: PoolDigest<T>,
1181 backer: Backer<T>,
1182 amount: AuthorAsset<T>,
1183 },
1184
1185 AuthorDrawn {
1188 author: Author<T>,
1189 backer: Backer<T>,
1190 amount: AuthorAsset<T>,
1191 },
1192
1193 IndexDrawn {
1196 index: IndexDigest<T>,
1197 backer: Backer<T>,
1198 amount: AuthorAsset<T>,
1199 },
1200
1201 PoolDrawn {
1204 pool: PoolDigest<T>,
1205 backer: Backer<T>,
1206 amount: AuthorAsset<T>,
1207 },
1208
1209 ScheduledRewards {
1212 author: Author<T>,
1213 rewards: Vec<(BlockNumberFor<T>, AuthorAsset<T>)>,
1214 },
1215
1216 ScheduledPenalties {
1219 author: Author<T>,
1220 penalties: Vec<(BlockNumberFor<T>, Ratio<T>)>,
1221 },
1222
1223 AuthorRewardScheduled {
1225 author: Author<T>,
1226 amount: AuthorAsset<T>,
1227 at: BlockNumberFor<T>,
1228 },
1229
1230 AuthorPenaltyScheduled {
1232 author: Author<T>,
1233 factor: Ratio<T>,
1234 at: BlockNumberFor<T>,
1235 },
1236
1237 AuthorStatus {
1240 author: Author<T>,
1241 status: AuthorStatus,
1242 },
1243
1244 AuthorAtRisk {
1247 author: Author<T>,
1248 status: AuthorStatus,
1249 until: BlockNumberFor<T>,
1250 },
1251
1252 AuthorPenaltyForgiven { author: Author<T>, factor: Ratio<T> },
1255
1256 AuthorRewardReclaimed {
1259 author: Author<T>,
1260 amount: AuthorAsset<T>,
1261 },
1262
1263 AuthorTotalHold {
1265 author: Author<T>,
1266 value: AuthorAsset<T>,
1267 },
1268
1269 ElectionPrepared { elects: Vec<Author<T>> },
1272
1273 ElectionFailed { error: DispatchError },
1275
1276 IndexCreated {
1278 index: IndexDigest<T>,
1279 #[cfg(any(feature = "dev", feature = "runtime-benchmarks"))]
1280 entries: Vec<(IndexDigest<T>, Shares<T>)>,
1281 },
1282
1283 PoolCreated {
1286 pool: PoolDigest<T>,
1287 commission: Commission<T>,
1288 manager: T::AccountId,
1289 #[cfg(any(feature = "dev", feature = "runtime-benchmarks"))]
1290 slots: Vec<(PoolDigest<T>, Shares<T>)>,
1291 },
1292
1293 PoolManager {
1295 digest: PoolDigest<T>,
1296 manager: T::AccountId,
1297 },
1298
1299 PoolSlotShare {
1301 pool: PoolDigest<T>,
1302 slots: (PoolDigest<T>, Shares<T>),
1303 },
1304
1305 GenesisConfigUpdated(ForceGenesisConfig<T>),
1307 }
1308
1309 #[pallet::hooks]
1314 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
1315 fn on_initialize(block: BlockNumberFor<T>) -> Weight {
1325 let reward_iter: Vec<_> = AuthorRewards::<T>::iter_prefix((block,)).collect();
1327 let reward_count = reward_iter.len() as u32;
1328 for (author, reward) in reward_iter {
1330 if let Ok(hold) = Self::get_hold(&author) {
1331 let value = hold.saturating_add(reward);
1332 if Self::set_hold(&author, value, Precision::BestEffort, Fortitude::Polite)
1333 .is_ok()
1334 {
1335 Self::on_set_hold(&author, value);
1336 }
1337 }
1338 AuthorRewards::<T>::remove((block, author));
1340 }
1341
1342 let penalty_iter: Vec<_> = AuthorPenalties::<T>::iter_prefix((block,)).collect();
1345 let penalty_count = penalty_iter.len() as u32;
1346 for (author, penalty_percent) in penalty_iter {
1347 if let Ok(hold) = Self::get_hold(&author) {
1348 let penalty = penalty_percent.mul_floor(hold);
1350 let value = hold.saturating_sub(penalty);
1351 if Self::set_hold(&author, value, Precision::Exact, Fortitude::Force).is_ok() {
1352 Self::on_set_hold(&author, value);
1353 }
1354 }
1355 AuthorPenalties::<T>::remove((block, author));
1357 }
1358
1359 T::WeightInfo::on_initialize_rewards_penalties(reward_count, penalty_count)
1360 }
1361 }
1362
1363 #[pallet::call]
1368 impl<T: Config> Pallet<T> {
1369 #[pallet::call_index(0)]
1395 #[pallet::weight(T::WeightInfo::enlist())]
1396 pub fn enlist(
1397 origin: OriginFor<T>,
1398 collateral: AuthorAsset<T>,
1399 fortitude: FortitudeWrapper,
1400 ) -> DispatchResult {
1401 let caller = ensure_signed(origin)?;
1402 ensure!(
1403 collateral >= MinCollateral::<T>::get(),
1404 Error::<T>::InadequateCollateral
1405 );
1406
1407 let fortitude = fortitude.into();
1408 let collateral =
1409 <Pallet<T> as RoleManager<Author<T>>>::enroll(&caller, collateral, fortitude)?;
1410 if !T::EmitEvents::get() {
1411 Self::deposit_event(Event::<T>::AuthorEnlisted {
1412 author: caller,
1413 collateral,
1414 });
1415 }
1416 Ok(())
1417 }
1418
1419 #[pallet::call_index(1)]
1453 #[pallet::weight(
1454 T::WeightInfo::direct_fund()
1455 .max(T::WeightInfo::index_fund())
1456 .max(T::WeightInfo::pool_fund())
1457 )]
1458 pub fn back(
1459 origin: OriginFor<T>,
1460 via: FundingTarget<T>,
1461 value: AuthorAsset<T>,
1462 fortitude: FortitudeWrapper,
1463 precision: PrecisionWrapper,
1464 ) -> DispatchResult {
1465 let caller = ensure_signed(origin)?;
1466
1467 let (to, funder) = match via {
1468 FundingTarget::Direct(author) => {
1469 let funder = Funder::Direct(caller);
1470 (author, funder)
1471 }
1472 FundingTarget::Index(index_digest) => {
1473 let reason = &FreezeReason::AuthorFunding.into();
1474 let index_entry_shares =
1475 T::CommitmentAdapter::get_entries_shares(reason, &index_digest)?;
1476 let entry_digest = &index_entry_shares[0].0;
1477 let to = AuthorsDigest::<T>::get(&entry_digest)
1480 .ok_or(Error::<T>::AuthorDigestNotFound)?;
1481 let index_funder = Funder::Index {
1482 digest: index_digest,
1483 backer: caller,
1484 };
1485 (to, index_funder)
1486 }
1487 FundingTarget::Pool(pool_digest) => {
1488 let reason = &FreezeReason::AuthorFunding.into();
1489 let pool_entry_shares =
1490 T::CommitmentAdapter::get_slots_shares(reason, &pool_digest)?;
1491 let slot_digest = &pool_entry_shares[0].0;
1492 let to = AuthorsDigest::<T>::get(&slot_digest)
1493 .ok_or(Error::<T>::AuthorDigestNotFound)?;
1494 let pool_funder = Funder::Pool {
1495 digest: pool_digest,
1496 backer: caller,
1497 };
1498 (to, pool_funder)
1499 }
1500 };
1501 let precision: Precision = precision.into();
1502 let fortitude: Fortitude = fortitude.into();
1503 let actual = <Pallet<T> as FundRoles<Author<T>>>::fund(
1504 &to, &funder, value, precision, fortitude,
1505 )?;
1506 if !T::EmitEvents::get() {
1507 match funder {
1508 Funder::Direct(backer) => {
1509 Self::deposit_event(Event::<T>::AuthorFunded {
1510 author: to,
1511 backer,
1512 amount: actual,
1513 });
1514 }
1515 Funder::Index { digest, backer } => {
1516 Self::deposit_event(Event::<T>::IndexFunded {
1517 index: digest,
1518 backer,
1519 amount: actual,
1520 });
1521 }
1522 Funder::Pool { digest, backer } => {
1523 Self::deposit_event(Event::<T>::PoolFunded {
1524 pool: digest,
1525 backer,
1526 amount: actual,
1527 });
1528 }
1529 }
1530 }
1531 Ok(())
1532 }
1533
1534 #[pallet::call_index(2)]
1552 #[pallet::weight(T::WeightInfo::refill())]
1553 pub fn refill(
1554 origin: OriginFor<T>,
1555 collateral: AuthorAsset<T>,
1556 fortitude: FortitudeWrapper,
1557 ) -> DispatchResult {
1558 let caller = ensure_signed(origin)?;
1559 let fortitude = fortitude.into();
1560 let raised = <Pallet<T> as RoleManager<Author<T>>>::add_collateral(
1561 &caller, collateral, fortitude,
1562 )?;
1563 if !T::EmitEvents::get() {
1564 Self::deposit_event(Event::<T>::AuthorCollateralRaised {
1565 author: caller,
1566 raised,
1567 });
1568 }
1569 Ok(())
1570 }
1571
1572 #[pallet::call_index(3)]
1587 #[pallet::weight(T::WeightInfo::confirm())]
1588 pub fn confirm(origin: OriginFor<T>) -> DispatchResult {
1589 let caller = ensure_signed(origin)?;
1590 <Pallet<T> as RoleManager<Author<T>>>::set_status(&caller, AuthorStatus::Active)?;
1591 if !T::EmitEvents::get() {
1592 Self::deposit_event(Event::AuthorStatus {
1593 author: caller,
1594 status: AuthorStatus::Active,
1595 });
1596 }
1597 Ok(())
1598 }
1599
1600 #[pallet::call_index(4)]
1620 #[pallet::weight(
1621 T::WeightInfo::release_direct_fund()
1622 .max(T::WeightInfo::release_index_fund())
1623 .max(T::WeightInfo::release_pool_fund())
1624 )]
1625 pub fn exit(origin: OriginFor<T>, from: FundingTarget<T>) -> DispatchResult {
1626 let caller = ensure_signed(origin)?;
1627 let (from, funder) = match from {
1628 FundingTarget::Direct(author) => {
1629 let funder = Funder::Direct(caller);
1630 (author, funder)
1631 }
1632 FundingTarget::Index(index_digest) => {
1633 let reason = &FreezeReason::AuthorFunding.into();
1634 let index_entry_shares =
1635 T::CommitmentAdapter::get_entries_shares(reason, &index_digest)?;
1636 let entry_digest = &index_entry_shares[0].0;
1637 let from = AuthorsDigest::<T>::get(&entry_digest)
1638 .ok_or(Error::<T>::AuthorDigestNotFound)?;
1639 let index_funder = Funder::Index {
1640 digest: index_digest,
1641 backer: caller,
1642 };
1643 (from, index_funder)
1644 }
1645 FundingTarget::Pool(pool_digest) => {
1646 let reason = &FreezeReason::AuthorFunding.into();
1647 let pool_entry_shares =
1648 T::CommitmentAdapter::get_slots_shares(reason, &pool_digest)?;
1649 let slot_digest = &pool_entry_shares[0].0;
1650 let from = AuthorsDigest::<T>::get(&slot_digest)
1651 .ok_or(Error::<T>::AuthorDigestNotFound)?;
1652 let pool_funder = Funder::Pool {
1653 digest: pool_digest,
1654 backer: caller,
1655 };
1656 (from, pool_funder)
1657 }
1658 };
1659 let draw_value = <Pallet<T> as FundRoles<Author<T>>>::draw(&from, &funder)?;
1660 if !T::EmitEvents::get() {
1661 match funder {
1662 Funder::Direct(backer) => {
1663 Self::deposit_event(Event::<T>::AuthorDrawn {
1664 author: from,
1665 backer,
1666 amount: draw_value,
1667 });
1668 }
1669 Funder::Index { digest, backer } => {
1670 Self::deposit_event(Event::<T>::IndexDrawn {
1671 index: digest,
1672 backer,
1673 amount: draw_value,
1674 });
1675 }
1676 Funder::Pool { digest, backer } => {
1677 Self::deposit_event(Event::<T>::PoolDrawn {
1678 pool: digest,
1679 backer,
1680 amount: draw_value,
1681 });
1682 }
1683 }
1684 }
1685 Ok(())
1686 }
1687
1688 #[pallet::call_index(5)]
1701 #[pallet::weight(T::WeightInfo::demit())]
1702 pub fn demit(origin: OriginFor<T>) -> DispatchResult {
1703 let caller = ensure_signed(origin)?;
1704 let released = <Pallet<T> as RoleManager<Author<T>>>::resign(&caller)?;
1705 if !T::EmitEvents::get() {
1706 Self::deposit_event(Event::<T>::AuthorResigned {
1707 author: caller,
1708 released,
1709 });
1710 }
1711 Ok(())
1712 }
1713
1714 #[pallet::call_index(6)]
1725 #[pallet::weight(T::WeightInfo::create_index())]
1726 pub fn create_index(
1727 origin: OriginFor<T>,
1728 entries: Vec<(Author<T>, Shares<T>)>,
1729 ) -> DispatchResult {
1730 let caller = ensure_signed(origin)?;
1731 let mut digest_entries = Vec::new();
1732 for (author, shares) in entries {
1733 let author_reason = FreezeReason::AuthorCollateral.into();
1734 let author_digest =
1735 <T as Config>::CommitmentAdapter::get_commit_digest(&author, &author_reason)?;
1736 digest_entries.push((author_digest, shares));
1737 }
1738 let funding_reason = FreezeReason::AuthorFunding.into();
1739 let index_info = <T as Config>::CommitmentAdapter::prepare_index(
1740 &caller,
1741 &funding_reason,
1742 &digest_entries,
1743 )?;
1744 let index_digest = <T as Config>::CommitmentAdapter::gen_index_digest(
1745 &caller,
1746 &funding_reason,
1747 &index_info,
1748 )?;
1749 <T as Config>::CommitmentAdapter::set_index(
1750 &caller,
1751 &funding_reason,
1752 &index_info,
1753 &index_digest,
1754 )?;
1755
1756 #[cfg(not(any(feature = "dev", feature = "runtime-benchmarks")))]
1757 {
1758 Self::deposit_event(Event::<T>::IndexCreated {
1759 index: index_digest,
1760 });
1761 }
1762
1763 #[cfg(any(feature = "dev", feature = "runtime-benchmarks"))]
1764 {
1765 let entries = <T as Config>::CommitmentAdapter::get_entries_shares(
1766 &funding_reason,
1767 &index_digest,
1768 )?;
1769 Self::deposit_event(Event::<T>::IndexCreated {
1770 index: index_digest,
1771 entries: entries,
1772 });
1773 }
1774 Ok(())
1775 }
1776
1777 #[pallet::call_index(7)]
1789 #[pallet::weight(T::WeightInfo::create_pool())]
1790 pub fn create_pool(
1791 origin: OriginFor<T>,
1792 index: IndexDigest<T>,
1793 commission: Commission<T>,
1794 ) -> DispatchResult {
1795 let caller = ensure_signed(origin)?;
1796 let funding_reason = FreezeReason::AuthorFunding.into();
1797 let pool_digest = <T as Config>::CommitmentAdapter::gen_pool_digest(
1798 &caller,
1799 &funding_reason,
1800 &index,
1801 commission,
1802 )?;
1803 <T as Config>::CommitmentAdapter::set_pool(
1804 &caller,
1805 &funding_reason,
1806 &pool_digest,
1807 &index,
1808 commission,
1809 )?;
1810
1811 #[cfg(not(any(feature = "dev", feature = "runtime-benchmarks")))]
1812 {
1813 Self::deposit_event(Event::<T>::PoolCreated {
1814 pool: pool_digest,
1815 commission: commission,
1816 manager: caller,
1817 });
1818 }
1819
1820 #[cfg(any(feature = "dev", feature = "runtime-benchmarks"))]
1821 {
1822 let slots = <T as Config>::CommitmentAdapter::get_slots_shares(
1823 &funding_reason,
1824 &pool_digest,
1825 )?;
1826 Self::deposit_event(Event::<T>::PoolCreated {
1827 pool: pool_digest,
1828 commission: commission,
1829 manager: caller,
1830 slots: slots,
1831 });
1832 }
1833 Ok(())
1834 }
1835
1836 #[pallet::call_index(8)]
1851 #[pallet::weight(T::WeightInfo::transfer_pool())]
1852 pub fn transfer_pool(
1853 origin: OriginFor<T>,
1854 pool: PoolDigest<T>,
1855 to: T::AccountId,
1856 ) -> DispatchResult {
1857 let caller = ensure_signed(origin)?;
1858 let funding_reason = FreezeReason::AuthorFunding.into();
1859 let current_manager =
1860 <T as Config>::CommitmentAdapter::get_manager(&funding_reason, &pool)?;
1861 ensure!(current_manager == caller, Error::<T>::InvalidPoolManager);
1862 <T as Config>::CommitmentAdapter::set_pool_manager(&funding_reason, &pool, &to)?;
1863 Self::deposit_event(Event::<T>::PoolManager {
1864 digest: pool,
1865 manager: to,
1866 });
1867 Ok(())
1868 }
1869
1870 #[pallet::call_index(9)]
1888 #[pallet::weight(T::WeightInfo::update_commission())]
1889 pub fn update_commission(
1890 origin: OriginFor<T>,
1891 index: IndexDigest<T>,
1892 commission: Commission<T>,
1893 ) -> DispatchResult {
1894 let caller = ensure_signed(origin)?;
1895 let funding_reason = FreezeReason::AuthorFunding.into();
1896 let pool_digest = <T as Config>::CommitmentAdapter::set_commission(
1897 &caller,
1898 &funding_reason,
1899 &index,
1900 commission,
1901 )?;
1902
1903 #[cfg(not(any(feature = "dev", feature = "runtime-benchmarks")))]
1904 {
1905 Self::deposit_event(Event::<T>::PoolCreated {
1906 pool: pool_digest,
1907 commission: commission,
1908 manager: caller,
1909 });
1910 }
1911
1912 #[cfg(any(feature = "dev", feature = "runtime-benchmarks"))]
1913 {
1914 let slots = <T as Config>::CommitmentAdapter::get_slots_shares(
1915 &funding_reason,
1916 &pool_digest,
1917 )?;
1918 Self::deposit_event(Event::<T>::PoolCreated {
1919 pool: pool_digest,
1920 commission: commission,
1921 manager: caller,
1922 slots: slots,
1923 });
1924 }
1925 Ok(())
1926 }
1927
1928 #[pallet::call_index(10)]
1944 #[pallet::weight(T::WeightInfo::update_entry_shares())]
1945 pub fn update_entry_shares(
1946 origin: OriginFor<T>,
1947 index: IndexDigest<T>,
1948 entry: IndexDigest<T>,
1949 shares: Shares<T>,
1950 ) -> DispatchResult {
1951 let caller = ensure_signed(origin)?;
1952 let funding_reason = FreezeReason::AuthorFunding.into();
1953 let new_index = <T as Config>::CommitmentAdapter::set_entry_shares(
1954 &caller,
1955 &funding_reason,
1956 &index,
1957 &entry,
1958 shares,
1959 )?;
1960
1961 #[cfg(not(any(feature = "dev", feature = "runtime-benchmarks")))]
1962 {
1963 Self::deposit_event(Event::<T>::IndexCreated { index: new_index });
1964 }
1965
1966 #[cfg(any(feature = "dev", feature = "runtime-benchmarks"))]
1967 {
1968 let entries = <T as Config>::CommitmentAdapter::get_entries_shares(
1969 &funding_reason,
1970 &new_index,
1971 )?;
1972 Self::deposit_event(Event::<T>::IndexCreated {
1973 index: new_index,
1974 entries: entries,
1975 });
1976 }
1977 Ok(())
1978 }
1979
1980 #[pallet::call_index(11)]
1998 #[pallet::weight(T::WeightInfo::update_slot_shares())]
1999 pub fn update_slot_shares(
2000 origin: OriginFor<T>,
2001 pool: PoolDigest<T>,
2002 slot: PoolDigest<T>,
2003 shares: Shares<T>,
2004 ) -> DispatchResult {
2005 let caller = ensure_signed(origin)?;
2006 let funding_reason = FreezeReason::AuthorFunding.into();
2007 let current_manager =
2008 <T as Config>::CommitmentAdapter::get_manager(&funding_reason, &pool)?;
2009 ensure!(current_manager == caller, Error::<T>::InvalidPoolManager);
2010 <T as Config>::CommitmentAdapter::set_slot_shares(
2011 &caller,
2012 &funding_reason,
2013 &pool,
2014 &slot,
2015 shares,
2016 )?;
2017 Self::deposit_event(Event::<T>::PoolSlotShare {
2018 pool,
2019 slots: (slot, shares),
2020 });
2021 Ok(())
2022 }
2023
2024 #[cfg(any(feature = "dev", feature = "runtime-benchmarks"))]
2039 #[pallet::call_index(12)]
2040 #[pallet::weight(T::WeightInfo::my_collateral())]
2041 pub fn my_collateral(origin: OriginFor<T>) -> DispatchResult {
2042 let caller = ensure_signed(origin)?;
2043 <Pallet<T> as RoleManager<Author<T>>>::role_exists(&caller)?;
2044 let collateral = <Pallet<T> as RoleManager<Author<T>>>::get_collateral(&caller)?;
2045 Self::deposit_event(Event::<T>::AuthorTotalCollateral {
2046 author: caller,
2047 collateral,
2048 });
2049 Ok(())
2050 }
2051
2052 #[cfg(any(feature = "dev", feature = "runtime-benchmarks"))]
2072 #[pallet::call_index(13)]
2073 #[pallet::weight(
2074 T::WeightInfo::check_direct_fund()
2075 .max(T::WeightInfo::check_index_fund())
2076 .max(T::WeightInfo::check_pool_fund())
2077 )]
2078 pub fn my_fund(origin: OriginFor<T>, from: FundingTarget<T>) -> DispatchResult {
2079 let caller = ensure_signed(origin)?;
2080 match from {
2081 FundingTarget::Direct(author) => {
2082 let funder = Funder::<T>::Direct(caller.clone());
2083 let amount = <Pallet<T> as FundRoles<Author<T>>>::get_fund(&author, &funder)?;
2084 Self::deposit_event(Event::<T>::InspectAuthorFund {
2085 author,
2086 backer: caller,
2087 amount,
2088 });
2089 }
2090 FundingTarget::Index(index_digest) => {
2091 let reason = &FreezeReason::AuthorFunding.into();
2092 let actual_digest = T::CommitmentAdapter::get_commit_digest(&caller, reason)?;
2093 T::CommitmentAdapter::index_exists(reason, &actual_digest)?;
2094 ensure!(
2095 index_digest == actual_digest,
2096 Error::<T>::FundedToAnotherDigest
2097 );
2098 let index_fund = T::CommitmentAdapter::get_commit_value(&caller, reason)?;
2099 Self::deposit_event(Event::<T>::InspectIndexFund {
2100 index: index_digest,
2101 backer: caller,
2102 amount: index_fund,
2103 });
2104 }
2105 FundingTarget::Pool(pool_digest) => {
2106 let reason = &FreezeReason::AuthorFunding.into();
2107 let actual_digest = T::CommitmentAdapter::get_commit_digest(&caller, reason)?;
2108 T::CommitmentAdapter::pool_exists(reason, &actual_digest)?;
2109 ensure!(
2110 pool_digest == actual_digest,
2111 Error::<T>::FundedToAnotherDigest
2112 );
2113 let pool_fund = T::CommitmentAdapter::get_commit_value(&caller, reason)?;
2114 Self::deposit_event(Event::<T>::InspectPoolFund {
2115 pool: pool_digest,
2116 backer: caller,
2117 amount: pool_fund,
2118 });
2119 }
2120 };
2121 Ok(())
2122 }
2123
2124 #[cfg(any(feature = "dev", feature = "runtime-benchmarks"))]
2136 #[pallet::call_index(14)]
2137 #[pallet::weight(T::WeightInfo::check_index_fund_towards()
2138 .max(T::WeightInfo::check_pool_fund_towards())
2139 .max(T::WeightInfo::check_direct_fund())
2140 )]
2141 pub fn my_author_fund(
2142 origin: OriginFor<T>,
2143 author: Author<T>,
2144 from: FundingTarget<T>,
2145 ) -> DispatchResult {
2146 let caller = ensure_signed(origin)?;
2147 let funder = match from {
2148 FundingTarget::Direct(_author) => {
2149 let funder = Funder::<T>::Direct(caller);
2150 funder
2151 }
2152 FundingTarget::Index(index_digest) => {
2153 let funder = Funder::<T>::Index {
2154 digest: index_digest,
2155 backer: caller,
2156 };
2157 funder
2158 }
2159 FundingTarget::Pool(pool_digest) => {
2160 let funder = Funder::<T>::Pool {
2161 digest: pool_digest,
2162 backer: caller,
2163 };
2164 funder
2165 }
2166 };
2167 let amount = <Pallet<T> as FundRoles<Author<T>>>::get_fund(&author, &funder)?;
2168 Self::deposit_event(Event::<T>::InspectFund {
2169 author,
2170 funder,
2171 amount,
2172 });
2173 Ok(())
2174 }
2175
2176 #[cfg(any(feature = "dev", feature = "runtime-benchmarks"))]
2183 #[pallet::call_index(15)]
2184 #[pallet::weight(T::WeightInfo::shed_rewards())]
2185 pub fn shed_rewards(origin: OriginFor<T>) -> DispatchResult {
2186 let caller = ensure_signed(origin)?;
2187 Self::has_reward(&caller)?;
2188 let shed_rewards = Self::get_rewards_of(&caller)?;
2189 Self::deposit_event(Event::<T>::ScheduledRewards {
2190 author: caller,
2191 rewards: shed_rewards,
2192 });
2193 Ok(())
2194 }
2195
2196 #[cfg(any(feature = "dev", feature = "runtime-benchmarks"))]
2207 #[pallet::call_index(16)]
2208 #[pallet::weight(T::WeightInfo::shed_penalties())]
2209 pub fn shed_penalties(origin: OriginFor<T>) -> DispatchResult {
2210 let caller = ensure_signed(origin)?;
2211 Self::has_penalty(&caller)?;
2212 let shed_penalties = Self::get_penalties_of(&caller)?;
2213 Self::deposit_event(Event::<T>::ScheduledPenalties {
2214 author: caller,
2215 penalties: shed_penalties,
2216 });
2217 Ok(())
2218 }
2219
2220 #[pallet::call_index(17)]
2254 #[pallet::weight(
2255 T::WeightInfo::force_probation_period()
2256 .max(T::WeightInfo::force_enforce_max_elected())
2257 .max(T::WeightInfo::force_increase_probation_by())
2258 .max(T::WeightInfo::force_max_elected())
2259 .max(T::WeightInfo::force_max_exposure())
2260 .max(T::WeightInfo::force_min_collateral())
2261 .max(T::WeightInfo::force_min_elected())
2262 .max(T::WeightInfo::force_min_fund())
2263 .max(T::WeightInfo::force_penalties_buffer())
2264 .max(T::WeightInfo::force_reduce_probation_by())
2265 .max(T::WeightInfo::force_rewards_buffer())
2266 )]
2267 pub fn force_genesis_config(
2268 origin: OriginFor<T>,
2269 field: ForceGenesisConfig<T>,
2270 ) -> DispatchResult {
2271 ensure_root(origin)?;
2272 match field {
2273 ForceGenesisConfig::ProbationPeriod(block) => ProbationPeriod::<T>::put(block),
2274 ForceGenesisConfig::ReduceProbationBy(block) => ReduceProbationBy::<T>::put(block),
2275 ForceGenesisConfig::IncreaseProbationBy(block) => {
2276 IncreaseProbationBy::<T>::put(block)
2277 }
2278 ForceGenesisConfig::RewardsBuffer(block) => RewardsBuffer::<T>::put(block),
2279 ForceGenesisConfig::PenaltiesBuffer(block) => PenaltiesBuffer::<T>::put(block),
2280 ForceGenesisConfig::MaxElected(max_elected) => {
2281 ensure!(!max_elected.is_zero(), Error::<T>::NonZeroConfigRequired);
2282 ensure!(
2283 max_elected >= MinElected::<T>::get(),
2284 Error::<T>::MinGreaterThanMax
2285 );
2286 MaxElected::<T>::put(max_elected);
2287 }
2288 ForceGenesisConfig::MinElected(min_elected) => {
2289 ensure!(!min_elected.is_zero(), Error::<T>::NonZeroConfigRequired);
2290 ensure!(
2291 min_elected <= MaxElected::<T>::get(),
2292 Error::<T>::MinGreaterThanMax
2293 );
2294 MinElected::<T>::put(min_elected);
2295 }
2296 ForceGenesisConfig::EnforceMaxElected(bool) => ForceMaxElected::<T>::put(bool),
2297 ForceGenesisConfig::MinFund(asset) => {
2298 ensure!(!asset.is_zero(), Error::<T>::NonZeroConfigRequired);
2299 ensure!(
2300 asset <= MaxExposure::<T>::get(),
2301 Error::<T>::MinGreaterThanMax
2302 );
2303 MinFund::<T>::put(asset);
2304 }
2305 ForceGenesisConfig::MaxExposure(asset) => {
2306 ensure!(asset >= MinFund::<T>::get(), Error::<T>::MinGreaterThanMax);
2307 MaxExposure::<T>::put(asset);
2308 }
2309 ForceGenesisConfig::MinCollateral(asset) => {
2310 ensure!(!asset.is_zero(), Error::<T>::NonZeroConfigRequired);
2311 MinCollateral::<T>::put(asset);
2312 }
2313 }
2314 Self::deposit_event(Event::GenesisConfigUpdated(field));
2315 Ok(())
2316 }
2317 }
2318
2319 impl<T: Config> Pallet<T> {
2329 pub fn fetch_collateral(who: Author<T>) -> Result<AuthorAsset<T>, DispatchError> {
2332 <Pallet<T> as RoleManager<Author<T>>>::role_exists(&who)?;
2333 let total_collateral = <Pallet<T> as RoleManager<Author<T>>>::get_collateral(&who)?;
2334 Ok(total_collateral)
2335 }
2336
2337 pub fn inspect_fund(
2342 caller: T::AccountId,
2343 from: FundingTarget<T>,
2344 ) -> Result<AuthorAsset<T>, DispatchError> {
2345 match from {
2346 FundingTarget::Direct(author) => {
2347 let funder = Funder::<T>::Direct(caller);
2348 let fund = <Pallet<T> as FundRoles<Author<T>>>::get_fund(&author, &funder)?;
2349 return Ok(fund);
2350 }
2351 FundingTarget::Index(index_digest) => {
2352 let reason = &FreezeReason::AuthorFunding.into();
2353 let actual_digest = T::CommitmentAdapter::get_commit_digest(&caller, reason)?;
2354 T::CommitmentAdapter::index_exists(reason, &actual_digest)?;
2355 ensure!(
2356 index_digest == actual_digest,
2357 Error::<T>::FundedToAnotherDigest
2358 );
2359 let index_fund = T::CommitmentAdapter::get_commit_value(&caller, reason)?;
2360 return Ok(index_fund);
2361 }
2362 FundingTarget::Pool(pool_digest) => {
2363 let reason = &FreezeReason::AuthorFunding.into();
2364 let actual_digest = T::CommitmentAdapter::get_commit_digest(&caller, reason)?;
2365 T::CommitmentAdapter::pool_exists(reason, &actual_digest)?;
2366 ensure!(
2367 pool_digest == actual_digest,
2368 Error::<T>::FundedToAnotherDigest
2369 );
2370 let pool_fund = T::CommitmentAdapter::get_commit_value(&caller, reason)?;
2371 return Ok(pool_fund);
2372 }
2373 };
2374 }
2375
2376 pub fn inspect_author_fund(
2381 caller: T::AccountId,
2382 author: Author<T>,
2383 from: FundingTarget<T>,
2384 ) -> Result<AuthorAsset<T>, DispatchError> {
2385 let funder = match from {
2386 FundingTarget::Direct(_author) => {
2387 let funder = Funder::<T>::Direct(caller);
2388 funder
2389 }
2390 FundingTarget::Index(index_digest) => {
2391 let funder = Funder::<T>::Index {
2392 digest: index_digest,
2393 backer: caller,
2394 };
2395 funder
2396 }
2397 FundingTarget::Pool(pool_digest) => {
2398 let funder = Funder::<T>::Pool {
2399 digest: pool_digest,
2400 backer: caller,
2401 };
2402 funder
2403 }
2404 };
2405 let fund = <Pallet<T> as FundRoles<Author<T>>>::get_fund(&author, &funder)?;
2406 Ok(fund)
2407 }
2408 }
2409
2410 pub struct FlatElection<T: Config>(PhantomData<T>);
2452
2453 pub struct FairElection<T: Config>(PhantomData<T>);
2500}
2501
2502#[cfg(test)]
2507mod ext_tests {
2508
2509 use crate::{
2515 mock::authors_test_ext,
2516 mock::*,
2517 types::{
2518 AuthorStatus, ForceGenesisConfig, FortitudeWrapper, Funder, FundingTarget,
2519 PrecisionWrapper,
2520 },
2521 FreezeReason,
2522 };
2523
2524 use frame_suite::{
2526 commitment::*,
2527 roles::{CompensateRoles, FundRoles, RoleManager, RoleProbation},
2528 };
2529
2530 use frame_support::{
2532 assert_err, assert_ok,
2533 traits::{
2534 tokens::{Fortitude, Precision},
2535 Hooks,
2536 },
2537 };
2538
2539 use sp_runtime::{DispatchError, Perbill};
2541
2542 fn assert_index_created_and_get_digest() -> IndexDigest {
2548 System::events()
2549 .iter()
2550 .rev()
2551 .find_map(|record| {
2552 if let RuntimeEvent::Authors(Event::IndexCreated { index, .. }) = &record.event {
2553 Some(index.clone())
2554 } else {
2555 None
2556 }
2557 })
2558 .expect("IndexCreated event not emitted")
2559 }
2560
2561 fn assert_pool_created_and_get_digest() -> PoolDigest {
2563 System::events()
2564 .iter()
2565 .rev()
2566 .find_map(|record| {
2567 if let RuntimeEvent::Authors(Event::PoolCreated { pool, .. }) = &record.event {
2568 Some(pool.clone())
2569 } else {
2570 None
2571 }
2572 })
2573 .expect("PoolCreated event not emitted")
2574 }
2575
2576 #[test]
2581 fn on_initialize_succes() {
2582 authors_test_ext().execute_with(|| {
2583 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD).unwrap();
2584 initiate_key_and_set_balance_and_hold(&&CHARLIE, INITIAL_BALANCE, STANDARD_HOLD)
2585 .unwrap();
2586
2587 System::set_block_number(6);
2588 Pallet::enroll(&ALICE, 250, Fortitude::Force).unwrap();
2589 Pallet::fund(
2590 &ALICE,
2591 &Funder::Direct(CHARLIE),
2592 125,
2593 Precision::Exact,
2594 Fortitude::Force,
2595 )
2596 .unwrap();
2597
2598 System::set_block_number(16);
2599 Pallet::set_permanence(&ALICE).unwrap();
2600
2601 let author_collateral = Pallet::get_collateral(&ALICE).unwrap();
2602 assert_eq!(author_collateral, 250);
2603 let author_backing = Pallet::get_fund(&ALICE, &Funder::Direct(CHARLIE)).unwrap();
2604 assert_eq!(author_backing, 125);
2605 let hold = Pallet::get_hold(&ALICE).unwrap();
2606 assert_eq!(hold, 375);
2607
2608 System::set_block_number(20);
2609 let reward = 20;
2610 Pallet::reward(&ALICE, reward, Precision::Exact).unwrap();
2611
2612 assert_ok!(Pallet::has_reward(&ALICE));
2613 System::set_block_number(22);
2614 Pallet::on_initialize(22);
2615
2616 let hold = Pallet::get_hold(&ALICE).unwrap();
2617 assert_eq!(hold, 395); let author_collateral = Pallet::get_collateral(&ALICE).unwrap();
2621 assert_eq!(author_collateral, 263);
2622 let author_backing = Pallet::get_fund(&ALICE, &Funder::Direct(CHARLIE)).unwrap();
2623 assert_eq!(author_backing, 132);
2624
2625 assert_err!(Pallet::has_reward(&ALICE), Error::RewardNotFound);
2626
2627 System::set_block_number(24);
2628 let penalty = Perbill::from_percent(10);
2629 Pallet::penalize(&ALICE, penalty).unwrap();
2630
2631 assert_ok!(Pallet::has_penalty(&ALICE));
2632 System::set_block_number(28);
2633 Pallet::on_initialize(28);
2634
2635 let hold = Pallet::get_hold(&ALICE).unwrap();
2636 assert_eq!(hold, 356); let author_collateral = Pallet::get_collateral(&ALICE).unwrap();
2641 assert!(author_collateral == 237 || author_collateral == 236);
2643 let author_backing = Pallet::get_fund(&ALICE, &Funder::Direct(CHARLIE)).unwrap();
2644 assert!(author_backing == 119 || author_backing == 118);
2645
2646 assert_err!(Pallet::has_penalty(&ALICE), Error::PenaltyNotFound);
2647 })
2648 }
2649
2650 #[test]
2655 fn enroll_author_success() {
2656 authors_test_ext().execute_with(|| {
2657 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD).unwrap();
2658
2659 assert_err!(Pallet::role_exists(&ALICE), Error::AuthorNotFound);
2660 System::set_block_number(10);
2661 assert_ok!(Pallet::enlist(
2662 RuntimeOrigin::signed(ALICE),
2663 100,
2664 FortitudeWrapper::Force
2665 ));
2666
2667 assert_ok!(Pallet::role_exists(&ALICE));
2668 let meta = Pallet::get_meta(&ALICE).unwrap();
2669 assert_eq!(meta.since, 10);
2670 assert_eq!(meta.status, AuthorStatus::Probation);
2671
2672 System::assert_last_event(
2673 Event::AuthorEnlisted {
2674 author: ALICE,
2675 collateral: 100,
2676 }
2677 .into(),
2678 );
2679 })
2680 }
2681
2682 #[test]
2683 fn enroll_author_inadequate_collateral() {
2684 authors_test_ext().execute_with(|| {
2685 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD).unwrap();
2686
2687 assert_err!(Pallet::role_exists(&ALICE), Error::AuthorNotFound);
2688 System::set_block_number(4);
2689 assert_err!(
2690 Pallet::enlist(RuntimeOrigin::signed(ALICE), 15, FortitudeWrapper::Force),
2691 Error::InadequateCollateral
2692 );
2693 })
2694 }
2695
2696 #[test]
2697 fn enroll_author_bad_origin() {
2698 authors_test_ext().execute_with(|| {
2699 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD)
2700 .unwrap();
2701
2702 assert_err!(
2703 Pallet::role_exists(&ALICE),
2704 Error::AuthorNotFound
2705 );
2706 System::set_block_number(4);
2707 assert_err!{Pallet::enlist(RuntimeOrigin::root(), 100, FortitudeWrapper::Force), DispatchError::BadOrigin};
2708 })
2709 }
2710
2711 #[test]
2712 fn resign_author_success() {
2713 authors_test_ext().execute_with(|| {
2714 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD).unwrap();
2715
2716 System::set_block_number(10);
2717 Pallet::enroll(&ALICE, 100, Fortitude::Force).unwrap();
2718
2719 System::set_block_number(20);
2720 Pallet::set_status(&ALICE, AuthorStatus::Active).unwrap();
2721
2722 System::set_block_number(25);
2723 assert_ok!(Pallet::demit(RuntimeOrigin::signed(ALICE)));
2724
2725 System::assert_last_event(
2726 Event::AuthorResigned {
2727 author: ALICE,
2728 released: 100,
2729 }
2730 .into(),
2731 );
2732 })
2733 }
2734
2735 #[test]
2736 fn resign_author_err_author_in_probation() {
2737 authors_test_ext().execute_with(|| {
2738 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD).unwrap();
2739
2740 System::set_block_number(10);
2741 Pallet::enroll(&ALICE, 100, Fortitude::Force).unwrap();
2742
2743 System::set_block_number(15);
2744 assert_err!(
2745 Pallet::demit(RuntimeOrigin::signed(ALICE)),
2746 Error::AuthorInProbation
2747 );
2748 })
2749 }
2750
2751 #[test]
2752 fn resign_author_err_author_has_penalties() {
2753 authors_test_ext().execute_with(|| {
2754 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD).unwrap();
2755
2756 System::set_block_number(10);
2757 Pallet::enroll(&ALICE, 100, Fortitude::Force).unwrap();
2758
2759 System::set_block_number(20);
2760 Pallet::set_status(&ALICE, AuthorStatus::Active).unwrap();
2761
2762 System::set_block_number(25);
2763 Pallet::penalize(&ALICE, Perbill::from_percent(5)).unwrap();
2764
2765 System::set_block_number(26);
2766 assert_err!(
2767 Pallet::demit(RuntimeOrigin::signed(ALICE)),
2768 Error::AuthorHasPenalties
2769 );
2770 })
2771 }
2772
2773 #[test]
2774 fn resign_author_err_bad_origin() {
2775 authors_test_ext().execute_with(|| {
2776 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD).unwrap();
2777
2778 System::set_block_number(10);
2779 Pallet::enroll(&ALICE, 100, Fortitude::Force).unwrap();
2780
2781 System::set_block_number(20);
2782 Pallet::set_status(&ALICE, AuthorStatus::Active).unwrap();
2783
2784 System::set_block_number(25);
2785 assert_err!(
2786 Pallet::demit(RuntimeOrigin::root()),
2787 DispatchError::BadOrigin
2788 );
2789 })
2790 }
2791
2792 #[test]
2793 fn raise_collateral_success() {
2794 authors_test_ext().execute_with(|| {
2795 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD).unwrap();
2796
2797 System::set_block_number(10);
2798 Pallet::enroll(&ALICE, 100, Fortitude::Force).unwrap();
2799
2800 let current_collateral = Pallet::get_collateral(&ALICE).unwrap();
2801 assert_eq!(current_collateral, 100);
2802
2803 System::set_block_number(15);
2804 Pallet::refill(RuntimeOrigin::signed(ALICE), 50, FortitudeWrapper::Force).unwrap();
2805
2806 let current_collateral = Pallet::get_collateral(&ALICE).unwrap();
2807 assert_eq!(current_collateral, 150);
2808
2809 System::assert_last_event(
2810 Event::AuthorCollateralRaised {
2811 author: ALICE,
2812 raised: 50,
2813 }
2814 .into(),
2815 );
2816 })
2817 }
2818
2819 #[test]
2820 fn raise_collateral_err_bad_origin() {
2821 authors_test_ext().execute_with(|| {
2822 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD).unwrap();
2823
2824 System::set_block_number(10);
2825 Pallet::enroll(&ALICE, 100, Fortitude::Force).unwrap();
2826
2827 System::set_block_number(15);
2828 assert_err!(
2829 Pallet::refill(RuntimeOrigin::root(), 50, FortitudeWrapper::Force),
2830 DispatchError::BadOrigin
2831 );
2832 })
2833 }
2834
2835 #[cfg(feature = "dev")]
2836 #[test]
2837 fn check_collateral_success() {
2838 authors_test_ext().execute_with(|| {
2839 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD).unwrap();
2840
2841 System::set_block_number(10);
2842 Pallet::enroll(&ALICE, 100, Fortitude::Force).unwrap();
2843
2844 assert_ok!(Pallet::my_collateral(RuntimeOrigin::signed(ALICE)));
2845
2846 System::assert_last_event(
2847 Event::AuthorTotalCollateral {
2848 author: ALICE,
2849 collateral: 100,
2850 }
2851 .into(),
2852 );
2853 })
2854 }
2855
2856 #[cfg(feature = "dev")]
2857 #[test]
2858 fn check_collateral_err_author_not_found() {
2859 authors_test_ext().execute_with(|| {
2860 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD).unwrap();
2861
2862 System::set_block_number(10);
2863 Pallet::enroll(&ALICE, 100, Fortitude::Force).unwrap();
2864
2865 assert_err!(
2866 Pallet::my_collateral(RuntimeOrigin::signed(BOB)),
2867 Error::AuthorNotFound
2868 );
2869 })
2870 }
2871
2872 #[cfg(feature = "dev")]
2873 #[test]
2874 fn check_collateral_err_bad_origin() {
2875 authors_test_ext().execute_with(|| {
2876 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD).unwrap();
2877
2878 System::set_block_number(10);
2879 Pallet::enroll(&ALICE, 100, Fortitude::Force).unwrap();
2880
2881 assert_err!(
2882 Pallet::my_collateral(RuntimeOrigin::root()),
2883 DispatchError::BadOrigin
2884 );
2885 })
2886 }
2887
2888 #[test]
2889 fn fund_author_direct_success() {
2890 authors_test_ext().execute_with(|| {
2891 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD).unwrap();
2892 initiate_key_and_set_balance_and_hold(&CHARLIE, INITIAL_BALANCE, STANDARD_HOLD)
2893 .unwrap();
2894
2895 System::set_block_number(10);
2896 Pallet::enroll(&ALICE, 100, Fortitude::Force).unwrap();
2897
2898 System::set_block_number(20);
2899 assert_ok!(Pallet::back(
2900 RuntimeOrigin::signed(CHARLIE),
2901 FundingTarget::Direct(ALICE),
2902 100,
2903 FortitudeWrapper::Force,
2904 PrecisionWrapper::Exact
2905 ));
2906
2907 let current_hold = Pallet::get_hold(&ALICE).unwrap();
2908 assert_eq!(current_hold, 200);
2909 let backed_value = Pallet::backed_value(&ALICE).unwrap();
2910 assert_eq!(backed_value, 100);
2911 let backers_of = Pallet::backers_of(&ALICE).unwrap();
2912 assert_eq!(backers_of, vec![(Funder::Direct(CHARLIE), 100)]);
2913
2914 System::assert_last_event(
2915 Event::AuthorFunded {
2916 author: ALICE,
2917 backer: CHARLIE,
2918 amount: 100,
2919 }
2920 .into(),
2921 );
2922 })
2923 }
2924
2925 #[test]
2926 fn fund_author_direct_err_bad_origin() {
2927 authors_test_ext().execute_with(|| {
2928 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD).unwrap();
2929 initiate_key_and_set_balance_and_hold(&CHARLIE, INITIAL_BALANCE, STANDARD_HOLD)
2930 .unwrap();
2931
2932 System::set_block_number(10);
2933 Pallet::enroll(&ALICE, 100, Fortitude::Force).unwrap();
2934
2935 System::set_block_number(20);
2936 assert_err!(
2937 Pallet::back(
2938 RuntimeOrigin::root(),
2939 FundingTarget::Direct(ALICE),
2940 100,
2941 FortitudeWrapper::Force,
2942 PrecisionWrapper::Exact
2943 ),
2944 DispatchError::BadOrigin
2945 );
2946 })
2947 }
2948
2949 #[test]
2950 fn fund_author_direct_err_below_minimum_fund() {
2951 authors_test_ext().execute_with(|| {
2952 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD).unwrap();
2953 initiate_key_and_set_balance_and_hold(&CHARLIE, INITIAL_BALANCE, STANDARD_HOLD)
2954 .unwrap();
2955
2956 System::set_block_number(10);
2957 Pallet::enroll(&ALICE, 100, Fortitude::Force).unwrap();
2958
2959 System::set_block_number(20);
2960 assert_err!(
2961 Pallet::back(
2962 RuntimeOrigin::signed(CHARLIE),
2963 FundingTarget::Direct(ALICE),
2964 15,
2965 FortitudeWrapper::Force,
2966 PrecisionWrapper::Exact
2967 ),
2968 Error::BelowMinimumFund
2969 );
2970 })
2971 }
2972
2973 #[test]
2974 fn fund_author_index_success() {
2975 authors_test_ext().execute_with(|| {
2976 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
2977 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
2978 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
2979 initiate_key_and_set_balance_and_hold(&MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
2980 initiate_key_and_set_balance_and_hold(&ALAN, LARGE_VALUE, LARGE_VALUE).unwrap();
2981
2982 System::set_block_number(6);
2983 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
2984
2985 Pallet::enroll(&BOB, STANDARD_VALUE, Fortitude::Force).unwrap();
2986
2987 Pallet::fund(
2988 &ALICE,
2989 &Funder::Direct(CHARLIE),
2990 STANDARD_VALUE,
2991 Precision::Exact,
2992 Fortitude::Force,
2993 )
2994 .unwrap();
2995
2996 Pallet::fund(
2997 &BOB,
2998 &Funder::Direct(ALAN),
2999 LARGE_VALUE,
3000 Precision::Exact,
3001 Fortitude::Force,
3002 )
3003 .unwrap();
3004
3005 let alice_digest = gen_author_digest(&ALICE).unwrap();
3006 let bob_digest = gen_author_digest(&BOB).unwrap();
3007 let entries = vec![(alice_digest.clone(), 60), (bob_digest.clone(), 40)];
3008
3009 let alice_current_hold = Pallet::get_hold(&ALICE).unwrap();
3010 assert_eq!(alice_current_hold, 100);
3011 let bob_current_hold = Pallet::get_hold(&BOB).unwrap();
3012 assert_eq!(bob_current_hold, 150);
3013
3014 prepare_and_initiate_index(MIKE, FUNDING.into(), &entries, INDEX_DIGEST).unwrap();
3015
3016 let by = Funder::Index {
3017 digest: INDEX_DIGEST,
3018 backer: MIKE,
3019 };
3020
3021 assert_ok!(Pallet::back(
3022 RuntimeOrigin::signed(MIKE),
3023 FundingTarget::Index(INDEX_DIGEST),
3024 100,
3025 FortitudeWrapper::Force,
3026 PrecisionWrapper::Exact
3027 ));
3028
3029 let backers_of_alice = Pallet::backers_of(&ALICE).unwrap();
3030 let expected_backers_of_alice = vec![(by.clone(), 60), (Funder::Direct(CHARLIE), 50)];
3031 assert_eq!(backers_of_alice, expected_backers_of_alice);
3032
3033 let backers_of_bob = Pallet::backers_of(&BOB).unwrap();
3034 let expected_backers_of_bob = vec![(by.clone(), 40), (Funder::Direct(ALAN), 100)];
3035 assert_eq!(backers_of_bob, expected_backers_of_bob);
3036
3037 let alice_current_hold = Pallet::get_hold(&ALICE).unwrap();
3038 assert_eq!(alice_current_hold, 160);
3039 let bob_current_hold = Pallet::get_hold(&BOB).unwrap();
3040 assert_eq!(bob_current_hold, 190);
3041
3042 System::assert_last_event(
3043 Event::IndexFunded {
3044 index: INDEX_DIGEST,
3045 backer: MIKE,
3046 amount: 100,
3047 }
3048 .into(),
3049 );
3050 })
3051 }
3052
3053 #[test]
3054 fn fund_author_pool_success() {
3055 authors_test_ext().execute_with(|| {
3056 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3057 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
3058 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
3059 initiate_key_and_set_balance_and_hold(&MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
3060 initiate_key_and_set_balance_and_hold(&ALAN, LARGE_VALUE, LARGE_VALUE).unwrap();
3061
3062 System::set_block_number(6);
3063 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
3064
3065 System::set_block_number(8);
3066 Pallet::fund(
3067 &ALICE,
3068 &Funder::Direct(CHARLIE),
3069 STANDARD_VALUE,
3070 Precision::Exact,
3071 Fortitude::Force,
3072 )
3073 .unwrap();
3074
3075 System::set_block_number(12);
3076 Pallet::enroll(&BOB, STANDARD_VALUE, Fortitude::Force).unwrap();
3077
3078 System::set_block_number(15);
3079 Pallet::fund(
3080 &BOB,
3081 &Funder::Direct(ALAN),
3082 LARGE_VALUE,
3083 Precision::Exact,
3084 Fortitude::Force,
3085 )
3086 .unwrap();
3087
3088 let total_backing = Pallet::total_backing();
3089 assert_eq!(total_backing, 150);
3090 let alice_backed_value = Pallet::backed_value(&ALICE).unwrap();
3091 assert_eq!(alice_backed_value, 50);
3092 let bob_backed_value = Pallet::backed_value(&BOB).unwrap();
3093 assert_eq!(bob_backed_value, 100);
3094
3095 let alice_digest = gen_author_digest(&ALICE).unwrap();
3096 let bob_digest = gen_author_digest(&BOB).unwrap();
3097 let entries = vec![(alice_digest.clone(), 60), (bob_digest.clone(), 40)];
3098
3099 let alice_current_hold = Pallet::get_hold(&ALICE).unwrap();
3100 assert_eq!(alice_current_hold, 100);
3101 let bob_current_hold = Pallet::get_hold(&BOB).unwrap();
3102 assert_eq!(bob_current_hold, 150);
3103
3104 prepare_and_initiate_pool(
3105 ALAN,
3106 FUNDING.into(),
3107 &entries,
3108 INDEX_DIGEST,
3109 POOL_DIGEST,
3110 Perbill::from_percent(5),
3111 )
3112 .unwrap();
3113
3114 let by = Funder::Pool {
3115 digest: POOL_DIGEST,
3116 backer: MIKE,
3117 };
3118
3119 assert_ok!(Pallet::back(
3120 RuntimeOrigin::signed(MIKE),
3121 FundingTarget::Pool(POOL_DIGEST),
3122 100,
3123 FortitudeWrapper::Force,
3124 PrecisionWrapper::Exact
3125 ));
3126
3127 let total_backing = Pallet::total_backing();
3128 assert_eq!(total_backing, 250);
3129 let alice_backed_value = Pallet::backed_value(&ALICE).unwrap();
3130 assert_eq!(alice_backed_value, 110); let bob_backed_value = Pallet::backed_value(&BOB).unwrap();
3132 assert_eq!(bob_backed_value, 140); let author_funders = AuthorFunders::get((ALICE, MIKE)).unwrap();
3135 assert_eq!(author_funders, by);
3136
3137 let alice_current_hold = Pallet::get_hold(&ALICE).unwrap();
3138 assert_eq!(alice_current_hold, 160);
3139 let bob_current_hold = Pallet::get_hold(&BOB).unwrap();
3140 assert_eq!(bob_current_hold, 190);
3141
3142 System::assert_last_event(
3143 Event::PoolFunded {
3144 pool: POOL_DIGEST,
3145 backer: MIKE,
3146 amount: 100,
3147 }
3148 .into(),
3149 );
3150 })
3151 }
3152
3153 #[test]
3154 fn release_fund_direct_success() {
3155 authors_test_ext().execute_with(|| {
3156 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD).unwrap();
3157 initiate_key_and_set_balance_and_hold(&CHARLIE, INITIAL_BALANCE, STANDARD_HOLD)
3158 .unwrap();
3159
3160 System::set_block_number(10);
3161 Pallet::enroll(&ALICE, 100, Fortitude::Force).unwrap();
3162
3163 System::set_block_number(20);
3164 assert_ok!(Pallet::back(
3165 RuntimeOrigin::signed(CHARLIE),
3166 FundingTarget::Direct(ALICE),
3167 100,
3168 FortitudeWrapper::Force,
3169 PrecisionWrapper::Exact
3170 ));
3171
3172 let current_hold = Pallet::get_hold(&ALICE).unwrap();
3173 assert_eq!(current_hold, 200);
3174 let backed_value = Pallet::backed_value(&ALICE).unwrap();
3175 assert_eq!(backed_value, 100);
3176 let backers_of = Pallet::backers_of(&ALICE).unwrap();
3177 assert_eq!(backers_of, vec![(Funder::Direct(CHARLIE), 100)]);
3178
3179 let charlie_balance = get_user_balance(&CHARLIE);
3180 assert_eq!(charlie_balance, 100);
3181
3182 System::set_block_number(25);
3183 assert_ok!(Pallet::exit(
3184 RuntimeOrigin::signed(CHARLIE),
3185 FundingTarget::Direct(ALICE)
3186 ));
3187
3188 let current_hold = Pallet::get_hold(&ALICE).unwrap();
3189 assert_eq!(current_hold, 100);
3190
3191 let backed_value = Pallet::backed_value(&ALICE).unwrap();
3192 assert_eq!(backed_value, 0);
3193
3194 let backers_of = Pallet::backers_of(&ALICE).unwrap();
3195 assert_eq!(backers_of, vec![]);
3196
3197 let charlie_balance = get_user_balance(&CHARLIE);
3198 assert_eq!(charlie_balance, 200);
3199
3200 System::assert_last_event(
3201 Event::AuthorDrawn {
3202 author: ALICE,
3203 backer: CHARLIE,
3204 amount: 100,
3205 }
3206 .into(),
3207 );
3208 })
3209 }
3210
3211 #[test]
3212 fn release_fund_direct_err_bad_origin() {
3213 authors_test_ext().execute_with(|| {
3214 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD).unwrap();
3215 initiate_key_and_set_balance_and_hold(&CHARLIE, INITIAL_BALANCE, STANDARD_HOLD)
3216 .unwrap();
3217
3218 System::set_block_number(10);
3219 Pallet::enroll(&ALICE, 100, Fortitude::Force).unwrap();
3220
3221 System::set_block_number(20);
3222 assert_ok!(Pallet::back(
3223 RuntimeOrigin::signed(CHARLIE),
3224 FundingTarget::Direct(ALICE),
3225 100,
3226 FortitudeWrapper::Force,
3227 PrecisionWrapper::Exact
3228 ));
3229
3230 let current_hold = Pallet::get_hold(&ALICE).unwrap();
3231 assert_eq!(current_hold, 200);
3232 let backed_value = Pallet::backed_value(&ALICE).unwrap();
3233 assert_eq!(backed_value, 100);
3234 let backers_of = Pallet::backers_of(&ALICE).unwrap();
3235 assert_eq!(backers_of, vec![(Funder::Direct(CHARLIE), 100)]);
3236
3237 let charlie_balance = get_user_balance(&CHARLIE);
3238 assert_eq!(charlie_balance, 100);
3239
3240 System::set_block_number(25);
3241 assert_err!(
3242 Pallet::exit(RuntimeOrigin::root(), FundingTarget::Direct(ALICE)),
3243 DispatchError::BadOrigin
3244 );
3245 })
3246 }
3247
3248 #[test]
3249 fn release_fund_index_success() {
3250 authors_test_ext().execute_with(|| {
3251 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3252 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
3253 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
3254 initiate_key_and_set_balance_and_hold(&MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
3255 initiate_key_and_set_balance_and_hold(&ALAN, LARGE_VALUE, LARGE_VALUE).unwrap();
3256
3257 System::set_block_number(6);
3258 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
3259
3260 System::set_block_number(8);
3261 Pallet::fund(
3262 &ALICE,
3263 &Funder::Direct(CHARLIE),
3264 STANDARD_VALUE,
3265 Precision::Exact,
3266 Fortitude::Force,
3267 )
3268 .unwrap();
3269
3270 System::set_block_number(12);
3271 Pallet::enroll(&BOB, STANDARD_VALUE, Fortitude::Force).unwrap();
3272
3273 System::set_block_number(15);
3274 Pallet::fund(
3275 &BOB,
3276 &Funder::Direct(ALAN),
3277 LARGE_VALUE,
3278 Precision::Exact,
3279 Fortitude::Force,
3280 )
3281 .unwrap();
3282
3283 let alice_digest = gen_author_digest(&ALICE).unwrap();
3284 let bob_digest = gen_author_digest(&BOB).unwrap();
3285 let entries = vec![(alice_digest.clone(), 60), (bob_digest.clone(), 40)];
3286
3287 prepare_and_initiate_index(MIKE, FUNDING.into(), &entries, INDEX_DIGEST).unwrap();
3288
3289 let by = Funder::Index {
3290 digest: INDEX_DIGEST,
3291 backer: MIKE,
3292 };
3293
3294 Pallet::fund(&ALICE, &by, LARGE_VALUE, Precision::Exact, Fortitude::Force).unwrap();
3295
3296 let total_backing = Pallet::total_backing();
3297 assert_eq!(total_backing, 250);
3298 let alice_backed_value = Pallet::backed_value(&ALICE).unwrap();
3299 assert_eq!(alice_backed_value, 110); let bob_backed_value = Pallet::backed_value(&BOB).unwrap();
3301 assert_eq!(bob_backed_value, 140); let author_funders = AuthorFunders::get((ALICE, MIKE)).unwrap();
3304 assert_eq!(author_funders, by);
3305
3306 assert_ok!(Pallet::exit(
3307 RuntimeOrigin::signed(MIKE),
3308 FundingTarget::Index(INDEX_DIGEST)
3309 ));
3310
3311 let total_backing = Pallet::total_backing();
3312 assert_eq!(total_backing, 150);
3313 let alice_backed_value = Pallet::backed_value(&ALICE).unwrap();
3314 assert_eq!(alice_backed_value, 50); let bob_backed_value = Pallet::backed_value(&BOB).unwrap();
3316 assert_eq!(bob_backed_value, 100); assert!(!AuthorFunders::contains_key((ALICE, MIKE)));
3319
3320 let mike_balance = get_user_balance(&MIKE);
3321 assert_eq!(mike_balance, 200);
3322 })
3323 }
3324
3325 #[test]
3326 fn release_fund_pool_success() {
3327 authors_test_ext().execute_with(|| {
3328 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3329 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
3330 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
3331 initiate_key_and_set_balance_and_hold(&MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
3332 initiate_key_and_set_balance_and_hold(&ALAN, LARGE_VALUE, LARGE_VALUE).unwrap();
3333
3334 System::set_block_number(6);
3335 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
3336
3337 System::set_block_number(8);
3338 Pallet::fund(
3339 &ALICE,
3340 &Funder::Direct(CHARLIE),
3341 STANDARD_VALUE,
3342 Precision::Exact,
3343 Fortitude::Force,
3344 )
3345 .unwrap();
3346
3347 System::set_block_number(12);
3348 Pallet::enroll(&BOB, STANDARD_VALUE, Fortitude::Force).unwrap();
3349
3350 System::set_block_number(15);
3351 Pallet::fund(
3352 &BOB,
3353 &Funder::Direct(ALAN),
3354 LARGE_VALUE,
3355 Precision::Exact,
3356 Fortitude::Force,
3357 )
3358 .unwrap();
3359
3360 let alice_digest = gen_author_digest(&ALICE).unwrap();
3361 let bob_digest = gen_author_digest(&BOB).unwrap();
3362 let entries = vec![(alice_digest.clone(), 60), (bob_digest.clone(), 40)];
3363
3364 prepare_and_initiate_pool(
3365 ALAN,
3366 FUNDING.into(),
3367 &entries,
3368 INDEX_DIGEST,
3369 POOL_DIGEST,
3370 Perbill::from_percent(5),
3371 )
3372 .unwrap();
3373
3374 let by = Funder::Pool {
3375 digest: POOL_DIGEST,
3376 backer: MIKE,
3377 };
3378
3379 Pallet::fund(&ALICE, &by, LARGE_VALUE, Precision::Exact, Fortitude::Force).unwrap();
3380
3381 let total_backing = Pallet::total_backing();
3382 assert_eq!(total_backing, 250);
3383 let alice_backed_value = Pallet::backed_value(&ALICE).unwrap();
3384 assert_eq!(alice_backed_value, 110); let bob_backed_value = Pallet::backed_value(&BOB).unwrap();
3386 assert_eq!(bob_backed_value, 140); let author_funders = AuthorFunders::get((ALICE, MIKE)).unwrap();
3389 assert_eq!(author_funders, by);
3390 let author_funders = AuthorFunders::get((BOB, MIKE)).unwrap();
3391 assert_eq!(author_funders, by);
3392
3393 assert_ok!(Pallet::exit(
3394 RuntimeOrigin::signed(MIKE),
3395 FundingTarget::Pool(POOL_DIGEST)
3396 ));
3397
3398 let total_backing = Pallet::total_backing();
3399 assert_eq!(total_backing, 150);
3400 let alice_backed_value = Pallet::backed_value(&ALICE).unwrap();
3401 assert_eq!(alice_backed_value, 50); let bob_backed_value = Pallet::backed_value(&BOB).unwrap();
3403 assert_eq!(bob_backed_value, 100); assert!(!AuthorFunders::contains_key((ALICE, MIKE)));
3406
3407 let mike_balance = get_user_balance(&MIKE);
3408 assert_eq!(mike_balance, 195); let alan_balance = get_user_balance(&ALAN);
3410 assert_eq!(alan_balance, 105); })
3412 }
3413
3414 #[cfg(feature = "dev")]
3415 #[test]
3416 fn check_fund_direct_success() {
3417 authors_test_ext().execute_with(|| {
3418 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD).unwrap();
3419 initiate_key_and_set_balance_and_hold(&CHARLIE, INITIAL_BALANCE, STANDARD_HOLD)
3420 .unwrap();
3421
3422 System::set_block_number(10);
3423 Pallet::enroll(&ALICE, 100, Fortitude::Force).unwrap();
3424
3425 System::set_block_number(20);
3426 assert_ok!(Pallet::back(
3427 RuntimeOrigin::signed(CHARLIE),
3428 FundingTarget::Direct(ALICE),
3429 100,
3430 FortitudeWrapper::Force,
3431 PrecisionWrapper::Exact
3432 ));
3433
3434 let current_hold = Pallet::get_hold(&ALICE).unwrap();
3435 assert_eq!(current_hold, 200);
3436 let backed_value = Pallet::backed_value(&ALICE).unwrap();
3437 assert_eq!(backed_value, 100);
3438 let backers_of = Pallet::backers_of(&ALICE).unwrap();
3439 assert_eq!(backers_of, vec![(Funder::Direct(CHARLIE), 100)]);
3440
3441 System::set_block_number(25);
3442 assert_ok!(Pallet::my_fund(
3443 RuntimeOrigin::signed(CHARLIE),
3444 FundingTarget::Direct(ALICE)
3445 ));
3446
3447 System::assert_last_event(
3448 Event::InspectAuthorFund {
3449 author: ALICE,
3450 backer: CHARLIE,
3451 amount: 100,
3452 }
3453 .into(),
3454 );
3455 })
3456 }
3457
3458 #[cfg(feature = "dev")]
3459 #[test]
3460 fn check_fund_towards_index_success() {
3461 authors_test_ext().execute_with(|| {
3462 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3463 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
3464 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
3465 initiate_key_and_set_balance_and_hold(&MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
3466 initiate_key_and_set_balance_and_hold(&ALAN, LARGE_VALUE, LARGE_VALUE).unwrap();
3467 initiate_key_and_set_balance_and_hold(&NIX, LARGE_VALUE, LARGE_VALUE).unwrap();
3468
3469 System::set_block_number(6);
3470 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
3471
3472 System::set_block_number(8);
3473 Pallet::fund(
3474 &ALICE,
3475 &Funder::Direct(CHARLIE),
3476 STANDARD_VALUE,
3477 Precision::Exact,
3478 Fortitude::Force,
3479 )
3480 .unwrap();
3481
3482 System::set_block_number(12);
3483 Pallet::enroll(&BOB, STANDARD_VALUE, Fortitude::Force).unwrap();
3484
3485 System::set_block_number(15);
3486 Pallet::fund(
3487 &BOB,
3488 &Funder::Direct(ALAN),
3489 LARGE_VALUE,
3490 Precision::Exact,
3491 Fortitude::Force,
3492 )
3493 .unwrap();
3494
3495 let alice_digest = gen_author_digest(&ALICE).unwrap();
3496 let bob_digest = gen_author_digest(&BOB).unwrap();
3497 let entries = vec![(alice_digest.clone(), 60), (bob_digest.clone(), 40)];
3498
3499 prepare_and_initiate_index(MIKE, FUNDING.into(), &entries, INDEX_DIGEST).unwrap();
3500
3501 let by_mike = Funder::Index {
3502 digest: INDEX_DIGEST,
3503 backer: MIKE,
3504 };
3505
3506 Pallet::fund(
3507 &ALICE,
3508 &by_mike,
3509 LARGE_VALUE,
3510 Precision::Exact,
3511 Fortitude::Force,
3512 )
3513 .unwrap();
3514
3515 let by_nix = Funder::Index {
3516 digest: INDEX_DIGEST,
3517 backer: NIX,
3518 };
3519
3520 Pallet::fund(
3521 &ALICE,
3522 &by_nix,
3523 STANDARD_VALUE,
3524 Precision::Exact,
3525 Fortitude::Force,
3526 )
3527 .unwrap();
3528
3529 System::set_block_number(25);
3530 assert_ok!(Pallet::my_author_fund(
3531 RuntimeOrigin::signed(MIKE),
3532 ALICE,
3533 FundingTarget::Index(INDEX_DIGEST)
3534 ));
3535
3536 System::assert_last_event(
3537 Event::InspectFund {
3538 author: ALICE,
3539 funder: by_mike.clone(),
3540 amount: 60,
3541 }
3542 .into(),
3543 );
3544
3545 assert_ok!(Pallet::my_author_fund(
3546 RuntimeOrigin::signed(MIKE),
3547 BOB,
3548 FundingTarget::Index(INDEX_DIGEST)
3549 ));
3550
3551 System::assert_last_event(
3552 Event::InspectFund {
3553 author: BOB,
3554 funder: by_mike,
3555 amount: 40,
3556 }
3557 .into(),
3558 );
3559
3560 System::set_block_number(26);
3561 assert_ok!(Pallet::my_author_fund(
3562 RuntimeOrigin::signed(NIX),
3563 ALICE,
3564 FundingTarget::Index(INDEX_DIGEST)
3565 ));
3566
3567 System::assert_last_event(
3568 Event::InspectFund {
3569 author: ALICE,
3570 funder: by_nix.clone(),
3571 amount: 30,
3572 }
3573 .into(),
3574 );
3575
3576 assert_ok!(Pallet::my_author_fund(
3577 RuntimeOrigin::signed(NIX),
3578 BOB,
3579 FundingTarget::Index(INDEX_DIGEST)
3580 ));
3581
3582 System::assert_last_event(
3583 Event::InspectFund {
3584 author: BOB,
3585 funder: by_nix,
3586 amount: 20,
3587 }
3588 .into(),
3589 );
3590 })
3591 }
3592
3593 #[cfg(feature = "dev")]
3594 #[test]
3595 fn check_fund_index_success() {
3596 authors_test_ext().execute_with(|| {
3597 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3598 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
3599 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
3600 initiate_key_and_set_balance_and_hold(&MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
3601 initiate_key_and_set_balance_and_hold(&ALAN, LARGE_VALUE, LARGE_VALUE).unwrap();
3602 initiate_key_and_set_balance_and_hold(&NIX, LARGE_VALUE, LARGE_VALUE).unwrap();
3603
3604 System::set_block_number(6);
3605 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
3606
3607 System::set_block_number(8);
3608 Pallet::fund(
3609 &ALICE,
3610 &Funder::Direct(CHARLIE),
3611 STANDARD_VALUE,
3612 Precision::Exact,
3613 Fortitude::Force,
3614 )
3615 .unwrap();
3616
3617 System::set_block_number(12);
3618 Pallet::enroll(&BOB, STANDARD_VALUE, Fortitude::Force).unwrap();
3619
3620 System::set_block_number(15);
3621 Pallet::fund(
3622 &BOB,
3623 &Funder::Direct(ALAN),
3624 LARGE_VALUE,
3625 Precision::Exact,
3626 Fortitude::Force,
3627 )
3628 .unwrap();
3629
3630 let alice_digest = gen_author_digest(&ALICE).unwrap();
3631 let bob_digest = gen_author_digest(&BOB).unwrap();
3632 let entries = vec![(alice_digest.clone(), 60), (bob_digest.clone(), 40)];
3633
3634 prepare_and_initiate_index(MIKE, FUNDING.into(), &entries, INDEX_DIGEST).unwrap();
3635
3636 let by_mike = Funder::Index {
3637 digest: INDEX_DIGEST,
3638 backer: MIKE,
3639 };
3640
3641 Pallet::fund(
3642 &ALICE,
3643 &by_mike,
3644 LARGE_VALUE,
3645 Precision::Exact,
3646 Fortitude::Force,
3647 )
3648 .unwrap();
3649
3650 let by_nix = Funder::Index {
3651 digest: INDEX_DIGEST,
3652 backer: NIX,
3653 };
3654
3655 Pallet::fund(
3656 &ALICE,
3657 &by_nix,
3658 STANDARD_VALUE,
3659 Precision::Exact,
3660 Fortitude::Force,
3661 )
3662 .unwrap();
3663
3664 System::set_block_number(25);
3665 assert_ok!(Pallet::my_fund(
3666 RuntimeOrigin::signed(MIKE),
3667 FundingTarget::Index(INDEX_DIGEST)
3668 ));
3669
3670 System::assert_last_event(
3671 Event::InspectIndexFund {
3672 index: INDEX_DIGEST,
3673 backer: MIKE,
3674 amount: 100,
3675 }
3676 .into(),
3677 );
3678
3679 System::set_block_number(26);
3680 assert_ok!(Pallet::my_fund(
3681 RuntimeOrigin::signed(NIX),
3682 FundingTarget::Index(INDEX_DIGEST)
3683 ));
3684
3685 System::assert_last_event(
3686 Event::InspectIndexFund {
3687 index: INDEX_DIGEST,
3688 backer: NIX,
3689 amount: 50,
3690 }
3691 .into(),
3692 );
3693 })
3694 }
3695
3696 #[cfg(feature = "dev")]
3697 #[test]
3698 fn check_fund_towards_pool_success() {
3699 authors_test_ext().execute_with(|| {
3700 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3701 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
3702 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
3703 initiate_key_and_set_balance_and_hold(&MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
3704 initiate_key_and_set_balance_and_hold(&ALAN, LARGE_VALUE, LARGE_VALUE).unwrap();
3705 initiate_key_and_set_balance_and_hold(&NIX, LARGE_VALUE, LARGE_VALUE).unwrap();
3706
3707 System::set_block_number(6);
3708 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
3709
3710 System::set_block_number(8);
3711 Pallet::fund(
3712 &ALICE,
3713 &Funder::Direct(CHARLIE),
3714 STANDARD_VALUE,
3715 Precision::Exact,
3716 Fortitude::Force,
3717 )
3718 .unwrap();
3719
3720 System::set_block_number(12);
3721 Pallet::enroll(&BOB, STANDARD_VALUE, Fortitude::Force).unwrap();
3722
3723 System::set_block_number(15);
3724 Pallet::fund(
3725 &BOB,
3726 &Funder::Direct(ALAN),
3727 LARGE_VALUE,
3728 Precision::Exact,
3729 Fortitude::Force,
3730 )
3731 .unwrap();
3732
3733 let alice_digest = gen_author_digest(&ALICE).unwrap();
3734 let bob_digest = gen_author_digest(&BOB).unwrap();
3735 let entries = vec![(alice_digest.clone(), 60), (bob_digest.clone(), 40)];
3736
3737 prepare_and_initiate_pool(
3738 ALAN,
3739 FUNDING.into(),
3740 &entries,
3741 INDEX_DIGEST,
3742 POOL_DIGEST,
3743 Perbill::from_percent(5),
3744 )
3745 .unwrap();
3746
3747 let by_mike = Funder::Pool {
3748 digest: POOL_DIGEST,
3749 backer: MIKE,
3750 };
3751
3752 Pallet::fund(
3753 &ALICE,
3754 &by_mike,
3755 LARGE_VALUE,
3756 Precision::Exact,
3757 Fortitude::Force,
3758 )
3759 .unwrap();
3760
3761 let by_nix = Funder::Pool {
3762 digest: POOL_DIGEST,
3763 backer: NIX,
3764 };
3765
3766 Pallet::fund(
3767 &ALICE,
3768 &by_nix,
3769 STANDARD_VALUE,
3770 Precision::Exact,
3771 Fortitude::Force,
3772 )
3773 .unwrap();
3774
3775 System::set_block_number(25);
3776 assert_ok!(Pallet::my_author_fund(
3777 RuntimeOrigin::signed(MIKE),
3778 ALICE,
3779 FundingTarget::Pool(POOL_DIGEST)
3780 ));
3781
3782 System::assert_last_event(
3783 Event::InspectFund {
3784 author: ALICE,
3785 funder: by_mike.clone(),
3786 amount: 60,
3787 }
3788 .into(),
3789 );
3790
3791 assert_ok!(Pallet::my_author_fund(
3792 RuntimeOrigin::signed(MIKE),
3793 BOB,
3794 FundingTarget::Pool(POOL_DIGEST)
3795 ));
3796
3797 System::assert_last_event(
3798 Event::InspectFund {
3799 author: BOB,
3800 funder: by_mike,
3801 amount: 40,
3802 }
3803 .into(),
3804 );
3805
3806 System::set_block_number(26);
3807 assert_ok!(Pallet::my_author_fund(
3808 RuntimeOrigin::signed(NIX),
3809 ALICE,
3810 FundingTarget::Pool(POOL_DIGEST)
3811 ));
3812
3813 System::assert_last_event(
3814 Event::InspectFund {
3815 author: ALICE,
3816 funder: by_nix.clone(),
3817 amount: 30,
3818 }
3819 .into(),
3820 );
3821
3822 assert_ok!(Pallet::my_author_fund(
3823 RuntimeOrigin::signed(NIX),
3824 BOB,
3825 FundingTarget::Pool(POOL_DIGEST)
3826 ));
3827
3828 System::assert_last_event(
3829 Event::InspectFund {
3830 author: BOB,
3831 funder: by_nix,
3832 amount: 20,
3833 }
3834 .into(),
3835 );
3836 })
3837 }
3838
3839 #[cfg(feature = "dev")]
3840 #[test]
3841 fn check_fund_pool_success() {
3842 authors_test_ext().execute_with(|| {
3843 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
3844 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
3845 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
3846 initiate_key_and_set_balance_and_hold(&MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
3847 initiate_key_and_set_balance_and_hold(&ALAN, LARGE_VALUE, LARGE_VALUE).unwrap();
3848 initiate_key_and_set_balance_and_hold(&NIX, LARGE_VALUE, LARGE_VALUE).unwrap();
3849
3850 System::set_block_number(6);
3851 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
3852
3853 System::set_block_number(8);
3854 Pallet::fund(
3855 &ALICE,
3856 &Funder::Direct(CHARLIE),
3857 STANDARD_VALUE,
3858 Precision::Exact,
3859 Fortitude::Force,
3860 )
3861 .unwrap();
3862
3863 System::set_block_number(12);
3864 Pallet::enroll(&BOB, STANDARD_VALUE, Fortitude::Force).unwrap();
3865
3866 System::set_block_number(15);
3867 Pallet::fund(
3868 &BOB,
3869 &Funder::Direct(ALAN),
3870 LARGE_VALUE,
3871 Precision::Exact,
3872 Fortitude::Force,
3873 )
3874 .unwrap();
3875
3876 let alice_digest = gen_author_digest(&ALICE).unwrap();
3877 let bob_digest = gen_author_digest(&BOB).unwrap();
3878 let entries = vec![(alice_digest.clone(), 60), (bob_digest.clone(), 40)];
3879
3880 prepare_and_initiate_pool(
3881 ALAN,
3882 FUNDING.into(),
3883 &entries,
3884 INDEX_DIGEST,
3885 POOL_DIGEST,
3886 Perbill::from_percent(5),
3887 )
3888 .unwrap();
3889
3890 let by_mike = Funder::Pool {
3891 digest: POOL_DIGEST,
3892 backer: MIKE,
3893 };
3894
3895 Pallet::fund(
3896 &ALICE,
3897 &by_mike,
3898 LARGE_VALUE,
3899 Precision::Exact,
3900 Fortitude::Force,
3901 )
3902 .unwrap();
3903
3904 let by_nix = Funder::Pool {
3905 digest: POOL_DIGEST,
3906 backer: NIX,
3907 };
3908
3909 Pallet::fund(
3910 &ALICE,
3911 &by_nix,
3912 STANDARD_VALUE,
3913 Precision::Exact,
3914 Fortitude::Force,
3915 )
3916 .unwrap();
3917
3918 System::set_block_number(25);
3919 assert_ok!(Pallet::my_fund(
3920 RuntimeOrigin::signed(MIKE),
3921 FundingTarget::Pool(POOL_DIGEST)
3922 ));
3923
3924 System::assert_last_event(
3925 Event::InspectPoolFund {
3926 pool: POOL_DIGEST,
3927 backer: MIKE,
3928 amount: 100,
3929 }
3930 .into(),
3931 );
3932
3933 System::set_block_number(26);
3934 assert_ok!(Pallet::my_fund(
3935 RuntimeOrigin::signed(NIX),
3936 FundingTarget::Pool(POOL_DIGEST)
3937 ));
3938
3939 System::assert_last_event(
3940 Event::InspectPoolFund {
3941 pool: POOL_DIGEST,
3942 backer: NIX,
3943 amount: 50,
3944 }
3945 .into(),
3946 );
3947 })
3948 }
3949
3950 #[cfg(feature = "dev")]
3951 #[test]
3952 fn upcoming_rewards_success() {
3953 authors_test_ext().execute_with(|| {
3954 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD).unwrap();
3955
3956 System::set_block_number(10);
3957 Pallet::enroll(&ALICE, 100, Fortitude::Force).unwrap();
3958
3959 System::set_block_number(12);
3960 let reward_a = 20;
3961 Pallet::reward(&ALICE, reward_a, Precision::Exact).unwrap();
3962
3963 System::set_block_number(13);
3964 let reward_b = 15;
3965 Pallet::reward(&ALICE, reward_b, Precision::Exact).unwrap();
3966
3967 assert_ok!(Pallet::shed_rewards(RuntimeOrigin::signed(ALICE)));
3968
3969 let expected_rewards = vec![(14, 20), (15, 15)];
3970 System::assert_last_event(
3971 Event::ScheduledRewards {
3972 author: ALICE,
3973 rewards: expected_rewards,
3974 }
3975 .into(),
3976 );
3977 })
3978 }
3979
3980 #[cfg(feature = "dev")]
3981 #[test]
3982 fn upcoming_rewards_err_reward_not_found() {
3983 authors_test_ext().execute_with(|| {
3984 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD).unwrap();
3985
3986 System::set_block_number(10);
3987 Pallet::enroll(&ALICE, 100, Fortitude::Force).unwrap();
3988
3989 assert_err!(
3990 Pallet::shed_rewards(RuntimeOrigin::signed(ALICE)),
3991 Error::RewardNotFound
3992 );
3993 })
3994 }
3995
3996 #[cfg(feature = "dev")]
3997 #[test]
3998 fn upcoming_penalties_success() {
3999 authors_test_ext().execute_with(|| {
4000 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD).unwrap();
4001
4002 System::set_block_number(10);
4003 Pallet::enroll(&ALICE, 100, Fortitude::Force).unwrap();
4004
4005 System::set_block_number(12);
4006 let penalty_a = Perbill::from_percent(10);
4007 Pallet::penalize(&ALICE, penalty_a).unwrap();
4008
4009 System::set_block_number(14);
4010 let penalty_b = Perbill::from_percent(5);
4011 Pallet::penalize(&ALICE, penalty_b).unwrap();
4012
4013 assert_ok!(Pallet::shed_penalties(RuntimeOrigin::signed(ALICE)));
4014
4015 let expected_penalties = vec![(16, penalty_a), (18, penalty_b)];
4016 System::assert_last_event(
4017 Event::ScheduledPenalties {
4018 author: ALICE,
4019 penalties: expected_penalties,
4020 }
4021 .into(),
4022 );
4023 })
4024 }
4025
4026 #[cfg(feature = "dev")]
4027 #[test]
4028 fn upcoming_penalties_err_penalty_not_found() {
4029 authors_test_ext().execute_with(|| {
4030 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD).unwrap();
4031
4032 System::set_block_number(10);
4033 Pallet::enroll(&ALICE, 100, Fortitude::Force).unwrap();
4034
4035 assert_err!(
4036 Pallet::shed_penalties(RuntimeOrigin::signed(ALICE)),
4037 Error::PenaltyNotFound
4038 );
4039 })
4040 }
4041
4042 #[test]
4043 fn end_probation_success() {
4044 authors_test_ext().execute_with(|| {
4045 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD).unwrap();
4046
4047 System::set_block_number(10);
4048 Pallet::enroll(&ALICE, 100, Fortitude::Force).unwrap();
4049
4050 let current_status = Pallet::get_status(&ALICE).unwrap();
4051 assert_eq!(current_status, AuthorStatus::Probation);
4052
4053 System::set_block_number(20);
4054 assert_ok!(Pallet::confirm(RuntimeOrigin::signed(ALICE)));
4055
4056 let current_status = Pallet::get_status(&ALICE).unwrap();
4057 assert_eq!(current_status, AuthorStatus::Active);
4058
4059 System::assert_last_event(
4060 Event::AuthorStatus {
4061 author: ALICE,
4062 status: AuthorStatus::Active,
4063 }
4064 .into(),
4065 );
4066 })
4067 }
4068
4069 #[test]
4070 fn end_probation_err_author_in_probation() {
4071 authors_test_ext().execute_with(|| {
4072 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD).unwrap();
4073
4074 System::set_block_number(10);
4075 Pallet::enroll(&ALICE, 100, Fortitude::Force).unwrap();
4076
4077 let current_status = Pallet::get_status(&ALICE).unwrap();
4078 assert_eq!(current_status, AuthorStatus::Probation);
4079
4080 System::set_block_number(15);
4081 assert_err!(
4082 Pallet::confirm(RuntimeOrigin::signed(ALICE)),
4083 Error::AuthorInProbation
4084 );
4085 })
4086 }
4087
4088 #[test]
4089 fn end_probation_err_author_is_unsafe() {
4090 authors_test_ext().execute_with(|| {
4091 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD).unwrap();
4092
4093 System::set_block_number(10);
4094 Pallet::enroll(&ALICE, 100, Fortitude::Force).unwrap();
4095
4096 let current_status = Pallet::get_status(&ALICE).unwrap();
4097 assert_eq!(current_status, AuthorStatus::Probation);
4098
4099 System::set_block_number(20);
4100
4101 Pallet::penalize(&ALICE, Perbill::from_percent(5)).unwrap();
4102
4103 assert_err!(
4104 Pallet::confirm(RuntimeOrigin::signed(ALICE)),
4105 Error::AuthorIsUnsafe
4106 );
4107 })
4108 }
4109
4110 #[test]
4111 fn end_probation_err_bad_origin() {
4112 authors_test_ext().execute_with(|| {
4113 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD).unwrap();
4114
4115 System::set_block_number(10);
4116 Pallet::enroll(&ALICE, 100, Fortitude::Force).unwrap();
4117
4118 let current_status = Pallet::get_status(&ALICE).unwrap();
4119 assert_eq!(current_status, AuthorStatus::Probation);
4120
4121 System::set_block_number(20);
4122 assert_err!(
4123 Pallet::confirm(RuntimeOrigin::root()),
4124 DispatchError::BadOrigin
4125 );
4126 })
4127 }
4128
4129 #[test]
4130 fn force_genesis_config_probation_period_success() {
4131 authors_test_ext().execute_with(|| {
4132 System::set_block_number(10);
4133 let before_probation_period = ProbationPeriod::get();
4134 assert_eq!(before_probation_period, 10);
4135 let new_probation_period = 15;
4136 assert_ok!(Pallet::force_genesis_config(
4137 RuntimeOrigin::root(),
4138 ForceGenesisConfig::ProbationPeriod(new_probation_period)
4139 ));
4140 let after_probation_period = ProbationPeriod::get();
4141 assert_eq!(after_probation_period, 15);
4142 System::assert_last_event(
4143 Event::GenesisConfigUpdated(ForceGenesisConfig::ProbationPeriod(
4144 new_probation_period,
4145 ))
4146 .into(),
4147 );
4148 })
4149 }
4150
4151 #[test]
4152 fn force_genesis_config_probation_period_err_bad_origin() {
4153 authors_test_ext().execute_with(|| {
4154 let before_probation_period = ProbationPeriod::get();
4155 assert_eq!(before_probation_period, 10);
4156 let new_probation_period = 15;
4157 assert_err!(
4158 Pallet::force_genesis_config(
4159 RuntimeOrigin::signed(ALICE),
4160 ForceGenesisConfig::ProbationPeriod(new_probation_period)
4161 ),
4162 DispatchError::BadOrigin
4163 );
4164 })
4165 }
4166
4167 #[test]
4168 fn force_genesis_config_reduce_probation_by_success() {
4169 authors_test_ext().execute_with(|| {
4170 System::set_block_number(10);
4171 let before_reduce_probation_by = ReduceProbationBy::get();
4172 assert_eq!(before_reduce_probation_by, 1);
4173 let new_reduce_probation_by = 2;
4174 assert_ok!(Pallet::force_genesis_config(
4175 RuntimeOrigin::root(),
4176 ForceGenesisConfig::ReduceProbationBy(new_reduce_probation_by)
4177 ));
4178 let after_reduce_probation_by = ReduceProbationBy::get();
4179 assert_eq!(after_reduce_probation_by, 2);
4180 System::assert_last_event(
4181 Event::GenesisConfigUpdated(ForceGenesisConfig::ReduceProbationBy(
4182 new_reduce_probation_by,
4183 ))
4184 .into(),
4185 );
4186 })
4187 }
4188
4189 #[test]
4190 fn force_genesis_config_reduce_probation_by_err_bad_origin() {
4191 authors_test_ext().execute_with(|| {
4192 let before_reduce_probation_by = ReduceProbationBy::get();
4193 assert_eq!(before_reduce_probation_by, 1);
4194 let new_reduce_probation_by = 2;
4195 assert_err!(
4196 Pallet::force_genesis_config(
4197 RuntimeOrigin::signed(ALICE),
4198 ForceGenesisConfig::ReduceProbationBy(new_reduce_probation_by)
4199 ),
4200 DispatchError::BadOrigin
4201 );
4202 })
4203 }
4204
4205 #[test]
4206 fn force_genesis_config_increase_probation_by_success() {
4207 authors_test_ext().execute_with(|| {
4208 System::set_block_number(10);
4209 let before_increase_probation_by = IncreaseProbationBy::get();
4210 assert_eq!(before_increase_probation_by, 1);
4211 let new_increase_probation_by = 2;
4212 assert_ok!(Pallet::force_genesis_config(
4213 RuntimeOrigin::root(),
4214 ForceGenesisConfig::IncreaseProbationBy(new_increase_probation_by)
4215 ));
4216 let after_increase_probation_by = IncreaseProbationBy::get();
4217 assert_eq!(after_increase_probation_by, 2);
4218 System::assert_last_event(
4219 Event::GenesisConfigUpdated(ForceGenesisConfig::IncreaseProbationBy(
4220 new_increase_probation_by,
4221 ))
4222 .into(),
4223 );
4224 })
4225 }
4226
4227 #[test]
4228 fn force_genesis_config_increase_probation_by_err_bad_origin() {
4229 authors_test_ext().execute_with(|| {
4230 let before_increase_probation_by = IncreaseProbationBy::get();
4231 assert_eq!(before_increase_probation_by, 1);
4232 let new_increase_probation_by = 2;
4233 assert_err!(
4234 Pallet::force_genesis_config(
4235 RuntimeOrigin::signed(ALICE),
4236 ForceGenesisConfig::IncreaseProbationBy(new_increase_probation_by)
4237 ),
4238 DispatchError::BadOrigin
4239 );
4240 })
4241 }
4242
4243 #[test]
4244 fn force_genesis_config_rewards_buffer_success() {
4245 authors_test_ext().execute_with(|| {
4246 System::set_block_number(10);
4247 let before_rewards_buffer = RewardsBuffer::get();
4248 assert_eq!(before_rewards_buffer, 2);
4249 let new_rewards_buffer = 4;
4250 assert_ok!(Pallet::force_genesis_config(
4251 RuntimeOrigin::root(),
4252 ForceGenesisConfig::RewardsBuffer(new_rewards_buffer)
4253 ));
4254 let after_rewards_buffer = RewardsBuffer::get();
4255 assert_eq!(after_rewards_buffer, 4);
4256 System::assert_last_event(
4257 Event::GenesisConfigUpdated(ForceGenesisConfig::RewardsBuffer(new_rewards_buffer))
4258 .into(),
4259 );
4260 })
4261 }
4262
4263 #[test]
4264 fn force_genesis_config_rewards_buffer_err_bad_origin() {
4265 authors_test_ext().execute_with(|| {
4266 let before_rewards_buffer = RewardsBuffer::get();
4267 assert_eq!(before_rewards_buffer, 2);
4268 let new_rewards_buffer = 4;
4269 assert_err!(
4270 Pallet::force_genesis_config(
4271 RuntimeOrigin::signed(ALICE),
4272 ForceGenesisConfig::RewardsBuffer(new_rewards_buffer)
4273 ),
4274 DispatchError::BadOrigin
4275 );
4276 })
4277 }
4278
4279 #[test]
4280 fn force_genesis_config_penalties_buffer_success() {
4281 authors_test_ext().execute_with(|| {
4282 System::set_block_number(10);
4283 let before_penalties_buffer = PenaltiesBuffer::get();
4284 assert_eq!(before_penalties_buffer, 4);
4285 let new_penalties_buffer = 5;
4286 assert_ok!(Pallet::force_genesis_config(
4287 RuntimeOrigin::root(),
4288 ForceGenesisConfig::PenaltiesBuffer(new_penalties_buffer)
4289 ));
4290 let after_penalties_buffer = PenaltiesBuffer::get();
4291 assert_eq!(after_penalties_buffer, 5);
4292 System::assert_last_event(
4293 Event::GenesisConfigUpdated(ForceGenesisConfig::PenaltiesBuffer(
4294 new_penalties_buffer,
4295 ))
4296 .into(),
4297 );
4298 })
4299 }
4300
4301 #[test]
4302 fn force_genesis_config_penalties_buffer_err_bad_origin() {
4303 authors_test_ext().execute_with(|| {
4304 let before_penalties_buffer = PenaltiesBuffer::get();
4305 assert_eq!(before_penalties_buffer, 4);
4306 let new_penalties_buffer = 5;
4307 assert_err!(
4308 Pallet::force_genesis_config(
4309 RuntimeOrigin::signed(ALICE),
4310 ForceGenesisConfig::PenaltiesBuffer(new_penalties_buffer)
4311 ),
4312 DispatchError::BadOrigin
4313 );
4314 })
4315 }
4316
4317 #[test]
4318 fn force_genesis_config_max_elected_success() {
4319 authors_test_ext().execute_with(|| {
4320 System::set_block_number(6);
4321 let before_max_elected = MaxElected::get();
4322 assert_eq!(before_max_elected, 100);
4323 let new_max_elected = 75;
4324 assert_ok!(Pallet::force_genesis_config(
4325 RuntimeOrigin::root(),
4326 ForceGenesisConfig::MaxElected(new_max_elected)
4327 ));
4328 let after_max_elected = MaxElected::get();
4329 assert_eq!(after_max_elected, 75);
4330 System::assert_last_event(
4331 Event::GenesisConfigUpdated(ForceGenesisConfig::MaxElected(new_max_elected)).into(),
4332 );
4333 })
4334 }
4335
4336 #[test]
4337 fn force_genesis_config_max_elected_err_bad_origin() {
4338 authors_test_ext().execute_with(|| {
4339 let before_max_elected = MaxElected::get();
4340 assert_eq!(before_max_elected, 100);
4341 let new_max_elected = 75;
4342 assert_err!(
4343 Pallet::force_genesis_config(
4344 RuntimeOrigin::signed(ALICE),
4345 ForceGenesisConfig::MaxElected(new_max_elected)
4346 ),
4347 DispatchError::BadOrigin
4348 );
4349 })
4350 }
4351
4352 #[test]
4353 fn force_genesis_config_min_elected_success() {
4354 authors_test_ext().execute_with(|| {
4355 System::set_block_number(10);
4356 let before_min_elected = MinElected::get();
4357 assert_eq!(before_min_elected, 6);
4358 let new_min_elected = 15;
4359 assert_ok!(Pallet::force_genesis_config(
4360 RuntimeOrigin::root(),
4361 ForceGenesisConfig::MinElected(new_min_elected)
4362 ));
4363 let after_min_elected = MinElected::get();
4364 assert_eq!(after_min_elected, 15);
4365 System::assert_last_event(
4366 Event::GenesisConfigUpdated(ForceGenesisConfig::MinElected(new_min_elected)).into(),
4367 );
4368 })
4369 }
4370
4371 #[test]
4372 fn force_genesis_config_min_elected_err_bad_origin() {
4373 authors_test_ext().execute_with(|| {
4374 let before_min_elected = MinElected::get();
4375 assert_eq!(before_min_elected, 6);
4376 let new_min_elected = 15;
4377 assert_err!(
4378 Pallet::force_genesis_config(
4379 RuntimeOrigin::signed(ALICE),
4380 ForceGenesisConfig::MinElected(new_min_elected)
4381 ),
4382 DispatchError::BadOrigin
4383 );
4384 })
4385 }
4386
4387 #[test]
4388 fn force_genesis_config_enforce_max_elected_success() {
4389 authors_test_ext().execute_with(|| {
4390 System::set_block_number(10);
4391 let before_enforce_max_elected = ForceMaxElected::get();
4392 assert_eq!(before_enforce_max_elected, false);
4393 let new_enforce_max_elected = true;
4394 assert_ok!(Pallet::force_genesis_config(
4395 RuntimeOrigin::root(),
4396 ForceGenesisConfig::EnforceMaxElected(new_enforce_max_elected)
4397 ));
4398 let after_enforce_max_elected = ForceMaxElected::get();
4399 assert_eq!(after_enforce_max_elected, true);
4400 System::assert_last_event(
4401 Event::GenesisConfigUpdated(ForceGenesisConfig::EnforceMaxElected(
4402 new_enforce_max_elected,
4403 ))
4404 .into(),
4405 );
4406 })
4407 }
4408
4409 #[test]
4410 fn force_genesis_config_enforce_max_elected_err_bad_origin() {
4411 authors_test_ext().execute_with(|| {
4412 let before_enforce_max_elected = ForceMaxElected::get();
4413 assert_eq!(before_enforce_max_elected, false);
4414 let new_enforce_max_elected = true;
4415 assert_err!(
4416 Pallet::force_genesis_config(
4417 RuntimeOrigin::signed(ALICE),
4418 ForceGenesisConfig::EnforceMaxElected(new_enforce_max_elected)
4419 ),
4420 DispatchError::BadOrigin
4421 );
4422 })
4423 }
4424
4425 #[test]
4426 fn force_genesis_config_min_fund_success() {
4427 authors_test_ext().execute_with(|| {
4428 System::set_block_number(10);
4429 let before_min_fund = MinFund::get();
4430 assert_eq!(before_min_fund, 25);
4431 let new_min_fund = 50;
4432 assert_ok!(Pallet::force_genesis_config(
4433 RuntimeOrigin::root(),
4434 ForceGenesisConfig::MinFund(new_min_fund)
4435 ));
4436 let after_min_fund = MinFund::get();
4437 assert_eq!(after_min_fund, 50);
4438 System::assert_last_event(
4439 Event::GenesisConfigUpdated(ForceGenesisConfig::MinFund(new_min_fund)).into(),
4440 );
4441 })
4442 }
4443
4444 #[test]
4445 fn force_genesis_config_min_fund_err_bad_origin() {
4446 authors_test_ext().execute_with(|| {
4447 let before_min_fund = MinFund::get();
4448 assert_eq!(before_min_fund, 25);
4449 let new_min_fund = 50;
4450 assert_err!(
4451 Pallet::force_genesis_config(
4452 RuntimeOrigin::signed(ALICE),
4453 ForceGenesisConfig::MinFund(new_min_fund)
4454 ),
4455 DispatchError::BadOrigin
4456 );
4457 })
4458 }
4459
4460 #[test]
4461 fn force_genesis_config_max_exposure_success() {
4462 authors_test_ext().execute_with(|| {
4463 System::set_block_number(10);
4464 let before_max_exposure = MaxExposure::get();
4465 assert_eq!(before_max_exposure, 1000);
4466 let new_max_exposure = u64::MAX;
4467 assert_ok!(Pallet::force_genesis_config(
4468 RuntimeOrigin::root(),
4469 ForceGenesisConfig::MaxExposure(new_max_exposure)
4470 ));
4471 let after_max_exposure = MaxExposure::get();
4472 assert_eq!(after_max_exposure, u64::MAX);
4473 System::assert_last_event(
4474 Event::GenesisConfigUpdated(ForceGenesisConfig::MaxExposure(new_max_exposure))
4475 .into(),
4476 );
4477 })
4478 }
4479
4480 #[test]
4481 fn force_genesis_config_max_exposure_err_bad_origin() {
4482 authors_test_ext().execute_with(|| {
4483 let before_max_exposure = MaxExposure::get();
4484 assert_eq!(before_max_exposure, 1000);
4485 let new_max_exposure = u64::MAX;
4486 assert_err!(
4487 Pallet::force_genesis_config(
4488 RuntimeOrigin::signed(ALICE),
4489 ForceGenesisConfig::MaxExposure(new_max_exposure)
4490 ),
4491 DispatchError::BadOrigin
4492 );
4493 })
4494 }
4495
4496 #[test]
4497 fn force_genesis_config_min_collateral_success() {
4498 authors_test_ext().execute_with(|| {
4499 System::set_block_number(10);
4500 let before_min_collateral = MinCollateral::get();
4501 assert_eq!(before_min_collateral, 50);
4502 let new_min_collateral = 100;
4503 assert_ok!(Pallet::force_genesis_config(
4504 RuntimeOrigin::root(),
4505 ForceGenesisConfig::MinCollateral(new_min_collateral)
4506 ));
4507 let after_min_collateral = MinCollateral::get();
4508 assert_eq!(after_min_collateral, 100);
4509 System::assert_last_event(
4510 Event::GenesisConfigUpdated(ForceGenesisConfig::MinCollateral(new_min_collateral))
4511 .into(),
4512 );
4513 })
4514 }
4515
4516 #[test]
4517 fn force_genesis_config_min_collateral_err_bad_origin() {
4518 authors_test_ext().execute_with(|| {
4519 let before_min_collateral = MinCollateral::get();
4520 assert_eq!(before_min_collateral, 50);
4521 let new_min_collateral = 100;
4522 assert_err!(
4523 Pallet::force_genesis_config(
4524 RuntimeOrigin::signed(ALICE),
4525 ForceGenesisConfig::MinCollateral(new_min_collateral)
4526 ),
4527 DispatchError::BadOrigin
4528 );
4529 })
4530 }
4531
4532 #[test]
4533 fn force_genesis_config_enforces_invariants() {
4534 authors_test_ext().execute_with(|| {
4535 assert_err!(
4536 Pallet::force_genesis_config(
4537 RuntimeOrigin::root(),
4538 ForceGenesisConfig::MinCollateral(0)
4539 ),
4540 Error::NonZeroConfigRequired
4541 );
4542
4543 assert_err!(
4544 Pallet::force_genesis_config(
4545 RuntimeOrigin::root(),
4546 ForceGenesisConfig::MinElected(0)
4547 ),
4548 Error::NonZeroConfigRequired
4549 );
4550
4551 assert_err!(
4552 Pallet::force_genesis_config(
4553 RuntimeOrigin::root(),
4554 ForceGenesisConfig::MaxElected(0)
4555 ),
4556 Error::NonZeroConfigRequired
4557 );
4558
4559 assert_err!(
4560 Pallet::force_genesis_config(RuntimeOrigin::root(), ForceGenesisConfig::MinFund(0)),
4561 Error::NonZeroConfigRequired
4562 );
4563
4564 let max_exposure = MaxExposure::get();
4565 let min_fund = MinFund::get();
4566 assert_eq!(max_exposure, 1000);
4567 assert!(min_fund <= max_exposure);
4568 assert_err!(
4569 Pallet::force_genesis_config(
4570 RuntimeOrigin::root(),
4571 ForceGenesisConfig::MinFund(1001)
4572 ),
4573 Error::MinGreaterThanMax
4574 );
4575 assert_eq!(min_fund, 25);
4576 assert_err!(
4577 Pallet::force_genesis_config(
4578 RuntimeOrigin::root(),
4579 ForceGenesisConfig::MaxExposure(24)
4580 ),
4581 Error::MinGreaterThanMax
4582 );
4583
4584 let min_elected = MinElected::get();
4585 let max_elected = MaxElected::get();
4586 assert!(min_elected <= max_elected);
4587 assert_eq!(max_elected, 100);
4588 assert_err!(
4589 Pallet::force_genesis_config(
4590 RuntimeOrigin::root(),
4591 ForceGenesisConfig::MinElected(101)
4592 ),
4593 Error::MinGreaterThanMax
4594 );
4595 assert_eq!(min_elected, 6);
4596 assert_err!(
4597 Pallet::force_genesis_config(
4598 RuntimeOrigin::root(),
4599 ForceGenesisConfig::MaxElected(5)
4600 ),
4601 Error::MinGreaterThanMax
4602 );
4603 })
4604 }
4605
4606 #[test]
4607 fn create_index_success() {
4608 authors_test_ext().execute_with(|| {
4609 initiate_key_and_set_balance_and_hold(&ALICE, 500, 500).unwrap();
4610 initiate_key_and_set_balance_and_hold(&BOB, 500, 500).unwrap();
4611 initiate_key_and_set_balance_and_hold(&CHARLIE, 500, 500).unwrap();
4612 initiate_key_and_set_balance_and_hold(&MIKE, 500, 500).unwrap();
4613 initiate_key_and_set_balance_and_hold(&ALAN, 500, 500).unwrap();
4614 initiate_key_and_set_balance_and_hold(&NIX, 500, 500).unwrap();
4615
4616 Pallet::enroll(&ALICE, 250, Fortitude::Force).unwrap();
4617 Pallet::enroll(&BOB, 300, Fortitude::Force).unwrap();
4618
4619 Pallet::fund(
4620 &ALICE,
4621 &Funder::Direct(ALAN),
4622 100,
4623 Precision::Exact,
4624 Fortitude::Force,
4625 )
4626 .unwrap();
4627
4628 Pallet::fund(
4629 &BOB,
4630 &Funder::Direct(CHARLIE),
4631 200,
4632 Precision::Exact,
4633 Fortitude::Force,
4634 )
4635 .unwrap();
4636
4637 let alice_current_hold = Pallet::get_hold(&ALICE).unwrap();
4638 assert_eq!(alice_current_hold, 350); let bob_current_hold = Pallet::get_hold(&BOB).unwrap();
4640 assert_eq!(bob_current_hold, 500); let entries = vec![(ALICE, 100), (BOB, 100)];
4643
4644 System::set_block_number(10);
4645 assert_ok!(Pallet::create_index(
4646 RuntimeOrigin::signed(MIKE),
4647 entries.clone()
4648 ));
4649
4650 let index_digest = assert_index_created_and_get_digest();
4651
4652 let index_reason = FreezeReason::AuthorFunding.into();
4653 assert_ok!(CommitAdapter::index_exists(&index_reason, &index_digest));
4654
4655 let author_reason = FreezeReason::AuthorCollateral.into();
4656 let alice_digest = CommitAdapter::get_commit_digest(&ALICE, &author_reason).unwrap();
4657 let bob_digest = CommitAdapter::get_commit_digest(&BOB, &author_reason).unwrap();
4658
4659 let mut actual_entries_and_shares =
4660 CommitAdapter::get_entries_shares(&index_reason, &index_digest).unwrap();
4661 let mut expected_entries_and_shares =
4662 vec![(alice_digest.clone(), 100), (bob_digest.clone(), 100)];
4663 actual_entries_and_shares.sort();
4664 expected_entries_and_shares.sort();
4665 assert_eq!(
4666 actual_entries_and_shares,
4667 expected_entries_and_shares
4668 );
4669
4670 let mut actual_entries_and_values =
4671 CommitAdapter::get_entries_value(&index_reason, &index_digest).unwrap();
4672 let mut expected_entries_and_values =
4673 vec![(alice_digest.clone(), 0), (bob_digest.clone(), 0)];
4674 actual_entries_and_values.sort();
4675 expected_entries_and_values.sort();
4676 assert_eq!(
4677 actual_entries_and_values,
4678 expected_entries_and_values
4679 );
4680
4681 let index_info = CommitAdapter::get_index(&index_reason, &index_digest).unwrap();
4682 assert_eq!(index_info.capital(), 200);
4683 assert_eq!(index_info.principal(), 0);
4684
4685 let fund_by = Funder::Index {
4686 digest: index_digest.clone(),
4687 backer: NIX,
4688 };
4689 Pallet::fund(&ALICE, &fund_by, 100, Precision::Exact, Fortitude::Force).unwrap();
4690
4691 let mut actual_entries_and_values =
4692 CommitAdapter::get_entries_value(&index_reason, &index_digest).unwrap();
4693 let mut expected_entries_and_values = vec![(alice_digest, 50), (bob_digest, 50)];
4694 actual_entries_and_values.sort();
4695 expected_entries_and_values.sort();
4696 assert_eq!(
4697 actual_entries_and_values,
4698 expected_entries_and_values
4699 );
4700
4701 let index_info = CommitAdapter::get_index(&index_reason, &index_digest).unwrap();
4702 assert_eq!(index_info.principal(), 100);
4703
4704 let alice_current_hold = Pallet::get_hold(&ALICE).unwrap();
4705 assert_eq!(alice_current_hold, 400); let bob_current_hold = Pallet::get_hold(&BOB).unwrap();
4707 assert_eq!(bob_current_hold, 550); })
4709 }
4710
4711 #[test]
4712 fn crate_pool_success() {
4713 authors_test_ext().execute_with(|| {
4714 initiate_key_and_set_balance_and_hold(&ALICE, 500, 500).unwrap();
4715 initiate_key_and_set_balance_and_hold(&BOB, 500, 500).unwrap();
4716 initiate_key_and_set_balance_and_hold(&CHARLIE, 500, 500).unwrap();
4717 initiate_key_and_set_balance_and_hold(&MIKE, 500, 500).unwrap();
4718 initiate_key_and_set_balance_and_hold(&ALAN, 500, 500).unwrap();
4719 initiate_key_and_set_balance_and_hold(&NIX, 500, 500).unwrap();
4720
4721 Pallet::enroll(&ALICE, 250, Fortitude::Force).unwrap();
4722 Pallet::enroll(&BOB, 300, Fortitude::Force).unwrap();
4723
4724 Pallet::fund(
4725 &ALICE,
4726 &Funder::Direct(ALAN),
4727 100,
4728 Precision::Exact,
4729 Fortitude::Force,
4730 )
4731 .unwrap();
4732
4733 Pallet::fund(
4734 &BOB,
4735 &Funder::Direct(CHARLIE),
4736 200,
4737 Precision::Exact,
4738 Fortitude::Force,
4739 )
4740 .unwrap();
4741
4742 let alice_current_hold = Pallet::get_hold(&ALICE).unwrap();
4743 assert_eq!(alice_current_hold, 350); let bob_current_hold = Pallet::get_hold(&BOB).unwrap();
4745 assert_eq!(bob_current_hold, 500); let entries = vec![(ALICE, 100), (BOB, 100)];
4748
4749 System::set_block_number(10);
4750 assert_ok!(Pallet::create_index(
4751 RuntimeOrigin::signed(MIKE),
4752 entries.clone()
4753 ));
4754
4755 let index_digest = assert_index_created_and_get_digest();
4756
4757 let pool_reason = FreezeReason::AuthorFunding.into();
4758
4759 System::set_block_number(15);
4760 let commission = Perbill::from_percent(10);
4761 assert_ok!(Pallet::create_pool(
4762 RuntimeOrigin::signed(MIKE),
4763 index_digest.clone(),
4764 commission
4765 ));
4766
4767 let pool_digest = assert_pool_created_and_get_digest();
4768
4769 assert_ok!(CommitAdapter::pool_exists(&pool_reason, &pool_digest));
4770
4771 let pool_info = CommitAdapter::get_pool(&pool_reason, &pool_digest).unwrap();
4772 assert_eq!(pool_info.capital(), 200);
4773
4774 let author_reason = FreezeReason::AuthorCollateral.into();
4775 let alice_digest = CommitAdapter::get_commit_digest(&ALICE, &author_reason).unwrap();
4776 let bob_digest = CommitAdapter::get_commit_digest(&BOB, &author_reason).unwrap();
4777
4778 let mut actual_slots_and_shares =
4779 CommitAdapter::get_slots_shares(&pool_reason, &pool_digest).unwrap();
4780 let mut expected_entries_and_shares =
4781 vec![(alice_digest.clone(), 100), (bob_digest.clone(), 100)];
4782 actual_slots_and_shares.sort();
4783 expected_entries_and_shares.sort();
4784 assert_eq!(
4785 actual_slots_and_shares,
4786 expected_entries_and_shares
4787 );
4788
4789 let mut actual_entries_and_values =
4790 CommitAdapter::get_slots_value(&pool_reason, &pool_digest).unwrap();
4791 let mut expected_entries_and_values =
4792 vec![(alice_digest.clone(), 0), (bob_digest.clone(), 0)];
4793 actual_entries_and_values.sort();
4794 expected_entries_and_values.sort();
4795 assert_eq!(
4796 actual_entries_and_values,
4797 expected_entries_and_values
4798 );
4799 })
4800 }
4801
4802 #[test]
4803 fn transfer_pool_ownership_success() {
4804 authors_test_ext().execute_with(|| {
4805 initiate_key_and_set_balance_and_hold(&ALICE, 500, 500).unwrap();
4806 initiate_key_and_set_balance_and_hold(&BOB, 500, 500).unwrap();
4807 initiate_key_and_set_balance_and_hold(&CHARLIE, 500, 500).unwrap();
4808 initiate_key_and_set_balance_and_hold(&MIKE, 500, 500).unwrap();
4809 initiate_key_and_set_balance_and_hold(&ALAN, 500, 500).unwrap();
4810 initiate_key_and_set_balance_and_hold(&NIX, 500, 500).unwrap();
4811
4812 Pallet::enroll(&ALICE, 250, Fortitude::Force).unwrap();
4813 Pallet::enroll(&BOB, 300, Fortitude::Force).unwrap();
4814
4815 Pallet::fund(
4816 &ALICE,
4817 &Funder::Direct(ALAN),
4818 100,
4819 Precision::Exact,
4820 Fortitude::Force,
4821 )
4822 .unwrap();
4823
4824 Pallet::fund(
4825 &BOB,
4826 &Funder::Direct(CHARLIE),
4827 200,
4828 Precision::Exact,
4829 Fortitude::Force,
4830 )
4831 .unwrap();
4832
4833 let entries = vec![(ALICE, 100), (BOB, 100)];
4834
4835 System::set_block_number(10);
4836 assert_ok!(Pallet::create_index(
4837 RuntimeOrigin::signed(MIKE),
4838 entries.clone()
4839 ));
4840
4841 let index_digest = assert_index_created_and_get_digest();
4842
4843 let pool_reason = FreezeReason::AuthorFunding.into();
4844
4845 System::set_block_number(15);
4846 let commission = Perbill::from_percent(10);
4847 assert_ok!(Pallet::create_pool(
4848 RuntimeOrigin::signed(MIKE),
4849 index_digest.clone(),
4850 commission
4851 ));
4852
4853 let pool_digest = assert_pool_created_and_get_digest();
4854
4855 assert_ok!(CommitAdapter::pool_exists(&pool_reason, &pool_digest));
4856
4857 let current_manager = CommitAdapter::get_manager(&pool_reason, &pool_digest).unwrap();
4858 assert_eq!(current_manager, MIKE);
4859
4860 Pallet::transfer_pool(RuntimeOrigin::signed(MIKE), pool_digest.clone(), NIX).unwrap();
4861
4862 System::assert_last_event(
4863 Event::PoolManager {
4864 digest: pool_digest.clone(),
4865 manager: NIX,
4866 }
4867 .into(),
4868 );
4869
4870 let current_manager = CommitAdapter::get_manager(&pool_reason, &pool_digest).unwrap();
4871 assert_eq!(current_manager, NIX);
4872 })
4873 }
4874
4875 #[test]
4876 fn transfer_pool_ownership_err_invalid_pool_manager() {
4877 authors_test_ext().execute_with(|| {
4878 initiate_key_and_set_balance_and_hold(&ALICE, 500, 500).unwrap();
4879 initiate_key_and_set_balance_and_hold(&BOB, 500, 500).unwrap();
4880 initiate_key_and_set_balance_and_hold(&CHARLIE, 500, 500).unwrap();
4881 initiate_key_and_set_balance_and_hold(&MIKE, 500, 500).unwrap();
4882 initiate_key_and_set_balance_and_hold(&ALAN, 500, 500).unwrap();
4883 initiate_key_and_set_balance_and_hold(&NIX, 500, 500).unwrap();
4884
4885 Pallet::enroll(&ALICE, 250, Fortitude::Force).unwrap();
4886 Pallet::enroll(&BOB, 300, Fortitude::Force).unwrap();
4887
4888 Pallet::fund(
4889 &ALICE,
4890 &Funder::Direct(ALAN),
4891 100,
4892 Precision::Exact,
4893 Fortitude::Force,
4894 )
4895 .unwrap();
4896
4897 Pallet::fund(
4898 &BOB,
4899 &Funder::Direct(CHARLIE),
4900 200,
4901 Precision::Exact,
4902 Fortitude::Force,
4903 )
4904 .unwrap();
4905
4906 let entries = vec![(ALICE, 100), (BOB, 100)];
4907
4908 System::set_block_number(10);
4909 assert_ok!(Pallet::create_index(
4910 RuntimeOrigin::signed(MIKE),
4911 entries.clone()
4912 ));
4913
4914 let index_digest = assert_index_created_and_get_digest();
4915
4916 let pool_reason = FreezeReason::AuthorFunding.into();
4917
4918 System::set_block_number(15);
4919 let commission = Perbill::from_percent(10);
4920 assert_ok!(Pallet::create_pool(
4921 RuntimeOrigin::signed(MIKE),
4922 index_digest.clone(),
4923 commission
4924 ));
4925
4926 let pool_digest = assert_pool_created_and_get_digest();
4927
4928 assert_ok!(CommitAdapter::pool_exists(&pool_reason, &pool_digest));
4929
4930 let current_manager = CommitAdapter::get_manager(&pool_reason, &pool_digest).unwrap();
4931 assert_eq!(current_manager, MIKE);
4932
4933 assert_err!(
4934 Pallet::transfer_pool(RuntimeOrigin::signed(ALICE), pool_digest.clone(), NIX,),
4935 Error::InvalidPoolManager
4936 );
4937 })
4938 }
4939
4940 #[test]
4941 fn update_commission_success() {
4942 authors_test_ext().execute_with(|| {
4943 initiate_key_and_set_balance_and_hold(&ALICE, 500, 500).unwrap();
4944 initiate_key_and_set_balance_and_hold(&BOB, 500, 500).unwrap();
4945 initiate_key_and_set_balance_and_hold(&CHARLIE, 500, 500).unwrap();
4946 initiate_key_and_set_balance_and_hold(&MIKE, 500, 500).unwrap();
4947 initiate_key_and_set_balance_and_hold(&ALAN, 500, 500).unwrap();
4948 initiate_key_and_set_balance_and_hold(&NIX, 500, 500).unwrap();
4949
4950 Pallet::enroll(&ALICE, 250, Fortitude::Force).unwrap();
4951 Pallet::enroll(&BOB, 300, Fortitude::Force).unwrap();
4952
4953 Pallet::fund(
4954 &ALICE,
4955 &Funder::Direct(ALAN),
4956 100,
4957 Precision::Exact,
4958 Fortitude::Force,
4959 )
4960 .unwrap();
4961
4962 Pallet::fund(
4963 &BOB,
4964 &Funder::Direct(CHARLIE),
4965 200,
4966 Precision::Exact,
4967 Fortitude::Force,
4968 )
4969 .unwrap();
4970
4971 let entries = vec![(ALICE, 100), (BOB, 100)];
4972
4973 System::set_block_number(10);
4974 assert_ok!(Pallet::create_index(
4975 RuntimeOrigin::signed(MIKE),
4976 entries.clone()
4977 ));
4978
4979 let index_digest = assert_index_created_and_get_digest();
4980
4981 let pool_reason = FreezeReason::AuthorFunding.into();
4982
4983 System::set_block_number(15);
4984 let commission = Perbill::from_percent(10);
4985 assert_ok!(Pallet::create_pool(
4986 RuntimeOrigin::signed(MIKE),
4987 index_digest.clone(),
4988 commission
4989 ));
4990
4991 let pool_digest = assert_pool_created_and_get_digest();
4992
4993 assert_ok!(CommitAdapter::pool_exists(&pool_reason, &pool_digest));
4994
4995 let actual_commison =
4996 CommitAdapter::get_commission(&pool_reason, &pool_digest).unwrap();
4997 assert_eq!(actual_commison, commission);
4998
4999 let new_commission = Perbill::from_percent(5);
5000 System::set_block_number(20);
5001 Pallet::update_commission(RuntimeOrigin::signed(MIKE), index_digest, new_commission)
5002 .unwrap();
5003
5004 let new_pool_digest = assert_pool_created_and_get_digest();
5005
5006 #[cfg(feature = "dev")]
5007 {
5008 let slots = CommitAdapter::get_slots_shares(&pool_reason, &new_pool_digest).unwrap();
5009 System::assert_last_event(
5010 Event::PoolCreated {
5011 pool: new_pool_digest.clone(),
5012 manager: MIKE,
5013 commission: new_commission,
5014 #[cfg(feature = "dev")]
5015 slots: slots,
5016 }
5017 .into(),
5018 );
5019 }
5020
5021 #[cfg(not(feature = "dev"))]
5022 {
5023 System::assert_last_event(
5024 Event::PoolCreated {
5025 pool: new_pool_digest.clone(),
5026 manager: MIKE,
5027 commission: new_commission,
5028 }
5029 .into(),
5030 );
5031 }
5032
5033 let actual_commison =
5034 CommitAdapter::get_commission(&pool_reason, &new_pool_digest).unwrap();
5035 assert_eq!(actual_commison, new_commission);
5036 })
5037 }
5038
5039 #[test]
5040 fn update_entry_shares_success() {
5041 authors_test_ext().execute_with(|| {
5042 initiate_key_and_set_balance_and_hold(&ALICE, 500, 500).unwrap();
5043 initiate_key_and_set_balance_and_hold(&BOB, 500, 500).unwrap();
5044 initiate_key_and_set_balance_and_hold(&CHARLIE, 500, 500).unwrap();
5045 initiate_key_and_set_balance_and_hold(&MIKE, 500, 500).unwrap();
5046 initiate_key_and_set_balance_and_hold(&ALAN, 500, 500).unwrap();
5047 initiate_key_and_set_balance_and_hold(&NIX, 500, 500).unwrap();
5048
5049 Pallet::enroll(&ALICE, 250, Fortitude::Force).unwrap();
5050 Pallet::enroll(&BOB, 300, Fortitude::Force).unwrap();
5051
5052 Pallet::fund(
5053 &ALICE,
5054 &Funder::Direct(ALAN),
5055 100,
5056 Precision::Exact,
5057 Fortitude::Force,
5058 )
5059 .unwrap();
5060
5061 Pallet::fund(
5062 &BOB,
5063 &Funder::Direct(CHARLIE),
5064 200,
5065 Precision::Exact,
5066 Fortitude::Force,
5067 )
5068 .unwrap();
5069
5070 let entries = vec![(ALICE, 100), (BOB, 100)];
5071
5072 System::set_block_number(10);
5073 assert_ok!(Pallet::create_index(
5074 RuntimeOrigin::signed(MIKE),
5075 entries.clone()
5076 ));
5077
5078 let index_digest = assert_index_created_and_get_digest();
5079
5080 let index_reason = FreezeReason::AuthorFunding.into();
5081 assert_ok!(CommitAdapter::index_exists(&index_reason, &index_digest));
5082
5083 let author_reason = FreezeReason::AuthorCollateral.into();
5084 let alice_digest = CommitAdapter::get_commit_digest(&ALICE, &author_reason).unwrap();
5085 let bob_digest = CommitAdapter::get_commit_digest(&BOB, &author_reason).unwrap();
5086
5087 let index_info = CommitAdapter::get_index(&index_reason, &index_digest).unwrap();
5088 assert_eq!(index_info.capital(), 200);
5089 let mut actual_entries_and_shares =
5090 CommitAdapter::get_entries_shares(&index_reason, &index_digest).unwrap();
5091 let mut expected_entries_and_shares =
5092 vec![(alice_digest.clone(), 100), (bob_digest.clone(), 100)];
5093 actual_entries_and_shares.sort();
5094 expected_entries_and_shares.sort();
5095 assert_eq!(
5096 actual_entries_and_shares,
5097 expected_entries_and_shares
5098 );
5099
5100 let new_alice_shares = 25;
5101 assert_ok!(Pallet::update_entry_shares(
5102 RuntimeOrigin::signed(MIKE),
5103 index_digest,
5104 alice_digest.clone(),
5105 new_alice_shares,
5106 ));
5107
5108 let new_index_digest = assert_index_created_and_get_digest();
5109
5110 let index_info = CommitAdapter::get_index(&index_reason, &new_index_digest).unwrap();
5111 assert_eq!(index_info.capital(), 125);
5112 let mut actual_entries_and_shares =
5113 CommitAdapter::get_entries_shares(&index_reason, &new_index_digest).unwrap();
5114 let mut expected_entries_and_shares =
5115 vec![(alice_digest.clone(), 25), (bob_digest.clone(), 100)];
5116 actual_entries_and_shares.sort();
5117 expected_entries_and_shares.sort();
5118 assert_eq!(
5119 actual_entries_and_shares,
5120 expected_entries_and_shares
5121 );
5122
5123 let new_bob_shares = 75;
5124 assert_ok!(Pallet::update_entry_shares(
5125 RuntimeOrigin::signed(MIKE),
5126 new_index_digest.clone(),
5127 bob_digest.clone(),
5128 new_bob_shares,
5129 ));
5130
5131 let new_index_digest = assert_index_created_and_get_digest();
5132
5133 let index_info = CommitAdapter::get_index(&index_reason, &new_index_digest).unwrap();
5134 assert_eq!(index_info.capital(), 100);
5135 let mut actual_entries_and_shares =
5136 CommitAdapter::get_entries_shares(&index_reason, &new_index_digest).unwrap();
5137 let mut expected_entries_and_shares =
5138 vec![(alice_digest.clone(), 25), (bob_digest.clone(), 75)];
5139 actual_entries_and_shares.sort();
5140 expected_entries_and_shares.sort();
5141 assert_eq!(
5142 actual_entries_and_shares,
5143 expected_entries_and_shares
5144 );
5145 })
5146 }
5147
5148 #[test]
5149 fn update_slot_shares_success() {
5150 authors_test_ext().execute_with(|| {
5151 initiate_key_and_set_balance_and_hold(&ALICE, 500, 500).unwrap();
5152 initiate_key_and_set_balance_and_hold(&BOB, 500, 500).unwrap();
5153 initiate_key_and_set_balance_and_hold(&CHARLIE, 500, 500).unwrap();
5154 initiate_key_and_set_balance_and_hold(&MIKE, 500, 500).unwrap();
5155 initiate_key_and_set_balance_and_hold(&ALAN, 500, 500).unwrap();
5156 initiate_key_and_set_balance_and_hold(&NIX, 500, 500).unwrap();
5157
5158 Pallet::enroll(&ALICE, 250, Fortitude::Force).unwrap();
5159 Pallet::enroll(&BOB, 300, Fortitude::Force).unwrap();
5160
5161 Pallet::fund(
5162 &ALICE,
5163 &Funder::Direct(ALAN),
5164 100,
5165 Precision::Exact,
5166 Fortitude::Force,
5167 )
5168 .unwrap();
5169
5170 Pallet::fund(
5171 &BOB,
5172 &Funder::Direct(CHARLIE),
5173 200,
5174 Precision::Exact,
5175 Fortitude::Force,
5176 )
5177 .unwrap();
5178
5179 let entries = vec![(ALICE, 100), (BOB, 100)];
5180
5181 System::set_block_number(10);
5182 assert_ok!(Pallet::create_index(
5183 RuntimeOrigin::signed(MIKE),
5184 entries.clone()
5185 ));
5186
5187 let index_digest = assert_index_created_and_get_digest();
5188
5189 let pool_reason = FreezeReason::AuthorFunding.into();
5190
5191 System::set_block_number(15);
5192 let commission = Perbill::from_percent(10);
5193 assert_ok!(Pallet::create_pool(
5194 RuntimeOrigin::signed(MIKE),
5195 index_digest.clone(),
5196 commission
5197 ));
5198
5199 let pool_digest = assert_pool_created_and_get_digest();
5200
5201 assert_ok!(CommitAdapter::pool_exists(&pool_reason, &pool_digest));
5202
5203 let author_reason = FreezeReason::AuthorCollateral.into();
5204 let alice_digest = CommitAdapter::get_commit_digest(&ALICE, &author_reason).unwrap();
5205 let bob_digest = CommitAdapter::get_commit_digest(&BOB, &author_reason).unwrap();
5206
5207 let pool_info = CommitAdapter::get_pool(&pool_reason, &pool_digest).unwrap();
5208 assert_eq!(pool_info.capital(), 200);
5209 let mut actual_slots_and_shares =
5210 CommitAdapter::get_slots_shares(&pool_reason, &pool_digest).unwrap();
5211 let mut expected_entries_and_shares =
5212 vec![(alice_digest.clone(), 100), (bob_digest.clone(), 100)];
5213 actual_slots_and_shares.sort();
5214 expected_entries_and_shares.sort();
5215 assert_eq!(
5216 actual_slots_and_shares,
5217 expected_entries_and_shares
5218 );
5219
5220 let new_alice_shares = 40;
5221 assert_ok!(Pallet::update_slot_shares(
5222 RuntimeOrigin::signed(MIKE),
5223 pool_digest.clone(),
5224 alice_digest.clone(),
5225 new_alice_shares
5226 ));
5227
5228 let pool_info = CommitAdapter::get_pool(&pool_reason, &pool_digest).unwrap();
5229 assert_eq!(pool_info.capital(), 140);
5230 let mut actual_slots_and_shares =
5231 CommitAdapter::get_slots_shares(&pool_reason, &pool_digest).unwrap();
5232 let mut expected_slots_and_shares =
5233 vec![(alice_digest.clone(), 40), (bob_digest.clone(), 100)];
5234 actual_slots_and_shares.sort();
5235 expected_slots_and_shares.sort();
5236 assert_eq!(
5237 actual_slots_and_shares,
5238 expected_slots_and_shares
5239 );
5240
5241 System::assert_last_event(
5242 Event::PoolSlotShare {
5243 pool: pool_digest.clone(),
5244 slots: (alice_digest.clone(), new_alice_shares),
5245 }
5246 .into(),
5247 );
5248
5249 let new_bob_shares = 60;
5250 assert_ok!(Pallet::update_slot_shares(
5251 RuntimeOrigin::signed(MIKE),
5252 pool_digest.clone(),
5253 bob_digest.clone(),
5254 new_bob_shares
5255 ));
5256
5257 let pool_info = CommitAdapter::get_pool(&pool_reason, &pool_digest).unwrap();
5258 assert_eq!(pool_info.capital(), 100);
5259 let mut actual_slots_and_shares =
5260 CommitAdapter::get_slots_shares(&pool_reason, &pool_digest).unwrap();
5261 let mut expected_slots_and_shares =
5262 vec![(alice_digest.clone(), 40), (bob_digest.clone(), 60)];
5263 actual_slots_and_shares.sort();
5264 expected_slots_and_shares.sort();
5265 assert_eq!(
5266 actual_slots_and_shares,
5267 expected_slots_and_shares
5268 );
5269
5270 System::assert_last_event(
5271 Event::PoolSlotShare {
5272 pool: pool_digest,
5273 slots: (bob_digest, new_bob_shares),
5274 }
5275 .into(),
5276 );
5277 })
5278 }
5279
5280 #[test]
5281 fn update_slot_shares_err_invalid_pool_manager() {
5282 authors_test_ext().execute_with(|| {
5283 initiate_key_and_set_balance_and_hold(&ALICE, 500, 500).unwrap();
5284 initiate_key_and_set_balance_and_hold(&BOB, 500, 500).unwrap();
5285 initiate_key_and_set_balance_and_hold(&CHARLIE, 500, 500).unwrap();
5286 initiate_key_and_set_balance_and_hold(&MIKE, 500, 500).unwrap();
5287 initiate_key_and_set_balance_and_hold(&ALAN, 500, 500).unwrap();
5288 initiate_key_and_set_balance_and_hold(&NIX, 500, 500).unwrap();
5289
5290 Pallet::enroll(&ALICE, 250, Fortitude::Force).unwrap();
5291 Pallet::enroll(&BOB, 300, Fortitude::Force).unwrap();
5292
5293 Pallet::fund(
5294 &ALICE,
5295 &Funder::Direct(ALAN),
5296 100,
5297 Precision::Exact,
5298 Fortitude::Force,
5299 )
5300 .unwrap();
5301
5302 Pallet::fund(
5303 &BOB,
5304 &Funder::Direct(CHARLIE),
5305 200,
5306 Precision::Exact,
5307 Fortitude::Force,
5308 )
5309 .unwrap();
5310
5311 let entries = vec![(ALICE, 100), (BOB, 100)];
5312
5313 System::set_block_number(10);
5314 assert_ok!(Pallet::create_index(
5315 RuntimeOrigin::signed(MIKE),
5316 entries.clone()
5317 ));
5318
5319 let index_digest = assert_index_created_and_get_digest();
5320
5321 let pool_reason = FreezeReason::AuthorFunding.into();
5322
5323 System::set_block_number(15);
5324 let commission = Perbill::from_percent(10);
5325 assert_ok!(Pallet::create_pool(
5326 RuntimeOrigin::signed(MIKE),
5327 index_digest.clone(),
5328 commission
5329 ));
5330
5331 let pool_digest = assert_pool_created_and_get_digest();
5332
5333 assert_ok!(CommitAdapter::pool_exists(&pool_reason, &pool_digest));
5334
5335 let author_reason = FreezeReason::AuthorCollateral.into();
5336 let alice_digest = CommitAdapter::get_commit_digest(&ALICE, &author_reason).unwrap();
5337 let bob_digest = CommitAdapter::get_commit_digest(&BOB, &author_reason).unwrap();
5338
5339 let pool_info = CommitAdapter::get_pool(&pool_reason, &pool_digest).unwrap();
5340 assert_eq!(pool_info.capital(), 200);
5341 let mut actual_slots_and_shares =
5342 CommitAdapter::get_slots_shares(&pool_reason, &pool_digest).unwrap();
5343 let mut expected_entries_and_shares =
5344 vec![(alice_digest.clone(), 100), (bob_digest.clone(), 100)];
5345 actual_slots_and_shares.sort();
5346 expected_entries_and_shares.sort();
5347 assert_eq!(
5348 actual_slots_and_shares,
5349 expected_entries_and_shares
5350 );
5351
5352 let new_alice_shares = 40;
5353 assert_err!(
5354 Pallet::update_slot_shares(
5355 RuntimeOrigin::signed(CHARLIE),
5356 pool_digest.clone(),
5357 alice_digest.clone(),
5358 new_alice_shares
5359 ),
5360 Error::InvalidPoolManager
5361 );
5362 })
5363 }
5364
5365 #[cfg(feature = "dev")]
5366 #[test]
5367 fn check_direct_funds_towards_author_success() {
5368 authors_test_ext().execute_with(|| {
5369 initiate_key_and_set_balance_and_hold(&ALICE, 500, 500).unwrap();
5370 initiate_key_and_set_balance_and_hold(&BOB, 500, 500).unwrap();
5371
5372 Pallet::enroll(&ALICE, 350, Fortitude::Force).unwrap();
5373
5374 Pallet::fund(
5375 &ALICE,
5376 &Funder::Direct(BOB),
5377 250,
5378 Precision::Exact,
5379 Fortitude::Force,
5380 )
5381 .unwrap();
5382
5383 System::set_block_number(10);
5384 Pallet::my_author_fund(
5385 RuntimeOrigin::signed(BOB),
5386 ALICE,
5387 FundingTarget::Direct(ALICE),
5388 )
5389 .unwrap();
5390
5391 System::assert_last_event(
5392 Event::InspectFund {
5393 author: ALICE,
5394 funder: Funder::Direct(BOB),
5395 amount: 250,
5396 }
5397 .into(),
5398 );
5399 })
5400 }
5401
5402 #[test]
5407 fn fetch_collateral_success() {
5408 authors_test_ext().execute_with(|| {
5409 initiate_key_and_set_balance_and_hold(&ALICE, 500, 500).unwrap();
5410 initiate_key_and_set_balance_and_hold(&BOB, 500, 500).unwrap();
5411
5412 Pallet::enroll(&ALICE, 135, Fortitude::Force).unwrap();
5413 Pallet::enroll(&BOB, 425, Fortitude::Force).unwrap();
5414
5415 let alice_collateral = Pallet::fetch_collateral(ALICE).unwrap();
5416 let bob_collateral = Pallet::fetch_collateral(BOB).unwrap();
5417
5418 assert_eq!(alice_collateral, 135);
5419 assert_eq!(bob_collateral, 425);
5420 })
5421 }
5422
5423 #[test]
5424 fn inspect_fund_direct_success() {
5425 authors_test_ext().execute_with(|| {
5426 initiate_key_and_set_balance_and_hold(&ALICE, INITIAL_BALANCE, STANDARD_HOLD).unwrap();
5427 initiate_key_and_set_balance_and_hold(&CHARLIE, INITIAL_BALANCE, STANDARD_HOLD)
5428 .unwrap();
5429
5430 System::set_block_number(10);
5431 Pallet::enroll(&ALICE, 100, Fortitude::Force).unwrap();
5432
5433 System::set_block_number(20);
5434 assert_ok!(Pallet::back(
5435 RuntimeOrigin::signed(CHARLIE),
5436 FundingTarget::Direct(ALICE),
5437 100,
5438 FortitudeWrapper::Force,
5439 PrecisionWrapper::Exact
5440 ));
5441
5442 let current_hold = Pallet::get_hold(&ALICE).unwrap();
5443 assert_eq!(current_hold, 200);
5444 let backed_value = Pallet::backed_value(&ALICE).unwrap();
5445 assert_eq!(backed_value, 100);
5446 let backers_of = Pallet::backers_of(&ALICE).unwrap();
5447 assert_eq!(backers_of, vec![(Funder::Direct(CHARLIE), 100)]);
5448
5449 System::set_block_number(25);
5450 let fund = Pallet::inspect_fund(CHARLIE, FundingTarget::Direct(ALICE)).unwrap();
5451 assert_eq!(fund, 100);
5452 })
5453 }
5454
5455 #[test]
5456 fn inspect_fund_towards_index_success() {
5457 authors_test_ext().execute_with(|| {
5458 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5459 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
5460 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
5461 initiate_key_and_set_balance_and_hold(&MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
5462 initiate_key_and_set_balance_and_hold(&ALAN, LARGE_VALUE, LARGE_VALUE).unwrap();
5463 initiate_key_and_set_balance_and_hold(&NIX, LARGE_VALUE, LARGE_VALUE).unwrap();
5464
5465 System::set_block_number(6);
5466 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5467
5468 System::set_block_number(8);
5469 Pallet::fund(
5470 &ALICE,
5471 &Funder::Direct(CHARLIE),
5472 STANDARD_VALUE,
5473 Precision::Exact,
5474 Fortitude::Force,
5475 )
5476 .unwrap();
5477
5478 System::set_block_number(12);
5479 Pallet::enroll(&BOB, STANDARD_VALUE, Fortitude::Force).unwrap();
5480
5481 System::set_block_number(15);
5482 Pallet::fund(
5483 &BOB,
5484 &Funder::Direct(ALAN),
5485 LARGE_VALUE,
5486 Precision::Exact,
5487 Fortitude::Force,
5488 )
5489 .unwrap();
5490
5491 let alice_digest = gen_author_digest(&ALICE).unwrap();
5492 let bob_digest = gen_author_digest(&BOB).unwrap();
5493 let entries = vec![(alice_digest.clone(), 60), (bob_digest.clone(), 40)];
5494
5495 prepare_and_initiate_index(MIKE, FUNDING.into(), &entries, INDEX_DIGEST).unwrap();
5496
5497 let by_mike = Funder::Index {
5498 digest: INDEX_DIGEST,
5499 backer: MIKE,
5500 };
5501
5502 Pallet::fund(
5503 &ALICE,
5504 &by_mike,
5505 LARGE_VALUE,
5506 Precision::Exact,
5507 Fortitude::Force,
5508 )
5509 .unwrap();
5510
5511 let by_nix = Funder::Index {
5512 digest: INDEX_DIGEST,
5513 backer: NIX,
5514 };
5515
5516 Pallet::fund(
5517 &ALICE,
5518 &by_nix,
5519 STANDARD_VALUE,
5520 Precision::Exact,
5521 Fortitude::Force,
5522 )
5523 .unwrap();
5524
5525 System::set_block_number(25);
5526 let mike_alice_fund =
5527 Pallet::inspect_author_fund(MIKE, ALICE, FundingTarget::Index(INDEX_DIGEST))
5528 .unwrap();
5529 assert_eq!(mike_alice_fund, 60);
5530
5531 let mike_bob_fund =
5532 Pallet::inspect_author_fund(MIKE, BOB, FundingTarget::Index(INDEX_DIGEST)).unwrap();
5533 assert_eq!(mike_bob_fund, 40);
5534
5535 let nix_alice_fund =
5536 Pallet::inspect_author_fund(NIX, ALICE, FundingTarget::Index(INDEX_DIGEST))
5537 .unwrap();
5538 assert_eq!(nix_alice_fund, 30);
5539
5540 let nix_bob_fund =
5541 Pallet::inspect_author_fund(NIX, BOB, FundingTarget::Index(INDEX_DIGEST)).unwrap();
5542 assert_eq!(nix_bob_fund, 20);
5543 })
5544 }
5545
5546 #[test]
5547 fn inspect_fund_index_success() {
5548 authors_test_ext().execute_with(|| {
5549 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5550 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
5551 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
5552 initiate_key_and_set_balance_and_hold(&MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
5553 initiate_key_and_set_balance_and_hold(&ALAN, LARGE_VALUE, LARGE_VALUE).unwrap();
5554 initiate_key_and_set_balance_and_hold(&NIX, LARGE_VALUE, LARGE_VALUE).unwrap();
5555
5556 System::set_block_number(6);
5557 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5558
5559 System::set_block_number(8);
5560 Pallet::fund(
5561 &ALICE,
5562 &Funder::Direct(CHARLIE),
5563 STANDARD_VALUE,
5564 Precision::Exact,
5565 Fortitude::Force,
5566 )
5567 .unwrap();
5568
5569 System::set_block_number(12);
5570 Pallet::enroll(&BOB, STANDARD_VALUE, Fortitude::Force).unwrap();
5571
5572 System::set_block_number(15);
5573 Pallet::fund(
5574 &BOB,
5575 &Funder::Direct(ALAN),
5576 LARGE_VALUE,
5577 Precision::Exact,
5578 Fortitude::Force,
5579 )
5580 .unwrap();
5581
5582 let alice_digest = gen_author_digest(&ALICE).unwrap();
5583 let bob_digest = gen_author_digest(&BOB).unwrap();
5584 let entries = vec![(alice_digest.clone(), 60), (bob_digest.clone(), 40)];
5585
5586 prepare_and_initiate_index(MIKE, FUNDING.into(), &entries, INDEX_DIGEST).unwrap();
5587
5588 let by_mike = Funder::Index {
5589 digest: INDEX_DIGEST,
5590 backer: MIKE,
5591 };
5592
5593 Pallet::fund(
5594 &ALICE,
5595 &by_mike,
5596 LARGE_VALUE,
5597 Precision::Exact,
5598 Fortitude::Force,
5599 )
5600 .unwrap();
5601
5602 let by_nix = Funder::Index {
5603 digest: INDEX_DIGEST,
5604 backer: NIX,
5605 };
5606
5607 Pallet::fund(
5608 &ALICE,
5609 &by_nix,
5610 STANDARD_VALUE,
5611 Precision::Exact,
5612 Fortitude::Force,
5613 )
5614 .unwrap();
5615
5616 let mike_index_fund =
5617 Pallet::inspect_fund(MIKE, FundingTarget::Index(INDEX_DIGEST)).unwrap();
5618 assert_eq!(mike_index_fund, 100);
5619
5620 let nix_index_fund =
5621 Pallet::inspect_fund(NIX, FundingTarget::Index(INDEX_DIGEST)).unwrap();
5622 assert_eq!(nix_index_fund, 50);
5623 })
5624 }
5625
5626 #[test]
5627 fn inspect_fund_towards_pool_success() {
5628 authors_test_ext().execute_with(|| {
5629 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5630 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
5631 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
5632 initiate_key_and_set_balance_and_hold(&MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
5633 initiate_key_and_set_balance_and_hold(&ALAN, LARGE_VALUE, LARGE_VALUE).unwrap();
5634 initiate_key_and_set_balance_and_hold(&NIX, LARGE_VALUE, LARGE_VALUE).unwrap();
5635
5636 System::set_block_number(6);
5637 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5638
5639 System::set_block_number(8);
5640 Pallet::fund(
5641 &ALICE,
5642 &Funder::Direct(CHARLIE),
5643 STANDARD_VALUE,
5644 Precision::Exact,
5645 Fortitude::Force,
5646 )
5647 .unwrap();
5648
5649 System::set_block_number(12);
5650 Pallet::enroll(&BOB, STANDARD_VALUE, Fortitude::Force).unwrap();
5651
5652 System::set_block_number(15);
5653 Pallet::fund(
5654 &BOB,
5655 &Funder::Direct(ALAN),
5656 LARGE_VALUE,
5657 Precision::Exact,
5658 Fortitude::Force,
5659 )
5660 .unwrap();
5661
5662 let alice_digest = gen_author_digest(&ALICE).unwrap();
5663 let bob_digest = gen_author_digest(&BOB).unwrap();
5664 let entries = vec![(alice_digest.clone(), 60), (bob_digest.clone(), 40)];
5665
5666 prepare_and_initiate_pool(
5667 ALAN,
5668 FUNDING.into(),
5669 &entries,
5670 INDEX_DIGEST,
5671 POOL_DIGEST,
5672 Perbill::from_percent(5),
5673 )
5674 .unwrap();
5675
5676 let by_mike = Funder::Pool {
5677 digest: POOL_DIGEST,
5678 backer: MIKE,
5679 };
5680
5681 Pallet::fund(
5682 &ALICE,
5683 &by_mike,
5684 LARGE_VALUE,
5685 Precision::Exact,
5686 Fortitude::Force,
5687 )
5688 .unwrap();
5689
5690 let by_nix = Funder::Pool {
5691 digest: POOL_DIGEST,
5692 backer: NIX,
5693 };
5694
5695 Pallet::fund(
5696 &ALICE,
5697 &by_nix,
5698 STANDARD_VALUE,
5699 Precision::Exact,
5700 Fortitude::Force,
5701 )
5702 .unwrap();
5703
5704 let mike_alice_fund =
5705 Pallet::inspect_author_fund(MIKE, ALICE, FundingTarget::Pool(POOL_DIGEST)).unwrap();
5706 assert_eq!(mike_alice_fund, 60);
5707
5708 let mike_bob_fund =
5709 Pallet::inspect_author_fund(MIKE, BOB, FundingTarget::Pool(POOL_DIGEST)).unwrap();
5710 assert_eq!(mike_bob_fund, 40);
5711
5712 let nix_alice_fund =
5713 Pallet::inspect_author_fund(NIX, ALICE, FundingTarget::Pool(POOL_DIGEST)).unwrap();
5714 assert_eq!(nix_alice_fund, 30);
5715
5716 let nix_bob_fund =
5717 Pallet::inspect_author_fund(NIX, BOB, FundingTarget::Pool(POOL_DIGEST)).unwrap();
5718
5719 assert_eq!(nix_bob_fund, 20);
5720 })
5721 }
5722
5723 #[test]
5724 fn inspect_fund_pool_success() {
5725 authors_test_ext().execute_with(|| {
5726 initiate_key_and_set_balance_and_hold(&ALICE, LARGE_VALUE, LARGE_VALUE).unwrap();
5727 initiate_key_and_set_balance_and_hold(&BOB, LARGE_VALUE, LARGE_VALUE).unwrap();
5728 initiate_key_and_set_balance_and_hold(&CHARLIE, LARGE_VALUE, LARGE_VALUE).unwrap();
5729 initiate_key_and_set_balance_and_hold(&MIKE, LARGE_VALUE, LARGE_VALUE).unwrap();
5730 initiate_key_and_set_balance_and_hold(&ALAN, LARGE_VALUE, LARGE_VALUE).unwrap();
5731 initiate_key_and_set_balance_and_hold(&NIX, LARGE_VALUE, LARGE_VALUE).unwrap();
5732
5733 System::set_block_number(6);
5734 Pallet::enroll(&ALICE, STANDARD_VALUE, Fortitude::Force).unwrap();
5735
5736 System::set_block_number(8);
5737 Pallet::fund(
5738 &ALICE,
5739 &Funder::Direct(CHARLIE),
5740 STANDARD_VALUE,
5741 Precision::Exact,
5742 Fortitude::Force,
5743 )
5744 .unwrap();
5745
5746 System::set_block_number(12);
5747 Pallet::enroll(&BOB, STANDARD_VALUE, Fortitude::Force).unwrap();
5748
5749 System::set_block_number(15);
5750 Pallet::fund(
5751 &BOB,
5752 &Funder::Direct(ALAN),
5753 LARGE_VALUE,
5754 Precision::Exact,
5755 Fortitude::Force,
5756 )
5757 .unwrap();
5758
5759 let alice_digest = gen_author_digest(&ALICE).unwrap();
5760 let bob_digest = gen_author_digest(&BOB).unwrap();
5761 let entries = vec![(alice_digest.clone(), 60), (bob_digest.clone(), 40)];
5762
5763 prepare_and_initiate_pool(
5764 ALAN,
5765 FUNDING.into(),
5766 &entries,
5767 INDEX_DIGEST,
5768 POOL_DIGEST,
5769 Perbill::from_percent(5),
5770 )
5771 .unwrap();
5772
5773 let by_mike = Funder::Pool {
5774 digest: POOL_DIGEST,
5775 backer: MIKE,
5776 };
5777
5778 Pallet::fund(
5779 &ALICE,
5780 &by_mike,
5781 LARGE_VALUE,
5782 Precision::Exact,
5783 Fortitude::Force,
5784 )
5785 .unwrap();
5786
5787 let by_nix = Funder::Pool {
5788 digest: POOL_DIGEST,
5789 backer: NIX,
5790 };
5791
5792 Pallet::fund(
5793 &ALICE,
5794 &by_nix,
5795 STANDARD_VALUE,
5796 Precision::Exact,
5797 Fortitude::Force,
5798 )
5799 .unwrap();
5800
5801 let mike_fund = Pallet::inspect_fund(MIKE, FundingTarget::Pool(POOL_DIGEST)).unwrap();
5802 assert_eq!(mike_fund, 100);
5803
5804 let nix_fund = Pallet::inspect_fund(NIX, FundingTarget::Pool(POOL_DIGEST)).unwrap();
5805 assert_eq!(nix_fund, 50);
5806 })
5807 }
5808}