diff --git a/integration-tests/src/tests/evaluator_slash_sideffects.rs b/integration-tests/src/tests/evaluator_slash_sideffects.rs index bf9633842..646a52263 100644 --- a/integration-tests/src/tests/evaluator_slash_sideffects.rs +++ b/integration-tests/src/tests/evaluator_slash_sideffects.rs @@ -78,8 +78,7 @@ fn evaluator_slash_reduces_vesting_schedules() { )); let alice_evaluation = UserToUSDBalance::::new(alice.clone(), 35_000 * USD_UNIT); - let alice_plmc_evaluated = - inst.calculate_evaluation_plmc_spent(vec![alice_evaluation.clone()], false)[0].plmc_amount; + let alice_plmc_evaluated = inst.calculate_evaluation_plmc_spent(vec![alice_evaluation.clone()])[0].plmc_amount; let alice_slashed = slash_percent * alice_plmc_evaluated; const BOB_EVALUATION: u128 = 60_000; @@ -94,8 +93,7 @@ fn evaluator_slash_reduces_vesting_schedules() { vesting_info_5 )); let bob_evaluation = UserToUSDBalance::::new(bob.clone(), BOB_EVALUATION * USD_UNIT); - let bob_plmc_evaluated = - inst.calculate_evaluation_plmc_spent(vec![bob_evaluation.clone()], false)[0].plmc_amount; + let bob_plmc_evaluated = inst.calculate_evaluation_plmc_spent(vec![bob_evaluation.clone()])[0].plmc_amount; let bob_slashed = slash_percent * bob_plmc_evaluated; // Set metadata so 50k USD succeeds the evaluation round diff --git a/integration-tests/src/tests/otm_edge_cases.rs b/integration-tests/src/tests/otm_edge_cases.rs index 4ea8236cc..bec65cd02 100644 --- a/integration-tests/src/tests/otm_edge_cases.rs +++ b/integration-tests/src/tests/otm_edge_cases.rs @@ -181,12 +181,7 @@ fn after_otm_fee_user_goes_under_ed_reverts() { pallet_funding::Error::::ParticipantNotEnoughFunds ); - inst.mint_funding_asset_to(vec![( - bobert.clone(), - usdt_ed, - AcceptedFundingAsset::USDT.id(), - ) - .into()]); + inst.mint_funding_asset_to(vec![(bobert.clone(), usdt_ed, AcceptedFundingAsset::USDT.id()).into()]); assert_ok!(PolimecFunding::contribute( PolimecOrigin::signed(bobert.clone()), diff --git a/pallets/funding/src/benchmarking.rs b/pallets/funding/src/benchmarking.rs index fafbe93ba..fb2c1f34a 100644 --- a/pallets/funding/src/benchmarking.rs +++ b/pallets/funding/src/benchmarking.rs @@ -503,9 +503,8 @@ mod benchmarks { let extrinsic_evaluation = UserToUSDBalance::new(test_evaluator.clone(), (1_000 * USD_UNIT).into()); let existing_evaluations = vec![existing_evaluation; x as usize]; - let plmc_for_existing_evaluations = inst.calculate_evaluation_plmc_spent(existing_evaluations.clone(), false); - let plmc_for_extrinsic_evaluation = - inst.calculate_evaluation_plmc_spent(vec![extrinsic_evaluation.clone()], false); + let plmc_for_existing_evaluations = inst.calculate_evaluation_plmc_spent(existing_evaluations.clone()); + let plmc_for_extrinsic_evaluation = inst.calculate_evaluation_plmc_spent(vec![extrinsic_evaluation.clone()]); let existential_plmc: Vec> = plmc_for_extrinsic_evaluation.accounts().existential_deposits(); @@ -609,8 +608,9 @@ mod benchmarks { (Percent::from_percent(25) * evaluation_usd_target).into(), ), ]; - let plmc_for_evaluating = inst.calculate_evaluation_plmc_spent(evaluations.clone(), true); + let plmc_for_evaluating = inst.calculate_evaluation_plmc_spent(evaluations.clone()); + inst.mint_plmc_ed_if_required(plmc_for_evaluating.accounts()); inst.mint_plmc_to(plmc_for_evaluating); inst.advance_time(One::one()); @@ -681,11 +681,8 @@ mod benchmarks { &existing_bids, project_metadata.clone(), None, - false, ); - let existential_deposits: Vec> = vec![bidder.clone()].existential_deposits(); - let usdt_for_existing_bids: Vec> = inst .calculate_auction_funding_asset_charged_from_all_bids_made_or_with_bucket( &existing_bids, @@ -694,10 +691,11 @@ mod benchmarks { ); let escrow_account = Pallet::::fund_account_id(project_id); let prev_total_escrow_usdt_locked = - inst.get_free_funding_asset_balances_for(usdt_id(), vec![escrow_account.clone()]); + inst.get_free_funding_asset_balances_for(vec![(escrow_account.clone(), usdt_id())]); + inst.mint_plmc_ed_if_required(plmc_for_existing_bids.accounts()); inst.mint_plmc_to(plmc_for_existing_bids.clone()); - inst.mint_plmc_to(existential_deposits.clone()); + inst.mint_funding_asset_ed_if_required(usdt_for_existing_bids.to_account_asset_map()); inst.mint_funding_asset_to(usdt_for_existing_bids.clone()); // do "x" contributions for this user @@ -716,7 +714,7 @@ mod benchmarks { // first lets bring the bucket to almost its limit with another bidder: assert!(new_bidder.clone() != bidder.clone()); let bid_params = BidParams::new( - new_bidder, + new_bidder.clone(), current_bucket.amount_left, ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, @@ -725,16 +723,16 @@ mod benchmarks { let plmc_for_new_bidder = inst.calculate_auction_plmc_charged_with_given_price( &vec![bid_params.clone()], current_bucket.current_price, - false, ); - let plmc_ed = plmc_for_new_bidder.accounts().existential_deposits(); let usdt_for_new_bidder = inst.calculate_auction_funding_asset_charged_with_given_price( &vec![bid_params.clone()], current_bucket.current_price, ); + inst.mint_plmc_ed_if_required(vec![(new_bidder.clone())]); inst.mint_plmc_to(plmc_for_new_bidder); - inst.mint_plmc_to(plmc_ed); + + inst.mint_funding_asset_ed_if_required(vec![(new_bidder, AcceptedFundingAsset::USDT.id())]); inst.mint_funding_asset_to(usdt_for_new_bidder.clone()); inst.bid_for_users(project_id, vec![bid_params]).unwrap(); @@ -763,7 +761,6 @@ mod benchmarks { &vec![extrinsic_bid.clone()], project_metadata.clone(), Some(current_bucket), - false, ); let usdt_for_extrinsic_bids: Vec> = inst .calculate_auction_funding_asset_charged_from_all_bids_made_or_with_bucket( @@ -771,13 +768,15 @@ mod benchmarks { project_metadata.clone(), Some(current_bucket), ); + inst.mint_plmc_ed_if_required(plmc_for_extrinsic_bids.accounts()); inst.mint_plmc_to(plmc_for_extrinsic_bids.clone()); + inst.mint_funding_asset_ed_if_required(usdt_for_extrinsic_bids.to_account_asset_map()); inst.mint_funding_asset_to(usdt_for_extrinsic_bids.clone()); - let total_free_plmc = existential_deposits[0].plmc_amount; + let total_free_plmc = inst.get_ed(); let total_plmc_participation_bonded = inst.sum_balance_mappings(vec![plmc_for_extrinsic_bids.clone(), plmc_for_existing_bids.clone()]); - let total_free_usdt = Zero::zero(); + let total_free_usdt = inst.get_funding_asset_ed(AcceptedFundingAsset::USDT.id()); let total_escrow_usdt_locked = inst.sum_funding_asset_mappings(vec![ prev_total_escrow_usdt_locked.clone(), usdt_for_extrinsic_bids.clone(), @@ -861,11 +860,10 @@ mod benchmarks { 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; + let locked_usdt = inst.get_free_funding_asset_balance_for(usdt_id(), escrow_account.clone()); 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; + let free_usdt = inst.get_free_funding_asset_balance_for(usdt_id(), bidder); assert_eq!(free_usdt, total_free_usdt); // Events @@ -978,7 +976,6 @@ mod benchmarks { &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( @@ -986,8 +983,9 @@ mod benchmarks { project_metadata.clone(), None, ); - + inst.mint_plmc_ed_if_required(plmc_needed_for_bids.accounts()); inst.mint_plmc_to(plmc_needed_for_bids); + inst.mint_funding_asset_ed_if_required(funding_asset_needed_for_bids.to_account_asset_map()); inst.mint_funding_asset_to(funding_asset_needed_for_bids); inst.bid_for_users(project_id, all_bids).unwrap(); @@ -1063,14 +1061,16 @@ mod benchmarks { x as usize + 1 ]; - let plmc = inst.calculate_contributed_plmc_spent(contributions.clone(), price, false); + let plmc = inst.calculate_contributed_plmc_spent(contributions.clone(), price); 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()]); + let prev_total_usdt_locked = + inst.get_free_funding_asset_balances_for(vec![(escrow_account.clone(), usdt_id())]); + inst.mint_plmc_ed_if_required(plmc.accounts()); inst.mint_plmc_to(plmc.clone()); - inst.mint_plmc_to(plmc.accounts().existential_deposits()); + inst.mint_funding_asset_ed_if_required(usdt.to_account_asset_map()); inst.mint_funding_asset_to(usdt.clone()); // do "x" contributions for this user @@ -1080,7 +1080,7 @@ mod benchmarks { let total_usdt_locked = inst.sum_funding_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 total_free_usdt = inst.get_funding_asset_ed(AcceptedFundingAsset::USDT.id()); let jwt = get_mock_jwt_with_cid( contributor.clone(), diff --git a/pallets/funding/src/instantiator/calculations.rs b/pallets/funding/src/instantiator/calculations.rs index bfeade94b..7e41d3d92 100644 --- a/pallets/funding/src/instantiator/calculations.rs +++ b/pallets/funding/src/instantiator/calculations.rs @@ -33,7 +33,6 @@ impl< pub fn calculate_evaluation_plmc_spent( &mut self, evaluations: Vec>, - with_ed: bool, ) -> Vec> { let plmc_usd_price = self.execute(|| { >::get_decimals_aware_price(PLMC_FOREIGN_ID, USD_DECIMALS, PLMC_DECIMALS).unwrap() @@ -42,10 +41,8 @@ impl< let mut output = Vec::new(); for eval in evaluations { let usd_bond = eval.usd_amount; - let mut plmc_bond = plmc_usd_price.reciprocal().unwrap().saturating_mul_int(usd_bond); - if with_ed { - plmc_bond = plmc_bond.saturating_add(self.get_ed()); - } + let plmc_bond = plmc_usd_price.reciprocal().unwrap().saturating_mul_int(usd_bond); + output.push(UserToPLMCBalance::new(eval.account, plmc_bond)); } output @@ -83,7 +80,6 @@ impl< &mut self, bids: &Vec>, ct_price: PriceOf, - with_ed: bool, ) -> Vec> { let mut output = Vec::new(); for bid in bids { @@ -92,9 +88,7 @@ impl< if let ParticipationMode::Classic(multiplier) = bid.mode { self.add_required_plmc_to(&mut plmc_required, usd_ticket_size, multiplier) } - if with_ed { - plmc_required = plmc_required.saturating_add(self.get_ed()); - } + output.push(UserToPLMCBalance::new(bid.bidder.clone(), plmc_required)); } output @@ -106,7 +100,6 @@ impl< bids: &Vec>, project_metadata: ProjectMetadataOf, maybe_bucket: Option>, - with_ed: bool, ) -> Vec> { let mut output = Vec::new(); @@ -116,9 +109,7 @@ impl< if let ParticipationMode::Classic(multiplier) = bid.mode { self.add_required_plmc_to(&mut plmc_required, usd_ticket_size, multiplier) } - if with_ed { - plmc_required = plmc_required.saturating_add(self.get_ed()); - } + output.push(UserToPLMCBalance::::new(bid.bidder.clone(), plmc_required)); } @@ -184,12 +175,8 @@ impl< project_metadata: ProjectMetadataOf, weighted_average_price: PriceOf, ) -> Vec> { - let plmc_charged = self.calculate_auction_plmc_charged_from_all_bids_made_or_with_bucket( - bids, - project_metadata.clone(), - None, - false, - ); + let plmc_charged = + self.calculate_auction_plmc_charged_from_all_bids_made_or_with_bucket(bids, project_metadata.clone(), None); let plmc_returned = self.calculate_auction_plmc_returned_from_all_bids_made( bids, project_metadata.clone(), @@ -341,7 +328,6 @@ impl< &mut self, contributions: Vec>, token_usd_price: PriceOf, - with_ed: bool, ) -> Vec> { let mut output = Vec::new(); for cont in contributions { @@ -351,9 +337,6 @@ impl< self.add_required_plmc_to(&mut plmc_bond, usd_ticket_size, multiplier); } - if with_ed { - plmc_bond = plmc_bond.saturating_add(self.get_ed()); - } output.push(UserToPLMCBalance::new(cont.contributor, plmc_bond)); } output @@ -367,10 +350,9 @@ impl< slashed: bool, with_ed: bool, ) -> Vec> { - let evaluation_locked_plmc_amounts = self.calculate_evaluation_plmc_spent(evaluations, false); + let evaluation_locked_plmc_amounts = self.calculate_evaluation_plmc_spent(evaluations); // how much new plmc would be locked without considering evaluation bonds - let theoretical_contribution_locked_plmc_amounts = - self.calculate_contributed_plmc_spent(contributions, price, false); + let theoretical_contribution_locked_plmc_amounts = self.calculate_contributed_plmc_spent(contributions, price); let slash_percentage = ::EvaluatorSlash::get(); let slashable_min_deposits = evaluation_locked_plmc_amounts @@ -420,6 +402,7 @@ impl< if cont.mode == ParticipationMode::OTM { self.add_otm_fee_to(&mut funding_asset_spent, usd_ticket_size, cont.asset); } + output.push(UserToFundingAsset::new(cont.contributor, funding_asset_spent, cont.asset.id())); } output diff --git a/pallets/funding/src/instantiator/chain_interactions.rs b/pallets/funding/src/instantiator/chain_interactions.rs index 8328f77d4..421b4815f 100644 --- a/pallets/funding/src/instantiator/chain_interactions.rs +++ b/pallets/funding/src/instantiator/chain_interactions.rs @@ -74,12 +74,11 @@ impl< pub fn get_free_funding_asset_balances_for( &mut self, - asset_id: AssetIdOf, - user_keys: Vec>, + list: Vec<(AccountIdOf, AssetIdOf)>, ) -> Vec> { self.execute(|| { let mut balances: Vec> = Vec::new(); - for account in user_keys { + for (account, asset_id) in list { let asset_amount = ::FundingCurrency::balance(asset_id, &account); balances.push(UserToFundingAsset { account, asset_amount, asset_id }); } @@ -121,8 +120,8 @@ impl< } pub fn get_all_free_funding_asset_balances(&mut self, asset_id: AssetIdOf) -> Vec> { - let user_keys = self.execute(|| frame_system::Account::::iter_keys().collect()); - self.get_free_funding_asset_balances_for(asset_id, user_keys) + let user_keys = self.execute(|| frame_system::Account::::iter_keys().map(|a| (a, asset_id)).collect()); + self.get_free_funding_asset_balances_for(user_keys) } pub fn get_plmc_total_supply(&mut self) -> Balance { @@ -212,6 +211,28 @@ impl< }); } } + + pub fn mint_plmc_ed_if_required(&mut self, accounts: Vec>) { + let ed = self.get_ed(); + for account in accounts { + self.execute(|| { + if ::NativeCurrency::balance(&account) < ed { + ::NativeCurrency::mint_into(&account, ed).expect("Minting should work"); + } + }); + } + } + + pub fn mint_funding_asset_ed_if_required(&mut self, list: Vec<(AccountIdOf, AssetIdOf)>) { + for (account, asset_id) in list { + let ed = self.get_funding_asset_ed(asset_id); + self.execute(|| { + if ::FundingCurrency::balance(asset_id, &account) < ed { + ::FundingCurrency::mint_into(asset_id, &account, ed).expect("Minting should work"); + } + }); + } + } } // assertions @@ -408,40 +429,6 @@ impl< new_details.status } - pub fn create_new_project( - &mut self, - project_metadata: ProjectMetadataOf, - issuer: AccountIdOf, - maybe_did: Option, - ) -> ProjectId { - // one ED for the issuer, one ED for the escrow account - self.mint_plmc_to(vec![UserToPLMCBalance::new(issuer.clone(), self.get_ed() * 2u128)]); - - let did = if let Some(did) = maybe_did.clone() { did } else { generate_did_from_account(issuer.clone()) }; - - self.execute(|| { - crate::Pallet::::do_create_project(&issuer, project_metadata.clone(), did).unwrap(); - let last_project_metadata = ProjectsMetadata::::iter().last().unwrap(); - log::trace!("Last project metadata: {:?}", last_project_metadata); - }); - - let created_project_id = self.execute(|| NextProjectId::::get().saturating_sub(One::one())); - self.creation_assertions(created_project_id, maybe_did, project_metadata); - created_project_id - } - - pub fn create_evaluating_project( - &mut self, - project_metadata: ProjectMetadataOf, - issuer: AccountIdOf, - maybe_did: Option, - ) -> ProjectId { - let project_id = self.create_new_project(project_metadata, issuer.clone(), maybe_did); - assert_eq!(self.go_to_next_state(project_id), ProjectStatus::EvaluationRound); - - project_id - } - pub fn evaluate_for_users( &mut self, project_id: ProjectId, @@ -462,54 +449,6 @@ impl< Ok(().into()) } - pub fn create_auctioning_project( - &mut self, - project_metadata: ProjectMetadataOf, - issuer: AccountIdOf, - maybe_did: Option, - evaluations: Vec>, - ) -> ProjectId { - let project_id = self.create_evaluating_project(project_metadata, issuer.clone(), maybe_did); - - let evaluators = evaluations.accounts(); - - let prev_supply = self.get_plmc_total_supply(); - let prev_free_plmc_balances = self.get_free_plmc_balances_for(evaluators.clone()); - let prev_held_plmc_balances = - self.get_reserved_plmc_balances_for(evaluators.clone(), HoldReason::Evaluation.into()); - - let plmc_evaluation_deposits: Vec> = - self.calculate_evaluation_plmc_spent(evaluations.clone(), false); - let plmc_existential_deposits: Vec> = evaluators.existential_deposits(); - - self.mint_plmc_to(plmc_evaluation_deposits.clone()); - self.mint_plmc_to(plmc_existential_deposits.clone()); - - self.evaluate_for_users(project_id, evaluations).unwrap(); - - let expected_free_plmc_balances = self.generic_map_operation( - vec![prev_free_plmc_balances.clone(), plmc_existential_deposits.clone()], - MergeOperation::Add, - ); - let expected_held_plmc_balances = self.generic_map_operation( - vec![prev_held_plmc_balances.clone(), plmc_evaluation_deposits.clone()], - MergeOperation::Add, - ); - let expected_total_plmc_supply = prev_supply + - self.sum_balance_mappings(vec![plmc_existential_deposits.clone(), plmc_evaluation_deposits.clone()]); - - self.evaluation_assertions( - project_id, - expected_free_plmc_balances, - expected_held_plmc_balances, - expected_total_plmc_supply, - ); - - assert_eq!(self.go_to_next_state(project_id), ProjectStatus::AuctionRound); - - project_id - } - pub fn bid_for_users(&mut self, project_id: ProjectId, bids: Vec>) -> DispatchResultWithPostInfo { let project_policy = self.get_project_metadata(project_id).policy_ipfs_cid.unwrap(); @@ -532,87 +471,6 @@ impl< Ok(().into()) } - pub fn create_community_contributing_project( - &mut self, - project_metadata: ProjectMetadataOf, - issuer: AccountIdOf, - maybe_did: Option, - evaluations: Vec>, - bids: Vec>, - ) -> ProjectId { - let project_id = - self.create_auctioning_project(project_metadata.clone(), issuer, maybe_did, evaluations.clone()); - if bids.is_empty() { - assert!(matches!(self.go_to_next_state(project_id), ProjectStatus::CommunityRound(_))); - return project_id - } - let prev_plmc_supply = self.get_plmc_total_supply(); - - let bidders = bids.accounts(); - let prev_free_plmc_balances = self.get_free_plmc_balances_for(bidders.clone()); - let prev_held_plmc_balances = - self.get_reserved_plmc_balances_for(bidders.clone(), HoldReason::Participation.into()); - let prev_funding_asset_balances = self.get_free_funding_asset_balances_for(bids[0].asset.id(), bidders.clone()); - - let plmc_evaluation_deposits: Vec> = - self.calculate_evaluation_plmc_spent(evaluations, false); - let plmc_bid_deposits: Vec> = self - .calculate_auction_plmc_charged_from_all_bids_made_or_with_bucket( - &bids, - project_metadata.clone(), - None, - false, - ); - let plmc_existential_deposits: Vec> = bidders.existential_deposits(); - - let participation_usable_evaluation_deposits = plmc_evaluation_deposits - .into_iter() - .map(|mut x| { - x.plmc_amount = x.plmc_amount.saturating_sub(::EvaluatorSlash::get() * x.plmc_amount); - x - }) - .collect::>>(); - - let necessary_plmc_contribution_mint = self.generic_map_operation( - vec![plmc_bid_deposits.clone(), participation_usable_evaluation_deposits], - MergeOperation::Subtract, - ); - let funding_asset_deposits = self.calculate_auction_funding_asset_charged_from_all_bids_made_or_with_bucket( - &bids, - project_metadata.clone(), - None, - ); - - let bidder_balances = self - .sum_balance_mappings(vec![necessary_plmc_contribution_mint.clone(), plmc_existential_deposits.clone()]); - - let expected_free_plmc_balances = self.generic_map_operation( - vec![prev_free_plmc_balances, plmc_existential_deposits.clone()], - MergeOperation::Add, - ); - let expected_held_plmc_balances = - self.generic_map_operation(vec![prev_held_plmc_balances, plmc_bid_deposits], MergeOperation::Add); - let expected_plmc_supply = prev_plmc_supply + bidder_balances; - - self.mint_plmc_to(necessary_plmc_contribution_mint.clone()); - self.mint_plmc_to(plmc_existential_deposits.clone()); - self.mint_funding_asset_to(funding_asset_deposits.clone()); - - self.bid_for_users(project_id, bids.clone()).unwrap(); - - self.do_free_plmc_assertions(expected_free_plmc_balances.merge_accounts(MergeOperation::Add)); - self.do_reserved_plmc_assertions( - expected_held_plmc_balances.merge_accounts(MergeOperation::Add), - HoldReason::Participation.into(), // TODO: Check the `Reason` - ); - self.do_free_funding_asset_assertions(prev_funding_asset_balances.merge_accounts(MergeOperation::Add)); - assert_eq!(self.get_plmc_total_supply(), expected_plmc_supply); - - assert!(matches!(self.go_to_next_state(project_id), ProjectStatus::CommunityRound(_))); - - project_id - } - pub fn contribute_for_users( &mut self, project_id: ProjectId, @@ -701,21 +559,18 @@ impl< } } - let total_stored_dot = self.get_free_funding_asset_balances_for( + let total_stored_dot = self.get_free_funding_asset_balance_for( AcceptedFundingAsset::DOT.id(), - vec![project_metadata.funding_destination_account.clone()], - )[0] - .asset_amount; - let total_stored_usdt = self.get_free_funding_asset_balances_for( + project_metadata.funding_destination_account.clone(), + ); + let total_stored_usdt = self.get_free_funding_asset_balance_for( AcceptedFundingAsset::USDT.id(), - vec![project_metadata.funding_destination_account.clone()], - )[0] - .asset_amount; - let total_stored_usdc = self.get_free_funding_asset_balances_for( + project_metadata.funding_destination_account.clone(), + ); + let total_stored_usdc = self.get_free_funding_asset_balance_for( AcceptedFundingAsset::USDC.id(), - vec![project_metadata.funding_destination_account.clone()], - )[0] - .asset_amount; + project_metadata.funding_destination_account, + ); assert_eq!(total_expected_dot, total_stored_dot, "DOT amount is incorrect"); assert_eq!(total_expected_usdt, total_stored_usdt, "USDT amount is incorrect"); @@ -835,6 +690,143 @@ impl< }; } + pub fn create_new_project( + &mut self, + project_metadata: ProjectMetadataOf, + issuer: AccountIdOf, + maybe_did: Option, + ) -> ProjectId { + // one ED for the issuer, one ED for the escrow account + self.mint_plmc_to(vec![UserToPLMCBalance::new(issuer.clone(), self.get_ed() * 2u128)]); + + let did = if let Some(did) = maybe_did.clone() { did } else { generate_did_from_account(issuer.clone()) }; + + self.execute(|| { + crate::Pallet::::do_create_project(&issuer, project_metadata.clone(), did).unwrap(); + let last_project_metadata = ProjectsMetadata::::iter().last().unwrap(); + log::trace!("Last project metadata: {:?}", last_project_metadata); + }); + + let created_project_id = self.execute(|| NextProjectId::::get().saturating_sub(One::one())); + self.creation_assertions(created_project_id, maybe_did, project_metadata); + created_project_id + } + + pub fn create_evaluating_project( + &mut self, + project_metadata: ProjectMetadataOf, + issuer: AccountIdOf, + maybe_did: Option, + ) -> ProjectId { + let project_id = self.create_new_project(project_metadata, issuer.clone(), maybe_did); + assert_eq!(self.go_to_next_state(project_id), ProjectStatus::EvaluationRound); + + project_id + } + + pub fn create_auctioning_project( + &mut self, + project_metadata: ProjectMetadataOf, + issuer: AccountIdOf, + maybe_did: Option, + evaluations: Vec>, + ) -> ProjectId { + let project_id = self.create_evaluating_project(project_metadata, issuer.clone(), maybe_did); + + let evaluators = evaluations.accounts(); + self.mint_plmc_ed_if_required(evaluators.clone()); + + let prev_supply = self.get_plmc_total_supply(); + let prev_free_plmc_balances = self.get_free_plmc_balances_for(evaluators.clone()); + let prev_held_plmc_balances = + self.get_reserved_plmc_balances_for(evaluators.clone(), HoldReason::Evaluation.into()); + + let plmc_evaluation_deposits: Vec> = + self.calculate_evaluation_plmc_spent(evaluations.clone()); + + self.mint_plmc_to(plmc_evaluation_deposits.clone()); + + self.evaluate_for_users(project_id, evaluations).unwrap(); + + let expected_free_plmc_balances = prev_free_plmc_balances; + let expected_held_plmc_balances = self.generic_map_operation( + vec![prev_held_plmc_balances.clone(), plmc_evaluation_deposits.clone()], + MergeOperation::Add, + ); + let expected_total_plmc_supply = + prev_supply + self.sum_balance_mappings(vec![plmc_evaluation_deposits.clone()]); + + self.evaluation_assertions( + project_id, + expected_free_plmc_balances, + expected_held_plmc_balances, + expected_total_plmc_supply, + ); + + assert_eq!(self.go_to_next_state(project_id), ProjectStatus::AuctionRound); + + project_id + } + + pub fn create_community_contributing_project( + &mut self, + project_metadata: ProjectMetadataOf, + issuer: AccountIdOf, + maybe_did: Option, + evaluations: Vec>, + bids: Vec>, + ) -> ProjectId { + let project_id = + self.create_auctioning_project(project_metadata.clone(), issuer, maybe_did, evaluations.clone()); + if bids.is_empty() { + assert!(matches!(self.go_to_next_state(project_id), ProjectStatus::CommunityRound(_))); + return project_id + } + + self.mint_plmc_ed_if_required(bids.accounts()); + self.mint_funding_asset_ed_if_required(bids.to_account_asset_map()); + + let prev_plmc_supply = self.get_plmc_total_supply(); + let prev_free_plmc_balances = self.get_free_plmc_balances_for(bids.accounts()); + let prev_held_plmc_balances = + self.get_reserved_plmc_balances_for(bids.accounts(), HoldReason::Participation.into()); + let prev_funding_asset_balances = self.get_free_funding_asset_balances_for(bids.to_account_asset_map()); + + let plmc_evaluation_deposits: Vec> = self.calculate_evaluation_plmc_spent(evaluations); + let plmc_bid_deposits: Vec> = self + .calculate_auction_plmc_charged_from_all_bids_made_or_with_bucket(&bids, project_metadata.clone(), None); + let reducible_evaluator_balances = self.slash_evaluator_balances(plmc_evaluation_deposits.clone()); + + let necessary_plmc_mints = self.generic_map_operation( + vec![plmc_bid_deposits.clone(), reducible_evaluator_balances], + MergeOperation::Subtract, + ); + let funding_asset_deposits = self.calculate_auction_funding_asset_charged_from_all_bids_made_or_with_bucket( + &bids, + project_metadata.clone(), + None, + ); + + let expected_free_plmc_balances = prev_free_plmc_balances; + let expected_held_plmc_balances = + self.generic_map_operation(vec![prev_held_plmc_balances, plmc_bid_deposits], MergeOperation::Add); + let expected_plmc_supply = prev_plmc_supply + necessary_plmc_mints.total(); + + self.mint_plmc_to(necessary_plmc_mints.clone()); + self.mint_funding_asset_to(funding_asset_deposits.clone()); + + self.bid_for_users(project_id, bids.clone()).unwrap(); + + self.do_free_plmc_assertions(expected_free_plmc_balances); + self.do_reserved_plmc_assertions(expected_held_plmc_balances, HoldReason::Participation.into()); + self.do_free_funding_asset_assertions(prev_funding_asset_balances); + assert_eq!(self.get_plmc_total_supply(), expected_plmc_supply); + + assert!(matches!(self.go_to_next_state(project_id), ProjectStatus::CommunityRound(_))); + + project_id + } + pub fn create_remainder_contributing_project( &mut self, project_metadata: ProjectMetadataOf, @@ -855,55 +847,41 @@ impl< if !contributions.is_empty() { let ct_price = self.get_project_details(project_id).weighted_average_price.unwrap(); - let contributors = contributions.accounts(); - - let asset_id = contributions[0].asset.id(); + self.mint_plmc_ed_if_required(contributions.accounts()); + self.mint_funding_asset_ed_if_required(contributions.to_account_asset_map()); - let prev_free_plmc_balances = self.get_free_plmc_balances_for(contributors.clone()); + let prev_free_plmc_balances = self.get_free_plmc_balances_for(contributions.accounts()); let prev_held_plmc_balances = - self.get_reserved_plmc_balances_for(contributors.clone(), HoldReason::Participation.into()); - let prev_funding_asset_balances = self.get_free_funding_asset_balances_for(asset_id, contributors.clone()); + self.get_reserved_plmc_balances_for(contributions.accounts(), HoldReason::Participation.into()); + let prev_funding_asset_balances = + self.get_free_funding_asset_balances_for(contributions.to_account_asset_map()); + let prev_plmc_supply = self.get_plmc_total_supply(); - let plmc_contribution_deposits = - self.calculate_contributed_plmc_spent(contributions.clone(), ct_price, false); + let plmc_contribution_deposits = self.calculate_contributed_plmc_spent(contributions.clone(), ct_price); let funding_asset_contribution_deposits = self.calculate_contributed_funding_asset_spent(contributions.clone(), ct_price); - let plmc_existential_deposits = contributors.existential_deposits(); - let plmc_evaluation_deposits = self.calculate_evaluation_plmc_spent(evaluations.clone(), false); + let plmc_evaluation_deposits = self.calculate_evaluation_plmc_spent(evaluations.clone()); let reducible_evaluator_balances = self.slash_evaluator_balances(plmc_evaluation_deposits.clone()); let necessary_plmc_contribution_mint = self.generic_map_operation( vec![plmc_contribution_deposits.clone(), reducible_evaluator_balances], MergeOperation::Subtract, ); - let expected_free_plmc_balances = self.generic_map_operation( - vec![prev_free_plmc_balances, plmc_existential_deposits.clone()], - MergeOperation::Add, - ); + let expected_free_plmc_balances = prev_free_plmc_balances; let expected_held_plmc_balances = self .generic_map_operation(vec![prev_held_plmc_balances, plmc_contribution_deposits], MergeOperation::Add); - let total_plmc_minted = self.sum_balance_mappings(vec![ - necessary_plmc_contribution_mint.clone(), - plmc_existential_deposits.clone(), - ]); - let prev_plmc_supply = self.get_plmc_total_supply(); - - let expected_plmc_supply = prev_plmc_supply + total_plmc_minted; + let expected_plmc_supply = prev_plmc_supply + necessary_plmc_contribution_mint.total(); self.mint_plmc_to(necessary_plmc_contribution_mint.clone()); - self.mint_plmc_to(plmc_existential_deposits.clone()); self.mint_funding_asset_to(funding_asset_contribution_deposits.clone()); self.contribute_for_users(project_id, contributions).expect("Contributing should work"); - self.do_free_plmc_assertions(expected_free_plmc_balances.merge_accounts(MergeOperation::Add)); - self.do_reserved_plmc_assertions( - expected_held_plmc_balances.merge_accounts(MergeOperation::Add), - HoldReason::Participation.into(), - ); + self.do_free_plmc_assertions(expected_free_plmc_balances); + self.do_reserved_plmc_assertions(expected_held_plmc_balances, HoldReason::Participation.into()); self.do_free_funding_asset_assertions(prev_funding_asset_balances.merge_accounts(MergeOperation::Add)); assert_eq!(self.get_plmc_total_supply(), expected_plmc_supply); @@ -938,25 +916,25 @@ impl< if !remainder_contributions.is_empty() { let ct_price = self.get_project_details(project_id).weighted_average_price.unwrap(); - let contributors = remainder_contributions.accounts(); - let asset_id = remainder_contributions[0].asset.id(); - let prev_free_plmc_balances = self.get_free_plmc_balances_for(contributors.clone()); - let prev_held_plmc_balances = - self.get_reserved_plmc_balances_for(contributors.clone(), HoldReason::Participation.into()); - let prev_funding_asset_balances = self.get_free_funding_asset_balances_for(asset_id, contributors.clone()); + self.mint_plmc_ed_if_required(remainder_contributions.accounts()); + self.mint_funding_asset_ed_if_required(remainder_contributions.to_account_asset_map()); + + let prev_free_plmc_balances = self.get_free_plmc_balances_for(remainder_contributions.accounts()); + let prev_held_plmc_balances = self + .get_reserved_plmc_balances_for(remainder_contributions.accounts(), HoldReason::Participation.into()); + let prev_funding_asset_balances = + self.get_free_funding_asset_balances_for(remainder_contributions.to_account_asset_map()); + let prev_supply = self.get_plmc_total_supply(); - let plmc_evaluation_deposits = self.calculate_evaluation_plmc_spent(evaluations, false); + let plmc_evaluation_deposits = self.calculate_evaluation_plmc_spent(evaluations); let plmc_bid_deposits = self.calculate_auction_plmc_charged_from_all_bids_made_or_with_bucket( &bids, project_metadata.clone(), None, - false, ); - let plmc_remainder_contribution_deposits = - self.calculate_contributed_plmc_spent(remainder_contributions.clone(), ct_price, false); - + self.calculate_contributed_plmc_spent(remainder_contributions.clone(), ct_price); let reducible_evaluator_balances = self.slash_evaluator_balances(plmc_evaluation_deposits); let remaining_reducible_evaluator_balances = self.generic_map_operation( vec![reducible_evaluator_balances, plmc_bid_deposits.clone()], @@ -967,42 +945,28 @@ impl< vec![plmc_remainder_contribution_deposits.clone(), remaining_reducible_evaluator_balances], MergeOperation::Subtract, ); - let plmc_existential_deposits = contributors.existential_deposits(); let funding_asset_deposits = self.calculate_contributed_funding_asset_spent(remainder_contributions.clone(), ct_price); - let total_plmc_minted = self.sum_balance_mappings(vec![ - necessary_plmc_contribution_mint.clone(), - plmc_existential_deposits.clone(), - ]); - - let expected_free_plmc_balances = self.generic_map_operation( - vec![prev_free_plmc_balances, plmc_existential_deposits.clone()], - MergeOperation::Add, - ); + let expected_free_plmc_balances = prev_free_plmc_balances; let expected_held_plmc_balances = self.generic_map_operation( vec![prev_held_plmc_balances, plmc_remainder_contribution_deposits], MergeOperation::Add, ); - let prev_supply = self.get_plmc_total_supply(); - let post_supply = prev_supply + total_plmc_minted; + let expected_supply = prev_supply + necessary_plmc_contribution_mint.total(); self.mint_plmc_to(necessary_plmc_contribution_mint.clone()); - self.mint_plmc_to(plmc_existential_deposits.clone()); self.mint_funding_asset_to(funding_asset_deposits.clone()); self.contribute_for_users(project_id, remainder_contributions.clone()) .expect("Remainder Contributing should work"); - self.do_free_plmc_assertions(expected_free_plmc_balances.merge_accounts(MergeOperation::Add)); - self.do_reserved_plmc_assertions( - expected_held_plmc_balances.merge_accounts(MergeOperation::Add), - HoldReason::Participation.into(), - ); - self.do_free_funding_asset_assertions(prev_funding_asset_balances.merge_accounts(MergeOperation::Add)); - assert_eq!(self.get_plmc_total_supply(), post_supply); + self.do_free_plmc_assertions(expected_free_plmc_balances); + self.do_reserved_plmc_assertions(expected_held_plmc_balances, HoldReason::Participation.into()); + self.do_free_funding_asset_assertions(prev_funding_asset_balances); + assert_eq!(self.get_plmc_total_supply(), expected_supply); } let status = self.go_to_next_state(project_id); diff --git a/pallets/funding/src/instantiator/traits.rs b/pallets/funding/src/instantiator/traits.rs index cfbe9a378..f75ca4056 100644 --- a/pallets/funding/src/instantiator/traits.rs +++ b/pallets/funding/src/instantiator/traits.rs @@ -1,4 +1,5 @@ use super::{Config, UserToPLMCBalance, Vec}; +use crate::Balance; pub trait Deposits { fn existential_deposits(&self) -> Vec>; @@ -24,3 +25,18 @@ pub trait AccountMerge: Accounts + Sized { fn sum_accounts(&self, other_list: Self) -> Self; } + +pub trait Total { + fn total(&self) -> Balance; +} + +pub trait Totals { + type AssetId; + fn totals(&self) -> Vec<(Self::AssetId, Balance)>; +} + +pub trait Conversions { + type AccountId; + type AssetId; + fn to_account_asset_map(&self) -> Vec<(Self::AccountId, Self::AssetId)>; +} diff --git a/pallets/funding/src/instantiator/types.rs b/pallets/funding/src/instantiator/types.rs index 36dafc4ff..36bbc2146 100644 --- a/pallets/funding/src/instantiator/types.rs +++ b/pallets/funding/src/instantiator/types.rs @@ -107,6 +107,12 @@ impl AccountMerge for Vec> { } } +impl Total for Vec> { + fn total(&self) -> Balance { + self.iter().map(|x| x.plmc_amount).sum() + } +} + #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo, Serialize, Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields, bound(serialize = ""), bound(deserialize = ""))] pub struct UserToUSDBalance { @@ -167,6 +173,11 @@ impl AccountMerge for Vec> { output.merge_accounts(MergeOperation::Add) } } +impl Total for Vec> { + fn total(&self) -> Balance { + self.iter().map(|x| x.usd_amount).sum() + } +} #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] pub struct UserToFundingAsset { @@ -236,6 +247,32 @@ impl AccountMerge for Vec> { output.merge_accounts(MergeOperation::Add) } } +impl Totals for Vec> { + type AssetId = AssetIdOf; + + fn totals(&self) -> Vec<(Self::AssetId, Balance)> { + let mut btree = BTreeMap::new(); + for UserToFundingAsset { account: _, asset_amount, asset_id } in self.iter() { + btree + .entry(*asset_id) + .and_modify(|e: &mut Balance| *e = e.saturating_add(*asset_amount)) + .or_insert(*asset_amount); + } + btree.into_iter().collect_vec() + } +} +impl Conversions for Vec> { + type AccountId = AccountIdOf; + type AssetId = AssetIdOf; + + fn to_account_asset_map(&self) -> Vec<(Self::AccountId, Self::AssetId)> { + let mut btree = BTreeSet::new(); + for UserToFundingAsset { account, asset_id, .. } in self.iter() { + btree.insert((account.clone(), *asset_id)); + } + btree.into_iter().collect_vec() + } +} #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo, Serialize, Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields, bound(serialize = ""), bound(deserialize = ""))] @@ -274,6 +311,11 @@ impl From<(AccountIdOf, Balance, AcceptedFundingAsset)> for BidPar Self { bidder, amount, mode: ParticipationMode::Classic(1u8), asset } } } +impl From> for (AccountIdOf, AssetIdOf) { + fn from(bid: BidParams) -> (AccountIdOf, AssetIdOf) { + (bid.bidder, bid.asset.id()) + } +} impl Accounts for Vec> { type Account = AccountIdOf; @@ -286,6 +328,18 @@ impl Accounts for Vec> { btree.into_iter().collect_vec() } } +impl Conversions for Vec> { + type AccountId = AccountIdOf; + type AssetId = AssetIdOf; + + fn to_account_asset_map(&self) -> Vec<(Self::AccountId, Self::AssetId)> { + let mut btree = BTreeSet::new(); + for BidParams { bidder, asset, .. } in self.iter() { + btree.insert((bidder.clone(), asset.id())); + } + btree.into_iter().collect_vec() + } +} #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo, Serialize, Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields, bound(serialize = ""), bound(deserialize = ""))] @@ -337,6 +391,18 @@ impl Accounts for Vec> { btree.into_iter().collect_vec() } } +impl Conversions for Vec> { + type AccountId = AccountIdOf; + type AssetId = AssetIdOf; + + fn to_account_asset_map(&self) -> Vec<(Self::AccountId, Self::AssetId)> { + let mut btree = BTreeSet::new(); + for ContributionParams { contributor, asset, .. } in self.iter() { + btree.insert((contributor.clone(), asset.id())); + } + btree.into_iter().collect_vec() + } +} #[derive(Clone, PartialEq, Eq, Debug)] pub struct BidInfoFilter { diff --git a/pallets/funding/src/tests/2_evaluation.rs b/pallets/funding/src/tests/2_evaluation.rs index df16a6ede..ffcfe5250 100644 --- a/pallets/funding/src/tests/2_evaluation.rs +++ b/pallets/funding/src/tests/2_evaluation.rs @@ -45,7 +45,9 @@ mod round_flow { let target_evaluation_usd = Percent::from_percent(10) * target_funding; let evaluations = vec![(EVALUATOR_1, target_evaluation_usd).into()]; - let evaluation_plmc = inst.calculate_evaluation_plmc_spent(evaluations.clone(), true); + let evaluation_plmc = inst.calculate_evaluation_plmc_spent(evaluations.clone()); + + inst.mint_plmc_ed_if_required(evaluations.accounts()); inst.mint_plmc_to(evaluation_plmc); let project_id = inst.create_evaluating_project(project_metadata.clone(), ISSUER_1, None); @@ -58,7 +60,7 @@ mod round_flow { // Increasing the price before the end doesn't make a project under the threshold succeed. let evaluations = vec![(EVALUATOR_1, target_evaluation_usd / 2).into()]; - let evaluation_plmc = inst.calculate_evaluation_plmc_spent(evaluations.clone(), true); + let evaluation_plmc = inst.calculate_evaluation_plmc_spent(evaluations.clone()); inst.mint_plmc_to(evaluation_plmc); let project_id = inst.create_evaluating_project(project_metadata.clone(), ISSUER_2, None); @@ -208,8 +210,7 @@ mod round_flow { let issuer = ISSUER_1; let project_metadata = default_project_metadata(issuer); let evaluations = default_failing_evaluations(); - let plmc_eval_deposits: Vec> = - inst.calculate_evaluation_plmc_spent(evaluations, false); + let plmc_eval_deposits: Vec> = inst.calculate_evaluation_plmc_spent(evaluations); let plmc_existential_deposits = plmc_eval_deposits.accounts().existential_deposits(); let expected_evaluator_balances = inst.generic_map_operation( @@ -469,8 +470,9 @@ mod evaluate_extrinsic { (EVALUATOR_2, 1000 * USD_UNIT).into(), (EVALUATOR_3, 20_000 * USD_UNIT).into(), ]; - let necessary_plmc = inst.calculate_evaluation_plmc_spent(evaluations.clone(), true); + let necessary_plmc = inst.calculate_evaluation_plmc_spent(evaluations.clone()); + inst.mint_plmc_ed_if_required(evaluations.accounts()); inst.mint_plmc_to(necessary_plmc); assert_ok!(inst.execute(|| PolimecFunding::evaluate( @@ -518,8 +520,9 @@ mod evaluate_extrinsic { let project_id = inst.create_evaluating_project(project_metadata.clone(), issuer, None); let evaluation = UserToUSDBalance::new(EVALUATOR_1, 500 * USD_UNIT); - let necessary_plmc = inst.calculate_evaluation_plmc_spent(vec![evaluation.clone()], true); + let necessary_plmc = inst.calculate_evaluation_plmc_spent(vec![evaluation.clone()]); + inst.mint_plmc_ed_if_required(necessary_plmc.accounts()); inst.mint_plmc_to(necessary_plmc.clone()); inst.execute(|| { @@ -545,7 +548,7 @@ mod evaluate_extrinsic { let project_metadata = default_project_metadata(ISSUER_1); let project_id = inst.create_evaluating_project(project_metadata.clone(), ISSUER_1, None); let evaluation = UserToUSDBalance::new(EVALUATOR_1, 500 * USD_UNIT); - let necessary_plmc = inst.calculate_evaluation_plmc_spent(vec![evaluation.clone()], false); + let necessary_plmc = inst.calculate_evaluation_plmc_spent(vec![evaluation.clone()]); let plmc_existential_deposits = necessary_plmc.accounts().existential_deposits(); inst.mint_plmc_to(necessary_plmc.clone()); @@ -595,12 +598,11 @@ mod evaluate_extrinsic { let project_metadata = default_project_metadata(issuer); let evaluation = UserToUSDBalance::new(EVALUATOR_4, 1_000_000 * USD_UNIT); - let plmc_required = inst.calculate_evaluation_plmc_spent(vec![evaluation.clone()], false); - let plmc_existential_deposits = plmc_required.accounts().existential_deposits(); + let plmc_required = inst.calculate_evaluation_plmc_spent(vec![evaluation.clone()]); let frozen_amount = plmc_required[0].plmc_amount; + inst.mint_plmc_ed_if_required(vec![EVALUATOR_4]); inst.mint_plmc_to(plmc_required.clone()); - inst.mint_plmc_to(plmc_existential_deposits.clone()); inst.execute(|| { mock::Balances::set_freeze(&(), &EVALUATOR_4, plmc_required[0].plmc_amount).unwrap(); @@ -629,7 +631,8 @@ mod evaluate_extrinsic { }); let new_evaluations = default_evaluations(); - let new_plmc_required = inst.calculate_evaluation_plmc_spent(new_evaluations.clone(), true); + let new_plmc_required = inst.calculate_evaluation_plmc_spent(new_evaluations.clone()); + inst.mint_plmc_ed_if_required(new_plmc_required.accounts()); inst.mint_plmc_to(new_plmc_required.clone()); inst.evaluate_for_users(project_id, new_evaluations).unwrap(); @@ -722,7 +725,7 @@ mod evaluate_extrinsic { let project_metadata = default_project_metadata(issuer); let evaluations = default_evaluations(); let insufficient_eval_deposits = inst - .calculate_evaluation_plmc_spent(evaluations.clone(), false) + .calculate_evaluation_plmc_spent(evaluations.clone()) .iter() .map(|UserToPLMCBalance { account, plmc_amount }| UserToPLMCBalance::new(*account, plmc_amount / 2)) .collect::>>(); @@ -744,7 +747,7 @@ mod evaluate_extrinsic { let issuer = ISSUER_1; let project_metadata = default_project_metadata(issuer); let evaluations = vec![UserToUSDBalance::new(EVALUATOR_1, 1000 * USD_UNIT)]; - let evaluating_plmc = inst.calculate_evaluation_plmc_spent(evaluations.clone(), false); + let evaluating_plmc = inst.calculate_evaluation_plmc_spent(evaluations.clone()); let mut plmc_insufficient_existential_deposit = evaluating_plmc.accounts().existential_deposits(); plmc_insufficient_existential_deposit[0].plmc_amount = @@ -770,14 +773,14 @@ mod evaluate_extrinsic { let project_id = inst.create_evaluating_project(project_metadata.clone(), ISSUER_1, None); - let plmc_for_evaluating = inst.calculate_evaluation_plmc_spent(evaluations.clone(), true); + let plmc_for_evaluating = inst.calculate_evaluation_plmc_spent(evaluations.clone()); + inst.mint_plmc_ed_if_required(plmc_for_evaluating.accounts()); inst.mint_plmc_to(plmc_for_evaluating.clone()); inst.evaluate_for_users(project_id, evaluations.clone()).unwrap(); - let plmc_for_failing_evaluating = - inst.calculate_evaluation_plmc_spent(vec![failing_evaluation.clone()], true); + let plmc_for_failing_evaluating = inst.calculate_evaluation_plmc_spent(vec![failing_evaluation.clone()]); inst.mint_plmc_to(plmc_for_failing_evaluating.clone()); @@ -798,7 +801,7 @@ mod evaluate_extrinsic { let project_id = inst.create_evaluating_project(project_metadata.clone(), ISSUER_1, None); - let plmc_for_evaluating = inst.calculate_evaluation_plmc_spent(evaluations.clone(), false); + let plmc_for_evaluating = inst.calculate_evaluation_plmc_spent(evaluations.clone()); let plmc_existential_deposits = evaluations.accounts().existential_deposits(); inst.mint_plmc_to(plmc_for_evaluating.clone()); @@ -806,8 +809,7 @@ mod evaluate_extrinsic { inst.evaluate_for_users(project_id, evaluations.clone()).unwrap(); - let plmc_for_failing_evaluating = - inst.calculate_evaluation_plmc_spent(vec![failing_evaluation.clone()], true); + let plmc_for_failing_evaluating = inst.calculate_evaluation_plmc_spent(vec![failing_evaluation.clone()]); inst.mint_plmc_to(plmc_for_failing_evaluating.clone()); @@ -825,7 +827,7 @@ mod evaluate_extrinsic { let project_id = inst.create_evaluating_project(project_metadata.clone(), issuer, None); let evaluation = UserToUSDBalance::new(EVALUATOR_1, 500 * USD_UNIT); - let necessary_plmc = inst.calculate_evaluation_plmc_spent(vec![evaluation.clone()], false); + let necessary_plmc = inst.calculate_evaluation_plmc_spent(vec![evaluation.clone()]); let ed = necessary_plmc.accounts().existential_deposits(); inst.mint_plmc_to(necessary_plmc.clone()); @@ -883,8 +885,9 @@ mod evaluate_extrinsic { let project_id = inst.create_evaluating_project(project_metadata.clone(), issuer, None); let evaluation = UserToUSDBalance::new(EVALUATOR_1, 500 * USD_UNIT); - let necessary_plmc = inst.calculate_evaluation_plmc_spent(vec![evaluation.clone()], true); + let necessary_plmc = inst.calculate_evaluation_plmc_spent(vec![evaluation.clone()]); + inst.mint_plmc_ed_if_required(necessary_plmc.accounts()); inst.mint_plmc_to(necessary_plmc.clone()); inst.execute(|| { diff --git a/pallets/funding/src/tests/3_auction.rs b/pallets/funding/src/tests/3_auction.rs index 002966ebe..ab92268a3 100644 --- a/pallets/funding/src/tests/3_auction.rs +++ b/pallets/funding/src/tests/3_auction.rs @@ -206,6 +206,8 @@ mod round_flow { assert_eq!(auction_allocation_usd, 5_000_000 * USD_UNIT); // A minimum bid goes through. This is a fixed USD value, but the extrinsic amount depends on CT decimals. + inst.mint_plmc_ed_if_required(vec![BIDDER_1]); + inst.mint_funding_asset_ed_if_required(vec![(BIDDER_1, funding_asset.id())]); inst.mint_plmc_to(vec![UserToPLMCBalance::new(BIDDER_1, min_professional_bid_plmc + ed)]); inst.mint_funding_asset_to(vec![UserToFundingAsset::new( BIDDER_1, @@ -352,6 +354,7 @@ mod bid_extrinsic { #[cfg(test)] mod success { use super::*; + use crate::AcceptedFundingAsset::USDT; use frame_support::pallet_prelude::DispatchResultWithPostInfo; #[test] @@ -360,7 +363,7 @@ mod bid_extrinsic { let issuer = ISSUER_1; let project_metadata = default_project_metadata(issuer); let mut evaluations = default_evaluations(); - let evaluator_bidder = 69; + let evaluator_bidder = 69u64; let evaluation_amount = 420 * USD_UNIT; let evaluator_bid = BidParams::new( evaluator_bidder, @@ -372,9 +375,8 @@ mod bid_extrinsic { let project_id = inst.create_auctioning_project(project_metadata.clone(), issuer, None, evaluations); - let already_bonded_plmc = inst - .calculate_evaluation_plmc_spent(vec![(evaluator_bidder, evaluation_amount).into()], false)[0] - .plmc_amount; + let already_bonded_plmc = + inst.calculate_evaluation_plmc_spent(vec![(evaluator_bidder, evaluation_amount).into()])[0].plmc_amount; let usable_evaluation_plmc = already_bonded_plmc - ::EvaluatorSlash::get() * already_bonded_plmc; @@ -382,7 +384,6 @@ mod bid_extrinsic { let necessary_plmc_for_bid = inst.calculate_auction_plmc_charged_with_given_price( &vec![evaluator_bid.clone()], project_metadata.minimum_price, - false, )[0] .plmc_amount; @@ -391,6 +392,8 @@ mod bid_extrinsic { project_metadata.minimum_price, ); + inst.mint_plmc_ed_if_required(vec![evaluator_bidder]); + inst.mint_funding_asset_ed_if_required(vec![(evaluator_bidder, USDT.id())]); inst.mint_plmc_to(vec![UserToPLMCBalance::new( evaluator_bidder, necessary_plmc_for_bid - usable_evaluation_plmc, @@ -451,7 +454,6 @@ mod bid_extrinsic { let plmc_fundings = inst.calculate_auction_plmc_charged_with_given_price( &vec![usdt_bid.clone(), usdc_bid.clone(), dot_bid.clone()], project_metadata_all.minimum_price, - true, ); inst.mint_plmc_to(plmc_fundings.clone()); @@ -625,11 +627,13 @@ mod bid_extrinsic { let all_bids = vec![bid_40_percent[0].clone(), bid_23_percent[0].clone()]; + inst.mint_plmc_ed_if_required(all_bids.accounts()); + inst.mint_funding_asset_ed_if_required(all_bids.to_account_asset_map()); + let necessary_plmc = inst.calculate_auction_plmc_charged_from_all_bids_made_or_with_bucket( &all_bids, project_metadata.clone(), None, - true, ); let necessary_usdt = inst.calculate_auction_funding_asset_charged_from_all_bids_made_or_with_bucket( &all_bids, @@ -702,12 +706,10 @@ mod bid_extrinsic { &vec![bid.clone()], project_metadata.clone(), None, - false, ); let frozen_amount = plmc_required[0].plmc_amount; - let plmc_existential_deposits = plmc_required.accounts().existential_deposits(); - inst.mint_plmc_to(plmc_existential_deposits); + inst.mint_plmc_ed_if_required(plmc_required.accounts()); inst.mint_plmc_to(plmc_required.clone()); inst.execute(|| { @@ -719,6 +721,7 @@ mod bid_extrinsic { project_metadata.clone(), None, ); + inst.mint_funding_asset_ed_if_required(vec![bid.clone()].to_account_asset_map()); inst.mint_funding_asset_to(usdt_required); inst.execute(|| { @@ -784,12 +787,10 @@ mod bid_extrinsic { &vec![bid.clone()], project_metadata.clone(), None, - false, ); let frozen_amount = plmc_required[0].plmc_amount; - let plmc_existential_deposits = plmc_required.accounts().existential_deposits(); - inst.mint_plmc_to(plmc_existential_deposits); + inst.mint_plmc_ed_if_required(plmc_required.accounts()); inst.mint_plmc_to(plmc_required.clone()); inst.execute(|| { @@ -801,6 +802,7 @@ mod bid_extrinsic { project_metadata.clone(), None, ); + inst.mint_funding_asset_ed_if_required(vec![bid.clone()].to_account_asset_map()); inst.mint_funding_asset_to(usdt_required); inst.execute(|| { @@ -836,12 +838,13 @@ mod bid_extrinsic { default_community_contributors(), default_modes(), ); - let plmc_required = inst.calculate_contributed_plmc_spent(contributions.clone(), wap, true); + let plmc_required = inst.calculate_contributed_plmc_spent(contributions.clone(), wap); + inst.mint_plmc_ed_if_required(contributions.accounts()); inst.mint_plmc_to(plmc_required.clone()); let usdt_required = inst.calculate_contributed_funding_asset_spent(contributions.clone(), wap); + inst.mint_funding_asset_ed_if_required(contributions.to_account_asset_map()); inst.mint_funding_asset_to(usdt_required.clone()); - inst.contribute_for_users(project_id, contributions).unwrap(); assert_eq!(inst.go_to_next_state(project_id), ProjectStatus::FundingSuccessful); @@ -1250,15 +1253,13 @@ mod bid_extrinsic { inst.create_auctioning_project(project_metadata_2.clone(), ISSUER_2, None, evaluations_2); // Necessary Mints - let already_bonded_plmc = inst - .calculate_evaluation_plmc_spent(vec![(evaluator_bidder, evaluation_amount).into()], false)[0] - .plmc_amount; + let already_bonded_plmc = + inst.calculate_evaluation_plmc_spent(vec![(evaluator_bidder, evaluation_amount).into()])[0].plmc_amount; let usable_evaluation_plmc = already_bonded_plmc - ::EvaluatorSlash::get() * already_bonded_plmc; let necessary_plmc_for_bid = inst.calculate_auction_plmc_charged_with_given_price( &vec![evaluator_bid.clone()], project_metadata_2.minimum_price, - false, )[0] .plmc_amount; let necessary_usdt_for_bid = inst.calculate_auction_funding_asset_charged_with_given_price( @@ -1330,18 +1331,19 @@ mod bid_extrinsic { let project_id = inst.create_auctioning_project(project_metadata.clone(), ISSUER_1, None, evaluations); - let plmc_for_bidding = inst.calculate_auction_plmc_charged_with_given_price( - &bids.clone(), - project_metadata.minimum_price, - true, - ); + let plmc_for_bidding = + inst.calculate_auction_plmc_charged_with_given_price(&bids.clone(), project_metadata.minimum_price); let usdt_for_bidding = inst.calculate_auction_funding_asset_charged_with_given_price( &bids.clone(), project_metadata.minimum_price, ); + inst.mint_plmc_ed_if_required(bids.accounts()); inst.mint_plmc_to(plmc_for_bidding.clone()); + + inst.mint_funding_asset_ed_if_required(bids.to_account_asset_map()); inst.mint_funding_asset_to(usdt_for_bidding.clone()); + inst.bid_for_users(project_id, bids.clone()).unwrap(); let current_bucket = inst.execute(|| Buckets::::get(project_id)).unwrap(); @@ -1358,7 +1360,6 @@ mod bid_extrinsic { &vec![failing_bid.clone()], project_metadata.clone(), Some(current_bucket), - true, ); let usdt_for_bidding = inst.calculate_auction_funding_asset_charged_from_all_bids_made_or_with_bucket( @@ -1439,18 +1440,19 @@ mod bid_extrinsic { let project_id = inst.create_auctioning_project(project_metadata.clone(), ISSUER_1, None, evaluations); - let plmc_for_bidding = inst.calculate_auction_plmc_charged_with_given_price( - &bids.clone(), - project_metadata.minimum_price, - true, - ); + let plmc_for_bidding = + inst.calculate_auction_plmc_charged_with_given_price(&bids.clone(), project_metadata.minimum_price); let usdt_for_bidding = inst.calculate_auction_funding_asset_charged_with_given_price( &bids.clone(), project_metadata.minimum_price, ); + inst.mint_plmc_ed_if_required(bids.accounts()); inst.mint_plmc_to(plmc_for_bidding.clone()); + + inst.mint_funding_asset_ed_if_required(bids.to_account_asset_map()); inst.mint_funding_asset_to(usdt_for_bidding.clone()); + inst.bid_for_users(project_id, bids.clone()).unwrap(); let current_bucket = inst.execute(|| Buckets::::get(project_id)).unwrap(); @@ -1467,7 +1469,6 @@ mod bid_extrinsic { &vec![failing_bid.clone()], project_metadata.clone(), Some(current_bucket), - true, ); let usdt_for_bidding = inst.calculate_auction_funding_asset_charged_from_all_bids_made_or_with_bucket( &vec![failing_bid.clone()], @@ -2036,7 +2037,6 @@ mod end_auction_extrinsic { &bids, project_metadata.clone(), None, - false, ); let funding_asset_amounts = inst.calculate_auction_funding_asset_charged_from_all_bids_made_or_with_bucket( &bids, @@ -2044,10 +2044,13 @@ mod end_auction_extrinsic { None, ); - let plmc_existential_amounts = plmc_amounts.accounts().existential_deposits(); + inst.mint_plmc_ed_if_required(bids.accounts()); + inst.mint_funding_asset_ed_if_required(bids.to_account_asset_map()); + + let prev_plmc_balances = inst.get_free_plmc_balances_for(bids.accounts()); + let prev_funding_asset_balances = inst.get_free_funding_asset_balances_for(bids.to_account_asset_map()); inst.mint_plmc_to(plmc_amounts.clone()); - inst.mint_plmc_to(plmc_existential_amounts.clone()); inst.mint_funding_asset_to(funding_asset_amounts.clone()); inst.bid_for_users(project_id, bids.clone()).unwrap(); @@ -2066,12 +2069,12 @@ mod end_auction_extrinsic { let returned_funding_assets = inst.calculate_auction_funding_asset_returned_from_all_bids_made(&bids, project_metadata, wap); - let expected_free_plmc = inst.generic_map_operation( - vec![returned_auction_plmc.clone(), plmc_existential_amounts], + let expected_free_plmc = inst + .generic_map_operation(vec![returned_auction_plmc.clone(), prev_plmc_balances], MergeOperation::Add); + let expected_free_funding_assets = inst.generic_map_operation( + vec![returned_funding_assets.clone(), prev_funding_asset_balances], MergeOperation::Add, ); - let expected_free_funding_assets = - inst.generic_map_operation(vec![returned_funding_assets.clone()], MergeOperation::Add); let expected_reserved_plmc = inst.generic_map_operation(vec![plmc_amounts.clone(), returned_auction_plmc], MergeOperation::Subtract); let expected_final_funding_spent = inst.generic_map_operation( diff --git a/pallets/funding/src/tests/4_contribution.rs b/pallets/funding/src/tests/4_contribution.rs index 562e481c1..079586abf 100644 --- a/pallets/funding/src/tests/4_contribution.rs +++ b/pallets/funding/src/tests/4_contribution.rs @@ -88,13 +88,17 @@ mod round_flow { ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, )]; - let plmc_fundings = inst.calculate_contributed_plmc_spent(contributions.clone(), ct_price, false); - let plmc_existential_deposits = plmc_fundings.accounts().existential_deposits(); + let plmc_fundings = inst.calculate_contributed_plmc_spent(contributions.clone(), ct_price); let foreign_asset_fundings = inst.calculate_contributed_funding_asset_spent(contributions.clone(), ct_price); + inst.mint_plmc_ed_if_required(contributions.accounts()); + inst.mint_funding_asset_ed_if_required(contributions.to_account_asset_map()); + + let prev_free_funding_asset_balances = + inst.get_free_funding_asset_balances_for(contributions.to_account_asset_map()); + inst.mint_plmc_to(plmc_fundings.clone()); - inst.mint_plmc_to(plmc_existential_deposits.clone()); inst.mint_funding_asset_to(foreign_asset_fundings.clone()); // Buy remaining CTs @@ -112,13 +116,9 @@ mod round_flow { assert_eq!(inst.go_to_next_state(project_id), ProjectStatus::FundingSuccessful); assert_eq!(inst.go_to_next_state(project_id), ProjectStatus::SettlementStarted(FundingOutcome::Success)); - inst.do_free_plmc_assertions(plmc_existential_deposits); - inst.do_free_funding_asset_assertions(vec![UserToFundingAsset::::new( - BOB, - 0_u128, - AcceptedFundingAsset::USDT.id(), - )]); - inst.do_reserved_plmc_assertions(vec![plmc_fundings[0].clone()], HoldReason::Participation.into()); + // inst.do_free_plmc_assertions(plmc_existential_deposits); + inst.do_free_funding_asset_assertions(prev_free_funding_asset_balances); + inst.do_reserved_plmc_assertions(plmc_fundings, HoldReason::Participation.into()); } #[test] @@ -150,16 +150,16 @@ mod round_flow { let plmc_contribution_funding = inst.calculate_contributed_plmc_spent( contributions.clone(), project_details.weighted_average_price.unwrap(), - false, ); - let plmc_existential_deposits = plmc_contribution_funding.accounts().existential_deposits(); + + inst.mint_plmc_ed_if_required(contributions.accounts()); inst.mint_plmc_to(plmc_contribution_funding.clone()); - inst.mint_plmc_to(plmc_existential_deposits.clone()); let foreign_asset_contribution_funding = inst.calculate_contributed_funding_asset_spent( contributions.clone(), project_details.weighted_average_price.unwrap(), ); + inst.mint_funding_asset_ed_if_required(contributions.to_account_asset_map()); inst.mint_funding_asset_to(foreign_asset_contribution_funding.clone()); inst.contribute_for_users(project_id, contributions).unwrap(); @@ -278,6 +278,8 @@ mod round_flow { assert_eq!(total_funding_ct, 1_000_000 * 10u128.pow(decimals as u32)); // Buying all the remaining tokens. This is a fixed USD value, but the extrinsic amount depends on CT decimals. + inst.mint_plmc_ed_if_required(vec![BUYER_1]); + inst.mint_funding_asset_ed_if_required(vec![(BUYER_1, funding_asset.id())]); inst.mint_plmc_to(vec![UserToPLMCBalance::new(BUYER_1, total_funding_plmc + ed)]); inst.mint_funding_asset_to(vec![UserToFundingAsset::new( BUYER_1, @@ -332,6 +334,7 @@ mod contribute_extrinsic { #[cfg(test)] mod success { use super::*; + use crate::AcceptedFundingAsset::{DOT, USDC, USDT}; use frame_support::{dispatch::DispatchResultWithPostInfo, traits::fungible::InspectFreeze}; #[test] @@ -395,6 +398,7 @@ mod contribute_extrinsic { // Can partially use the usable evaluation bond (half in this case) let contribution_usdt = inst.calculate_contributed_funding_asset_spent(vec![(BOB, usable_ct / 2).into()], ct_price); + inst.mint_funding_asset_ed_if_required(vec![(BOB, AcceptedFundingAsset::USDT.id())]); inst.mint_funding_asset_to(contribution_usdt.clone()); inst.execute(|| { assert_ok!(Pallet::::contribute( @@ -415,6 +419,7 @@ mod contribute_extrinsic { // Can use the full evaluation bond let contribution_usdt = inst.calculate_contributed_funding_asset_spent(vec![(CARL, usable_ct).into()], ct_price); + inst.mint_funding_asset_ed_if_required(vec![(CARL, AcceptedFundingAsset::USDT.id())]); inst.mint_funding_asset_to(contribution_usdt.clone()); inst.execute(|| { assert_ok!(Pallet::::contribute( @@ -472,11 +477,11 @@ mod contribute_extrinsic { &bids, project_metadata.clone(), None, - true, ); // We don't want bob to get any PLMC bids_plmc.remove(2); + inst.mint_plmc_ed_if_required(bids.accounts()); inst.mint_plmc_to(bids_plmc.clone()); assert_eq!(inst.execute(|| Balances::free_balance(&bob)), inst.get_ed()); @@ -485,7 +490,9 @@ mod contribute_extrinsic { project_metadata.clone(), None, ); + inst.mint_funding_asset_ed_if_required(bids.to_account_asset_map()); inst.mint_funding_asset_to(bids_funding_assets.clone()); + inst.bid_for_users(project_id, bids).unwrap(); assert_eq!(inst.execute(|| Balances::free_balance(&bob)), inst.get_ed()); @@ -573,18 +580,23 @@ mod contribute_extrinsic { let plmc_fundings = inst.calculate_contributed_plmc_spent( vec![usdt_contribution.clone(), usdc_contribution.clone(), dot_contribution.clone()], wap, - false, ); let plmc_existential_deposits = plmc_fundings.accounts().existential_deposits(); let plmc_all_mints = inst.generic_map_operation(vec![plmc_fundings, plmc_existential_deposits], MergeOperation::Add); + inst.mint_plmc_ed_if_required(vec![BUYER_1, BUYER_2, BUYER_3]); inst.mint_plmc_to(plmc_all_mints.clone()); let asset_hub_fundings = inst.calculate_contributed_funding_asset_spent( vec![usdt_contribution.clone(), usdc_contribution.clone(), dot_contribution.clone()], wap, ); + inst.mint_funding_asset_ed_if_required(vec![ + (BUYER_1, USDT.id()), + (BUYER_2, USDC.id()), + (BUYER_3, DOT.id()), + ]); inst.mint_funding_asset_to(asset_hub_fundings.clone()); assert_ok!(inst.contribute_for_users( @@ -756,8 +768,8 @@ mod contribute_extrinsic { &all_bids.clone(), project_metadata.clone(), None, - true, ); + inst.mint_plmc_ed_if_required(plmc_fundings.accounts()); inst.mint_plmc_to(plmc_fundings.clone()); let foreign_funding = inst.calculate_auction_funding_asset_charged_from_all_bids_made_or_with_bucket( @@ -765,6 +777,7 @@ mod contribute_extrinsic { project_metadata.clone(), None, ); + inst.mint_funding_asset_ed_if_required(all_bids.to_account_asset_map()); inst.mint_funding_asset_to(foreign_funding.clone()); inst.bid_for_users(project_id, failing_bids_sold_out).unwrap(); @@ -843,11 +856,10 @@ mod contribute_extrinsic { ParticipationMode::Classic(1u8), AcceptedFundingAsset::USDT, ); - let plmc_required = inst.calculate_contributed_plmc_spent(vec![contribution.clone()], wap, false); + let plmc_required = inst.calculate_contributed_plmc_spent(vec![contribution.clone()], wap); let frozen_amount = plmc_required[0].plmc_amount; - let plmc_existential_deposits = plmc_required.accounts().existential_deposits(); - inst.mint_plmc_to(plmc_existential_deposits); + inst.mint_plmc_ed_if_required(vec![BUYER_4]); inst.mint_plmc_to(plmc_required.clone()); inst.execute(|| { @@ -855,6 +867,7 @@ mod contribute_extrinsic { }); let usdt_required = inst.calculate_contributed_funding_asset_spent(vec![contribution.clone()], wap); + inst.mint_funding_asset_ed_if_required(vec![(BUYER_4, AcceptedFundingAsset::USDT.id())]); inst.mint_funding_asset_to(usdt_required); inst.execute(|| { @@ -925,11 +938,10 @@ mod contribute_extrinsic { ParticipationMode::Classic(5u8), AcceptedFundingAsset::USDT, ); - let plmc_required = inst.calculate_contributed_plmc_spent(vec![contribution.clone()], wap, false); + let plmc_required = inst.calculate_contributed_plmc_spent(vec![contribution.clone()], wap); let frozen_amount = plmc_required[0].plmc_amount; - let plmc_existential_deposits = plmc_required.accounts().existential_deposits(); - inst.mint_plmc_to(plmc_existential_deposits); + inst.mint_plmc_ed_if_required(vec![BUYER_4]); inst.mint_plmc_to(plmc_required.clone()); inst.execute(|| { @@ -937,6 +949,7 @@ mod contribute_extrinsic { }); let usdt_required = inst.calculate_contributed_funding_asset_spent(vec![contribution.clone()], wap); + inst.mint_funding_asset_ed_if_required(vec![(BUYER_4, AcceptedFundingAsset::USDT.id())]); inst.mint_funding_asset_to(usdt_required); inst.execute(|| { @@ -1378,14 +1391,13 @@ mod contribute_extrinsic { }) .collect(); - let plmc_funding = inst.calculate_contributed_plmc_spent(contributions.clone(), token_price, false); - let plmc_existential_deposits = plmc_funding.accounts().existential_deposits(); - + let plmc_funding = inst.calculate_contributed_plmc_spent(contributions.clone(), token_price); let foreign_funding = inst.calculate_contributed_funding_asset_spent(contributions.clone(), token_price); + inst.mint_plmc_ed_if_required(contributions.accounts()); inst.mint_plmc_to(plmc_funding.clone()); - inst.mint_plmc_to(plmc_existential_deposits.clone()); + inst.mint_funding_asset_ed_if_required(contributions.to_account_asset_map()); inst.mint_funding_asset_to(foreign_funding.clone()); // Reach up to the limit of contributions for a user-project @@ -1408,7 +1420,10 @@ mod contribute_extrinsic { }); assert_eq!(contributor_post_buy_plmc_balance, inst.get_ed()); - assert_eq!(contributor_post_buy_foreign_asset_balance, 0); + assert_eq!( + contributor_post_buy_foreign_asset_balance, + inst.get_funding_asset_ed(AcceptedFundingAsset::USDT.id()) + ); let plmc_bond_stored = inst.execute(|| { ::NativeCurrency::balance_on_hold( @@ -1836,7 +1851,7 @@ mod contribute_extrinsic { let wap = inst.get_project_details(project_id).weighted_average_price.unwrap(); // 1 unit less native asset than needed - let plmc_funding = inst.calculate_contributed_plmc_spent(vec![contribution.clone()], wap, false); + let plmc_funding = inst.calculate_contributed_plmc_spent(vec![contribution.clone()], wap); let plmc_existential_deposits = plmc_funding.accounts().existential_deposits(); inst.mint_plmc_to(plmc_funding.clone()); inst.mint_plmc_to(plmc_existential_deposits.clone()); @@ -1862,7 +1877,7 @@ mod contribute_extrinsic { }); // 1 unit less funding asset than needed - let plmc_funding = inst.calculate_contributed_plmc_spent(vec![contribution.clone()], wap, false); + let plmc_funding = inst.calculate_contributed_plmc_spent(vec![contribution.clone()], wap); let plmc_existential_deposits = plmc_funding.accounts().existential_deposits(); inst.mint_plmc_to(plmc_funding.clone()); inst.mint_plmc_to(plmc_existential_deposits.clone()); @@ -2056,13 +2071,13 @@ mod contribute_extrinsic { let wap = inst.get_project_details(project_id_2).weighted_average_price.unwrap(); // Necessary Mints - let already_bonded_plmc = inst - .calculate_evaluation_plmc_spent(vec![(evaluator_contributor, evaluation_amount).into()], false)[0] - .plmc_amount; + let already_bonded_plmc = + inst.calculate_evaluation_plmc_spent(vec![(evaluator_contributor, evaluation_amount).into()])[0] + .plmc_amount; let usable_evaluation_plmc = already_bonded_plmc - ::EvaluatorSlash::get() * already_bonded_plmc; let necessary_plmc_for_contribution = - inst.calculate_contributed_plmc_spent(vec![evaluator_contribution.clone()], wap, false)[0].plmc_amount; + inst.calculate_contributed_plmc_spent(vec![evaluator_contribution.clone()], wap)[0].plmc_amount; let necessary_usdt_for_contribution = inst.calculate_contributed_funding_asset_spent(vec![evaluator_contribution.clone()], wap); inst.mint_plmc_to(vec![UserToPLMCBalance::new( @@ -2143,10 +2158,12 @@ mod contribute_extrinsic { AcceptedFundingAsset::USDT, ); let wap = project_details.weighted_average_price.unwrap(); - let plmc_mint = inst.calculate_contributed_plmc_spent(vec![glutton_contribution.clone()], wap, true); + let plmc_mint = inst.calculate_contributed_plmc_spent(vec![glutton_contribution.clone()], wap); let funding_asset_mint = inst.calculate_contributed_funding_asset_spent(vec![glutton_contribution.clone()], wap); + inst.mint_plmc_ed_if_required(vec![BUYER_1]); inst.mint_plmc_to(plmc_mint); + inst.mint_funding_asset_ed_if_required(vec![(BUYER_1, AcceptedFundingAsset::USDT.id())]); inst.mint_funding_asset_to(funding_asset_mint); inst.contribute_for_users(project_id, vec![glutton_contribution.clone()]).unwrap(); @@ -2156,10 +2173,13 @@ mod contribute_extrinsic { ParticipationMode::Classic(1), AcceptedFundingAsset::USDT, ); - let plmc_mint = inst.calculate_contributed_plmc_spent(vec![glutton_contribution.clone()], wap, true); + let plmc_mint = inst.calculate_contributed_plmc_spent(vec![glutton_contribution.clone()], wap); let funding_asset_mint = inst.calculate_contributed_funding_asset_spent(vec![glutton_contribution.clone()], wap); + + inst.mint_plmc_ed_if_required(vec![BUYER_2]); inst.mint_plmc_to(plmc_mint); + inst.mint_funding_asset_ed_if_required(vec![(BUYER_2, AcceptedFundingAsset::USDT.id())]); inst.mint_funding_asset_to(funding_asset_mint); inst.execute(|| { assert_noop!( diff --git a/pallets/funding/src/tests/6_settlement.rs b/pallets/funding/src/tests/6_settlement.rs index 1b65ee0b3..adc79329a 100644 --- a/pallets/funding/src/tests/6_settlement.rs +++ b/pallets/funding/src/tests/6_settlement.rs @@ -302,7 +302,8 @@ mod settle_evaluation_extrinsic { let evaluation = UserToUSDBalance::new(EVALUATOR_1, 1_000 * USD_UNIT); let project_id = inst.create_evaluating_project(project_metadata.clone(), ISSUER_1, None); - let evaluation_plmc = inst.calculate_evaluation_plmc_spent(vec![evaluation.clone()], true); + let evaluation_plmc = inst.calculate_evaluation_plmc_spent(vec![evaluation.clone()]); + inst.mint_plmc_ed_if_required(vec![EVALUATOR_1]); inst.mint_plmc_to(evaluation_plmc.clone()); inst.evaluate_for_users(project_id, vec![evaluation]).unwrap(); @@ -390,6 +391,8 @@ mod settle_bid_extrinsic { fn accepted_bid_with_refund_on_project_success() { let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); let ed = inst.get_ed(); + let usdt_ed = inst.get_funding_asset_ed(AcceptedFundingAsset::USDT.id()); + let dot_ed = inst.get_funding_asset_ed(AcceptedFundingAsset::DOT.id()); let mut project_metadata = default_project_metadata(ISSUER_1); project_metadata.participation_currencies = bounded_vec![AcceptedFundingAsset::USDT, AcceptedFundingAsset::DOT]; @@ -425,7 +428,6 @@ mod settle_bid_extrinsic { let expected_final_plmc_bonded = inst.calculate_auction_plmc_charged_with_given_price( &vec![final_partial_amount_bid_params.clone()], project_metadata.minimum_price, - false, )[0] .plmc_amount; let expected_final_usdt_paid = inst.calculate_auction_funding_asset_charged_with_given_price( @@ -451,7 +453,11 @@ mod settle_bid_extrinsic { project_metadata.funding_destination_account, ); - inst.assert_funding_asset_free_balance(BIDDER_1, AcceptedFundingAsset::USDT.id(), expected_usdt_refund); + inst.assert_funding_asset_free_balance( + BIDDER_1, + AcceptedFundingAsset::USDT.id(), + expected_usdt_refund + usdt_ed, + ); assert_eq!(post_issuer_usdt_balance, pre_issuer_usdt_balance + expected_final_usdt_paid); inst.assert_plmc_free_balance(BIDDER_1, expected_plmc_refund + ed); @@ -476,9 +482,8 @@ mod settle_bid_extrinsic { // Price > wap bid assertions let lower_price_bid_stored = inst.execute(|| Bids::::get((project_id, BIDDER_2, 1)).unwrap()); - let expected_final_plmc_bonded = - inst.calculate_auction_plmc_charged_with_given_price(&vec![lower_price_bid_params.clone()], wap, false) - [0] + let expected_final_plmc_bonded = inst + .calculate_auction_plmc_charged_with_given_price(&vec![lower_price_bid_params.clone()], wap)[0] .plmc_amount; let expected_final_dot_paid = inst .calculate_auction_funding_asset_charged_with_given_price(&vec![lower_price_bid_params.clone()], wap)[0] @@ -500,7 +505,11 @@ mod settle_bid_extrinsic { project_metadata.funding_destination_account, ); - inst.assert_funding_asset_free_balance(BIDDER_2, AcceptedFundingAsset::DOT.id(), expected_dot_refund); + inst.assert_funding_asset_free_balance( + BIDDER_2, + AcceptedFundingAsset::DOT.id(), + expected_dot_refund + dot_ed, + ); assert_eq!(post_issuer_dot_balance, pre_issuer_dot_balance + expected_final_dot_paid); inst.assert_plmc_free_balance(BIDDER_2, expected_plmc_refund + ed); @@ -532,6 +541,8 @@ mod settle_bid_extrinsic { fn accepted_bid_without_refund_on_project_success() { let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); let ed = inst.get_ed(); + let usdt_ed = inst.get_funding_asset_ed(AcceptedFundingAsset::USDT.id()); + let mut project_metadata = default_project_metadata(ISSUER_1); project_metadata.participation_currencies = bounded_vec![AcceptedFundingAsset::USDT, AcceptedFundingAsset::DOT]; @@ -571,7 +582,7 @@ mod settle_bid_extrinsic { project_metadata.funding_destination_account, ); - inst.assert_funding_asset_free_balance(BIDDER_1, AcceptedFundingAsset::USDT.id(), Zero::zero()); + inst.assert_funding_asset_free_balance(BIDDER_1, AcceptedFundingAsset::USDT.id(), usdt_ed); assert_eq!( post_issuer_usdc_balance, pre_issuer_usdc_balance + no_refund_bid_stored.funding_asset_amount_locked @@ -602,6 +613,9 @@ mod settle_bid_extrinsic { fn accepted_bid_with_refund_on_project_failure() { let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); let ed = inst.get_ed(); + let usdt_ed = inst.get_funding_asset_ed(AcceptedFundingAsset::USDT.id()); + let dot_ed = inst.get_funding_asset_ed(AcceptedFundingAsset::DOT.id()); + let mut project_metadata = default_project_metadata(ISSUER_1); project_metadata.participation_currencies = bounded_vec![AcceptedFundingAsset::USDC, AcceptedFundingAsset::DOT]; @@ -651,7 +665,7 @@ mod settle_bid_extrinsic { inst.assert_funding_asset_free_balance( BIDDER_1, AcceptedFundingAsset::USDC.id(), - partial_amount_bid_stored.funding_asset_amount_locked, + partial_amount_bid_stored.funding_asset_amount_locked + usdt_ed, ); assert_eq!(post_issuer_usdc_balance, pre_issuer_usdc_balance); @@ -687,7 +701,7 @@ mod settle_bid_extrinsic { inst.assert_funding_asset_free_balance( BIDDER_2, AcceptedFundingAsset::DOT.id(), - lower_price_bid_stored.funding_asset_amount_locked, + lower_price_bid_stored.funding_asset_amount_locked + dot_ed, ); assert_eq!(post_issuer_dot_balance, pre_issuer_dot_balance); @@ -708,6 +722,7 @@ mod settle_bid_extrinsic { fn accepted_bid_without_refund_on_project_failure() { let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); let ed = inst.get_ed(); + let usdt_ed = inst.get_funding_asset_ed(AcceptedFundingAsset::USDT.id()); let mut project_metadata = default_project_metadata(ISSUER_1); project_metadata.participation_currencies = bounded_vec![AcceptedFundingAsset::USDT, AcceptedFundingAsset::DOT]; @@ -745,7 +760,7 @@ mod settle_bid_extrinsic { inst.assert_funding_asset_free_balance( BIDDER_1, AcceptedFundingAsset::USDT.id(), - no_refund_bid_stored.funding_asset_amount_locked, + no_refund_bid_stored.funding_asset_amount_locked + usdt_ed, ); assert_eq!(post_issuer_usdc_balance, pre_issuer_usdc_balance); @@ -765,6 +780,7 @@ mod settle_bid_extrinsic { fn rejected_bid_on_community_round() { let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); let ed = inst.get_ed(); + let usdt_ed = inst.get_funding_asset_ed(AcceptedFundingAsset::USDT.id()); let mut project_metadata = default_project_metadata(ISSUER_1); project_metadata.participation_currencies = bounded_vec![AcceptedFundingAsset::USDT, AcceptedFundingAsset::DOT]; @@ -812,7 +828,7 @@ mod settle_bid_extrinsic { inst.assert_funding_asset_free_balance( BIDDER_1, AcceptedFundingAsset::USDT.id(), - rejected_bid_stored.funding_asset_amount_locked, + rejected_bid_stored.funding_asset_amount_locked + usdt_ed, ); assert_eq!(post_issuer_usdt_balance, pre_issuer_usdt_balance); @@ -832,6 +848,7 @@ mod settle_bid_extrinsic { fn rejected_bid_on_project_success() { let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); let ed = inst.get_ed(); + let usdt_ed = inst.get_funding_asset_ed(AcceptedFundingAsset::USDT.id()); let mut project_metadata = default_project_metadata(ISSUER_1); project_metadata.participation_currencies = bounded_vec![AcceptedFundingAsset::USDT, AcceptedFundingAsset::DOT]; @@ -882,7 +899,7 @@ mod settle_bid_extrinsic { inst.assert_funding_asset_free_balance( BIDDER_1, AcceptedFundingAsset::USDT.id(), - rejected_bid_stored.funding_asset_amount_locked, + rejected_bid_stored.funding_asset_amount_locked + usdt_ed, ); assert_eq!(post_issuer_usdt_balance, pre_issuer_usdt_balance); @@ -902,6 +919,7 @@ mod settle_bid_extrinsic { fn rejected_bid_on_project_failure() { let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); let ed = inst.get_ed(); + let usdt_ed = inst.get_funding_asset_ed(AcceptedFundingAsset::USDT.id()); let mut project_metadata = default_project_metadata(ISSUER_1); project_metadata.participation_currencies = bounded_vec![AcceptedFundingAsset::USDT, AcceptedFundingAsset::DOT]; @@ -953,7 +971,7 @@ mod settle_bid_extrinsic { inst.assert_funding_asset_free_balance( BIDDER_1, AcceptedFundingAsset::USDT.id(), - rejected_bid_stored.funding_asset_amount_locked, + rejected_bid_stored.funding_asset_amount_locked + usdt_ed, ); assert_eq!(post_issuer_usdt_balance, pre_issuer_usdt_balance); @@ -1034,6 +1052,7 @@ mod settle_contribution_extrinsic { fn contribution_on_successful_project() { let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); let ed = inst.get_ed(); + let usdt_ed = inst.get_funding_asset_ed(AcceptedFundingAsset::USDT.id()); let project_metadata = default_project_metadata(ISSUER_1); let contribution = ContributionParams::::new( @@ -1063,7 +1082,7 @@ mod settle_contribution_extrinsic { inst.assert_plmc_free_balance(BUYER_1, ed); inst.assert_plmc_held_balance(BUYER_1, stored_contribution.plmc_bond, hold_reason); inst.assert_ct_balance(project_id, BUYER_1, Zero::zero()); - inst.assert_funding_asset_free_balance(BUYER_1, AcceptedFundingAsset::USDT.id(), Zero::zero()); + inst.assert_funding_asset_free_balance(BUYER_1, AcceptedFundingAsset::USDT.id(), usdt_ed); inst.assert_funding_asset_free_balance( project_metadata.funding_destination_account, AcceptedFundingAsset::USDT.id(), @@ -1077,7 +1096,7 @@ mod settle_contribution_extrinsic { inst.assert_plmc_free_balance(BUYER_1, ed); inst.assert_plmc_held_balance(BUYER_1, stored_contribution.plmc_bond, hold_reason); inst.assert_ct_balance(project_id, BUYER_1, stored_contribution.ct_amount); - inst.assert_funding_asset_free_balance(BUYER_1, AcceptedFundingAsset::USDT.id(), Zero::zero()); + inst.assert_funding_asset_free_balance(BUYER_1, AcceptedFundingAsset::USDT.id(), usdt_ed); inst.assert_funding_asset_free_balance( project_metadata.funding_destination_account, AcceptedFundingAsset::USDT.id(), @@ -1148,11 +1167,10 @@ mod settle_contribution_extrinsic { ); let wap = inst.get_project_details(project_id).weighted_average_price.unwrap(); - let plmc_required = inst.calculate_contributed_plmc_spent(vec![contribution_mul_2.clone()], wap, false); - let plmc_ed = plmc_required.accounts().existential_deposits(); + let plmc_required = inst.calculate_contributed_plmc_spent(vec![contribution_mul_2.clone()], wap); + inst.mint_plmc_ed_if_required(plmc_required.accounts()); inst.mint_plmc_to(plmc_required.clone()); - inst.mint_plmc_to(plmc_ed); - + inst.mint_funding_asset_ed_if_required(vec![(BUYER_7, AcceptedFundingAsset::USDT.id())]); let usdt_required = inst.calculate_contributed_funding_asset_spent(vec![contribution_mul_2.clone()], wap); inst.mint_funding_asset_to(usdt_required.clone()); diff --git a/pallets/funding/src/tests/misc.rs b/pallets/funding/src/tests/misc.rs index 7d91f5840..859d962c2 100644 --- a/pallets/funding/src/tests/misc.rs +++ b/pallets/funding/src/tests/misc.rs @@ -112,7 +112,7 @@ mod helper_functions { ]; let calculated_plmc_spent = inst - .calculate_evaluation_plmc_spent(evaluations, false) + .calculate_evaluation_plmc_spent(evaluations) .into_iter() .sorted_by(|a, b| a.account.cmp(&b.account)) .map(|map| map.plmc_amount) @@ -332,7 +332,6 @@ mod helper_functions { CT_DECIMALS, ) .unwrap(), - false, ) .into_iter() .sorted_by(|a, b| a.account.cmp(&b.account)) diff --git a/pallets/funding/src/tests/mod.rs b/pallets/funding/src/tests/mod.rs index a1032b8a7..2a9de406a 100644 --- a/pallets/funding/src/tests/mod.rs +++ b/pallets/funding/src/tests/mod.rs @@ -508,9 +508,11 @@ pub fn create_finished_project_with_usd_raised( default_community_contributors(), default_modes(), ); - let plmc_required = inst.calculate_contributed_plmc_spent(community_contributions.clone(), required_price, true); + let plmc_required = inst.calculate_contributed_plmc_spent(community_contributions.clone(), required_price); let usdt_required = inst.calculate_contributed_funding_asset_spent(community_contributions.clone(), required_price); + inst.mint_plmc_ed_if_required(plmc_required.accounts()); inst.mint_plmc_to(plmc_required); + inst.mint_funding_asset_ed_if_required(usdt_required.to_account_asset_map()); inst.mint_funding_asset_to(usdt_required); inst.contribute_for_users(project_id, community_contributions).unwrap(); diff --git a/pallets/funding/src/tests/runtime_api.rs b/pallets/funding/src/tests/runtime_api.rs index 213d615b4..189d3f2e2 100644 --- a/pallets/funding/src/tests/runtime_api.rs +++ b/pallets/funding/src/tests/runtime_api.rs @@ -407,12 +407,8 @@ fn funding_asset_to_ct_amount() { |acc| acc + 1, AcceptedFundingAsset::USDT, ); - let necessary_plmc = inst.calculate_auction_plmc_charged_from_all_bids_made_or_with_bucket( - &bids, - project_metadata_3.clone(), - None, - true, - ); + let necessary_plmc = + inst.calculate_auction_plmc_charged_from_all_bids_made_or_with_bucket(&bids, project_metadata_3.clone(), None); let necessary_usdt = inst.calculate_auction_funding_asset_charged_from_all_bids_made_or_with_bucket( &bids, project_metadata_3.clone(), @@ -600,27 +596,18 @@ fn all_project_participations_by_did() { ), ]; - let evaluations_plmc = inst.calculate_evaluation_plmc_spent(evaluations.clone(), true); - let bids_plmc = inst.calculate_auction_plmc_charged_from_all_bids_made_or_with_bucket( - &bids, - project_metadata.clone(), - None, - true, - ); - let community_contributions_plmc = inst.calculate_contributed_plmc_spent( - community_contributions.clone(), - project_metadata.minimum_price.clone(), - true, - ); - let remainder_contributions_plmc = inst.calculate_contributed_plmc_spent( - remainder_contributions.clone(), - project_metadata.minimum_price.clone(), - true, - ); + let evaluations_plmc = inst.calculate_evaluation_plmc_spent(evaluations.clone()); + let bids_plmc = + inst.calculate_auction_plmc_charged_from_all_bids_made_or_with_bucket(&bids, project_metadata.clone(), None); + let community_contributions_plmc = + inst.calculate_contributed_plmc_spent(community_contributions.clone(), project_metadata.minimum_price.clone()); + let remainder_contributions_plmc = + inst.calculate_contributed_plmc_spent(remainder_contributions.clone(), project_metadata.minimum_price.clone()); let all_plmc = inst.generic_map_operation( vec![evaluations_plmc, bids_plmc, community_contributions_plmc, remainder_contributions_plmc], MergeOperation::Add, ); + inst.mint_plmc_ed_if_required(all_plmc.accounts()); inst.mint_plmc_to(all_plmc); let bids_usdt = inst.calculate_auction_funding_asset_charged_from_all_bids_made_or_with_bucket( @@ -640,6 +627,7 @@ fn all_project_participations_by_did() { vec![bids_usdt, community_contributions_usdt, remainder_contributions_usdt], MergeOperation::Add, ); + inst.mint_funding_asset_ed_if_required(all_usdt.to_account_asset_map()); inst.mint_funding_asset_to(all_usdt); inst.evaluate_for_users(project_id, evaluations[..1].to_vec()).unwrap();