diff --git a/pallets/funding/src/functions/1_application.rs b/pallets/funding/src/functions/1_application.rs index d38035fca..46470edce 100644 --- a/pallets/funding/src/functions/1_application.rs +++ b/pallets/funding/src/functions/1_application.rs @@ -40,7 +40,7 @@ impl Pallet { evaluation_round_info: EvaluationRoundInfoOf:: { total_bonded_usd: Zero::zero(), total_bonded_plmc: Zero::zero(), - evaluators_outcome: EvaluatorsOutcome::Unchanged, + evaluators_outcome: None, }, usd_bid_on_oversubscription: None, funding_end_block: None, diff --git a/pallets/funding/src/functions/5_funding_end.rs b/pallets/funding/src/functions/5_funding_end.rs index 7e445d9eb..e758a8ac7 100644 --- a/pallets/funding/src/functions/5_funding_end.rs +++ b/pallets/funding/src/functions/5_funding_end.rs @@ -55,24 +55,17 @@ impl Pallet { // * Update Storage * DidWithActiveProjects::::set(issuer_did, None); - let evaluator_outcome = match funding_ratio { - ratio if ratio <= Perquintill::from_percent(75u64) => EvaluatorsOutcome::Slashed, - ratio if ratio < Perquintill::from_percent(90u64) => EvaluatorsOutcome::Unchanged, - _ => { - let reward_info = Self::generate_evaluator_rewards_info(project_id)?; - EvaluatorsOutcome::Rewarded(reward_info) - }, - }; - - project_details.evaluation_round_info.evaluators_outcome = evaluator_outcome; let (next_status, duration, actual_weight) = if funding_ratio <= T::FundingSuccessThreshold::get() { + project_details.evaluation_round_info.evaluators_outcome = Some(EvaluatorsOutcome::Slashed); ( ProjectStatus::FundingFailed, 1u32.into(), WeightInfoOf::::end_funding_automatically_rejected_evaluators_slashed(1), ) } else { + let reward_info = Self::generate_evaluator_rewards_info(project_id)?; + project_details.evaluation_round_info.evaluators_outcome = Some(EvaluatorsOutcome::Rewarded(reward_info)); ( ProjectStatus::FundingSuccessful, T::SuccessToSettlementTime::get(), diff --git a/pallets/funding/src/functions/6_settlement.rs b/pallets/funding/src/functions/6_settlement.rs index d69612482..4013f38fc 100644 --- a/pallets/funding/src/functions/6_settlement.rs +++ b/pallets/funding/src/functions/6_settlement.rs @@ -98,27 +98,24 @@ impl Pallet { Error::::FundingSuccessSettlementNotStarted ); - // Based on the results of the funding round, the evaluator is either: - // 1. Slashed - // 2. Rewarded with CT tokens - // 3. Not slashed or Rewarded. - let (bond, reward): (BalanceOf, BalanceOf) = - match project_details.evaluation_round_info.evaluators_outcome { - EvaluatorsOutcome::Slashed => (Self::slash_evaluator(project_id, &evaluation)?, Zero::zero()), - EvaluatorsOutcome::Rewarded(info) => Self::reward_evaluator(project_id, &evaluation, &info)?, - EvaluatorsOutcome::Unchanged => (evaluation.current_plmc_bond, Zero::zero()), - }; + let Some(EvaluatorsOutcome::Rewarded(reward_info)) = project_details.evaluation_round_info.evaluators_outcome + else { + return Err(Error::::ImpossibleState.into()); + }; + + let (plmc_bond, ct_reward): (BalanceOf, BalanceOf) = + Self::reward_evaluator(project_id, &evaluation, &reward_info)?; // Release the held PLMC bond T::NativeCurrency::release( &HoldReason::Evaluation(project_id).into(), &evaluation.evaluator, - bond, + plmc_bond, Precision::Exact, )?; // Create Migration - if reward > Zero::zero() { + if ct_reward > Zero::zero() { let multiplier = MultiplierOf::::try_from(1u8).map_err(|_| Error::::BadMath)?; let duration = multiplier.calculate_vesting_duration::(); Self::create_migration( @@ -126,7 +123,7 @@ impl Pallet { &evaluation.evaluator, evaluation.id, ParticipationType::Evaluation, - reward, + ct_reward, duration, )?; } @@ -136,8 +133,8 @@ impl Pallet { project_id, account: evaluation.evaluator, id: evaluation.id, - ct_amount: reward, - slashed_plmc_amount: evaluation.current_plmc_bond.saturating_sub(bond), + ct_amount: ct_reward, + slashed_plmc_amount: evaluation.current_plmc_bond.saturating_sub(plmc_bond), }); Ok(()) @@ -150,17 +147,18 @@ impl Pallet { Error::::FundingFailedSettlementNotStarted ); - let bond = if matches!(project_details.evaluation_round_info.evaluators_outcome, EvaluatorsOutcome::Slashed) { - Self::slash_evaluator(project_id, &evaluation)? - } else { - evaluation.current_plmc_bond - }; + ensure!( + project_details.evaluation_round_info.evaluators_outcome == Some(EvaluatorsOutcome::Slashed), + Error::::ImpossibleState + ); + + let plmc_bond_released = Self::slash_evaluator(project_id, &evaluation)?; // Release the held PLMC bond T::NativeCurrency::release( &HoldReason::Evaluation(project_id).into(), &evaluation.evaluator, - bond, + plmc_bond_released, Precision::Exact, )?; @@ -171,7 +169,7 @@ impl Pallet { account: evaluation.evaluator, id: evaluation.id, ct_amount: Zero::zero(), - slashed_plmc_amount: evaluation.current_plmc_bond.saturating_sub(bond), + slashed_plmc_amount: evaluation.current_plmc_bond.saturating_sub(plmc_bond_released), }); Ok(()) diff --git a/pallets/funding/src/runtime_api.rs b/pallets/funding/src/runtime_api.rs index 4d56fa1f1..b3627a544 100644 --- a/pallets/funding/src/runtime_api.rs +++ b/pallets/funding/src/runtime_api.rs @@ -61,24 +61,21 @@ sp_api::decl_runtime_apis! { } impl Pallet { - pub fn top_evaluations -(project_id: ProjectId, amount: u32) -> Vec> { + pub fn top_evaluations(project_id: ProjectId, amount: u32) -> Vec> { Evaluations::::iter_prefix_values((project_id,)) .sorted_by(|a, b| b.original_plmc_bond.cmp(&a.original_plmc_bond)) .take(amount as usize) .collect_vec() } - pub fn top_bids -(project_id: ProjectId, amount: u32) -> Vec> { + pub fn top_bids(project_id: ProjectId, amount: u32) -> Vec> { Bids::::iter_prefix_values((project_id,)) .sorted_by(|a, b| b.final_ct_amount.cmp(&a.final_ct_amount)) .take(amount as usize) .collect_vec() } - pub fn top_contributions -(project_id: ProjectId, amount: u32) -> Vec> { + pub fn top_contributions(project_id: ProjectId, amount: u32) -> Vec> { Contributions::::iter_prefix_values((project_id,)) .sorted_by(|a, b| b.ct_amount.cmp(&a.ct_amount)) .take(amount as usize) diff --git a/pallets/funding/src/tests/runtime_api.rs b/pallets/funding/src/tests/runtime_api.rs index 462191954..66001f2e9 100644 --- a/pallets/funding/src/tests/runtime_api.rs +++ b/pallets/funding/src/tests/runtime_api.rs @@ -2,8 +2,7 @@ use super::*; use crate::runtime_api::{ExtrinsicHelpers, Leaderboards, ProjectInformation, UserInformation}; #[test] -fn top_evaluations -() { +fn top_evaluations() { let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); let evaluations = vec![ UserToUSDBalance::new(EVALUATOR_1, 500_000 * USD_UNIT), @@ -16,21 +15,18 @@ fn top_evaluations inst.execute(|| { let block_hash = System::block_hash(System::block_number()); - let top_1 = TestRuntime::top_evaluations -(&TestRuntime, block_hash, project_id, 1).unwrap(); + let top_1 = TestRuntime::top_evaluations(&TestRuntime, block_hash, project_id, 1).unwrap(); let evaluator_4_evaluation = Evaluations::::get((project_id, EVALUATOR_4, 3)).unwrap(); assert!(top_1.len() == 1 && top_1[0] == evaluator_4_evaluation); - let top_4_evaluators = TestRuntime::top_evaluations -(&TestRuntime, block_hash, project_id, 4) + let top_4_evaluators = TestRuntime::top_evaluations(&TestRuntime, block_hash, project_id, 4) .unwrap() .into_iter() .map(|evaluation| evaluation.evaluator) .collect_vec(); assert_eq!(top_4_evaluators, vec![EVALUATOR_4, EVALUATOR_1, EVALUATOR_3, EVALUATOR_2]); - let top_6_evaluators = TestRuntime::top_evaluations -(&TestRuntime, block_hash, project_id, 6) + let top_6_evaluators = TestRuntime::top_evaluations(&TestRuntime, block_hash, project_id, 6) .unwrap() .into_iter() .map(|evaluation| evaluation.evaluator) @@ -40,8 +36,7 @@ fn top_evaluations } #[test] -fn top_bids -() { +fn top_bids() { let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); let bids = vec![ (BIDDER_1, 8000 * CT_UNIT).into(), @@ -60,21 +55,18 @@ fn top_bids inst.execute(|| { let block_hash = System::block_hash(System::block_number()); - let top_1 = TestRuntime::top_bids -(&TestRuntime, block_hash, project_id, 1).unwrap(); + let top_1 = TestRuntime::top_bids(&TestRuntime, block_hash, project_id, 1).unwrap(); let bidder_4_evaluation = Bids::::get((project_id, BIDDER_4, 3)).unwrap(); assert!(top_1.len() == 1 && top_1[0] == bidder_4_evaluation); - let top_4_bidders = TestRuntime::top_bids -(&TestRuntime, block_hash, project_id, 4) + let top_4_bidders = TestRuntime::top_bids(&TestRuntime, block_hash, project_id, 4) .unwrap() .into_iter() .map(|evaluation| evaluation.bidder) .collect_vec(); assert_eq!(top_4_bidders, vec![BIDDER_4, BIDDER_1, BIDDER_3, BIDDER_2]); - let top_6_bidders = TestRuntime::top_bids -(&TestRuntime, block_hash, project_id, 6) + let top_6_bidders = TestRuntime::top_bids(&TestRuntime, block_hash, project_id, 6) .unwrap() .into_iter() .map(|evaluation| evaluation.bidder) @@ -84,8 +76,7 @@ fn top_bids } #[test] -fn top_contributions -() { +fn top_contributions() { let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); let community_contributors = vec![(BUYER_1, 8000 * CT_UNIT).into(), (BUYER_2, 501 * CT_UNIT).into(), (BUYER_3, 1200 * CT_UNIT).into()]; @@ -102,21 +93,18 @@ fn top_contributions inst.execute(|| { let block_hash = System::block_hash(System::block_number()); - let top_1 = TestRuntime::top_contributions -(&TestRuntime, block_hash, project_id, 1).unwrap(); + let top_1 = TestRuntime::top_contributions(&TestRuntime, block_hash, project_id, 1).unwrap(); let contributor_4_evaluation = Contributions::::get((project_id, BUYER_4, 3)).unwrap(); assert!(top_1.len() == 1 && top_1[0] == contributor_4_evaluation); - let top_4_contributors = TestRuntime::top_contributions -(&TestRuntime, block_hash, project_id, 4) + let top_4_contributors = TestRuntime::top_contributions(&TestRuntime, block_hash, project_id, 4) .unwrap() .into_iter() .map(|evaluation| evaluation.contributor) .collect_vec(); assert_eq!(top_4_contributors, vec![BUYER_4, BUYER_1, BUYER_3, BUYER_2]); - let top_6_contributors = TestRuntime::top_contributions -(&TestRuntime, block_hash, project_id, 6) + let top_6_contributors = TestRuntime::top_contributions(&TestRuntime, block_hash, project_id, 6) .unwrap() .into_iter() .map(|evaluation| evaluation.contributor) diff --git a/pallets/funding/src/types.rs b/pallets/funding/src/types.rs index ddae6c917..1b2660e2e 100644 --- a/pallets/funding/src/types.rs +++ b/pallets/funding/src/types.rs @@ -791,9 +791,7 @@ pub mod inner_types { /// An enum representing all possible outcomes for a project. #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum ProjectOutcome { - /// 90%+ of the funding target was reached, so the project is successful. FundingSuccessful, - /// 33%- of the funding target was reached, so the project failed. FundingFailed, } @@ -801,22 +799,15 @@ pub mod inner_types { pub struct EvaluationRoundInfo { pub total_bonded_usd: Balance, pub total_bonded_plmc: Balance, - pub evaluators_outcome: EvaluatorsOutcome, + pub evaluators_outcome: Option>, } #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub enum EvaluatorsOutcome { - Unchanged, Rewarded(RewardInfo), Slashed, } - #[derive(Clone, Copy, Encode, Decode, Eq, PartialEq, PartialOrd, Ord, RuntimeDebug, TypeInfo, MaxEncodedLen)] - pub enum RewardOrSlash { - Reward(Balance), - Slash(Balance), - } - #[derive(Default, Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct RewardInfo { // Total "Early Evaluators" rewards amount in Contribution Tokens