Skip to content

Commit

Permalink
✅ Test freeze restrictions on contributions (#308)
Browse files Browse the repository at this point in the history
## What?
- Test what happens when you contribute (community/remainder) with frozen balance, i.e. a hold on a freeze.

## Why?
- To double-check our assumptions about these interactions

## How?
- An contributor holds ED + an amount frozen.
- It uses that frozen amount to contribute
- The project fails / succeeds
- If it fails, he gets the PLMC back, if it succeeds, he waits and then vests the full amount.
- In the end, the user still has the freeze restriction

## Testing?
`can_contribute_with_frozen_tokens_funding_success` and  `can_contribute_with_frozen_tokens_funding_failed`
  • Loading branch information
JuaniRios committed Jun 11, 2024
1 parent 6775ef7 commit 8fcf294
Show file tree
Hide file tree
Showing 5 changed files with 442 additions and 9 deletions.
7 changes: 1 addition & 6 deletions pallets/funding/src/tests/2_evaluation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -675,7 +671,6 @@ mod evaluate_extrinsic {
let evaluation_held_balance =
inst.get_reserved_plmc_balance_for(EVALUATOR_4, HoldReason::Evaluation(project_id).into());
let frozen_balance = inst.execute(|| mock::Balances::balance_frozen(&(), &EVALUATOR_4));
let account_data = inst.execute(|| System::account(&EVALUATOR_4)).data;

assert_eq!(free_balance, inst.get_ed());
assert_eq!(evaluation_held_balance, frozen_amount);
Expand Down
1 change: 0 additions & 1 deletion pallets/funding/src/tests/3_auction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -866,7 +866,6 @@ mod bid_extrinsic {
mod success {
use super::*;
use frame_support::{dispatch::DispatchResultWithPostInfo, traits::fungible::InspectFreeze};
use pallet_balances::AccountData;

#[test]
fn evaluation_bond_counts_towards_bid() {
Expand Down
198 changes: 197 additions & 1 deletion pallets/funding/src/tests/4_community.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,8 @@ mod community_contribute_extrinsic {
#[cfg(test)]
mod success {
use super::*;
use frame_support::dispatch::DispatchResultWithPostInfo;
use frame_support::{dispatch::DispatchResultWithPostInfo, traits::fungible::InspectFreeze};
use polimec_common_test_utils::get_mock_jwt;

#[test]
fn evaluation_bond_counts_towards_contribution() {
Expand Down Expand Up @@ -842,6 +843,201 @@ 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));

assert_eq!(free_balance, inst.get_ed());
assert_eq!(bid_held_balance, frozen_amount);
assert_eq!(frozen_balance, frozen_amount);

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));

assert_eq!(free_balance, inst.get_ed() + frozen_amount);
assert_eq!(bid_held_balance, Zero::zero());
assert_eq!(frozen_balance, frozen_amount);
}

#[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));

assert_eq!(free_balance, inst.get_ed());
assert_eq!(bid_held_balance, frozen_amount);
assert_eq!(frozen_balance, frozen_amount);

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));

assert_eq!(free_balance, inst.get_ed());
assert_eq!(bid_held_balance, frozen_amount);
assert_eq!(frozen_balance, frozen_amount);

let vest_duration =
MultiplierOf::<TestRuntime>::new(5u8).unwrap().calculate_vesting_duration::<TestRuntime>();
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));

assert_eq!(free_balance, inst.get_ed() + frozen_amount);
assert_eq!(bid_held_balance, Zero::zero());
assert_eq!(frozen_balance, frozen_amount);
}
}

#[cfg(test)]
Expand Down
Loading

0 comments on commit 8fcf294

Please sign in to comment.