diff --git a/pallets/funding/src/storage_migrations.rs b/pallets/funding/src/storage_migrations.rs index cf46d54c1..7754406d9 100644 --- a/pallets/funding/src/storage_migrations.rs +++ b/pallets/funding/src/storage_migrations.rs @@ -1,6 +1,159 @@ //! A module that is responsible for migration of storage. -use frame_support::traits::StorageVersion; - +use super::*; +use frame_support::{ + pallet_prelude::*, + traits::{tokens::Balance as BalanceT, StorageVersion}, +}; +use serde::{Deserialize, Serialize}; /// The current storage version -pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(3); +pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(4); pub const LOG: &str = "runtime::funding::migration"; +use frame_support::traits::OnRuntimeUpgrade; + +pub mod v3tov4 { + use super::*; + #[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, + /// If the auction was oversubscribed, how much USD was raised across all winning bids + 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, + } + + #[derive(Clone, Copy, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] + pub struct MigrationReadinessCheck { + pub holding_check: (xcm::v3::QueryId, CheckOutcome), + pub pallet_check: (xcm::v3::QueryId, CheckOutcome), + } + + impl MigrationReadinessCheck { + pub fn is_ready(&self) -> bool { + self.holding_check.1 == CheckOutcome::Passed(None) && + matches!(self.pallet_check.1, CheckOutcome::Passed(Some(_))) + } + } + + pub type PalletIndex = u8; + #[derive(Clone, Copy, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen)] + pub enum CheckOutcome { + AwaitingResponse, + Passed(Option), + Failed, + } + + #[derive( + Default, Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, TypeInfo, MaxEncodedLen, Serialize, Deserialize, + )] + pub enum OldProjectStatus { + #[default] + Application, + EvaluationRound, + AuctionInitializePeriod, + AuctionOpening, + AuctionClosing, + CalculatingWAP, + CommunityRound, + RemainderRound, + FundingFailed, + AwaitingProjectDecision, + FundingSuccessful, + ReadyToStartMigration, + MigrationCompleted, + } + + type OldProjectDetailsOf = + OldProjectDetails, Did, BlockNumberFor, PriceOf, BalanceOf, EvaluationRoundInfoOf>; + + pub struct UncheckedMigrationToV4(PhantomData); + impl OnRuntimeUpgrade for UncheckedMigrationToV4 { + 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::CalculatingWAP => ProjectStatus::CalculatingWAP, + OldProjectStatus::CommunityRound => ProjectStatus::CommunityRound, + OldProjectStatus::RemainderRound => ProjectStatus::RemainderRound, + OldProjectStatus::FundingFailed => ProjectStatus::FundingFailed, + OldProjectStatus::AwaitingProjectDecision => ProjectStatus::AwaitingProjectDecision, + OldProjectStatus::FundingSuccessful => { + debug_assert!(item.funding_end_block.is_none(), "Settlement shouldn't have started yet"); + ProjectStatus::FundingSuccessful + }, + + OldProjectStatus::ReadyToStartMigration => { + debug_assert!(false, "No project should be in this state when upgrading to v4"); + ProjectStatus::CTMigrationStarted + }, + OldProjectStatus::MigrationCompleted => { + debug_assert!(false, "No project should be in this state when upgrading to v4"); + ProjectStatus::CTMigrationFinished + }, + }; + 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: item.usd_bid_on_oversubscription, + funding_end_block: item.funding_end_block, + migration_type: None, + }) + }; + + crate::ProjectsDetails::::translate(|key, object: OldProjectDetailsOf| translate(key, object)); + + T::DbWeight::get().reads_writes(items, items) + } + } + + pub type MigrationToV4 = frame_support::migrations::VersionedMigration< + 3, + 4, + UncheckedMigrationToV4, + crate::Pallet, + ::DbWeight, + >; +} diff --git a/pallets/linear-release/src/tests.rs b/pallets/linear-release/src/tests.rs index 901e860b3..d5d81baa9 100644 --- a/pallets/linear-release/src/tests.rs +++ b/pallets/linear-release/src/tests.rs @@ -125,9 +125,9 @@ fn check_vesting_status_for_multi_schedule_account() { assert_eq!(Balances::balance_on_hold(&MockRuntimeHoldReason::Reason, &2), 20 * ED); assert_ok!(Vesting::vested_transfer(Some(4).into(), 2, sched1, MockRuntimeHoldReason::Reason)); assert_eq!(Balances::balance_on_hold(&MockRuntimeHoldReason::Reason, &2), 29 * ED); // Why 29 and not 30? Because sched1 is already unlocking. - // Free balance is the one set in Genesis inside the Balances pallet - // + the one from the vested transfer. - // BUT NOT the one in sched0, since the vesting will start at block #10. + // Free balance is the one set in Genesis inside the Balances pallet + // + the one from the vested transfer. + // BUT NOT the one in sched0, since the vesting will start at block #10. let balance = Balances::balance(&2); assert_eq!(balance, ED * (2)); // The most recently added schedule exists. @@ -193,7 +193,7 @@ fn unvested_balance_should_not_transfer() { ExtBuilder::default().existential_deposit(10).build().execute_with(|| { let user1_free_balance = Balances::free_balance(1); assert_eq!(user1_free_balance, 50); // Account 1 has free balance - // Account 1 has only 5 units vested at block 1 (plus 50 unvested) + // Account 1 has only 5 units vested at block 1 (plus 50 unvested) assert_eq!(Vesting::vesting_balance(&1, MockRuntimeHoldReason::Reason), Some(5)); // Account 1 cannot send more than vested amount... assert_noop!(Balances::transfer_allow_death(Some(1).into(), 2, 56), TokenError::FundsUnavailable); }); @@ -205,13 +205,13 @@ fn vested_balance_should_transfer() { assert_eq!(System::block_number(), 1); let user1_free_balance = Balances::free_balance(1); assert_eq!(user1_free_balance, 50); // Account 1 has free balance - // Account 1 has only 5 units vested at block 1 (plus 50 unvested) + // Account 1 has only 5 units vested at block 1 (plus 50 unvested) assert_eq!(Vesting::vesting_balance(&1, MockRuntimeHoldReason::Reason), Some(5)); assert_noop!(Balances::transfer_allow_death(Some(1).into(), 2, 45), TokenError::Frozen); // Account 1 free balance - ED is < 45 assert_ok!(Vesting::vest(Some(1).into(), MockRuntimeHoldReason::Reason)); let user1_free_balance = Balances::free_balance(1); assert_eq!(user1_free_balance, 55); // Account 1 has free balance - // Account 1 has vested 1 unit at block 1 (plus 50 unvested) + // Account 1 has vested 1 unit at block 1 (plus 50 unvested) assert_ok!(Balances::transfer_allow_death(Some(1).into(), 2, 45)); // After the vest it can now send the 45 UNIT }); } @@ -259,7 +259,7 @@ fn vested_balance_should_transfer_using_vest_other() { ExtBuilder::default().existential_deposit(10).build().execute_with(|| { let user1_free_balance = Balances::free_balance(1); assert_eq!(user1_free_balance, 50); // Account 1 has free balance - // Account 1 has only 5 units vested at block 1 (plus 50 unvested) + // Account 1 has only 5 units vested at block 1 (plus 50 unvested) assert_eq!(Vesting::vesting_balance(&1, MockRuntimeHoldReason::Reason), Some(5)); assert_ok!(Vesting::vest_other(Some(2).into(), 1, MockRuntimeHoldReason::Reason)); assert_ok!(Balances::transfer_allow_death(Some(1).into(), 2, 55 - 10)); @@ -317,7 +317,7 @@ fn extra_balance_should_transfer() { // Account 2 has no units vested at block 1, but gained 100 assert_ok!(Balances::transfer_allow_death(Some(2).into(), 3, 100 - 10)); // Account 2 can send extra - // units gained + // units gained }); } @@ -327,7 +327,7 @@ fn liquid_funds_should_transfer_with_delayed_vesting() { let user12_free_balance = Balances::free_balance(12); assert_eq!(user12_free_balance, 1280); // Account 12 has free balance - // Account 12 has liquid funds + // Account 12 has liquid funds assert_eq!(Vesting::vesting_balance(&12, MockRuntimeHoldReason::Reason), Some(0)); // Account 12 has delayed vesting diff --git a/runtimes/polimec/src/lib.rs b/runtimes/polimec/src/lib.rs index f25495240..b1cdbb005 100644 --- a/runtimes/polimec/src/lib.rs +++ b/runtimes/polimec/src/lib.rs @@ -157,9 +157,11 @@ pub type Migrations = migrations::Unreleased; /// The runtime migrations per release. #[allow(missing_docs)] pub mod migrations { + use crate::Runtime; + /// Unreleased migrations. Add new ones here: #[allow(unused_parens)] - pub type Unreleased = (); + pub type Unreleased = (pallet_funding::storage_migrations::v3tov4::MigrationToV4); } /// Executive: handles dispatch to the various modules. @@ -205,10 +207,10 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("polimec-mainnet"), impl_name: create_runtime_str!("polimec-mainnet"), authoring_version: 1, - spec_version: 0_007_005, + spec_version: 0_007_006, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 3, + transaction_version: 4, state_version: 1, }; diff --git a/scripts/chopsticks/polimec-testing/polkadot-polimec.yml b/scripts/chopsticks/polimec-testing/polkadot-polimec.yml index e858c63f0..52f63e03f 100644 --- a/scripts/chopsticks/polimec-testing/polkadot-polimec.yml +++ b/scripts/chopsticks/polimec-testing/polkadot-polimec.yml @@ -10,61 +10,6 @@ import-storage: data: free: "500000000000000" - # account1 - 50k PLMC - - - - "5EoHniZVuKRKNXNtVZzw8Jbc8Qtgy8GN5QKDKSA78HEok7YW" - - providers: 1 - data: - free: "500000000000000" - - # account2 - 50k PLMC - - - - "5GeXY2mKL4ADz7mDtsuHvNrRky48NqdWb4u8c5Sg9N8s3T1y" - - providers: 1 - data: - free: "500000000000000" - - # account3 - 50k PLMC - - - - "5EfE8r9uWWMazvyh8tkcuuKSy6PbAZQSqq42CXYwGdvwjpb8" - - providers: 1 - data: - free: "500000000000000" - - # account4 - 50k PLMC - - - - "5C8ULBGhfaP2nmDcuFbiShQ1hMwWsB7ghbChDKAwdszSWnA5" - - providers: 1 - data: - free: "500000000000000" - - # account5 - 50k PLMC - - - - "5HGqvcE29nHekDEYND3ZZtobbP4UeCcALFgwEm5YUvroZJr6" - - providers: 1 - data: - free: "500000000000000" - - # account6 - 50k PLMC - - - - "5CGEmsGTJcYSBCdXvsjDUBxW2dtvte5M8By95gwMwToih37s" - - providers: 1 - data: - free: "500000000000000" - - # account7 - 50k PLMC - - - - "5GsWm46kXRF7p6ifSQjrdc8HgPbzY4uWgJdQSUcGGDczkDGa" - - providers: 1 - data: - free: "500000000000000" - - # account8 - 50k PLMC - - - - "5H4AWTrkHN6aaQCv2jn48HVZjGhiCqswt6sPBksFPrrf2FPY" - - providers: 1 - data: - free: "500000000000000" - - # account9 - 50k PLMC - - - - "5CabLepLT8e6NvJCtzrEZLEBRd1FxKXU72F2NvbYTVf3bNej" - - providers: 1 - data: - free: "500000000000000" - - ForeignAssets: Account: # account0 - 50k DOT, 50k USDT, 50k USDC