diff --git a/nodes/parachain/src/chain_spec/polimec.rs b/nodes/parachain/src/chain_spec/polimec.rs index b55178e6e..c7f62ccd6 100644 --- a/nodes/parachain/src/chain_spec/polimec.rs +++ b/nodes/parachain/src/chain_spec/polimec.rs @@ -180,6 +180,7 @@ pub fn get_rococo_chain_spec() -> GenericChainSpec { } fn base_testnet_genesis( + #[allow(unused)] stakers: Vec<(AccountId, Option, Balance)>, inflation_config: InflationInfo, initial_authorities: Vec, diff --git a/nodes/parachain/src/chain_spec/politest.rs b/nodes/parachain/src/chain_spec/politest.rs index 6782dc128..d81e5be8f 100644 --- a/nodes/parachain/src/chain_spec/politest.rs +++ b/nodes/parachain/src/chain_spec/politest.rs @@ -192,6 +192,7 @@ pub fn get_live_chain_spec() -> GenericChainSpec { #[allow(clippy::too_many_arguments)] fn testnet_genesis( + #[allow(unused)] stakers: Vec<(AccountId, Option, Balance)>, inflation_config: InflationInfo, initial_authorities: Vec, diff --git a/pallets/funding/src/tests/3_auction.rs b/pallets/funding/src/tests/3_auction.rs index d732bed4d..e2548b9fe 100644 --- a/pallets/funding/src/tests/3_auction.rs +++ b/pallets/funding/src/tests/3_auction.rs @@ -6,6 +6,7 @@ mod round_flow { #[cfg(test)] mod success { + use std::collections::HashSet; use super::*; use frame_support::traits::fungibles::metadata::Inspect; use sp_core::bounded_vec; @@ -516,6 +517,166 @@ mod round_flow { Perquintill::from_float(0.99) ); } + + #[test] + fn different_decimals_ct_works_as_expected() { + // Setup some base values to compare different decimals + let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); + let ed = inst.get_ed(); + let default_project_metadata = default_project_metadata(ISSUER_1); + let original_decimal_aware_price = default_project_metadata.minimum_price; + let original_price = ::PriceProvider::convert_back_to_normal_price( + original_decimal_aware_price, + USD_DECIMALS, + default_project_metadata.token_information.decimals, + ) + .unwrap(); + let usable_plmc_price = inst.execute(|| { + ::PriceProvider::get_decimals_aware_price( + PLMC_FOREIGN_ID, + USD_DECIMALS, + PLMC_DECIMALS, + ) + .unwrap() + }); + let usdt_price = inst.execute(|| { + ::PriceProvider::get_decimals_aware_price( + AcceptedFundingAsset::USDT.to_assethub_id(), + USD_DECIMALS, + ForeignAssets::decimals(AcceptedFundingAsset::USDT.to_assethub_id()), + ) + .unwrap() + }); + let usdc_price = inst.execute(|| { + ::PriceProvider::get_decimals_aware_price( + AcceptedFundingAsset::USDC.to_assethub_id(), + USD_DECIMALS, + ForeignAssets::decimals(AcceptedFundingAsset::USDC.to_assethub_id()), + ) + .unwrap() + }); + let dot_price = inst.execute(|| { + ::PriceProvider::get_decimals_aware_price( + AcceptedFundingAsset::DOT.to_assethub_id(), + USD_DECIMALS, + ForeignAssets::decimals(AcceptedFundingAsset::DOT.to_assethub_id()), + ) + .unwrap() + }); + + + let mut funding_assets_cycle = vec![ + AcceptedFundingAsset::USDT, + AcceptedFundingAsset::USDC, + AcceptedFundingAsset::DOT, + ].into_iter().cycle(); + + let mut min_bid_amounts_ct = Vec::new(); + let mut min_bid_amounts_usd = Vec::new(); + let mut auction_allocations_ct = Vec::new(); + let mut auction_allocations_usd = Vec::new(); + + let mut decimal_test = |decimals: u8| { + let funding_asset = funding_assets_cycle.next().unwrap(); + dbg!(&funding_asset); + let funding_asset_usd_price = match funding_asset { + AcceptedFundingAsset::USDT => usdt_price, + AcceptedFundingAsset::USDC => usdc_price, + AcceptedFundingAsset::DOT => dot_price, + }; + + dbg!(decimals); + let mut project_metadata = default_project_metadata.clone(); + project_metadata.token_information.decimals = decimals; + project_metadata.minimum_price = + ::PriceProvider::calculate_decimals_aware_price( + original_price, + USD_DECIMALS, + decimals, + ) + .unwrap(); + + dbg!(original_price); + dbg!(project_metadata.minimum_price); + project_metadata.total_allocation_size = 1_000_000 * 10u128.pow(decimals as u32); + project_metadata.mainnet_token_max_supply = project_metadata.total_allocation_size; + project_metadata.participation_currencies = bounded_vec!(funding_asset); + + let issuer: AccountIdOf = (10_000 + inst.get_new_nonce()).try_into().unwrap(); + let evaluations = inst.generate_successful_evaluations(project_metadata.clone(), default_evaluators(), default_weights()); + let project_id = inst.create_auctioning_project(project_metadata.clone(), issuer, evaluations); + + let auction_allocation_percentage = project_metadata.auction_round_allocation_percentage; + let auction_allocation_ct = auction_allocation_percentage * project_metadata.total_allocation_size; + auction_allocations_ct.push(auction_allocation_ct); + dbg!(&project_metadata.minimum_price); + dbg!(&auction_allocation_ct); + let auction_allocation_usd = project_metadata.minimum_price.saturating_mul_int(auction_allocation_ct); + auction_allocations_usd.push(auction_allocation_usd); + + + + let min_professional_bid_usd = project_metadata.bidding_ticket_sizes.professional.usd_minimum_per_participation.unwrap(); + min_bid_amounts_usd.push(min_professional_bid_usd); + let min_professional_bid_ct = project_metadata.minimum_price.reciprocal().unwrap().saturating_mul_int(min_professional_bid_usd); + let min_professional_bid_plmc = usable_plmc_price.reciprocal().unwrap().saturating_mul_int(min_professional_bid_usd); + min_bid_amounts_ct.push(min_professional_bid_ct); + let min_professional_bid_funding_asset = funding_asset_usd_price.reciprocal().unwrap().saturating_mul_int(min_professional_bid_usd); + + // Every project should want to raise 5MM USD on the auction round regardless of CT decimals + 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_to(vec![UserToPLMCBalance::new(BIDDER_1, min_professional_bid_plmc + ed)]); + inst.mint_foreign_asset_to(vec![UserToForeignAssets::new(BIDDER_1, min_professional_bid_funding_asset, funding_asset.to_assethub_id())]); + + dbg!(&min_professional_bid_funding_asset); + dbg!(&min_professional_bid_usd); + dbg!(&min_professional_bid_ct); + dbg!(&min_professional_bid_plmc); + + assert_ok!(inst.execute(|| PolimecFunding::bid( + RuntimeOrigin::signed(BIDDER_1), + get_mock_jwt_with_cid( + BIDDER_1, + InvestorType::Professional, + generate_did_from_account(BIDDER_1), + project_metadata.clone().policy_ipfs_cid.unwrap() + ), + project_id, + min_professional_bid_ct, + 1u8.try_into().unwrap(), + funding_asset, + ))); + + // The bucket should have 1MM * 10^decimals CT minus what we just bid + let bucket = inst.execute(|| Buckets::::get(project_id).unwrap()); + assert_eq!(bucket.amount_left, 500_000u128 * 10u128.pow(decimals as u32) - min_professional_bid_ct); + + + }; + + for decimals in 0..25 { + decimal_test(decimals); + } + + // Since we use the same original price and allocation size and adjust for decimals, + // the USD amounts should be the same + assert!(min_bid_amounts_usd.iter().all(|x| *x == min_bid_amounts_usd[0])); + assert!(auction_allocations_usd.iter().all(|x| *x == auction_allocations_usd[0])); + + // CT amounts however should be different from each other + let mut hash_set_1 = HashSet::new(); + for amount in min_bid_amounts_ct { + assert!(!hash_set_1.contains(&amount)); + hash_set_1.insert(amount); + } + let mut hash_set_2 = HashSet::new(); + for amount in auction_allocations_ct { + assert!(!hash_set_2.contains(&amount)); + hash_set_2.insert(amount); + } + } } #[cfg(test)] diff --git a/runtimes/polimec/src/benchmarks/helpers.rs b/runtimes/polimec/src/benchmarks/helpers.rs index 30124d735..bd0aede0d 100644 --- a/runtimes/polimec/src/benchmarks/helpers.rs +++ b/runtimes/polimec/src/benchmarks/helpers.rs @@ -7,7 +7,7 @@ pub struct SetOraclePrices; impl SetPrices for SetOraclePrices { fn set_prices() { let dot = (AcceptedFundingAsset::DOT.to_assethub_id(), FixedU128::from_rational(69, 1)); - let usdc = (AcceptedFundingAsset::USDT.to_assethub_id(), FixedU128::from_rational(1, 1)); + let usdc = (AcceptedFundingAsset::USDC.to_assethub_id(), FixedU128::from_rational(1, 1)); let usdt = (AcceptedFundingAsset::USDT.to_assethub_id(), FixedU128::from_rational(1, 1)); let plmc = (pallet_funding::PLMC_FOREIGN_ID, FixedU128::from_rational(840, 100)); diff --git a/runtimes/politest/src/benchmarks/helpers.rs b/runtimes/politest/src/benchmarks/helpers.rs index 5dfee57b0..33e99bad0 100644 --- a/runtimes/politest/src/benchmarks/helpers.rs +++ b/runtimes/politest/src/benchmarks/helpers.rs @@ -6,7 +6,7 @@ pub struct SetOraclePrices; impl SetPrices for SetOraclePrices { fn set_prices() { let dot = (AcceptedFundingAsset::DOT.to_assethub_id(), FixedU128::from_rational(69, 1)); - let usdc = (AcceptedFundingAsset::USDT.to_assethub_id(), FixedU128::from_rational(1, 1)); + let usdc = (AcceptedFundingAsset::USDC.to_assethub_id(), FixedU128::from_rational(1, 1)); let usdt = (AcceptedFundingAsset::USDT.to_assethub_id(), FixedU128::from_rational(1, 1)); let plmc = (pallet_funding::PLMC_FOREIGN_ID, FixedU128::from_rational(840, 100));