From 80fbb7fdd65ac545e089153dd405de71ac73d5cb Mon Sep 17 00:00:00 2001 From: Juan Ignacio Rios Date: Mon, 27 May 2024 13:56:45 +0200 Subject: [PATCH] test-freeze-contribution-interaction --- pallets/funding/src/tests/2_evaluation.rs | 6 +- pallets/funding/src/tests/4_community.rs | 240 ++++++++++++++++++++- pallets/funding/src/tests/5_remainder.rs | 243 ++++++++++++++++++++++ 3 files changed, 483 insertions(+), 6 deletions(-) diff --git a/pallets/funding/src/tests/2_evaluation.rs b/pallets/funding/src/tests/2_evaluation.rs index 10a824296..799266e74 100644 --- a/pallets/funding/src/tests/2_evaluation.rs +++ b/pallets/funding/src/tests/2_evaluation.rs @@ -484,12 +484,8 @@ mod evaluate_extrinsic { #[cfg(test)] mod success { use super::*; - use frame_support::traits::{ - fungible::{InspectFreeze, Mutate}, - tokens::Preservation, - }; + use frame_support::traits::fungible::InspectFreeze; use pallet_balances::AccountData; - use sp_runtime::DispatchError::Token; #[test] fn all_investor_types() { diff --git a/pallets/funding/src/tests/4_community.rs b/pallets/funding/src/tests/4_community.rs index e041482b7..c3741171c 100644 --- a/pallets/funding/src/tests/4_community.rs +++ b/pallets/funding/src/tests/4_community.rs @@ -315,7 +315,9 @@ mod community_contribute_extrinsic { #[cfg(test)] mod success { use super::*; - use frame_support::dispatch::DispatchResultWithPostInfo; + use frame_support::{dispatch::DispatchResultWithPostInfo, traits::fungible::InspectFreeze}; + use pallet_balances::AccountData; + use polimec_common_test_utils::get_mock_jwt; #[test] fn evaluation_bond_counts_towards_contribution() { @@ -842,6 +844,242 @@ mod community_contribute_extrinsic { bid_should_succeed(BIDDER_6, InvestorType::Retail, BIDDER_6); bid_should_succeed(BUYER_6, InvestorType::Retail, BIDDER_6); } + + #[test] + fn can_contribute_with_frozen_tokens_funding_failed() { + let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); + let issuer = ISSUER_1; + let project_metadata = default_project_metadata(issuer); + let project_id = inst.create_community_contributing_project( + project_metadata.clone(), + issuer, + default_evaluations(), + vec![], + ); + let wap = inst.get_project_details(project_id).weighted_average_price.unwrap(); + + let contribution = ContributionParams::new(BUYER_4, 500 * CT_UNIT, 1u8, AcceptedFundingAsset::USDT); + 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_to(plmc_required.clone()); + + inst.execute(|| { + mock::Balances::set_freeze(&(), &BUYER_4, plmc_required[0].plmc_amount).unwrap(); + }); + + let usdt_required = inst.calculate_contributed_funding_asset_spent(vec![contribution.clone()], wap); + inst.mint_foreign_asset_to(usdt_required); + + inst.execute(|| { + assert_noop!( + Balances::transfer_allow_death(RuntimeOrigin::signed(BUYER_4), ISSUER_1, frozen_amount,), + TokenError::Frozen + ); + }); + + inst.execute(|| { + assert_ok!(PolimecFunding::community_contribute( + RuntimeOrigin::signed(BUYER_4), + get_mock_jwt_with_cid( + BUYER_4, + InvestorType::Institutional, + generate_did_from_account(BUYER_4), + project_metadata.clone().policy_ipfs_cid.unwrap() + ), + project_id, + contribution.amount, + contribution.multiplier, + contribution.asset + )); + }); + + inst.start_remainder_or_end_funding(project_id).unwrap(); + inst.finish_funding(project_id).unwrap(); + + assert_eq!(inst.get_project_details(project_id).status, ProjectStatus::FundingFailed); + + let free_balance = inst.get_free_plmc_balance_for(BUYER_4); + let bid_held_balance = + inst.get_reserved_plmc_balance_for(BUYER_4, HoldReason::Participation(project_id).into()); + let frozen_balance = inst.execute(|| mock::Balances::balance_frozen(&(), &BUYER_4)); + let account_data = inst.execute(|| System::account(&BUYER_4)).data; + + assert_eq!(free_balance, inst.get_ed()); + assert_eq!(bid_held_balance, frozen_amount); + assert_eq!(frozen_balance, frozen_amount); + let expected_account_data = AccountData { + free: inst.get_ed(), + reserved: frozen_amount, + frozen: frozen_amount, + flags: Default::default(), + }; + assert_eq!(account_data, expected_account_data); + + inst.execute(|| { + PolimecFunding::settle_failed_contribution(RuntimeOrigin::signed(BUYER_4), project_id, BUYER_4, 0) + .unwrap(); + }); + + let free_balance = inst.get_free_plmc_balance_for(BUYER_4); + let bid_held_balance = + inst.get_reserved_plmc_balance_for(BUYER_4, HoldReason::Evaluation(project_id).into()); + let frozen_balance = inst.execute(|| mock::Balances::balance_frozen(&(), &BUYER_4)); + let account_data = inst.execute(|| System::account(&BUYER_4)).data; + + assert_eq!(free_balance, inst.get_ed() + frozen_amount); + assert_eq!(bid_held_balance, Zero::zero()); + assert_eq!(frozen_balance, frozen_amount); + let expected_account_data = AccountData { + free: inst.get_ed() + frozen_amount, + reserved: Zero::zero(), + frozen: frozen_amount, + flags: Default::default(), + }; + assert_eq!(account_data, expected_account_data); + assert_eq!(account_data.frozen, account_data.free - inst.get_ed()); + } + + #[test] + fn can_contribute_with_frozen_tokens_funding_success() { + let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); + let issuer = ISSUER_1; + let project_metadata = default_project_metadata(issuer); + let project_id = inst.create_community_contributing_project( + project_metadata.clone(), + issuer, + default_evaluations(), + default_bids(), + ); + let wap = inst.get_project_details(project_id).weighted_average_price.unwrap(); + + let contribution = ContributionParams::new(BUYER_4, 500 * CT_UNIT, 5u8, AcceptedFundingAsset::USDT); + 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_to(plmc_required.clone()); + + inst.execute(|| { + mock::Balances::set_freeze(&(), &BUYER_4, plmc_required[0].plmc_amount).unwrap(); + }); + + let usdt_required = inst.calculate_contributed_funding_asset_spent(vec![contribution.clone()], wap); + inst.mint_foreign_asset_to(usdt_required); + + inst.execute(|| { + assert_noop!( + Balances::transfer_allow_death(RuntimeOrigin::signed(BUYER_4), ISSUER_1, frozen_amount,), + TokenError::Frozen + ); + }); + + inst.execute(|| { + assert_ok!(PolimecFunding::community_contribute( + RuntimeOrigin::signed(BUYER_4), + get_mock_jwt_with_cid( + BUYER_4, + InvestorType::Institutional, + generate_did_from_account(BUYER_4), + project_metadata.clone().policy_ipfs_cid.unwrap() + ), + project_id, + contribution.amount, + contribution.multiplier, + contribution.asset + )); + }); + + inst.start_remainder_or_end_funding(project_id).unwrap(); + inst.finish_funding(project_id).unwrap(); + + assert_eq!(inst.get_project_details(project_id).status, ProjectStatus::AwaitingProjectDecision); + inst.execute(|| { + assert_ok!(PolimecFunding::decide_project_outcome( + RuntimeOrigin::signed(ISSUER_1), + get_mock_jwt(ISSUER_1, InvestorType::Institutional, generate_did_from_account(ISSUER_1)), + project_id, + FundingOutcomeDecision::AcceptFunding + )); + }); + let decision_block = inst + .get_update_block(project_id, &UpdateType::ProjectDecision(FundingOutcomeDecision::AcceptFunding)) + .unwrap(); + inst.jump_to_block(decision_block); + + let settlement_block = inst.get_update_block(project_id, &UpdateType::StartSettlement).unwrap(); + inst.jump_to_block(settlement_block); + + let free_balance = inst.get_free_plmc_balance_for(BUYER_4); + let bid_held_balance = + inst.get_reserved_plmc_balance_for(BUYER_4, HoldReason::Participation(project_id).into()); + let frozen_balance = inst.execute(|| mock::Balances::balance_frozen(&(), &BUYER_4)); + let account_data = inst.execute(|| System::account(&BUYER_4)).data; + + assert_eq!(free_balance, inst.get_ed()); + assert_eq!(bid_held_balance, frozen_amount); + assert_eq!(frozen_balance, frozen_amount); + let expected_account_data = AccountData { + free: inst.get_ed(), + reserved: frozen_amount, + frozen: frozen_amount, + flags: Default::default(), + }; + assert_eq!(account_data, expected_account_data); + + inst.execute(|| { + PolimecFunding::settle_successful_contribution(RuntimeOrigin::signed(BUYER_4), project_id, BUYER_4, 0) + .unwrap(); + }); + + let free_balance = inst.get_free_plmc_balance_for(BUYER_4); + let bid_held_balance = + inst.get_reserved_plmc_balance_for(BUYER_4, HoldReason::Participation(project_id).into()); + let frozen_balance = inst.execute(|| mock::Balances::balance_frozen(&(), &BUYER_4)); + let account_data = inst.execute(|| System::account(&BUYER_4)).data; + + assert_eq!(free_balance, inst.get_ed()); + assert_eq!(bid_held_balance, frozen_amount); + assert_eq!(frozen_balance, frozen_amount); + let expected_account_data = AccountData { + free: inst.get_ed(), + reserved: frozen_amount, + frozen: frozen_amount, + flags: Default::default(), + }; + assert_eq!(account_data, expected_account_data); + + let vest_duration = + MultiplierOf::::new(5u8).unwrap().calculate_vesting_duration::(); + let now = inst.current_block(); + inst.jump_to_block(now + vest_duration + 1u64); + inst.execute(|| { + assert_ok!(mock::LinearRelease::vest( + RuntimeOrigin::signed(BUYER_4), + HoldReason::Participation(project_id).into() + )); + }); + + let free_balance = inst.get_free_plmc_balance_for(BUYER_4); + let bid_held_balance = + inst.get_reserved_plmc_balance_for(BUYER_4, HoldReason::Participation(project_id).into()); + let frozen_balance = inst.execute(|| mock::Balances::balance_frozen(&(), &BUYER_4)); + let account_data = inst.execute(|| System::account(&BUYER_4)).data; + + assert_eq!(free_balance, inst.get_ed() + frozen_amount); + assert_eq!(bid_held_balance, Zero::zero()); + assert_eq!(frozen_balance, frozen_amount); + let expected_account_data = AccountData { + free: inst.get_ed() + frozen_amount, + reserved: Zero::zero(), + frozen: frozen_amount, + flags: Default::default(), + }; + assert_eq!(account_data, expected_account_data); + } } #[cfg(test)] diff --git a/pallets/funding/src/tests/5_remainder.rs b/pallets/funding/src/tests/5_remainder.rs index a5d7f79c9..e6f953269 100644 --- a/pallets/funding/src/tests/5_remainder.rs +++ b/pallets/funding/src/tests/5_remainder.rs @@ -329,6 +329,8 @@ mod remaining_contribute_extrinsic { #[cfg(test)] mod success { use super::*; + use frame_support::traits::fungible::InspectFreeze; + use pallet_balances::AccountData; #[test] fn evaluation_bond_counts_towards_contribution() { @@ -974,6 +976,247 @@ mod remaining_contribute_extrinsic { bid_should_succeed(BIDDER_6, InvestorType::Retail, BIDDER_6); bid_should_succeed(BUYER_6, InvestorType::Retail, BIDDER_6); } + + #[test] + fn can_contribute_with_frozen_tokens_funding_failed() { + let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); + let issuer = ISSUER_1; + let project_metadata = default_project_metadata(issuer); + let project_id = inst.create_remainder_contributing_project( + project_metadata.clone(), + issuer, + default_evaluations(), + vec![], + vec![], + ); + let wap = inst.get_project_details(project_id).weighted_average_price.unwrap(); + + let contribution = ContributionParams::new(BUYER_4, 500 * CT_UNIT, 1u8, AcceptedFundingAsset::USDT); + 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_to(plmc_required.clone()); + + inst.execute(|| { + mock::Balances::set_freeze(&(), &BUYER_4, plmc_required[0].plmc_amount).unwrap(); + }); + + let usdt_required = inst.calculate_contributed_funding_asset_spent(vec![contribution.clone()], wap); + inst.mint_foreign_asset_to(usdt_required); + + inst.execute(|| { + assert_noop!( + Balances::transfer_allow_death(RuntimeOrigin::signed(BUYER_4), ISSUER_1, frozen_amount,), + TokenError::Frozen + ); + }); + + inst.execute(|| { + assert_ok!(PolimecFunding::remaining_contribute( + RuntimeOrigin::signed(BUYER_4), + get_mock_jwt_with_cid( + BUYER_4, + InvestorType::Institutional, + generate_did_from_account(BUYER_4), + project_metadata.clone().policy_ipfs_cid.unwrap() + ), + project_id, + contribution.amount, + contribution.multiplier, + contribution.asset + )); + }); + + inst.finish_funding(project_id).unwrap(); + + assert_eq!(inst.get_project_details(project_id).status, ProjectStatus::FundingFailed); + + let free_balance = inst.get_free_plmc_balance_for(BUYER_4); + let bid_held_balance = + inst.get_reserved_plmc_balance_for(BUYER_4, HoldReason::Participation(project_id).into()); + let frozen_balance = inst.execute(|| mock::Balances::balance_frozen(&(), &BUYER_4)); + let account_data = inst.execute(|| System::account(&BUYER_4)).data; + + assert_eq!(free_balance, inst.get_ed()); + assert_eq!(bid_held_balance, frozen_amount); + assert_eq!(frozen_balance, frozen_amount); + let expected_account_data = AccountData { + free: inst.get_ed(), + reserved: frozen_amount, + frozen: frozen_amount, + flags: Default::default(), + }; + assert_eq!(account_data, expected_account_data); + + inst.execute(|| { + PolimecFunding::settle_failed_contribution(RuntimeOrigin::signed(BUYER_4), project_id, BUYER_4, 0) + .unwrap(); + }); + + let free_balance = inst.get_free_plmc_balance_for(BUYER_4); + let bid_held_balance = + inst.get_reserved_plmc_balance_for(BUYER_4, HoldReason::Evaluation(project_id).into()); + let frozen_balance = inst.execute(|| mock::Balances::balance_frozen(&(), &BUYER_4)); + let account_data = inst.execute(|| System::account(&BUYER_4)).data; + + assert_eq!(free_balance, inst.get_ed() + frozen_amount); + assert_eq!(bid_held_balance, Zero::zero()); + assert_eq!(frozen_balance, frozen_amount); + let expected_account_data = AccountData { + free: inst.get_ed() + frozen_amount, + reserved: Zero::zero(), + frozen: frozen_amount, + flags: Default::default(), + }; + assert_eq!(account_data, expected_account_data); + assert_eq!(account_data.frozen, account_data.free - inst.get_ed()); + } + + #[test] + fn can_contribute_with_frozen_tokens_funding_success() { + let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); + let issuer = ISSUER_1; + let project_metadata = default_project_metadata(issuer); + let project_id = inst.create_remainder_contributing_project( + project_metadata.clone(), + issuer, + default_evaluations(), + default_bids(), + vec![], + ); + let wap = inst.get_project_details(project_id).weighted_average_price.unwrap(); + + let contribution = ContributionParams::new(BUYER_4, 500 * CT_UNIT, 5u8, AcceptedFundingAsset::USDT); + 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_to(plmc_required.clone()); + + inst.execute(|| { + mock::Balances::set_freeze(&(), &BUYER_4, plmc_required[0].plmc_amount).unwrap(); + }); + + let usdt_required = inst.calculate_contributed_funding_asset_spent(vec![contribution.clone()], wap); + inst.mint_foreign_asset_to(usdt_required); + + inst.execute(|| { + assert_noop!( + Balances::transfer_allow_death(RuntimeOrigin::signed(BUYER_4), ISSUER_1, frozen_amount,), + TokenError::Frozen + ); + }); + + inst.execute(|| { + assert_ok!(PolimecFunding::remaining_contribute( + RuntimeOrigin::signed(BUYER_4), + get_mock_jwt_with_cid( + BUYER_4, + InvestorType::Institutional, + generate_did_from_account(BUYER_4), + project_metadata.clone().policy_ipfs_cid.unwrap() + ), + project_id, + contribution.amount, + contribution.multiplier, + contribution.asset + )); + }); + + inst.finish_funding(project_id).unwrap(); + + assert_eq!(inst.get_project_details(project_id).status, ProjectStatus::AwaitingProjectDecision); + inst.execute(|| { + assert_ok!(PolimecFunding::decide_project_outcome( + RuntimeOrigin::signed(ISSUER_1), + get_mock_jwt_with_cid( + ISSUER_1, + InvestorType::Institutional, + generate_did_from_account(ISSUER_1), + project_metadata.policy_ipfs_cid.unwrap() + ), + project_id, + FundingOutcomeDecision::AcceptFunding + )); + }); + let decision_block = inst + .get_update_block(project_id, &UpdateType::ProjectDecision(FundingOutcomeDecision::AcceptFunding)) + .unwrap(); + inst.jump_to_block(decision_block); + + let settlement_block = inst.get_update_block(project_id, &UpdateType::StartSettlement).unwrap(); + inst.jump_to_block(settlement_block); + + let free_balance = inst.get_free_plmc_balance_for(BUYER_4); + let bid_held_balance = + inst.get_reserved_plmc_balance_for(BUYER_4, HoldReason::Participation(project_id).into()); + let frozen_balance = inst.execute(|| mock::Balances::balance_frozen(&(), &BUYER_4)); + let account_data = inst.execute(|| System::account(&BUYER_4)).data; + + assert_eq!(free_balance, inst.get_ed()); + assert_eq!(bid_held_balance, frozen_amount); + assert_eq!(frozen_balance, frozen_amount); + let expected_account_data = AccountData { + free: inst.get_ed(), + reserved: frozen_amount, + frozen: frozen_amount, + flags: Default::default(), + }; + assert_eq!(account_data, expected_account_data); + + inst.execute(|| { + PolimecFunding::settle_successful_contribution(RuntimeOrigin::signed(BUYER_4), project_id, BUYER_4, 0) + .unwrap(); + }); + + let free_balance = inst.get_free_plmc_balance_for(BUYER_4); + let bid_held_balance = + inst.get_reserved_plmc_balance_for(BUYER_4, HoldReason::Participation(project_id).into()); + let frozen_balance = inst.execute(|| mock::Balances::balance_frozen(&(), &BUYER_4)); + let account_data = inst.execute(|| System::account(&BUYER_4)).data; + + assert_eq!(free_balance, inst.get_ed()); + assert_eq!(bid_held_balance, frozen_amount); + assert_eq!(frozen_balance, frozen_amount); + let expected_account_data = AccountData { + free: inst.get_ed(), + reserved: frozen_amount, + frozen: frozen_amount, + flags: Default::default(), + }; + assert_eq!(account_data, expected_account_data); + + let vest_duration = + MultiplierOf::::new(5u8).unwrap().calculate_vesting_duration::(); + let now = inst.current_block(); + inst.jump_to_block(now + vest_duration + 1u64); + inst.execute(|| { + assert_ok!(mock::LinearRelease::vest( + RuntimeOrigin::signed(BUYER_4), + HoldReason::Participation(project_id).into() + )); + }); + + let free_balance = inst.get_free_plmc_balance_for(BUYER_4); + let bid_held_balance = + inst.get_reserved_plmc_balance_for(BUYER_4, HoldReason::Participation(project_id).into()); + let frozen_balance = inst.execute(|| mock::Balances::balance_frozen(&(), &BUYER_4)); + let account_data = inst.execute(|| System::account(&BUYER_4)).data; + + assert_eq!(free_balance, inst.get_ed() + frozen_amount); + assert_eq!(bid_held_balance, Zero::zero()); + assert_eq!(frozen_balance, frozen_amount); + let expected_account_data = AccountData { + free: inst.get_ed() + frozen_amount, + reserved: Zero::zero(), + frozen: frozen_amount, + flags: Default::default(), + }; + assert_eq!(account_data, expected_account_data); + } } #[cfg(test)]