diff --git a/integration-tests/src/tests/e2e.rs b/integration-tests/src/tests/e2e.rs index 8c30bde56..180045cc5 100644 --- a/integration-tests/src/tests/e2e.rs +++ b/integration-tests/src/tests/e2e.rs @@ -399,6 +399,7 @@ fn funds_raised() { excel_bidders(), excel_contributions(), excel_remainders(), + true, ); inst.execute(|| { @@ -430,6 +431,7 @@ fn ct_minted() { excel_bidders(), excel_contributions(), excel_remainders(), + true, ); for (contributor, expected_amount_fixed, project_id) in excel_ct_amounts() { @@ -456,6 +458,7 @@ fn ct_migrated() { excel_bidders(), excel_contributions(), excel_remainders(), + true, ); for (contributor, expected_amount_fixed, project_id) in excel_ct_amounts() { diff --git a/pallets/funding/src/benchmarking.rs b/pallets/funding/src/benchmarking.rs index 544f634e2..412c25a8a 100644 --- a/pallets/funding/src/benchmarking.rs +++ b/pallets/funding/src/benchmarking.rs @@ -24,9 +24,8 @@ use crate::{ traits::{ProvideAssetPrice, SetPrices}, }; use frame_benchmarking::v2::*; -#[cfg(test)] -use frame_support::assert_ok; use frame_support::{ + assert_ok, dispatch::RawOrigin, traits::{ fungibles::{metadata::MetadataDeposit, Inspect}, @@ -38,7 +37,7 @@ use itertools::Itertools; #[allow(unused_imports)] use pallet::Pallet as PalletFunding; use parity_scale_codec::{Decode, Encode}; -use polimec_common::{credentials::InvestorType, USD_DECIMALS, USD_UNIT}; +use polimec_common::{credentials::InvestorType, ReleaseSchedule, USD_DECIMALS, USD_UNIT}; use polimec_common_test_utils::{generate_did_from_account, get_mock_jwt_with_cid}; use sp_arithmetic::Percent; use sp_core::H256; @@ -290,21 +289,9 @@ pub fn string_account( .expect("infinite length input; no invalid inputs for type; qed") } -// IMPORTANT: make sure your project starts at (block 1 + `total_vecs_in_storage` - `fully_filled_vecs_from_insertion`) to always have room to insert new vecs -pub fn fill_projects_to_update( - fully_filled_vecs_from_insertion: u32, - mut expected_insertion_block: BlockNumberFor, -) { - // fill the `ProjectsToUpdate` vectors from @ expected_insertion_block to @ expected_insertion_block+x, to benchmark all the failed insertion attempts - for _ in 0..fully_filled_vecs_from_insertion { - ProjectsToUpdate::::insert(expected_insertion_block, (&69u32, UpdateType::EvaluationEnd)); - expected_insertion_block += 1u32.into(); - } -} - #[benchmarks( where - T: Config + frame_system::Config::RuntimeEvent> + pallet_balances::Config>, + T: Config + frame_system::Config::RuntimeEvent> + pallet_balances::Config> + std::fmt::Debug, ::RuntimeEvent: TryInto> + Parameter + Member, ::Price: From, ::Balance: From + Into, @@ -317,15 +304,12 @@ mod benchmarks { impl_benchmark_test_suite!(PalletFunding, crate::mock::new_test_ext(), crate::mock::TestRuntime); - // - // Extrinsics - // #[benchmark] fn create_project() { // * setup * let mut inst = BenchInstantiator::::new(None); ::SetPrices::set_prices(); - // real benchmark starts at block 0, and we can't call `events()` at block 0 + // We can't see events at block 0 inst.advance_time(1u32.into()); let ed = inst.get_ed(); @@ -376,7 +360,7 @@ mod benchmarks { // * setup * let mut inst = BenchInstantiator::::new(None); ::SetPrices::set_prices(); - // real benchmark starts at block 0, and we can't call `events()` at block 0 + // We can't see events at block 0 inst.advance_time(1u32.into()); let issuer = account::>("issuer", 0, 0); @@ -409,7 +393,7 @@ mod benchmarks { let mut inst = BenchInstantiator::::new(None); ::SetPrices::set_prices(); - // real benchmark starts at block 0, and we can't call `events()` at block 0 + // We can't see events at block 0 inst.advance_time(1u32.into()); let issuer = account::>("issuer", 0, 0); @@ -505,16 +489,13 @@ mod benchmarks { } #[benchmark] - fn start_evaluation( - // insertion attempts in add_to_update_store. - x: Linear<1, { ::MaxProjectsToUpdateInsertionAttempts::get() - 1 }>, - ) { + fn start_evaluation() { // * setup * let mut inst = BenchInstantiator::::new(None); ::SetPrices::set_prices(); - // real benchmark starts at block 0, and we can't call `events()` at block 0 - inst.advance_time(1u32.into()); + // We can't see events at block 0 + inst.jump_to_block(1u32.into()); let issuer = account::>("issuer", 0, 0); whitelist_account!(issuer); @@ -522,10 +503,6 @@ mod benchmarks { let project_metadata = default_project_metadata::(issuer.clone()); let project_id = inst.create_new_project(project_metadata.clone(), issuer.clone(), None); - // start_evaluation fn will try to add an automatic transition 1 block after the last evaluation block - let block_number: BlockNumberFor = inst.current_block() + T::EvaluationDuration::get() + One::one(); - // fill the `ProjectsToUpdate` vectors from @ block_number to @ block_number+x, to benchmark all the failed insertion attempts - fill_projects_to_update::(x, block_number); let jwt = get_mock_jwt_with_cid( issuer.clone(), InvestorType::Institutional, @@ -542,82 +519,24 @@ mod benchmarks { let starting_evaluation_info = EvaluationRoundInfoOf:: { total_bonded_usd: Zero::zero(), total_bonded_plmc: Zero::zero(), - evaluators_outcome: EvaluatorsOutcome::Unchanged, + evaluators_outcome: None, }; assert_eq!(stored_details.evaluation_round_info, starting_evaluation_info); - let evaluation_transition_points = stored_details.phase_transition_points.evaluation; - match evaluation_transition_points { - BlockNumberPair { start: Some(_), end: Some(_) } => {}, - _ => assert!(false, "Evaluation transition points are not set"), - } - - // Events - frame_system::Pallet::::assert_last_event( - Event::ProjectPhaseTransition { project_id, phase: ProjectPhases::Evaluation }.into(), - ) - } - - #[benchmark] - fn start_auction_manually( - // Insertion attempts in add_to_update_store. Total amount of storage items iterated through in `ProjectsToUpdate`. Leave one free to make the extrinsic pass - x: Linear<1, { ::MaxProjectsToUpdateInsertionAttempts::get() - 1 }>, - ) { - // * setup * - let mut inst = BenchInstantiator::::new(None); - ::SetPrices::set_prices(); - - // We need to leave enough block numbers to fill `ProjectsToUpdate` before our project insertion - let time_advance: u32 = x + 2; - frame_system::Pallet::::set_block_number(time_advance.into()); - - let issuer = account::>("issuer", 0, 0); - whitelist_account!(issuer); - - let project_metadata = default_project_metadata::(issuer.clone()); - let project_id = inst.create_evaluating_project(project_metadata.clone(), issuer.clone(), None); - - let evaluations = default_evaluations(); - let plmc_for_evaluating = inst.calculate_evaluation_plmc_spent(evaluations.clone(), true); - - inst.mint_plmc_to(plmc_for_evaluating); - - inst.advance_time(One::one()); - inst.evaluate_for_users(project_id, evaluations).expect("All evaluations are accepted"); + let evaluation_transition_points = stored_details.round_duration; + let evaluation_start: BlockNumberFor = 1u32.into(); + let evaluation_end = ::EvaluationRoundDuration::get(); - run_blocks_to_execute_next_transition(project_id, UpdateType::EvaluationEnd, &mut inst); - inst.advance_time(1u32.into()); - - assert_eq!(inst.get_project_details(project_id).status, ProjectStatus::AuctionInitializePeriod); - - let current_block = inst.current_block(); - // `do_auction_opening` fn will try to add an automatic transition 1 block after the last opening round block - let insertion_block_number: BlockNumberFor = current_block + T::AuctionOpeningDuration::get(); - - fill_projects_to_update::(x, insertion_block_number); - - let jwt = get_mock_jwt_with_cid( - issuer.clone(), - InvestorType::Institutional, - generate_did_from_account(issuer.clone()), - project_metadata.clone().policy_ipfs_cid.unwrap(), - ); - #[extrinsic_call] - start_auction(RawOrigin::Signed(issuer), jwt, project_id); - - // * validity checks * - // Storage - let stored_details = ProjectsDetails::::get(project_id).unwrap(); - assert_eq!(stored_details.status, ProjectStatus::AuctionOpening); + assert_eq!(evaluation_transition_points.start(), Some(evaluation_start)); + assert_eq!(evaluation_transition_points.end(), Some(evaluation_end)); // Events frame_system::Pallet::::assert_last_event( - Event::::ProjectPhaseTransition { project_id, phase: ProjectPhases::AuctionOpening }.into(), - ); + Event::ProjectPhaseTransition { project_id, phase: ProjectStatus::EvaluationRound }.into(), + ) } - // - We don't know how many iterations it does in storage (i.e "x") #[benchmark] - fn evaluation( + fn evaluate( // How many other evaluations the user did for that same project x: Linear<0, { T::MaxEvaluationsPerUser::get() - 1 }>, ) { @@ -625,8 +544,7 @@ mod benchmarks { let mut inst = BenchInstantiator::::new(None); ::SetPrices::set_prices(); - // real benchmark starts at block 0, and we can't call `events()` at block 0 - inst.advance_time(1u32.into()); + // We can't see events at block 0 inst.advance_time(1u32.into()); let issuer = account::>("issuer", 0, 0); let test_evaluator = account::>("evaluator", 0, 0); @@ -649,8 +567,6 @@ mod benchmarks { inst.mint_plmc_to(plmc_for_existing_evaluations.clone()); inst.mint_plmc_to(plmc_for_extrinsic_evaluation.clone()); - inst.advance_time(One::one()); - // do "x" evaluations for this user inst.evaluate_for_users(project_id, existing_evaluations).expect("All evaluations are accepted"); @@ -664,6 +580,7 @@ mod benchmarks { generate_did_from_account(extrinsic_evaluation.account.clone()), project_metadata.clone().policy_ipfs_cid.unwrap(), ); + #[extrinsic_call] evaluate( RawOrigin::Signed(extrinsic_evaluation.account.clone()), @@ -711,34 +628,115 @@ mod benchmarks { ); } - fn bid_setup( - existing_bids_count: u32, - do_perform_bid_calls: u32, - ) -> ( - BenchInstantiator, - ProjectId, - ProjectMetadataOf, - BidParams, - Option>, - Vec<(BidParams, PriceOf)>, - Vec<(BidParams, PriceOf)>, - BalanceOf, - BalanceOf, - BalanceOf, - BalanceOf, - ) - where - T: Config, - ::Balance: From, - ::Price: From, - T::Hash: From, - ::RuntimeEvent: From>, - { + // There are 2 logic branches in end_evaluation + // 1. If the evaluation round is successful + // 2. If the evaluation round failed + // 2- only differs by having one additional storage write, so we choose to only benchmark and use this one. + #[benchmark] + fn end_evaluation_failure() { + // * setup * + let mut inst = BenchInstantiator::::new(None); + ::SetPrices::set_prices(); + + // We can't see events at block 0 + inst.advance_time(1u32.into()); + + let issuer = account::>("issuer", 0, 0); + whitelist_account!(issuer); + + let project_metadata = default_project_metadata::(issuer.clone()); + let project_id = inst.create_evaluating_project(project_metadata, issuer.clone(), None); + let project_details = inst.get_project_details(project_id); + + let evaluation_usd_target = + ::EvaluationSuccessThreshold::get() * project_details.fundraising_target_usd; + // we only fund 50% of the minimum threshold for the evaluation round, since we want it to fail + let evaluations = vec![ + UserToUSDBalance::new( + account::>("evaluator_1", 0, 0), + (Percent::from_percent(5) * evaluation_usd_target).into(), + ), + UserToUSDBalance::new( + account::>("evaluator_2", 0, 0), + (Percent::from_percent(20) * evaluation_usd_target).into(), + ), + UserToUSDBalance::new( + account::>("evaluator_3", 0, 0), + (Percent::from_percent(25) * evaluation_usd_target).into(), + ), + ]; + let plmc_for_evaluating = inst.calculate_evaluation_plmc_spent(evaluations.clone(), true); + + inst.mint_plmc_to(plmc_for_evaluating); + + inst.advance_time(One::one()); + inst.evaluate_for_users(project_id, evaluations).expect("All evaluations are accepted"); + + let evaluation_end_block = inst.get_project_details(project_id).round_duration.end().unwrap(); + // 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); + + // Instead of advancing in time for the automatic `do_evaluation_end` call in on_initialize, we call it directly to benchmark it + #[block] + { + Pallet::::do_end_evaluation(project_id).unwrap(); + } + + // * validity checks * + let project_details = inst.get_project_details(project_id); + assert_eq!(project_details.status, ProjectStatus::FundingFailed); + } + + #[benchmark] + fn start_auction() { + // * setup * + let mut inst = BenchInstantiator::::new(None); + ::SetPrices::set_prices(); + + // We can't see events at block 0 + inst.advance_time(1u32.into()); + + let issuer = account::>("issuer", 0, 0); + whitelist_account!(issuer); + + let project_metadata = default_project_metadata::(issuer.clone()); + let project_id = inst.create_evaluating_project(project_metadata.clone(), issuer.clone(), None); + + let evaluations = default_evaluations(); + let plmc_for_evaluating = inst.calculate_evaluation_plmc_spent(evaluations.clone(), true); + + inst.mint_plmc_to(plmc_for_evaluating); + + inst.evaluate_for_users(project_id, evaluations).expect("All evaluations are accepted"); + + assert_eq!(inst.go_to_next_state(project_id), ProjectStatus::AuctionInitializePeriod); + + #[extrinsic_call] + start_auction(RawOrigin::Signed(issuer), project_id); + + // * validity checks * + // Storage + let stored_details = ProjectsDetails::::get(project_id).unwrap(); + assert_eq!(stored_details.status, ProjectStatus::AuctionRound); + + // Events + frame_system::Pallet::::assert_last_event( + Event::::ProjectPhaseTransition { project_id, phase: ProjectStatus::AuctionRound }.into(), + ); + } + + #[benchmark] + fn bid( + // amount of already made bids by the same user. Leave 10 bids available to make the extrinsic pass in case y = max (10) + x: Linear<0, { T::MaxBidsPerUser::get() - 10 }>, + // amount of times when `perform_bid` is called (i.e. into how many buckets the bid is spread) + y: Linear<0, 10>, + ) { // * setup * let mut inst = BenchInstantiator::::new(None); ::SetPrices::set_prices(); - // real benchmark starts at block 0, and we can't call `events()` at block 0 + // We can't see events at block 0 inst.advance_time(1u32.into()); let issuer = account::>("issuer", 0, 0); @@ -767,7 +765,7 @@ mod benchmarks { let existing_bid = BidParams::new(bidder.clone(), (50 * CT_UNIT).into(), 5u8, AcceptedFundingAsset::USDT); - let existing_bids = vec![existing_bid; existing_bids_count as usize]; + let existing_bids = vec![existing_bid; x as usize]; let existing_bids_post_bucketing = inst.get_actual_price_charged_for_bucketed_bids(&existing_bids, project_metadata.clone(), None); let plmc_for_existing_bids = inst.calculate_auction_plmc_charged_from_all_bids_made_or_with_bucket( @@ -804,7 +802,7 @@ mod benchmarks { let mut usdt_for_filler_bidder = vec![UserToForeignAssets::::new(new_bidder.clone(), Zero::zero(), AcceptedFundingAsset::USDT.id())]; - if do_perform_bid_calls > 0 { + if y > 0 { let current_bucket = Buckets::::get(project_id).unwrap(); // first lets bring the bucket to almost its limit with another bidder: assert!(new_bidder.clone() != bidder.clone()); @@ -830,7 +828,7 @@ mod benchmarks { let auction_allocation = project_metadata.auction_round_allocation_percentage * project_metadata.total_allocation_size; let bucket_size = Percent::from_percent(10) * auction_allocation; - ct_amount = bucket_size * (do_perform_bid_calls as u128).into(); + ct_amount = bucket_size * (y as u128).into(); usdt_for_filler_bidder = usdt_for_new_bidder; } let extrinsic_bid = BidParams::new(bidder.clone(), ct_amount, 1u8, AcceptedFundingAsset::USDT); @@ -842,7 +840,8 @@ mod benchmarks { project_metadata.clone(), Some(current_bucket), ); - assert_eq!(extrinsic_bids_post_bucketing.len(), (do_perform_bid_calls as usize).max(1usize)); + + assert_eq!(extrinsic_bids_post_bucketing.len(), (y as usize).max(1usize)); let plmc_for_extrinsic_bids: Vec> = inst .calculate_auction_plmc_charged_from_all_bids_made_or_with_bucket( @@ -869,45 +868,28 @@ mod benchmarks { usdt_for_extrinsic_bids.clone(), usdt_for_existing_bids.clone(), usdt_for_filler_bidder.clone(), - ]); + ])[0] + .1; + + let jwt = get_mock_jwt_with_cid( + original_extrinsic_bid.bidder.clone(), + InvestorType::Institutional, + generate_did_from_account(original_extrinsic_bid.bidder.clone()), + project_metadata.clone().policy_ipfs_cid.unwrap(), + ); - ( - inst, + #[extrinsic_call] + bid( + RawOrigin::Signed(original_extrinsic_bid.bidder.clone()), + jwt, project_id, - project_metadata, - original_extrinsic_bid, - maybe_filler_bid, - extrinsic_bids_post_bucketing, - existing_bids_post_bucketing, - total_free_plmc, - total_plmc_participation_bonded, - total_free_usdt, - total_escrow_usdt_locked, - ) - } + original_extrinsic_bid.amount, + original_extrinsic_bid.multiplier, + original_extrinsic_bid.asset, + ); - fn bid_verification( - mut inst: BenchInstantiator, - project_id: ProjectId, - project_metadata: ProjectMetadataOf, - maybe_filler_bid: Option>, - extrinsic_bids_post_bucketing: Vec<(BidParams, PriceOf)>, - existing_bids_post_bucketing: Vec<(BidParams, PriceOf)>, - total_free_plmc: BalanceOf, - total_plmc_bonded: BalanceOf, - total_free_usdt: BalanceOf, - total_usdt_locked: BalanceOf, - ) -> () - where - T: Config, - ::Balance: From, - ::Price: From, - T::Hash: From, - ::RuntimeEvent: From>, - { // * validity checks * - let bidder = extrinsic_bids_post_bucketing[0].0.bidder.clone(); // Storage for (bid_params, price) in extrinsic_bids_post_bucketing.clone() { let bid_filter = BidInfoFilter:: { @@ -917,8 +899,6 @@ mod benchmarks { status: Some(BidStatus::YetUnknown), original_ct_amount: Some(bid_params.amount), original_ct_usd_price: Some(price), - final_ct_amount: Some(bid_params.amount), - final_ct_usd_price: None, funding_asset: Some(AcceptedFundingAsset::USDT), funding_asset_amount_locked: None, multiplier: Some(bid_params.multiplier), @@ -937,7 +917,7 @@ mod benchmarks { let ten_percent_in_price: ::Price = PriceOf::::checked_from_rational(1, 10).unwrap() * project_metadata.minimum_price; - let mut starting_bucket = Bucket::new( + let mut expected_bucket = Bucket::new( project_metadata.auction_round_allocation_percentage * project_metadata.total_allocation_size, project_metadata.minimum_price, ten_percent_in_price, @@ -945,23 +925,23 @@ mod benchmarks { ); for (bid_params, _price_) in existing_bids_post_bucketing.clone() { - starting_bucket.update(bid_params.amount); + expected_bucket.update(bid_params.amount); } if let Some(bid_params) = maybe_filler_bid { - starting_bucket.update(bid_params.amount); + expected_bucket.update(bid_params.amount); } for (bid_params, _price_) in extrinsic_bids_post_bucketing.clone() { - starting_bucket.update(bid_params.amount); + expected_bucket.update(bid_params.amount); } let current_bucket = Buckets::::get(project_id).unwrap(); - assert_eq!(current_bucket, starting_bucket); + assert_eq!(current_bucket, expected_bucket); // Balances let bonded_plmc = inst .get_reserved_plmc_balances_for(vec![bidder.clone()], HoldReason::Participation(project_id).into())[0] .plmc_amount; - assert_eq!(bonded_plmc, total_plmc_bonded); + assert_eq!(bonded_plmc, total_plmc_participation_bonded); let free_plmc = inst.get_free_plmc_balances_for(vec![bidder.clone()])[0].plmc_amount; assert_eq!(free_plmc, total_free_plmc); @@ -969,14 +949,14 @@ mod benchmarks { let escrow_account = Pallet::::fund_account_id(project_id); let locked_usdt = inst.get_free_funding_asset_balances_for(usdt_id(), vec![escrow_account.clone()])[0].asset_amount; - assert_eq!(locked_usdt, total_usdt_locked); + assert_eq!(locked_usdt, total_escrow_usdt_locked); let free_usdt = inst.get_free_funding_asset_balances_for(usdt_id(), vec![bidder])[0].asset_amount; assert_eq!(free_usdt, total_free_usdt); // Events for (bid_params, _price_) in extrinsic_bids_post_bucketing { - find_event! { + let maybe_event = find_event! { T, Event::::Bid { project_id, @@ -986,450 +966,349 @@ mod benchmarks { project_id == project_id, ct_amount == bid_params.amount, multiplier == bid_params.multiplier - } - .expect("Event has to be emitted"); + }; + assert!(maybe_event.is_some(), "Event not found"); } } #[benchmark] - fn bid( - // amount of already made bids by the same user. Leave y::max (10) to make the extrinsic pass - x: Linear<0, { T::MaxBidsPerUser::get() - 10 }>, - // amount of times where `perform_bid` is called (i.e how many buckets) - y: Linear<0, 10>, + fn end_auction( + // Accepted Bids + x: Linear<10, { 25 }>, + // Failed Bids + y: Linear<0, { 8 }>, ) { - let ( - inst, - project_id, - project_metadata, - original_extrinsic_bid, - maybe_filler_bid, - extrinsic_bids_post_bucketing, - existing_bids_post_bucketing, - total_free_plmc, - total_plmc_bonded, - total_free_usdt, - total_usdt_locked, - ) = bid_setup::(x, y); - - let jwt = get_mock_jwt_with_cid( - original_extrinsic_bid.bidder.clone(), - InvestorType::Institutional, - generate_did_from_account(original_extrinsic_bid.bidder.clone()), - project_metadata.clone().policy_ipfs_cid.unwrap(), - ); - #[extrinsic_call] - bid( - RawOrigin::Signed(original_extrinsic_bid.bidder.clone()), - jwt, - project_id, - original_extrinsic_bid.amount, - original_extrinsic_bid.multiplier, - original_extrinsic_bid.asset, - ); - - bid_verification::( - inst, - project_id, - project_metadata, - maybe_filler_bid, - extrinsic_bids_post_bucketing, - existing_bids_post_bucketing, - total_free_plmc, - total_plmc_bonded, - total_free_usdt, - total_usdt_locked, - ); - } - - fn contribution_setup( - x: u32, - ends_round: Option, - ) -> ( - BenchInstantiator, - ProjectId, - ProjectMetadataOf, - ContributionParams, - BalanceOf, - BalanceOf, - BalanceOf, - BalanceOf, - BalanceOf, - ) - where - T: Config, - ::Balance: From, - ::Price: From, - T::Hash: From, - ::RuntimeEvent: From>, - { - // setup + // * setup * let mut inst = BenchInstantiator::::new(None); ::SetPrices::set_prices(); - - // We need to leave enough block numbers to fill `ProjectsToUpdate` before our project insertion - let mut time_advance: u32 = 1; - if let Some(y) = ends_round { - time_advance += y + 1; - } - frame_system::Pallet::::set_block_number(time_advance.into()); + // We can't see events at block 0 + inst.jump_to_block(1u32.into()); let issuer = account::>("issuer", 0, 0); - let contributor = account::>("contributor", 0, 0); - whitelist_account!(contributor); + whitelist_account!(issuer); - let project_metadata = default_project_metadata::(issuer.clone()); + let mut project_metadata = default_project_metadata::(issuer.clone()); + project_metadata.mainnet_token_max_supply = + BalanceOf::::try_from(10_000_000 * CT_UNIT).unwrap_or_else(|_| panic!("Failed to create BalanceOf")); + project_metadata.total_allocation_size = + BalanceOf::::try_from(10_000_000 * CT_UNIT).unwrap_or_else(|_| panic!("Failed to create BalanceOf")); + project_metadata.auction_round_allocation_percentage = Percent::from_percent(100u8); - let project_id = inst.create_community_contributing_project( + let project_id = inst.create_auctioning_project( project_metadata.clone(), - issuer, + issuer.clone(), None, - default_evaluations::(), - full_bids::(), + inst.generate_successful_evaluations( + project_metadata.clone(), + default_evaluators::(), + default_weights(), + ), ); + let expected_remainder_round_block = inst.remainder_round_block() - One::one(); - let price = inst.get_project_details(project_id).weighted_average_price.unwrap(); + let mut all_bids = Vec::new(); + + let auction_allocation = + project_metadata.auction_round_allocation_percentage * project_metadata.total_allocation_size; + let min_bid_amount = 500u128; + + // These bids will always be rejected, and will be made after the first bucket bid + let rejected_bids = (0..y.saturating_sub(1)) + .map(|i| { + BidParams::::new( + account::>("bidder", 0, i), + (min_bid_amount * CT_UNIT).into(), + 1u8, + AcceptedFundingAsset::USDT, + ) + }) + .collect_vec(); + all_bids.extend(rejected_bids.clone()); + + let already_accepted_bids_count = if y > 0 { + // This one needs to fill the remaining with the bucket, so that all "accepted" bids will take the CT from a rejected one + let last_rejected_bid = BidParams::::new( + account::>("bidder", 0, 420), + auction_allocation - (min_bid_amount * CT_UNIT * (y as u128 - 1u128)).into(), + 1u8, + AcceptedFundingAsset::USDT, + ); + all_bids.push(last_rejected_bid.clone()); + + // We first need to invalidate all rejected bids. + // We do it by placing a bid of the whole auction allocation, i.e. 10 new bids + let allocation_bid = BidParams::::new( + account::>("bidder", 0, y), + auction_allocation, + 1u8, + AcceptedFundingAsset::USDT, + ); + all_bids.push(allocation_bid); - let existing_amount: BalanceOf = (50 * CT_UNIT).into(); - let extrinsic_amount: BalanceOf = if ends_round.is_some() { - project_metadata.auction_round_allocation_percentage * project_metadata.total_allocation_size - - existing_amount * (x.min(::MaxContributionsPerUser::get() - 1) as u128).into() + 10 } else { - (100 * CT_UNIT).into() + 0 }; - let existing_contribution = - ContributionParams::new(contributor.clone(), existing_amount, 1u8, AcceptedFundingAsset::USDT); - let extrinsic_contribution = - ContributionParams::new(contributor.clone(), extrinsic_amount, 1u8, AcceptedFundingAsset::USDT); - let existing_contributions = vec![existing_contribution; x as usize]; - - let mut total_ct_sold: BalanceOf = existing_amount * (x as u128).into() + extrinsic_amount; - - let plmc_for_existing_contributions = - inst.calculate_contributed_plmc_spent(existing_contributions.clone(), price, false); - let plmc_for_extrinsic_contribution = - inst.calculate_contributed_plmc_spent(vec![extrinsic_contribution.clone()], price, false); - let usdt_for_existing_contributions = - inst.calculate_contributed_funding_asset_spent(existing_contributions.clone(), price); - let usdt_for_extrinsic_contribution = - inst.calculate_contributed_funding_asset_spent(vec![extrinsic_contribution.clone()], price); - - let existential_deposits: Vec> = - plmc_for_extrinsic_contribution.accounts().existential_deposits(); - - let escrow_account = Pallet::::fund_account_id(project_id); - let prev_total_usdt_locked = inst.get_free_funding_asset_balances_for(usdt_id(), vec![escrow_account.clone()]); - inst.mint_plmc_to(plmc_for_existing_contributions.clone()); - inst.mint_plmc_to(plmc_for_extrinsic_contribution.clone()); - inst.mint_plmc_to(existential_deposits.clone()); - inst.mint_funding_asset_to(usdt_for_existing_contributions.clone()); - inst.mint_funding_asset_to(usdt_for_extrinsic_contribution.clone()); + let accepted_bids = (0..x.saturating_sub(already_accepted_bids_count)) + .map(|i| { + BidParams::::new( + account::>("bidder", 0, i), + (min_bid_amount * CT_UNIT).into(), + 1u8, + AcceptedFundingAsset::USDT, + ) + }) + .collect_vec(); + all_bids.extend(accepted_bids.clone()); - // do "x" contributions for this user - inst.contribute_for_users(project_id, existing_contributions).expect("All contributions are accepted"); - - let mut total_plmc_bonded = inst.sum_balance_mappings(vec![ - plmc_for_existing_contributions.clone(), - plmc_for_extrinsic_contribution.clone(), - ]); - let mut total_usdt_locked = inst.sum_foreign_asset_mappings(vec![ - prev_total_usdt_locked, - usdt_for_existing_contributions.clone(), - usdt_for_extrinsic_contribution.clone(), - ]); - - let over_limit_count = x.saturating_sub(::MaxContributionsPerUser::get() - 1); - - let mut total_free_plmc = existential_deposits[0].plmc_amount; - let mut total_free_usdt = Zero::zero(); - - if x > 0 { - let plmc_returned = plmc_for_existing_contributions[0].plmc_amount * (over_limit_count as u128).into(); - total_plmc_bonded -= plmc_returned; - - let usdt_returned = usdt_for_existing_contributions[0].asset_amount * (over_limit_count as u128).into(); - total_usdt_locked -= usdt_returned; - total_ct_sold -= existing_amount * (over_limit_count as u128).into(); - total_free_plmc += plmc_returned; - total_free_usdt += usdt_returned; - } + let plmc_needed_for_bids = inst.calculate_auction_plmc_charged_from_all_bids_made_or_with_bucket( + &all_bids, + project_metadata.clone(), + None, + true, + ); + let funding_asset_needed_for_bids = inst + .calculate_auction_funding_asset_charged_from_all_bids_made_or_with_bucket( + &all_bids, + project_metadata.clone(), + None, + ); - if let Some(fully_filled_vecs_from_insertion) = ends_round { - // if all CTs are sold, next round is scheduled for next block (either remainder or success) - let expected_insertion_block = inst.current_block() + One::one(); - fill_projects_to_update::(fully_filled_vecs_from_insertion, expected_insertion_block); - } + inst.mint_plmc_to(plmc_needed_for_bids); + inst.mint_funding_asset_to(funding_asset_needed_for_bids); - ( - inst, - project_id, - project_metadata, - extrinsic_contribution, - total_free_plmc, - total_plmc_bonded, - total_free_usdt, - total_usdt_locked, - total_ct_sold, - ) - } + inst.bid_for_users(project_id, all_bids).unwrap(); - fn contribution_verification( - mut inst: BenchInstantiator, - project_id: ProjectId, - project_metadata: ProjectMetadataOf, - extrinsic_contribution: ContributionParams, - total_free_plmc: BalanceOf, - total_plmc_bonded: BalanceOf, - total_free_usdt: BalanceOf, - total_usdt_locked: BalanceOf, - total_ct_sold: BalanceOf, - ) where - T: Config, - ::Balance: From, - ::Price: From, - T::Hash: From, - ::RuntimeEvent: From>, - { - // * validity checks * - // Storage - let contributor = extrinsic_contribution.contributor.clone(); - let stored_contribution = Contributions::::iter_prefix_values((project_id, contributor.clone())) - .sorted_by(|a, b| a.id.cmp(&b.id)) - .last() - .unwrap(); + let auction_end = inst.get_project_details(project_id).round_duration.end().unwrap(); + inst.jump_to_block(auction_end); - match stored_contribution { - ContributionInfoOf:: { project_id, contributor, ct_amount, .. } - if project_id == project_id && - contributor == contributor && - ct_amount == extrinsic_contribution.amount => {}, - _ => { - assert!(false, "Contribution is not stored correctly") - }, + #[block] + { + Pallet::::do_end_auction(project_id).unwrap(); } - let stored_project_details = ProjectsDetails::::get(project_id).unwrap(); - - let bid_ct_sold = crate::Bids::::iter_prefix_values((project_id,)) - .map(|bid_in_project: BidInfoOf| bid_in_project.final_ct_amount) - .fold(Zero::zero(), |acc, x| acc + x); - - assert_eq!( - stored_project_details.remaining_contribution_tokens, - project_metadata.total_allocation_size.saturating_sub(total_ct_sold).saturating_sub(bid_ct_sold) - ); - - // Balances - let bonded_plmc = inst - .get_reserved_plmc_balances_for(vec![contributor.clone()], HoldReason::Participation(project_id).into())[0] - .plmc_amount; - assert_eq!(bonded_plmc, total_plmc_bonded); - - let free_plmc = inst.get_free_plmc_balances_for(vec![contributor.clone()])[0].plmc_amount; - assert_eq!(free_plmc, total_free_plmc); - - let escrow_account = Pallet::::fund_account_id(project_id); - let locked_usdt = - inst.get_free_funding_asset_balances_for(usdt_id(), vec![escrow_account.clone()])[0].asset_amount; - assert_eq!(locked_usdt, total_usdt_locked); + // * validity checks * + // Storage + let stored_details = ProjectsDetails::::get(project_id).unwrap(); + assert!(matches!(stored_details.status, ProjectStatus::CommunityRound(..))); - let free_usdt = inst.get_free_funding_asset_balances_for(usdt_id(), vec![contributor.clone()])[0].asset_amount; - assert_eq!(free_usdt, total_free_usdt); + let accepted_bids_count = Bids::::iter_prefix_values((project_id,)) + .filter(|b| matches!(b.status, BidStatus::Accepted | BidStatus::PartiallyAccepted(..))) + .count(); + let rejected_bids_count = + Bids::::iter_prefix_values((project_id,)).filter(|b| matches!(b.status, BidStatus::Rejected)).count(); + assert_eq!(accepted_bids_count, x as usize); + assert_eq!(rejected_bids_count, y as usize); // Events frame_system::Pallet::::assert_last_event( - Event::Contribution { + Event::::ProjectPhaseTransition { project_id, - contributor, - id: stored_contribution.id, - ct_amount: extrinsic_contribution.amount, - funding_asset: stored_contribution.funding_asset, - funding_amount: stored_contribution.funding_asset_amount, - plmc_bond: stored_contribution.plmc_bond, - multiplier: extrinsic_contribution.multiplier, + phase: ProjectStatus::CommunityRound(expected_remainder_round_block), } .into(), ); } + // We check if the user has a winning bid regardless if its the community or remainder round, so both rounds should have + // the same weight with `x` being equal. #[benchmark] - fn contribution( + fn contribute( // How many other contributions the user did for that same project x: Linear<0, { T::MaxContributionsPerUser::get() - 1 }>, ) { - let ends_round = None; + // setup + let mut inst = BenchInstantiator::::new(None); + ::SetPrices::set_prices(); - let ( - inst, - project_id, - project_metadata, - extrinsic_contribution, - total_free_plmc, - total_plmc_bonded, - total_free_usdt, - total_usdt_locked, - total_ct_sold, - ) = contribution_setup::(x, ends_round); + // We can't see events at block 0 + inst.jump_to_block(1u32.into()); - let jwt = get_mock_jwt_with_cid( - extrinsic_contribution.contributor.clone(), - InvestorType::Retail, - generate_did_from_account(extrinsic_contribution.contributor.clone()), - project_metadata.clone().policy_ipfs_cid.unwrap(), - ); + let issuer = account::>("issuer", 0, 0); + let contributor = account::>("contributor", 0, 0); + whitelist_account!(contributor); - #[extrinsic_call] - contribute( - RawOrigin::Signed(extrinsic_contribution.contributor.clone()), - jwt, - project_id, - extrinsic_contribution.amount, - extrinsic_contribution.multiplier, - extrinsic_contribution.asset, - ); + let project_metadata = default_project_metadata::(issuer.clone()); - contribution_verification::( - inst, - project_id, - project_metadata, - extrinsic_contribution, - total_free_plmc, - total_plmc_bonded, - total_free_usdt, - total_usdt_locked, - total_ct_sold, + let project_id = inst.create_community_contributing_project( + project_metadata.clone(), + issuer, + None, + default_evaluations::(), + full_bids::(), ); - } - #[benchmark] - fn contribution_ends_round( - // How many other contributions the user did for that same project - x: Linear<0, { T::MaxContributionsPerUser::get() - 1 }>, - // Insertion attempts in add_to_update_store. Total amount of storage items iterated through in `ProjectsToUpdate`. Leave one free to make the extrinsic pass - y: Linear<1, { ::MaxProjectsToUpdateInsertionAttempts::get() - 1 }>, - ) { - let ends_round = Some(y); + let price = inst.get_project_details(project_id).weighted_average_price.unwrap(); - let ( - inst, - project_id, - project_metadata, - extrinsic_contribution, - total_free_plmc, - total_plmc_bonded, - total_free_usdt, - total_usdt_locked, - total_ct_sold, - ) = contribution_setup::(x, ends_round); + let contributions = + vec![ + ContributionParams::new(contributor.clone(), (50 * CT_UNIT).into(), 1u8, AcceptedFundingAsset::USDT); + x as usize + 1 + ]; + + let plmc = inst.calculate_contributed_plmc_spent(contributions.clone(), price, false); + let usdt = inst.calculate_contributed_funding_asset_spent(contributions.clone(), price); + + let escrow_account = Pallet::::fund_account_id(project_id); + let prev_total_usdt_locked = inst.get_free_funding_asset_balances_for(usdt_id(), vec![escrow_account.clone()]); + + inst.mint_plmc_to(plmc.clone()); + inst.mint_plmc_to(plmc.accounts().existential_deposits()); + inst.mint_funding_asset_to(usdt.clone()); + + // do "x" contributions for this user + inst.contribute_for_users(project_id, contributions[1..].to_vec()).expect("All contributions are accepted"); + + let total_plmc_bonded = inst.sum_balance_mappings(vec![plmc.clone()]); + let total_usdt_locked = inst.sum_foreign_asset_mappings(vec![prev_total_usdt_locked, usdt.clone()])[0].1; + + let total_free_plmc = inst.get_ed(); + let total_free_usdt = Zero::zero(); let jwt = get_mock_jwt_with_cid( - extrinsic_contribution.contributor.clone(), + contributor.clone(), InvestorType::Retail, - generate_did_from_account(extrinsic_contribution.contributor.clone()), + generate_did_from_account(contributor.clone()), project_metadata.clone().policy_ipfs_cid.unwrap(), ); #[extrinsic_call] contribute( - RawOrigin::Signed(extrinsic_contribution.contributor.clone()), + RawOrigin::Signed(contributor.clone()), jwt, project_id, - extrinsic_contribution.amount, - extrinsic_contribution.multiplier, - extrinsic_contribution.asset, + contributions[0].amount, + contributions[0].multiplier, + contributions[0].asset, ); - contribution_verification::( - inst, - project_id, - project_metadata, - extrinsic_contribution, - total_free_plmc, - total_plmc_bonded, - total_free_usdt, - total_usdt_locked, - total_ct_sold, + // * validity checks * + // Storage + let stored_contributions = + Contributions::::iter_prefix_values((project_id, contributor.clone())).collect_vec(); + assert_eq!(stored_contributions.len(), x as usize + 1); + + // Balances + let bonded_plmc = + inst.get_reserved_plmc_balance_for(contributor.clone(), HoldReason::Participation(project_id).into()); + assert_eq!(bonded_plmc, total_plmc_bonded); + + let free_plmc = inst.get_free_plmc_balance_for(contributor.clone()); + assert_eq!(free_plmc, total_free_plmc); + + let escrow_account = Pallet::::fund_account_id(project_id); + let locked_usdt = inst.get_free_funding_asset_balance_for(usdt_id(), escrow_account.clone()); + assert_eq!(locked_usdt, total_usdt_locked); + + let free_usdt = inst.get_free_funding_asset_balance_for(usdt_id(), contributor.clone()); + assert_eq!(free_usdt, total_free_usdt); + + // Events + frame_system::Pallet::::assert_last_event( + Event::Contribution { + project_id, + contributor, + id: x, + ct_amount: contributions[0].amount, + funding_asset: AcceptedFundingAsset::USDT, + funding_amount: usdt[0].asset_amount, + plmc_bond: plmc[0].plmc_amount, + multiplier: contributions[0].multiplier, + } + .into(), ); } + // end_funding has 2 logic paths: + // 1 - Funding successful (most expensive, not by much) + // 2 - Funding failed + // They only differ in that 1- has to calculate the evaluator rewards. #[benchmark] - fn decide_project_outcome( - // Insertion attempts in add_to_update_store. Total amount of storage items iterated through in `ProjectsToUpdate`. Leave one free to make the extrinsic pass - x: Linear<1, { ::MaxProjectsToUpdateInsertionAttempts::get() - 1 }>, - ) { + fn end_funding_project_successful() { // setup let mut inst = BenchInstantiator::::new(None); ::SetPrices::set_prices(); - // We need to leave enough block numbers to fill `ProjectsToUpdate` before our project insertion - - let time_advance: u32 = x + 2; - frame_system::Pallet::::set_block_number(time_advance.into()); + // We can't see events at block 0 + inst.jump_to_block(1u32.into()); let issuer = account::>("issuer", 0, 0); - whitelist_account!(issuer); let project_metadata = default_project_metadata::(issuer.clone()); - let target_funding_amount: BalanceOf = - project_metadata.minimum_price.saturating_mul_int(project_metadata.total_allocation_size); - let evaluations = default_evaluations::(); - let bids = inst.generate_bids_from_total_usd( - Percent::from_percent(30) * target_funding_amount, - project_metadata.minimum_price, - default_weights(), - default_bidders::(), - default_bidder_multipliers(), + let project_id = inst.create_remainder_contributing_project( + project_metadata, + issuer.clone(), + None, + default_evaluations::(), + default_bids::(), + default_community_contributions::(), ); - let contributions = inst.generate_contributions_from_total_usd( - Percent::from_percent(40) * target_funding_amount, - project_metadata.minimum_price, - default_weights(), - default_community_contributors::(), - default_community_contributor_multipliers(), - ); + let end_block = inst.get_project_details(project_id).round_duration.end().unwrap(); + inst.jump_to_block(end_block); + + #[block] + { + Pallet::::do_end_funding(project_id).unwrap(); + } + + // * validity checks * + let project_details = inst.get_project_details(project_id); + assert_eq!(project_details.status, ProjectStatus::FundingSuccessful); + assert!(matches!( + project_details.evaluation_round_info.evaluators_outcome, + Some(EvaluatorsOutcome::Rewarded(_)) + )); + } + + // Success case is the most expensive, so we always charge for that. + #[benchmark] + fn start_settlement() { + let mut inst = BenchInstantiator::::new(None); + ::SetPrices::set_prices(); + + // We can't see events at block 0 + inst.jump_to_block(1u32.into()); + + let anyone = account::>("anyone", 0, 0); + let issuer = account::>("issuer", 0, 0); + whitelist_account!(anyone); let project_id = inst.create_finished_project( - project_metadata.clone(), - issuer.clone(), + default_project_metadata::(issuer.clone()), + issuer, None, - evaluations, - bids, - contributions, + default_evaluations::(), + default_bids::(), + default_community_contributions::(), vec![], ); - inst.advance_time(One::one()); - - let current_block = inst.current_block(); - let insertion_block_number: BlockNumberFor = current_block + One::one(); - - fill_projects_to_update::(x, insertion_block_number); - let jwt = get_mock_jwt_with_cid( - issuer.clone(), - InvestorType::Institutional, - generate_did_from_account(issuer.clone()), - project_metadata.clone().policy_ipfs_cid.unwrap(), - ); + inst.advance_time(::SuccessToSettlementTime::get()); #[extrinsic_call] - decide_project_outcome(RawOrigin::Signed(issuer), jwt, project_id, FundingOutcomeDecision::AcceptFunding); + start_settlement(RawOrigin::Signed(anyone), project_id); // * validity checks * - // Storage - let maybe_transition = inst.go_to_next_state(project_id); - assert!(maybe_transition.is_some()); + let project_details = ProjectsDetails::::get(project_id).unwrap(); + assert_eq!(project_details.status, ProjectStatus::SettlementStarted(FundingOutcome::Success)); + assert!(::ContributionTokenCurrency::asset_exists(project_id)); } + // We have 3 logic paths: + // 1 - Evaluation rewarded + // 2 - Evaluation slashed + // 3 - Evaluation failed (evaluation round unsuccessful) + // Path 1 is the most expensive but not by far, so we only benchmark and charge for this weight #[benchmark] - fn settle_successful_evaluation() { + fn settle_rewarded_evaluation() { // setup let mut inst = BenchInstantiator::::new(None); ::SetPrices::set_prices(); - // real benchmark starts at block 0, and we can't call `events()` at block 0 + // We can't see events at block 0 inst.advance_time(1u32.into()); let issuer = account::>("issuer", 0, 0); @@ -1447,18 +1326,14 @@ mod benchmarks { vec![], ); - run_blocks_to_execute_next_transition(project_id, UpdateType::StartSettlement, &mut inst); - let evaluation_to_settle = inst.execute(|| Evaluations::::iter_prefix_values((project_id, evaluator.clone())).next().unwrap()); + inst.advance_time(::SuccessToSettlementTime::get()); + assert_ok!(>::do_start_settlement(project_id)); + #[extrinsic_call] - settle_successful_evaluation( - RawOrigin::Signed(evaluator.clone()), - project_id, - evaluator.clone(), - evaluation_to_settle.id, - ); + settle_evaluation(RawOrigin::Signed(evaluator.clone()), project_id, evaluator.clone(), evaluation_to_settle.id); // * validity checks * // Evaluation should be removed @@ -1467,13 +1342,11 @@ mod benchmarks { // Balances let project_details = ProjectsDetails::::get(project_id).unwrap(); let reward_info = match project_details.evaluation_round_info.evaluators_outcome { - EvaluatorsOutcome::Rewarded(reward_info) => reward_info, + Some(EvaluatorsOutcome::Rewarded(reward_info)) => reward_info, _ => panic!("EvaluatorsOutcome should be Rewarded"), }; let reward = Pallet::::calculate_evaluator_reward(&evaluation_to_settle, &reward_info); - - let ct_amount = inst.get_ct_asset_balances_for(project_id, vec![evaluator.clone()])[0]; - assert_eq!(ct_amount, reward); + inst.assert_ct_balance(project_id, evaluator.clone(), reward); // Events frame_system::Pallet::::assert_last_event( @@ -1481,133 +1354,70 @@ mod benchmarks { project_id, account: evaluator.clone(), id: evaluation_to_settle.id, - ct_amount: reward, - slashed_plmc_amount: 0.into(), + ct_rewarded: reward, + plmc_released: evaluation_to_settle.original_plmc_bond, } .into(), ); } + // We have 3 logic paths + // 1 - Accepted bid with no refunds (i.e. final price <= WAP, no partial acceptance) + // 2 - Accepted bid with refund (i.e. final price > WAP or partial acceptance) + // 3 - Rejected bid (i.e. bid not accepted, everything refunded, no CT/migration) + // Path 2 is the most expensive but not by far, so we only benchmark and charge for this weight #[benchmark] - fn settle_failed_evaluation() { + fn settle_accepted_bid_with_refund() { // setup let mut inst = BenchInstantiator::::new(None); ::SetPrices::set_prices(); - // real benchmark starts at block 0, and we can't call `events()` at block 0 + // We can't see events at block 0 inst.advance_time(1u32.into()); let issuer = account::>("issuer", 0, 0); - let evaluations = default_evaluations::(); - let evaluator = evaluations[0].account.clone(); - whitelist_account!(evaluator); + let mut bidder_accounts = default_bidders::().into_iter(); let project_metadata = default_project_metadata::(issuer.clone()); - let target_funding_amount: BalanceOf = - project_metadata.minimum_price.saturating_mul_int(project_metadata.total_allocation_size); - - let bids = inst.generate_bids_from_total_usd( - Percent::from_percent(15) * target_funding_amount, - project_metadata.minimum_price, - default_weights(), - default_bidders::(), - default_bidder_multipliers(), - ); - let contributions = inst.generate_contributions_from_total_usd( - Percent::from_percent(10) * target_funding_amount, - project_metadata.minimum_price, - default_weights(), - default_community_contributors::(), - default_community_contributor_multipliers(), - ); - - let project_id = - inst.create_finished_project(project_metadata, issuer, None, evaluations, bids, contributions, vec![]); - - inst.advance_time(One::one()); - assert_eq!( - inst.get_project_details(project_id).status, - ProjectStatus::SettlementStarted(FundingOutcome::Failure) - ); - - let evaluation_to_settle = - inst.execute(|| Evaluations::::iter_prefix_values((project_id, evaluator.clone())).next().unwrap()); - - let treasury_account = T::BlockchainOperationTreasury::get(); - let prev_free_treasury_plmc = inst.get_free_plmc_balances_for(vec![treasury_account])[0].plmc_amount; - - #[extrinsic_call] - settle_failed_evaluation( - RawOrigin::Signed(evaluator.clone()), - project_id, - evaluator.clone(), - evaluation_to_settle.id, - ); - - // * validity checks * - // Storage - // Evaluation should be removed - assert!(Evaluations::::get((project_id, evaluator.clone(), evaluation_to_settle.id)).is_none()); - let slashed_amount = T::EvaluatorSlash::get() * evaluation_to_settle.original_plmc_bond; - - let reserved_plmc = inst - .get_reserved_plmc_balances_for(vec![evaluator.clone()], HoldReason::Evaluation(project_id).into())[0] - .plmc_amount; - assert_eq!(reserved_plmc, 0.into()); + // let target_wap = project_metadata.minimum_price + project_metadata.minimum_price * >::saturating_from_rational(1, 10); + let mut target_bucket = >::create_bucket_from_metadata(&project_metadata.clone()).unwrap(); + target_bucket.update(target_bucket.amount_left); + target_bucket.update(target_bucket.amount_left); - let treasury_account = T::BlockchainOperationTreasury::get(); - let post_free_treasury_plmc = inst.get_free_plmc_balances_for(vec![treasury_account])[0].plmc_amount; - assert_eq!(post_free_treasury_plmc, prev_free_treasury_plmc + slashed_amount); - - // Events - frame_system::Pallet::::assert_last_event( - Event::EvaluationSettled { - project_id, - account: evaluator.clone(), - id: evaluation_to_settle.id, - ct_amount: 0.into(), - slashed_plmc_amount: slashed_amount, - } - .into(), + let bids = inst.generate_bids_from_bucket( + project_metadata.clone(), + target_bucket, + bidder_accounts.next().unwrap(), + |_| bidder_accounts.next().unwrap(), + AcceptedFundingAsset::USDT, ); - } - - #[benchmark] - fn settle_successful_bid() { - // setup - let mut inst = BenchInstantiator::::new(None); - ::SetPrices::set_prices(); - - // real benchmark starts at block 0, and we can't call `events()` at block 0 - inst.advance_time(1u32.into()); - - let issuer = account::>("issuer", 0, 0); - let bids = default_bids::(); - let bidder = bids[0].bidder.clone(); - whitelist_account!(bidder); let project_id = inst.create_finished_project( - default_project_metadata::(issuer.clone()), + project_metadata.clone(), issuer, None, default_evaluations::(), - bids, + bids.clone(), default_community_contributions::(), vec![], ); - run_blocks_to_execute_next_transition(project_id, UpdateType::StartSettlement, &mut inst); + let wap = inst.get_project_details(project_id).weighted_average_price.unwrap(); - assert_eq!( - inst.get_project_details(project_id).status, - ProjectStatus::SettlementStarted(FundingOutcome::Success) - ); + let bidder = bids.last().unwrap().bidder.clone(); + whitelist_account!(bidder); + + inst.advance_time(::SuccessToSettlementTime::get()); + assert_ok!(>::do_start_settlement(project_id)); let bid_to_settle = inst.execute(|| Bids::::iter_prefix_values((project_id, bidder.clone())).next().unwrap()); + // Make sure a refund has to happen + assert!(bid_to_settle.original_ct_usd_price > wap); + #[extrinsic_call] - settle_successful_bid(RawOrigin::Signed(bidder.clone()), project_id, bidder.clone(), bid_to_settle.id); + settle_bid(RawOrigin::Signed(bidder.clone()), project_id, bidder.clone(), bid_to_settle.id); // * validity checks * // Storage @@ -1615,100 +1425,42 @@ mod benchmarks { // Balances let ct_amount = inst.get_ct_asset_balances_for(project_id, vec![bidder.clone()])[0]; - assert_eq!(bid_to_settle.final_ct_amount, ct_amount); + assert_eq!(bid_to_settle.original_ct_amount, ct_amount); // Events frame_system::Pallet::::assert_last_event( - Event::BidSettled { project_id, account: bidder.clone(), id: bid_to_settle.id, ct_amount }.into(), + Event::BidSettled { + project_id, + account: bidder.clone(), + id: bid_to_settle.id, + final_ct_amount: bid_to_settle.original_ct_amount, + final_ct_price: wap, + } + .into(), ); } + // We have 2 logic paths + // 1 - Project was successful, USDT is transferred to issuer, CT minted, PLMC locked for vesting + // 2 - Project failed, USDT is refunded to contributor, CT is not minted, PLMC is released + // Path 1 is the most expensive but not by far, so we only benchmark and charge for this weight #[benchmark] - fn settle_failed_bid() { + fn settle_contribution_project_successful() { // setup let mut inst = BenchInstantiator::::new(None); ::SetPrices::set_prices(); - // real benchmark starts at block 0, and we can't call `events()` at block 0 + // We can't see events at block 0 inst.advance_time(1u32.into()); let issuer = account::>("issuer", 0, 0); - let evaluations = default_evaluations::(); + let contributions = default_community_contributions::(); + let contributor = contributions[0].contributor.clone(); + whitelist_account!(contributor); let project_metadata = default_project_metadata::(issuer.clone()); - let target_funding_amount: BalanceOf = - project_metadata.minimum_price.saturating_mul_int(project_metadata.total_allocation_size); - - let bids: Vec> = inst.generate_bids_from_total_usd( - Percent::from_percent(15) * target_funding_amount, - project_metadata.minimum_price, - default_weights(), - default_bidders::(), - default_bidder_multipliers(), - ); - let bidder = bids[0].bidder.clone(); - whitelist_account!(bidder); - let contributions = inst.generate_contributions_from_total_usd( - Percent::from_percent(10) * target_funding_amount, - project_metadata.minimum_price, - default_weights(), - default_community_contributors::(), - default_community_contributor_multipliers(), - ); - let project_id = inst.create_finished_project( - project_metadata, - issuer.clone(), - None, - evaluations, - bids, - contributions, - vec![], - ); - - inst.advance_time(One::one()); - assert_eq!( - inst.get_project_details(project_id).status, - ProjectStatus::SettlementStarted(FundingOutcome::Failure) - ); - - let bid_to_settle = - inst.execute(|| Bids::::iter_prefix_values((project_id, bidder.clone())).next().unwrap()); - let asset = bid_to_settle.funding_asset.id(); - let free_assets_before = inst.get_free_funding_asset_balances_for(asset, vec![bidder.clone()])[0].asset_amount; - #[extrinsic_call] - settle_failed_bid(RawOrigin::Signed(issuer.clone()), project_id, bidder.clone(), bid_to_settle.id); - - // * validity checks * - // Storage - assert!(Bids::::get((project_id, bidder.clone(), bid_to_settle.id)).is_none()); - - // Balances - let free_assets = inst.get_free_funding_asset_balances_for(asset, vec![bidder.clone()])[0].asset_amount; - assert_eq!(free_assets, bid_to_settle.funding_asset_amount_locked + free_assets_before); - - // Events - frame_system::Pallet::::assert_last_event( - Event::BidSettled { project_id, account: bidder.clone(), id: bid_to_settle.id, ct_amount: 0.into() }.into(), - ); - } - - #[benchmark] - fn settle_successful_contribution() { - // setup - let mut inst = BenchInstantiator::::new(None); - ::SetPrices::set_prices(); - - // real benchmark starts at block 0, and we can't call `events()` at block 0 - inst.advance_time(1u32.into()); - - let issuer = account::>("issuer", 0, 0); - let contributions = default_community_contributions::(); - let contributor = contributions[0].contributor.clone(); - whitelist_account!(contributor); - - let project_id = inst.create_finished_project( - default_project_metadata::(issuer.clone()), + project_metadata.clone(), issuer, None, default_evaluations::(), @@ -1717,980 +1469,67 @@ mod benchmarks { vec![], ); - run_blocks_to_execute_next_transition(project_id, UpdateType::StartSettlement, &mut inst); - - assert_eq!( - inst.get_project_details(project_id).status, - ProjectStatus::SettlementStarted(FundingOutcome::Success) - ); - - let contribution_to_settle = - inst.execute(|| Contributions::::iter_prefix_values((project_id, contributor.clone())).next().unwrap()); - - #[extrinsic_call] - settle_successful_contribution( - RawOrigin::Signed(contributor.clone()), - project_id, - contributor.clone(), - contribution_to_settle.id, - ); - - // * validity checks * - // Storage - assert!(Contributions::::get((project_id, contributor.clone(), contribution_to_settle.id)).is_none()); - - // Balances - let ct_amount = inst.get_ct_asset_balances_for(project_id, vec![contributor.clone()])[0]; - assert_eq!(contribution_to_settle.ct_amount, ct_amount); - - // Events - frame_system::Pallet::::assert_last_event( - Event::ContributionSettled { - project_id, - account: contributor.clone(), - id: contribution_to_settle.id, - ct_amount, - } - .into(), - ); - } - - #[benchmark] - fn settle_failed_contribution() { - // setup - let mut inst = BenchInstantiator::::new(None); - ::SetPrices::set_prices(); - - // real benchmark starts at block 0, and we can't call `events()` at block 0 - inst.advance_time(1u32.into()); - - let issuer = account::>("issuer", 0, 0); - let evaluations = default_evaluations::(); - - let project_metadata = default_project_metadata::(issuer.clone()); - let target_funding_amount: BalanceOf = - project_metadata.minimum_price.saturating_mul_int(project_metadata.total_allocation_size); - - let bids: Vec> = inst.generate_bids_from_total_usd( - Percent::from_percent(15) * target_funding_amount, - project_metadata.minimum_price, - default_weights(), - default_bidders::(), - default_bidder_multipliers(), - ); - let contributions: Vec> = inst.generate_contributions_from_total_usd( - Percent::from_percent(10) * target_funding_amount, - project_metadata.minimum_price, - default_weights(), - default_community_contributors::(), - default_community_contributor_multipliers(), - ); - let contributor = contributions[0].contributor.clone(); - whitelist_account!(contributor); - - let project_id = - inst.create_finished_project(project_metadata, issuer, None, evaluations, bids, contributions, vec![]); - - inst.advance_time(One::one()); - assert_eq!( - inst.get_project_details(project_id).status, - ProjectStatus::SettlementStarted(FundingOutcome::Failure) - ); + inst.advance_time(::SuccessToSettlementTime::get()); + assert_ok!(>::do_start_settlement(project_id)); let contribution_to_settle = inst.execute(|| Contributions::::iter_prefix_values((project_id, contributor.clone())).next().unwrap()); - let asset = contribution_to_settle.funding_asset.id(); - let free_assets_before = - inst.get_free_funding_asset_balances_for(asset, vec![contributor.clone()])[0].asset_amount; #[extrinsic_call] - settle_failed_contribution( + settle_contribution( RawOrigin::Signed(contributor.clone()), project_id, contributor.clone(), contribution_to_settle.id, - ); - - // * validity checks * - // Storage - assert!(Contributions::::get((project_id, contributor.clone(), contribution_to_settle.id)).is_none()); - - // Balances - let free_assets = inst.get_free_funding_asset_balances_for(asset, vec![contributor.clone()])[0].asset_amount; - assert_eq!(free_assets, contribution_to_settle.funding_asset_amount + free_assets_before); - - // Events - frame_system::Pallet::::assert_last_event( - Event::ContributionSettled { - project_id, - account: contributor.clone(), - id: contribution_to_settle.id, - ct_amount: 0.into(), - } - .into(), - ); - } - - //do_evaluation_end - #[benchmark] - fn end_evaluation_success( - // 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(); - - // real benchmark starts at block 0, and we can't call `events()` at block 0 - inst.advance_time(1u32.into()); - - let issuer = account::>("issuer", 0, 0); - whitelist_account!(issuer); - - let project_metadata = default_project_metadata::(issuer.clone()); - let project_id = inst.create_evaluating_project(project_metadata, issuer.clone(), None); - - let evaluations = default_evaluations(); - let plmc_for_evaluating = inst.calculate_evaluation_plmc_spent(evaluations.clone(), true); - - inst.mint_plmc_to(plmc_for_evaluating); - - inst.advance_time(One::one()); - inst.evaluate_for_users(project_id, evaluations).expect("All evaluations are accepted"); - - let evaluation_end_block = - inst.get_project_details(project_id).phase_transition_points.evaluation.end().unwrap(); - // 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()); - - let insertion_block_number = - inst.current_block() + One::one() + ::AuctionInitializePeriodDuration::get(); - fill_projects_to_update::(x, insertion_block_number); - - // Instead of advancing in time for the automatic `do_evaluation_end` call in on_initialize, we call it directly to benchmark it - #[block] - { - Pallet::::do_end_evaluation(project_id).unwrap(); - } - - // * validity checks * - let project_details = inst.get_project_details(project_id); - assert_eq!(project_details.status, ProjectStatus::AuctionInitializePeriod); - } - - #[benchmark] - 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(); - - // real benchmark starts at block 0, and we can't call `events()` at block 0 - inst.advance_time(1u32.into()); - - let issuer = account::>("issuer", 0, 0); - whitelist_account!(issuer); - - let project_metadata = default_project_metadata::(issuer.clone()); - let project_id = inst.create_evaluating_project(project_metadata, issuer.clone(), None); - let project_details = inst.get_project_details(project_id); - - let evaluation_usd_target = - ::EvaluationSuccessThreshold::get() * project_details.fundraising_target_usd; - // we only fund 50% of the minimum threshold for the evaluation round, since we want it to fail - let evaluations = vec![ - UserToUSDBalance::new( - account::>("evaluator_1", 0, 0), - (Percent::from_percent(5) * evaluation_usd_target).into(), - ), - UserToUSDBalance::new( - account::>("evaluator_2", 0, 0), - (Percent::from_percent(20) * evaluation_usd_target).into(), - ), - UserToUSDBalance::new( - account::>("evaluator_3", 0, 0), - (Percent::from_percent(25) * evaluation_usd_target).into(), - ), - ]; - let plmc_for_evaluating = inst.calculate_evaluation_plmc_spent(evaluations.clone(), true); - - inst.mint_plmc_to(plmc_for_evaluating); - - inst.advance_time(One::one()); - inst.evaluate_for_users(project_id, evaluations).expect("All evaluations are accepted"); - - let evaluation_end_block = - inst.get_project_details(project_id).phase_transition_points.evaluation.end().unwrap(); - // 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] - { - Pallet::::do_end_evaluation(project_id).unwrap(); - } - - // * validity checks * - let project_details = inst.get_project_details(project_id); - assert_eq!(project_details.status, ProjectStatus::FundingFailed); - } - - // do_auction_closing_auction - #[benchmark] - fn start_auction_closing_phase( - // 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(); - - // real benchmark starts at block 0, and we can't call `events()` at block 0 - inst.advance_time(1u32.into()); - - let issuer = account::>("issuer", 0, 0); - whitelist_account!(issuer); - - let project_metadata = default_project_metadata::(issuer.clone()); - let project_id = inst.create_auctioning_project(project_metadata, issuer.clone(), None, default_evaluations()); - - let opening_end_block = - inst.get_project_details(project_id).phase_transition_points.auction_opening.end().unwrap(); - // we don't use advance time to avoid triggering on_initialize. This benchmark should only measure the extrinsic - // weight and not the whole on_initialize call weight - frame_system::Pallet::::set_block_number(opening_end_block + One::one()); - - let insertion_block_number = inst.current_block() + T::AuctionClosingDuration::get() + One::one(); - - fill_projects_to_update::(x, insertion_block_number); - - #[block] - { - Pallet::::do_start_auction_closing(project_id).unwrap(); - } - // * validity checks * - // Storage - let stored_details = ProjectsDetails::::get(project_id).unwrap(); - assert_eq!(stored_details.status, ProjectStatus::AuctionClosing); - - // Events - frame_system::Pallet::::assert_last_event( - Event::::ProjectPhaseTransition { project_id, phase: ProjectPhases::AuctionClosing }.into(), - ); - } - - #[benchmark] - fn end_auction_closing( - // 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 }>, - // Accepted Bids - y: Linear<1, { ::MaxBidsPerProject::get() / 2 }>, - // Failed Bids - z: Linear<1, { ::MaxBidsPerProject::get() / 2 }>, - ) { - // * setup * - let mut inst = BenchInstantiator::::new(None); - ::SetPrices::set_prices(); - // real benchmark starts at block 0, and we can't call `events()` at block 0 - inst.advance_time(1u32.into()); - - let issuer = account::>("issuer", 0, 0); - whitelist_account!(issuer); - - let mut project_metadata = default_project_metadata::(issuer.clone()); - project_metadata.mainnet_token_max_supply = - BalanceOf::::try_from(10_000_000 * CT_UNIT).unwrap_or_else(|_| panic!("Failed to create BalanceOf")); - project_metadata.total_allocation_size = - BalanceOf::::try_from(10_000_000 * CT_UNIT).unwrap_or_else(|_| panic!("Failed to create BalanceOf")); - project_metadata.auction_round_allocation_percentage = Percent::from_percent(100u8); - - let project_id = inst.create_auctioning_project( - project_metadata.clone(), - issuer.clone(), - None, - inst.generate_successful_evaluations( - project_metadata.clone(), - default_evaluators::(), - default_weights(), - ), - ); - - let auction_allocation = - project_metadata.auction_round_allocation_percentage * project_metadata.total_allocation_size; - let min_bid_amount = 500u128; - let smaller_than_wap_accepted_bid = vec![BidParams::::new( - account::>("bidder", 0, 0), - auction_allocation, - 1u8, - AcceptedFundingAsset::USDT, - )]; - let higher_than_wap_accepted_bids = (1..y) - .map(|i| { - BidParams::::new( - account::>("bidder", 0, i), - (min_bid_amount * CT_UNIT).into(), - 1u8, - AcceptedFundingAsset::USDT, - ) - }) - .collect_vec(); - - let accepted_bids = - vec![smaller_than_wap_accepted_bid, higher_than_wap_accepted_bids].into_iter().flatten().collect_vec(); - let rejected_bids = (0..z) - .map(|i| { - BidParams::::new( - account::>("bidder", 0, i), - (500 * CT_UNIT).into(), - 1u8, - AcceptedFundingAsset::USDT, - ) - }) - .collect_vec(); - - let all_bids = vec![accepted_bids.clone(), rejected_bids.clone()].into_iter().flatten().collect_vec(); - - let plmc_needed_for_bids = inst.calculate_auction_plmc_charged_from_all_bids_made_or_with_bucket( - &all_bids, - project_metadata.clone(), - None, - false, - ); - let plmc_ed = all_bids.accounts().existential_deposits(); - let funding_asset_needed_for_bids = inst - .calculate_auction_funding_asset_charged_from_all_bids_made_or_with_bucket( - &all_bids, - project_metadata.clone(), - None, - ); - - inst.mint_plmc_to(plmc_needed_for_bids); - inst.mint_plmc_to(plmc_ed); - inst.mint_funding_asset_to(funding_asset_needed_for_bids); - - inst.bid_for_users(project_id, accepted_bids).unwrap(); - - let transition_block = inst.go_to_next_state(project_id).unwrap(); - inst.jump_to_block(transition_block); - let auction_closing_end_block = - inst.get_project_details(project_id).phase_transition_points.auction_closing.end().unwrap(); - // Go to the last block of closing auction, to make bids fail - frame_system::Pallet::::set_block_number(auction_closing_end_block); - inst.bid_for_users(project_id, rejected_bids).unwrap(); - - let now = inst.current_block(); - let transition_block = now + One::one(); - frame_system::Pallet::::set_block_number(transition_block); - - fill_projects_to_update::(x, transition_block); - - #[block] - { - Pallet::::do_end_auction(project_id).unwrap(); - } - - // * validity checks * - // Storage - let stored_details = ProjectsDetails::::get(project_id).unwrap(); - assert_eq!(stored_details.status, ProjectStatus::CommunityRound); - assert!( - stored_details.phase_transition_points.random_closing_ending.unwrap() < - stored_details.phase_transition_points.auction_closing.end().unwrap() - ); - let accepted_bids_count = Bids::::iter_prefix_values((project_id,)) - .filter(|b| matches!(b.status, BidStatus::Accepted | BidStatus::PartiallyAccepted(..))) - .count(); - let rejected_bids_count = - Bids::::iter_prefix_values((project_id,)).filter(|b| matches!(b.status, BidStatus::Rejected(_))).count(); - assert_eq!(rejected_bids_count, 0); - assert_eq!(accepted_bids_count, y as usize); - - // Events - frame_system::Pallet::::assert_last_event( - Event::::ProjectPhaseTransition { project_id, phase: ProjectPhases::CalculatingWAP }.into(), - ); - } - - // do_community_funding - // Should be complex due to calling `calculate_weighted_average_price` - #[benchmark] - fn start_community_funding( - // 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 }>, - // Accepted Bids - y: Linear<1, { ::MaxBidsPerProject::get() / 2 }>, - // Rejected Bids - z: Linear<1, { ::MaxBidsPerProject::get() / 2 }>, - ) { - // * setup * - let mut inst = BenchInstantiator::::new(None); - ::SetPrices::set_prices(); - // real benchmark starts at block 0, and we can't call `events()` at block 0 - inst.advance_time(1u32.into()); - - let issuer = account::>("issuer", 0, 0); - whitelist_account!(issuer); - let mut project_metadata = default_project_metadata::(issuer.clone()); - - project_metadata.mainnet_token_max_supply = - BalanceOf::::try_from(10_000_000 * CT_UNIT).unwrap_or_else(|_| panic!("Failed to create BalanceOf")); - project_metadata.total_allocation_size = - BalanceOf::::try_from(10_000_000 * CT_UNIT).unwrap_or_else(|_| panic!("Failed to create BalanceOf")); - project_metadata.auction_round_allocation_percentage = Percent::from_percent(100u8); - - let project_id = inst.create_auctioning_project( - project_metadata.clone(), - issuer.clone(), - None, - inst.generate_successful_evaluations( - project_metadata.clone(), - default_evaluators::(), - default_weights(), - ), - ); - - let auction_allocation = - project_metadata.auction_round_allocation_percentage * project_metadata.total_allocation_size; - let min_bid_amount = 500u128; - let smaller_than_wap_accepted_bid = vec![BidParams::::new( - account::>("bidder", 0, 0), - auction_allocation, - 1u8, - AcceptedFundingAsset::USDT, - )]; - let higher_than_wap_accepted_bids = (1..y) - .map(|i| { - BidParams::::new( - account::>("bidder", 0, i), - (min_bid_amount * CT_UNIT).into(), - 1u8, - AcceptedFundingAsset::USDT, - ) - }) - .collect_vec(); - - let accepted_bids = - vec![smaller_than_wap_accepted_bid, higher_than_wap_accepted_bids].into_iter().flatten().collect_vec(); - - let rejected_bids = (0..z) - .map(|i| { - BidParams::::new( - account::>("bidder", 0, i), - (500 * CT_UNIT).into(), - 1u8, - AcceptedFundingAsset::USDT, - ) - }) - .collect_vec(); - - let all_bids = vec![accepted_bids.clone(), rejected_bids.clone()].into_iter().flatten().collect_vec(); - - let plmc_needed_for_bids = inst.calculate_auction_plmc_charged_from_all_bids_made_or_with_bucket( - &all_bids, - project_metadata.clone(), - None, - false, - ); - let plmc_ed = all_bids.accounts().existential_deposits(); - let funding_asset_needed_for_bids = inst - .calculate_auction_funding_asset_charged_from_all_bids_made_or_with_bucket( - &all_bids, - project_metadata.clone(), - None, - ); - - inst.mint_plmc_to(plmc_needed_for_bids); - inst.mint_plmc_to(plmc_ed); - inst.mint_funding_asset_to(funding_asset_needed_for_bids); - - inst.bid_for_users(project_id, accepted_bids).unwrap(); - - let transition_block = inst.get_update_block(project_id, &UpdateType::AuctionClosingStart).unwrap(); - inst.jump_to_block(transition_block); - let auction_closing_end_block = - inst.get_project_details(project_id).phase_transition_points.auction_closing.end().unwrap(); - // Go to the last block of closing auction, to make bids fail - frame_system::Pallet::::set_block_number(auction_closing_end_block); - inst.bid_for_users(project_id, rejected_bids).unwrap(); - - let transition_block = inst.get_update_block(project_id, &UpdateType::AuctionClosingEnd).unwrap(); - inst.jump_to_block(transition_block); - let transition_block = inst.get_update_block(project_id, &UpdateType::CommunityFundingStart).unwrap(); - // Block is at automatic transition, but it's not run with on_initialize, we do it manually - frame_system::Pallet::::set_block_number(transition_block); - - let now = inst.current_block(); - let community_end_block = now + T::CommunityFundingDuration::get() - One::one(); - - let insertion_block_number = community_end_block + One::one(); - fill_projects_to_update::(x, insertion_block_number); - - #[block] - { - Pallet::::do_start_community_funding(project_id).unwrap(); - } - - // * validity checks * - // Storage - let stored_details = ProjectsDetails::::get(project_id).unwrap(); - assert_eq!(stored_details.status, ProjectStatus::CommunityRound); - let accepted_bids_count = Bids::::iter_prefix_values((project_id,)).count(); - assert_eq!(accepted_bids_count, y as usize); - - // Events - frame_system::Pallet::::assert_last_event( - Event::::ProjectPhaseTransition { project_id, phase: ProjectPhases::CommunityFunding }.into(), - ); - } - - // do_remainder_funding - #[benchmark] - fn start_remainder_funding( - // 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(); - - // real benchmark starts at block 0, and we can't call `events()` at block 0 - inst.advance_time(1u32.into()); - - let issuer = account::>("issuer", 0, 0); - whitelist_account!(issuer); - - let project_metadata = default_project_metadata::(issuer.clone()); - let project_id = inst.create_community_contributing_project( - project_metadata, - issuer.clone(), - None, - default_evaluations(), - default_bids(), - ); - - let community_end_block = inst.get_project_details(project_id).phase_transition_points.community.end().unwrap(); - - // we don't use advance time to avoid triggering on_initialize. This benchmark should only measure the fn - // weight and not the whole on_initialize call weight - frame_system::Pallet::::set_block_number(community_end_block + One::one()); - - let now = inst.current_block(); - let remainder_end_block = now + T::RemainderFundingDuration::get(); - let insertion_block_number = remainder_end_block + 1u32.into(); - - fill_projects_to_update::(x, insertion_block_number); - - #[block] - { - Pallet::::do_start_remainder_funding(project_id).unwrap(); - } - - // * validity checks * - // Storage - let stored_details = ProjectsDetails::::get(project_id).unwrap(); - - // Events - frame_system::Pallet::::assert_last_event( - Event::::ProjectPhaseTransition { project_id, phase: ProjectPhases::RemainderFunding }.into(), - ); - } - - // do_end_funding - #[benchmark] - fn end_funding_automatically_rejected_evaluators_slashed( - // 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(); - - let issuer = account::>("issuer", 0, 0); - - let project_metadata = default_project_metadata::(issuer.clone()); - let target_funding_amount: BalanceOf = - project_metadata.minimum_price.saturating_mul_int(project_metadata.total_allocation_size); - - let automatically_rejected_threshold = Percent::from_percent(33); - - let bids: Vec> = inst.generate_bids_from_total_usd( - (automatically_rejected_threshold * target_funding_amount) / 2.into(), - project_metadata.minimum_price, - default_weights(), - default_bidders::(), - default_bidder_multipliers(), - ); - let contributions = inst.generate_contributions_from_total_usd( - (automatically_rejected_threshold * target_funding_amount) / 2.into(), - project_metadata.minimum_price, - default_weights(), - default_community_contributors::(), - default_community_contributor_multipliers(), - ); - - let project_id = inst.create_remainder_contributing_project( - project_metadata, - issuer.clone(), - None, - default_evaluations::(), - bids, - contributions, - ); - - let project_details = inst.get_project_details(project_id); - let last_funding_block = project_details.phase_transition_points.remainder.end().unwrap(); - - frame_system::Pallet::::set_block_number(last_funding_block + 1u32.into()); - - let insertion_block_number = inst.current_block() + 1u32.into(); - fill_projects_to_update::(x, insertion_block_number); - - #[block] - { - Pallet::::do_end_funding(project_id).unwrap(); - } - - // * validity checks * - let project_details = inst.get_project_details(project_id); - assert_eq!(project_details.status, ProjectStatus::FundingFailed); - } - #[benchmark] - fn end_funding_awaiting_decision_evaluators_slashed( - // 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(); - - let issuer = account::>("issuer", 0, 0); - - let project_metadata = default_project_metadata::(issuer.clone()); - let target_funding_amount: BalanceOf = - project_metadata.minimum_price.saturating_mul_int(project_metadata.total_allocation_size); - - let automatically_rejected_threshold = Percent::from_percent(75); - - let bids: Vec> = inst.generate_bids_from_total_usd( - (automatically_rejected_threshold * target_funding_amount) / 2.into(), - project_metadata.minimum_price, - default_weights(), - default_bidders::(), - default_bidder_multipliers(), - ); - let contributions = inst.generate_contributions_from_total_usd( - (automatically_rejected_threshold * target_funding_amount) / 2.into(), - project_metadata.minimum_price, - default_weights(), - default_community_contributors::(), - default_community_contributor_multipliers(), - ); - - let project_id = inst.create_remainder_contributing_project( - project_metadata, - issuer.clone(), - None, - default_evaluations::(), - bids, - contributions, - ); - - let project_details = inst.get_project_details(project_id); - let last_funding_block = project_details.phase_transition_points.remainder.end().unwrap(); - - frame_system::Pallet::::set_block_number(last_funding_block + 1u32.into()); - - let insertion_block_number = inst.current_block() + T::ManualAcceptanceDuration::get() + 1u32.into(); - fill_projects_to_update::(x, insertion_block_number); - - #[block] - { - Pallet::::do_end_funding(project_id).unwrap(); - } - - // * validity checks * - let project_details = inst.get_project_details(project_id); - - assert_eq!(project_details.evaluation_round_info.evaluators_outcome, EvaluatorsOutcome::Slashed) - } - #[benchmark] - fn end_funding_awaiting_decision_evaluators_unchanged( - // 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(); - - let issuer = account::>("issuer", 0, 0); - - let project_metadata = default_project_metadata::(issuer.clone()); - let target_funding_amount: BalanceOf = - project_metadata.minimum_price.saturating_mul_int(project_metadata.total_allocation_size); - - let automatically_rejected_threshold = Percent::from_percent(89); - - let bids: Vec> = inst.generate_bids_from_total_usd( - (automatically_rejected_threshold * target_funding_amount) / 2.into(), - project_metadata.minimum_price, - default_weights(), - default_bidders::(), - default_bidder_multipliers(), - ); - let contributions = inst.generate_contributions_from_total_usd( - (automatically_rejected_threshold * target_funding_amount) / 2.into(), - project_metadata.minimum_price, - default_weights(), - default_community_contributors::(), - default_community_contributor_multipliers(), - ); - - let project_id = inst.create_remainder_contributing_project( - project_metadata, - issuer.clone(), - None, - default_evaluations::(), - bids, - contributions, - ); - - let project_details = inst.get_project_details(project_id); - let last_funding_block = project_details.phase_transition_points.remainder.end().unwrap(); - - frame_system::Pallet::::set_block_number(last_funding_block + 1u32.into()); - - let insertion_block_number = inst.current_block() + T::ManualAcceptanceDuration::get() + 1u32.into(); - fill_projects_to_update::(x, insertion_block_number); - - #[block] - { - Pallet::::do_end_funding(project_id).unwrap(); - } - - // * validity checks * - let project_details = inst.get_project_details(project_id); - assert_eq!(project_details.evaluation_round_info.evaluators_outcome, EvaluatorsOutcome::Unchanged) - } - #[benchmark] - fn end_funding_automatically_accepted_evaluators_rewarded( - // 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 }>, - // How many evaluations have been made. Used when calculating evaluator rewards - y: Linear<1, { ::MaxEvaluationsPerProject::get() }>, - ) { - // setup - let mut inst = BenchInstantiator::::new(None); - ::SetPrices::set_prices(); - - let issuer = account::>("issuer", 0, 0); - - let project_metadata = default_project_metadata::(issuer.clone()); - let target_funding_amount: BalanceOf = - project_metadata.minimum_price.saturating_mul_int(project_metadata.total_allocation_size); - - let automatically_rejected_threshold = Percent::from_percent(91); - - let mut evaluations = (0..y.saturating_sub(1)) - .map(|i| { - UserToUSDBalance::::new(account::>("evaluator", 0, i), (100u128 * USD_UNIT).into()) - }) - .collect_vec(); - - let evaluation_target_usd = ::EvaluationSuccessThreshold::get() * target_funding_amount; - evaluations.push(UserToUSDBalance::::new( - account::>("evaluator_success", 0, 69420), - evaluation_target_usd, - )); - - let plmc_needed_for_evaluating = inst.calculate_evaluation_plmc_spent(evaluations.clone(), true); - - inst.mint_plmc_to(plmc_needed_for_evaluating); - - let bids: Vec> = inst.generate_bids_from_total_usd( - (automatically_rejected_threshold * target_funding_amount) / 2.into(), - project_metadata.minimum_price, - default_weights(), - default_bidders::(), - default_bidder_multipliers(), - ); - let contributions = inst.generate_contributions_from_total_usd( - (automatically_rejected_threshold * target_funding_amount) / 2.into(), - project_metadata.minimum_price, - default_weights(), - default_community_contributors::(), - default_community_contributor_multipliers(), - ); - - let project_id = inst.create_remainder_contributing_project( - project_metadata, - issuer.clone(), - None, - evaluations, - bids, - contributions, - ); - - let project_details = inst.get_project_details(project_id); - let last_funding_block = project_details.phase_transition_points.remainder.end().unwrap(); - - frame_system::Pallet::::set_block_number(last_funding_block + 1u32.into()); - - let insertion_block_number = inst.current_block() + T::SuccessToSettlementTime::get(); - fill_projects_to_update::(x, insertion_block_number); - - #[block] - { - Pallet::::do_end_funding(project_id).unwrap(); - } - - // * validity checks * - let project_details = inst.get_project_details(project_id); - assert_eq!(project_details.status, ProjectStatus::FundingSuccessful); - } - - // do_project_decision - #[benchmark] - fn project_decision() { - // setup - let mut inst = BenchInstantiator::::new(None); - ::SetPrices::set_prices(); - - let issuer = account::>("issuer", 0, 0); - - let project_metadata = default_project_metadata::(issuer.clone()); - let target_funding_amount: BalanceOf = - project_metadata.minimum_price.saturating_mul_int(project_metadata.total_allocation_size); - let manual_outcome_threshold = Percent::from_percent(50); - - let bids: Vec> = inst.generate_bids_from_total_usd( - (manual_outcome_threshold * target_funding_amount) / 2.into(), - project_metadata.minimum_price, - default_weights(), - default_bidders::(), - default_bidder_multipliers(), - ); - let contributions = inst.generate_contributions_from_total_usd( - (manual_outcome_threshold * target_funding_amount) / 2.into(), - project_metadata.minimum_price, - default_weights(), - default_community_contributors::(), - default_community_contributor_multipliers(), - ); - - let project_id = inst.create_finished_project( - project_metadata, - issuer.clone(), - None, - default_evaluations::(), - bids, - contributions, - vec![], - ); - - #[block] - { - Pallet::::do_project_decision(project_id, FundingOutcomeDecision::AcceptFunding).unwrap(); - } - - // * validity checks * - let project_details = inst.get_project_details(project_id); - assert_eq!(project_details.status, ProjectStatus::FundingSuccessful); - } - - // do_start_settlement - #[benchmark] - fn start_settlement_funding_success() { - // setup - let mut inst = BenchInstantiator::::new(None); - ::SetPrices::set_prices(); - - let issuer = account::>("issuer", 0, 0); - - let project_metadata = default_project_metadata::(issuer.clone()); - let project_id = inst.create_finished_project( - project_metadata, - issuer.clone(), - None, - default_evaluations::(), - default_bids::(), - default_community_contributions::(), - vec![], - ); - - #[block] - { - Pallet::::do_start_settlement(project_id).unwrap(); - } - - // * validity checks * - let project_details = inst.get_project_details(project_id); - assert_eq!(project_details.status, ProjectStatus::SettlementStarted(FundingOutcome::Success)); - } - - #[benchmark] - fn start_settlement_funding_failure() { - // setup - let mut inst = BenchInstantiator::::new(None); - ::SetPrices::set_prices(); - - let issuer = account::>("issuer", 0, 0); - - let project_metadata = default_project_metadata::(issuer.clone()); - let target_funding_amount: BalanceOf = - project_metadata.minimum_price.saturating_mul_int(project_metadata.total_allocation_size); - - let bids: Vec> = inst.generate_bids_from_total_usd( - Percent::from_percent(15) * target_funding_amount, - project_metadata.minimum_price, - default_weights(), - default_bidders::(), - default_bidder_multipliers(), - ); - - let contributions = inst.generate_contributions_from_total_usd( - Percent::from_percent(10) * target_funding_amount, - project_metadata.minimum_price, - default_weights(), - default_community_contributors::(), - default_community_contributor_multipliers(), - ); - - let project_id = inst.create_finished_project( - project_metadata, - issuer.clone(), - None, - default_evaluations::(), - bids, - contributions, - vec![], - ); - - assert_eq!(inst.get_project_details(project_id).status, ProjectStatus::FundingFailed); - - #[block] - { - Pallet::::do_start_settlement(project_id).unwrap(); - } + ); // * validity checks * - let project_details = inst.get_project_details(project_id); - assert_eq!(project_details.status, ProjectStatus::SettlementStarted(FundingOutcome::Failure)); + // Storage + assert!(Contributions::::get((project_id, contributor.clone(), contribution_to_settle.id)).is_none()); + + // Balances + let ct_amount = inst.get_ct_asset_balances_for(project_id, vec![contributor.clone()])[0]; + assert_eq!(contribution_to_settle.ct_amount, ct_amount); + inst.assert_plmc_held_balance( + contributor.clone(), + contribution_to_settle.plmc_bond, + HoldReason::Participation(project_id).into(), + ); + assert_eq!( + ::Vesting::total_scheduled_amount(&contributor, HoldReason::Participation(project_id).into()), + Some(contribution_to_settle.plmc_bond) + ); + let funding_account = project_metadata.funding_destination_account; + inst.assert_funding_asset_free_balance( + funding_account, + AcceptedFundingAsset::USDT.id(), + contribution_to_settle.funding_asset_amount, + ); + + // Events + frame_system::Pallet::::assert_last_event( + Event::ContributionSettled { + project_id, + account: contributor.clone(), + id: contribution_to_settle.id, + ct_amount, + } + .into(), + ); } #[benchmark] - fn start_pallet_migration() { + fn mark_project_as_settled() { // setup let mut inst = BenchInstantiator::::new(None); ::SetPrices::set_prices(); let issuer = account::>("issuer", 0, 0); + let anyone = account::>("anyone", 0, 0); + whitelist_account!(anyone); let project_metadata = default_project_metadata::(issuer.clone()); - let project_id = inst.create_finished_project( + let project_id = inst.create_settled_project( project_metadata.clone(), issuer.clone(), None, @@ -2698,37 +1537,15 @@ mod benchmarks { default_bids::(), default_community_contributions::(), vec![], - ); - - let settlement_block = inst.go_to_next_state(project_id).unwrap(); - inst.jump_to_block(settlement_block); - - inst.settle_project(project_id, true).unwrap(); - - let jwt = get_mock_jwt_with_cid( - issuer.clone(), - InvestorType::Institutional, - generate_did_from_account(issuer.clone()), - project_metadata.clone().policy_ipfs_cid.unwrap(), + false, ); #[extrinsic_call] - start_pallet_migration(RawOrigin::Signed(issuer), jwt, project_id, ParaId::from(6969)); + mark_project_as_settled(RawOrigin::Signed(anyone), project_id); // * validity checks * let project_details = inst.get_project_details(project_id); - assert_eq!(project_details.status, ProjectStatus::CTMigrationStarted); - assert_eq!( - project_details.migration_type, - Some(MigrationType::Pallet(PalletMigrationInfo { - parachain_id: ParaId::from(6969), - hrmp_channel_status: HRMPChannelStatus { - project_to_polimec: ChannelStatus::Closed, - polimec_to_project: ChannelStatus::Closed - }, - migration_readiness_check: None, - })) - ) + assert_eq!(project_details.status, ProjectStatus::SettlementFinished(FundingOutcome::Success)); } #[benchmark] @@ -2740,7 +1557,7 @@ mod benchmarks { let issuer = account::>("issuer", 0, 0); let project_metadata = default_project_metadata::(issuer.clone()); - let project_id = inst.create_finished_project( + let project_id = inst.create_settled_project( project_metadata.clone(), issuer.clone(), None, @@ -2748,13 +1565,9 @@ mod benchmarks { default_bids::(), default_community_contributions::(), vec![], + true, ); - let settlement_block = inst.go_to_next_state(project_id).unwrap(); - inst.jump_to_block(settlement_block); - - inst.settle_project(project_id, true).unwrap(); - let jwt = get_mock_jwt_with_cid( issuer.clone(), InvestorType::Institutional, @@ -2811,7 +1624,7 @@ mod benchmarks { bids.extend(participant_bids); let project_metadata = default_project_metadata::(issuer.clone()); - let project_id = inst.create_finished_project( + let project_id = inst.create_settled_project( project_metadata.clone(), issuer.clone(), None, @@ -2819,13 +1632,9 @@ mod benchmarks { bids, default_community_contributions::(), participant_contributions, + true, ); - let settlement_block = inst.go_to_next_state(project_id).unwrap(); - inst.jump_to_block(settlement_block); - - inst.settle_project(project_id, true).unwrap(); - let jwt = get_mock_jwt_with_cid( issuer.clone(), InvestorType::Institutional, @@ -2833,7 +1642,7 @@ mod benchmarks { project_metadata.clone().policy_ipfs_cid.unwrap(), ); - crate::Pallet::::start_offchain_migration(RawOrigin::Signed(issuer.clone()).into(), jwt.clone(), project_id) + >::start_offchain_migration(RawOrigin::Signed(issuer.clone()).into(), jwt.clone(), project_id) .unwrap(); let participant_migrations_len = UserMigrations::::get((project_id, participant.clone())).unwrap().1.len(); @@ -2849,7 +1658,7 @@ mod benchmarks { } #[benchmark] - fn mark_project_ct_migration_as_finished() { + fn start_pallet_migration() { // setup let mut inst = BenchInstantiator::::new(None); ::SetPrices::set_prices(); @@ -2857,7 +1666,7 @@ mod benchmarks { let issuer = account::>("issuer", 0, 0); let project_metadata = default_project_metadata::(issuer.clone()); - let project_id = inst.create_finished_project( + let project_id = inst.create_settled_project( project_metadata.clone(), issuer.clone(), None, @@ -2865,13 +1674,9 @@ mod benchmarks { default_bids::(), default_community_contributions::(), vec![], + true, ); - let settlement_block = inst.go_to_next_state(project_id).unwrap(); - inst.jump_to_block(settlement_block); - - inst.settle_project(project_id, true).unwrap(); - let jwt = get_mock_jwt_with_cid( issuer.clone(), InvestorType::Institutional, @@ -2879,32 +1684,23 @@ mod benchmarks { project_metadata.clone().policy_ipfs_cid.unwrap(), ); - crate::Pallet::::start_offchain_migration(RawOrigin::Signed(issuer.clone()).into(), jwt.clone(), project_id) - .unwrap(); - - let participants = UserMigrations::::iter_key_prefix((project_id,)).collect_vec(); - for participant in participants { - >::confirm_offchain_migration( - RawOrigin::Signed(issuer.clone().clone()).into(), - project_id, - participant, - ) - .unwrap() - } - #[extrinsic_call] - mark_project_ct_migration_as_finished(RawOrigin::Signed(issuer), project_id); + start_pallet_migration(RawOrigin::Signed(issuer), jwt, project_id, ParaId::from(6969)); // * validity checks * let project_details = inst.get_project_details(project_id); - assert_eq!(project_details.status, ProjectStatus::CTMigrationFinished); - assert_eq!(UnmigratedCounter::::get(project_id), 0); + assert_eq!(project_details.status, ProjectStatus::CTMigrationStarted); assert_eq!( - UserMigrations::::iter_prefix_values((project_id,)) - .map(|item| item.0) - .all(|status| status == MigrationStatus::Confirmed), - true - ); + project_details.migration_type, + Some(MigrationType::Pallet(PalletMigrationInfo { + parachain_id: ParaId::from(6969), + hrmp_channel_status: HRMPChannelStatus { + project_to_polimec: ChannelStatus::Closed, + polimec_to_project: ChannelStatus::Closed + }, + migration_readiness_check: None, + })) + ) } #[benchmark] @@ -2916,7 +1712,7 @@ mod benchmarks { let issuer = account::>("issuer", 0, 0); let project_metadata = default_project_metadata::(issuer.clone()); - let project_id = inst.create_finished_project( + let project_id = inst.create_settled_project( project_metadata.clone(), issuer.clone(), None, @@ -2924,13 +1720,9 @@ mod benchmarks { default_bids::(), default_community_contributions::(), vec![], + true, ); - let settlement_block = inst.go_to_next_state(project_id).unwrap(); - inst.jump_to_block(settlement_block); - - inst.settle_project(project_id, true).unwrap(); - let jwt = get_mock_jwt_with_cid( issuer.clone(), InvestorType::Institutional, @@ -2979,7 +1771,7 @@ mod benchmarks { let issuer = account::>("issuer", 0, 0); let project_metadata = default_project_metadata::(issuer.clone()); - let project_id = inst.create_finished_project( + let project_id = inst.create_settled_project( project_metadata.clone(), issuer.clone(), None, @@ -2987,13 +1779,9 @@ mod benchmarks { default_bids::(), default_community_contributions::(), vec![], + true, ); - let settlement_block = inst.go_to_next_state(project_id).unwrap(); - inst.jump_to_block(settlement_block); - - inst.settle_project(project_id, true).unwrap(); - let jwt = get_mock_jwt_with_cid( issuer.clone(), InvestorType::Institutional, @@ -3001,7 +1789,7 @@ mod benchmarks { project_metadata.clone().policy_ipfs_cid.unwrap(), ); - crate::Pallet::::start_pallet_migration( + >::start_pallet_migration( RawOrigin::Signed(issuer.clone()).into(), jwt.clone(), project_id, @@ -3022,7 +1810,7 @@ mod benchmarks { ProjectsDetails::::insert(project_id, project_details); // Create query id's - crate::Pallet::::do_start_pallet_migration_readiness_check( + >::do_start_pallet_migration_readiness_check( &T::PalletId::get().into_account_truncating(), project_id, ) @@ -3060,7 +1848,7 @@ mod benchmarks { let issuer = account::>("issuer", 0, 0); let project_metadata = default_project_metadata::(issuer.clone()); - let project_id = inst.create_finished_project( + let project_id = inst.create_settled_project( project_metadata.clone(), issuer.clone(), None, @@ -3068,13 +1856,9 @@ mod benchmarks { default_bids::(), default_community_contributions::(), vec![], + true, ); - let settlement_block = inst.go_to_next_state(project_id).unwrap(); - inst.jump_to_block(settlement_block); - - inst.settle_project(project_id, true).unwrap(); - let jwt = get_mock_jwt_with_cid( issuer.clone(), InvestorType::Institutional, @@ -3082,7 +1866,7 @@ mod benchmarks { project_metadata.clone().policy_ipfs_cid.unwrap(), ); - crate::Pallet::::start_pallet_migration( + >::start_pallet_migration( RawOrigin::Signed(issuer.clone()).into(), jwt.clone(), project_id, @@ -3182,7 +1966,7 @@ mod benchmarks { bids.extend(participant_bids); let project_metadata = default_project_metadata::(issuer.clone()); - let project_id = inst.create_finished_project( + let project_id = inst.create_settled_project( project_metadata.clone(), issuer.clone(), None, @@ -3190,13 +1974,9 @@ mod benchmarks { bids, default_community_contributions::(), participant_contributions, + true, ); - let settlement_block = inst.go_to_next_state(project_id).unwrap(); - inst.jump_to_block(settlement_block); - - inst.settle_project(project_id, true).unwrap(); - let jwt = get_mock_jwt_with_cid( issuer.clone(), InvestorType::Institutional, @@ -3204,7 +1984,7 @@ mod benchmarks { project_metadata.clone().policy_ipfs_cid.unwrap(), ); - crate::Pallet::::start_pallet_migration( + >::start_pallet_migration( RawOrigin::Signed(issuer.clone()).into(), jwt.clone(), project_id, @@ -3277,7 +2057,7 @@ mod benchmarks { bids.extend(participant_bids); let project_metadata = default_project_metadata::(issuer.clone()); - let project_id = inst.create_finished_project( + let project_id = inst.create_settled_project( project_metadata.clone(), issuer.clone(), None, @@ -3285,13 +2065,9 @@ mod benchmarks { bids, default_community_contributions::(), participant_contributions, + true, ); - let settlement_block = inst.go_to_next_state(project_id).unwrap(); - inst.jump_to_block(settlement_block); - - inst.settle_project(project_id, true).unwrap(); - let jwt = get_mock_jwt_with_cid( issuer.clone(), InvestorType::Institutional, @@ -3322,19 +2098,15 @@ mod benchmarks { })); ProjectsDetails::::insert(project_id, project_details); - crate::Pallet::::send_pallet_migration_for( - RawOrigin::Signed(issuer).into(), - project_id, - participant.clone(), - ) - .unwrap(); + >::send_pallet_migration_for(RawOrigin::Signed(issuer).into(), project_id, participant.clone()) + .unwrap(); let project_location = MultiLocation::new(1, X1(Parachain(6969))); let xcm_response = Response::DispatchResult(MaybeErrorCode::Success); #[block] { - crate::Pallet::::do_confirm_pallet_migrations(project_location, 0, xcm_response).unwrap(); + >::do_confirm_pallet_migrations(project_location, 0, xcm_response).unwrap(); } // * validity checks * @@ -3353,7 +2125,7 @@ mod benchmarks { let issuer = account::>("issuer", 0, 0); let project_metadata = default_project_metadata::(issuer.clone()); - let project_id = inst.create_finished_project( + let project_id = inst.create_settled_project( project_metadata.clone(), issuer.clone(), None, @@ -3361,13 +2133,9 @@ mod benchmarks { default_bids::(), default_community_contributions::(), vec![], + true, ); - let settlement_block = inst.go_to_next_state(project_id).unwrap(); - inst.jump_to_block(settlement_block); - - inst.settle_project(project_id, true).unwrap(); - let jwt = get_mock_jwt_with_cid( issuer.clone(), InvestorType::Institutional, @@ -3375,7 +2143,7 @@ mod benchmarks { project_metadata.clone().policy_ipfs_cid.unwrap(), ); - crate::Pallet::::start_pallet_migration( + >::start_pallet_migration( RawOrigin::Signed(issuer.clone()).into(), jwt.clone(), project_id, @@ -3385,7 +2153,7 @@ mod benchmarks { #[block] { - crate::Pallet::::do_handle_channel_open_request(Instruction::HrmpNewChannelOpenRequest { + >::do_handle_channel_open_request(Instruction::HrmpNewChannelOpenRequest { sender: 6969u32, max_message_size: 102_400u32, max_capacity: 1000, @@ -3403,7 +2171,7 @@ mod benchmarks { let issuer = account::>("issuer", 0, 0); let project_metadata = default_project_metadata::(issuer.clone()); - let project_id = inst.create_finished_project( + let project_id = inst.create_settled_project( project_metadata.clone(), issuer.clone(), None, @@ -3411,13 +2179,9 @@ mod benchmarks { default_bids::(), default_community_contributions::(), vec![], + true, ); - let settlement_block = inst.go_to_next_state(project_id).unwrap(); - inst.jump_to_block(settlement_block); - - inst.settle_project(project_id, true).unwrap(); - let jwt = get_mock_jwt_with_cid( issuer.clone(), InvestorType::Institutional, @@ -3425,7 +2189,7 @@ mod benchmarks { project_metadata.clone().policy_ipfs_cid.unwrap(), ); - crate::Pallet::::start_pallet_migration( + >::start_pallet_migration( RawOrigin::Signed(issuer.clone()).into(), jwt.clone(), project_id, @@ -3433,7 +2197,7 @@ mod benchmarks { ) .unwrap(); - crate::Pallet::::do_handle_channel_open_request(Instruction::HrmpNewChannelOpenRequest { + >::do_handle_channel_open_request(Instruction::HrmpNewChannelOpenRequest { sender: 6969u32, max_message_size: 102_400u32, max_capacity: 1000, @@ -3442,9 +2206,63 @@ mod benchmarks { #[block] { - crate::Pallet::::do_handle_channel_accepted(Instruction::HrmpChannelAccepted { recipient: 6969u32 }) - .unwrap(); + >::do_handle_channel_accepted(Instruction::HrmpChannelAccepted { recipient: 6969u32 }).unwrap(); + } + } + + #[benchmark] + fn mark_project_ct_migration_as_finished() { + // setup + let mut inst = BenchInstantiator::::new(None); + ::SetPrices::set_prices(); + + let issuer = account::>("issuer", 0, 0); + + let project_metadata = default_project_metadata::(issuer.clone()); + let project_id = inst.create_settled_project( + project_metadata.clone(), + issuer.clone(), + None, + default_evaluations::(), + default_bids::(), + default_community_contributions::(), + vec![], + true, + ); + + let jwt = get_mock_jwt_with_cid( + issuer.clone(), + InvestorType::Institutional, + generate_did_from_account(issuer.clone()), + project_metadata.clone().policy_ipfs_cid.unwrap(), + ); + + crate::Pallet::::start_offchain_migration(RawOrigin::Signed(issuer.clone()).into(), jwt.clone(), project_id) + .unwrap(); + + let participants = UserMigrations::::iter_key_prefix((project_id,)).collect_vec(); + for participant in participants { + >::confirm_offchain_migration( + RawOrigin::Signed(issuer.clone().clone()).into(), + project_id, + participant, + ) + .unwrap() } + + #[extrinsic_call] + mark_project_ct_migration_as_finished(RawOrigin::Signed(issuer), project_id); + + // * validity checks * + let project_details = inst.get_project_details(project_id); + assert_eq!(project_details.status, ProjectStatus::CTMigrationFinished); + assert_eq!(UnmigratedCounter::::get(project_id), 0); + assert_eq!( + UserMigrations::::iter_prefix_values((project_id,)) + .map(|item| item.0) + .all(|status| status == MigrationStatus::Confirmed), + true + ); } #[cfg(test)] @@ -3474,94 +2292,16 @@ mod benchmarks { } #[test] - fn bench_evaluation() { - new_test_ext().execute_with(|| { - assert_ok!(PalletFunding::::test_evaluation()); - }); - } - - #[test] - fn bench_start_auction_manually() { - new_test_ext().execute_with(|| { - assert_ok!(PalletFunding::::test_start_auction_manually()); - }); - } - - #[test] - fn bench_bid() { - new_test_ext().execute_with(|| { - assert_ok!(PalletFunding::::test_bid()); - }); - } - - #[test] - fn bench_contribution() { - new_test_ext().execute_with(|| { - assert_ok!(PalletFunding::::test_contribution()); - }); - } - - #[test] - fn bench_contribution_ends_round() { - new_test_ext().execute_with(|| { - assert_ok!(PalletFunding::::test_contribution_ends_round()); - }); - } - - #[test] - fn bench_decide_project_outcome() { - new_test_ext().execute_with(|| { - assert_ok!(PalletFunding::::test_decide_project_outcome()); - }); - } - - #[test] - fn bench_settle_successful_evaluation() { - new_test_ext().execute_with(|| { - assert_ok!(PalletFunding::::test_settle_successful_evaluation()); - }); - } - - #[test] - fn bench_settle_failed_evaluation() { - new_test_ext().execute_with(|| { - assert_ok!(PalletFunding::::test_settle_failed_evaluation()); - }); - } - - #[test] - fn bench_settle_successful_bid() { - new_test_ext().execute_with(|| { - assert_ok!(PalletFunding::::test_settle_successful_bid()); - }); - } - - #[test] - fn bench_settle_failed_bid() { - new_test_ext().execute_with(|| { - assert_ok!(PalletFunding::::test_settle_failed_bid()); - }); - } - - #[test] - fn bench_settle_successful_contribution() { - new_test_ext().execute_with(|| { - assert_ok!(PalletFunding::::test_settle_successful_contribution()); - }); - } - - #[test] - fn bench_settle_failed_contribution() { + fn bench_start_evaluation() { new_test_ext().execute_with(|| { - assert_ok!(PalletFunding::::test_settle_failed_contribution()); + assert_ok!(PalletFunding::::test_start_evaluation()); }); } - // on_initialize benches #[test] - fn bench_end_evaluation_success() { + fn bench_evaluate() { new_test_ext().execute_with(|| { - assert_ok!(PalletFunding::::test_end_evaluation_success()); + assert_ok!(PalletFunding::::test_evaluate()); }); } @@ -3573,86 +2313,72 @@ mod benchmarks { } #[test] - fn bench_start_auction_closing_phase() { - new_test_ext().execute_with(|| { - assert_ok!(PalletFunding::::test_start_auction_closing_phase()); - }); - } - - #[test] - fn bench_end_auction_closing() { - new_test_ext().execute_with(|| { - assert_ok!(PalletFunding::::test_end_auction_closing()); - }); - } - - #[test] - fn bench_start_community_funding() { + fn bench_start_auction() { new_test_ext().execute_with(|| { - assert_ok!(PalletFunding::::test_start_community_funding()); + assert_ok!(PalletFunding::::test_start_auction()); }); } #[test] - fn bench_start_remainder_funding() { + fn bench_bid() { new_test_ext().execute_with(|| { - assert_ok!(PalletFunding::::test_start_remainder_funding()); + assert_ok!(PalletFunding::::test_bid()); }); } #[test] - fn bench_start_settlement_funding_success() { + fn bench_end_auction() { new_test_ext().execute_with(|| { - assert_ok!(PalletFunding::::test_start_settlement_funding_success()); + assert_ok!(PalletFunding::::test_end_auction()); }); } #[test] - fn bench_start_settlement_funding_failure() { + fn bench_contribute() { new_test_ext().execute_with(|| { - assert_ok!(PalletFunding::::test_start_settlement_funding_failure()); + assert_ok!(PalletFunding::::test_contribute()); }); } #[test] - fn bench_project_decision() { + fn bench_end_funding_project_successful() { new_test_ext().execute_with(|| { - assert_ok!(PalletFunding::::test_project_decision()); + assert_ok!(PalletFunding::::test_end_funding_project_successful()); }); } #[test] - fn bench_end_funding_automatically_rejected_evaluators_slashed() { + fn bench_start_settlement() { new_test_ext().execute_with(|| { - assert_ok!(PalletFunding::::test_end_funding_automatically_rejected_evaluators_slashed()); + assert_ok!(PalletFunding::::test_start_settlement()); }); } #[test] - fn bench_end_funding_automatically_accepted_evaluators_rewarded() { + fn bench_settle_rewarded_evaluation() { new_test_ext().execute_with(|| { - assert_ok!(PalletFunding::::test_end_funding_automatically_accepted_evaluators_rewarded()); + assert_ok!(PalletFunding::::test_settle_rewarded_evaluation()); }); } #[test] - fn bench_end_funding_awaiting_decision_evaluators_unchanged() { + fn bench_settle_accepted_bid_with_refund() { new_test_ext().execute_with(|| { - assert_ok!(PalletFunding::::test_end_funding_awaiting_decision_evaluators_unchanged()); + assert_ok!(PalletFunding::::test_settle_accepted_bid_with_refund()); }); } #[test] - fn bench_end_funding_awaiting_decision_evaluators_slashed() { + fn bench_settle_contribution_project_successful() { new_test_ext().execute_with(|| { - assert_ok!(PalletFunding::::test_end_funding_awaiting_decision_evaluators_slashed()); + assert_ok!(PalletFunding::::test_settle_contribution_project_successful()); }); } #[test] - fn bench_start_pallet_migration() { + fn bench_mark_project_as_settled() { new_test_ext().execute_with(|| { - assert_ok!(PalletFunding::::test_start_pallet_migration()); + assert_ok!(PalletFunding::::test_mark_project_as_settled()); }); } @@ -3678,16 +2404,16 @@ mod benchmarks { } #[test] - fn bench_start_pallet_migration_readiness_check() { + fn bench_start_pallet_migration() { new_test_ext().execute_with(|| { - assert_ok!(PalletFunding::::test_start_pallet_migration_readiness_check()); + assert_ok!(PalletFunding::::test_start_pallet_migration()); }); } #[test] - fn bench_pallet_migration_readiness_response_holding() { + fn bench_start_pallet_migration_readiness_check() { new_test_ext().execute_with(|| { - assert_ok!(PalletFunding::::test_pallet_migration_readiness_response_holding()); + assert_ok!(PalletFunding::::test_start_pallet_migration_readiness_check()); }); } diff --git a/pallets/funding/src/functions/5_funding_end.rs b/pallets/funding/src/functions/5_funding_end.rs index ee0314356..8a06942b4 100644 --- a/pallets/funding/src/functions/5_funding_end.rs +++ b/pallets/funding/src/functions/5_funding_end.rs @@ -44,7 +44,7 @@ impl Pallet { // Can end due to running out of CTs remaining_cts == Zero::zero() || // or the last funding round ending - now > round_end_block && matches!(project_details.status, ProjectStatus::CommunityRound(..)), + now >= round_end_block && matches!(project_details.status, ProjectStatus::CommunityRound(..)), Error::::TooEarlyForRound ); diff --git a/pallets/funding/src/instantiator/calculations.rs b/pallets/funding/src/instantiator/calculations.rs index f2962a5bf..db6db4eca 100644 --- a/pallets/funding/src/instantiator/calculations.rs +++ b/pallets/funding/src/instantiator/calculations.rs @@ -697,14 +697,17 @@ impl< } // We assume a single bid can cover the whole first bucket. Make sure the ticket sizes allow this. - pub fn generate_bids_from_bucket( + pub fn generate_bids_from_bucket( &self, project_metadata: ProjectMetadataOf, bucket: BucketOf, mut starting_account: AccountIdOf, - increment_account: fn(AccountIdOf) -> AccountIdOf, + mut increment_account: F, funding_asset: AcceptedFundingAsset, - ) -> Vec> { + ) -> Vec> + where + F: FnMut(AccountIdOf) -> AccountIdOf, + { if bucket.current_price == bucket.initial_price { return vec![] } @@ -741,13 +744,16 @@ impl< bids } - pub fn generate_bids_that_take_price_to( + pub fn generate_bids_that_take_price_to( &self, project_metadata: ProjectMetadataOf, desired_price: PriceOf, bidder_account: AccountIdOf, - next_bidder_account: fn(AccountIdOf) -> AccountIdOf, - ) -> Vec> { + next_bidder_account: F, + ) -> Vec> + where + F: FnMut(AccountIdOf) -> AccountIdOf, + { let necessary_bucket = self.find_bucket_for_wap(project_metadata.clone(), desired_price); self.generate_bids_from_bucket( project_metadata, @@ -774,4 +780,12 @@ impl< project_metadata.auction_round_allocation_percentage * project_metadata.total_allocation_size; bucket.calculate_wap(auction_allocation) } + + pub fn remainder_round_block(&self) -> BlockNumberFor { + T::EvaluationRoundDuration::get() + + T::AuctionInitializePeriodDuration::get() + + T::AuctionRoundDuration::get() + + T::CommunityRoundDuration::get() + + One::one() + } } diff --git a/pallets/funding/src/instantiator/chain_interactions.rs b/pallets/funding/src/instantiator/chain_interactions.rs index 3be82baf8..c0b6f86ce 100644 --- a/pallets/funding/src/instantiator/chain_interactions.rs +++ b/pallets/funding/src/instantiator/chain_interactions.rs @@ -1042,6 +1042,7 @@ impl< bids: Vec>, community_contributions: Vec>, remainder_contributions: Vec>, + mark_as_settled: bool, ) -> ProjectId { let project_id = self.create_finished_project( project_metadata.clone(), @@ -1055,7 +1056,7 @@ impl< assert!(matches!(self.go_to_next_state(project_id), ProjectStatus::SettlementStarted(_))); - self.settle_project(project_id, true); + self.settle_project(project_id, mark_as_settled); project_id } diff --git a/pallets/funding/src/instantiator/types.rs b/pallets/funding/src/instantiator/types.rs index 781531b9b..bb95d752f 100644 --- a/pallets/funding/src/instantiator/types.rs +++ b/pallets/funding/src/instantiator/types.rs @@ -374,8 +374,6 @@ pub struct BidInfoFilter { pub status: Option>>, pub original_ct_amount: Option>, pub original_ct_usd_price: Option>, - pub final_ct_amount: Option>, - pub final_ct_usd_price: Option>, pub funding_asset: Option, pub funding_asset_amount_locked: Option>, pub multiplier: Option>, @@ -432,8 +430,6 @@ impl Default for BidInfoFilter { status: None, original_ct_amount: None, original_ct_usd_price: None, - final_ct_amount: None, - final_ct_usd_price: None, funding_asset: None, funding_asset_amount_locked: None, multiplier: None, diff --git a/pallets/funding/src/mock.rs b/pallets/funding/src/mock.rs index f1af4d0f5..95ab87034 100644 --- a/pallets/funding/src/mock.rs +++ b/pallets/funding/src/mock.rs @@ -339,7 +339,7 @@ impl pallet_linear_release::Config for TestRuntime { type UnvestedFundsAllowedWithdrawReasons = UnvestedFundsAllowedWithdrawReasons; type WeightInfo = (); - const MAX_VESTING_SCHEDULES: u32 = 32; + const MAX_VESTING_SCHEDULES: u32 = 100; } parameter_types! { diff --git a/pallets/funding/src/tests/misc.rs b/pallets/funding/src/tests/misc.rs index 518324bab..b61b43daf 100644 --- a/pallets/funding/src/tests/misc.rs +++ b/pallets/funding/src/tests/misc.rs @@ -378,6 +378,7 @@ fn project_state_transition_event() { default_bids(), default_community_contributions(), default_remainder_contributions(), + true, ); let events = inst.execute(|| System::events()); diff --git a/pallets/funding/src/tests/runtime_api.rs b/pallets/funding/src/tests/runtime_api.rs index 4993b530e..2e940376f 100644 --- a/pallets/funding/src/tests/runtime_api.rs +++ b/pallets/funding/src/tests/runtime_api.rs @@ -238,6 +238,7 @@ fn contribution_tokens() { default_bids(), contributions_with_bob_1, default_remainder_contributions(), + true, ); let _project_id_2 = inst.create_settled_project( default_project_metadata(ISSUER_2), @@ -247,6 +248,7 @@ fn contribution_tokens() { default_bids(), default_community_contributions(), default_remainder_contributions(), + true, ); let _project_id_3 = inst.create_settled_project( default_project_metadata(ISSUER_3), @@ -256,6 +258,7 @@ fn contribution_tokens() { default_bids(), default_community_contributions(), default_remainder_contributions(), + true, ); let project_id_4 = inst.create_settled_project( default_project_metadata(ISSUER_4), @@ -265,6 +268,7 @@ fn contribution_tokens() { default_bids(), contributions_with_bob_2, default_remainder_contributions(), + true, ); let _project_id_5 = inst.create_settled_project( default_project_metadata(ISSUER_5), @@ -274,6 +278,7 @@ fn contribution_tokens() { default_bids(), default_community_contributions(), default_remainder_contributions(), + true, ); let project_id_6 = inst.create_settled_project( default_project_metadata(ISSUER_6), @@ -283,6 +288,7 @@ fn contribution_tokens() { default_bids(), contributions_with_bob_3, default_remainder_contributions(), + true, ); let project_id_7 = inst.create_settled_project( default_project_metadata(ISSUER_7), @@ -292,6 +298,7 @@ fn contribution_tokens() { default_bids(), contributions_with_bob_4, default_remainder_contributions(), + true, ); let expected_items = vec![ @@ -658,6 +665,7 @@ fn projects_by_did() { default_bids(), default_community_contributions(), default_remainder_contributions(), + true, ); let _project_id_2 = inst.create_settled_project( @@ -668,6 +676,7 @@ fn projects_by_did() { default_bids(), default_community_contributions(), default_remainder_contributions(), + true, ); let project_id_3 = inst.create_settled_project( @@ -678,6 +687,7 @@ fn projects_by_did() { default_bids(), default_community_contributions(), default_remainder_contributions(), + true, ); let _project_id_4 = inst.create_settled_project( @@ -688,6 +698,7 @@ fn projects_by_did() { default_bids(), default_community_contributions(), default_remainder_contributions(), + true, ); inst.execute(|| { diff --git a/pallets/funding/src/types.rs b/pallets/funding/src/types.rs index ab6f041d7..71028cb83 100644 --- a/pallets/funding/src/types.rs +++ b/pallets/funding/src/types.rs @@ -762,17 +762,6 @@ pub mod inner_types { pub duration: BlockNumber, } - #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] - pub enum ProjectPhases { - Evaluation, - AuctionInitializePeriod, - Auction, - CommunityFunding, - FundingFinalization, - Settlement, - Migration, - } - #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] pub struct EvaluationRoundInfo { pub total_bonded_usd: Balance, diff --git a/pallets/linear-release/src/lib.rs b/pallets/linear-release/src/lib.rs index d34db5b4d..86ffb8c02 100644 --- a/pallets/linear-release/src/lib.rs +++ b/pallets/linear-release/src/lib.rs @@ -156,35 +156,6 @@ pub mod pallet { } } - // #[pallet::genesis_build] - // impl BuildGenesisConfig for GenesisConfig { - // fn build(&self) { - // use sp_runtime::traits::Saturating; - - // // Generate initial vesting configuration - // // * who - Account which we are generating vesting configuration for - // // * begin - Block when the account will start to vest - // // * length - Number of blocks from `begin` until fully vested - // // * liquid - Number of units which can be spent before vesting begins - // for &(ref who, begin, length, liquid, reason) in self.vesting.iter() { - // let balance = T::Currency::balance(who); - // assert!(!balance.is_zero(), "Currencies must be init'd before vesting"); - // // Total genesis `balance` minus `liquid` equals funds locked for vesting - // let locked = balance.saturating_sub(liquid); - // let length_as_balance = T::BlockNumberToBalance::convert(length); - // let per_block = locked / length_as_balance.max(sp_runtime::traits::One::one()); - // let vesting_info = VestingInfo::new(locked, per_block, begin); - // if !vesting_info.is_valid() { - // panic!("Invalid VestingInfo params at genesis") - // }; - - // Vesting::::try_append(who, reason, vesting_info).expect("Too many vesting schedules at genesis."); - - // T::Currency::hold(&reason, who, locked).map_err(|err| panic!("{:?}", err)).unwrap(); - // } - // } - // } - #[pallet::hooks] impl Hooks> for Pallet { fn integrity_test() {