Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🧪 One Token Model - Pallet Funding Tests #402

Merged
merged 1 commit into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 8 additions & 10 deletions integration-tests/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ pub mod polimec {
let dot = (AcceptedFundingAsset::DOT.id(), prices.dot);
let usdc = (AcceptedFundingAsset::USDC.id(), prices.usdc);
let usdt = (AcceptedFundingAsset::USDT.id(), prices.usdt);
let plmc = (pallet_funding::PLMC_FOREIGN_ID, prices.plmc);
let plmc = (polimec_common::PLMC_FOREIGN_ID, prices.plmc);

let values: BoundedVec<(u32, FixedU128), <PolimecRuntime as orml_oracle::Config>::MaxFeedValues> =
vec![dot, usdc, usdt, plmc].try_into().expect("benchmarks can panic");
Expand Down Expand Up @@ -501,29 +501,27 @@ pub mod polimec {

funded_accounts.extend(accounts::init_balances().iter().cloned().map(|k| (k, INITIAL_DEPOSIT)));
funded_accounts.extend(collators::initial_authorities().iter().cloned().map(|(acc, _)| (acc, 20_005 * PLMC)));
funded_accounts.push((TreasuryAccount::get(), 20_005 * PLMC));
funded_accounts.push((TreasuryAccount::get(), 20_000_000 * PLMC));
funded_accounts.push((BlockchainOperationTreasury::get(), 20_005 * PLMC));
/// Treasury account needs PLMC for the One Token Model participations
funded_accounts.push((polimec_runtime::FeeRecipient::get(), INITIAL_DEPOSIT));

let genesis_config = polimec_runtime::RuntimeGenesisConfig {
system: Default::default(),
balances: polimec_runtime::BalancesConfig { balances: funded_accounts },
contribution_tokens: Default::default(),
foreign_assets: polimec_runtime::ForeignAssetsConfig {
assets: vec![
(dot_asset_id, alice_account.clone(), true, 0_0_010_000_000u128),
(usdt_asset_id, alice_account.clone(), true, 0_0_010_000_000u128),
(usdc_asset_id, alice_account.clone(), true, 0_0_010_000_000u128),
(dot_asset_id, alice_account.clone(), true, 100_000_000),
(usdt_asset_id, alice_account.clone(), true, 70_000),
(usdc_asset_id, alice_account.clone(), true, 70_000),
],
metadata: vec![
(dot_asset_id, "Local DOT".as_bytes().to_vec(), "DOT".as_bytes().to_vec(), 10),
(usdt_asset_id, "Local USDT".as_bytes().to_vec(), "USDT".as_bytes().to_vec(), 6),
(usdc_asset_id, "Local USDC".as_bytes().to_vec(), "USDC".as_bytes().to_vec(), 6),
],
accounts: vec![
(dot_asset_id, TreasuryAccount::get(), 0_0_010_000_000u128),
(usdt_asset_id, TreasuryAccount::get(), 0_0_010_000_000u128),
(usdc_asset_id, TreasuryAccount::get(), 0_0_010_000_000u128),
],
accounts: vec![],
},
parachain_info: polimec_runtime::ParachainInfoConfig { parachain_id: PARA_ID.into(), ..Default::default() },
session: polimec_runtime::SessionConfig {
Expand Down
1 change: 1 addition & 0 deletions integration-tests/src/tests/credentials.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use crate::*;
use frame_support::{assert_err, assert_ok, dispatch::GetDispatchInfo, traits::tokens::currency::VestingSchedule};
use macros::generate_accounts;
use pallet_funding::ParticipationMode::{Classic, OTM};
use polimec_common::credentials::{Did, InvestorType};
use polimec_common_test_utils::{get_fake_jwt, get_mock_jwt_with_cid, get_test_jwt};
use polimec_runtime::PLMC;
Expand Down
19 changes: 10 additions & 9 deletions integration-tests/src/tests/defaults.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,16 @@ use crate::PolimecRuntime;
use frame_support::BoundedVec;
pub use pallet_funding::instantiator::{BidParams, ContributionParams, UserToUSDBalance};
use pallet_funding::{
AcceptedFundingAsset, BiddingTicketSizes, ContributingTicketSizes, CurrencyMetadata, PriceProviderOf,
ProjectMetadata, ProjectMetadataOf, TicketSize,
AcceptedFundingAsset, BiddingTicketSizes, ContributingTicketSizes, CurrencyMetadata, ParticipationMode,
PriceProviderOf, ProjectMetadata, ProjectMetadataOf, TicketSize,
};
use sp_arithmetic::{FixedPointNumber, Percent};

use macros::generate_accounts;
use polimec_common::{ProvideAssetPrice, USD_DECIMALS, USD_UNIT};
use polimec_runtime::{AccountId, PLMC};
use sp_runtime::{traits::ConstU32, Perquintill};
use ParticipationMode::{Classic, OTM};

pub const IPFS_CID: &str = "QmeuJ24ffwLAZppQcgcggJs3n689bewednYkuc8Bx5Gngz";
pub const CT_DECIMALS: u8 = 18;
Expand Down Expand Up @@ -54,11 +55,11 @@ pub fn ipfs_hash() -> BoundedVec<u8, ConstU32<96>> {
pub fn default_weights() -> Vec<u8> {
vec![20u8, 15u8, 10u8, 25u8, 30u8]
}
pub fn default_bidder_multipliers() -> Vec<u8> {
vec![1u8, 6u8, 10u8, 8u8, 3u8]
pub fn default_bidder_modes() -> Vec<ParticipationMode> {
vec![Classic(1u8), Classic(6u8), OTM, OTM, Classic(3u8)]
}
pub fn default_contributor_multipliers() -> Vec<u8> {
vec![1u8, 1u8, 1u8, 1u8, 1u8]
pub fn default_contributor_modes() -> Vec<ParticipationMode> {
vec![Classic(1u8), Classic(1u8), OTM, OTM, Classic(3u8)]
}

pub fn default_project_metadata(issuer: AccountId) -> ProjectMetadataOf<polimec_runtime::Runtime> {
Expand Down Expand Up @@ -113,7 +114,7 @@ pub fn default_bids() -> Vec<BidParams<PolimecRuntime>> {
default_metadata.minimum_price,
default_weights(),
default_bidders(),
default_bidder_multipliers(),
default_bidder_modes(),
)
}

Expand All @@ -134,7 +135,7 @@ pub fn default_community_contributions() -> Vec<ContributionParams<PolimecRuntim
default_metadata.minimum_price,
default_weights(),
default_community_contributors(),
default_contributor_multipliers(),
default_contributor_modes(),
)
}

Expand All @@ -157,7 +158,7 @@ pub fn default_remainder_contributions() -> Vec<ContributionParams<PolimecRuntim
default_metadata.minimum_price,
vec![20u8, 15u8, 10u8, 25u8, 23u8, 7u8],
default_remainder_contributors(),
vec![1u8, 1u8, 1u8, 1u8, 1u8, 1u8],
default_contributor_modes(),
)
}
pub fn default_community_contributors() -> Vec<AccountId> {
Expand Down
1 change: 1 addition & 0 deletions integration-tests/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ mod e2e;
mod evaluator_slash_sideffects;
mod governance;
mod oracle;
mod otm_edge_cases;
mod reserve_backed_transfers;
mod vest;
mod xcm_config;
200 changes: 200 additions & 0 deletions integration-tests/src/tests/otm_edge_cases.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
use crate::{
constants::PricesBuilder,
tests::defaults::{default_evaluations, default_project_metadata, ipfs_hash, IntegrationInstantiator},
*,
};
use frame_support::traits::fungibles::Inspect;
use macros::generate_accounts;
use pallet_funding::{AcceptedFundingAsset, MultiplierOf, ParticipationMode, PriceProviderOf};
use polimec_common::{credentials::InvestorType, ProvideAssetPrice, PLMC_DECIMALS, PLMC_FOREIGN_ID, USD_UNIT};
use polimec_common_test_utils::{generate_did_from_account, get_mock_jwt_with_cid};
use polimec_runtime::OraclePriceProvider;
use sp_arithmetic::{FixedPointNumber, FixedU128, Perbill};
use sp_core::bounded_vec;
use sp_runtime::TokenError;
generate_accounts!(ISSUER, BOBERT);
use pallet_funding::traits::BondingRequirementCalculation;

#[test]
fn otm_fee_below_min_amount_reverts() {
let mut inst = IntegrationInstantiator::new(None);
let issuer: PolimecAccountId = ISSUER.into();
let bobert: PolimecAccountId = BOBERT.into();

let prices = PricesBuilder::new()
.plmc(FixedU128::from_float(0.17f64))
.usdt(FixedU128::from_float(0.9999f64))
.usdc(FixedU128::from_float(1.0001f64))
.dot(FixedU128::from_float(4.0f64))
.build();

polimec::set_prices(prices);

PolimecNet::execute_with(|| {
let mut project_metadata = default_project_metadata(issuer.clone());
project_metadata.participation_currencies =
bounded_vec![AcceptedFundingAsset::USDT, AcceptedFundingAsset::USDC, AcceptedFundingAsset::DOT,];

let usdt_price = <PolimecRuntime as pallet_funding::Config>::PriceProvider::get_decimals_aware_price(
AcceptedFundingAsset::USDT.id(),
6,
6,
)
.unwrap();

let plmc_price = <PolimecRuntime as pallet_funding::Config>::PriceProvider::get_decimals_aware_price(
PLMC_FOREIGN_ID,
6,
PLMC_DECIMALS,
)
.unwrap();

let project_id = inst.create_community_contributing_project(
project_metadata.clone(),
issuer.clone(),
None,
default_evaluations(),
vec![],
);

let plmc_ed = inst.get_ed();

let min_usd_contribution = USD_UNIT;
let otm_multiplier: MultiplierOf<PolimecRuntime> = ParticipationMode::OTM.multiplier().try_into().unwrap();
let min_usd_bond =
otm_multiplier.calculate_usd_bonding_requirement::<PolimecRuntime>(min_usd_contribution).unwrap();
let min_plmc_bond = plmc_price.reciprocal().unwrap().saturating_mul_int(min_usd_bond);
let min_usd_otm_fee =
polimec_runtime::ProxyBonding::calculate_fee(min_plmc_bond, AcceptedFundingAsset::USDT.id()).unwrap();

let mut min_usdt_contribution = usdt_price.reciprocal().unwrap().saturating_mul_int(min_usd_contribution);
while usdt_price.saturating_mul_int(min_usdt_contribution) < min_usd_contribution {
min_usdt_contribution += 1;
}

let min_usdt_contribution_otm_fee = usdt_price.reciprocal().unwrap().saturating_mul_int(min_usd_otm_fee);

let usdt_min_balance = inst.execute(|| PolimecForeignAssets::minimum_balance(AcceptedFundingAsset::USDT.id()));

assert!(min_usdt_contribution_otm_fee < usdt_min_balance);

let ct_for_min_usdt_contribution =
PolimecFunding::funding_asset_to_ct_amount(project_id, AcceptedFundingAsset::USDT, min_usdt_contribution);

let jwt = get_mock_jwt_with_cid(
bobert.clone(),
InvestorType::Retail,
generate_did_from_account(bobert.clone()),
ipfs_hash(),
);

inst.mint_plmc_to(vec![(bobert.clone(), plmc_ed).into()]);
inst.mint_funding_asset_to(vec![(
bobert.clone(),
min_usdt_contribution + min_usdt_contribution_otm_fee + 10_000,
AcceptedFundingAsset::USDT.id(),
)
.into()]);

// Assert noop checks that storage had no changes
assert_noop!(
PolimecFunding::contribute(
PolimecOrigin::signed(bobert.clone()),
jwt.clone(),
project_id,
ct_for_min_usdt_contribution,
ParticipationMode::OTM,
AcceptedFundingAsset::USDT
),
TokenError::BelowMinimum
);
});
}

#[test]
fn after_otm_fee_user_goes_under_ed_reverts() {
let mut inst = IntegrationInstantiator::new(None);
let issuer: PolimecAccountId = ISSUER.into();
let bobert: PolimecAccountId = BOBERT.into();

polimec::set_prices(PricesBuilder::default());
PolimecNet::execute_with(|| {
let mut project_metadata = default_project_metadata(issuer.clone());

let project_id = inst.create_community_contributing_project(
project_metadata.clone(),
issuer.clone(),
None,
default_evaluations(),
vec![],
);

let plmc_price = <PolimecRuntime as pallet_funding::Config>::PriceProvider::get_decimals_aware_price(
PLMC_FOREIGN_ID,
6,
PLMC_DECIMALS,
)
.unwrap();
let usdt_price = <PolimecRuntime as pallet_funding::Config>::PriceProvider::get_decimals_aware_price(
AcceptedFundingAsset::USDT.id(),
6,
6,
)
.unwrap();

let usd_contribution = 100 * USD_UNIT;
let otm_multiplier: MultiplierOf<PolimecRuntime> = ParticipationMode::OTM.multiplier().try_into().unwrap();
let usd_bond = otm_multiplier.calculate_usd_bonding_requirement::<PolimecRuntime>(usd_contribution).unwrap();
let plmc_bond = plmc_price.reciprocal().unwrap().saturating_mul_int(usd_bond);
let usd_otm_fee =
polimec_runtime::ProxyBonding::calculate_fee(plmc_bond, AcceptedFundingAsset::USDT.id()).unwrap();

let usdt_ed = inst.get_funding_asset_ed(AcceptedFundingAsset::USDT.id());
let usdt_contribution = usdt_price.reciprocal().unwrap().saturating_mul_int(usd_contribution);
let usdt_otm_fee = usdt_price.reciprocal().unwrap().saturating_mul_int(usd_otm_fee);

let ct_for_contribution =
PolimecFunding::funding_asset_to_ct_amount(project_id, AcceptedFundingAsset::USDT, usdt_contribution);
let jwt = get_mock_jwt_with_cid(
bobert.clone(),
InvestorType::Retail,
generate_did_from_account(bobert.clone()),
ipfs_hash(),
);

inst.mint_funding_asset_to(vec![(
bobert.clone(),
usdt_contribution + usdt_otm_fee,
AcceptedFundingAsset::USDT.id(),
)
.into()]);

assert_noop!(
PolimecFunding::contribute(
PolimecOrigin::signed(bobert.clone()),
jwt.clone(),
project_id,
ct_for_contribution,
ParticipationMode::OTM,
AcceptedFundingAsset::USDT,
),
pallet_funding::Error::<PolimecRuntime>::ParticipantNotEnoughFunds
);

inst.mint_funding_asset_to(vec![(
bobert.clone(),
usdt_ed,
AcceptedFundingAsset::USDT.id(),
)
.into()]);

assert_ok!(PolimecFunding::contribute(
PolimecOrigin::signed(bobert.clone()),
jwt.clone(),
project_id,
ct_for_contribution,
ParticipationMode::OTM,
AcceptedFundingAsset::USDT,
));
});
}
15 changes: 9 additions & 6 deletions nodes/parachain/src/chain_spec/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ use polimec_runtime::{
inflation::{perbill_annual_to_perbill_round, BLOCKS_PER_YEAR},
InflationInfo, Range,
},
AccountId, AuraId as AuthorityId, Balance, OracleProvidersMembershipConfig, Runtime, PLMC,
AccountId, AuraId as AuthorityId, Balance, BlockchainOperationTreasury, ContributionTreasuryAccount,
ExistentialDeposit, FeeRecipient, OracleProvidersMembershipConfig, Runtime, TreasuryAccount, PLMC,
};
use sp_core::{crypto::UncheckedInto, sr25519};
use sp_runtime::{traits::AccountIdConversion, Perbill, Percent};

pub type ChainSpec = sc_service::GenericChainSpec<Extensions>;

/// The default XCM version to set in genesis config.
Expand Down Expand Up @@ -86,13 +88,14 @@ pub fn genesis_config(genesis_config_params: GenesisConfigParams) -> serde_json:
id,
} = genesis_config_params;

let ed = ExistentialDeposit::get();
let system_accounts = vec![
(
<Runtime as pallet_funding::Config>::ContributionTreasury::get(),
<Runtime as pallet_funding::Config>::NativeCurrency::minimum_balance(),
),
(ContributionTreasuryAccount::get(), ed),
(FeeRecipient::get(), ed),
// Need this to have enough for staking rewards
(<Runtime as pallet_parachain_staking::Config>::PayMaster::get(), 10_000_000 * PLMC),
(BlockchainOperationTreasury::get(), 10_000_000 * PLMC),
// Need this to have enough for proxy bonding
(TreasuryAccount::get(), 10_000_000 * PLMC),
];
endowed_accounts.append(&mut system_accounts.clone());

Expand Down
Loading