diff --git a/integration-tests/src/tests/ct_migration.rs b/integration-tests/src/tests/ct_migration.rs index 9a97323b5..6fbbf84d7 100644 --- a/integration-tests/src/tests/ct_migration.rs +++ b/integration-tests/src/tests/ct_migration.rs @@ -16,7 +16,7 @@ use crate::*; use frame_support::traits::{fungible::Mutate, fungibles::Inspect}; -use pallet_funding::{assert_close_enough, ProjectId}; +use pallet_funding::{assert_close_enough, types::*, ProjectId}; use polimec_common::migration_types::{MigrationStatus, Migrations}; use polimec_runtime::Funding; use sp_runtime::Perquintill; @@ -34,7 +34,7 @@ fn mock_hrmp_establishment(project_id: u32) { }); PolimecNet::execute_with(|| { - assert_ok!(Funding::do_set_para_id_for_project(&ISSUER.into(), project_id, ParaId::from(6969u32))); + assert_ok!(Funding::do_configure_receiver_pallet_migration(&ISSUER.into(), project_id, ParaId::from(6969u32))); let open_channel_message = xcm::v3::opaque::Instruction::HrmpNewChannelOpenRequest { sender: 6969, @@ -54,7 +54,10 @@ fn mock_hrmp_establishment(project_id: u32) { fn assert_migration_is_ready(project_id: u32) { PolimecNet::execute_with(|| { let project_details = pallet_funding::ProjectsDetails::::get(project_id).unwrap(); - assert!(project_details.migration_readiness_check.unwrap().is_ready()) + let MigrationType::ParachainReceiverPallet(receiver_pallet_info) = project_details.migration_type else { + panic!("Migration type is not ParachainReceiverPallet"); + }; + assert!(receiver_pallet_info.migration_readiness_check.unwrap().is_ready()) }); } @@ -76,7 +79,11 @@ fn get_migrations_for_participants( fn send_migrations(project_id: ProjectId, accounts: Vec) { for user in accounts.into_iter() { PolimecNet::execute_with(|| { - assert_ok!(Funding::migrate_one_participant(PolimecOrigin::signed(user.clone()), project_id, user.clone())); + assert_ok!(Funding::receiver_pallet_migrate_for( + PolimecOrigin::signed(user.clone()), + project_id, + user.clone() + )); }); } } diff --git a/integration-tests/src/tests/e2e.rs b/integration-tests/src/tests/e2e.rs index 744cb30a5..e72b5f351 100644 --- a/integration-tests/src/tests/e2e.rs +++ b/integration-tests/src/tests/e2e.rs @@ -485,7 +485,11 @@ fn ct_migrated() { // Mock HRMP establishment PolimecNet::execute_with(|| { let _account_id: PolimecAccountId = ISSUER.into(); - assert_ok!(PolimecFunding::do_set_para_id_for_project(&ISSUER.into(), project_id, ParaId::from(6969u32),)); + assert_ok!(PolimecFunding::do_configure_receiver_pallet_migration( + &ISSUER.into(), + project_id, + ParaId::from(6969u32), + )); let open_channel_message = xcm::v3::opaque::Instruction::HrmpNewChannelOpenRequest { sender: 6969, max_message_size: 102_300, @@ -505,7 +509,10 @@ fn ct_migrated() { // Migration is ready PolimecNet::execute_with(|| { let project_details = pallet_funding::ProjectsDetails::::get(project_id).unwrap(); - assert!(project_details.migration_readiness_check.unwrap().is_ready()) + let MigrationType::ParachainReceiverPallet(migration_info) = project_details.migration_type else { + panic!("Migration type should be ParachainReceiverPallet"); + }; + assert!(migration_info.migration_readiness_check.unwrap().is_ready()) }); excel_ct_amounts().iter().map(|tup| tup.0.clone()).unique().for_each(|account| { @@ -525,7 +532,7 @@ fn ct_migrated() { for account in accounts { PolimecNet::execute_with(|| { - assert_ok!(PolimecFunding::migrate_one_participant( + assert_ok!(PolimecFunding::receiver_pallet_migrate_for( PolimecOrigin::signed(account.clone()), project_id, account.clone() diff --git a/pallets/funding/src/functions/1_application.rs b/pallets/funding/src/functions/1_application.rs index 2f6c855ba..1f5fc0daf 100644 --- a/pallets/funding/src/functions/1_application.rs +++ b/pallets/funding/src/functions/1_application.rs @@ -46,12 +46,7 @@ impl Pallet { }, usd_bid_on_oversubscription: None, funding_end_block: None, - parachain_id: None, - migration_readiness_check: None, - hrmp_channel_status: HRMPChannelStatus { - project_to_polimec: ChannelStatus::Closed, - polimec_to_project: ChannelStatus::Closed, - }, + migration_type: MigrationType::Offchain, }; let bucket: BucketOf = Self::create_bucket_from_metadata(&project_metadata)?; diff --git a/pallets/funding/src/functions/7_ct_migration.rs b/pallets/funding/src/functions/7_ct_migration.rs index 1c2f6656e..6689eb4bb 100644 --- a/pallets/funding/src/functions/7_ct_migration.rs +++ b/pallets/funding/src/functions/7_ct_migration.rs @@ -3,7 +3,7 @@ use xcm::v3::MaxPalletNameLen; impl Pallet { #[transactional] - pub fn do_set_para_id_for_project( + pub fn do_configure_receiver_pallet_migration( caller: &AccountIdOf, project_id: ProjectId, para_id: ParaId, @@ -13,9 +13,18 @@ impl Pallet { // * Validity checks * ensure!(&(project_details.issuer_account) == caller, Error::::NotIssuer); + ensure!(project_details.status == ProjectStatus::FundingSuccessful, Error::::IncorrectRound); // * Update storage * - project_details.parachain_id = Some(para_id); + let parachain_receiver_pallet_info = ParachainReceiverPalletInfo { + parachain_id: para_id, + hrmp_channel_status: HRMPChannelStatus { + project_to_polimec: ChannelStatus::Closed, + polimec_to_project: ChannelStatus::Closed, + }, + migration_readiness_check: None, + }; + project_details.migration_type = MigrationType::ParachainReceiverPallet(parachain_receiver_pallet_info); ProjectsDetails::::insert(project_id, project_details); // * Emit events * @@ -51,7 +60,10 @@ impl Pallet { let (project_id, mut project_details) = ProjectsDetails::::iter() .find(|(_id, details)| { - details.parachain_id == Some(ParaId::from(sender)) && details.status == FundingSuccessful + matches!( + &details.migration_type, + MigrationType::ParachainReceiverPallet(info) if + info.parachain_id == ParaId::from(sender) && details.status == FundingSuccessful) }) .ok_or(XcmError::BadOrigin)?; @@ -95,8 +107,14 @@ impl Pallet { match T::XcmRouter::deliver(ticket) { Ok(_) => { log::trace!(target: "pallet_funding::hrmp", "HrmpNewChannelOpenRequest: acceptance successfully sent"); - project_details.hrmp_channel_status.project_to_polimec = ChannelStatus::Open; - project_details.hrmp_channel_status.polimec_to_project = ChannelStatus::AwaitingAcceptance; + match project_details.migration_type { + MigrationType::ParachainReceiverPallet(ref mut info) => { + info.hrmp_channel_status.project_to_polimec = ChannelStatus::Open; + info.hrmp_channel_status.polimec_to_project = ChannelStatus::AwaitingAcceptance; + }, + _ => return Err(XcmError::NoDeal), + } + ProjectsDetails::::insert(project_id, project_details); Pallet::::deposit_event(Event::::HrmpChannelAccepted { @@ -126,11 +144,20 @@ impl Pallet { log::trace!(target: "pallet_funding::hrmp", "HrmpChannelAccepted received: {:?}", message); let (project_id, mut project_details) = ProjectsDetails::::iter() .find(|(_id, details)| { - details.parachain_id == Some(ParaId::from(recipient)) && details.status == FundingSuccessful + matches!( + &details.migration_type, + MigrationType::ParachainReceiverPallet(info) if + info.parachain_id == ParaId::from(recipient) && details.status == FundingSuccessful) }) .ok_or(XcmError::BadOrigin)?; - project_details.hrmp_channel_status.polimec_to_project = ChannelStatus::Open; + match project_details.migration_type { + MigrationType::ParachainReceiverPallet(ref mut info) => { + info.hrmp_channel_status.polimec_to_project = ChannelStatus::Open; + }, + _ => return Err(XcmError::NoDeal), + } + ProjectsDetails::::insert(project_id, project_details); Pallet::::deposit_event(Event::::HrmpChannelEstablished { project_id, @@ -157,7 +184,10 @@ impl Pallet { pub fn do_start_migration_readiness_check(caller: &AccountIdOf, project_id: ProjectId) -> DispatchResult { // * Get variables * let mut project_details = ProjectsDetails::::get(project_id).ok_or(Error::::ProjectDetailsNotFound)?; - let parachain_id: u32 = project_details.parachain_id.ok_or(Error::::ImpossibleState)?.into(); + let MigrationType::ParachainReceiverPallet(ref mut migration_info) = project_details.migration_type else { + return Err(Error::::NotAllowed.into()) + }; + let parachain_id: u32 = migration_info.parachain_id.into(); let project_multilocation = ParentThen(X1(Parachain(parachain_id))); let now = >::block_number(); @@ -167,17 +197,17 @@ impl Pallet { // * Validity checks * ensure!(project_details.status == ProjectStatus::FundingSuccessful, Error::::IncorrectRound); ensure!( - project_details.hrmp_channel_status == + migration_info.hrmp_channel_status == HRMPChannelStatus { project_to_polimec: ChannelStatus::Open, polimec_to_project: ChannelStatus::Open }, Error::::ChannelNotOpen ); - if project_details.migration_readiness_check.is_none() { + if migration_info.migration_readiness_check.is_none() { ensure!(caller.clone() == T::PalletId::get().into_account_truncating(), Error::::NotAllowed); } else if matches!( - project_details.migration_readiness_check, + migration_info.migration_readiness_check, Some(MigrationReadinessCheck { holding_check: (_, CheckOutcome::Failed), pallet_check: (_, CheckOutcome::Failed), @@ -203,7 +233,7 @@ impl Pallet { Here, ); - project_details.migration_readiness_check = Some(MigrationReadinessCheck { + migration_info.migration_readiness_check = Some(MigrationReadinessCheck { holding_check: (query_id_holdings, CheckOutcome::AwaitingResponse), pallet_check: (query_id_pallet, CheckOutcome::AwaitingResponse), }); @@ -253,13 +283,13 @@ impl Pallet { ) -> DispatchResult { use xcm::v3::prelude::*; // TODO: check if this is too low performance. Maybe we want a new map of query_id -> project_id - let (project_id, mut project_details, mut migration_check) = ProjectsDetails::::iter() + let (project_id, mut migration_info, mut project_details) = ProjectsDetails::::iter() .find_map(|(project_id, details)| { - if let Some(check @ MigrationReadinessCheck { holding_check, pallet_check }) = - details.migration_readiness_check - { - if holding_check.0 == query_id || pallet_check.0 == query_id { - return Some((project_id, details, check)); + if let MigrationType::ParachainReceiverPallet(ref info) = details.migration_type { + if let Some(check) = info.migration_readiness_check { + if check.holding_check.0 == query_id || check.pallet_check.0 == query_id { + return Some((project_id, info.clone(), details)); + } } } None @@ -271,16 +301,18 @@ impl Pallet { } else { return Err(Error::::WrongParaId.into()); }; + ensure!(migration_info.parachain_id == para_id, Error::::WrongParaId); let project_metadata = ProjectsMetadata::::get(project_id).ok_or(Error::::ProjectMetadataNotFound)?; let contribution_tokens_sold = project_metadata.total_allocation_size.saturating_sub(project_details.remaining_contribution_tokens); - ensure!(project_details.parachain_id == Some(para_id), Error::::WrongParaId); - match (response.clone(), migration_check) { + match (response.clone(), &mut migration_info.migration_readiness_check) { ( Response::Assets(assets), - MigrationReadinessCheck { holding_check: (_, CheckOutcome::AwaitingResponse), .. }, + &mut Some( + ref mut check @ MigrationReadinessCheck { holding_check: (_, CheckOutcome::AwaitingResponse), .. }, + ), ) => { let ct_sold_as_u128: u128 = contribution_tokens_sold.try_into().map_err(|_| Error::::BadMath)?; let assets: Vec = assets.into_inner(); @@ -290,7 +322,7 @@ impl Pallet { id: Concrete(MultiLocation { parents: 1, interior: X1(Parachain(pid)) }), fun: Fungible(amount), } if amount >= ct_sold_as_u128 && pid == u32::from(para_id) => { - migration_check.holding_check.1 = CheckOutcome::Passed(None); + check.holding_check.1 = CheckOutcome::Passed(None); Self::deposit_event(Event::::MigrationCheckResponseAccepted { project_id, query_id, @@ -298,7 +330,7 @@ impl Pallet { }); }, _ => { - migration_check.holding_check.1 = CheckOutcome::Failed; + check.holding_check.1 = CheckOutcome::Failed; Self::deposit_event(Event::::MigrationCheckResponseRejected { project_id, query_id, @@ -310,7 +342,7 @@ impl Pallet { ( Response::PalletsInfo(pallets_info), - MigrationReadinessCheck { pallet_check: (_, CheckOutcome::AwaitingResponse), .. }, + Some(ref mut check @ MigrationReadinessCheck { pallet_check: (_, CheckOutcome::AwaitingResponse), .. }), ) => { let expected_module_name: BoundedVec = BoundedVec::try_from("polimec_receiver".as_bytes().to_vec()).map_err(|_| Error::::NotAllowed)?; @@ -319,17 +351,17 @@ impl Pallet { }; let u8_index: u8 = (*index).try_into().map_err(|_| Error::::NotAllowed)?; if pallets_info.len() == 1 && module_name == &expected_module_name { - migration_check.pallet_check.1 = CheckOutcome::Passed(Some(u8_index)); + check.pallet_check.1 = CheckOutcome::Passed(Some(u8_index)); Self::deposit_event(Event::::MigrationCheckResponseAccepted { project_id, query_id, response }); } else { - migration_check.pallet_check.1 = CheckOutcome::Failed; + check.pallet_check.1 = CheckOutcome::Failed; Self::deposit_event(Event::::MigrationCheckResponseRejected { project_id, query_id, response }); } }, _ => return Err(Error::::NotAllowed.into()), }; - project_details.migration_readiness_check = Some(migration_check); + project_details.migration_type = MigrationType::ParachainReceiverPallet(migration_info); ProjectsDetails::::insert(project_id, project_details); Ok(()) } @@ -338,11 +370,15 @@ impl Pallet { /// This entails transferring the funds from the Polimec sovereign account to the participant account, and applying /// a vesting schedule if necessary. #[transactional] - pub fn do_migrate_one_participant(project_id: ProjectId, participant: AccountIdOf) -> DispatchResult { + pub fn do_receiver_pallet_migrate_for(project_id: ProjectId, participant: AccountIdOf) -> DispatchResult { // * Get variables * let project_details = ProjectsDetails::::get(project_id).ok_or(Error::::ProjectDetailsNotFound)?; - let migration_readiness_check = project_details.migration_readiness_check.ok_or(Error::::ChannelNotReady)?; - let project_para_id = project_details.parachain_id.ok_or(Error::::ImpossibleState)?; + let migration_info = match project_details.migration_type { + MigrationType::ParachainReceiverPallet(info) => info, + _ => return Err(Error::::NotAllowed.into()), + }; + let migration_readiness_check = migration_info.migration_readiness_check.ok_or(Error::::ChannelNotReady)?; + let project_para_id = migration_info.parachain_id; let now = >::block_number(); ensure!( Self::user_has_no_participations(project_id, participant.clone()), @@ -388,9 +424,13 @@ impl Pallet { let (project_id, participant) = ActiveMigrationQueue::::take(query_id).ok_or(Error::::NoActiveMigrationsFound)?; let project_details = ProjectsDetails::::get(project_id).ok_or(Error::::ProjectDetailsNotFound)?; + let migration_info = match project_details.migration_type { + MigrationType::ParachainReceiverPallet(info) => info, + _ => return Err(Error::::NotAllowed.into()), + }; ensure!( - matches!(location, MultiLocation { parents: 1, interior: X1(Parachain(para_id))} if Some(ParaId::from(para_id)) == project_details.parachain_id), + matches!(location, MultiLocation { parents: 1, interior: X1(Parachain(para_id))} if ParaId::from(para_id) == migration_info.parachain_id), Error::::WrongParaId ); diff --git a/pallets/funding/src/instantiator/chain_interactions.rs b/pallets/funding/src/instantiator/chain_interactions.rs index 1ec1182e2..b72f141ea 100644 --- a/pallets/funding/src/instantiator/chain_interactions.rs +++ b/pallets/funding/src/instantiator/chain_interactions.rs @@ -314,12 +314,7 @@ impl< }, usd_bid_on_oversubscription: None, funding_end_block: None, - parachain_id: None, - migration_readiness_check: None, - hrmp_channel_status: HRMPChannelStatus { - project_to_polimec: crate::ChannelStatus::Closed, - polimec_to_project: crate::ChannelStatus::Closed, - }, + migration_type: MigrationType::Offchain, }; assert_eq!(metadata, expected_metadata); assert_eq!(details, expected_details); diff --git a/pallets/funding/src/lib.rs b/pallets/funding/src/lib.rs index dd233dfd3..4f90bce0b 100644 --- a/pallets/funding/src/lib.rs +++ b/pallets/funding/src/lib.rs @@ -1098,7 +1098,7 @@ pub mod pallet { #[pallet::call_index(22)] #[pallet::weight(Weight::from_parts(1000, 0))] - pub fn set_para_id_for_project( + pub fn configure_receiver_pallet_migration( origin: OriginFor, jwt: UntrustedToken, project_id: ProjectId, @@ -1108,7 +1108,7 @@ pub mod pallet { T::InvestorOrigin::ensure_origin(origin, &jwt, T::VerifierPublicKey::get())?; ensure!(investor_type == InvestorType::Institutional, Error::::WrongInvestorType); - Self::do_set_para_id_for_project(&account, project_id, para_id) + Self::do_configure_receiver_pallet_migration(&account, project_id, para_id) } #[pallet::call_index(23)] @@ -1139,13 +1139,13 @@ pub mod pallet { #[pallet::call_index(26)] #[pallet::weight(Weight::from_parts(1000, 0))] - pub fn migrate_one_participant( + pub fn receiver_pallet_migrate_for( origin: OriginFor, project_id: ProjectId, participant: AccountIdOf, ) -> DispatchResult { let _caller = ensure_signed(origin)?; - Self::do_migrate_one_participant(project_id, participant) + Self::do_receiver_pallet_migrate_for(project_id, participant) } #[pallet::call_index(27)] diff --git a/pallets/funding/src/storage_migrations.rs b/pallets/funding/src/storage_migrations.rs index 3ccf42c5f..e2bdd4a5b 100644 --- a/pallets/funding/src/storage_migrations.rs +++ b/pallets/funding/src/storage_migrations.rs @@ -4,278 +4,278 @@ use frame_support::traits::StorageVersion; /// The current storage version pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(3); pub const LOG: &str = "runtime::funding::migration"; - -pub mod v2 { - use crate::{AccountIdOf, BalanceOf, Config, ProjectsMetadata}; - use frame_support::{ - pallet_prelude::{Decode, Encode, MaxEncodedLen, RuntimeDebug, TypeInfo}, - traits::{Get, OnRuntimeUpgrade}, - BoundedVec, - }; - use polimec_common::USD_DECIMALS; - use sp_arithmetic::{FixedPointNumber, Percent}; - use sp_core::ConstU32; - use sp_std::marker::PhantomData; - - #[derive(Clone, Copy, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] - #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] - pub struct OldTicketSize { - pub usd_minimum_per_participation: Option, - pub usd_maximum_per_did: Option, - } - - #[derive(Clone, Copy, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] - #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] - pub struct OldBiddingTicketSizes { - pub professional: OldTicketSize, - pub institutional: OldTicketSize, - pub phantom: PhantomData<(Price, Balance)>, - } - - #[derive(Clone, Copy, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] - #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] - pub struct OldContributingTicketSizes { - pub retail: OldTicketSize, - pub professional: OldTicketSize, - pub institutional: OldTicketSize, - pub phantom: PhantomData<(Price, Balance)>, - } - - type OldProjectMetadataOf = OldProjectMetadata< - BoundedVec>, - BalanceOf, - crate::PriceOf, - AccountIdOf, - polimec_common::credentials::Cid, - >; - #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] - #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] - pub struct OldProjectMetadata { - /// Token Metadata - pub token_information: crate::CurrencyMetadata, - /// Mainnet Token Max Supply - pub mainnet_token_max_supply: Balance, - /// Total allocation of Contribution Tokens available for the Funding Round. - pub total_allocation_size: Balance, - /// Percentage of the total allocation of Contribution Tokens available for the Auction Round - pub auction_round_allocation_percentage: Percent, - /// The minimum price per token in USD, decimal-aware. See [`calculate_decimals_aware_price()`](crate::traits::ProvideAssetPrice::calculate_decimals_aware_price) for more information. - pub minimum_price: Price, - /// Maximum and minimum ticket sizes for auction round - pub bidding_ticket_sizes: OldBiddingTicketSizes, - /// Maximum and minimum ticket sizes for community/remainder rounds - pub contributing_ticket_sizes: OldContributingTicketSizes, - /// Participation currencies (e.g stablecoin, DOT, KSM) - pub participation_currencies: - BoundedVec>, - pub funding_destination_account: AccountId, - /// Additional metadata - pub policy_ipfs_cid: Option, - } - - pub struct UncheckedMigrationToV2(PhantomData); - impl OnRuntimeUpgrade for UncheckedMigrationToV2 { - fn on_runtime_upgrade() -> frame_support::weights::Weight { - let mut items = 0; - let mut translate = |_key, item: OldProjectMetadataOf| -> Option> { - items += 1; - let usd_unit = sp_arithmetic::traits::checked_pow(BalanceOf::::from(10u64), USD_DECIMALS as usize)?; - Some(crate::ProjectMetadataOf:: { - token_information: item.token_information, - mainnet_token_max_supply: item.mainnet_token_max_supply, - total_allocation_size: item.total_allocation_size, - auction_round_allocation_percentage: item.auction_round_allocation_percentage, - minimum_price: item.minimum_price, - bidding_ticket_sizes: crate::BiddingTicketSizes { - professional: crate::TicketSize { - usd_minimum_per_participation: item - .bidding_ticket_sizes - .professional - .usd_minimum_per_participation - .unwrap_or_else(|| usd_unit), - usd_maximum_per_did: item.bidding_ticket_sizes.professional.usd_maximum_per_did, - }, - institutional: crate::TicketSize { - usd_minimum_per_participation: item - .bidding_ticket_sizes - .institutional - .usd_minimum_per_participation - .unwrap_or_else(|| usd_unit), - usd_maximum_per_did: item.bidding_ticket_sizes.institutional.usd_maximum_per_did, - }, - phantom: Default::default(), - }, - contributing_ticket_sizes: crate::ContributingTicketSizes { - retail: crate::TicketSize { - usd_minimum_per_participation: item - .contributing_ticket_sizes - .retail - .usd_minimum_per_participation - .unwrap_or_else(|| usd_unit), - usd_maximum_per_did: item.contributing_ticket_sizes.retail.usd_maximum_per_did, - }, - professional: crate::TicketSize { - usd_minimum_per_participation: item - .contributing_ticket_sizes - .professional - .usd_minimum_per_participation - .unwrap_or_else(|| usd_unit), - usd_maximum_per_did: item.contributing_ticket_sizes.professional.usd_maximum_per_did, - }, - institutional: crate::TicketSize { - usd_minimum_per_participation: item - .contributing_ticket_sizes - .institutional - .usd_minimum_per_participation - .unwrap_or_else(|| usd_unit), - usd_maximum_per_did: item.contributing_ticket_sizes.institutional.usd_maximum_per_did, - }, - phantom: Default::default(), - }, - participation_currencies: item.participation_currencies, - funding_destination_account: item.funding_destination_account, - policy_ipfs_cid: item.policy_ipfs_cid, - }) - }; - - ProjectsMetadata::::translate(|key, object: OldProjectMetadataOf| translate(key, object)); - - T::DbWeight::get().reads_writes(items, items) - } - } - - pub type MigrationToV2 = frame_support::migrations::VersionedMigration< - 1, - 2, - UncheckedMigrationToV2, - crate::Pallet, - ::DbWeight, - >; -} - -pub mod v3 { - use crate::{ - AccountIdOf, BalanceOf, Config, EvaluationRoundInfoOf, HRMPChannelStatus, MigrationReadinessCheck, - PhaseTransitionPoints, PriceOf, ProjectDetailsOf, ProjectStatus, - }; - use frame_support::{ - pallet_prelude::Get, - traits::{tokens::Balance as BalanceT, OnRuntimeUpgrade}, - }; - use frame_system::pallet_prelude::BlockNumberFor; - use polimec_common::credentials::Did; - use polkadot_parachain_primitives::primitives::Id as ParaId; - use scale_info::TypeInfo; - use sp_arithmetic::FixedPointNumber; - use sp_core::{Decode, Encode, MaxEncodedLen, RuntimeDebug}; - use sp_std::marker::PhantomData; - - #[derive(Default, Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] - #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] - pub enum OldProjectStatus { - #[default] - Application, - EvaluationRound, - AuctionInitializePeriod, - AuctionOpening, - AuctionClosing, - CommunityRound, - RemainderRound, - FundingFailed, - AwaitingProjectDecision, - FundingSuccessful, - ReadyToStartMigration, - MigrationCompleted, - } - #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] - pub struct OldProjectDetails< - AccountId, - Did, - BlockNumber, - Price: FixedPointNumber, - Balance: BalanceT, - EvaluationRoundInfo, - > { - pub issuer_account: AccountId, - pub issuer_did: Did, - /// Whether the project is frozen, so no `metadata` changes are allowed. - pub is_frozen: bool, - /// The price in USD per token decided after the Auction Round - pub weighted_average_price: Option, - /// The current status of the project - pub status: OldProjectStatus, - /// When the different project phases start and end - pub phase_transition_points: PhaseTransitionPoints, - /// Fundraising target amount in USD (6 decimals) - pub fundraising_target_usd: Balance, - /// The amount of Contribution Tokens that have not yet been sold - pub remaining_contribution_tokens: Balance, - /// Funding reached amount in USD (6 decimals) - pub funding_amount_reached_usd: Balance, - /// Information about the total amount bonded, and the outcome in regards to reward/slash/nothing - pub evaluation_round_info: EvaluationRoundInfo, - /// When the Funding Round ends - pub funding_end_block: Option, - /// ParaId of project - pub parachain_id: Option, - /// Migration readiness check - pub migration_readiness_check: Option, - /// HRMP Channel status - pub hrmp_channel_status: HRMPChannelStatus, - } - type OldProjectDetailsOf = - OldProjectDetails, Did, BlockNumberFor, PriceOf, BalanceOf, EvaluationRoundInfoOf>; - - pub struct UncheckedMigrationToV3(PhantomData); - impl OnRuntimeUpgrade for UncheckedMigrationToV3 { - fn on_runtime_upgrade() -> frame_support::weights::Weight { - let mut items = 0; - let mut translate = |_key, item: OldProjectDetailsOf| -> Option> { - items += 1; - let new_status = match item.status { - OldProjectStatus::Application => ProjectStatus::Application, - OldProjectStatus::EvaluationRound => ProjectStatus::EvaluationRound, - OldProjectStatus::AuctionInitializePeriod => ProjectStatus::AuctionInitializePeriod, - OldProjectStatus::AuctionOpening => ProjectStatus::AuctionOpening, - OldProjectStatus::AuctionClosing => ProjectStatus::AuctionClosing, - OldProjectStatus::CommunityRound => ProjectStatus::CommunityRound, - OldProjectStatus::RemainderRound => ProjectStatus::RemainderRound, - OldProjectStatus::FundingFailed => ProjectStatus::FundingFailed, - OldProjectStatus::AwaitingProjectDecision => ProjectStatus::AwaitingProjectDecision, - OldProjectStatus::FundingSuccessful => ProjectStatus::FundingSuccessful, - OldProjectStatus::ReadyToStartMigration => ProjectStatus::ReadyToStartMigration, - OldProjectStatus::MigrationCompleted => ProjectStatus::MigrationCompleted, - }; - Some(ProjectDetailsOf:: { - issuer_account: item.issuer_account, - issuer_did: item.issuer_did, - is_frozen: item.is_frozen, - weighted_average_price: item.weighted_average_price, - status: new_status, - phase_transition_points: item.phase_transition_points, - fundraising_target_usd: item.fundraising_target_usd, - remaining_contribution_tokens: item.remaining_contribution_tokens, - funding_amount_reached_usd: item.funding_amount_reached_usd, - evaluation_round_info: item.evaluation_round_info, - usd_bid_on_oversubscription: None, - funding_end_block: item.funding_end_block, - parachain_id: item.parachain_id, - migration_readiness_check: item.migration_readiness_check, - hrmp_channel_status: item.hrmp_channel_status, - }) - }; - - crate::ProjectsDetails::::translate(|key, object: OldProjectDetailsOf| translate(key, object)); - - T::DbWeight::get().reads_writes(items, items) - } - } - - pub type MigrationToV3 = frame_support::migrations::VersionedMigration< - 2, - 3, - UncheckedMigrationToV3, - crate::Pallet, - ::DbWeight, - >; -} +// +// pub mod v2 { +// use crate::{AccountIdOf, BalanceOf, Config, ProjectsMetadata}; +// use frame_support::{ +// pallet_prelude::{Decode, Encode, MaxEncodedLen, RuntimeDebug, TypeInfo}, +// traits::{Get, OnRuntimeUpgrade}, +// BoundedVec, +// }; +// use polimec_common::USD_DECIMALS; +// use sp_arithmetic::{FixedPointNumber, Percent}; +// use sp_core::ConstU32; +// use sp_std::marker::PhantomData; +// +// #[derive(Clone, Copy, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] +// #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +// pub struct OldTicketSize { +// pub usd_minimum_per_participation: Option, +// pub usd_maximum_per_did: Option, +// } +// +// #[derive(Clone, Copy, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] +// #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +// pub struct OldBiddingTicketSizes { +// pub professional: OldTicketSize, +// pub institutional: OldTicketSize, +// pub phantom: PhantomData<(Price, Balance)>, +// } +// +// #[derive(Clone, Copy, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] +// #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +// pub struct OldContributingTicketSizes { +// pub retail: OldTicketSize, +// pub professional: OldTicketSize, +// pub institutional: OldTicketSize, +// pub phantom: PhantomData<(Price, Balance)>, +// } +// +// type OldProjectMetadataOf = OldProjectMetadata< +// BoundedVec>, +// BalanceOf, +// crate::PriceOf, +// AccountIdOf, +// polimec_common::credentials::Cid, +// >; +// #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] +// #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +// pub struct OldProjectMetadata { +// /// Token Metadata +// pub token_information: crate::CurrencyMetadata, +// /// Mainnet Token Max Supply +// pub mainnet_token_max_supply: Balance, +// /// Total allocation of Contribution Tokens available for the Funding Round. +// pub total_allocation_size: Balance, +// /// Percentage of the total allocation of Contribution Tokens available for the Auction Round +// pub auction_round_allocation_percentage: Percent, +// /// The minimum price per token in USD, decimal-aware. See [`calculate_decimals_aware_price()`](crate::traits::ProvideAssetPrice::calculate_decimals_aware_price) for more information. +// pub minimum_price: Price, +// /// Maximum and minimum ticket sizes for auction round +// pub bidding_ticket_sizes: OldBiddingTicketSizes, +// /// Maximum and minimum ticket sizes for community/remainder rounds +// pub contributing_ticket_sizes: OldContributingTicketSizes, +// /// Participation currencies (e.g stablecoin, DOT, KSM) +// pub participation_currencies: +// BoundedVec>, +// pub funding_destination_account: AccountId, +// /// Additional metadata +// pub policy_ipfs_cid: Option, +// } +// +// pub struct UncheckedMigrationToV2(PhantomData); +// impl OnRuntimeUpgrade for UncheckedMigrationToV2 { +// fn on_runtime_upgrade() -> frame_support::weights::Weight { +// let mut items = 0; +// let mut translate = |_key, item: OldProjectMetadataOf| -> Option> { +// items += 1; +// let usd_unit = sp_arithmetic::traits::checked_pow(BalanceOf::::from(10u64), USD_DECIMALS as usize)?; +// Some(crate::ProjectMetadataOf:: { +// token_information: item.token_information, +// mainnet_token_max_supply: item.mainnet_token_max_supply, +// total_allocation_size: item.total_allocation_size, +// auction_round_allocation_percentage: item.auction_round_allocation_percentage, +// minimum_price: item.minimum_price, +// bidding_ticket_sizes: crate::BiddingTicketSizes { +// professional: crate::TicketSize { +// usd_minimum_per_participation: item +// .bidding_ticket_sizes +// .professional +// .usd_minimum_per_participation +// .unwrap_or_else(|| usd_unit), +// usd_maximum_per_did: item.bidding_ticket_sizes.professional.usd_maximum_per_did, +// }, +// institutional: crate::TicketSize { +// usd_minimum_per_participation: item +// .bidding_ticket_sizes +// .institutional +// .usd_minimum_per_participation +// .unwrap_or_else(|| usd_unit), +// usd_maximum_per_did: item.bidding_ticket_sizes.institutional.usd_maximum_per_did, +// }, +// phantom: Default::default(), +// }, +// contributing_ticket_sizes: crate::ContributingTicketSizes { +// retail: crate::TicketSize { +// usd_minimum_per_participation: item +// .contributing_ticket_sizes +// .retail +// .usd_minimum_per_participation +// .unwrap_or_else(|| usd_unit), +// usd_maximum_per_did: item.contributing_ticket_sizes.retail.usd_maximum_per_did, +// }, +// professional: crate::TicketSize { +// usd_minimum_per_participation: item +// .contributing_ticket_sizes +// .professional +// .usd_minimum_per_participation +// .unwrap_or_else(|| usd_unit), +// usd_maximum_per_did: item.contributing_ticket_sizes.professional.usd_maximum_per_did, +// }, +// institutional: crate::TicketSize { +// usd_minimum_per_participation: item +// .contributing_ticket_sizes +// .institutional +// .usd_minimum_per_participation +// .unwrap_or_else(|| usd_unit), +// usd_maximum_per_did: item.contributing_ticket_sizes.institutional.usd_maximum_per_did, +// }, +// phantom: Default::default(), +// }, +// participation_currencies: item.participation_currencies, +// funding_destination_account: item.funding_destination_account, +// policy_ipfs_cid: item.policy_ipfs_cid, +// }) +// }; +// +// ProjectsMetadata::::translate(|key, object: OldProjectMetadataOf| translate(key, object)); +// +// T::DbWeight::get().reads_writes(items, items) +// } +// } +// +// pub type MigrationToV2 = frame_support::migrations::VersionedMigration< +// 1, +// 2, +// UncheckedMigrationToV2, +// crate::Pallet, +// ::DbWeight, +// >; +// } +// +// pub mod v3 { +// use crate::{ +// AccountIdOf, BalanceOf, Config, EvaluationRoundInfoOf, HRMPChannelStatus, MigrationReadinessCheck, +// PhaseTransitionPoints, PriceOf, ProjectDetailsOf, ProjectStatus, +// }; +// use frame_support::{ +// pallet_prelude::Get, +// traits::{tokens::Balance as BalanceT, OnRuntimeUpgrade}, +// }; +// use frame_system::pallet_prelude::BlockNumberFor; +// use polimec_common::credentials::Did; +// use polkadot_parachain_primitives::primitives::Id as ParaId; +// use scale_info::TypeInfo; +// use sp_arithmetic::FixedPointNumber; +// use sp_core::{Decode, Encode, MaxEncodedLen, RuntimeDebug}; +// use sp_std::marker::PhantomData; +// +// #[derive(Default, Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] +// #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))] +// pub enum OldProjectStatus { +// #[default] +// Application, +// EvaluationRound, +// AuctionInitializePeriod, +// AuctionOpening, +// AuctionClosing, +// CommunityRound, +// RemainderRound, +// FundingFailed, +// AwaitingProjectDecision, +// FundingSuccessful, +// ReadyToStartMigration, +// MigrationCompleted, +// } +// #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] +// pub struct OldProjectDetails< +// AccountId, +// Did, +// BlockNumber, +// Price: FixedPointNumber, +// Balance: BalanceT, +// EvaluationRoundInfo, +// > { +// pub issuer_account: AccountId, +// pub issuer_did: Did, +// /// Whether the project is frozen, so no `metadata` changes are allowed. +// pub is_frozen: bool, +// /// The price in USD per token decided after the Auction Round +// pub weighted_average_price: Option, +// /// The current status of the project +// pub status: OldProjectStatus, +// /// When the different project phases start and end +// pub phase_transition_points: PhaseTransitionPoints, +// /// Fundraising target amount in USD (6 decimals) +// pub fundraising_target_usd: Balance, +// /// The amount of Contribution Tokens that have not yet been sold +// pub remaining_contribution_tokens: Balance, +// /// Funding reached amount in USD (6 decimals) +// pub funding_amount_reached_usd: Balance, +// /// Information about the total amount bonded, and the outcome in regards to reward/slash/nothing +// pub evaluation_round_info: EvaluationRoundInfo, +// /// When the Funding Round ends +// pub funding_end_block: Option, +// /// ParaId of project +// pub parachain_id: Option, +// /// Migration readiness check +// pub migration_readiness_check: Option, +// /// HRMP Channel status +// pub hrmp_channel_status: HRMPChannelStatus, +// } +// type OldProjectDetailsOf = +// OldProjectDetails, Did, BlockNumberFor, PriceOf, BalanceOf, EvaluationRoundInfoOf>; +// +// pub struct UncheckedMigrationToV3(PhantomData); +// impl OnRuntimeUpgrade for UncheckedMigrationToV3 { +// fn on_runtime_upgrade() -> frame_support::weights::Weight { +// let mut items = 0; +// let mut translate = |_key, item: OldProjectDetailsOf| -> Option> { +// items += 1; +// let new_status = match item.status { +// OldProjectStatus::Application => ProjectStatus::Application, +// OldProjectStatus::EvaluationRound => ProjectStatus::EvaluationRound, +// OldProjectStatus::AuctionInitializePeriod => ProjectStatus::AuctionInitializePeriod, +// OldProjectStatus::AuctionOpening => ProjectStatus::AuctionOpening, +// OldProjectStatus::AuctionClosing => ProjectStatus::AuctionClosing, +// OldProjectStatus::CommunityRound => ProjectStatus::CommunityRound, +// OldProjectStatus::RemainderRound => ProjectStatus::RemainderRound, +// OldProjectStatus::FundingFailed => ProjectStatus::FundingFailed, +// OldProjectStatus::AwaitingProjectDecision => ProjectStatus::AwaitingProjectDecision, +// OldProjectStatus::FundingSuccessful => ProjectStatus::FundingSuccessful, +// OldProjectStatus::ReadyToStartMigration => ProjectStatus::ReadyToStartMigration, +// OldProjectStatus::MigrationCompleted => ProjectStatus::MigrationCompleted, +// }; +// Some(ProjectDetailsOf:: { +// issuer_account: item.issuer_account, +// issuer_did: item.issuer_did, +// is_frozen: item.is_frozen, +// weighted_average_price: item.weighted_average_price, +// status: new_status, +// phase_transition_points: item.phase_transition_points, +// fundraising_target_usd: item.fundraising_target_usd, +// remaining_contribution_tokens: item.remaining_contribution_tokens, +// funding_amount_reached_usd: item.funding_amount_reached_usd, +// evaluation_round_info: item.evaluation_round_info, +// usd_bid_on_oversubscription: None, +// funding_end_block: item.funding_end_block, +// parachain_id: item.parachain_id, +// migration_readiness_check: item.migration_readiness_check, +// hrmp_channel_status: item.hrmp_channel_status, +// }) +// }; +// +// crate::ProjectsDetails::::translate(|key, object: OldProjectDetailsOf| translate(key, object)); +// +// T::DbWeight::get().reads_writes(items, items) +// } +// } +// +// pub type MigrationToV3 = frame_support::migrations::VersionedMigration< +// 2, +// 3, +// UncheckedMigrationToV3, +// crate::Pallet, +// ::DbWeight, +// >; +// } diff --git a/pallets/funding/src/tests/2_evaluation.rs b/pallets/funding/src/tests/2_evaluation.rs index 39ea18100..fe1f336c2 100644 --- a/pallets/funding/src/tests/2_evaluation.rs +++ b/pallets/funding/src/tests/2_evaluation.rs @@ -329,12 +329,7 @@ mod start_evaluation_extrinsic { }, usd_bid_on_oversubscription: None, funding_end_block: None, - parachain_id: None, - migration_readiness_check: None, - hrmp_channel_status: HRMPChannelStatus { - project_to_polimec: ChannelStatus::Closed, - polimec_to_project: ChannelStatus::Closed, - }, + migration_type: MigrationType::Offchain, }; assert_ok!(inst.execute(|| PolimecFunding::start_evaluation( RuntimeOrigin::signed(issuer), diff --git a/pallets/funding/src/tests/8_ct_migration.rs b/pallets/funding/src/tests/8_ct_migration.rs index d26601554..e7b9f8397 100644 --- a/pallets/funding/src/tests/8_ct_migration.rs +++ b/pallets/funding/src/tests/8_ct_migration.rs @@ -15,18 +15,29 @@ fn para_id_for_project_can_be_set_by_issuer() { inst.advance_time(::SuccessToSettlementTime::get() + 20u64).unwrap(); inst.execute(|| { - assert_ok!(crate::Pallet::::do_set_para_id_for_project( + assert_ok!(crate::Pallet::::do_configure_receiver_pallet_migration( &ISSUER_1, project_id, - ParaId::from(2006u32), + ParaId::from(2006u32).into(), )); }); let project_details = inst.get_project_details(project_id); - assert_eq!(project_details.parachain_id, Some(ParaId::from(2006u32))); + + assert_eq!( + project_details.migration_type, + MigrationType::ParachainReceiverPallet(ParachainReceiverPalletInfo { + parachain_id: ParaId::from(2006u32), + hrmp_channel_status: HRMPChannelStatus { + project_to_polimec: ChannelStatus::Closed, + polimec_to_project: ChannelStatus::Closed + }, + migration_readiness_check: None, + }) + ); } #[test] -fn para_id_for_project_cannot_be_set_by_anyone_but_issuer() { +fn migration_config_cannot_be_set_by_anyone_but_issuer() { let mut inst = MockInstantiator::new(Some(RefCell::new(new_test_ext()))); let project_id = inst.create_finished_project( default_project_metadata(ISSUER_1), @@ -40,18 +51,30 @@ fn para_id_for_project_cannot_be_set_by_anyone_but_issuer() { inst.execute(|| { assert_err!( - crate::Pallet::::do_set_para_id_for_project(&EVALUATOR_1, project_id, ParaId::from(2006u32),), + crate::Pallet::::do_configure_receiver_pallet_migration( + &EVALUATOR_1, + project_id, + ParaId::from(2006u32), + ), Error::::NotIssuer ); assert_err!( - crate::Pallet::::do_set_para_id_for_project(&BIDDER_1, project_id, ParaId::from(2006u32),), + crate::Pallet::::do_configure_receiver_pallet_migration( + &BIDDER_1, + project_id, + ParaId::from(2006u32), + ), Error::::NotIssuer ); assert_err!( - crate::Pallet::::do_set_para_id_for_project(&BUYER_1, project_id, ParaId::from(2006u32),), + crate::Pallet::::do_configure_receiver_pallet_migration( + &BUYER_1, + project_id, + ParaId::from(2006u32), + ), Error::::NotIssuer ); }); let project_details = inst.get_project_details(project_id); - assert_eq!(project_details.parachain_id, None); + assert_eq!(project_details.migration_type, MigrationType::Offchain); } diff --git a/pallets/funding/src/types.rs b/pallets/funding/src/types.rs index 2fb3ebbf6..c9080d8fe 100644 --- a/pallets/funding/src/types.rs +++ b/pallets/funding/src/types.rs @@ -294,6 +294,22 @@ pub mod storage_types { Institutional(Bound), } + #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] + pub enum MigrationType { + Offchain, + ParachainReceiverPallet(ParachainReceiverPalletInfo), + } + + #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] + pub struct ParachainReceiverPalletInfo { + /// ParaId of project + pub parachain_id: ParaId, + /// HRMP Channel status + pub hrmp_channel_status: HRMPChannelStatus, + /// Migration readiness check + pub migration_readiness_check: Option, + } + #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, MaxEncodedLen, TypeInfo)] pub struct ProjectDetails< AccountId, @@ -325,12 +341,7 @@ pub mod storage_types { pub usd_bid_on_oversubscription: Option, /// When the Funding Round ends pub funding_end_block: Option, - /// ParaId of project - pub parachain_id: Option, - /// Migration readiness check - pub migration_readiness_check: Option, - /// HRMP Channel status - pub hrmp_channel_status: HRMPChannelStatus, + pub migration_type: MigrationType, } /// Tells on_initialize what to do with the project #[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)]