diff --git a/pallets/funding/src/benchmarking.rs b/pallets/funding/src/benchmarking.rs index f9b823d3b..03c5b224b 100644 --- a/pallets/funding/src/benchmarking.rs +++ b/pallets/funding/src/benchmarking.rs @@ -1867,7 +1867,10 @@ mod benchmarks { } #[benchmark] - fn end_evaluation_failure() { + fn end_evaluation_failure( + // Insertion attempts in add_to_update_store. Total amount of storage items iterated through in `ProjectsToUpdate`. Leave one free to make the fn succeed + x: Linear<1, { ::MaxProjectsToUpdateInsertionAttempts::get() - 1 }>, + ) { // * setup * let mut inst = BenchInstantiator::::new(None); ::SetPrices::set_prices(); @@ -1911,6 +1914,8 @@ mod benchmarks { // move block manually without calling any hooks, to avoid triggering the transition outside the benchmarking context frame_system::Pallet::::set_block_number(evaluation_end_block + One::one()); + fill_projects_to_update::(x, evaluation_end_block + 2u32.into()); + // Instead of advancing in time for the automatic `do_evaluation_end` call in on_initialize, we call it directly to benchmark it #[block] { diff --git a/pallets/funding/src/functions/2_evaluation.rs b/pallets/funding/src/functions/2_evaluation.rs index b18bb86c9..d757dc364 100644 --- a/pallets/funding/src/functions/2_evaluation.rs +++ b/pallets/funding/src/functions/2_evaluation.rs @@ -148,11 +148,18 @@ impl Pallet { // Unsuccessful path } else { // * Update storage * + project_details.status = ProjectStatus::FundingFailed; ProjectsDetails::::insert(project_id, project_details.clone()); let issuer_did = project_details.issuer_did.clone(); DidWithActiveProjects::::set(issuer_did, None); + let insertion_attempts = + match Self::add_to_update_store(now + One::one(), (&project_id, UpdateType::StartSettlement)) { + Ok(insertions) => insertions, + Err(_insertions) => return Err(Error::::TooManyInsertionAttempts.into()), + }; + // * Emit events * Self::deposit_event( Event::ProjectPhaseTransition { @@ -162,7 +169,7 @@ impl Pallet { .into(), ); return Ok(PostDispatchInfo { - actual_weight: Some(WeightInfoOf::::end_evaluation_failure()), + actual_weight: Some(WeightInfoOf::::end_evaluation_failure(insertion_attempts)), pays_fee: Pays::Yes, }); } diff --git a/pallets/funding/src/functions/6_settlement.rs b/pallets/funding/src/functions/6_settlement.rs index a8de06155..9943b1ed9 100644 --- a/pallets/funding/src/functions/6_settlement.rs +++ b/pallets/funding/src/functions/6_settlement.rs @@ -87,7 +87,8 @@ impl Pallet { pub fn do_settle_successful_evaluation(evaluation: EvaluationInfoOf, project_id: ProjectId) -> DispatchResult { let project_details = ProjectsDetails::::get(project_id).ok_or(Error::::ProjectDetailsNotFound)?; - ensure!(matches!(project_details.status, ProjectStatus::FundingSuccessful), Error::::IncorrectRound); + ensure!(matches!(project_details.funding_end_block, Some(_)), Error::::SettlementNotStarted); + ensure!(matches!(project_details.status, ProjectStatus::FundingSuccessful), Error::::WrongSettlementOutcome); // Based on the results of the funding round, the evaluator is either: // 1. Slashed @@ -136,7 +137,8 @@ impl Pallet { pub fn do_settle_failed_evaluation(evaluation: EvaluationInfoOf, project_id: ProjectId) -> DispatchResult { let project_details = ProjectsDetails::::get(project_id).ok_or(Error::::ProjectDetailsNotFound)?; - ensure!(matches!(project_details.status, ProjectStatus::FundingFailed), Error::::IncorrectRound); + ensure!(matches!(project_details.funding_end_block, Some(_)), Error::::SettlementNotStarted); + ensure!(matches!(project_details.status, ProjectStatus::FundingFailed), Error::::WrongSettlementOutcome); let bond = if matches!(project_details.evaluation_round_info.evaluators_outcome, EvaluatorsOutcome::Slashed) { Self::slash_evaluator(project_id, &evaluation)? @@ -169,7 +171,8 @@ impl Pallet { let project_metadata = ProjectsMetadata::::get(project_id).ok_or(Error::::ProjectMetadataNotFound)?; let project_details = ProjectsDetails::::get(project_id).ok_or(Error::::ProjectDetailsNotFound)?; - ensure!(project_details.status == ProjectStatus::FundingSuccessful, Error::::IncorrectRound); + ensure!(matches!(project_details.funding_end_block, Some(_)), Error::::SettlementNotStarted); + ensure!(matches!(project_details.status, ProjectStatus::FundingSuccessful), Error::::WrongSettlementOutcome); ensure!( matches!(bid.status, BidStatus::Accepted | BidStatus::PartiallyAccepted(..)), Error::::ImpossibleState @@ -231,7 +234,8 @@ impl Pallet { pub fn do_settle_failed_bid(bid: BidInfoOf, project_id: ProjectId) -> DispatchResult { let project_details = ProjectsDetails::::get(project_id).ok_or(Error::::ProjectDetailsNotFound)?; - ensure!(matches!(project_details.status, ProjectStatus::FundingFailed), Error::::IncorrectRound); + ensure!(matches!(project_details.funding_end_block, Some(_)), Error::::SettlementNotStarted); + ensure!(matches!(project_details.status, ProjectStatus::FundingFailed), Error::::WrongSettlementOutcome); let bidder = bid.bidder; @@ -258,7 +262,8 @@ impl Pallet { // Ensure that: // 1. The project is in the FundingSuccessful state // 2. The contribution token exists - ensure!(project_details.status == ProjectStatus::FundingSuccessful, Error::::IncorrectRound); + ensure!(matches!(project_details.funding_end_block, Some(_)), Error::::SettlementNotStarted); + ensure!(matches!(project_details.status, ProjectStatus::FundingSuccessful), Error::::WrongSettlementOutcome); ensure!(T::ContributionTokenCurrency::asset_exists(project_id), Error::::TooEarlyForRound); let contributor = contribution.contributor; @@ -316,7 +321,8 @@ impl Pallet { pub fn do_settle_failed_contribution(contribution: ContributionInfoOf, project_id: ProjectId) -> DispatchResult { let project_details = ProjectsDetails::::get(project_id).ok_or(Error::::ProjectDetailsNotFound)?; - ensure!(matches!(project_details.status, ProjectStatus::FundingFailed), Error::::IncorrectRound); + ensure!(matches!(project_details.funding_end_block, Some(_)), Error::::SettlementNotStarted); + ensure!(matches!(project_details.status, ProjectStatus::FundingFailed), Error::::WrongSettlementOutcome); // Check if the bidder has a future deposit held let contributor = contribution.contributor; diff --git a/pallets/funding/src/lib.rs b/pallets/funding/src/lib.rs index beb589496..ac87a35b2 100644 --- a/pallets/funding/src/lib.rs +++ b/pallets/funding/src/lib.rs @@ -810,6 +810,10 @@ pub mod pallet { WrongParaId, /// Migration channel is not ready for migrations. ChannelNotReady, + /// Settlement for this project has not yet started. + SettlementNotStarted, + /// Wanted to settle as successful when it failed, or vice versa. + WrongSettlementOutcome, /// User still has participations that need to be settled before migration. ParticipationsNotSettled, } diff --git a/pallets/funding/src/tests/2_evaluation.rs b/pallets/funding/src/tests/2_evaluation.rs index b9be2d43e..39ea18100 100644 --- a/pallets/funding/src/tests/2_evaluation.rs +++ b/pallets/funding/src/tests/2_evaluation.rs @@ -242,7 +242,12 @@ mod round_flow { assert_eq!(inst.get_project_details(project_id).status, ProjectStatus::FundingFailed); - // Check that on_idle has unlocked the failed bonds + // Cannot settle before the settlement starts + inst.settle_project(project_id).expect_err("Settlement should not be possible yet"); + + let settlement_block = inst.get_update_block(project_id, &UpdateType::StartSettlement).unwrap(); + inst.jump_to_block(settlement_block); + inst.settle_project(project_id).unwrap(); inst.do_free_plmc_assertions(expected_evaluator_balances); } @@ -678,6 +683,10 @@ mod evaluate_extrinsic { let treasury_account = ::ProtocolGrowthTreasury::get(); let pre_slash_treasury_balance = inst.get_free_plmc_balance_for(treasury_account); + + let settlement_block = inst.get_update_block(project_id, &UpdateType::StartSettlement).unwrap(); + inst.jump_to_block(settlement_block); + inst.execute(|| { PolimecFunding::settle_failed_evaluation( RuntimeOrigin::signed(EVALUATOR_4), diff --git a/pallets/funding/src/tests/3_auction.rs b/pallets/funding/src/tests/3_auction.rs index 60cb4f09a..18c7518f1 100644 --- a/pallets/funding/src/tests/3_auction.rs +++ b/pallets/funding/src/tests/3_auction.rs @@ -1259,6 +1259,9 @@ mod bid_extrinsic { assert_eq!(bid_held_balance, frozen_amount); assert_eq!(frozen_balance, frozen_amount); + let settlement_block = inst.get_update_block(project_id, &UpdateType::StartSettlement).unwrap(); + inst.jump_to_block(settlement_block); + inst.execute(|| { PolimecFunding::settle_failed_bid(RuntimeOrigin::signed(BIDDER_4), project_id, BIDDER_4, 0).unwrap(); }); diff --git a/pallets/funding/src/tests/4_community.rs b/pallets/funding/src/tests/4_community.rs index 2f066c7e1..f1f68e10f 100644 --- a/pallets/funding/src/tests/4_community.rs +++ b/pallets/funding/src/tests/4_community.rs @@ -909,6 +909,9 @@ mod community_contribute_extrinsic { assert_eq!(bid_held_balance, frozen_amount); assert_eq!(frozen_balance, frozen_amount); + let settlement_block = inst.get_update_block(project_id, &UpdateType::StartSettlement).unwrap(); + inst.jump_to_block(settlement_block); + inst.execute(|| { PolimecFunding::settle_failed_contribution(RuntimeOrigin::signed(BUYER_4), project_id, BUYER_4, 0) .unwrap(); diff --git a/pallets/funding/src/tests/5_remainder.rs b/pallets/funding/src/tests/5_remainder.rs index 6aeebadc9..6cda38c95 100644 --- a/pallets/funding/src/tests/5_remainder.rs +++ b/pallets/funding/src/tests/5_remainder.rs @@ -995,6 +995,9 @@ mod remaining_contribute_extrinsic { }; assert_eq!(account_data, expected_account_data); + let settlement_block = inst.get_update_block(project_id, &UpdateType::StartSettlement).unwrap(); + inst.jump_to_block(settlement_block); + inst.execute(|| { PolimecFunding::settle_failed_contribution(RuntimeOrigin::signed(BUYER_4), project_id, BUYER_4, 0) .unwrap(); diff --git a/pallets/funding/src/tests/6_funding_end.rs b/pallets/funding/src/tests/6_funding_end.rs index d9aa00cd8..5aa2ee480 100644 --- a/pallets/funding/src/tests/6_funding_end.rs +++ b/pallets/funding/src/tests/6_funding_end.rs @@ -8,7 +8,7 @@ mod round_flow { #[test] fn evaluator_slash_is_decided() { - let (mut inst, project_id) = create_project_with_funding_percentage(20, None); + let (mut inst, project_id) = create_project_with_funding_percentage(20, None, true); assert_eq!(inst.get_project_details(project_id).status, ProjectStatus::FundingFailed); assert_eq!( inst.get_project_details(project_id).evaluation_round_info.evaluators_outcome, @@ -19,7 +19,7 @@ mod round_flow { #[test] fn evaluator_unchanged_is_decided() { let (mut inst, project_id) = - create_project_with_funding_percentage(80, Some(FundingOutcomeDecision::AcceptFunding)); + create_project_with_funding_percentage(80, Some(FundingOutcomeDecision::AcceptFunding), true); assert_eq!(inst.get_project_details(project_id).status, ProjectStatus::FundingSuccessful); assert_eq!( inst.get_project_details(project_id).evaluation_round_info.evaluators_outcome, @@ -29,7 +29,7 @@ mod round_flow { #[test] fn evaluator_reward_is_decided() { - let (mut inst, project_id) = create_project_with_funding_percentage(95, None); + let (mut inst, project_id) = create_project_with_funding_percentage(95, None, true); let project_details = inst.get_project_details(project_id); let project_metadata = inst.get_project_metadata(project_id); assert_eq!(project_details.status, ProjectStatus::FundingSuccessful); @@ -85,6 +85,7 @@ mod decide_project_outcome { let _ = create_project_with_funding_percentage( funding_percent, Some(FundingOutcomeDecision::AcceptFunding), + true, ); } } @@ -95,6 +96,7 @@ mod decide_project_outcome { let _ = create_project_with_funding_percentage( funding_percent, Some(FundingOutcomeDecision::RejectFunding), + true, ); } } @@ -102,7 +104,7 @@ mod decide_project_outcome { #[test] fn automatic_fail_less_eq_33_percent() { for funding_percent in (1..=33).step_by(5) { - let _ = create_project_with_funding_percentage(funding_percent, None); + let _ = create_project_with_funding_percentage(funding_percent, None, true); } } @@ -144,7 +146,7 @@ mod decide_project_outcome { #[test] fn automatic_success_bigger_eq_90_percent() { for funding_percent in (90..=100).step_by(2) { - let _ = create_project_with_funding_percentage(funding_percent, None); + let _ = create_project_with_funding_percentage(funding_percent, None, true); } } } diff --git a/pallets/funding/src/tests/7_settlement.rs b/pallets/funding/src/tests/7_settlement.rs index 109ecc3da..9c4bdc498 100644 --- a/pallets/funding/src/tests/7_settlement.rs +++ b/pallets/funding/src/tests/7_settlement.rs @@ -11,7 +11,7 @@ mod round_flow { #[test] fn can_fully_settle_accepted_project() { let percentage = 100u64; - let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None); + let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None, true); let evaluations = inst.get_evaluations(project_id); let bids = inst.get_bids(project_id); let contributions = inst.get_contributions(project_id); @@ -27,7 +27,7 @@ mod round_flow { #[test] fn can_fully_settle_failed_project() { let percentage = 33u64; - let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None); + let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None, true); let evaluations = inst.get_evaluations(project_id); let bids = inst.get_bids(project_id); let contributions = inst.get_contributions(project_id); @@ -54,7 +54,7 @@ mod settle_successful_evaluation_extrinsic { let percentage = 89u64; let (mut inst, project_id) = - create_project_with_funding_percentage(percentage, Some(FundingOutcomeDecision::AcceptFunding)); + create_project_with_funding_percentage(percentage, Some(FundingOutcomeDecision::AcceptFunding), true); let first_evaluation = inst.get_evaluations(project_id).into_iter().next().unwrap(); let evaluator = first_evaluation.evaluator; @@ -80,7 +80,7 @@ mod settle_successful_evaluation_extrinsic { fn evaluation_slashed() { let percentage = 50u64; let (mut inst, project_id) = - create_project_with_funding_percentage(percentage, Some(FundingOutcomeDecision::AcceptFunding)); + create_project_with_funding_percentage(percentage, Some(FundingOutcomeDecision::AcceptFunding), true); let first_evaluation = inst.get_evaluations(project_id).into_iter().next().unwrap(); let evaluator = first_evaluation.evaluator; @@ -227,7 +227,7 @@ mod settle_successful_evaluation_extrinsic { #[test] fn cannot_settle_twice() { let percentage = 100u64; - let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None); + let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None, true); let first_evaluation = inst.get_evaluations(project_id).into_iter().next().unwrap(); inst.execute(|| { @@ -251,9 +251,9 @@ mod settle_successful_evaluation_extrinsic { } #[test] - fn cannot_be_called_in_unexpected_state() { + fn cannot_be_called_on_wrong_outcome() { let percentage = 10u64; - let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None); + let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None, true); let first_evaluation = inst.get_evaluations(project_id).into_iter().next().unwrap(); let evaluator = first_evaluation.evaluator; @@ -266,7 +266,28 @@ mod settle_successful_evaluation_extrinsic { evaluator, first_evaluation.id ), - Error::::IncorrectRound + Error::::WrongSettlementOutcome + ); + }); + } + + #[test] + fn cannot_be_called_before_settlement_started() { + let percentage = 100u64; + let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None, false); + + let first_evaluation = inst.get_evaluations(project_id).into_iter().next().unwrap(); + let evaluator = first_evaluation.evaluator; + + inst.execute(|| { + assert_noop!( + PolimecFunding::settle_successful_evaluation( + RuntimeOrigin::signed(evaluator), + project_id, + evaluator, + first_evaluation.id + ), + Error::::SettlementNotStarted ); }); } @@ -549,7 +570,7 @@ mod settle_successful_bid_extrinsic { #[test] fn cannot_settle_twice() { let percentage = 100u64; - let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None); + let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None, true); let first_bid = inst.get_bids(project_id).into_iter().next().unwrap(); inst.execute(|| { @@ -573,9 +594,29 @@ mod settle_successful_bid_extrinsic { } #[test] - fn cannot_be_called_in_unexpected_state() { + fn cannot_be_called_on_wrong_outcome() { let percentage = 10u64; - let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None); + let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None, true); + + let first_bid = inst.get_bids(project_id).into_iter().next().unwrap(); + let bidder = first_bid.bidder; + inst.execute(|| { + assert_noop!( + crate::Pallet::::settle_successful_bid( + RuntimeOrigin::signed(bidder), + project_id, + bidder, + first_bid.id + ), + Error::::WrongSettlementOutcome + ); + }); + } + + #[test] + fn cannot_be_called_before_settlement_started() { + let percentage = 100u64; + let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None, false); let first_bid = inst.get_bids(project_id).into_iter().next().unwrap(); let bidder = first_bid.bidder; @@ -587,7 +628,7 @@ mod settle_successful_bid_extrinsic { bidder, first_bid.id ), - Error::::IncorrectRound + Error::::SettlementNotStarted ); }); } @@ -818,7 +859,7 @@ mod settle_successful_contribution_extrinsic { #[test] fn cannot_settle_twice() { let percentage = 100u64; - let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None); + let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None, true); let first_contribution = inst.get_contributions(project_id).into_iter().next().unwrap(); inst.execute(|| { @@ -842,10 +883,29 @@ mod settle_successful_contribution_extrinsic { } #[test] - fn cannot_be_called_in_unexpected_state() { + fn cannot_be_called_on_wrong_outcome() { let percentage = 10u64; - let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None); + let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None, true); + + let first_contribution = inst.get_contributions(project_id).into_iter().next().unwrap(); + let contributor = first_contribution.contributor; + inst.execute(|| { + assert_noop!( + crate::Pallet::::settle_successful_contribution( + RuntimeOrigin::signed(contributor), + project_id, + contributor, + first_contribution.id + ), + Error::::WrongSettlementOutcome + ); + }); + } + #[test] + fn cannot_be_called_before_settlement_started() { + let percentage = 100u64; + let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None, false); let first_contribution = inst.get_contributions(project_id).into_iter().next().unwrap(); let contributor = first_contribution.contributor; inst.execute(|| { @@ -856,7 +916,7 @@ mod settle_successful_contribution_extrinsic { contributor, first_contribution.id ), - Error::::IncorrectRound + Error::::SettlementNotStarted ); }); } @@ -876,7 +936,7 @@ mod settle_failed_evaluation_extrinsic { let percentage = 89u64; let (mut inst, project_id) = - create_project_with_funding_percentage(percentage, Some(FundingOutcomeDecision::RejectFunding)); + create_project_with_funding_percentage(percentage, Some(FundingOutcomeDecision::RejectFunding), true); let first_evaluation = inst.get_evaluations(project_id).into_iter().next().unwrap(); let evaluator = first_evaluation.evaluator; @@ -902,7 +962,7 @@ mod settle_failed_evaluation_extrinsic { fn evaluation_slashed() { let percentage = 50u64; let (mut inst, project_id) = - create_project_with_funding_percentage(percentage, Some(FundingOutcomeDecision::RejectFunding)); + create_project_with_funding_percentage(percentage, Some(FundingOutcomeDecision::RejectFunding), true); let first_evaluation = inst.get_evaluations(project_id).into_iter().next().unwrap(); let evaluator = first_evaluation.evaluator; @@ -937,7 +997,7 @@ mod settle_failed_evaluation_extrinsic { #[test] fn cannot_settle_twice() { let percentage = 33u64; - let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None); + let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None, true); let first_evaluation = inst.get_evaluations(project_id).into_iter().next().unwrap(); inst.execute(|| { @@ -961,21 +1021,43 @@ mod settle_failed_evaluation_extrinsic { } #[test] - fn cannot_be_called_in_unexpected_state() { + fn cannot_be_called_on_wrong_outcome() { let percentage = 100u64; - let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None); + let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None, true); let first_evaluation = inst.get_evaluations(project_id).into_iter().next().unwrap(); let evaluator = first_evaluation.evaluator; + inst.execute(|| { assert_noop!( - crate::Pallet::::settle_failed_evaluation( + PolimecFunding::settle_failed_evaluation( + RuntimeOrigin::signed(evaluator), + project_id, + evaluator, + first_evaluation.id + ), + Error::::WrongSettlementOutcome + ); + }); + } + + #[test] + fn cannot_be_called_before_settlement_started() { + let percentage = 10u64; + let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None, false); + + let first_evaluation = inst.get_evaluations(project_id).into_iter().next().unwrap(); + let evaluator = first_evaluation.evaluator; + + inst.execute(|| { + assert_noop!( + PolimecFunding::settle_failed_evaluation( RuntimeOrigin::signed(evaluator), project_id, evaluator, first_evaluation.id ), - Error::::IncorrectRound + Error::::SettlementNotStarted ); }); } @@ -1120,7 +1202,7 @@ mod settle_failed_bid_extrinsic { #[test] fn cannot_settle_twice() { let percentage = 33u64; - let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None); + let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None, true); let first_bid = inst.get_bids(project_id).into_iter().next().unwrap(); inst.execute(|| { @@ -1144,9 +1226,28 @@ mod settle_failed_bid_extrinsic { } #[test] - fn cannot_be_called_in_unexpected_state() { + fn cannot_be_called_on_wrong_outcome() { let percentage = 100u64; - let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None); + let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None, true); + let first_bid = inst.get_bids(project_id).into_iter().next().unwrap(); + let bidder = first_bid.bidder; + inst.execute(|| { + assert_noop!( + crate::Pallet::::settle_failed_bid( + RuntimeOrigin::signed(bidder), + project_id, + bidder, + first_bid.id + ), + Error::::WrongSettlementOutcome + ); + }); + } + + #[test] + fn cannot_be_called_before_settlement_started() { + let percentage = 10u64; + let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None, false); let first_bid = inst.get_bids(project_id).into_iter().next().unwrap(); let bidder = first_bid.bidder; @@ -1158,7 +1259,7 @@ mod settle_failed_bid_extrinsic { bidder, first_bid.id ), - Error::::IncorrectRound + Error::::SettlementNotStarted ); }); } @@ -1367,7 +1468,7 @@ mod settle_failed_contribution_extrinsic { #[test] fn cannot_settle_twice() { let percentage = 33u64; - let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None); + let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None, true); let first_contribution = inst.get_contributions(project_id).into_iter().next().unwrap(); inst.execute(|| { @@ -1391,9 +1492,29 @@ mod settle_failed_contribution_extrinsic { } #[test] - fn cannot_be_called_in_unexpected_state() { + fn cannot_be_called_on_wrong_outcome() { let percentage = 100u64; - let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None); + let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None, true); + + let first_contribution = inst.get_contributions(project_id).into_iter().next().unwrap(); + let contributor = first_contribution.contributor; + inst.execute(|| { + assert_noop!( + crate::Pallet::::settle_failed_contribution( + RuntimeOrigin::signed(contributor), + project_id, + contributor, + first_contribution.id + ), + Error::::WrongSettlementOutcome + ); + }); + } + + #[test] + fn cannot_be_called_before_settlement_started() { + let percentage = 10u64; + let (mut inst, project_id) = create_project_with_funding_percentage(percentage, None, false); let first_contribution = inst.get_contributions(project_id).into_iter().next().unwrap(); let contributor = first_contribution.contributor; @@ -1405,7 +1526,7 @@ mod settle_failed_contribution_extrinsic { contributor, first_contribution.id ), - Error::::IncorrectRound + Error::::SettlementNotStarted ); }); } diff --git a/pallets/funding/src/tests/mod.rs b/pallets/funding/src/tests/mod.rs index 9f57505c4..288923edd 100644 --- a/pallets/funding/src/tests/mod.rs +++ b/pallets/funding/src/tests/mod.rs @@ -371,6 +371,7 @@ pub mod defaults { pub fn create_project_with_funding_percentage( percentage: u64, maybe_decision: Option, + start_settlement: bool, ) -> (MockInstantiator, ProjectId) { let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); let project_metadata = default_project_metadata(ISSUER_1); @@ -414,23 +415,25 @@ pub fn create_project_with_funding_percentage( _ => panic!("unexpected project status"), }; - let settlement_execution = inst.get_update_block(project_id, &UpdateType::StartSettlement).unwrap(); - inst.jump_to_block(settlement_execution); + if start_settlement { + let settlement_execution = inst.get_update_block(project_id, &UpdateType::StartSettlement).unwrap(); + inst.jump_to_block(settlement_execution); - let funding_sucessful = match percentage { - 0..=33 => false, - 34..=89 if matches!(maybe_decision, Some(FundingOutcomeDecision::RejectFunding)) => false, - 34..=89 if matches!(maybe_decision, Some(FundingOutcomeDecision::AcceptFunding)) => true, - 90..=100 => true, - _ => panic!("unexpected percentage"), - }; - - if funding_sucessful { - assert_eq!(inst.get_project_details(project_id).status, ProjectStatus::FundingSuccessful); - inst.test_ct_created_for(project_id); - } else { - assert_eq!(inst.get_project_details(project_id).status, ProjectStatus::FundingFailed); - inst.test_ct_not_created_for(project_id); + let funding_sucessful = match percentage { + 0..=33 => false, + 34..=89 if matches!(maybe_decision, Some(FundingOutcomeDecision::RejectFunding)) => false, + 34..=89 if matches!(maybe_decision, Some(FundingOutcomeDecision::AcceptFunding)) => true, + 90..=100 => true, + _ => panic!("unexpected percentage"), + }; + if funding_sucessful { + assert_eq!(inst.get_project_details(project_id).status, ProjectStatus::FundingSuccessful); + inst.test_ct_created_for(project_id); + } else { + assert_eq!(inst.get_project_details(project_id).status, ProjectStatus::FundingFailed); + inst.test_ct_not_created_for(project_id); + } } + (inst, project_id) } diff --git a/pallets/funding/src/weights.rs b/pallets/funding/src/weights.rs index 8c9b6a2df..7a9f177c7 100644 --- a/pallets/funding/src/weights.rs +++ b/pallets/funding/src/weights.rs @@ -70,7 +70,7 @@ pub trait WeightInfo { fn settle_successful_contribution() -> Weight; fn settle_failed_contribution() -> Weight; fn end_evaluation_success(x: u32, ) -> Weight; - fn end_evaluation_failure() -> Weight; + fn end_evaluation_failure(x: u32, ) -> Weight; fn start_auction_closing_phase(x: u32, ) -> Weight; fn end_auction_closing(x: u32, y: u32, z: u32, ) -> Weight; fn start_community_funding(x: u32, y: u32, z: u32, ) -> Weight; @@ -531,7 +531,7 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Funding::ProjectsDetails` (`max_values`: None, `max_size`: Some(380), added: 2855, mode: `MaxEncodedLen`) /// Storage: `Funding::DidWithActiveProjects` (r:0 w:1) /// Proof: `Funding::DidWithActiveProjects` (`max_values`: None, `max_size`: Some(78), added: 2553, mode: `MaxEncodedLen`) - fn end_evaluation_failure() -> Weight { + fn end_evaluation_failure(_x: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `533` // Estimated: `3845` @@ -1260,7 +1260,7 @@ impl WeightInfo for () { /// Proof: `Funding::ProjectsDetails` (`max_values`: None, `max_size`: Some(380), added: 2855, mode: `MaxEncodedLen`) /// Storage: `Funding::DidWithActiveProjects` (r:0 w:1) /// Proof: `Funding::DidWithActiveProjects` (`max_values`: None, `max_size`: Some(78), added: 2553, mode: `MaxEncodedLen`) - fn end_evaluation_failure() -> Weight { + fn end_evaluation_failure(_x: u32) -> Weight { // Proof Size summary in bytes: // Measured: `533` // Estimated: `3845` diff --git a/runtimes/polimec/src/weights/pallet_funding.rs b/runtimes/polimec/src/weights/pallet_funding.rs index 2de52f98f..a0515d393 100644 --- a/runtimes/polimec/src/weights/pallet_funding.rs +++ b/runtimes/polimec/src/weights/pallet_funding.rs @@ -491,7 +491,7 @@ impl WeightInfo for SubstrateWeight { /// Proof: `Funding::ProjectsDetails` (`max_values`: None, `max_size`: Some(397), added: 2872, mode: `MaxEncodedLen`) /// Storage: `Funding::DidWithActiveProjects` (r:0 w:1) /// Proof: `Funding::DidWithActiveProjects` (`max_values`: None, `max_size`: Some(78), added: 2553, mode: `MaxEncodedLen`) - fn end_evaluation_failure() -> Weight { + fn end_evaluation_failure(_x: u32) -> Weight { // Proof Size summary in bytes: // Measured: `534` // Estimated: `3862`