From 21d1df42ca2d410907fb74ed5e9cdda6eb9aa2cb Mon Sep 17 00:00:00 2001 From: muharem Date: Fri, 2 Feb 2024 12:32:38 +0800 Subject: [PATCH 01/42] account id converter with pallet id salt --- .../assets/asset-hub-rococo/src/lib.rs | 13 +++++- .../assets/asset-hub-westend/src/lib.rs | 13 +++++- substrate/bin/node/runtime/src/lib.rs | 15 +++++-- substrate/frame/asset-conversion/src/mock.rs | 7 +++- substrate/frame/asset-conversion/src/types.rs | 42 ++++++++++++++----- .../asset-conversion-tx-payment/src/mock.rs | 9 +++- 6 files changed, 77 insertions(+), 22 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index d67595b10b4e..d2e7cfa7bf17 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -359,6 +359,11 @@ pub type NativeAndAssets = fungible::UnionOf< AccountId, >; +pub type PoolIdToAccountId = pallet_asset_conversion::AccountIdConverter< + AssetConversionPalletId, + (xcm::v3::Location, xcm::v3::Location), +>; + impl pallet_asset_conversion::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Balance = Balance; @@ -366,8 +371,12 @@ impl pallet_asset_conversion::Config for Runtime { type AssetKind = xcm::v3::Location; type Assets = NativeAndAssets; type PoolId = (Self::AssetKind, Self::AssetKind); - type PoolLocator = - pallet_asset_conversion::WithFirstAsset; + type PoolLocator = pallet_asset_conversion::WithFirstAsset< + TokenLocationV3, + AccountId, + Self::AssetKind, + PoolIdToAccountId, + >; type PoolAssetId = u32; type PoolAssets = PoolAssets; type PoolSetupFee = ConstU128<0>; // Asset class deposit fees are sufficient to prevent spam diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 6424cec675dd..8812d3eabd30 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -315,6 +315,11 @@ pub type NativeAndAssets = fungible::UnionOf< AccountId, >; +pub type PoolIdToAccountId = pallet_asset_conversion::AccountIdConverter< + AssetConversionPalletId, + (xcm::v3::Location, xcm::v3::Location), +>; + impl pallet_asset_conversion::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Balance = Balance; @@ -322,8 +327,12 @@ impl pallet_asset_conversion::Config for Runtime { type AssetKind = xcm::v3::Location; type Assets = NativeAndAssets; type PoolId = (Self::AssetKind, Self::AssetKind); - type PoolLocator = - pallet_asset_conversion::WithFirstAsset; + type PoolLocator = pallet_asset_conversion::WithFirstAsset< + WestendLocationV3, + AccountId, + Self::AssetKind, + PoolIdToAccountId, + >; type PoolAssetId = u32; type PoolAssets = PoolAssets; type PoolSetupFee = ConstU128<0>; // Asset class deposit fees are sufficient to prevent spam diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index c2472e906de6..99c618dcffcb 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -62,7 +62,7 @@ use frame_system::{ }; pub use node_primitives::{AccountId, Signature}; use node_primitives::{AccountIndex, Balance, BlockNumber, Hash, Moment, Nonce}; -use pallet_asset_conversion::{Ascending, Chain, WithFirstAsset}; +use pallet_asset_conversion::{AccountIdConverter, Ascending, Chain, WithFirstAsset}; use pallet_broker::{CoreAssignment, CoreIndex, CoretimeInterface, PartsOf57600}; use pallet_election_provider_multi_phase::{GeometricDepositBase, SolutionAccuracyOf}; use pallet_identity::legacy::IdentityInfo; @@ -1688,8 +1688,17 @@ impl pallet_asset_conversion::Config for Runtime { type Assets = UnionOf, AccountId>; type PoolId = (Self::AssetKind, Self::AssetKind); type PoolLocator = Chain< - WithFirstAsset>, - Ascending>, + WithFirstAsset< + Native, + AccountId, + NativeOrWithId, + AccountIdConverter, + >, + Ascending< + AccountId, + NativeOrWithId, + AccountIdConverter, + >, >; type PoolAssetId = >::AssetId; type PoolAssets = PoolAssets; diff --git a/substrate/frame/asset-conversion/src/mock.rs b/substrate/frame/asset-conversion/src/mock.rs index dd1d26ff238d..18fc4022af86 100644 --- a/substrate/frame/asset-conversion/src/mock.rs +++ b/substrate/frame/asset-conversion/src/mock.rs @@ -157,8 +157,11 @@ ord_parameter_types! { } pub type NativeAndAssets = UnionOf, u128>; -pub type AscendingLocator = Ascending>; -pub type WithFirstAssetLocator = WithFirstAsset>; +pub type PoolIdToAccountId = + AccountIdConverter, NativeOrWithId)>; +pub type AscendingLocator = Ascending, PoolIdToAccountId>; +pub type WithFirstAssetLocator = + WithFirstAsset, PoolIdToAccountId>; impl Config for Test { type RuntimeEvent = RuntimeEvent; diff --git a/substrate/frame/asset-conversion/src/types.rs b/substrate/frame/asset-conversion/src/types.rs index fd6d41a55b61..7e25db4eca2f 100644 --- a/substrate/frame/asset-conversion/src/types.rs +++ b/substrate/frame/asset-conversion/src/types.rs @@ -18,6 +18,7 @@ use super::*; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; +use sp_runtime::traits::TryConvert; use sp_std::marker::PhantomData; /// Represents a swap path with associated asset amounts indicating how much of the asset needs to @@ -68,15 +69,17 @@ pub trait PoolLocator { /// /// The `PoolId` is represented as a tuple of `AssetKind`s with `FirstAsset` always positioned as /// the first element. -pub struct WithFirstAsset( - PhantomData<(FirstAsset, AccountId, AssetKind)>, +pub struct WithFirstAsset( + PhantomData<(FirstAsset, AccountId, AssetKind, AccountIdConverter)>, ); -impl PoolLocator - for WithFirstAsset +impl + PoolLocator + for WithFirstAsset where AssetKind: Eq + Clone + Encode, AccountId: Decode, FirstAsset: Get, + AccountIdConverter: for<'a> TryConvert<&'a (AssetKind, AssetKind), AccountId>, { fn pool_id(asset1: &AssetKind, asset2: &AssetKind) -> Result<(AssetKind, AssetKind), ()> { let first = FirstAsset::get(); @@ -88,18 +91,21 @@ where } } fn address(id: &(AssetKind, AssetKind)) -> Result { - let encoded = sp_io::hashing::blake2_256(&Encode::encode(id)[..]); - Decode::decode(&mut TrailingZeroInput::new(encoded.as_ref())).map_err(|_| ()) + AccountIdConverter::try_convert(id).map_err(|_| ()) } } /// Pool locator where the `PoolId` is a tuple of `AssetKind`s arranged in ascending order. -pub struct Ascending(PhantomData<(AccountId, AssetKind)>); -impl PoolLocator - for Ascending +pub struct Ascending( + PhantomData<(AccountId, AssetKind, AccountIdConverter)>, +); +impl + PoolLocator + for Ascending where AssetKind: Ord + Clone + Encode, AccountId: Decode, + AccountIdConverter: for<'a> TryConvert<&'a (AssetKind, AssetKind), AccountId>, { fn pool_id(asset1: &AssetKind, asset2: &AssetKind) -> Result<(AssetKind, AssetKind), ()> { match true { @@ -109,8 +115,7 @@ where } } fn address(id: &(AssetKind, AssetKind)) -> Result { - let encoded = sp_io::hashing::blake2_256(&Encode::encode(id)[..]); - Decode::decode(&mut TrailingZeroInput::new(encoded.as_ref())).map_err(|_| ()) + AccountIdConverter::try_convert(id).map_err(|_| ()) } } @@ -131,3 +136,18 @@ where First::address(id).or(Second::address(id)) } } + +/// `PoolId` to `AccountId` conversion. +pub struct AccountIdConverter(PhantomData<(GetPalletId, PoolId)>); +impl TryConvert<&PoolId, AccountId> + for AccountIdConverter +where + PoolId: Encode, + AccountId: Decode, + GetPalletId: Get, +{ + fn try_convert(id: &PoolId) -> Result { + let encoded = sp_io::hashing::blake2_256(&Encode::encode(&(GetPalletId::get(), id))[..]); + Decode::decode(&mut TrailingZeroInput::new(encoded.as_ref())).map_err(|_| id) + } +} diff --git a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs index c8bf2eb8f440..1ee0a0bd6da0 100644 --- a/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs +++ b/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs @@ -238,6 +238,11 @@ ord_parameter_types! { pub const AssetConversionOrigin: u64 = AccountIdConversion::::into_account_truncating(&AssetConversionPalletId::get()); } +pub type PoolIdToAccountId = pallet_asset_conversion::AccountIdConverter< + AssetConversionPalletId, + (NativeOrWithId, NativeOrWithId), +>; + impl pallet_asset_conversion::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Balance = Balance; @@ -246,8 +251,8 @@ impl pallet_asset_conversion::Config for Runtime { type Assets = UnionOf, AccountId>; type PoolId = (Self::AssetKind, Self::AssetKind); type PoolLocator = Chain< - WithFirstAsset>, - Ascending>, + WithFirstAsset, PoolIdToAccountId>, + Ascending, PoolIdToAccountId>, >; type PoolAssetId = u32; type PoolAssets = PoolAssets; From ebbad9fe9650532a2cfd05ce30129aaabde3b916 Mon Sep 17 00:00:00 2001 From: muharem Date: Fri, 2 Feb 2024 16:49:14 +0800 Subject: [PATCH 02/42] migration for pool account --- Cargo.lock | 1 + substrate/frame/asset-conversion/Cargo.toml | 2 + substrate/frame/asset-conversion/src/lib.rs | 1 + .../frame/asset-conversion/src/migration.rs | 155 ++++++++++++++++++ substrate/frame/assets/src/functions.rs | 25 +++ substrate/frame/assets/src/impl_fungibles.rs | 12 ++ .../src/traits/tokens/fungibles/lifetime.rs | 22 ++- .../src/traits/tokens/fungibles/mod.rs | 2 +- 8 files changed, 218 insertions(+), 2 deletions(-) create mode 100644 substrate/frame/asset-conversion/src/migration.rs diff --git a/Cargo.lock b/Cargo.lock index b1d05c194ebc..ca189a4b75aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9015,6 +9015,7 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "log", "pallet-assets", "pallet-balances", "parity-scale-codec", diff --git a/substrate/frame/asset-conversion/Cargo.toml b/substrate/frame/asset-conversion/Cargo.toml index 1f2db14dac2d..09cc6a115ddc 100644 --- a/substrate/frame/asset-conversion/Cargo.toml +++ b/substrate/frame/asset-conversion/Cargo.toml @@ -17,6 +17,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +log = { version = "0.4.20", default-features = false } frame-support = { path = "../support", default-features = false } frame-system = { path = "../system", default-features = false } frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true } @@ -40,6 +41,7 @@ std = [ "frame-benchmarking?/std", "frame-support/std", "frame-system/std", + "log/std", "pallet-assets/std", "pallet-balances/std", "primitive-types/std", diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index f0695678fbdd..cfdede967b91 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -56,6 +56,7 @@ #[cfg(feature = "runtime-benchmarks")] mod benchmarking; +pub mod migration; #[cfg(test)] mod mock; mod swap; diff --git a/substrate/frame/asset-conversion/src/migration.rs b/substrate/frame/asset-conversion/src/migration.rs new file mode 100644 index 000000000000..7b16022a1ca6 --- /dev/null +++ b/substrate/frame/asset-conversion/src/migration.rs @@ -0,0 +1,155 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Storage migrations. + +use super::*; +use codec::{Decode, Encode}; +use frame_support::{traits::OnRuntimeUpgrade, weights::Weight}; +use log; +#[cfg(feature = "try-runtime")] +use sp_runtime::TryRuntimeError; +use sp_std::marker::PhantomData; + +const LOG_TARGET: &'static str = "runtime::asset-conversion::migration"; + +/// Module providing migration functionality for updating account ids when the type deriving a +/// pool's account id from pool id has changed. +pub mod new_pool_account_id { + use super::*; + use frame_support::{ + traits::{fungibles::ResetTeam, tokens::Preservation}, + Parameter, + }; + use sp_runtime::traits::TryConvert; + + /// Type facilitating the migration of existing pools to new account ids when the type deriving + /// a pool's account id from pool id has changed. + pub struct Migrate(PhantomData<(T, C, A)>); + impl OnRuntimeUpgrade for Migrate + where + A: Parameter, + T: Config, + T::PoolAssets: ResetTeam, + C: for<'a> TryConvert<&'a T::PoolId, T::AccountId>, + { + fn on_runtime_upgrade() -> Weight { + // TODO calculate actual weight + let weight = Weight::zero(); + for (pool_id, pool_info) in Pools::::iter() { + let (account_id, new_account_id) = + match (C::try_convert(&pool_id), T::PoolLocator::address(&pool_id)) { + (Ok(a), Ok(b)) if a != b => (a, b), + _ => continue, + }; + + let (asset1, asset2) = pool_id; + let balance1 = T::Assets::balance(asset1.clone(), &account_id); + if let Err(e) = T::Assets::transfer( + asset1.clone(), + &account_id, + &new_account_id, + balance1, + Preservation::Expendable, + ) { + log::error!( + target: LOG_TARGET, + "transfer all, of `{:?}` from `{}` to `{}` failed with error `{:?}`", + asset1, + account_id, + new_account_id, + e, + ); + continue; + } + + let balance2 = T::Assets::balance(asset2.clone(), &account_id); + if let Err(e) = T::Assets::transfer( + asset2.clone(), + &account_id, + &new_account_id, + balance2, + Preservation::Expendable, + ) { + log::error!( + target: LOG_TARGET, + "transfer all, of `{:?}` from `{}` to `{}` failed with error `{:?}`", + asset2, + account_id, + new_account_id, + e, + ); + let _ = T::Assets::transfer( + asset1, + &new_account_id, + &account_id, + balance1, + Preservation::Expendable, + ); + continue; + } + + if let Err(e) = T::PoolAssets::reset_team( + pool_info.lp_token.clone(), + new_account_id.clone(), + new_account_id.clone(), + new_account_id.clone(), + new_account_id, + ) { + log::error!( + target: LOG_TARGET, + "team reset for asset `{:?}` failed with error `{:?}`", + pool_info.lp_token, + e, + ); + } + } + weight + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, TryRuntimeError> { + let mut expected: Vec<(T::PoolId, ::Balance, ::Balance)> = + vec![]; + for (pool_id, _) in Pools::::iter() { + let account_id = C::try_convert(&pool_id) + .expect("pool ids must be convertible with old account id conversion type"); + let (asset1, asset2) = pool_id; + let balance1 = T::Assets::total_balance(asset1.clone(), &account_id); + let balance2 = T::Assets::total_balance(asset2.clone(), &account_id); + expected.push(((asset1, asset2), balance1, balance2)); + } + Ok(expected.encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), TryRuntimeError> { + let expected: Vec<(T::PoolId, T::Balance, T::Balance)> = Decode::decode( + &mut state.as_slice(), + ) + .expect("the state parameter should be something that was generated by pre_upgrade"); + for (pool_id, balance1, balance2) in expected { + let new_account_id = T::PoolLocator::address(&pool_id) + .expect("pool ids must be convertible with new account id conversion type"); + let (asset1, asset2) = pool_id; + assert_eq!(balance1, T::Assets::total_balance(asset1, &new_account_id)); + assert_eq!(balance2, T::Assets::total_balance(asset2, &new_account_id)); + } + Ok(()) + } + } +} diff --git a/substrate/frame/assets/src/functions.rs b/substrate/frame/assets/src/functions.rs index 8791aaa736b3..8ba42c6d64f6 100644 --- a/substrate/frame/assets/src/functions.rs +++ b/substrate/frame/assets/src/functions.rs @@ -1013,4 +1013,29 @@ impl, I: 'static> Pallet { }) .collect::>() } + + /// Reset the team for the asset with the given `id`. + /// + /// ### Parameters + /// + /// - `id`: The identifier of the asset for which the team is being reset. + /// - `owner`: The new `owner` account for the asset. + /// - `admin`: The new `admin` account for the asset. + /// - `issuer`: The new `issuer` account for the asset. + /// - `freezer`: The new `freezer` account for the asset. + pub(crate) fn do_reset_team( + id: T::AssetId, + owner: T::AccountId, + admin: T::AccountId, + issuer: T::AccountId, + freezer: T::AccountId, + ) -> DispatchResult { + let mut d = Asset::::get(&id).ok_or(Error::::Unknown)?; + d.owner = owner; + d.admin = admin; + d.issuer = issuer; + d.freezer = freezer; + Asset::::insert(&id, d); + Ok(()) + } } diff --git a/substrate/frame/assets/src/impl_fungibles.rs b/substrate/frame/assets/src/impl_fungibles.rs index 123abeba8283..98a68f4c7d63 100644 --- a/substrate/frame/assets/src/impl_fungibles.rs +++ b/substrate/frame/assets/src/impl_fungibles.rs @@ -308,3 +308,15 @@ impl, I: 'static> fungibles::InspectEnumerable for Pa Asset::::iter_keys() } } + +impl, I: 'static> fungibles::ResetTeam for Pallet { + fn reset_team( + id: T::AssetId, + owner: T::AccountId, + admin: T::AccountId, + issuer: T::AccountId, + freezer: T::AccountId, + ) -> DispatchResult { + Self::do_reset_team(id, owner, admin, issuer, freezer) + } +} diff --git a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs index 0e195a52318b..7be7808809ce 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs @@ -15,7 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! Traits for creating and destroying assets. +//! Traits for creating, editing and destroying assets. use sp_runtime::{DispatchError, DispatchResult}; @@ -32,6 +32,26 @@ pub trait Create: Inspect { ) -> DispatchResult; } +/// Trait for resetting the team configuration of an existing fungible asset. +pub trait ResetTeam: Inspect { + /// Reset the team for the asset with the given `id`. + /// + /// ### Parameters + /// + /// - `id`: The identifier of the asset for which the team is being reset. + /// - `owner`: The new `owner` account for the asset. + /// - `admin`: The new `admin` account for the asset. + /// - `issuer`: The new `issuer` account for the asset. + /// - `freezer`: The new `freezer` account for the asset. + fn reset_team( + id: Self::AssetId, + owner: AccountId, + admin: AccountId, + issuer: AccountId, + freezer: AccountId, + ) -> DispatchResult; +} + /// Trait for providing the ability to destroy existing fungible assets. pub trait Destroy: Inspect { /// Start the destruction an existing fungible asset. diff --git a/substrate/frame/support/src/traits/tokens/fungibles/mod.rs b/substrate/frame/support/src/traits/tokens/fungibles/mod.rs index 1db0706ba4fd..ff59b0aadf9f 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/mod.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/mod.rs @@ -35,7 +35,7 @@ pub use hold::{ Unbalanced as UnbalancedHold, }; pub use imbalance::{Credit, Debt, HandleImbalanceDrop, Imbalance}; -pub use lifetime::{Create, Destroy}; +pub use lifetime::{Create, Destroy, ResetTeam}; pub use regular::{ Balanced, DecreaseIssuance, Dust, IncreaseIssuance, Inspect, Mutate, Unbalanced, }; From 1e2a9252bddde93ecdad6a6a10ac9b0b4c454981 Mon Sep 17 00:00:00 2001 From: muharem Date: Wed, 7 Feb 2024 16:57:50 +0800 Subject: [PATCH 03/42] refund trait and impl --- substrate/frame/assets/src/functions.rs | 11 ++++++++--- substrate/frame/assets/src/impl_fungibles.rs | 12 ++++++++++++ substrate/frame/assets/src/lib.rs | 2 +- .../support/src/traits/tokens/fungibles/lifetime.rs | 12 ++++++++++-- .../frame/support/src/traits/tokens/fungibles/mod.rs | 2 +- 5 files changed, 32 insertions(+), 7 deletions(-) diff --git a/substrate/frame/assets/src/functions.rs b/substrate/frame/assets/src/functions.rs index 8ba42c6d64f6..ddedca7a3b24 100644 --- a/substrate/frame/assets/src/functions.rs +++ b/substrate/frame/assets/src/functions.rs @@ -368,11 +368,14 @@ impl, I: 'static> Pallet { Ok(()) } - /// Returns a `DepositFrom` of an account only if balance is zero. + /// Refunds the DepositFrom of an account only if its balance is zero. + /// + /// If the `maybe_check_caller` parameter is specified, it must match the account that provided + /// the deposit or must be the admin of the asset. pub(super) fn do_refund_other( id: T::AssetId, who: &T::AccountId, - caller: &T::AccountId, + maybe_check_caller: Option, ) -> DispatchResult { let mut account = Account::::get(&id, &who).ok_or(Error::::NoDeposit)?; let (depositor, deposit) = @@ -380,7 +383,9 @@ impl, I: 'static> Pallet { let mut details = Asset::::get(&id).ok_or(Error::::Unknown)?; ensure!(details.status == AssetStatus::Live, Error::::AssetNotLive); ensure!(!account.status.is_frozen(), Error::::Frozen); - ensure!(caller == &depositor || caller == &details.admin, Error::::NoPermission); + if let Some(caller) = maybe_check_caller { + ensure!(caller == depositor || caller == details.admin, Error::::NoPermission); + } ensure!(account.balance.is_zero(), Error::::WouldBurn); T::Currency::unreserve(&depositor, deposit); diff --git a/substrate/frame/assets/src/impl_fungibles.rs b/substrate/frame/assets/src/impl_fungibles.rs index 98a68f4c7d63..97a60678418a 100644 --- a/substrate/frame/assets/src/impl_fungibles.rs +++ b/substrate/frame/assets/src/impl_fungibles.rs @@ -320,3 +320,15 @@ impl, I: 'static> fungibles::ResetTeam for Pallet, I: 'static> fungibles::Refund for Pallet { + type AssetId = T::AssetId; + fn refund(id: Self::AssetId, who: T::AccountId) -> DispatchResult { + use ExistenceReason::*; + match Account::::get(&id, &who).ok_or(Error::::NoDeposit)?.reason { + DepositHeld(..) => Self::do_refund(id, who, false), + DepositFrom(..) => Self::do_refund_other(id, &who, None), + _ => Err(Error::::NoDeposit.into()), + } + } +} diff --git a/substrate/frame/assets/src/lib.rs b/substrate/frame/assets/src/lib.rs index cafe7bb1a3b5..1186c946f863 100644 --- a/substrate/frame/assets/src/lib.rs +++ b/substrate/frame/assets/src/lib.rs @@ -1593,7 +1593,7 @@ pub mod pallet { let origin = ensure_signed(origin)?; let who = T::Lookup::lookup(who)?; let id: T::AssetId = id.into(); - Self::do_refund_other(id, &who, &origin) + Self::do_refund_other(id, &who, Some(origin)) } /// Disallow further unprivileged transfers of an asset `id` to and from an account `who`. diff --git a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs index 7be7808809ce..e2560b8e9622 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs @@ -17,9 +17,9 @@ //! Traits for creating, editing and destroying assets. -use sp_runtime::{DispatchError, DispatchResult}; - use super::Inspect; +use crate::traits::tokens::AssetId; +use sp_runtime::{DispatchError, DispatchResult}; /// Trait for providing the ability to create new fungible assets. pub trait Create: Inspect { @@ -52,6 +52,14 @@ pub trait ResetTeam: Inspect { ) -> DispatchResult; } +/// Trait for refunding the deposit of a target asset account. +pub trait Refund { + /// Means of identifying one asset class from another. + type AssetId: AssetId; + /// Return the deposit (if any) of a target asset account. + fn refund(id: Self::AssetId, who: AccountId) -> DispatchResult; +} + /// Trait for providing the ability to destroy existing fungible assets. pub trait Destroy: Inspect { /// Start the destruction an existing fungible asset. diff --git a/substrate/frame/support/src/traits/tokens/fungibles/mod.rs b/substrate/frame/support/src/traits/tokens/fungibles/mod.rs index ff59b0aadf9f..a75a5101497a 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/mod.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/mod.rs @@ -35,7 +35,7 @@ pub use hold::{ Unbalanced as UnbalancedHold, }; pub use imbalance::{Credit, Debt, HandleImbalanceDrop, Imbalance}; -pub use lifetime::{Create, Destroy, ResetTeam}; +pub use lifetime::{Create, Destroy, Refund, ResetTeam}; pub use regular::{ Balanced, DecreaseIssuance, Dust, IncreaseIssuance, Inspect, Mutate, Unbalanced, }; From a45b2980bf873063917836c27b17bbb1e959ddf1 Mon Sep 17 00:00:00 2001 From: muharem Date: Wed, 7 Feb 2024 17:00:00 +0800 Subject: [PATCH 04/42] drop super trait for reset team trait --- substrate/frame/assets/src/impl_fungibles.rs | 1 + .../frame/support/src/traits/tokens/fungibles/lifetime.rs | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/substrate/frame/assets/src/impl_fungibles.rs b/substrate/frame/assets/src/impl_fungibles.rs index 97a60678418a..ceb1acbd37c2 100644 --- a/substrate/frame/assets/src/impl_fungibles.rs +++ b/substrate/frame/assets/src/impl_fungibles.rs @@ -310,6 +310,7 @@ impl, I: 'static> fungibles::InspectEnumerable for Pa } impl, I: 'static> fungibles::ResetTeam for Pallet { + type AssetId = T::AssetId; fn reset_team( id: T::AssetId, owner: T::AccountId, diff --git a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs index e2560b8e9622..d404bfd5d0aa 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs @@ -33,7 +33,9 @@ pub trait Create: Inspect { } /// Trait for resetting the team configuration of an existing fungible asset. -pub trait ResetTeam: Inspect { +pub trait ResetTeam { + /// Means of identifying one asset class from another. + type AssetId: AssetId; /// Reset the team for the asset with the given `id`. /// /// ### Parameters From d8f7b4ef2e2584d001e695cb135d52a7958623e1 Mon Sep 17 00:00:00 2001 From: muharem Date: Thu, 8 Feb 2024 11:14:12 +0800 Subject: [PATCH 05/42] account id types --- substrate/frame/asset-conversion/src/types.rs | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/substrate/frame/asset-conversion/src/types.rs b/substrate/frame/asset-conversion/src/types.rs index 7e25db4eca2f..b34a01aaccad 100644 --- a/substrate/frame/asset-conversion/src/types.rs +++ b/substrate/frame/asset-conversion/src/types.rs @@ -138,16 +138,28 @@ where } /// `PoolId` to `AccountId` conversion. -pub struct AccountIdConverter(PhantomData<(GetPalletId, PoolId)>); -impl TryConvert<&PoolId, AccountId> - for AccountIdConverter +pub struct AccountIdConverter(PhantomData<(Seed, PoolId)>); +impl TryConvert<&PoolId, AccountId> for AccountIdConverter where PoolId: Encode, AccountId: Decode, - GetPalletId: Get, + Seed: Get, { fn try_convert(id: &PoolId) -> Result { - let encoded = sp_io::hashing::blake2_256(&Encode::encode(&(GetPalletId::get(), id))[..]); + let encoded = sp_io::hashing::blake2_256(&Encode::encode(&(Seed::get(), id))[..]); + Decode::decode(&mut TrailingZeroInput::new(encoded.as_ref())).map_err(|_| id) + } +} + +/// `PoolId` to `AccountId` conversion without [`PalledId`] seed. +pub struct AccountIdConverterNoSeed(PhantomData); +impl TryConvert<&PoolId, AccountId> for AccountIdConverterNoSeed +where + PoolId: Encode, + AccountId: Decode, +{ + fn try_convert(id: &PoolId) -> Result { + let encoded = sp_io::hashing::blake2_256(&Encode::encode(id)[..]); Decode::decode(&mut TrailingZeroInput::new(encoded.as_ref())).map_err(|_| id) } } From 1d30b89d796b1070ee1fb446c92b2b3b9d4f0ee5 Mon Sep 17 00:00:00 2001 From: muharem Date: Thu, 8 Feb 2024 11:14:54 +0800 Subject: [PATCH 06/42] fungibles --- substrate/frame/assets/src/impl_fungibles.rs | 18 ++++++++--- .../src/traits/tokens/fungible/union_of.rs | 25 +++++++++++++++ .../src/traits/tokens/fungibles/lifetime.rs | 6 +++- .../src/traits/tokens/fungibles/union_of.rs | 32 +++++++++++++++++++ 4 files changed, 75 insertions(+), 6 deletions(-) diff --git a/substrate/frame/assets/src/impl_fungibles.rs b/substrate/frame/assets/src/impl_fungibles.rs index ceb1acbd37c2..24a45376a687 100644 --- a/substrate/frame/assets/src/impl_fungibles.rs +++ b/substrate/frame/assets/src/impl_fungibles.rs @@ -324,12 +324,20 @@ impl, I: 'static> fungibles::ResetTeam for Pallet, I: 'static> fungibles::Refund for Pallet { type AssetId = T::AssetId; - fn refund(id: Self::AssetId, who: T::AccountId) -> DispatchResult { + type Balance = DepositBalanceOf; + fn deposit(id: Self::AssetId, who: T::AccountId) -> Option<(T::AccountId, Self::Balance)> { use ExistenceReason::*; - match Account::::get(&id, &who).ok_or(Error::::NoDeposit)?.reason { - DepositHeld(..) => Self::do_refund(id, who, false), - DepositFrom(..) => Self::do_refund_other(id, &who, None), - _ => Err(Error::::NoDeposit.into()), + match Account::::get(&id, &who).ok_or(Error::::NoDeposit).ok()?.reason { + DepositHeld(b) => Some((who, b)), + DepositFrom(d, b) => Some((d, b)), + _ => None, + } + } + fn refund(id: Self::AssetId, who: T::AccountId) -> DispatchResult { + match Self::deposit(id.clone(), who.clone()) { + Some((d, _)) if d == who => Self::do_refund(id, who, false), + Some(..) => Self::do_refund_other(id, &who, None), + None => Err(Error::::NoDeposit.into()), } } } diff --git a/substrate/frame/support/src/traits/tokens/fungible/union_of.rs b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs index 33711d7a16cc..48fcbf1142e0 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/union_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs @@ -923,3 +923,28 @@ impl< } } } + +impl< + Left: fungible::Inspect, + Right: fungibles::Inspect + fungibles::Refund, + Criterion: Convert>::AssetId>>, + AssetKind: AssetId, + AccountId, + > fungibles::Refund for UnionOf +{ + type AssetId = AssetKind; + type Balance = >::Balance; + + fn deposit(asset: AssetKind, who: AccountId) -> Option<(AccountId, Self::Balance)> { + match Criterion::convert(asset) { + Left(()) => None, + Right(a) => >::deposit(a, who), + } + } + fn refund(asset: AssetKind, who: AccountId) -> DispatchResult { + match Criterion::convert(asset) { + Left(()) => Err(DispatchError::Unavailable), + Right(a) => >::refund(a, who), + } + } +} diff --git a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs index d404bfd5d0aa..e5d98b2eb156 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs @@ -18,7 +18,7 @@ //! Traits for creating, editing and destroying assets. use super::Inspect; -use crate::traits::tokens::AssetId; +use crate::traits::tokens::{AssetId, Balance}; use sp_runtime::{DispatchError, DispatchResult}; /// Trait for providing the ability to create new fungible assets. @@ -58,6 +58,10 @@ pub trait ResetTeam { pub trait Refund { /// Means of identifying one asset class from another. type AssetId: AssetId; + /// Scalar type for representing balance of an account. + type Balance: Balance; + /// Returns the amount of account deposit and depositor address, if any. + fn deposit(id: Self::AssetId, who: AccountId) -> Option<(AccountId, Self::Balance)>; /// Return the deposit (if any) of a target asset account. fn refund(id: Self::AssetId, who: AccountId) -> DispatchResult; } diff --git a/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs b/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs index 9d2a783df2a4..8be1348c90b8 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs @@ -902,3 +902,35 @@ impl< } } } + +impl< + Left: fungibles::Inspect + fungibles::Refund, + Right: fungibles::Inspect + + fungibles::Refund>::Balance>, + Criterion: Convert< + AssetKind, + Either< + >::AssetId, + >::AssetId, + >, + >, + AssetKind: AssetId, + AccountId, + > fungibles::Refund for UnionOf +{ + type AssetId = AssetKind; + type Balance = >::Balance; + + fn deposit(asset: AssetKind, who: AccountId) -> Option<(AccountId, Self::Balance)> { + match Criterion::convert(asset) { + Left(a) => >::deposit(a, who), + Right(a) => >::deposit(a, who), + } + } + fn refund(asset: AssetKind, who: AccountId) -> DispatchResult { + match Criterion::convert(asset) { + Left(a) => >::refund(a, who), + Right(a) => >::refund(a, who), + } + } +} From cb3b79d1d004942ab5558fba03395a3ef0eaf449 Mon Sep 17 00:00:00 2001 From: muharem Date: Thu, 8 Feb 2024 11:15:15 +0800 Subject: [PATCH 07/42] migration --- .../frame/asset-conversion/src/migration.rs | 69 ++++++++++++++----- 1 file changed, 53 insertions(+), 16 deletions(-) diff --git a/substrate/frame/asset-conversion/src/migration.rs b/substrate/frame/asset-conversion/src/migration.rs index 7b16022a1ca6..0ee7cc759358 100644 --- a/substrate/frame/asset-conversion/src/migration.rs +++ b/substrate/frame/asset-conversion/src/migration.rs @@ -18,7 +18,6 @@ //! Storage migrations. use super::*; -use codec::{Decode, Encode}; use frame_support::{traits::OnRuntimeUpgrade, weights::Weight}; use log; #[cfg(feature = "try-runtime")] @@ -31,28 +30,42 @@ const LOG_TARGET: &'static str = "runtime::asset-conversion::migration"; /// pool's account id from pool id has changed. pub mod new_pool_account_id { use super::*; - use frame_support::{ - traits::{fungibles::ResetTeam, tokens::Preservation}, - Parameter, + use frame_support::traits::{ + fungibles::{Refund as RefundT, ResetTeam as ResetTeamT}, + tokens::Preservation, }; - use sp_runtime::traits::TryConvert; /// Type facilitating the migration of existing pools to new account ids when the type deriving /// a pool's account id from pool id has changed. - pub struct Migrate(PhantomData<(T, C, A)>); - impl OnRuntimeUpgrade for Migrate + /// + /// ### Parameters: + /// - `T`: The [`Config`] implementation for the target asset conversion instance with a new + /// account derivation method defined by [`PoolLocator`]. + /// - `OldLocator`: The previously used type for account derivation. + /// - `ResetTeam`: A type used for resetting the team configuration of an LP token. + /// - `Refund`: A type used to perform a refund if the previous pool account holds a deposit. + /// - `WeightPerItem`: A getter returning the weight required for the migration of a single pool + /// account ID. It should include: 2 * weight_of(T::Assets::balance(..)) + 2 * + /// weight_of(T::Assets::transfer(..)) + 2 * weight_of(Refund::deposit(..)) + 2 * + /// weight_of(Refund::refund(..)) + weight_of(ResetTeam::reset_team(..)); + pub struct Migrate( + PhantomData<(T, OldLocator, ResetTeam, Refund, WeightPerItem)>, + ); + impl OnRuntimeUpgrade + for Migrate where - A: Parameter, - T: Config, - T::PoolAssets: ResetTeam, - C: for<'a> TryConvert<&'a T::PoolId, T::AccountId>, + T: Config::AssetKind, ::AssetKind)>, + OldLocator: PoolLocator, + ResetTeam: ResetTeamT, + Refund: RefundT, + WeightPerItem: Get, { fn on_runtime_upgrade() -> Weight { - // TODO calculate actual weight - let weight = Weight::zero(); + let mut weight = Weight::zero(); for (pool_id, pool_info) in Pools::::iter() { + weight.saturating_accrue(WeightPerItem::get()); let (account_id, new_account_id) = - match (C::try_convert(&pool_id), T::PoolLocator::address(&pool_id)) { + match (OldLocator::address(&pool_id), T::PoolLocator::address(&pool_id)) { (Ok(a), Ok(b)) if a != b => (a, b), _ => continue, }; @@ -103,7 +116,31 @@ pub mod new_pool_account_id { continue; } - if let Err(e) = T::PoolAssets::reset_team( + if Refund::deposit(asset1.clone(), account_id.clone()).is_some() { + if let Err(e) = Refund::refund(asset1.clone(), account_id.clone()) { + log::error!( + target: LOG_TARGET, + "refund for asset1 `{:?}` to account `{}` failed with error `{:?}`", + asset1, + account_id, + e, + ); + } + } + + if Refund::deposit(asset2.clone(), account_id.clone()).is_some() { + if let Err(e) = Refund::refund(asset2.clone(), account_id.clone()) { + log::error!( + target: LOG_TARGET, + "refund for asset2 `{:?}` to account `{}` failed with error `{:?}`", + asset2.clone(), + account_id, + e, + ); + } + } + + if let Err(e) = ResetTeam::reset_team( pool_info.lp_token.clone(), new_account_id.clone(), new_account_id.clone(), @@ -126,7 +163,7 @@ pub mod new_pool_account_id { let mut expected: Vec<(T::PoolId, ::Balance, ::Balance)> = vec![]; for (pool_id, _) in Pools::::iter() { - let account_id = C::try_convert(&pool_id) + let account_id = OldLocator::address(&pool_id) .expect("pool ids must be convertible with old account id conversion type"); let (asset1, asset2) = pool_id; let balance1 = T::Assets::total_balance(asset1.clone(), &account_id); From 9f2c71a96e43da59a4d096b9e8a9b0ed71cde974 Mon Sep 17 00:00:00 2001 From: muharem Date: Thu, 8 Feb 2024 11:20:20 +0800 Subject: [PATCH 08/42] setup migration for asset hubs --- .../assets/asset-hub-rococo/src/lib.rs | 36 +++++++++++++++++++ .../assets/asset-hub-westend/src/lib.rs | 34 ++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index d2e7cfa7bf17..1d72dd6fc0d3 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -994,12 +994,48 @@ pub type SignedExtra = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; + +parameter_types! { + pub PerAccountMigrationWeight: Weight = { + // 2 balance + 2 deposit + ::DbWeight::get().reads(5) + .saturating_add( + as pallet_assets::WeightInfo>::transfer() + ).saturating_add( + as pallet_assets::WeightInfo>::transfer() + ).saturating_add( + as pallet_assets::WeightInfo>::refund_other() + ).saturating_add( + as pallet_assets::WeightInfo>::refund_other() + ).saturating_add( // team reset + ::DbWeight::get().reads_writes(1, 1) + ) + }; +} + /// Migrations to apply on runtime upgrade. +#[allow(deprecated)] pub type Migrations = ( pallet_collator_selection::migration::v1::MigrateToV1, InitStorageVersions, // unreleased cumulus_pallet_xcmp_queue::migration::v4::MigrationToV4, + // unreleased + pallet_asset_conversion::migration::new_pool_account_id::Migrate< + Runtime, + pallet_asset_conversion::WithFirstAsset< + TokenLocationV3, + AccountId, + xcm::v3::Location, + pallet_asset_conversion::AccountIdConverterNoSeed<( + xcm::v3::Location, + xcm::v3::Location, + )>, + >, + ::PoolAssets, + ::Assets, + PerAccountMigrationWeight, + >, ); /// Migration to initialize storage versions for pallets added after genesis. diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 8812d3eabd30..dc6cb8927de3 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -939,6 +939,24 @@ pub type SignedExtra = ( pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; +parameter_types! { + pub PerAccountMigrationWeight: Weight = { + // 2 balance + 2 deposit + ::DbWeight::get().reads(5) + .saturating_add( + as pallet_assets::WeightInfo>::transfer() + ).saturating_add( + as pallet_assets::WeightInfo>::transfer() + ).saturating_add( + as pallet_assets::WeightInfo>::refund_other() + ).saturating_add( + as pallet_assets::WeightInfo>::refund_other() + ).saturating_add( // team reset + ::DbWeight::get().reads_writes(1, 1) + ) + }; +} + /// Migrations to apply on runtime upgrade. pub type Migrations = ( // v9420 @@ -953,6 +971,22 @@ pub type Migrations = ( DeleteUndecodableStorage, // unreleased cumulus_pallet_xcmp_queue::migration::v4::MigrationToV4, + // unreleased + pallet_asset_conversion::migration::new_pool_account_id::Migrate< + Runtime, + pallet_asset_conversion::WithFirstAsset< + WestendLocationV3, + AccountId, + xcm::v3::Location, + pallet_asset_conversion::AccountIdConverterNoSeed<( + xcm::v3::Location, + xcm::v3::Location, + )>, + >, + ::PoolAssets, + ::Assets, + PerAccountMigrationWeight, + >, ); /// Asset Hub Westend has some undecodable storage, delete it. From f9a0edc127055b54a4fbca97d149da2c21285c36 Mon Sep 17 00:00:00 2001 From: muharem Date: Thu, 8 Feb 2024 11:49:33 +0800 Subject: [PATCH 09/42] doc fixes --- substrate/frame/asset-conversion/src/types.rs | 2 +- substrate/frame/assets/src/functions.rs | 3 +-- .../frame/support/src/traits/tokens/fungibles/lifetime.rs | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/substrate/frame/asset-conversion/src/types.rs b/substrate/frame/asset-conversion/src/types.rs index b34a01aaccad..4d28ecc01bd8 100644 --- a/substrate/frame/asset-conversion/src/types.rs +++ b/substrate/frame/asset-conversion/src/types.rs @@ -151,7 +151,7 @@ where } } -/// `PoolId` to `AccountId` conversion without [`PalledId`] seed. +/// `PoolId` to `AccountId` conversion without an addition arguments to the seed. pub struct AccountIdConverterNoSeed(PhantomData); impl TryConvert<&PoolId, AccountId> for AccountIdConverterNoSeed where diff --git a/substrate/frame/assets/src/functions.rs b/substrate/frame/assets/src/functions.rs index ddedca7a3b24..623a8558e176 100644 --- a/substrate/frame/assets/src/functions.rs +++ b/substrate/frame/assets/src/functions.rs @@ -368,7 +368,7 @@ impl, I: 'static> Pallet { Ok(()) } - /// Refunds the DepositFrom of an account only if its balance is zero. + /// Refunds the `DepositFrom` of an account only if its balance is zero. /// /// If the `maybe_check_caller` parameter is specified, it must match the account that provided /// the deposit or must be the admin of the asset. @@ -1022,7 +1022,6 @@ impl, I: 'static> Pallet { /// Reset the team for the asset with the given `id`. /// /// ### Parameters - /// /// - `id`: The identifier of the asset for which the team is being reset. /// - `owner`: The new `owner` account for the asset. /// - `admin`: The new `admin` account for the asset. diff --git a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs index e5d98b2eb156..68de17ac7360 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs @@ -39,7 +39,6 @@ pub trait ResetTeam { /// Reset the team for the asset with the given `id`. /// /// ### Parameters - /// /// - `id`: The identifier of the asset for which the team is being reset. /// - `owner`: The new `owner` account for the asset. /// - `admin`: The new `admin` account for the asset. From 6fce4bf6ca7989d5ff83fe581dc6d36e0af19708 Mon Sep 17 00:00:00 2001 From: muharem Date: Thu, 8 Feb 2024 11:56:58 +0800 Subject: [PATCH 10/42] prdoc --- prdoc/pr_3250.prdoc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 prdoc/pr_3250.prdoc diff --git a/prdoc/pr_3250.prdoc b/prdoc/pr_3250.prdoc new file mode 100644 index 000000000000..023b723d21b4 --- /dev/null +++ b/prdoc/pr_3250.prdoc @@ -0,0 +1,14 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "Asset Conversion: Pool Account ID derivation with additional Pallet ID seed" + +doc: + - audience: Runtime Dev + description: | + Introduce PalletId as an additional seed parameter for pool's account id derivation. + The PR also introduces the fungibles::lifetime::ResetTeam and fungible::lifetime::Refund traits, + which facilitate the migration of pools to the new account IDs. + +crates: + - name: pallet-asset-conversion From 2321031778ad465f3624ebd76e1ad34d4bafd386 Mon Sep 17 00:00:00 2001 From: muharem Date: Thu, 8 Feb 2024 12:07:09 +0800 Subject: [PATCH 11/42] try runtime imports --- substrate/frame/asset-conversion/src/migration.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/substrate/frame/asset-conversion/src/migration.rs b/substrate/frame/asset-conversion/src/migration.rs index 0ee7cc759358..5bda826a3d7d 100644 --- a/substrate/frame/asset-conversion/src/migration.rs +++ b/substrate/frame/asset-conversion/src/migration.rs @@ -18,6 +18,8 @@ //! Storage migrations. use super::*; +#[cfg(feature = "try-runtime")] +use codec::{Decode, Encode}; use frame_support::{traits::OnRuntimeUpgrade, weights::Weight}; use log; #[cfg(feature = "try-runtime")] From 3d3e5b3dcf46a6c3b69532b23ca8ba8cfb0895a7 Mon Sep 17 00:00:00 2001 From: muharem Date: Thu, 8 Feb 2024 13:23:16 +0800 Subject: [PATCH 12/42] change account id format for logs --- substrate/frame/asset-conversion/src/migration.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/substrate/frame/asset-conversion/src/migration.rs b/substrate/frame/asset-conversion/src/migration.rs index 5bda826a3d7d..b845e3b6b6c1 100644 --- a/substrate/frame/asset-conversion/src/migration.rs +++ b/substrate/frame/asset-conversion/src/migration.rs @@ -83,7 +83,7 @@ pub mod new_pool_account_id { ) { log::error!( target: LOG_TARGET, - "transfer all, of `{:?}` from `{}` to `{}` failed with error `{:?}`", + "transfer all, of `{:?}` from `{:?}` to `{:?}` failed with error `{:?}`", asset1, account_id, new_account_id, @@ -102,7 +102,7 @@ pub mod new_pool_account_id { ) { log::error!( target: LOG_TARGET, - "transfer all, of `{:?}` from `{}` to `{}` failed with error `{:?}`", + "transfer all, of `{:?}` from `{:?}` to `{:?}` failed with error `{:?}`", asset2, account_id, new_account_id, @@ -122,7 +122,7 @@ pub mod new_pool_account_id { if let Err(e) = Refund::refund(asset1.clone(), account_id.clone()) { log::error!( target: LOG_TARGET, - "refund for asset1 `{:?}` to account `{}` failed with error `{:?}`", + "refund for asset1 `{:?}` to account `{:?}` failed with error `{:?}`", asset1, account_id, e, @@ -134,7 +134,7 @@ pub mod new_pool_account_id { if let Err(e) = Refund::refund(asset2.clone(), account_id.clone()) { log::error!( target: LOG_TARGET, - "refund for asset2 `{:?}` to account `{}` failed with error `{:?}`", + "refund for asset2 `{:?}` to account `{:?}` failed with error `{:?}`", asset2.clone(), account_id, e, From ff19ff1c1f81998f6c25a3eb49aed7e6ed65bf09 Mon Sep 17 00:00:00 2001 From: muharem Date: Thu, 8 Feb 2024 14:32:53 +0800 Subject: [PATCH 13/42] import --- substrate/frame/asset-conversion/src/migration.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/substrate/frame/asset-conversion/src/migration.rs b/substrate/frame/asset-conversion/src/migration.rs index b845e3b6b6c1..51d638c2d549 100644 --- a/substrate/frame/asset-conversion/src/migration.rs +++ b/substrate/frame/asset-conversion/src/migration.rs @@ -25,6 +25,8 @@ use log; #[cfg(feature = "try-runtime")] use sp_runtime::TryRuntimeError; use sp_std::marker::PhantomData; +#[cfg(feature = "try-runtime")] +use sp_std::vec; const LOG_TARGET: &'static str = "runtime::asset-conversion::migration"; From 4dd4334494f61d5d3ef7dc740ae6dd743b20eb09 Mon Sep 17 00:00:00 2001 From: muharem Date: Thu, 8 Feb 2024 15:31:28 +0800 Subject: [PATCH 14/42] rename deposit fn to deposit_held --- substrate/frame/asset-conversion/src/migration.rs | 6 +++--- substrate/frame/assets/src/impl_fungibles.rs | 4 ++-- .../frame/support/src/traits/tokens/fungible/union_of.rs | 4 ++-- .../frame/support/src/traits/tokens/fungibles/lifetime.rs | 2 +- .../frame/support/src/traits/tokens/fungibles/union_of.rs | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/substrate/frame/asset-conversion/src/migration.rs b/substrate/frame/asset-conversion/src/migration.rs index 51d638c2d549..657430dbccf3 100644 --- a/substrate/frame/asset-conversion/src/migration.rs +++ b/substrate/frame/asset-conversion/src/migration.rs @@ -50,7 +50,7 @@ pub mod new_pool_account_id { /// - `Refund`: A type used to perform a refund if the previous pool account holds a deposit. /// - `WeightPerItem`: A getter returning the weight required for the migration of a single pool /// account ID. It should include: 2 * weight_of(T::Assets::balance(..)) + 2 * - /// weight_of(T::Assets::transfer(..)) + 2 * weight_of(Refund::deposit(..)) + 2 * + /// weight_of(T::Assets::transfer(..)) + 2 * weight_of(Refund::deposit_held(..)) + 2 * /// weight_of(Refund::refund(..)) + weight_of(ResetTeam::reset_team(..)); pub struct Migrate( PhantomData<(T, OldLocator, ResetTeam, Refund, WeightPerItem)>, @@ -120,7 +120,7 @@ pub mod new_pool_account_id { continue; } - if Refund::deposit(asset1.clone(), account_id.clone()).is_some() { + if Refund::deposit_held(asset1.clone(), account_id.clone()).is_some() { if let Err(e) = Refund::refund(asset1.clone(), account_id.clone()) { log::error!( target: LOG_TARGET, @@ -132,7 +132,7 @@ pub mod new_pool_account_id { } } - if Refund::deposit(asset2.clone(), account_id.clone()).is_some() { + if Refund::deposit_held(asset2.clone(), account_id.clone()).is_some() { if let Err(e) = Refund::refund(asset2.clone(), account_id.clone()) { log::error!( target: LOG_TARGET, diff --git a/substrate/frame/assets/src/impl_fungibles.rs b/substrate/frame/assets/src/impl_fungibles.rs index 24a45376a687..30a90aca8d07 100644 --- a/substrate/frame/assets/src/impl_fungibles.rs +++ b/substrate/frame/assets/src/impl_fungibles.rs @@ -325,7 +325,7 @@ impl, I: 'static> fungibles::ResetTeam for Pallet, I: 'static> fungibles::Refund for Pallet { type AssetId = T::AssetId; type Balance = DepositBalanceOf; - fn deposit(id: Self::AssetId, who: T::AccountId) -> Option<(T::AccountId, Self::Balance)> { + fn deposit_held(id: Self::AssetId, who: T::AccountId) -> Option<(T::AccountId, Self::Balance)> { use ExistenceReason::*; match Account::::get(&id, &who).ok_or(Error::::NoDeposit).ok()?.reason { DepositHeld(b) => Some((who, b)), @@ -334,7 +334,7 @@ impl, I: 'static> fungibles::Refund for Pallet } } fn refund(id: Self::AssetId, who: T::AccountId) -> DispatchResult { - match Self::deposit(id.clone(), who.clone()) { + match Self::deposit_held(id.clone(), who.clone()) { Some((d, _)) if d == who => Self::do_refund(id, who, false), Some(..) => Self::do_refund_other(id, &who, None), None => Err(Error::::NoDeposit.into()), diff --git a/substrate/frame/support/src/traits/tokens/fungible/union_of.rs b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs index 48fcbf1142e0..e9b97b849abf 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/union_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs @@ -935,10 +935,10 @@ impl< type AssetId = AssetKind; type Balance = >::Balance; - fn deposit(asset: AssetKind, who: AccountId) -> Option<(AccountId, Self::Balance)> { + fn deposit_held(asset: AssetKind, who: AccountId) -> Option<(AccountId, Self::Balance)> { match Criterion::convert(asset) { Left(()) => None, - Right(a) => >::deposit(a, who), + Right(a) => >::deposit_held(a, who), } } fn refund(asset: AssetKind, who: AccountId) -> DispatchResult { diff --git a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs index 68de17ac7360..716c970fd32f 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs @@ -60,7 +60,7 @@ pub trait Refund { /// Scalar type for representing balance of an account. type Balance: Balance; /// Returns the amount of account deposit and depositor address, if any. - fn deposit(id: Self::AssetId, who: AccountId) -> Option<(AccountId, Self::Balance)>; + fn deposit_held(id: Self::AssetId, who: AccountId) -> Option<(AccountId, Self::Balance)>; /// Return the deposit (if any) of a target asset account. fn refund(id: Self::AssetId, who: AccountId) -> DispatchResult; } diff --git a/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs b/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs index 8be1348c90b8..841830974a03 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs @@ -921,10 +921,10 @@ impl< type AssetId = AssetKind; type Balance = >::Balance; - fn deposit(asset: AssetKind, who: AccountId) -> Option<(AccountId, Self::Balance)> { + fn deposit_held(asset: AssetKind, who: AccountId) -> Option<(AccountId, Self::Balance)> { match Criterion::convert(asset) { - Left(a) => >::deposit(a, who), - Right(a) => >::deposit(a, who), + Left(a) => >::deposit_held(a, who), + Right(a) => >::deposit_held(a, who), } } fn refund(asset: AssetKind, who: AccountId) -> DispatchResult { From 3537f90ebdd9a757390636154b57840f93775ef8 Mon Sep 17 00:00:00 2001 From: muharem Date: Fri, 9 Feb 2024 13:42:33 +0800 Subject: [PATCH 15/42] migration adjustments --- .../assets/asset-hub-rococo/src/lib.rs | 2 + .../assets/asset-hub-westend/src/lib.rs | 2 + .../frame/asset-conversion/src/migration.rs | 342 ++++++++++++++++-- 3 files changed, 321 insertions(+), 25 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 2bed3e29c3c6..38019c9ce7e9 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -1013,6 +1013,8 @@ pub type Migrations = ( >, ::PoolAssets, ::Assets, + ::PoolAssets, + Balances, PerAccountMigrationWeight, >, ); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index ed4cfc24bbc5..d91a846f7046 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -992,6 +992,8 @@ pub type Migrations = ( >, ::PoolAssets, ::Assets, + ::PoolAssets, + Balances, PerAccountMigrationWeight, >, ); diff --git a/substrate/frame/asset-conversion/src/migration.rs b/substrate/frame/asset-conversion/src/migration.rs index 657430dbccf3..2fa44a5ee7e2 100644 --- a/substrate/frame/asset-conversion/src/migration.rs +++ b/substrate/frame/asset-conversion/src/migration.rs @@ -35,8 +35,9 @@ const LOG_TARGET: &'static str = "runtime::asset-conversion::migration"; pub mod new_pool_account_id { use super::*; use frame_support::traits::{ - fungibles::{Refund as RefundT, ResetTeam as ResetTeamT}, - tokens::Preservation, + fungible::Mutate as FungibleMutate, + fungibles::{Inspect, Refund as RefundT, ResetTeam as ResetTeamT}, + tokens::{Fortitude, Precision, Preservation, WithdrawConsequence}, }; /// Type facilitating the migration of existing pools to new account ids when the type deriving @@ -47,26 +48,35 @@ pub mod new_pool_account_id { /// account derivation method defined by [`PoolLocator`]. /// - `OldLocator`: The previously used type for account derivation. /// - `ResetTeam`: A type used for resetting the team configuration of an LP token. - /// - `Refund`: A type used to perform a refund if the previous pool account holds a deposit. + /// - `Refund`: A type used to perform a refund for assets from `T::Assets` registry if the + /// previous pool account holds a deposit. + /// - `PoolRefund`: A type used to perform a refund for assets from `T::PoolAssets` registry if + /// the previous pool account holds a deposit. + /// - `DepositAssets`: asset registry used for deposits for assets from T::Assets` and + /// `T::PoolAssets`. /// - `WeightPerItem`: A getter returning the weight required for the migration of a single pool /// account ID. It should include: 2 * weight_of(T::Assets::balance(..)) + 2 * /// weight_of(T::Assets::transfer(..)) + 2 * weight_of(Refund::deposit_held(..)) + 2 * /// weight_of(Refund::refund(..)) + weight_of(ResetTeam::reset_team(..)); - pub struct Migrate( - PhantomData<(T, OldLocator, ResetTeam, Refund, WeightPerItem)>, + pub struct Migrate( + PhantomData<(T, OldLocator, ResetTeam, Refund, PoolRefund, DepositAssets, WeightPerItem)>, ); - impl OnRuntimeUpgrade - for Migrate + impl + OnRuntimeUpgrade + for Migrate where T: Config::AssetKind, ::AssetKind)>, OldLocator: PoolLocator, ResetTeam: ResetTeamT, - Refund: RefundT, + Refund: RefundT, + PoolRefund: + RefundT, + DepositAssets: FungibleMutate, WeightPerItem: Get, { fn on_runtime_upgrade() -> Weight { let mut weight = Weight::zero(); - for (pool_id, pool_info) in Pools::::iter() { + for (pool_id, info) in Pools::::iter() { weight.saturating_accrue(WeightPerItem::get()); let (account_id, new_account_id) = match (OldLocator::address(&pool_id), T::PoolLocator::address(&pool_id)) { @@ -75,7 +85,173 @@ pub mod new_pool_account_id { }; let (asset1, asset2) = pool_id; + + log::info!( + target: LOG_TARGET, + "migrating an asset pair (`{:?}`, `{:?}`).", + asset1.clone(), + asset2.clone(), + ); + + // assets that must be transferred to the new account id. let balance1 = T::Assets::balance(asset1.clone(), &account_id); + let balance2 = T::Assets::balance(asset2.clone(), &account_id); + let balance3 = T::PoolAssets::balance(info.lp_token.clone(), &account_id); + + // check if it possible to withdraw the assets from old account id. + + let withdraw_result1 = + T::Assets::can_withdraw(asset1.clone(), &account_id, balance1); + if withdraw_result1 != WithdrawConsequence::<_>::Success { + log::error!( + target: LOG_TARGET, + "total balance cannot be withdrawn for asset1 from pair (`{:?}`,`{:?}`), account id `{:?}` with result `{:?}`.", + asset1, + asset2, + account_id, + withdraw_result1, + ); + continue; + } + + let withdraw_result2 = + T::Assets::can_withdraw(asset2.clone(), &account_id, balance2); + if withdraw_result2 != WithdrawConsequence::<_>::Success { + log::error!( + target: LOG_TARGET, + "total balance cannot be withdrawn for asset2 from pair (`{:?}`,`{:?}`), account id `{:?}` with result `{:?}`.", + asset1, + asset2, + account_id, + withdraw_result2, + ); + continue; + } + + let withdraw_result3 = + T::PoolAssets::can_withdraw(info.lp_token.clone(), &account_id, balance3); + if withdraw_result3 != WithdrawConsequence::<_>::Success { + log::error!( + target: LOG_TARGET, + "total balance cannot be withdrawn for lp token `{:?}`, from pair (`{:?}`,`{:?}`), account id `{:?}` with result `{:?}`.", + info.lp_token, + asset1, + asset2, + account_id, + withdraw_result3, + ); + continue; + } + + // check if deposit has to be placed for the new account. + // if deposit required mint a deposit amount to the depositor account to ensure the + // deposit can be provided. after the deposit from the old account will be returned, + // the minted assets will be burned. + + if let Some((d, b)) = Refund::deposit_held(asset1.clone(), account_id.clone()) { + let ed = DepositAssets::minimum_balance(); + if let Err(e) = DepositAssets::mint_into(&d, b + ed) { + log::error!( + target: LOG_TARGET, + "failed to mint deposit for asset1 `{:?}`, into account id `{:?}` with error `{:?}`.", + asset1, + d, + e, + ); + continue; + } + if let Err(e) = T::Assets::touch(asset1.clone(), &new_account_id, &d) { + let burn_res = DepositAssets::burn_from( + &d, + b + ed, + Precision::Exact, + Fortitude::Force, + ); + log::error!( + target: LOG_TARGET, + "failed to touch account `{:?}`, `{:?}`, from pair (`{:?}`,`{:?}`), with error `{:?}` and burn result `{:?}`.", + asset1.clone(), + new_account_id, + asset1, + asset2, + e, + burn_res, + ); + continue; + } + } + + if let Some((d, b)) = Refund::deposit_held(asset2.clone(), account_id.clone()) { + let ed = DepositAssets::minimum_balance(); + if let Err(e) = DepositAssets::mint_into(&d, b + ed) { + log::error!( + target: LOG_TARGET, + "failed to mint deposit for asset2 `{:?}`, into account id `{:?}` with error `{:?}`.", + asset2, + d, + e, + ); + continue; + } + if let Err(e) = T::Assets::touch(asset2.clone(), &new_account_id, &d) { + let burn_res = DepositAssets::burn_from( + &d, + b + ed, + Precision::Exact, + Fortitude::Force, + ); + log::error!( + target: LOG_TARGET, + "failed to touch account `{:?}`, `{:?}`, from pair (`{:?}`,`{:?}`), with error `{:?}` and burn result `{:?}`.", + asset2.clone(), + new_account_id, + asset1, + asset2, + e, + burn_res, + ); + continue; + } + } + + if let Some((d, b)) = + PoolRefund::deposit_held(info.lp_token.clone(), account_id.clone()) + { + let ed = DepositAssets::minimum_balance(); + if let Err(e) = DepositAssets::mint_into(&d, b + ed) { + log::error!( + target: LOG_TARGET, + "failed to mint deposit for lp token `{:?}`, into account id `{:?}` with error `{:?}`.", + info.lp_token.clone(), + d, + e, + ); + continue; + } + if let Err(e) = T::PoolAssets::touch(info.lp_token.clone(), &new_account_id, &d) + { + let burn_res = DepositAssets::burn_from( + &d, + b + ed, + Precision::Exact, + Fortitude::Force, + ); + log::error!( + target: LOG_TARGET, + "failed to touch account `{:?}`, `{:?}`, from pair (`{:?}`,`{:?}`), with error `{:?}` with a burn result `{:?}`.", + info.lp_token, + new_account_id, + asset1, + asset2, + e, + burn_res, + ); + continue; + } + } + + // transfer all pool related assets to the new account. + if let Err(e) = T::Assets::transfer( asset1.clone(), &account_id, @@ -94,7 +270,6 @@ pub mod new_pool_account_id { continue; } - let balance2 = T::Assets::balance(asset2.clone(), &account_id); if let Err(e) = T::Assets::transfer( asset2.clone(), &account_id, @@ -102,25 +277,62 @@ pub mod new_pool_account_id { balance2, Preservation::Expendable, ) { + let transfer_res = T::Assets::transfer( + asset1, + &new_account_id, + &account_id, + balance1, + Preservation::Expendable, + ); log::error!( target: LOG_TARGET, - "transfer all, of `{:?}` from `{:?}` to `{:?}` failed with error `{:?}`", + "transfer all, of `{:?}` from `{:?}` to `{:?}` failed with error `{:?}` with rollback transfer result `{:?}`", asset2, account_id, new_account_id, e, + transfer_res, ); - let _ = T::Assets::transfer( + continue; + } + + if let Err(e) = T::PoolAssets::transfer( + info.lp_token.clone(), + &account_id, + &new_account_id, + balance3, + Preservation::Expendable, + ) { + let transfer_res1 = T::Assets::transfer( asset1, &new_account_id, &account_id, balance1, Preservation::Expendable, ); + let transfer_res2 = T::Assets::transfer( + asset2, + &new_account_id, + &account_id, + balance2, + Preservation::Expendable, + ); + log::error!( + target: LOG_TARGET, + "transfer all, of `{:?}` from `{:?}` to `{:?}` failed with error `{:?}` with rollback transfer result `{:?}` and `{:?}`", + info.lp_token, + account_id, + new_account_id, + e, + transfer_res1, + transfer_res2, + ); continue; } - if Refund::deposit_held(asset1.clone(), account_id.clone()).is_some() { + // refund deposits from old accounts and burn previously minted assets. + + if let Some((d, b)) = Refund::deposit_held(asset1.clone(), account_id.clone()) { if let Err(e) = Refund::refund(asset1.clone(), account_id.clone()) { log::error!( target: LOG_TARGET, @@ -130,9 +342,21 @@ pub mod new_pool_account_id { e, ); } + let ed = DepositAssets::minimum_balance(); + if let Err(e) = + DepositAssets::burn_from(&d, b + ed, Precision::Exact, Fortitude::Force) + { + log::error!( + target: LOG_TARGET, + "failed to burn deposit for asset1 from `{:?}` with error `{:?}`.", + d, + e, + ); + continue; + } } - if Refund::deposit_held(asset2.clone(), account_id.clone()).is_some() { + if let Some((d, b)) = Refund::deposit_held(asset2.clone(), account_id.clone()) { if let Err(e) = Refund::refund(asset2.clone(), account_id.clone()) { log::error!( target: LOG_TARGET, @@ -142,10 +366,48 @@ pub mod new_pool_account_id { e, ); } + let ed = DepositAssets::minimum_balance(); + if let Err(e) = + DepositAssets::burn_from(&d, b + ed, Precision::Exact, Fortitude::Force) + { + log::error!( + target: LOG_TARGET, + "failed to burn deposit for asset2 from `{:?}` with error `{:?}`.", + d, + e, + ); + continue; + } + } + + if let Some((d, b)) = + PoolRefund::deposit_held(info.lp_token.clone(), account_id.clone()) + { + if let Err(e) = PoolRefund::refund(info.lp_token.clone(), account_id.clone()) { + log::error!( + target: LOG_TARGET, + "refund for lp token `{:?}` to account `{:?}` failed with error `{:?}`", + info.lp_token.clone(), + account_id, + e, + ); + } + let ed = DepositAssets::minimum_balance(); + if let Err(e) = + DepositAssets::burn_from(&d, b + ed, Precision::Exact, Fortitude::Force) + { + log::error!( + target: LOG_TARGET, + "failed to burn deposit for lp token from `{:?}` with error `{:?}`.", + d, + e, + ); + continue; + } } if let Err(e) = ResetTeam::reset_team( - pool_info.lp_token.clone(), + info.lp_token.clone(), new_account_id.clone(), new_account_id.clone(), new_account_id.clone(), @@ -154,7 +416,7 @@ pub mod new_pool_account_id { log::error!( target: LOG_TARGET, "team reset for asset `{:?}` failed with error `{:?}`", - pool_info.lp_token, + info.lp_token, e, ); } @@ -164,31 +426,61 @@ pub mod new_pool_account_id { #[cfg(feature = "try-runtime")] fn pre_upgrade() -> Result, TryRuntimeError> { - let mut expected: Vec<(T::PoolId, ::Balance, ::Balance)> = - vec![]; - for (pool_id, _) in Pools::::iter() { + let mut expected: Vec<( + T::PoolId, + // asset1 balance + ::Balance, + // asset2 balance + ::Balance, + // lp token balance + ::Balance, + // total issuance + DepositAssets::Balance, + )> = vec![]; + for (pool_id, info) in Pools::::iter() { let account_id = OldLocator::address(&pool_id) .expect("pool ids must be convertible with old account id conversion type"); let (asset1, asset2) = pool_id; let balance1 = T::Assets::total_balance(asset1.clone(), &account_id); let balance2 = T::Assets::total_balance(asset2.clone(), &account_id); - expected.push(((asset1, asset2), balance1, balance2)); + let balance3 = T::PoolAssets::total_balance(info.lp_token.clone(), &account_id); + let total_issuance = DepositAssets::total_issuance(); + let withdraw_success = WithdrawConsequence::<::Balance>::Success; + if T::Assets::can_withdraw(asset1.clone(), &account_id, balance1) == + withdraw_success && T::Assets::can_withdraw( + asset2.clone(), + &account_id, + balance2, + ) == withdraw_success && + T::PoolAssets::can_withdraw(info.lp_token, &account_id, balance3) == + withdraw_success + { + expected.push(((asset1, asset2), balance1, balance2, balance3, total_issuance)); + } } Ok(expected.encode()) } #[cfg(feature = "try-runtime")] fn post_upgrade(state: Vec) -> Result<(), TryRuntimeError> { - let expected: Vec<(T::PoolId, T::Balance, T::Balance)> = Decode::decode( - &mut state.as_slice(), - ) - .expect("the state parameter should be something that was generated by pre_upgrade"); - for (pool_id, balance1, balance2) in expected { + let expected: Vec<( + T::PoolId, + T::Balance, + T::Balance, + T::Balance, + DepositAssets::Balance, + )> = Decode::decode(&mut state.as_slice()).expect( + "the state parameter should be something that was generated by pre_upgrade", + ); + for (pool_id, balance1, balance2, balance3, total_issuance) in expected { let new_account_id = T::PoolLocator::address(&pool_id) .expect("pool ids must be convertible with new account id conversion type"); + let info = Pools::::get(&pool_id).expect("pool info must be present"); let (asset1, asset2) = pool_id; assert_eq!(balance1, T::Assets::total_balance(asset1, &new_account_id)); assert_eq!(balance2, T::Assets::total_balance(asset2, &new_account_id)); + assert_eq!(balance3, T::PoolAssets::total_balance(info.lp_token, &new_account_id)); + assert_eq!(total_issuance, DepositAssets::total_issuance()); } Ok(()) } From 0eee02e74ca47a97705f53ec579d8590a411722c Mon Sep 17 00:00:00 2001 From: muharem Date: Fri, 9 Feb 2024 14:04:48 +0800 Subject: [PATCH 16/42] migration asserts reduce to zero instead success --- substrate/frame/asset-conversion/src/migration.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/substrate/frame/asset-conversion/src/migration.rs b/substrate/frame/asset-conversion/src/migration.rs index 2fa44a5ee7e2..c218eed6564a 100644 --- a/substrate/frame/asset-conversion/src/migration.rs +++ b/substrate/frame/asset-conversion/src/migration.rs @@ -102,7 +102,7 @@ pub mod new_pool_account_id { let withdraw_result1 = T::Assets::can_withdraw(asset1.clone(), &account_id, balance1); - if withdraw_result1 != WithdrawConsequence::<_>::Success { + if withdraw_result1 != WithdrawConsequence::<_>::ReducedToZero(0u32.into()) { log::error!( target: LOG_TARGET, "total balance cannot be withdrawn for asset1 from pair (`{:?}`,`{:?}`), account id `{:?}` with result `{:?}`.", @@ -116,7 +116,7 @@ pub mod new_pool_account_id { let withdraw_result2 = T::Assets::can_withdraw(asset2.clone(), &account_id, balance2); - if withdraw_result2 != WithdrawConsequence::<_>::Success { + if withdraw_result2 != WithdrawConsequence::<_>::ReducedToZero(0u32.into()) { log::error!( target: LOG_TARGET, "total balance cannot be withdrawn for asset2 from pair (`{:?}`,`{:?}`), account id `{:?}` with result `{:?}`.", @@ -130,7 +130,7 @@ pub mod new_pool_account_id { let withdraw_result3 = T::PoolAssets::can_withdraw(info.lp_token.clone(), &account_id, balance3); - if withdraw_result3 != WithdrawConsequence::<_>::Success { + if withdraw_result3 != WithdrawConsequence::<_>::ReducedToZero(0u32.into()) { log::error!( target: LOG_TARGET, "total balance cannot be withdrawn for lp token `{:?}`, from pair (`{:?}`,`{:?}`), account id `{:?}` with result `{:?}`.", @@ -445,7 +445,7 @@ pub mod new_pool_account_id { let balance2 = T::Assets::total_balance(asset2.clone(), &account_id); let balance3 = T::PoolAssets::total_balance(info.lp_token.clone(), &account_id); let total_issuance = DepositAssets::total_issuance(); - let withdraw_success = WithdrawConsequence::<::Balance>::Success; + let withdraw_success = WithdrawConsequence::<_>::ReducedToZero(0u32.into()); if T::Assets::can_withdraw(asset1.clone(), &account_id, balance1) == withdraw_success && T::Assets::can_withdraw( asset2.clone(), From 11e300422a79588aeaba6862c05b112fff756754 Mon Sep 17 00:00:00 2001 From: muharem Date: Fri, 9 Feb 2024 14:05:04 +0800 Subject: [PATCH 17/42] correct doc --- substrate/frame/asset-conversion/src/migration.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/substrate/frame/asset-conversion/src/migration.rs b/substrate/frame/asset-conversion/src/migration.rs index c218eed6564a..dc3624f23ca2 100644 --- a/substrate/frame/asset-conversion/src/migration.rs +++ b/substrate/frame/asset-conversion/src/migration.rs @@ -56,8 +56,12 @@ pub mod new_pool_account_id { /// `T::PoolAssets`. /// - `WeightPerItem`: A getter returning the weight required for the migration of a single pool /// account ID. It should include: 2 * weight_of(T::Assets::balance(..)) + 2 * - /// weight_of(T::Assets::transfer(..)) + 2 * weight_of(Refund::deposit_held(..)) + 2 * - /// weight_of(Refund::refund(..)) + weight_of(ResetTeam::reset_team(..)); + /// weight_of(T::Assets::transfer(..)) + weight_of(T::PoolAssets::balance(..)) + + /// weight_of(T::PoolAssets::transfer(..)) + 2 * weight_of(Refund::deposit_held(..)) + 2 * + /// weight_of(Refund::refund(..)) + weight_of(PoolRefund::deposit_held(..)) + + /// weight_of(PoolRefund::refund(..)) + 3 * weight_of(DepositAssets::minimum_balance(..)) + 3 + /// * weight_of(DepositAssets::mint_into(..)) + 3 * weight_of(DepositAssets::burn_from(..)) + + /// weight_of(ResetTeam::reset_team(..)); pub struct Migrate( PhantomData<(T, OldLocator, ResetTeam, Refund, PoolRefund, DepositAssets, WeightPerItem)>, ); From 03363c851026cc79e699511f0aa6e68e6f1e39f7 Mon Sep 17 00:00:00 2001 From: muharem Date: Mon, 12 Feb 2024 13:12:53 +0800 Subject: [PATCH 18/42] balance for destroying asset cannot be increased/decreased --- substrate/frame/assets/src/functions.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/substrate/frame/assets/src/functions.rs b/substrate/frame/assets/src/functions.rs index 623a8558e176..0fc2e16617a0 100644 --- a/substrate/frame/assets/src/functions.rs +++ b/substrate/frame/assets/src/functions.rs @@ -132,6 +132,9 @@ impl, I: 'static> Pallet { Some(details) => details, None => return DepositConsequence::UnknownAsset, }; + if details.status == AssetStatus::Destroying { + return DepositConsequence::UnknownAsset + } if increase_supply && details.supply.checked_add(&amount).is_none() { return DepositConsequence::Overflow } @@ -175,6 +178,9 @@ impl, I: 'static> Pallet { if details.status == AssetStatus::Frozen { return Frozen } + if details.status == AssetStatus::Destroying { + return UnknownAsset + } if amount.is_zero() { return Success } From 58f0a66b6c78933c4ee77af3025b10fcde923f8c Mon Sep 17 00:00:00 2001 From: muharem Date: Mon, 12 Feb 2024 13:13:41 +0800 Subject: [PATCH 19/42] migration --- .../frame/asset-conversion/src/migration.rs | 299 ++++++++++++------ 1 file changed, 208 insertions(+), 91 deletions(-) diff --git a/substrate/frame/asset-conversion/src/migration.rs b/substrate/frame/asset-conversion/src/migration.rs index dc3624f23ca2..1f1157a05a61 100644 --- a/substrate/frame/asset-conversion/src/migration.rs +++ b/substrate/frame/asset-conversion/src/migration.rs @@ -37,7 +37,9 @@ pub mod new_pool_account_id { use frame_support::traits::{ fungible::Mutate as FungibleMutate, fungibles::{Inspect, Refund as RefundT, ResetTeam as ResetTeamT}, - tokens::{Fortitude, Precision, Preservation, WithdrawConsequence}, + tokens::{ + DepositConsequence, Fortitude, Precision, Preservation, Provenance, WithdrawConsequence, + }, }; /// Type facilitating the migration of existing pools to new account ids when the type deriving @@ -90,29 +92,35 @@ pub mod new_pool_account_id { let (asset1, asset2) = pool_id; + // Assets that must be transferred to the new account id. + let balance1 = T::Assets::balance(asset1.clone(), &account_id); + let balance2 = T::Assets::balance(asset2.clone(), &account_id); + let balance3 = T::PoolAssets::balance(info.lp_token.clone(), &account_id); + log::info!( target: LOG_TARGET, - "migrating an asset pair (`{:?}`, `{:?}`).", + "migrating an asset pair (`{:?}`, `{:?}`) with lp token `{:?}` from old account id `{:?}` to the new account id `{:?}` with balances `{:?}`, `{:?}`, `{:?}`.", asset1.clone(), asset2.clone(), + info.lp_token.clone(), + account_id.clone(), new_account_id.clone(), + balance1, + balance2, + balance3, ); - // assets that must be transferred to the new account id. - let balance1 = T::Assets::balance(asset1.clone(), &account_id); - let balance2 = T::Assets::balance(asset2.clone(), &account_id); - let balance3 = T::PoolAssets::balance(info.lp_token.clone(), &account_id); - - // check if it possible to withdraw the assets from old account id. + // Check if it's possible to withdraw the assets from old account id. + // It might fail if asset is not live. let withdraw_result1 = T::Assets::can_withdraw(asset1.clone(), &account_id, balance1); - if withdraw_result1 != WithdrawConsequence::<_>::ReducedToZero(0u32.into()) { + if !matches!( + withdraw_result1, + WithdrawConsequence::<_>::Success | WithdrawConsequence::<_>::ReducedToZero(_) + ) { log::error!( target: LOG_TARGET, - "total balance cannot be withdrawn for asset1 from pair (`{:?}`,`{:?}`), account id `{:?}` with result `{:?}`.", - asset1, - asset2, - account_id, + "total balance of asset1 cannot be withdrawn from the old account with result `{:?}`.", withdraw_result1, ); continue; @@ -120,13 +128,13 @@ pub mod new_pool_account_id { let withdraw_result2 = T::Assets::can_withdraw(asset2.clone(), &account_id, balance2); - if withdraw_result2 != WithdrawConsequence::<_>::ReducedToZero(0u32.into()) { + if !matches!( + withdraw_result2, + WithdrawConsequence::<_>::Success | WithdrawConsequence::<_>::ReducedToZero(_) + ) { log::error!( target: LOG_TARGET, - "total balance cannot be withdrawn for asset2 from pair (`{:?}`,`{:?}`), account id `{:?}` with result `{:?}`.", - asset1, - asset2, - account_id, + "total balance of asset2 cannot be withdrawn from the old account with result `{:?}`.", withdraw_result2, ); continue; @@ -134,31 +142,88 @@ pub mod new_pool_account_id { let withdraw_result3 = T::PoolAssets::can_withdraw(info.lp_token.clone(), &account_id, balance3); - if withdraw_result3 != WithdrawConsequence::<_>::ReducedToZero(0u32.into()) { + if !matches!( + withdraw_result3, + WithdrawConsequence::<_>::Success | WithdrawConsequence::<_>::ReducedToZero(_) + ) { log::error!( target: LOG_TARGET, - "total balance cannot be withdrawn for lp token `{:?}`, from pair (`{:?}`,`{:?}`), account id `{:?}` with result `{:?}`.", - info.lp_token, - asset1, - asset2, - account_id, + "total balance of lp token cannot be withdrawn from the old account with result `{:?}`.", withdraw_result3, ); continue; } - // check if deposit has to be placed for the new account. - // if deposit required mint a deposit amount to the depositor account to ensure the - // deposit can be provided. after the deposit from the old account will be returned, - // the minted assets will be burned. + // Check if it's possible to deposit the assets to new account id. + // It might fail if asset is not live or minimum balance has changed. + + let deposit_result1 = T::Assets::can_deposit( + asset1.clone(), + &new_account_id, + balance1, + Provenance::Extant, + ); + if !matches!( + deposit_result1, + DepositConsequence::Success | DepositConsequence::CannotCreate + ) { + log::error!( + target: LOG_TARGET, + "total balance of asset1 cannot be deposited to the new account with result `{:?}`.", + deposit_result1, + ); + continue; + } + + let deposit_result2 = T::Assets::can_deposit( + asset2.clone(), + &new_account_id, + balance2, + Provenance::Extant, + ); + if !matches!( + deposit_result2, + DepositConsequence::Success | DepositConsequence::CannotCreate + ) { + log::error!( + target: LOG_TARGET, + "total balance of asset2 cannot be deposited to the new account with result `{:?}`.", + deposit_result2, + ); + continue; + } + + let deposit_result3 = T::PoolAssets::can_deposit( + info.lp_token.clone(), + &new_account_id, + balance3, + Provenance::Extant, + ); + if !matches!( + deposit_result3, + DepositConsequence::Success | DepositConsequence::CannotCreate + ) { + log::error!( + target: LOG_TARGET, + "total balance of lp token cannot be deposited to the new account with result `{:?}`.", + deposit_result3, + ); + continue; + } + + // Check if a deposit needs to be placed for the new account. If so, mint the + // required deposit amount to the depositor's account to ensure it can be provided. + // Once the deposit from the old account is returned, the minted assets will be + // burned. Minting assets is necessary because it's not possible to transfer assets + // to the new account if a deposit is required but not provided. Additionally, the + // deposit cannot be refunded from the old account until its balance is zero. if let Some((d, b)) = Refund::deposit_held(asset1.clone(), account_id.clone()) { let ed = DepositAssets::minimum_balance(); if let Err(e) = DepositAssets::mint_into(&d, b + ed) { log::error!( target: LOG_TARGET, - "failed to mint deposit for asset1 `{:?}`, into account id `{:?}` with error `{:?}`.", - asset1, + "failed to mint deposit for asset1 into depositor account id `{:?}` with error `{:?}`.", d, e, ); @@ -173,11 +238,7 @@ pub mod new_pool_account_id { ); log::error!( target: LOG_TARGET, - "failed to touch account `{:?}`, `{:?}`, from pair (`{:?}`,`{:?}`), with error `{:?}` and burn result `{:?}`.", - asset1.clone(), - new_account_id, - asset1, - asset2, + "failed to touch the new account for asset1 with error `{:?}` and burn result `{:?}`.", e, burn_res, ); @@ -190,8 +251,7 @@ pub mod new_pool_account_id { if let Err(e) = DepositAssets::mint_into(&d, b + ed) { log::error!( target: LOG_TARGET, - "failed to mint deposit for asset2 `{:?}`, into account id `{:?}` with error `{:?}`.", - asset2, + "failed to mint deposit for asset2 into depositor account id `{:?}` with error `{:?}`.", d, e, ); @@ -206,11 +266,7 @@ pub mod new_pool_account_id { ); log::error!( target: LOG_TARGET, - "failed to touch account `{:?}`, `{:?}`, from pair (`{:?}`,`{:?}`), with error `{:?}` and burn result `{:?}`.", - asset2.clone(), - new_account_id, - asset1, - asset2, + "failed to touch the new account for asset2 with error `{:?}` and burn result `{:?}`.", e, burn_res, ); @@ -225,8 +281,7 @@ pub mod new_pool_account_id { if let Err(e) = DepositAssets::mint_into(&d, b + ed) { log::error!( target: LOG_TARGET, - "failed to mint deposit for lp token `{:?}`, into account id `{:?}` with error `{:?}`.", - info.lp_token.clone(), + "failed to mint deposit for lp token into depositor account id `{:?}` with error `{:?}`.", d, e, ); @@ -242,11 +297,7 @@ pub mod new_pool_account_id { ); log::error!( target: LOG_TARGET, - "failed to touch account `{:?}`, `{:?}`, from pair (`{:?}`,`{:?}`), with error `{:?}` with a burn result `{:?}`.", - info.lp_token, - new_account_id, - asset1, - asset2, + "failed to touch the new account for lp token with error `{:?}` with a burn result `{:?}`.", e, burn_res, ); @@ -254,7 +305,7 @@ pub mod new_pool_account_id { } } - // transfer all pool related assets to the new account. + // Transfer all pool related assets to the new account. if let Err(e) = T::Assets::transfer( asset1.clone(), @@ -265,10 +316,7 @@ pub mod new_pool_account_id { ) { log::error!( target: LOG_TARGET, - "transfer all, of `{:?}` from `{:?}` to `{:?}` failed with error `{:?}`", - asset1, - account_id, - new_account_id, + "transfer of asset1 to the new account failed with error `{:?}`", e, ); continue; @@ -290,10 +338,7 @@ pub mod new_pool_account_id { ); log::error!( target: LOG_TARGET, - "transfer all, of `{:?}` from `{:?}` to `{:?}` failed with error `{:?}` with rollback transfer result `{:?}`", - asset2, - account_id, - new_account_id, + "transfer of asset2 failed with error `{:?}` and rollback transfer result `{:?}`", e, transfer_res, ); @@ -323,10 +368,7 @@ pub mod new_pool_account_id { ); log::error!( target: LOG_TARGET, - "transfer all, of `{:?}` from `{:?}` to `{:?}` failed with error `{:?}` with rollback transfer result `{:?}` and `{:?}`", - info.lp_token, - account_id, - new_account_id, + "transfer of lp tokens failed with error `{:?}` and rollback transfer results `{:?}` and `{:?}`", e, transfer_res1, transfer_res2, @@ -334,15 +376,13 @@ pub mod new_pool_account_id { continue; } - // refund deposits from old accounts and burn previously minted assets. + // Refund deposits from old accounts and burn previously minted assets. if let Some((d, b)) = Refund::deposit_held(asset1.clone(), account_id.clone()) { if let Err(e) = Refund::refund(asset1.clone(), account_id.clone()) { log::error!( target: LOG_TARGET, - "refund for asset1 `{:?}` to account `{:?}` failed with error `{:?}`", - asset1, - account_id, + "refund of asset1 account deposit failed with error `{:?}`", e, ); } @@ -352,7 +392,7 @@ pub mod new_pool_account_id { { log::error!( target: LOG_TARGET, - "failed to burn deposit for asset1 from `{:?}` with error `{:?}`.", + "burn of asset1 from depositor account id `{:?}` failed with error `{:?}`.", d, e, ); @@ -364,9 +404,7 @@ pub mod new_pool_account_id { if let Err(e) = Refund::refund(asset2.clone(), account_id.clone()) { log::error!( target: LOG_TARGET, - "refund for asset2 `{:?}` to account `{:?}` failed with error `{:?}`", - asset2.clone(), - account_id, + "refund of asset2 account deposit failed with error `{:?}`", e, ); } @@ -376,7 +414,7 @@ pub mod new_pool_account_id { { log::error!( target: LOG_TARGET, - "failed to burn deposit for asset2 from `{:?}` with error `{:?}`.", + "burn of asset2 from depositor account id `{:?}` failed with error `{:?}`.", d, e, ); @@ -390,9 +428,7 @@ pub mod new_pool_account_id { if let Err(e) = PoolRefund::refund(info.lp_token.clone(), account_id.clone()) { log::error!( target: LOG_TARGET, - "refund for lp token `{:?}` to account `{:?}` failed with error `{:?}`", - info.lp_token.clone(), - account_id, + "refund of lp token account deposit failed with error `{:?}`", e, ); } @@ -402,7 +438,7 @@ pub mod new_pool_account_id { { log::error!( target: LOG_TARGET, - "failed to burn deposit for lp token from `{:?}` with error `{:?}`.", + "burn of lp tokens from depositor account id `{:?}` failed with error `{:?}`.", d, e, ); @@ -411,7 +447,7 @@ pub mod new_pool_account_id { } if let Err(e) = ResetTeam::reset_team( - info.lp_token.clone(), + info.lp_token, new_account_id.clone(), new_account_id.clone(), new_account_id.clone(), @@ -419,8 +455,7 @@ pub mod new_pool_account_id { ) { log::error!( target: LOG_TARGET, - "team reset for asset `{:?}` failed with error `{:?}`", - info.lp_token, + "team reset for lp tone failed with error `{:?}`", e, ); } @@ -443,24 +478,98 @@ pub mod new_pool_account_id { )> = vec![]; for (pool_id, info) in Pools::::iter() { let account_id = OldLocator::address(&pool_id) - .expect("pool ids must be convertible with old account id conversion type"); + .expect("account id must be derivable with old pool locator"); + let new_account_id = T::PoolLocator::address(&pool_id) + .expect("account id must be derivable with new pool locator"); let (asset1, asset2) = pool_id; - let balance1 = T::Assets::total_balance(asset1.clone(), &account_id); - let balance2 = T::Assets::total_balance(asset2.clone(), &account_id); - let balance3 = T::PoolAssets::total_balance(info.lp_token.clone(), &account_id); + let balance1 = T::Assets::balance(asset1.clone(), &account_id); + let balance2 = T::Assets::balance(asset2.clone(), &account_id); + let balance3 = T::PoolAssets::balance(info.lp_token.clone(), &account_id); let total_issuance = DepositAssets::total_issuance(); - let withdraw_success = WithdrawConsequence::<_>::ReducedToZero(0u32.into()); - if T::Assets::can_withdraw(asset1.clone(), &account_id, balance1) == - withdraw_success && T::Assets::can_withdraw( + + assert_eq!(T::Balance::zero(), T::Assets::balance(asset1.clone(), &new_account_id)); + assert_eq!(T::Balance::zero(), T::Assets::balance(asset2.clone(), &new_account_id)); + assert_eq!( + T::Balance::zero(), + T::PoolAssets::balance(info.lp_token.clone(), &new_account_id) + ); + + let withdraw_result1 = + T::Assets::can_withdraw(asset1.clone(), &account_id, balance1); + let withdraw_result2 = + T::Assets::can_withdraw(asset2.clone(), &account_id, balance2); + let withdraw_result3 = + T::PoolAssets::can_withdraw(info.lp_token.clone(), &account_id, balance3); + + if !matches!( + withdraw_result1, + WithdrawConsequence::<_>::Success | WithdrawConsequence::<_>::ReducedToZero(_) + ) || !matches!( + withdraw_result2, + WithdrawConsequence::<_>::Success | WithdrawConsequence::<_>::ReducedToZero(_) + ) || !matches!( + withdraw_result3, + WithdrawConsequence::<_>::Success | WithdrawConsequence::<_>::ReducedToZero(_) + ) { + log::warn!( + target: LOG_TARGET, + "cannot withdraw, migration for asset pair (`{:?}`,`{:?}`) will be skipped, with results: `{:?}`, `{:?}`, `{:?}`", + asset1, + asset2, + withdraw_result1, + withdraw_result2, + withdraw_result3, + ); + continue; + } + + let increase_result1 = T::Assets::can_deposit( + asset1.clone(), + &new_account_id, + balance1, + Provenance::Extant, + ); + let increase_result2 = T::Assets::can_deposit( asset2.clone(), - &account_id, + &new_account_id, balance2, - ) == withdraw_success && - T::PoolAssets::can_withdraw(info.lp_token, &account_id, balance3) == - withdraw_success - { - expected.push(((asset1, asset2), balance1, balance2, balance3, total_issuance)); + Provenance::Extant, + ); + let increase_result3 = T::PoolAssets::can_deposit( + info.lp_token, + &new_account_id, + balance3, + Provenance::Extant, + ); + + if !matches!( + increase_result1, + DepositConsequence::Success | DepositConsequence::CannotCreate + ) || !matches!( + increase_result2, + DepositConsequence::Success | DepositConsequence::CannotCreate + ) || !matches!( + increase_result3, + DepositConsequence::Success | DepositConsequence::CannotCreate + ) { + log::warn!( + target: LOG_TARGET, + "cannot deposit, migration for asset pair (`{:?}`,`{:?}`) will be skipped, with results: `{:?}`, `{:?}`, `{:?}`", asset1, + asset2, + increase_result1, + increase_result2, + increase_result3, + ); + continue; } + + log::info!( + target: LOG_TARGET, + "asset pair (`{:?}`,`{:?}`) will be migrated with balance1 `{:?}`, balance2 `{:?}` and balance3 `{:?}`.", + asset1.clone(), asset2.clone(), balance1, balance2, balance3 + ); + + expected.push(((asset1, asset2), balance1, balance2, balance3, total_issuance)); } Ok(expected.encode()) } @@ -481,6 +590,14 @@ pub mod new_pool_account_id { .expect("pool ids must be convertible with new account id conversion type"); let info = Pools::::get(&pool_id).expect("pool info must be present"); let (asset1, asset2) = pool_id; + + log::info!( + target: LOG_TARGET, + "assert migration results for asset pair (`{:?}`, `{:?}`).", + asset1.clone(), + asset2.clone(), + ); + assert_eq!(balance1, T::Assets::total_balance(asset1, &new_account_id)); assert_eq!(balance2, T::Assets::total_balance(asset2, &new_account_id)); assert_eq!(balance3, T::PoolAssets::total_balance(info.lp_token, &new_account_id)); From d14b412ec68c2a71f36025ad7837d86766c1f437 Mon Sep 17 00:00:00 2001 From: muharem Date: Mon, 12 Feb 2024 16:18:28 +0800 Subject: [PATCH 20/42] make migration idempotent --- .../frame/asset-conversion/src/migration.rs | 47 +++++++++++-------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/substrate/frame/asset-conversion/src/migration.rs b/substrate/frame/asset-conversion/src/migration.rs index 1f1157a05a61..8677899d5b9b 100644 --- a/substrate/frame/asset-conversion/src/migration.rs +++ b/substrate/frame/asset-conversion/src/migration.rs @@ -109,6 +109,14 @@ pub mod new_pool_account_id { balance3, ); + if balance1 == T::Balance::zero() && + balance2 == T::Balance::zero() && + balance3 == T::Balance::zero() + { + log::info!(target: LOG_TARGET, "skip migration for the pool with no liquidity"); + continue; + } + // Check if it's possible to withdraw the assets from old account id. // It might fail if asset is not live. @@ -118,7 +126,7 @@ pub mod new_pool_account_id { withdraw_result1, WithdrawConsequence::<_>::Success | WithdrawConsequence::<_>::ReducedToZero(_) ) { - log::error!( + log::warn!( target: LOG_TARGET, "total balance of asset1 cannot be withdrawn from the old account with result `{:?}`.", withdraw_result1, @@ -132,7 +140,7 @@ pub mod new_pool_account_id { withdraw_result2, WithdrawConsequence::<_>::Success | WithdrawConsequence::<_>::ReducedToZero(_) ) { - log::error!( + log::warn!( target: LOG_TARGET, "total balance of asset2 cannot be withdrawn from the old account with result `{:?}`.", withdraw_result2, @@ -146,7 +154,7 @@ pub mod new_pool_account_id { withdraw_result3, WithdrawConsequence::<_>::Success | WithdrawConsequence::<_>::ReducedToZero(_) ) { - log::error!( + log::warn!( target: LOG_TARGET, "total balance of lp token cannot be withdrawn from the old account with result `{:?}`.", withdraw_result3, @@ -167,7 +175,7 @@ pub mod new_pool_account_id { deposit_result1, DepositConsequence::Success | DepositConsequence::CannotCreate ) { - log::error!( + log::warn!( target: LOG_TARGET, "total balance of asset1 cannot be deposited to the new account with result `{:?}`.", deposit_result1, @@ -185,7 +193,7 @@ pub mod new_pool_account_id { deposit_result2, DepositConsequence::Success | DepositConsequence::CannotCreate ) { - log::error!( + log::warn!( target: LOG_TARGET, "total balance of asset2 cannot be deposited to the new account with result `{:?}`.", deposit_result2, @@ -203,7 +211,7 @@ pub mod new_pool_account_id { deposit_result3, DepositConsequence::Success | DepositConsequence::CannotCreate ) { - log::error!( + log::warn!( target: LOG_TARGET, "total balance of lp token cannot be deposited to the new account with result `{:?}`.", deposit_result3, @@ -487,13 +495,20 @@ pub mod new_pool_account_id { let balance3 = T::PoolAssets::balance(info.lp_token.clone(), &account_id); let total_issuance = DepositAssets::total_issuance(); - assert_eq!(T::Balance::zero(), T::Assets::balance(asset1.clone(), &new_account_id)); - assert_eq!(T::Balance::zero(), T::Assets::balance(asset2.clone(), &new_account_id)); - assert_eq!( - T::Balance::zero(), - T::PoolAssets::balance(info.lp_token.clone(), &new_account_id) + log::info!( + target: LOG_TARGET, + "run pre upgrade check for asset pair (`{:?}`,`{:?}`) with balance1 `{:?}`, balance2 `{:?}` and balance3 `{:?}`.", + asset1.clone(), asset2.clone(), balance1, balance2, balance3 ); + if balance1 == T::Balance::zero() && + balance2 == T::Balance::zero() && + balance3 == T::Balance::zero() + { + log::info!(target: LOG_TARGET, "skip pre upgrade for the pool with no liquidity"); + continue; + } + let withdraw_result1 = T::Assets::can_withdraw(asset1.clone(), &account_id, balance1); let withdraw_result2 = @@ -513,7 +528,7 @@ pub mod new_pool_account_id { ) { log::warn!( target: LOG_TARGET, - "cannot withdraw, migration for asset pair (`{:?}`,`{:?}`) will be skipped, with results: `{:?}`, `{:?}`, `{:?}`", + "cannot withdraw, migration for asset pair (`{:?}`,`{:?}`) will be skipped, with `can_withdraw` results: `{:?}`, `{:?}`, `{:?}`", asset1, asset2, withdraw_result1, @@ -554,7 +569,7 @@ pub mod new_pool_account_id { ) { log::warn!( target: LOG_TARGET, - "cannot deposit, migration for asset pair (`{:?}`,`{:?}`) will be skipped, with results: `{:?}`, `{:?}`, `{:?}`", asset1, + "cannot deposit, migration for asset pair (`{:?}`,`{:?}`) will be skipped, with `can_deposit` results: `{:?}`, `{:?}`, `{:?}`", asset1, asset2, increase_result1, increase_result2, @@ -563,12 +578,6 @@ pub mod new_pool_account_id { continue; } - log::info!( - target: LOG_TARGET, - "asset pair (`{:?}`,`{:?}`) will be migrated with balance1 `{:?}`, balance2 `{:?}` and balance3 `{:?}`.", - asset1.clone(), asset2.clone(), balance1, balance2, balance3 - ); - expected.push(((asset1, asset2), balance1, balance2, balance3, total_issuance)); } Ok(expected.encode()) From 979ae0ccf78ffc7f95c6987ea93524908b634b4e Mon Sep 17 00:00:00 2001 From: muharem Date: Fri, 16 Feb 2024 14:40:13 +0800 Subject: [PATCH 21/42] asset conversion ops pallet --- Cargo.lock | 25 + Cargo.toml | 1 + .../assets/asset-hub-rococo/Cargo.toml | 4 + .../assets/asset-hub-rococo/src/lib.rs | 52 +- .../asset-hub-rococo/src/weights/mod.rs | 1 + .../weights/pallet_asset_conversion_ops.rs | 71 ++ .../assets/asset-hub-westend/Cargo.toml | 4 + .../assets/asset-hub-westend/src/lib.rs | 52 +- .../asset-hub-westend/src/weights/mod.rs | 1 + .../weights/pallet_asset_conversion_ops.rs | 71 ++ substrate/bin/node/runtime/Cargo.toml | 4 + substrate/bin/node/runtime/src/lib.rs | 15 + .../frame/asset-conversion/ops/Cargo.toml | 74 +++ .../asset-conversion/ops/src/benchmarking.rs | 166 +++++ .../frame/asset-conversion/ops/src/lib.rs | 322 +++++++++ .../frame/asset-conversion/ops/src/mock.rs | 218 ++++++ .../frame/asset-conversion/ops/src/tests.rs | 140 ++++ .../frame/asset-conversion/ops/src/weights.rs | 102 +++ substrate/frame/asset-conversion/src/lib.rs | 1 - .../frame/asset-conversion/src/migration.rs | 618 ------------------ 20 files changed, 1251 insertions(+), 691 deletions(-) create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion_ops.rs create mode 100644 cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion_ops.rs create mode 100644 substrate/frame/asset-conversion/ops/Cargo.toml create mode 100644 substrate/frame/asset-conversion/ops/src/benchmarking.rs create mode 100644 substrate/frame/asset-conversion/ops/src/lib.rs create mode 100644 substrate/frame/asset-conversion/ops/src/mock.rs create mode 100644 substrate/frame/asset-conversion/ops/src/tests.rs create mode 100644 substrate/frame/asset-conversion/ops/src/weights.rs delete mode 100644 substrate/frame/asset-conversion/src/migration.rs diff --git a/Cargo.lock b/Cargo.lock index ac83374ee879..f3bda8395b9f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -869,6 +869,7 @@ dependencies = [ "hex-literal", "log", "pallet-asset-conversion", + "pallet-asset-conversion-ops", "pallet-asset-conversion-tx-payment", "pallet-assets", "pallet-aura", @@ -991,6 +992,7 @@ dependencies = [ "hex-literal", "log", "pallet-asset-conversion", + "pallet-asset-conversion-ops", "pallet-asset-conversion-tx-payment", "pallet-assets", "pallet-aura", @@ -6975,6 +6977,7 @@ dependencies = [ "node-primitives", "pallet-alliance", "pallet-asset-conversion", + "pallet-asset-conversion-ops", "pallet-asset-conversion-tx-payment", "pallet-asset-rate", "pallet-asset-tx-payment", @@ -9037,6 +9040,28 @@ dependencies = [ "sp-std 14.0.0", ] +[[package]] +name = "pallet-asset-conversion-ops" +version = "0.0.1" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-asset-conversion", + "pallet-assets", + "pallet-balances", + "parity-scale-codec", + "primitive-types", + "scale-info", + "sp-api", + "sp-arithmetic", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std 14.0.0", +] + [[package]] name = "pallet-asset-conversion-tx-payment" version = "10.0.0" diff --git a/Cargo.toml b/Cargo.toml index 0a70bb03756b..0f481c3fd480 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -295,6 +295,7 @@ members = [ "substrate/frame", "substrate/frame/alliance", "substrate/frame/asset-conversion", + "substrate/frame/asset-conversion/ops", "substrate/frame/asset-rate", "substrate/frame/assets", "substrate/frame/atomic-swap", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index d1b302dc6d4f..d29024b220ed 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -25,6 +25,7 @@ frame-system-rpc-runtime-api = { path = "../../../../../substrate/frame/system/r frame-try-runtime = { path = "../../../../../substrate/frame/try-runtime", default-features = false, optional = true } pallet-asset-conversion-tx-payment = { path = "../../../../../substrate/frame/transaction-payment/asset-conversion-tx-payment", default-features = false } pallet-assets = { path = "../../../../../substrate/frame/assets", default-features = false } +pallet-asset-conversion-ops = { path = "../../../../../substrate/frame/asset-conversion/ops", default-features = false } pallet-asset-conversion = { path = "../../../../../substrate/frame/asset-conversion", default-features = false } pallet-aura = { path = "../../../../../substrate/frame/aura", default-features = false } pallet-authorship = { path = "../../../../../substrate/frame/authorship", default-features = false } @@ -119,6 +120,7 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", + "pallet-asset-conversion-ops/runtime-benchmarks", "pallet-asset-conversion/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", @@ -152,6 +154,7 @@ try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", "frame-try-runtime/try-runtime", + "pallet-asset-conversion-ops/try-runtime", "pallet-asset-conversion-tx-payment/try-runtime", "pallet-asset-conversion/try-runtime", "pallet-assets/try-runtime", @@ -199,6 +202,7 @@ std = [ "frame-system/std", "frame-try-runtime?/std", "log/std", + "pallet-asset-conversion-ops/std", "pallet-asset-conversion-tx-payment/std", "pallet-asset-conversion/std", "pallet-assets/std", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index b00bb4b22421..830c0af2037e 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -374,6 +374,18 @@ impl pallet_asset_conversion::Config for Runtime { >; } +impl pallet_asset_conversion_ops::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type PriorAccountIdConverter = pallet_asset_conversion::AccountIdConverterNoSeed< + ::PoolId, + >; + type AssetsRefund = ::Assets; + type PoolAssetsRefund = ::PoolAssets; + type PoolAssetsTeam = ::PoolAssets; + type DepositAsset = Balances; + type WeightInfo = weights::pallet_asset_conversion_ops::WeightInfo; +} + parameter_types! { // we just reuse the same deposits pub const ForeignAssetsAssetDeposit: Balance = AssetDeposit::get(); @@ -946,6 +958,9 @@ construct_runtime!( #[cfg(feature = "state-trie-version-1")] StateTrieMigration: pallet_state_trie_migration = 70, + + // TODO + AssetConversionMigration: pallet_asset_conversion_ops = 200, } ); @@ -972,24 +987,6 @@ pub type SignedExtra = ( pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; -parameter_types! { - pub PerAccountMigrationWeight: Weight = { - // 2 balance + 2 deposit - ::DbWeight::get().reads(5) - .saturating_add( - as pallet_assets::WeightInfo>::transfer() - ).saturating_add( - as pallet_assets::WeightInfo>::transfer() - ).saturating_add( - as pallet_assets::WeightInfo>::refund_other() - ).saturating_add( - as pallet_assets::WeightInfo>::refund_other() - ).saturating_add( // team reset - ::DbWeight::get().reads_writes(1, 1) - ) - }; -} - /// Migrations to apply on runtime upgrade. #[allow(deprecated)] pub type Migrations = ( @@ -999,24 +996,6 @@ pub type Migrations = ( cumulus_pallet_xcmp_queue::migration::v4::MigrationToV4, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, - // unreleased - pallet_asset_conversion::migration::new_pool_account_id::Migrate< - Runtime, - pallet_asset_conversion::WithFirstAsset< - TokenLocationV3, - AccountId, - xcm::v3::Location, - pallet_asset_conversion::AccountIdConverterNoSeed<( - xcm::v3::Location, - xcm::v3::Location, - )>, - >, - ::PoolAssets, - ::Assets, - ::PoolAssets, - Balances, - PerAccountMigrationWeight, - >, ); /// Migration to initialize storage versions for pallets added after genesis. @@ -1101,6 +1080,7 @@ mod benches { [pallet_collator_selection, CollatorSelection] [cumulus_pallet_xcmp_queue, XcmpQueue] [pallet_xcm_bridge_hub_router, ToWestend] + [pallet_asset_conversion_ops, AssetConversionMigration] // XCM [pallet_xcm, PalletXcmExtrinsicsBenchmark::] // NOTE: Make sure you point to the individual modules below. diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs index fa9e86102c61..f20790cde39c 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs @@ -20,6 +20,7 @@ pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; pub mod pallet_asset_conversion; +pub mod pallet_asset_conversion_ops; pub mod pallet_assets_foreign; pub mod pallet_assets_local; pub mod pallet_assets_pool; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion_ops.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion_ops.rs new file mode 100644 index 000000000000..e85420d32d9c --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion_ops.rs @@ -0,0 +1,71 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +//! Autogenerated weights for `pallet_asset_conversion_ops` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-15, STEPS: `10`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `cob`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/debug/polkadot-parachain +// benchmark +// pallet +// --chain=asset-hub-rococo-dev +// --steps=10 +// --repeat=2 +// --pallet=pallet-asset-conversion-ops +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_asset_conversion_ops`. +pub struct WeightInfo(PhantomData); +impl pallet_asset_conversion_ops::WeightInfo for WeightInfo { + /// Storage: `AssetConversion::Pools` (r:1 w:0) + /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:2 w:2) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Account` (r:2 w:2) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + fn migrate_to_new_account() -> Weight { + // Proof Size summary in bytes: + // Measured: `1105` + // Estimated: `7404` + // Minimum execution time: 2_323_000_000 picoseconds. + Weight::from_parts(2_404_000_000, 0) + .saturating_add(Weight::from_parts(0, 7404)) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(8)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index 415c8c1cb062..dfbf3dccb8c0 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -23,6 +23,7 @@ frame-system = { path = "../../../../../substrate/frame/system", default-feature frame-system-benchmarking = { path = "../../../../../substrate/frame/system/benchmarking", default-features = false, optional = true } frame-system-rpc-runtime-api = { path = "../../../../../substrate/frame/system/rpc/runtime-api", default-features = false } frame-try-runtime = { path = "../../../../../substrate/frame/try-runtime", default-features = false, optional = true } +pallet-asset-conversion-ops = { path = "../../../../../substrate/frame/asset-conversion/ops", default-features = false } pallet-asset-conversion-tx-payment = { path = "../../../../../substrate/frame/transaction-payment/asset-conversion-tx-payment", default-features = false } pallet-assets = { path = "../../../../../substrate/frame/assets", default-features = false } pallet-asset-conversion = { path = "../../../../../substrate/frame/asset-conversion", default-features = false } @@ -110,6 +111,7 @@ runtime-benchmarks = [ "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", "hex-literal", + "pallet-asset-conversion-ops/runtime-benchmarks", "pallet-asset-conversion/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", @@ -141,6 +143,7 @@ try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", "frame-try-runtime/try-runtime", + "pallet-asset-conversion-ops/try-runtime", "pallet-asset-conversion-tx-payment/try-runtime", "pallet-asset-conversion/try-runtime", "pallet-assets/try-runtime", @@ -187,6 +190,7 @@ std = [ "frame-system/std", "frame-try-runtime?/std", "log/std", + "pallet-asset-conversion-ops/std", "pallet-asset-conversion-tx-payment/std", "pallet-asset-conversion/std", "pallet-assets/std", diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 05e8b6301fac..3a85786eef37 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -356,6 +356,18 @@ impl pallet_asset_conversion::Config for Runtime { >; } +impl pallet_asset_conversion_ops::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type PriorAccountIdConverter = pallet_asset_conversion::AccountIdConverterNoSeed< + ::PoolId, + >; + type AssetsRefund = ::Assets; + type PoolAssetsRefund = ::PoolAssets; + type PoolAssetsTeam = ::PoolAssets; + type DepositAsset = Balances; + type WeightInfo = weights::pallet_asset_conversion_ops::WeightInfo; +} + parameter_types! { // we just reuse the same deposits pub const ForeignAssetsAssetDeposit: Balance = AssetDeposit::get(); @@ -918,6 +930,9 @@ construct_runtime!( NftFractionalization: pallet_nft_fractionalization = 54, PoolAssets: pallet_assets:: = 55, AssetConversion: pallet_asset_conversion = 56, + + // TODO + AssetConversionMigration: pallet_asset_conversion_ops = 200, } ); @@ -944,24 +959,6 @@ pub type SignedExtra = ( pub type UncheckedExtrinsic = generic::UncheckedExtrinsic; -parameter_types! { - pub PerAccountMigrationWeight: Weight = { - // 2 balance + 2 deposit - ::DbWeight::get().reads(5) - .saturating_add( - as pallet_assets::WeightInfo>::transfer() - ).saturating_add( - as pallet_assets::WeightInfo>::transfer() - ).saturating_add( - as pallet_assets::WeightInfo>::refund_other() - ).saturating_add( - as pallet_assets::WeightInfo>::refund_other() - ).saturating_add( // team reset - ::DbWeight::get().reads_writes(1, 1) - ) - }; -} - /// Migrations to apply on runtime upgrade. pub type Migrations = ( // v9420 @@ -978,24 +975,6 @@ pub type Migrations = ( cumulus_pallet_xcmp_queue::migration::v4::MigrationToV4, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, - // unreleased - pallet_asset_conversion::migration::new_pool_account_id::Migrate< - Runtime, - pallet_asset_conversion::WithFirstAsset< - WestendLocationV3, - AccountId, - xcm::v3::Location, - pallet_asset_conversion::AccountIdConverterNoSeed<( - xcm::v3::Location, - xcm::v3::Location, - )>, - >, - ::PoolAssets, - ::Assets, - ::PoolAssets, - Balances, - PerAccountMigrationWeight, - >, ); /// Asset Hub Westend has some undecodable storage, delete it. @@ -1131,6 +1110,7 @@ mod benches { [pallet_collator_selection, CollatorSelection] [cumulus_pallet_xcmp_queue, XcmpQueue] [pallet_xcm_bridge_hub_router, ToRococo] + [pallet_asset_conversion_ops, AssetConversionMigration] // XCM [pallet_xcm, PalletXcmExtrinsicsBenchmark::] // NOTE: Make sure you point to the individual modules below. diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs index 2f1fcfb05f39..4eebb1f8d786 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs @@ -19,6 +19,7 @@ pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; pub mod pallet_asset_conversion; +pub mod pallet_asset_conversion_ops; pub mod pallet_assets_foreign; pub mod pallet_assets_local; pub mod pallet_assets_pool; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion_ops.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion_ops.rs new file mode 100644 index 000000000000..dfe4092c3f02 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion_ops.rs @@ -0,0 +1,71 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +//! Autogenerated weights for `pallet_asset_conversion_ops` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-15, STEPS: `10`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `cob`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/debug/polkadot-parachain +// benchmark +// pallet +// --chain=asset-hub-westend-dev +// --steps=10 +// --repeat=2 +// --pallet=pallet-asset-conversion-ops +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_asset_conversion_ops`. +pub struct WeightInfo(PhantomData); +impl pallet_asset_conversion_ops::WeightInfo for WeightInfo { + /// Storage: `AssetConversion::Pools` (r:1 w:0) + /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(1224), added: 3699, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:2 w:2) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Account` (r:2 w:2) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + fn migrate_to_new_account() -> Weight { + // Proof Size summary in bytes: + // Measured: `1105` + // Estimated: `7404` + // Minimum execution time: 2_216_000_000 picoseconds. + Weight::from_parts(2_379_000_000, 0) + .saturating_add(Weight::from_parts(0, 7404)) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(8)) + } +} diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index 76e32f02f0a3..82a715fb330f 100644 --- a/substrate/bin/node/runtime/Cargo.toml +++ b/substrate/bin/node/runtime/Cargo.toml @@ -66,6 +66,7 @@ frame-system-rpc-runtime-api = { path = "../../../frame/system/rpc/runtime-api", frame-try-runtime = { path = "../../../frame/try-runtime", default-features = false, optional = true } pallet-alliance = { path = "../../../frame/alliance", default-features = false } pallet-asset-conversion = { path = "../../../frame/asset-conversion", default-features = false } +pallet-asset-conversion-ops = { path = "../../../frame/asset-conversion/ops", default-features = false } pallet-asset-rate = { path = "../../../frame/asset-rate", default-features = false } pallet-assets = { path = "../../../frame/assets", default-features = false } pallet-authority-discovery = { path = "../../../frame/authority-discovery", default-features = false } @@ -164,6 +165,7 @@ std = [ "log/std", "node-primitives/std", "pallet-alliance/std", + "pallet-asset-conversion-ops/std", "pallet-asset-conversion-tx-payment/std", "pallet-asset-conversion/std", "pallet-asset-rate/std", @@ -274,6 +276,7 @@ runtime-benchmarks = [ "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-alliance/runtime-benchmarks", + "pallet-asset-conversion-ops/runtime-benchmarks", "pallet-asset-conversion/runtime-benchmarks", "pallet-asset-rate/runtime-benchmarks", "pallet-asset-tx-payment/runtime-benchmarks", @@ -348,6 +351,7 @@ try-runtime = [ "frame-system/try-runtime", "frame-try-runtime/try-runtime", "pallet-alliance/try-runtime", + "pallet-asset-conversion-ops/try-runtime", "pallet-asset-conversion-tx-payment/try-runtime", "pallet-asset-conversion/try-runtime", "pallet-asset-rate/try-runtime", diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index b526517db656..3ef1b9ca151e 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -1719,6 +1719,19 @@ impl pallet_asset_conversion::Config for Runtime { type BenchmarkHelper = (); } +impl pallet_asset_conversion_ops::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type PriorAccountIdConverter = pallet_asset_conversion::AccountIdConverterNoSeed<( + NativeOrWithId, + NativeOrWithId, + )>; + type AssetsRefund = ::Assets; + type PoolAssetsRefund = ::PoolAssets; + type PoolAssetsTeam = ::PoolAssets; + type DepositAsset = Balances; + type WeightInfo = pallet_asset_conversion_ops::weights::SubstrateWeight; +} + parameter_types! { pub const QueueCount: u32 = 300; pub const MaxQueueLen: u32 = 1000; @@ -2254,6 +2267,7 @@ construct_runtime!( Mixnet: pallet_mixnet, Parameters: pallet_parameters, SkipFeelessPayment: pallet_skip_feeless_payment, + AssetConversionMigration: pallet_asset_conversion_ops = 200, } ); @@ -2412,6 +2426,7 @@ mod benches { [pallet_whitelist, Whitelist] [pallet_tx_pause, TxPause] [pallet_safe_mode, SafeMode] + [pallet_asset_conversion_ops, AssetConversionMigration] ); } diff --git a/substrate/frame/asset-conversion/ops/Cargo.toml b/substrate/frame/asset-conversion/ops/Cargo.toml new file mode 100644 index 000000000000..1ef3d412415a --- /dev/null +++ b/substrate/frame/asset-conversion/ops/Cargo.toml @@ -0,0 +1,74 @@ +[package] +name = "pallet-asset-conversion-ops" +version = "0.0.1" +authors.workspace = true +edition.workspace = true +license = "Apache-2.0" +homepage = "https://substrate.io" +repository.workspace = true +description = "FRAME asset conversion pallet's operations suite" +readme = "README.md" + +[lints] +workspace = true + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false } +log = { version = "0.4.20", default-features = false } +frame-support = { path = "../../support", default-features = false } +frame-system = { path = "../../system", default-features = false } +frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true } +pallet-asset-conversion = { path = "..", default-features = false } +scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } +sp-api = { path = "../../../primitives/api", default-features = false } +sp-core = { path = "../../../primitives/core", default-features = false } +sp-io = { path = "../../../primitives/io", default-features = false } +sp-std = { path = "../../../primitives/std", default-features = false } +sp-runtime = { path = "../../../primitives/runtime", default-features = false } +sp-arithmetic = { path = "../../../primitives/arithmetic", default-features = false } + +[dev-dependencies] +pallet-balances = { path = "../../balances" } +pallet-assets = { path = "../../assets" } +primitive-types = { version = "0.12.0", default-features = false, features = ["codec", "num-traits", "scale-info"] } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-benchmarking?/std", + "frame-support/std", + "frame-system/std", + "log/std", + "pallet-assets/std", + "pallet-asset-conversion/std", + "pallet-balances/std", + "primitive-types/std", + "scale-info/std", + "sp-api/std", + "sp-arithmetic/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", +] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", + "pallet-asset-conversion/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", + "pallet-assets/try-runtime", + "pallet-asset-conversion/try-runtime", + "pallet-balances/try-runtime", + "sp-runtime/try-runtime", +] diff --git a/substrate/frame/asset-conversion/ops/src/benchmarking.rs b/substrate/frame/asset-conversion/ops/src/benchmarking.rs new file mode 100644 index 000000000000..02a3d88825f7 --- /dev/null +++ b/substrate/frame/asset-conversion/ops/src/benchmarking.rs @@ -0,0 +1,166 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Asset Conversion Ops pallet benchmarking. + +use super::*; +use crate::Pallet as AssetConversionOps; +use frame_benchmarking::{v2::*, whitelisted_caller}; +use frame_support::{ + assert_ok, + traits::fungibles::{Create, Inspect, Mutate}, +}; +use frame_system::RawOrigin as SystemOrigin; +use pallet_asset_conversion::{BenchmarkHelper, Pallet as AssetConversion}; +use sp_core::Get; +use sp_std::prelude::*; + +/// Provides a pair of amounts expected to serve as sufficient initial liquidity for a pool. +fn valid_liquidity_amount(ed1: T::Balance, ed2: T::Balance) -> (T::Balance, T::Balance) +where + T::Assets: Inspect, +{ + let l = + ed1.max(ed2) + T::MintMinLiquidity::get() + T::MintMinLiquidity::get() + T::Balance::one(); + (l, l) +} + +/// Create the `asset` and mint the `amount` for the `caller`. +fn create_asset(caller: &T::AccountId, asset: &T::AssetKind, amount: T::Balance) +where + T::Assets: Create + Mutate, +{ + if !T::Assets::asset_exists(asset.clone()) { + assert_ok!(T::Assets::create(asset.clone(), caller.clone(), true, T::Balance::one())); + } + assert_ok!(T::Assets::mint_into( + asset.clone(), + &caller, + amount + T::Assets::minimum_balance(asset.clone()) + )); +} + +/// Create the designated fee asset for pool creation. +fn create_fee_asset(caller: &T::AccountId) +where + T::Assets: Create + Mutate, +{ + let fee_asset = T::PoolSetupFeeAsset::get(); + if !T::Assets::asset_exists(fee_asset.clone()) { + assert_ok!(T::Assets::create(fee_asset.clone(), caller.clone(), true, T::Balance::one())); + } + assert_ok!(T::Assets::mint_into( + fee_asset.clone(), + &caller, + T::Assets::minimum_balance(fee_asset) + )); +} + +/// Mint the fee asset for the `caller` sufficient to cover the fee for creating a new pool. +fn mint_setup_fee_asset( + caller: &T::AccountId, + asset1: &T::AssetKind, + asset2: &T::AssetKind, + lp_token: &T::PoolAssetId, +) where + T::Assets: Create + Mutate, +{ + assert_ok!(T::Assets::mint_into( + T::PoolSetupFeeAsset::get(), + &caller, + T::PoolSetupFee::get() + + T::Assets::deposit_required(asset1.clone()) + + T::Assets::deposit_required(asset2.clone()) + + T::PoolAssets::deposit_required(lp_token.clone()) + )); +} + +/// Creates a pool for a given asset pair. +/// +/// This action mints the necessary amounts of the given assets for the `caller` to provide initial +/// liquidity. It returns the LP token ID along with a pair of amounts sufficient for the pool's +/// initial liquidity. +fn create_asset_and_pool( + caller: &T::AccountId, + asset1: &T::AssetKind, + asset2: &T::AssetKind, +) -> (T::PoolAssetId, T::Balance, T::Balance) +where + T::Assets: Create + Mutate, +{ + let (liquidity1, liquidity2) = valid_liquidity_amount::( + T::Assets::minimum_balance(asset1.clone()), + T::Assets::minimum_balance(asset2.clone()), + ); + create_asset::(caller, asset1, liquidity1); + create_asset::(caller, asset2, liquidity2); + let lp_token = AssetConversion::::get_next_pool_asset_id(); + + mint_setup_fee_asset::(caller, asset1, asset2, &lp_token); + + assert_ok!(AssetConversion::::create_pool( + SystemOrigin::Signed(caller.clone()).into(), + Box::new(asset1.clone()), + Box::new(asset2.clone()) + )); + + (lp_token, liquidity1, liquidity2) +} + +fn assert_last_event(generic_event: ::RuntimeEvent) { + let events = frame_system::Pallet::::events(); + let system_event: ::RuntimeEvent = generic_event.into(); + // compare to the last event record + let frame_system::EventRecord { event, .. } = &events[events.len() - 1]; + assert_eq!(event, &system_event); +} + +#[benchmarks(where T::Assets: Create + Mutate, T::PoolAssetId: Into,)] +mod benchmarks { + use super::*; + + #[benchmark] + fn migrate_to_new_account() { + let caller: T::AccountId = whitelisted_caller(); + let (asset1, asset2) = T::BenchmarkHelper::create_pair(0, 1); + + create_fee_asset::(&caller); + let (_, liquidity1, liquidity2) = create_asset_and_pool::(&caller, &asset1, &asset2); + + assert_ok!(AssetConversion::::add_liquidity( + SystemOrigin::Signed(caller.clone()).into(), + Box::new(asset1.clone()), + Box::new(asset2.clone()), + liquidity1, + liquidity2, + T::Balance::one(), + T::Balance::zero(), + caller.clone(), + )); + + #[extrinsic_call] + _(SystemOrigin::Signed(caller.clone()), Box::new(asset1.clone()), Box::new(asset2.clone())); + + let pool_id = T::PoolLocator::pool_id(&asset1, &asset2).unwrap(); + let (prior_account, new_account) = AssetConversionOps::::addresses(&pool_id).unwrap(); + assert_last_event::( + Event::MigratedToNewAccount { pool_id, new_account, prior_account }.into(), + ); + } + + impl_benchmark_test_suite!(AssetConversionOps, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/substrate/frame/asset-conversion/ops/src/lib.rs b/substrate/frame/asset-conversion/ops/src/lib.rs new file mode 100644 index 000000000000..96653c7e6730 --- /dev/null +++ b/substrate/frame/asset-conversion/ops/src/lib.rs @@ -0,0 +1,322 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! # Asset Conversion Operations Suite. +//! +//! This pallet provides operational functionalities for the Asset Conversion pallet, +//! allowing you to perform various migration and one-time-use operations. These operations +//! are designed to facilitate updates and changes to the Asset Conversion pallet without +//! breaking its API. +//! +//! ## Overview +//! +//! This suite allows you to perform the following operations: +//! - Perform migration to update account ID derivation methods for existing pools. + +#![deny(missing_docs)] +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; +pub mod weights; +pub use pallet::*; +pub use weights::WeightInfo; + +use frame_support::traits::{ + fungible::{Inspect as FungibleInspect, Mutate as FungibleMutate}, + fungibles::{Inspect, Mutate, Refund, ResetTeam}, + tokens::{Fortitude, Precision, Preservation}, + AccountTouch, +}; +use pallet_asset_conversion::{PoolLocator, Pools}; +use sp_runtime::traits::{One, TryConvert, Zero}; +use sp_std::boxed::Box; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: + pallet_asset_conversion::Config< + PoolId = ( + ::AssetKind, + ::AssetKind, + ), + > + frame_system::Config + { + /// Overarching event type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// Type previously used to derive the account ID for a pool. Indicates that the pool's + /// liquidity assets are located at this account before the migration. + type PriorAccountIdConverter: for<'a> TryConvert< + &'a (Self::AssetKind, Self::AssetKind), + Self::AccountId, + >; + + /// Retrieves information about an existing deposit for a given account ID and asset from + /// the [`Self::Assets`] registry and can initiate the refund. + type AssetsRefund: Refund< + Self::AccountId, + AssetId = Self::AssetKind, + Balance = >::Balance, + >; + + /// Retrieves information about an existing deposit for a given account ID and asset from + /// the [`Self::PoolAssets`] registry and can initiate the refund. + type PoolAssetsRefund: Refund< + Self::AccountId, + AssetId = Self::PoolAssetId, + Balance = >::Balance, + >; + + /// Means to reset the team for assets from the [`Self::PoolAssets`] registry. + type PoolAssetsTeam: ResetTeam; + + /// Registry of an asset used as an account deposit for the [`Self::Assets`] and + /// [`Self::PoolAssets`] registries. + type DepositAsset: FungibleMutate; + + /// Weight information for extrinsics in this pallet. + type WeightInfo: WeightInfo; + } + + // Pallet's events. + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// Indicates that a pool has been migrated to the new account ID. + MigratedToNewAccount { + /// Pool's ID. + pool_id: T::PoolId, + /// Pool's prior account ID. + prior_account: T::AccountId, + /// Pool's new account ID. + new_account: T::AccountId, + }, + } + + #[pallet::error] + pub enum Error { + /// Provided asset pair is not supported for pool. + InvalidAssetPair, + /// The pool doesn't exist. + PoolNotFound, + /// Pool's balance cannot be zero. + ZeroBalance, + /// Indicates a partial transfer of balance to the new account during a migration. + PartialTransfer, + } + + #[pallet::hooks] + impl Hooks> for Pallet { + fn integrity_test() { + // TODO + } + } + + /// Pallet's callable functions. + #[pallet::call] + impl Pallet { + /// Migrates an existing pool to a new account ID derivation method for a given asset pair. + /// If the migration is successful, transaction fees are refunded to the caller. + /// + /// Must be signed. + #[pallet::call_index(0)] + #[pallet::weight(::WeightInfo::migrate_to_new_account())] + pub fn migrate_to_new_account( + origin: OriginFor, + asset1: Box, + asset2: Box, + ) -> DispatchResultWithPostInfo { + let _ = ensure_signed(origin)?; + + let pool_id = T::PoolLocator::pool_id(&asset1, &asset2) + .map_err(|_| Error::::InvalidAssetPair)?; + let info = Pools::::get(&pool_id).ok_or(Error::::PoolNotFound)?; + + let (prior_account, new_account) = + Self::addresses(&pool_id).ok_or(Error::::InvalidAssetPair)?; + + let (asset1, asset2) = pool_id.clone(); + + // Assets that must be transferred to the new account id. + let balance1 = T::Assets::balance(asset1.clone(), &prior_account); + let balance2 = T::Assets::balance(asset2.clone(), &prior_account); + let balance3 = T::PoolAssets::balance(info.lp_token.clone(), &prior_account); + + ensure!(!balance1.is_zero(), Error::::ZeroBalance); + ensure!(!balance2.is_zero(), Error::::ZeroBalance); + ensure!(!balance3.is_zero(), Error::::ZeroBalance); + + // Check if a deposit needs to be placed for the new account. If so, mint the + // required deposit amount to the depositor's account to ensure the deposit can be + // provided. Once the deposit from the prior account is returned, the minted assets will + // be burned. Touching the new account is necessary because it's not possible to + // transfer assets to the new account if it's required. Additionally, the deposit cannot + // be refunded from the prior account until its balance is zero. + + if let Some((d, b)) = + T::AssetsRefund::deposit_held(asset1.clone(), prior_account.clone()) + { + let ed = T::DepositAsset::minimum_balance(); + T::DepositAsset::mint_into(&d, b + ed)?; + T::Assets::touch(asset1.clone(), &new_account, &d)?; + } + + if let Some((d, b)) = + T::AssetsRefund::deposit_held(asset2.clone(), prior_account.clone()) + { + let ed = T::DepositAsset::minimum_balance(); + T::DepositAsset::mint_into(&d, b + ed)?; + T::Assets::touch(asset2.clone(), &new_account, &d)?; + } + + if let Some((d, b)) = + T::PoolAssetsRefund::deposit_held(info.lp_token.clone(), prior_account.clone()) + { + let ed = T::DepositAsset::minimum_balance(); + T::DepositAsset::mint_into(&d, b + ed)?; + T::PoolAssets::touch(info.lp_token.clone(), &new_account, &d)?; + } + + // Transfer all pool related assets to the new account. + + ensure!( + balance1 == + T::Assets::transfer( + asset1.clone(), + &prior_account, + &new_account, + balance1, + Preservation::Expendable, + )?, + Error::::PartialTransfer + ); + + ensure!( + balance2 == + T::Assets::transfer( + asset2.clone(), + &prior_account, + &new_account, + balance2, + Preservation::Expendable, + )?, + Error::::PartialTransfer + ); + + ensure!( + balance3 == + T::PoolAssets::transfer( + info.lp_token.clone(), + &prior_account, + &new_account, + balance3, + Preservation::Expendable, + )?, + Error::::PartialTransfer + ); + + // Refund deposits from prior accounts and burn previously minted assets. + + if let Some((d, b)) = + T::AssetsRefund::deposit_held(asset1.clone(), prior_account.clone()) + { + T::AssetsRefund::refund(asset1.clone(), prior_account.clone())?; + let ed = T::DepositAsset::minimum_balance(); + T::DepositAsset::burn_from(&d, b + ed, Precision::Exact, Fortitude::Force)?; + } + + if let Some((d, b)) = + T::AssetsRefund::deposit_held(asset2.clone(), prior_account.clone()) + { + T::AssetsRefund::refund(asset2.clone(), prior_account.clone())?; + let ed = T::DepositAsset::minimum_balance(); + T::DepositAsset::burn_from(&d, b + ed, Precision::Exact, Fortitude::Force)?; + } + + if let Some((d, b)) = + T::PoolAssetsRefund::deposit_held(info.lp_token.clone(), prior_account.clone()) + { + T::PoolAssetsRefund::refund(info.lp_token.clone(), prior_account.clone())?; + let ed = T::DepositAsset::minimum_balance(); + T::DepositAsset::burn_from(&d, b + ed, Precision::Exact, Fortitude::Force)?; + } + + T::PoolAssetsTeam::reset_team( + info.lp_token, + new_account.clone(), + new_account.clone(), + new_account.clone(), + new_account.clone(), + )?; + + Self::deposit_event(Event::MigratedToNewAccount { + pool_id, + prior_account, + new_account, + }); + + Ok(Pays::No.into()) + } + } + + impl Pallet { + /// Returns the prior and new account IDs for a given pool ID. The prior account ID comes + /// first in the tuple. + #[cfg(not(any(test, feature = "runtime-benchmarks")))] + fn addresses(pool_id: &T::PoolId) -> Option<(T::AccountId, T::AccountId)> { + match ( + T::PriorAccountIdConverter::try_convert(pool_id), + T::PoolLocator::address(pool_id), + ) { + (Ok(a), Ok(b)) if a != b => Some((a, b)), + _ => None, + } + } + + /// Returns the prior and new account IDs for a given pool ID. The prior account ID comes + /// first in the tuple. + /// + /// This function is intended for use only in test and benchmark environments. The prior + /// account ID represents the new account ID from [`Config::PoolLocator`], allowing the use + /// of the main pallet's calls to set up a pool with liquidity placed in that account and + /// migrate it to another account, which in this case is the result of + /// [`Config::PriorAccountIdConverter`]. + #[cfg(any(test, feature = "runtime-benchmarks"))] + pub(crate) fn addresses(pool_id: &T::PoolId) -> Option<(T::AccountId, T::AccountId)> { + match ( + T::PoolLocator::address(pool_id), + T::PriorAccountIdConverter::try_convert(pool_id), + ) { + (Ok(a), Ok(b)) if a != b => Some((a, b)), + _ => None, + } + } + } +} diff --git a/substrate/frame/asset-conversion/ops/src/mock.rs b/substrate/frame/asset-conversion/ops/src/mock.rs new file mode 100644 index 000000000000..8460d1a47e00 --- /dev/null +++ b/substrate/frame/asset-conversion/ops/src/mock.rs @@ -0,0 +1,218 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Test environment for Asset Conversion Ops pallet. + +use super::*; +use crate as pallet_asset_conversion_ops; +use core::default::Default; +use frame_support::{ + construct_runtime, derive_impl, + instances::{Instance1, Instance2}, + ord_parameter_types, parameter_types, + traits::{ + tokens::{ + fungible::{NativeFromLeft, NativeOrWithId, UnionOf}, + imbalance::ResolveAssetTo, + }, + AsEnsureOriginWithArg, ConstU128, ConstU32, ConstU64, + }, + PalletId, +}; +use frame_system::{EnsureSigned, EnsureSignedBy}; +use pallet_asset_conversion::{ + self, AccountIdConverter, AccountIdConverterNoSeed, Ascending, Chain, WithFirstAsset, +}; +use sp_arithmetic::Permill; +use sp_core::H256; +use sp_runtime::{ + traits::{AccountIdConversion, BlakeTwo256, IdentityLookup}, + BuildStorage, +}; + +type Block = frame_system::mocking::MockBlock; + +construct_runtime!( + pub enum Test + { + System: frame_system, + Balances: pallet_balances, + Assets: pallet_assets::, + PoolAssets: pallet_assets::, + AssetConversion: pallet_asset_conversion, + AssetConversionOps: pallet_asset_conversion_ops, + } +); + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] +impl frame_system::Config for Test { + type BaseCallFilter = frame_support::traits::Everything; + type BlockWeights = (); + type BlockLength = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Nonce = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u128; + type Lookup = IdentityLookup; + type Block = Block; + type RuntimeEvent = RuntimeEvent; + type BlockHashCount = ConstU64<250>; + type DbWeight = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); + type MaxConsumers = ConstU32<16>; +} + +impl pallet_balances::Config for Test { + type Balance = u128; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ConstU128<100>; + type AccountStore = System; + type WeightInfo = (); + type MaxLocks = (); + type MaxReserves = ConstU32<50>; + type ReserveIdentifier = [u8; 8]; + type FreezeIdentifier = (); + type MaxFreezes = (); + type RuntimeHoldReason = (); + type RuntimeFreezeReason = (); +} + +impl pallet_assets::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Balance = u128; + type RemoveItemsLimit = ConstU32<1000>; + type AssetId = u32; + type AssetIdParameter = u32; + type Currency = Balances; + type CreateOrigin = AsEnsureOriginWithArg>; + type ForceOrigin = frame_system::EnsureRoot; + type AssetDeposit = ConstU128<1>; + type AssetAccountDeposit = ConstU128<10>; + type MetadataDepositBase = ConstU128<1>; + type MetadataDepositPerByte = ConstU128<1>; + type ApprovalDeposit = ConstU128<1>; + type StringLimit = ConstU32<50>; + type Freezer = (); + type Extra = (); + type WeightInfo = (); + type CallbackHandle = (); + pallet_assets::runtime_benchmarks_enabled! { + type BenchmarkHelper = (); + } +} + +impl pallet_assets::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Balance = u128; + type RemoveItemsLimit = ConstU32<1000>; + type AssetId = u32; + type AssetIdParameter = u32; + type Currency = Balances; + type CreateOrigin = + AsEnsureOriginWithArg>; + type ForceOrigin = frame_system::EnsureRoot; + type AssetDeposit = ConstU128<0>; + type AssetAccountDeposit = ConstU128<0>; + type MetadataDepositBase = ConstU128<0>; + type MetadataDepositPerByte = ConstU128<0>; + type ApprovalDeposit = ConstU128<0>; + type StringLimit = ConstU32<50>; + type Freezer = (); + type Extra = (); + type WeightInfo = (); + type CallbackHandle = (); + pallet_assets::runtime_benchmarks_enabled! { + type BenchmarkHelper = (); + } +} + +parameter_types! { + pub const AssetConversionPalletId: PalletId = PalletId(*b"py/ascon"); + pub const Native: NativeOrWithId = NativeOrWithId::Native; + pub storage LiquidityWithdrawalFee: Permill = Permill::from_percent(0); +} + +ord_parameter_types! { + pub const AssetConversionOrigin: u128 = AccountIdConversion::::into_account_truncating(&AssetConversionPalletId::get()); +} + +pub type NativeAndAssets = UnionOf, u128>; +pub type PoolIdToAccountId = + AccountIdConverter, NativeOrWithId)>; +pub type AscendingLocator = Ascending, PoolIdToAccountId>; +pub type WithFirstAssetLocator = + WithFirstAsset, PoolIdToAccountId>; + +impl pallet_asset_conversion::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Balance = ::Balance; + type HigherPrecisionBalance = sp_core::U256; + type AssetKind = NativeOrWithId; + type Assets = NativeAndAssets; + type PoolId = (Self::AssetKind, Self::AssetKind); + type PoolLocator = Chain; + type PoolAssetId = u32; + type PoolAssets = PoolAssets; + type PoolSetupFee = ConstU128<100>; + type PoolSetupFeeAsset = Native; + type PoolSetupFeeTarget = ResolveAssetTo; + type PalletId = AssetConversionPalletId; + type WeightInfo = (); + type LPFee = ConstU32<3>; + type LiquidityWithdrawalFee = LiquidityWithdrawalFee; + type MaxSwapPathLength = ConstU32<4>; + type MintMinLiquidity = ConstU128<100>; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); +} + +pub type OldPoolIdToAccountId = + AccountIdConverterNoSeed<(NativeOrWithId, NativeOrWithId)>; + +impl pallet_asset_conversion_ops::Config for Test { + type RuntimeEvent = RuntimeEvent; + type PriorAccountIdConverter = OldPoolIdToAccountId; + type AssetsRefund = NativeAndAssets; + type PoolAssetsRefund = PoolAssets; + type PoolAssetsTeam = PoolAssets; + type DepositAsset = Balances; + type WeightInfo = (); +} + +pub(crate) fn new_test_ext() -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![(1, 10000), (2, 20000), (3, 30000), (4, 40000)], + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext +} diff --git a/substrate/frame/asset-conversion/ops/src/tests.rs b/substrate/frame/asset-conversion/ops/src/tests.rs new file mode 100644 index 000000000000..f16a7cc0e278 --- /dev/null +++ b/substrate/frame/asset-conversion/ops/src/tests.rs @@ -0,0 +1,140 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Asset Conversion Ops pallet tests. + +use crate::{mock::*, *}; +use frame_support::{ + assert_noop, assert_ok, + traits::{ + fungible::{Inspect as FungibleInspect, NativeOrWithId}, + fungibles::{Create, Inspect}, + Incrementable, + }, +}; + +#[test] +fn migrate_pool_account_id() { + new_test_ext().execute_with(|| { + type PoolLocator = ::PoolLocator; + let user = 1; + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); + let pool_id = PoolLocator::pool_id(&token_1, &token_2).unwrap(); + let lp_token = + ::PoolAssetId::initial_value().unwrap(); + + // setup pool and add provide some liquidity. + assert_ok!(NativeAndAssets::create(token_2.clone(), user, false, 1)); + + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1.clone()), + Box::new(token_2.clone()) + )); + + let ed = Balances::minimum_balance(); + assert_ok!(Balances::force_set_balance(RuntimeOrigin::root(), user, 10000 * 2 + ed)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); + + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(user), + Box::new(token_1.clone()), + Box::new(token_2.clone()), + 10000, + 10, + 10000, + 10, + user, + )); + + // assert user's balance. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &user), 10000 + ed); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &user), 1000 - 10); + assert_eq!(PoolAssets::balance(lp_token.clone(), &user), 216); + + // record total issuances before migration. + let total_issuance_token1 = NativeAndAssets::total_issuance(token_1.clone()); + let total_issuance_token2 = NativeAndAssets::total_issuance(token_2.clone()); + let total_issuance_lp_token = PoolAssets::total_issuance(lp_token.clone()); + + let pool_account = PoolLocator::address(&pool_id).unwrap(); + let (prior_pool_account, new_pool_account) = + AssetConversionOps::addresses(&pool_id).unwrap(); + assert_eq!(pool_account, prior_pool_account); + + // assert pool's balances before migration. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &prior_pool_account), 10000); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &prior_pool_account), 10); + assert_eq!(PoolAssets::balance(lp_token.clone(), &prior_pool_account), 100); + + // migrate. + assert_ok!(AssetConversionOps::migrate_to_new_account( + RuntimeOrigin::signed(user), + Box::new(token_1.clone()), + Box::new(token_2.clone()), + )); + + // assert user's balance has not changed. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &user), 10000 + ed); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &user), 1000 - 10); + assert_eq!(PoolAssets::balance(lp_token.clone(), &user), 216); + + // assert pool's balance on new account id is same as on prior account id. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &new_pool_account), 10000); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &new_pool_account), 10); + assert_eq!(PoolAssets::balance(lp_token.clone(), &new_pool_account), 100); + + // assert pool's balance on prior account id is zero. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &prior_pool_account), 0); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &prior_pool_account), 0); + assert_eq!(PoolAssets::balance(lp_token.clone(), &prior_pool_account), 0); + + // assert total issuance has not changed. + assert_eq!(total_issuance_token1, NativeAndAssets::total_issuance(token_1)); + assert_eq!(total_issuance_token2, NativeAndAssets::total_issuance(token_2)); + assert_eq!(total_issuance_lp_token, PoolAssets::total_issuance(lp_token)); + }); +} + +#[test] +fn migrate_empty_pool_account_id() { + new_test_ext().execute_with(|| { + let user = 1; + let token_1 = NativeOrWithId::Native; + let token_2 = NativeOrWithId::WithId(2); + + // setup pool and add provide some liquidity. + assert_ok!(NativeAndAssets::create(token_2.clone(), user, false, 1)); + + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1.clone()), + Box::new(token_2.clone()) + )); + + // migrate. + assert_noop!( + AssetConversionOps::migrate_to_new_account( + RuntimeOrigin::signed(user), + Box::new(token_1.clone()), + Box::new(token_2.clone()), + ), + Error::::ZeroBalance + ); + }); +} diff --git a/substrate/frame/asset-conversion/ops/src/weights.rs b/substrate/frame/asset-conversion/ops/src/weights.rs new file mode 100644 index 000000000000..4a907e83410a --- /dev/null +++ b/substrate/frame/asset-conversion/ops/src/weights.rs @@ -0,0 +1,102 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_asset_conversion_ops` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-15, STEPS: `30`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `cob`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` + +// Executed Command: +// ./target/debug/substrate-node +// benchmark +// pallet +// --chain=dev +// --steps=30 +// --repeat=2 +// --pallet=pallet-asset-conversion-ops +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --output=./substrate/frame/asset-conversion/ops/src/._weights0.rs +// --template=./substrate/.maintain/frame-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use core::marker::PhantomData; + +/// Weight functions needed for `pallet_asset_conversion_ops`. +pub trait WeightInfo { + fn migrate_to_new_account() -> Weight; +} + +/// Weights for `pallet_asset_conversion_ops` using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: `AssetConversion::Pools` (r:1 w:0) + /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:4 w:4) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Account` (r:2 w:2) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:2 w:2) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn migrate_to_new_account() -> Weight { + // Proof Size summary in bytes: + // Measured: `1762` + // Estimated: `11426` + // Minimum execution time: 2_460_000_000 picoseconds. + Weight::from_parts(2_524_000_000, 11426) + .saturating_add(T::DbWeight::get().reads(12_u64)) + .saturating_add(T::DbWeight::get().writes(11_u64)) + } +} + +// For backwards compatibility and tests. +impl WeightInfo for () { + /// Storage: `AssetConversion::Pools` (r:1 w:0) + /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:4 w:4) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Account` (r:2 w:2) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:2 w:2) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn migrate_to_new_account() -> Weight { + // Proof Size summary in bytes: + // Measured: `1762` + // Estimated: `11426` + // Minimum execution time: 2_460_000_000 picoseconds. + Weight::from_parts(2_524_000_000, 11426) + .saturating_add(RocksDbWeight::get().reads(12_u64)) + .saturating_add(RocksDbWeight::get().writes(11_u64)) + } +} diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index cfdede967b91..f0695678fbdd 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -56,7 +56,6 @@ #[cfg(feature = "runtime-benchmarks")] mod benchmarking; -pub mod migration; #[cfg(test)] mod mock; mod swap; diff --git a/substrate/frame/asset-conversion/src/migration.rs b/substrate/frame/asset-conversion/src/migration.rs deleted file mode 100644 index 8677899d5b9b..000000000000 --- a/substrate/frame/asset-conversion/src/migration.rs +++ /dev/null @@ -1,618 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Storage migrations. - -use super::*; -#[cfg(feature = "try-runtime")] -use codec::{Decode, Encode}; -use frame_support::{traits::OnRuntimeUpgrade, weights::Weight}; -use log; -#[cfg(feature = "try-runtime")] -use sp_runtime::TryRuntimeError; -use sp_std::marker::PhantomData; -#[cfg(feature = "try-runtime")] -use sp_std::vec; - -const LOG_TARGET: &'static str = "runtime::asset-conversion::migration"; - -/// Module providing migration functionality for updating account ids when the type deriving a -/// pool's account id from pool id has changed. -pub mod new_pool_account_id { - use super::*; - use frame_support::traits::{ - fungible::Mutate as FungibleMutate, - fungibles::{Inspect, Refund as RefundT, ResetTeam as ResetTeamT}, - tokens::{ - DepositConsequence, Fortitude, Precision, Preservation, Provenance, WithdrawConsequence, - }, - }; - - /// Type facilitating the migration of existing pools to new account ids when the type deriving - /// a pool's account id from pool id has changed. - /// - /// ### Parameters: - /// - `T`: The [`Config`] implementation for the target asset conversion instance with a new - /// account derivation method defined by [`PoolLocator`]. - /// - `OldLocator`: The previously used type for account derivation. - /// - `ResetTeam`: A type used for resetting the team configuration of an LP token. - /// - `Refund`: A type used to perform a refund for assets from `T::Assets` registry if the - /// previous pool account holds a deposit. - /// - `PoolRefund`: A type used to perform a refund for assets from `T::PoolAssets` registry if - /// the previous pool account holds a deposit. - /// - `DepositAssets`: asset registry used for deposits for assets from T::Assets` and - /// `T::PoolAssets`. - /// - `WeightPerItem`: A getter returning the weight required for the migration of a single pool - /// account ID. It should include: 2 * weight_of(T::Assets::balance(..)) + 2 * - /// weight_of(T::Assets::transfer(..)) + weight_of(T::PoolAssets::balance(..)) + - /// weight_of(T::PoolAssets::transfer(..)) + 2 * weight_of(Refund::deposit_held(..)) + 2 * - /// weight_of(Refund::refund(..)) + weight_of(PoolRefund::deposit_held(..)) + - /// weight_of(PoolRefund::refund(..)) + 3 * weight_of(DepositAssets::minimum_balance(..)) + 3 - /// * weight_of(DepositAssets::mint_into(..)) + 3 * weight_of(DepositAssets::burn_from(..)) + - /// weight_of(ResetTeam::reset_team(..)); - pub struct Migrate( - PhantomData<(T, OldLocator, ResetTeam, Refund, PoolRefund, DepositAssets, WeightPerItem)>, - ); - impl - OnRuntimeUpgrade - for Migrate - where - T: Config::AssetKind, ::AssetKind)>, - OldLocator: PoolLocator, - ResetTeam: ResetTeamT, - Refund: RefundT, - PoolRefund: - RefundT, - DepositAssets: FungibleMutate, - WeightPerItem: Get, - { - fn on_runtime_upgrade() -> Weight { - let mut weight = Weight::zero(); - for (pool_id, info) in Pools::::iter() { - weight.saturating_accrue(WeightPerItem::get()); - let (account_id, new_account_id) = - match (OldLocator::address(&pool_id), T::PoolLocator::address(&pool_id)) { - (Ok(a), Ok(b)) if a != b => (a, b), - _ => continue, - }; - - let (asset1, asset2) = pool_id; - - // Assets that must be transferred to the new account id. - let balance1 = T::Assets::balance(asset1.clone(), &account_id); - let balance2 = T::Assets::balance(asset2.clone(), &account_id); - let balance3 = T::PoolAssets::balance(info.lp_token.clone(), &account_id); - - log::info!( - target: LOG_TARGET, - "migrating an asset pair (`{:?}`, `{:?}`) with lp token `{:?}` from old account id `{:?}` to the new account id `{:?}` with balances `{:?}`, `{:?}`, `{:?}`.", - asset1.clone(), - asset2.clone(), - info.lp_token.clone(), - account_id.clone(), new_account_id.clone(), - balance1, - balance2, - balance3, - ); - - if balance1 == T::Balance::zero() && - balance2 == T::Balance::zero() && - balance3 == T::Balance::zero() - { - log::info!(target: LOG_TARGET, "skip migration for the pool with no liquidity"); - continue; - } - - // Check if it's possible to withdraw the assets from old account id. - // It might fail if asset is not live. - - let withdraw_result1 = - T::Assets::can_withdraw(asset1.clone(), &account_id, balance1); - if !matches!( - withdraw_result1, - WithdrawConsequence::<_>::Success | WithdrawConsequence::<_>::ReducedToZero(_) - ) { - log::warn!( - target: LOG_TARGET, - "total balance of asset1 cannot be withdrawn from the old account with result `{:?}`.", - withdraw_result1, - ); - continue; - } - - let withdraw_result2 = - T::Assets::can_withdraw(asset2.clone(), &account_id, balance2); - if !matches!( - withdraw_result2, - WithdrawConsequence::<_>::Success | WithdrawConsequence::<_>::ReducedToZero(_) - ) { - log::warn!( - target: LOG_TARGET, - "total balance of asset2 cannot be withdrawn from the old account with result `{:?}`.", - withdraw_result2, - ); - continue; - } - - let withdraw_result3 = - T::PoolAssets::can_withdraw(info.lp_token.clone(), &account_id, balance3); - if !matches!( - withdraw_result3, - WithdrawConsequence::<_>::Success | WithdrawConsequence::<_>::ReducedToZero(_) - ) { - log::warn!( - target: LOG_TARGET, - "total balance of lp token cannot be withdrawn from the old account with result `{:?}`.", - withdraw_result3, - ); - continue; - } - - // Check if it's possible to deposit the assets to new account id. - // It might fail if asset is not live or minimum balance has changed. - - let deposit_result1 = T::Assets::can_deposit( - asset1.clone(), - &new_account_id, - balance1, - Provenance::Extant, - ); - if !matches!( - deposit_result1, - DepositConsequence::Success | DepositConsequence::CannotCreate - ) { - log::warn!( - target: LOG_TARGET, - "total balance of asset1 cannot be deposited to the new account with result `{:?}`.", - deposit_result1, - ); - continue; - } - - let deposit_result2 = T::Assets::can_deposit( - asset2.clone(), - &new_account_id, - balance2, - Provenance::Extant, - ); - if !matches!( - deposit_result2, - DepositConsequence::Success | DepositConsequence::CannotCreate - ) { - log::warn!( - target: LOG_TARGET, - "total balance of asset2 cannot be deposited to the new account with result `{:?}`.", - deposit_result2, - ); - continue; - } - - let deposit_result3 = T::PoolAssets::can_deposit( - info.lp_token.clone(), - &new_account_id, - balance3, - Provenance::Extant, - ); - if !matches!( - deposit_result3, - DepositConsequence::Success | DepositConsequence::CannotCreate - ) { - log::warn!( - target: LOG_TARGET, - "total balance of lp token cannot be deposited to the new account with result `{:?}`.", - deposit_result3, - ); - continue; - } - - // Check if a deposit needs to be placed for the new account. If so, mint the - // required deposit amount to the depositor's account to ensure it can be provided. - // Once the deposit from the old account is returned, the minted assets will be - // burned. Minting assets is necessary because it's not possible to transfer assets - // to the new account if a deposit is required but not provided. Additionally, the - // deposit cannot be refunded from the old account until its balance is zero. - - if let Some((d, b)) = Refund::deposit_held(asset1.clone(), account_id.clone()) { - let ed = DepositAssets::minimum_balance(); - if let Err(e) = DepositAssets::mint_into(&d, b + ed) { - log::error!( - target: LOG_TARGET, - "failed to mint deposit for asset1 into depositor account id `{:?}` with error `{:?}`.", - d, - e, - ); - continue; - } - if let Err(e) = T::Assets::touch(asset1.clone(), &new_account_id, &d) { - let burn_res = DepositAssets::burn_from( - &d, - b + ed, - Precision::Exact, - Fortitude::Force, - ); - log::error!( - target: LOG_TARGET, - "failed to touch the new account for asset1 with error `{:?}` and burn result `{:?}`.", - e, - burn_res, - ); - continue; - } - } - - if let Some((d, b)) = Refund::deposit_held(asset2.clone(), account_id.clone()) { - let ed = DepositAssets::minimum_balance(); - if let Err(e) = DepositAssets::mint_into(&d, b + ed) { - log::error!( - target: LOG_TARGET, - "failed to mint deposit for asset2 into depositor account id `{:?}` with error `{:?}`.", - d, - e, - ); - continue; - } - if let Err(e) = T::Assets::touch(asset2.clone(), &new_account_id, &d) { - let burn_res = DepositAssets::burn_from( - &d, - b + ed, - Precision::Exact, - Fortitude::Force, - ); - log::error!( - target: LOG_TARGET, - "failed to touch the new account for asset2 with error `{:?}` and burn result `{:?}`.", - e, - burn_res, - ); - continue; - } - } - - if let Some((d, b)) = - PoolRefund::deposit_held(info.lp_token.clone(), account_id.clone()) - { - let ed = DepositAssets::minimum_balance(); - if let Err(e) = DepositAssets::mint_into(&d, b + ed) { - log::error!( - target: LOG_TARGET, - "failed to mint deposit for lp token into depositor account id `{:?}` with error `{:?}`.", - d, - e, - ); - continue; - } - if let Err(e) = T::PoolAssets::touch(info.lp_token.clone(), &new_account_id, &d) - { - let burn_res = DepositAssets::burn_from( - &d, - b + ed, - Precision::Exact, - Fortitude::Force, - ); - log::error!( - target: LOG_TARGET, - "failed to touch the new account for lp token with error `{:?}` with a burn result `{:?}`.", - e, - burn_res, - ); - continue; - } - } - - // Transfer all pool related assets to the new account. - - if let Err(e) = T::Assets::transfer( - asset1.clone(), - &account_id, - &new_account_id, - balance1, - Preservation::Expendable, - ) { - log::error!( - target: LOG_TARGET, - "transfer of asset1 to the new account failed with error `{:?}`", - e, - ); - continue; - } - - if let Err(e) = T::Assets::transfer( - asset2.clone(), - &account_id, - &new_account_id, - balance2, - Preservation::Expendable, - ) { - let transfer_res = T::Assets::transfer( - asset1, - &new_account_id, - &account_id, - balance1, - Preservation::Expendable, - ); - log::error!( - target: LOG_TARGET, - "transfer of asset2 failed with error `{:?}` and rollback transfer result `{:?}`", - e, - transfer_res, - ); - continue; - } - - if let Err(e) = T::PoolAssets::transfer( - info.lp_token.clone(), - &account_id, - &new_account_id, - balance3, - Preservation::Expendable, - ) { - let transfer_res1 = T::Assets::transfer( - asset1, - &new_account_id, - &account_id, - balance1, - Preservation::Expendable, - ); - let transfer_res2 = T::Assets::transfer( - asset2, - &new_account_id, - &account_id, - balance2, - Preservation::Expendable, - ); - log::error!( - target: LOG_TARGET, - "transfer of lp tokens failed with error `{:?}` and rollback transfer results `{:?}` and `{:?}`", - e, - transfer_res1, - transfer_res2, - ); - continue; - } - - // Refund deposits from old accounts and burn previously minted assets. - - if let Some((d, b)) = Refund::deposit_held(asset1.clone(), account_id.clone()) { - if let Err(e) = Refund::refund(asset1.clone(), account_id.clone()) { - log::error!( - target: LOG_TARGET, - "refund of asset1 account deposit failed with error `{:?}`", - e, - ); - } - let ed = DepositAssets::minimum_balance(); - if let Err(e) = - DepositAssets::burn_from(&d, b + ed, Precision::Exact, Fortitude::Force) - { - log::error!( - target: LOG_TARGET, - "burn of asset1 from depositor account id `{:?}` failed with error `{:?}`.", - d, - e, - ); - continue; - } - } - - if let Some((d, b)) = Refund::deposit_held(asset2.clone(), account_id.clone()) { - if let Err(e) = Refund::refund(asset2.clone(), account_id.clone()) { - log::error!( - target: LOG_TARGET, - "refund of asset2 account deposit failed with error `{:?}`", - e, - ); - } - let ed = DepositAssets::minimum_balance(); - if let Err(e) = - DepositAssets::burn_from(&d, b + ed, Precision::Exact, Fortitude::Force) - { - log::error!( - target: LOG_TARGET, - "burn of asset2 from depositor account id `{:?}` failed with error `{:?}`.", - d, - e, - ); - continue; - } - } - - if let Some((d, b)) = - PoolRefund::deposit_held(info.lp_token.clone(), account_id.clone()) - { - if let Err(e) = PoolRefund::refund(info.lp_token.clone(), account_id.clone()) { - log::error!( - target: LOG_TARGET, - "refund of lp token account deposit failed with error `{:?}`", - e, - ); - } - let ed = DepositAssets::minimum_balance(); - if let Err(e) = - DepositAssets::burn_from(&d, b + ed, Precision::Exact, Fortitude::Force) - { - log::error!( - target: LOG_TARGET, - "burn of lp tokens from depositor account id `{:?}` failed with error `{:?}`.", - d, - e, - ); - continue; - } - } - - if let Err(e) = ResetTeam::reset_team( - info.lp_token, - new_account_id.clone(), - new_account_id.clone(), - new_account_id.clone(), - new_account_id, - ) { - log::error!( - target: LOG_TARGET, - "team reset for lp tone failed with error `{:?}`", - e, - ); - } - } - weight - } - - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, TryRuntimeError> { - let mut expected: Vec<( - T::PoolId, - // asset1 balance - ::Balance, - // asset2 balance - ::Balance, - // lp token balance - ::Balance, - // total issuance - DepositAssets::Balance, - )> = vec![]; - for (pool_id, info) in Pools::::iter() { - let account_id = OldLocator::address(&pool_id) - .expect("account id must be derivable with old pool locator"); - let new_account_id = T::PoolLocator::address(&pool_id) - .expect("account id must be derivable with new pool locator"); - let (asset1, asset2) = pool_id; - let balance1 = T::Assets::balance(asset1.clone(), &account_id); - let balance2 = T::Assets::balance(asset2.clone(), &account_id); - let balance3 = T::PoolAssets::balance(info.lp_token.clone(), &account_id); - let total_issuance = DepositAssets::total_issuance(); - - log::info!( - target: LOG_TARGET, - "run pre upgrade check for asset pair (`{:?}`,`{:?}`) with balance1 `{:?}`, balance2 `{:?}` and balance3 `{:?}`.", - asset1.clone(), asset2.clone(), balance1, balance2, balance3 - ); - - if balance1 == T::Balance::zero() && - balance2 == T::Balance::zero() && - balance3 == T::Balance::zero() - { - log::info!(target: LOG_TARGET, "skip pre upgrade for the pool with no liquidity"); - continue; - } - - let withdraw_result1 = - T::Assets::can_withdraw(asset1.clone(), &account_id, balance1); - let withdraw_result2 = - T::Assets::can_withdraw(asset2.clone(), &account_id, balance2); - let withdraw_result3 = - T::PoolAssets::can_withdraw(info.lp_token.clone(), &account_id, balance3); - - if !matches!( - withdraw_result1, - WithdrawConsequence::<_>::Success | WithdrawConsequence::<_>::ReducedToZero(_) - ) || !matches!( - withdraw_result2, - WithdrawConsequence::<_>::Success | WithdrawConsequence::<_>::ReducedToZero(_) - ) || !matches!( - withdraw_result3, - WithdrawConsequence::<_>::Success | WithdrawConsequence::<_>::ReducedToZero(_) - ) { - log::warn!( - target: LOG_TARGET, - "cannot withdraw, migration for asset pair (`{:?}`,`{:?}`) will be skipped, with `can_withdraw` results: `{:?}`, `{:?}`, `{:?}`", - asset1, - asset2, - withdraw_result1, - withdraw_result2, - withdraw_result3, - ); - continue; - } - - let increase_result1 = T::Assets::can_deposit( - asset1.clone(), - &new_account_id, - balance1, - Provenance::Extant, - ); - let increase_result2 = T::Assets::can_deposit( - asset2.clone(), - &new_account_id, - balance2, - Provenance::Extant, - ); - let increase_result3 = T::PoolAssets::can_deposit( - info.lp_token, - &new_account_id, - balance3, - Provenance::Extant, - ); - - if !matches!( - increase_result1, - DepositConsequence::Success | DepositConsequence::CannotCreate - ) || !matches!( - increase_result2, - DepositConsequence::Success | DepositConsequence::CannotCreate - ) || !matches!( - increase_result3, - DepositConsequence::Success | DepositConsequence::CannotCreate - ) { - log::warn!( - target: LOG_TARGET, - "cannot deposit, migration for asset pair (`{:?}`,`{:?}`) will be skipped, with `can_deposit` results: `{:?}`, `{:?}`, `{:?}`", asset1, - asset2, - increase_result1, - increase_result2, - increase_result3, - ); - continue; - } - - expected.push(((asset1, asset2), balance1, balance2, balance3, total_issuance)); - } - Ok(expected.encode()) - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(state: Vec) -> Result<(), TryRuntimeError> { - let expected: Vec<( - T::PoolId, - T::Balance, - T::Balance, - T::Balance, - DepositAssets::Balance, - )> = Decode::decode(&mut state.as_slice()).expect( - "the state parameter should be something that was generated by pre_upgrade", - ); - for (pool_id, balance1, balance2, balance3, total_issuance) in expected { - let new_account_id = T::PoolLocator::address(&pool_id) - .expect("pool ids must be convertible with new account id conversion type"); - let info = Pools::::get(&pool_id).expect("pool info must be present"); - let (asset1, asset2) = pool_id; - - log::info!( - target: LOG_TARGET, - "assert migration results for asset pair (`{:?}`, `{:?}`).", - asset1.clone(), - asset2.clone(), - ); - - assert_eq!(balance1, T::Assets::total_balance(asset1, &new_account_id)); - assert_eq!(balance2, T::Assets::total_balance(asset2, &new_account_id)); - assert_eq!(balance3, T::PoolAssets::total_balance(info.lp_token, &new_account_id)); - assert_eq!(total_issuance, DepositAssets::total_issuance()); - } - Ok(()) - } - } -} From 3be3789eb08213e0d97d606e58babe7901d9f9a6 Mon Sep 17 00:00:00 2001 From: muharem Date: Fri, 16 Feb 2024 14:40:21 +0800 Subject: [PATCH 22/42] Revert "balance for destroying asset cannot be increased/decreased" This reverts commit 03363c851026cc79e699511f0aa6e68e6f1e39f7. --- substrate/frame/assets/src/functions.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/substrate/frame/assets/src/functions.rs b/substrate/frame/assets/src/functions.rs index 0fc2e16617a0..623a8558e176 100644 --- a/substrate/frame/assets/src/functions.rs +++ b/substrate/frame/assets/src/functions.rs @@ -132,9 +132,6 @@ impl, I: 'static> Pallet { Some(details) => details, None => return DepositConsequence::UnknownAsset, }; - if details.status == AssetStatus::Destroying { - return DepositConsequence::UnknownAsset - } if increase_supply && details.supply.checked_add(&amount).is_none() { return DepositConsequence::Overflow } @@ -178,9 +175,6 @@ impl, I: 'static> Pallet { if details.status == AssetStatus::Frozen { return Frozen } - if details.status == AssetStatus::Destroying { - return UnknownAsset - } if amount.is_zero() { return Success } From 086198c3280964a96cbfbb27d03d6f594acd811c Mon Sep 17 00:00:00 2001 From: muharem Date: Fri, 16 Feb 2024 15:06:31 +0800 Subject: [PATCH 23/42] todos and unused import --- cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs | 3 ++- .../parachains/runtimes/assets/asset-hub-westend/src/lib.rs | 3 ++- substrate/bin/node/runtime/src/lib.rs | 2 +- substrate/frame/asset-conversion/ops/src/benchmarking.rs | 1 + substrate/frame/asset-conversion/ops/src/lib.rs | 2 +- 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 830c0af2037e..cb9347ddd6ca 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -959,7 +959,8 @@ construct_runtime!( #[cfg(feature = "state-trie-version-1")] StateTrieMigration: pallet_state_trie_migration = 70, - // TODO + // TODO: the pallet instance should be removed once all pools have migrated + // to the new account IDs. AssetConversionMigration: pallet_asset_conversion_ops = 200, } ); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 3a85786eef37..13cd120a5f06 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -931,7 +931,8 @@ construct_runtime!( PoolAssets: pallet_assets:: = 55, AssetConversion: pallet_asset_conversion = 56, - // TODO + // TODO: the pallet instance should be removed once all pools have migrated + // to the new account IDs. AssetConversionMigration: pallet_asset_conversion_ops = 200, } ); diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 3ef1b9ca151e..72e0e7fbf898 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -2267,7 +2267,7 @@ construct_runtime!( Mixnet: pallet_mixnet, Parameters: pallet_parameters, SkipFeelessPayment: pallet_skip_feeless_payment, - AssetConversionMigration: pallet_asset_conversion_ops = 200, + AssetConversionMigration: pallet_asset_conversion_ops, } ); diff --git a/substrate/frame/asset-conversion/ops/src/benchmarking.rs b/substrate/frame/asset-conversion/ops/src/benchmarking.rs index 02a3d88825f7..a7370f38bc4b 100644 --- a/substrate/frame/asset-conversion/ops/src/benchmarking.rs +++ b/substrate/frame/asset-conversion/ops/src/benchmarking.rs @@ -27,6 +27,7 @@ use frame_support::{ use frame_system::RawOrigin as SystemOrigin; use pallet_asset_conversion::{BenchmarkHelper, Pallet as AssetConversion}; use sp_core::Get; +use sp_runtime::traits::One; use sp_std::prelude::*; /// Provides a pair of amounts expected to serve as sufficient initial liquidity for a pool. diff --git a/substrate/frame/asset-conversion/ops/src/lib.rs b/substrate/frame/asset-conversion/ops/src/lib.rs index 96653c7e6730..00a22858e8fb 100644 --- a/substrate/frame/asset-conversion/ops/src/lib.rs +++ b/substrate/frame/asset-conversion/ops/src/lib.rs @@ -47,7 +47,7 @@ use frame_support::traits::{ AccountTouch, }; use pallet_asset_conversion::{PoolLocator, Pools}; -use sp_runtime::traits::{One, TryConvert, Zero}; +use sp_runtime::traits::{TryConvert, Zero}; use sp_std::boxed::Box; #[frame_support::pallet] From 0e12b1fdd2b0a15bdf13dd9a618de9732a7da96b Mon Sep 17 00:00:00 2001 From: muharem Date: Fri, 16 Feb 2024 15:13:09 +0800 Subject: [PATCH 24/42] clippy fix: remove clone --- substrate/frame/asset-conversion/ops/src/tests.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/substrate/frame/asset-conversion/ops/src/tests.rs b/substrate/frame/asset-conversion/ops/src/tests.rs index f16a7cc0e278..979804543ef4 100644 --- a/substrate/frame/asset-conversion/ops/src/tests.rs +++ b/substrate/frame/asset-conversion/ops/src/tests.rs @@ -65,12 +65,12 @@ fn migrate_pool_account_id() { // assert user's balance. assert_eq!(NativeAndAssets::balance(token_1.clone(), &user), 10000 + ed); assert_eq!(NativeAndAssets::balance(token_2.clone(), &user), 1000 - 10); - assert_eq!(PoolAssets::balance(lp_token.clone(), &user), 216); + assert_eq!(PoolAssets::balance(lp_token, &user), 216); // record total issuances before migration. let total_issuance_token1 = NativeAndAssets::total_issuance(token_1.clone()); let total_issuance_token2 = NativeAndAssets::total_issuance(token_2.clone()); - let total_issuance_lp_token = PoolAssets::total_issuance(lp_token.clone()); + let total_issuance_lp_token = PoolAssets::total_issuance(lp_token); let pool_account = PoolLocator::address(&pool_id).unwrap(); let (prior_pool_account, new_pool_account) = @@ -80,7 +80,7 @@ fn migrate_pool_account_id() { // assert pool's balances before migration. assert_eq!(NativeAndAssets::balance(token_1.clone(), &prior_pool_account), 10000); assert_eq!(NativeAndAssets::balance(token_2.clone(), &prior_pool_account), 10); - assert_eq!(PoolAssets::balance(lp_token.clone(), &prior_pool_account), 100); + assert_eq!(PoolAssets::balance(lp_token, &prior_pool_account), 100); // migrate. assert_ok!(AssetConversionOps::migrate_to_new_account( @@ -92,17 +92,17 @@ fn migrate_pool_account_id() { // assert user's balance has not changed. assert_eq!(NativeAndAssets::balance(token_1.clone(), &user), 10000 + ed); assert_eq!(NativeAndAssets::balance(token_2.clone(), &user), 1000 - 10); - assert_eq!(PoolAssets::balance(lp_token.clone(), &user), 216); + assert_eq!(PoolAssets::balance(lp_token, &user), 216); // assert pool's balance on new account id is same as on prior account id. assert_eq!(NativeAndAssets::balance(token_1.clone(), &new_pool_account), 10000); assert_eq!(NativeAndAssets::balance(token_2.clone(), &new_pool_account), 10); - assert_eq!(PoolAssets::balance(lp_token.clone(), &new_pool_account), 100); + assert_eq!(PoolAssets::balance(lp_token, &new_pool_account), 100); // assert pool's balance on prior account id is zero. assert_eq!(NativeAndAssets::balance(token_1.clone(), &prior_pool_account), 0); assert_eq!(NativeAndAssets::balance(token_2.clone(), &prior_pool_account), 0); - assert_eq!(PoolAssets::balance(lp_token.clone(), &prior_pool_account), 0); + assert_eq!(PoolAssets::balance(lp_token, &prior_pool_account), 0); // assert total issuance has not changed. assert_eq!(total_issuance_token1, NativeAndAssets::total_issuance(token_1)); From 6deee7f0347667773ad1148b341b6a62dfeba116 Mon Sep 17 00:00:00 2001 From: muharem Date: Sat, 17 Feb 2024 13:46:26 +0800 Subject: [PATCH 25/42] format fixes --- Cargo.lock | 1 - .../frame/asset-conversion/ops/Cargo.toml | 59 +++++++++---------- .../frame/asset-conversion/ops/src/lib.rs | 13 ++-- 3 files changed, 36 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4dab4fc5111d..2c816eb44b72 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9087,7 +9087,6 @@ dependencies = [ "parity-scale-codec", "primitive-types", "scale-info", - "sp-api", "sp-arithmetic", "sp-core", "sp-io", diff --git a/substrate/frame/asset-conversion/ops/Cargo.toml b/substrate/frame/asset-conversion/ops/Cargo.toml index 1ef3d412415a..56a12c6bf0f5 100644 --- a/substrate/frame/asset-conversion/ops/Cargo.toml +++ b/substrate/frame/asset-conversion/ops/Cargo.toml @@ -7,7 +7,6 @@ license = "Apache-2.0" homepage = "https://substrate.io" repository.workspace = true description = "FRAME asset conversion pallet's operations suite" -readme = "README.md" [lints] workspace = true @@ -23,7 +22,6 @@ frame-system = { path = "../../system", default-features = false } frame-benchmarking = { path = "../../benchmarking", default-features = false, optional = true } pallet-asset-conversion = { path = "..", default-features = false } scale-info = { version = "2.10.0", default-features = false, features = ["derive"] } -sp-api = { path = "../../../primitives/api", default-features = false } sp-core = { path = "../../../primitives/core", default-features = false } sp-io = { path = "../../../primitives/io", default-features = false } sp-std = { path = "../../../primitives/std", default-features = false } @@ -38,37 +36,36 @@ primitive-types = { version = "0.12.0", default-features = false, features = ["c [features] default = ["std"] std = [ - "codec/std", - "frame-benchmarking?/std", - "frame-support/std", - "frame-system/std", - "log/std", - "pallet-assets/std", - "pallet-asset-conversion/std", - "pallet-balances/std", - "primitive-types/std", - "scale-info/std", - "sp-api/std", - "sp-arithmetic/std", - "sp-core/std", - "sp-io/std", - "sp-runtime/std", - "sp-std/std", + "codec/std", + "frame-benchmarking?/std", + "frame-support/std", + "frame-system/std", + "log/std", + "pallet-asset-conversion/std", + "pallet-assets/std", + "pallet-balances/std", + "primitive-types/std", + "scale-info/std", + "sp-arithmetic/std", + "sp-core/std", + "sp-io/std", + "sp-runtime/std", + "sp-std/std", ] runtime-benchmarks = [ - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", - "frame-system/runtime-benchmarks", - "pallet-assets/runtime-benchmarks", - "pallet-asset-conversion/runtime-benchmarks", - "pallet-balances/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "pallet-asset-conversion/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", + "pallet-balances/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", ] try-runtime = [ - "frame-support/try-runtime", - "frame-system/try-runtime", - "pallet-assets/try-runtime", - "pallet-asset-conversion/try-runtime", - "pallet-balances/try-runtime", - "sp-runtime/try-runtime", + "frame-support/try-runtime", + "frame-system/try-runtime", + "pallet-asset-conversion/try-runtime", + "pallet-assets/try-runtime", + "pallet-balances/try-runtime", + "sp-runtime/try-runtime", ] diff --git a/substrate/frame/asset-conversion/ops/src/lib.rs b/substrate/frame/asset-conversion/ops/src/lib.rs index 00a22858e8fb..df000e36d4c9 100644 --- a/substrate/frame/asset-conversion/ops/src/lib.rs +++ b/substrate/frame/asset-conversion/ops/src/lib.rs @@ -79,7 +79,7 @@ pub mod pallet { >; /// Retrieves information about an existing deposit for a given account ID and asset from - /// the [`Self::Assets`] registry and can initiate the refund. + /// the [`pallet_asset_conversion::Config::Assets`] registry and can initiate the refund. type AssetsRefund: Refund< Self::AccountId, AssetId = Self::AssetKind, @@ -87,18 +87,21 @@ pub mod pallet { >; /// Retrieves information about an existing deposit for a given account ID and asset from - /// the [`Self::PoolAssets`] registry and can initiate the refund. + /// the [`pallet_asset_conversion::Config::PoolAssets`] registry and can initiate the + /// refund. type PoolAssetsRefund: Refund< Self::AccountId, AssetId = Self::PoolAssetId, Balance = >::Balance, >; - /// Means to reset the team for assets from the [`Self::PoolAssets`] registry. + /// Means to reset the team for assets from the + /// [`pallet_asset_conversion::Config::PoolAssets`] registry. type PoolAssetsTeam: ResetTeam; - /// Registry of an asset used as an account deposit for the [`Self::Assets`] and - /// [`Self::PoolAssets`] registries. + /// Registry of an asset used as an account deposit for the + /// [`pallet_asset_conversion::Config::Assets`] and + /// [`pallet_asset_conversion::Config::PoolAssets`] registries. type DepositAsset: FungibleMutate; /// Weight information for extrinsics in this pallet. From 02a38f0ce429f2b9e2c2911bcc8d37fc3ee467a8 Mon Sep 17 00:00:00 2001 From: muharem Date: Mon, 26 Feb 2024 11:47:47 +0100 Subject: [PATCH 26/42] review fixes --- .../frame/asset-conversion/ops/src/lib.rs | 61 ++++++++------ .../frame/asset-conversion/ops/src/mock.rs | 8 +- .../frame/asset-conversion/ops/src/tests.rs | 84 +++++++++++++++++++ 3 files changed, 122 insertions(+), 31 deletions(-) diff --git a/substrate/frame/asset-conversion/ops/src/lib.rs b/substrate/frame/asset-conversion/ops/src/lib.rs index df000e36d4c9..3b703bf944f2 100644 --- a/substrate/frame/asset-conversion/ops/src/lib.rs +++ b/substrate/frame/asset-conversion/ops/src/lib.rs @@ -170,11 +170,11 @@ pub mod pallet { // Assets that must be transferred to the new account id. let balance1 = T::Assets::balance(asset1.clone(), &prior_account); let balance2 = T::Assets::balance(asset2.clone(), &prior_account); - let balance3 = T::PoolAssets::balance(info.lp_token.clone(), &prior_account); + let lp_balance = T::PoolAssets::balance(info.lp_token.clone(), &prior_account); ensure!(!balance1.is_zero(), Error::::ZeroBalance); ensure!(!balance2.is_zero(), Error::::ZeroBalance); - ensure!(!balance3.is_zero(), Error::::ZeroBalance); + ensure!(!lp_balance.is_zero(), Error::::ZeroBalance); // Check if a deposit needs to be placed for the new account. If so, mint the // required deposit amount to the depositor's account to ensure the deposit can be @@ -183,28 +183,27 @@ pub mod pallet { // transfer assets to the new account if it's required. Additionally, the deposit cannot // be refunded from the prior account until its balance is zero. - if let Some((d, b)) = + let deposit_asset_ed = T::DepositAsset::minimum_balance(); + + if let Some((depositor, deposit)) = T::AssetsRefund::deposit_held(asset1.clone(), prior_account.clone()) { - let ed = T::DepositAsset::minimum_balance(); - T::DepositAsset::mint_into(&d, b + ed)?; - T::Assets::touch(asset1.clone(), &new_account, &d)?; + T::DepositAsset::mint_into(&depositor, deposit + deposit_asset_ed)?; + T::Assets::touch(asset1.clone(), &new_account, &depositor)?; } - if let Some((d, b)) = + if let Some((depositor, deposit)) = T::AssetsRefund::deposit_held(asset2.clone(), prior_account.clone()) { - let ed = T::DepositAsset::minimum_balance(); - T::DepositAsset::mint_into(&d, b + ed)?; - T::Assets::touch(asset2.clone(), &new_account, &d)?; + T::DepositAsset::mint_into(&depositor, deposit + deposit_asset_ed)?; + T::Assets::touch(asset2.clone(), &new_account, &depositor)?; } - if let Some((d, b)) = + if let Some((depositor, deposit)) = T::PoolAssetsRefund::deposit_held(info.lp_token.clone(), prior_account.clone()) { - let ed = T::DepositAsset::minimum_balance(); - T::DepositAsset::mint_into(&d, b + ed)?; - T::PoolAssets::touch(info.lp_token.clone(), &new_account, &d)?; + T::DepositAsset::mint_into(&depositor, deposit + deposit_asset_ed)?; + T::PoolAssets::touch(info.lp_token.clone(), &new_account, &depositor)?; } // Transfer all pool related assets to the new account. @@ -234,12 +233,12 @@ pub mod pallet { ); ensure!( - balance3 == + lp_balance == T::PoolAssets::transfer( info.lp_token.clone(), &prior_account, &new_account, - balance3, + lp_balance, Preservation::Expendable, )?, Error::::PartialTransfer @@ -247,28 +246,40 @@ pub mod pallet { // Refund deposits from prior accounts and burn previously minted assets. - if let Some((d, b)) = + if let Some((depositor, deposit)) = T::AssetsRefund::deposit_held(asset1.clone(), prior_account.clone()) { T::AssetsRefund::refund(asset1.clone(), prior_account.clone())?; - let ed = T::DepositAsset::minimum_balance(); - T::DepositAsset::burn_from(&d, b + ed, Precision::Exact, Fortitude::Force)?; + T::DepositAsset::burn_from( + &depositor, + deposit + deposit_asset_ed, + Precision::Exact, + Fortitude::Force, + )?; } - if let Some((d, b)) = + if let Some((depositor, deposit)) = T::AssetsRefund::deposit_held(asset2.clone(), prior_account.clone()) { T::AssetsRefund::refund(asset2.clone(), prior_account.clone())?; - let ed = T::DepositAsset::minimum_balance(); - T::DepositAsset::burn_from(&d, b + ed, Precision::Exact, Fortitude::Force)?; + T::DepositAsset::burn_from( + &depositor, + deposit + deposit_asset_ed, + Precision::Exact, + Fortitude::Force, + )?; } - if let Some((d, b)) = + if let Some((depositor, deposit)) = T::PoolAssetsRefund::deposit_held(info.lp_token.clone(), prior_account.clone()) { T::PoolAssetsRefund::refund(info.lp_token.clone(), prior_account.clone())?; - let ed = T::DepositAsset::minimum_balance(); - T::DepositAsset::burn_from(&d, b + ed, Precision::Exact, Fortitude::Force)?; + T::DepositAsset::burn_from( + &depositor, + deposit + deposit_asset_ed, + Precision::Exact, + Fortitude::Force, + )?; } T::PoolAssetsTeam::reset_team( diff --git a/substrate/frame/asset-conversion/ops/src/mock.rs b/substrate/frame/asset-conversion/ops/src/mock.rs index 8460d1a47e00..2c9a3525f602 100644 --- a/substrate/frame/asset-conversion/ops/src/mock.rs +++ b/substrate/frame/asset-conversion/ops/src/mock.rs @@ -34,9 +34,7 @@ use frame_support::{ PalletId, }; use frame_system::{EnsureSigned, EnsureSignedBy}; -use pallet_asset_conversion::{ - self, AccountIdConverter, AccountIdConverterNoSeed, Ascending, Chain, WithFirstAsset, -}; +use pallet_asset_conversion::{self, AccountIdConverter, AccountIdConverterNoSeed, Ascending}; use sp_arithmetic::Permill; use sp_core::H256; use sp_runtime::{ @@ -164,8 +162,6 @@ pub type NativeAndAssets = UnionOf, NativeOrWithId)>; pub type AscendingLocator = Ascending, PoolIdToAccountId>; -pub type WithFirstAssetLocator = - WithFirstAsset, PoolIdToAccountId>; impl pallet_asset_conversion::Config for Test { type RuntimeEvent = RuntimeEvent; @@ -174,7 +170,7 @@ impl pallet_asset_conversion::Config for Test { type AssetKind = NativeOrWithId; type Assets = NativeAndAssets; type PoolId = (Self::AssetKind, Self::AssetKind); - type PoolLocator = Chain; + type PoolLocator = AscendingLocator; type PoolAssetId = u32; type PoolAssets = PoolAssets; type PoolSetupFee = ConstU128<100>; diff --git a/substrate/frame/asset-conversion/ops/src/tests.rs b/substrate/frame/asset-conversion/ops/src/tests.rs index 979804543ef4..86cdf20ccd9f 100644 --- a/substrate/frame/asset-conversion/ops/src/tests.rs +++ b/substrate/frame/asset-conversion/ops/src/tests.rs @@ -111,6 +111,90 @@ fn migrate_pool_account_id() { }); } +#[test] +fn migrate_pool_account_id_with_two_insufficient_assets() { + new_test_ext().execute_with(|| { + type PoolLocator = ::PoolLocator; + let user = 1; + let token_1 = NativeOrWithId::WithId(1); + let token_2 = NativeOrWithId::WithId(2); + let pool_id = PoolLocator::pool_id(&token_1, &token_2).unwrap(); + let lp_token = + ::PoolAssetId::initial_value().unwrap(); + + // setup pool and add provide some liquidity. + assert_ok!(NativeAndAssets::create(token_1.clone(), user, false, 1)); + assert_ok!(NativeAndAssets::create(token_2.clone(), user, false, 1)); + + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1.clone()), + Box::new(token_2.clone()) + )); + + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 1, user, 20000)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); + + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(user), + Box::new(token_1.clone()), + Box::new(token_2.clone()), + 10000, + 10, + 10000, + 10, + user, + )); + + // assert user's balance. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &user), 10000); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &user), 1000 - 10); + assert_eq!(PoolAssets::balance(lp_token, &user), 216); + + // record total issuances before migration. + let total_issuance_token1 = NativeAndAssets::total_issuance(token_1.clone()); + let total_issuance_token2 = NativeAndAssets::total_issuance(token_2.clone()); + let total_issuance_lp_token = PoolAssets::total_issuance(lp_token); + + let pool_account = PoolLocator::address(&pool_id).unwrap(); + let (prior_pool_account, new_pool_account) = + AssetConversionOps::addresses(&pool_id).unwrap(); + assert_eq!(pool_account, prior_pool_account); + + // assert pool's balances before migration. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &prior_pool_account), 10000); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &prior_pool_account), 10); + assert_eq!(PoolAssets::balance(lp_token, &prior_pool_account), 100); + + // migrate. + assert_ok!(AssetConversionOps::migrate_to_new_account( + RuntimeOrigin::signed(user), + Box::new(token_1.clone()), + Box::new(token_2.clone()), + )); + + // assert user's balance has not changed. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &user), 10000); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &user), 1000 - 10); + assert_eq!(PoolAssets::balance(lp_token, &user), 216); + + // assert pool's balance on new account id is same as on prior account id. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &new_pool_account), 10000); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &new_pool_account), 10); + assert_eq!(PoolAssets::balance(lp_token, &new_pool_account), 100); + + // assert pool's balance on prior account id is zero. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &prior_pool_account), 0); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &prior_pool_account), 0); + assert_eq!(PoolAssets::balance(lp_token, &prior_pool_account), 0); + + // assert total issuance has not changed. + assert_eq!(total_issuance_token1, NativeAndAssets::total_issuance(token_1)); + assert_eq!(total_issuance_token2, NativeAndAssets::total_issuance(token_2)); + assert_eq!(total_issuance_lp_token, PoolAssets::total_issuance(lp_token)); + }); +} + #[test] fn migrate_empty_pool_account_id() { new_test_ext().execute_with(|| { From 66b75736cd8c882af304a89d1300b571f15c3c24 Mon Sep 17 00:00:00 2001 From: muharem Date: Mon, 26 Feb 2024 11:52:15 +0100 Subject: [PATCH 27/42] test --- .../frame/asset-conversion/ops/src/tests.rs | 88 ++++++++++++++++++- 1 file changed, 86 insertions(+), 2 deletions(-) diff --git a/substrate/frame/asset-conversion/ops/src/tests.rs b/substrate/frame/asset-conversion/ops/src/tests.rs index 86cdf20ccd9f..397e508a2392 100644 --- a/substrate/frame/asset-conversion/ops/src/tests.rs +++ b/substrate/frame/asset-conversion/ops/src/tests.rs @@ -28,7 +28,7 @@ use frame_support::{ }; #[test] -fn migrate_pool_account_id() { +fn migrate_pool_account_id_with_native() { new_test_ext().execute_with(|| { type PoolLocator = ::PoolLocator; let user = 1; @@ -112,7 +112,7 @@ fn migrate_pool_account_id() { } #[test] -fn migrate_pool_account_id_with_two_insufficient_assets() { +fn migrate_pool_account_id_with_insufficient_assets() { new_test_ext().execute_with(|| { type PoolLocator = ::PoolLocator; let user = 1; @@ -195,6 +195,90 @@ fn migrate_pool_account_id_with_two_insufficient_assets() { }); } +#[test] +fn migrate_pool_account_id_with_sufficient_assets() { + new_test_ext().execute_with(|| { + type PoolLocator = ::PoolLocator; + let user = 1; + let token_1 = NativeOrWithId::WithId(1); + let token_2 = NativeOrWithId::WithId(2); + let pool_id = PoolLocator::pool_id(&token_1, &token_2).unwrap(); + let lp_token = + ::PoolAssetId::initial_value().unwrap(); + + // setup pool and add provide some liquidity. + assert_ok!(NativeAndAssets::create(token_1.clone(), user, true, 1)); + assert_ok!(NativeAndAssets::create(token_2.clone(), user, true, 1)); + + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(user), + Box::new(token_1.clone()), + Box::new(token_2.clone()) + )); + + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 1, user, 20000)); + assert_ok!(Assets::mint(RuntimeOrigin::signed(user), 2, user, 1000)); + + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(user), + Box::new(token_1.clone()), + Box::new(token_2.clone()), + 10000, + 10, + 10000, + 10, + user, + )); + + // assert user's balance. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &user), 10000); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &user), 1000 - 10); + assert_eq!(PoolAssets::balance(lp_token, &user), 216); + + // record total issuances before migration. + let total_issuance_token1 = NativeAndAssets::total_issuance(token_1.clone()); + let total_issuance_token2 = NativeAndAssets::total_issuance(token_2.clone()); + let total_issuance_lp_token = PoolAssets::total_issuance(lp_token); + + let pool_account = PoolLocator::address(&pool_id).unwrap(); + let (prior_pool_account, new_pool_account) = + AssetConversionOps::addresses(&pool_id).unwrap(); + assert_eq!(pool_account, prior_pool_account); + + // assert pool's balances before migration. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &prior_pool_account), 10000); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &prior_pool_account), 10); + assert_eq!(PoolAssets::balance(lp_token, &prior_pool_account), 100); + + // migrate. + assert_ok!(AssetConversionOps::migrate_to_new_account( + RuntimeOrigin::signed(user), + Box::new(token_1.clone()), + Box::new(token_2.clone()), + )); + + // assert user's balance has not changed. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &user), 10000); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &user), 1000 - 10); + assert_eq!(PoolAssets::balance(lp_token, &user), 216); + + // assert pool's balance on new account id is same as on prior account id. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &new_pool_account), 10000); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &new_pool_account), 10); + assert_eq!(PoolAssets::balance(lp_token, &new_pool_account), 100); + + // assert pool's balance on prior account id is zero. + assert_eq!(NativeAndAssets::balance(token_1.clone(), &prior_pool_account), 0); + assert_eq!(NativeAndAssets::balance(token_2.clone(), &prior_pool_account), 0); + assert_eq!(PoolAssets::balance(lp_token, &prior_pool_account), 0); + + // assert total issuance has not changed. + assert_eq!(total_issuance_token1, NativeAndAssets::total_issuance(token_1)); + assert_eq!(total_issuance_token2, NativeAndAssets::total_issuance(token_2)); + assert_eq!(total_issuance_lp_token, PoolAssets::total_issuance(lp_token)); + }); +} + #[test] fn migrate_empty_pool_account_id() { new_test_ext().execute_with(|| { From 30b9a39c838c13a5d8eb58dc536e3ddc566da0f1 Mon Sep 17 00:00:00 2001 From: muharem Date: Mon, 26 Feb 2024 14:18:02 +0100 Subject: [PATCH 28/42] transfer total balance --- substrate/frame/asset-conversion/ops/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/substrate/frame/asset-conversion/ops/src/lib.rs b/substrate/frame/asset-conversion/ops/src/lib.rs index 3b703bf944f2..d0553c794a4a 100644 --- a/substrate/frame/asset-conversion/ops/src/lib.rs +++ b/substrate/frame/asset-conversion/ops/src/lib.rs @@ -168,9 +168,9 @@ pub mod pallet { let (asset1, asset2) = pool_id.clone(); // Assets that must be transferred to the new account id. - let balance1 = T::Assets::balance(asset1.clone(), &prior_account); - let balance2 = T::Assets::balance(asset2.clone(), &prior_account); - let lp_balance = T::PoolAssets::balance(info.lp_token.clone(), &prior_account); + let balance1 = T::Assets::total_balance(asset1.clone(), &prior_account); + let balance2 = T::Assets::total_balance(asset2.clone(), &prior_account); + let lp_balance = T::PoolAssets::total_balance(info.lp_token.clone(), &prior_account); ensure!(!balance1.is_zero(), Error::::ZeroBalance); ensure!(!balance2.is_zero(), Error::::ZeroBalance); From 414205c03ad0473d44b610c68ddcba5ebeddd982 Mon Sep 17 00:00:00 2001 From: muharem Date: Wed, 13 Mar 2024 12:10:41 +0100 Subject: [PATCH 29/42] review fixes --- substrate/frame/asset-conversion/ops/src/lib.rs | 7 ------- substrate/frame/asset-conversion/ops/src/tests.rs | 8 ++++---- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/substrate/frame/asset-conversion/ops/src/lib.rs b/substrate/frame/asset-conversion/ops/src/lib.rs index d0553c794a4a..bf44dd75bd78 100644 --- a/substrate/frame/asset-conversion/ops/src/lib.rs +++ b/substrate/frame/asset-conversion/ops/src/lib.rs @@ -135,13 +135,6 @@ pub mod pallet { PartialTransfer, } - #[pallet::hooks] - impl Hooks> for Pallet { - fn integrity_test() { - // TODO - } - } - /// Pallet's callable functions. #[pallet::call] impl Pallet { diff --git a/substrate/frame/asset-conversion/ops/src/tests.rs b/substrate/frame/asset-conversion/ops/src/tests.rs index 397e508a2392..84bbe6336747 100644 --- a/substrate/frame/asset-conversion/ops/src/tests.rs +++ b/substrate/frame/asset-conversion/ops/src/tests.rs @@ -38,7 +38,7 @@ fn migrate_pool_account_id_with_native() { let lp_token = ::PoolAssetId::initial_value().unwrap(); - // setup pool and add provide some liquidity. + // setup pool and provide some liquidity. assert_ok!(NativeAndAssets::create(token_2.clone(), user, false, 1)); assert_ok!(AssetConversion::create_pool( @@ -122,7 +122,7 @@ fn migrate_pool_account_id_with_insufficient_assets() { let lp_token = ::PoolAssetId::initial_value().unwrap(); - // setup pool and add provide some liquidity. + // setup pool and provide some liquidity. assert_ok!(NativeAndAssets::create(token_1.clone(), user, false, 1)); assert_ok!(NativeAndAssets::create(token_2.clone(), user, false, 1)); @@ -206,7 +206,7 @@ fn migrate_pool_account_id_with_sufficient_assets() { let lp_token = ::PoolAssetId::initial_value().unwrap(); - // setup pool and add provide some liquidity. + // setup pool and provide some liquidity. assert_ok!(NativeAndAssets::create(token_1.clone(), user, true, 1)); assert_ok!(NativeAndAssets::create(token_2.clone(), user, true, 1)); @@ -286,7 +286,7 @@ fn migrate_empty_pool_account_id() { let token_1 = NativeOrWithId::Native; let token_2 = NativeOrWithId::WithId(2); - // setup pool and add provide some liquidity. + // setup pool and provide some liquidity. assert_ok!(NativeAndAssets::create(token_2.clone(), user, false, 1)); assert_ok!(AssetConversion::create_pool( From 9f3acde784839ea93afed74775381aef3e301733 Mon Sep 17 00:00:00 2001 From: muharem Date: Mon, 18 Mar 2024 14:55:38 +0100 Subject: [PATCH 30/42] style fixes --- substrate/frame/asset-conversion/src/types.rs | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/substrate/frame/asset-conversion/src/types.rs b/substrate/frame/asset-conversion/src/types.rs index 4444b5b2f3e4..27c0e8e68805 100644 --- a/substrate/frame/asset-conversion/src/types.rs +++ b/substrate/frame/asset-conversion/src/types.rs @@ -82,12 +82,16 @@ where AccountIdConverter: for<'a> TryConvert<&'a (AssetKind, AssetKind), AccountId>, { fn pool_id(asset1: &AssetKind, asset2: &AssetKind) -> Result<(AssetKind, AssetKind), ()> { + if asset1 == asset2 { + return Err(()); + } let first = FirstAsset::get(); - match true { - _ if asset1 == asset2 => Err(()), - _ if first == *asset1 => Ok((first, asset2.clone())), - _ if first == *asset2 => Ok((first, asset1.clone())), - _ => Err(()), + if first == *asset1 { + Ok((first, asset2.clone())) + } else if first == *asset2 { + Ok((first, asset1.clone())) + } else { + Err(()) } } fn address(id: &(AssetKind, AssetKind)) -> Result { @@ -108,10 +112,12 @@ where AccountIdConverter: for<'a> TryConvert<&'a (AssetKind, AssetKind), AccountId>, { fn pool_id(asset1: &AssetKind, asset2: &AssetKind) -> Result<(AssetKind, AssetKind), ()> { - match true { - _ if asset1 > asset2 => Ok((asset2.clone(), asset1.clone())), - _ if asset1 < asset2 => Ok((asset1.clone(), asset2.clone())), - _ => Err(()), + if asset1 > asset2 { + Ok((asset2.clone(), asset1.clone())) + } else if asset1 < asset2 { + Ok((asset1.clone(), asset2.clone())) + } else { + Err(()) } } fn address(id: &(AssetKind, AssetKind)) -> Result { @@ -146,8 +152,8 @@ where Seed: Get, { fn try_convert(id: &PoolId) -> Result { - let encoded = sp_io::hashing::blake2_256(&Encode::encode(&(Seed::get(), id))[..]); - Decode::decode(&mut TrailingZeroInput::new(encoded.as_ref())).map_err(|_| id) + sp_io::hashing::blake2_256(&Encode::encode(&(Seed::get(), id))[..]) + .using_encoded(|e| Decode::decode(&mut TrailingZeroInput::new(e)).map_err(|_| id)) } } @@ -159,7 +165,7 @@ where AccountId: Decode, { fn try_convert(id: &PoolId) -> Result { - let encoded = sp_io::hashing::blake2_256(&Encode::encode(id)[..]); - Decode::decode(&mut TrailingZeroInput::new(encoded.as_ref())).map_err(|_| id) + sp_io::hashing::blake2_256(&Encode::encode(id)[..]) + .using_encoded(|e| Decode::decode(&mut TrailingZeroInput::new(e)).map_err(|_| id)) } } From b756f5f5793969db24a6453d4492773f5037e01e Mon Sep 17 00:00:00 2001 From: muharem Date: Sat, 13 Apr 2024 16:29:18 +0200 Subject: [PATCH 31/42] folder for weights --- substrate/frame/asset-conversion-ops/src/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 substrate/frame/asset-conversion-ops/src/.gitkeep diff --git a/substrate/frame/asset-conversion-ops/src/.gitkeep b/substrate/frame/asset-conversion-ops/src/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 From 71c09eee23d7beed4e97c7136695bed8ab2efa4a Mon Sep 17 00:00:00 2001 From: command-bot <> Date: Sat, 13 Apr 2024 15:06:47 +0000 Subject: [PATCH 32/42] ".git/.scripts/commands/bench/bench.sh" --subcommand=pallet --runtime=dev --target_dir=substrate --pallet=pallet_asset_conversion_ops --- .../frame/asset-conversion-ops/src/weights.rs | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 substrate/frame/asset-conversion-ops/src/weights.rs diff --git a/substrate/frame/asset-conversion-ops/src/weights.rs b/substrate/frame/asset-conversion-ops/src/weights.rs new file mode 100644 index 000000000000..9e7379c50156 --- /dev/null +++ b/substrate/frame/asset-conversion-ops/src/weights.rs @@ -0,0 +1,104 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for `pallet_asset_conversion_ops` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-04-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` + +// Executed Command: +// target/production/substrate-node +// benchmark +// pallet +// --steps=50 +// --repeat=20 +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_asset_conversion_ops +// --chain=dev +// --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/asset-conversion-ops/src/weights.rs +// --template=./substrate/.maintain/frame-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use core::marker::PhantomData; + +/// Weight functions needed for `pallet_asset_conversion_ops`. +pub trait WeightInfo { + fn migrate_to_new_account() -> Weight; +} + +/// Weights for `pallet_asset_conversion_ops` using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: `AssetConversion::Pools` (r:1 w:0) + /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:4 w:4) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Account` (r:2 w:2) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:2 w:2) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn migrate_to_new_account() -> Weight { + // Proof Size summary in bytes: + // Measured: `1762` + // Estimated: `11426` + // Minimum execution time: 223_850_000 picoseconds. + Weight::from_parts(231_676_000, 11426) + .saturating_add(T::DbWeight::get().reads(12_u64)) + .saturating_add(T::DbWeight::get().writes(11_u64)) + } +} + +// For backwards compatibility and tests. +impl WeightInfo for () { + /// Storage: `AssetConversion::Pools` (r:1 w:0) + /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) + /// Storage: `Assets::Account` (r:4 w:4) + /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Account` (r:2 w:2) + /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) + /// Storage: `PoolAssets::Asset` (r:1 w:1) + /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `Assets::Asset` (r:2 w:2) + /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn migrate_to_new_account() -> Weight { + // Proof Size summary in bytes: + // Measured: `1762` + // Estimated: `11426` + // Minimum execution time: 223_850_000 picoseconds. + Weight::from_parts(231_676_000, 11426) + .saturating_add(RocksDbWeight::get().reads(12_u64)) + .saturating_add(RocksDbWeight::get().writes(11_u64)) + } +} From 41b9f9ee2657c2019e34b0e3f8920600a1c3e78c Mon Sep 17 00:00:00 2001 From: muharem Date: Sat, 13 Apr 2024 17:17:54 +0200 Subject: [PATCH 33/42] weights --- .../frame/asset-conversion-ops/src/.gitkeep | 0 .../frame/asset-conversion-ops/src/weights.rs | 104 ------------------ .../frame/asset-conversion/ops/src/weights.rs | 28 ++--- 3 files changed, 15 insertions(+), 117 deletions(-) delete mode 100644 substrate/frame/asset-conversion-ops/src/.gitkeep delete mode 100644 substrate/frame/asset-conversion-ops/src/weights.rs diff --git a/substrate/frame/asset-conversion-ops/src/.gitkeep b/substrate/frame/asset-conversion-ops/src/.gitkeep deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/substrate/frame/asset-conversion-ops/src/weights.rs b/substrate/frame/asset-conversion-ops/src/weights.rs deleted file mode 100644 index 9e7379c50156..000000000000 --- a/substrate/frame/asset-conversion-ops/src/weights.rs +++ /dev/null @@ -1,104 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Autogenerated weights for `pallet_asset_conversion_ops` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-04-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` - -// Executed Command: -// target/production/substrate-node -// benchmark -// pallet -// --steps=50 -// --repeat=20 -// --extrinsic=* -// --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_asset_conversion_ops -// --chain=dev -// --header=./substrate/HEADER-APACHE2 -// --output=./substrate/frame/asset-conversion-ops/src/weights.rs -// --template=./substrate/.maintain/frame-weight-template.hbs - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(missing_docs)] - -use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; -use core::marker::PhantomData; - -/// Weight functions needed for `pallet_asset_conversion_ops`. -pub trait WeightInfo { - fn migrate_to_new_account() -> Weight; -} - -/// Weights for `pallet_asset_conversion_ops` using the Substrate node and recommended hardware. -pub struct SubstrateWeight(PhantomData); -impl WeightInfo for SubstrateWeight { - /// Storage: `AssetConversion::Pools` (r:1 w:0) - /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:4 w:4) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `PoolAssets::Account` (r:2 w:2) - /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `PoolAssets::Asset` (r:1 w:1) - /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:2 w:2) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn migrate_to_new_account() -> Weight { - // Proof Size summary in bytes: - // Measured: `1762` - // Estimated: `11426` - // Minimum execution time: 223_850_000 picoseconds. - Weight::from_parts(231_676_000, 11426) - .saturating_add(T::DbWeight::get().reads(12_u64)) - .saturating_add(T::DbWeight::get().writes(11_u64)) - } -} - -// For backwards compatibility and tests. -impl WeightInfo for () { - /// Storage: `AssetConversion::Pools` (r:1 w:0) - /// Proof: `AssetConversion::Pools` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) - /// Storage: `Assets::Account` (r:4 w:4) - /// Proof: `Assets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `PoolAssets::Account` (r:2 w:2) - /// Proof: `PoolAssets::Account` (`max_values`: None, `max_size`: Some(134), added: 2609, mode: `MaxEncodedLen`) - /// Storage: `PoolAssets::Asset` (r:1 w:1) - /// Proof: `PoolAssets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `Assets::Asset` (r:2 w:2) - /// Proof: `Assets::Asset` (`max_values`: None, `max_size`: Some(210), added: 2685, mode: `MaxEncodedLen`) - /// Storage: `System::Account` (r:2 w:2) - /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) - fn migrate_to_new_account() -> Weight { - // Proof Size summary in bytes: - // Measured: `1762` - // Estimated: `11426` - // Minimum execution time: 223_850_000 picoseconds. - Weight::from_parts(231_676_000, 11426) - .saturating_add(RocksDbWeight::get().reads(12_u64)) - .saturating_add(RocksDbWeight::get().writes(11_u64)) - } -} diff --git a/substrate/frame/asset-conversion/ops/src/weights.rs b/substrate/frame/asset-conversion/ops/src/weights.rs index 4a907e83410a..9e7379c50156 100644 --- a/substrate/frame/asset-conversion/ops/src/weights.rs +++ b/substrate/frame/asset-conversion/ops/src/weights.rs @@ -7,7 +7,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -18,23 +18,25 @@ //! Autogenerated weights for `pallet_asset_conversion_ops` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-15, STEPS: `30`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-04-13, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `cob`, CPU: `` +//! HOSTNAME: `runner-anb7yjbi-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ./target/debug/substrate-node +// target/production/substrate-node // benchmark // pallet -// --chain=dev -// --steps=30 -// --repeat=2 -// --pallet=pallet-asset-conversion-ops +// --steps=50 +// --repeat=20 // --extrinsic=* // --wasm-execution=compiled // --heap-pages=4096 -// --output=./substrate/frame/asset-conversion/ops/src/._weights0.rs +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_asset_conversion_ops +// --chain=dev +// --header=./substrate/HEADER-APACHE2 +// --output=./substrate/frame/asset-conversion-ops/src/weights.rs // --template=./substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] @@ -69,8 +71,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1762` // Estimated: `11426` - // Minimum execution time: 2_460_000_000 picoseconds. - Weight::from_parts(2_524_000_000, 11426) + // Minimum execution time: 223_850_000 picoseconds. + Weight::from_parts(231_676_000, 11426) .saturating_add(T::DbWeight::get().reads(12_u64)) .saturating_add(T::DbWeight::get().writes(11_u64)) } @@ -94,8 +96,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1762` // Estimated: `11426` - // Minimum execution time: 2_460_000_000 picoseconds. - Weight::from_parts(2_524_000_000, 11426) + // Minimum execution time: 223_850_000 picoseconds. + Weight::from_parts(231_676_000, 11426) .saturating_add(RocksDbWeight::get().reads(12_u64)) .saturating_add(RocksDbWeight::get().writes(11_u64)) } From 8ce6f7c2aa165042334ece6bcc5c116ad693c719 Mon Sep 17 00:00:00 2001 From: muharem Date: Mon, 15 Apr 2024 14:33:51 +0200 Subject: [PATCH 34/42] update reset team trait --- substrate/frame/assets/src/impl_fungibles.rs | 1 - .../frame/support/src/traits/tokens/fungibles/lifetime.rs | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/substrate/frame/assets/src/impl_fungibles.rs b/substrate/frame/assets/src/impl_fungibles.rs index 30a90aca8d07..e4cdc670c179 100644 --- a/substrate/frame/assets/src/impl_fungibles.rs +++ b/substrate/frame/assets/src/impl_fungibles.rs @@ -310,7 +310,6 @@ impl, I: 'static> fungibles::InspectEnumerable for Pa } impl, I: 'static> fungibles::ResetTeam for Pallet { - type AssetId = T::AssetId; fn reset_team( id: T::AssetId, owner: T::AccountId, diff --git a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs index f94d91094539..e498eb7523fa 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs @@ -35,9 +35,7 @@ pub trait Create: Inspect { } /// Trait for resetting the team configuration of an existing fungible asset. -pub trait ResetTeam { - /// Means of identifying one asset class from another. - type AssetId: AssetId; +pub trait ResetTeam: Inspect { /// Reset the team for the asset with the given `id`. /// /// ### Parameters From 9247584b38f361eb165d302eab87495e8adffa96 Mon Sep 17 00:00:00 2001 From: muharem Date: Mon, 15 Apr 2024 14:21:44 +0200 Subject: [PATCH 35/42] update refund trait --- substrate/frame/assets/src/impl_fungibles.rs | 2 -- substrate/frame/assets/src/lib.rs | 2 +- .../support/src/traits/tokens/fungible/union_of.rs | 7 ++----- .../support/src/traits/tokens/fungibles/lifetime.rs | 6 +----- .../support/src/traits/tokens/fungibles/union_of.rs | 10 +++------- 5 files changed, 7 insertions(+), 20 deletions(-) diff --git a/substrate/frame/assets/src/impl_fungibles.rs b/substrate/frame/assets/src/impl_fungibles.rs index e4cdc670c179..5bddc7ab51b5 100644 --- a/substrate/frame/assets/src/impl_fungibles.rs +++ b/substrate/frame/assets/src/impl_fungibles.rs @@ -322,8 +322,6 @@ impl, I: 'static> fungibles::ResetTeam for Pallet, I: 'static> fungibles::Refund for Pallet { - type AssetId = T::AssetId; - type Balance = DepositBalanceOf; fn deposit_held(id: Self::AssetId, who: T::AccountId) -> Option<(T::AccountId, Self::Balance)> { use ExistenceReason::*; match Account::::get(&id, &who).ok_or(Error::::NoDeposit).ok()?.reason { diff --git a/substrate/frame/assets/src/lib.rs b/substrate/frame/assets/src/lib.rs index 72363c982124..99b3dba21845 100644 --- a/substrate/frame/assets/src/lib.rs +++ b/substrate/frame/assets/src/lib.rs @@ -305,7 +305,7 @@ pub mod pallet { /// The currency mechanism. #[pallet::no_default] - type Currency: ReservableCurrency; + type Currency: ReservableCurrency; /// Standard asset class creation is only allowed if the origin attempting it and the /// asset class are in this set. diff --git a/substrate/frame/support/src/traits/tokens/fungible/union_of.rs b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs index db44b2f43a4e..2eb61e4c0724 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/union_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs @@ -928,15 +928,12 @@ impl< impl< Left: fungible::Inspect, - Right: fungibles::Inspect + fungibles::Refund, - Criterion: Convert>::AssetId>>, + Right: fungibles::Inspect + fungibles::Refund, + Criterion: Convert>::AssetId>>, AssetKind: AssetId, AccountId, > fungibles::Refund for UnionOf { - type AssetId = AssetKind; - type Balance = >::Balance; - fn deposit_held(asset: AssetKind, who: AccountId) -> Option<(AccountId, Self::Balance)> { match Criterion::convert(asset) { Left(()) => None, diff --git a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs index e498eb7523fa..c0de98088ea2 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs @@ -54,11 +54,7 @@ pub trait ResetTeam: Inspect { } /// Trait for refunding the deposit of a target asset account. -pub trait Refund { - /// Means of identifying one asset class from another. - type AssetId: AssetId; - /// Scalar type for representing balance of an account. - type Balance: Balance; +pub trait Refund: Inspect { /// Returns the amount of account deposit and depositor address, if any. fn deposit_held(id: Self::AssetId, who: AccountId) -> Option<(AccountId, Self::Balance)>; /// Return the deposit (if any) of a target asset account. diff --git a/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs b/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs index 2c7d4bab7baa..ebd7f5f3f5f8 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs @@ -907,22 +907,18 @@ impl< impl< Left: fungibles::Inspect + fungibles::Refund, - Right: fungibles::Inspect - + fungibles::Refund>::Balance>, + Right: fungibles::Inspect + fungibles::Refund, Criterion: Convert< AssetKind, Either< - >::AssetId, - >::AssetId, + >::AssetId, + >::AssetId, >, >, AssetKind: AssetId, AccountId, > fungibles::Refund for UnionOf { - type AssetId = AssetKind; - type Balance = >::Balance; - fn deposit_held(asset: AssetKind, who: AccountId) -> Option<(AccountId, Self::Balance)> { match Criterion::convert(asset) { Left(a) => >::deposit_held(a, who), From 6915afe4b88e838d2f6c69f37e62c7b84241ec42 Mon Sep 17 00:00:00 2001 From: muharem Date: Mon, 15 Apr 2024 15:13:04 +0200 Subject: [PATCH 36/42] remove unused imports --- substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs index c0de98088ea2..b240e332b7bb 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs @@ -20,7 +20,6 @@ //! See the [`crate::traits::fungibles`] doc for more information about fungibles traits. use super::Inspect; -use crate::traits::tokens::{AssetId, Balance}; use sp_runtime::{DispatchError, DispatchResult}; /// Trait for providing the ability to create new fungible assets. From 73986965cb133d6dd0a06763268f941baec41705 Mon Sep 17 00:00:00 2001 From: muharem Date: Mon, 15 Apr 2024 17:15:18 +0200 Subject: [PATCH 37/42] Revert "update refund trait" This reverts commit 9247584b38f361eb165d302eab87495e8adffa96. --- substrate/frame/assets/src/impl_fungibles.rs | 2 ++ substrate/frame/assets/src/lib.rs | 2 +- .../support/src/traits/tokens/fungible/union_of.rs | 7 +++++-- .../support/src/traits/tokens/fungibles/lifetime.rs | 6 +++++- .../support/src/traits/tokens/fungibles/union_of.rs | 10 +++++++--- 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/substrate/frame/assets/src/impl_fungibles.rs b/substrate/frame/assets/src/impl_fungibles.rs index 5bddc7ab51b5..e4cdc670c179 100644 --- a/substrate/frame/assets/src/impl_fungibles.rs +++ b/substrate/frame/assets/src/impl_fungibles.rs @@ -322,6 +322,8 @@ impl, I: 'static> fungibles::ResetTeam for Pallet, I: 'static> fungibles::Refund for Pallet { + type AssetId = T::AssetId; + type Balance = DepositBalanceOf; fn deposit_held(id: Self::AssetId, who: T::AccountId) -> Option<(T::AccountId, Self::Balance)> { use ExistenceReason::*; match Account::::get(&id, &who).ok_or(Error::::NoDeposit).ok()?.reason { diff --git a/substrate/frame/assets/src/lib.rs b/substrate/frame/assets/src/lib.rs index 99b3dba21845..72363c982124 100644 --- a/substrate/frame/assets/src/lib.rs +++ b/substrate/frame/assets/src/lib.rs @@ -305,7 +305,7 @@ pub mod pallet { /// The currency mechanism. #[pallet::no_default] - type Currency: ReservableCurrency; + type Currency: ReservableCurrency; /// Standard asset class creation is only allowed if the origin attempting it and the /// asset class are in this set. diff --git a/substrate/frame/support/src/traits/tokens/fungible/union_of.rs b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs index 2eb61e4c0724..db44b2f43a4e 100644 --- a/substrate/frame/support/src/traits/tokens/fungible/union_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungible/union_of.rs @@ -928,12 +928,15 @@ impl< impl< Left: fungible::Inspect, - Right: fungibles::Inspect + fungibles::Refund, - Criterion: Convert>::AssetId>>, + Right: fungibles::Inspect + fungibles::Refund, + Criterion: Convert>::AssetId>>, AssetKind: AssetId, AccountId, > fungibles::Refund for UnionOf { + type AssetId = AssetKind; + type Balance = >::Balance; + fn deposit_held(asset: AssetKind, who: AccountId) -> Option<(AccountId, Self::Balance)> { match Criterion::convert(asset) { Left(()) => None, diff --git a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs index b240e332b7bb..9f55a8751281 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs @@ -53,7 +53,11 @@ pub trait ResetTeam: Inspect { } /// Trait for refunding the deposit of a target asset account. -pub trait Refund: Inspect { +pub trait Refund { + /// Means of identifying one asset class from another. + type AssetId: AssetId; + /// Scalar type for representing balance of an account. + type Balance: Balance; /// Returns the amount of account deposit and depositor address, if any. fn deposit_held(id: Self::AssetId, who: AccountId) -> Option<(AccountId, Self::Balance)>; /// Return the deposit (if any) of a target asset account. diff --git a/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs b/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs index ebd7f5f3f5f8..2c7d4bab7baa 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/union_of.rs @@ -907,18 +907,22 @@ impl< impl< Left: fungibles::Inspect + fungibles::Refund, - Right: fungibles::Inspect + fungibles::Refund, + Right: fungibles::Inspect + + fungibles::Refund>::Balance>, Criterion: Convert< AssetKind, Either< - >::AssetId, - >::AssetId, + >::AssetId, + >::AssetId, >, >, AssetKind: AssetId, AccountId, > fungibles::Refund for UnionOf { + type AssetId = AssetKind; + type Balance = >::Balance; + fn deposit_held(asset: AssetKind, who: AccountId) -> Option<(AccountId, Self::Balance)> { match Criterion::convert(asset) { Left(a) => >::deposit_held(a, who), From 7bfd1ff477384e2ba8a56338b18d5c767ce9d172 Mon Sep 17 00:00:00 2001 From: muharem Date: Mon, 15 Apr 2024 17:15:30 +0200 Subject: [PATCH 38/42] Revert "remove unused imports" This reverts commit 6915afe4b88e838d2f6c69f37e62c7b84241ec42. --- substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs index 9f55a8751281..e498eb7523fa 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs @@ -20,6 +20,7 @@ //! See the [`crate::traits::fungibles`] doc for more information about fungibles traits. use super::Inspect; +use crate::traits::tokens::{AssetId, Balance}; use sp_runtime::{DispatchError, DispatchResult}; /// Trait for providing the ability to create new fungible assets. From 7a579a9cd5c228c44e45628ade3699e9dbd7a791 Mon Sep 17 00:00:00 2001 From: muharem Date: Mon, 15 Apr 2024 17:16:12 +0200 Subject: [PATCH 39/42] update doc --- substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs index e498eb7523fa..07f41c885cd5 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs @@ -57,7 +57,7 @@ pub trait ResetTeam: Inspect { pub trait Refund { /// Means of identifying one asset class from another. type AssetId: AssetId; - /// Scalar type for representing balance of an account. + /// Scalar type for representing deposit balance of an account. type Balance: Balance; /// Returns the amount of account deposit and depositor address, if any. fn deposit_held(id: Self::AssetId, who: AccountId) -> Option<(AccountId, Self::Balance)>; From fba27bf3e4c5592867c1a961a29bc4ec86222fd3 Mon Sep 17 00:00:00 2001 From: muharem Date: Tue, 16 Apr 2024 15:12:10 +0200 Subject: [PATCH 40/42] update pr doc and use default configs for pallets in test env --- prdoc/pr_3250.prdoc | 6 +- .../frame/asset-conversion/ops/src/mock.rs | 91 +++---------------- 2 files changed, 16 insertions(+), 81 deletions(-) diff --git a/prdoc/pr_3250.prdoc b/prdoc/pr_3250.prdoc index 023b723d21b4..dbf1b8aeba8e 100644 --- a/prdoc/pr_3250.prdoc +++ b/prdoc/pr_3250.prdoc @@ -7,8 +7,10 @@ doc: - audience: Runtime Dev description: | Introduce PalletId as an additional seed parameter for pool's account id derivation. - The PR also introduces the fungibles::lifetime::ResetTeam and fungible::lifetime::Refund traits, - which facilitate the migration of pools to the new account IDs. + The PR also introduces the `pallet_asset_conversion_ops` pallet with a call to migrate + a pool to the new account. Additionally `fungibles::lifetime::ResetTeam` and + `fungible::lifetime::Refund` traits, to facilitate the migration functionality. crates: - name: pallet-asset-conversion + bump: minor diff --git a/substrate/frame/asset-conversion/ops/src/mock.rs b/substrate/frame/asset-conversion/ops/src/mock.rs index 2c9a3525f602..9454b3a9ad44 100644 --- a/substrate/frame/asset-conversion/ops/src/mock.rs +++ b/substrate/frame/asset-conversion/ops/src/mock.rs @@ -29,18 +29,14 @@ use frame_support::{ fungible::{NativeFromLeft, NativeOrWithId, UnionOf}, imbalance::ResolveAssetTo, }, - AsEnsureOriginWithArg, ConstU128, ConstU32, ConstU64, + AsEnsureOriginWithArg, ConstU32, ConstU64, }, PalletId, }; use frame_system::{EnsureSigned, EnsureSignedBy}; use pallet_asset_conversion::{self, AccountIdConverter, AccountIdConverterNoSeed, Ascending}; use sp_arithmetic::Permill; -use sp_core::H256; -use sp_runtime::{ - traits::{AccountIdConversion, BlakeTwo256, IdentityLookup}, - BuildStorage, -}; +use sp_runtime::{traits::AccountIdConversion, BuildStorage}; type Block = frame_system::mocking::MockBlock; @@ -58,94 +54,31 @@ construct_runtime!( #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] impl frame_system::Config for Test { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type RuntimeOrigin = RuntimeOrigin; - type RuntimeCall = RuntimeCall; - type Nonce = u64; - type Hash = H256; - type Hashing = BlakeTwo256; - type AccountId = u128; - type Lookup = IdentityLookup; type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type DbWeight = (); - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; + type AccountData = pallet_balances::AccountData; } +#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] impl pallet_balances::Config for Test { - type Balance = u128; - type DustRemoval = (); - type RuntimeEvent = RuntimeEvent; - type ExistentialDeposit = ConstU128<100>; - type AccountStore = System; - type WeightInfo = (); - type MaxLocks = (); - type MaxReserves = ConstU32<50>; type ReserveIdentifier = [u8; 8]; - type FreezeIdentifier = (); - type MaxFreezes = (); - type RuntimeHoldReason = (); - type RuntimeFreezeReason = (); + type AccountStore = System; } +#[derive_impl(pallet_assets::config_preludes::TestDefaultConfig)] impl pallet_assets::Config for Test { - type RuntimeEvent = RuntimeEvent; - type Balance = u128; - type RemoveItemsLimit = ConstU32<1000>; - type AssetId = u32; - type AssetIdParameter = u32; type Currency = Balances; type CreateOrigin = AsEnsureOriginWithArg>; type ForceOrigin = frame_system::EnsureRoot; - type AssetDeposit = ConstU128<1>; - type AssetAccountDeposit = ConstU128<10>; - type MetadataDepositBase = ConstU128<1>; - type MetadataDepositPerByte = ConstU128<1>; - type ApprovalDeposit = ConstU128<1>; - type StringLimit = ConstU32<50>; type Freezer = (); - type Extra = (); - type WeightInfo = (); - type CallbackHandle = (); - pallet_assets::runtime_benchmarks_enabled! { - type BenchmarkHelper = (); - } } +#[derive_impl(pallet_assets::config_preludes::TestDefaultConfig)] impl pallet_assets::Config for Test { - type RuntimeEvent = RuntimeEvent; - type Balance = u128; - type RemoveItemsLimit = ConstU32<1000>; - type AssetId = u32; - type AssetIdParameter = u32; type Currency = Balances; type CreateOrigin = AsEnsureOriginWithArg>; type ForceOrigin = frame_system::EnsureRoot; - type AssetDeposit = ConstU128<0>; - type AssetAccountDeposit = ConstU128<0>; - type MetadataDepositBase = ConstU128<0>; - type MetadataDepositPerByte = ConstU128<0>; - type ApprovalDeposit = ConstU128<0>; - type StringLimit = ConstU32<50>; type Freezer = (); - type Extra = (); - type WeightInfo = (); - type CallbackHandle = (); - pallet_assets::runtime_benchmarks_enabled! { - type BenchmarkHelper = (); - } } parameter_types! { @@ -155,13 +88,13 @@ parameter_types! { } ord_parameter_types! { - pub const AssetConversionOrigin: u128 = AccountIdConversion::::into_account_truncating(&AssetConversionPalletId::get()); + pub const AssetConversionOrigin: u64 = AccountIdConversion::::into_account_truncating(&AssetConversionPalletId::get()); } -pub type NativeAndAssets = UnionOf, u128>; +pub type NativeAndAssets = UnionOf, u64>; pub type PoolIdToAccountId = AccountIdConverter, NativeOrWithId)>; -pub type AscendingLocator = Ascending, PoolIdToAccountId>; +pub type AscendingLocator = Ascending, PoolIdToAccountId>; impl pallet_asset_conversion::Config for Test { type RuntimeEvent = RuntimeEvent; @@ -173,7 +106,7 @@ impl pallet_asset_conversion::Config for Test { type PoolLocator = AscendingLocator; type PoolAssetId = u32; type PoolAssets = PoolAssets; - type PoolSetupFee = ConstU128<100>; + type PoolSetupFee = ConstU64<100>; type PoolSetupFeeAsset = Native; type PoolSetupFeeTarget = ResolveAssetTo; type PalletId = AssetConversionPalletId; @@ -181,7 +114,7 @@ impl pallet_asset_conversion::Config for Test { type LPFee = ConstU32<3>; type LiquidityWithdrawalFee = LiquidityWithdrawalFee; type MaxSwapPathLength = ConstU32<4>; - type MintMinLiquidity = ConstU128<100>; + type MintMinLiquidity = ConstU64<100>; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = (); } From 82b0acae4f27b43d9008d1c8640674bd4ec6fb9e Mon Sep 17 00:00:00 2001 From: muharem Date: Tue, 16 Apr 2024 16:29:48 +0200 Subject: [PATCH 41/42] update docs --- Cargo.lock | 2 +- substrate/frame/asset-conversion/ops/Cargo.toml | 2 +- substrate/frame/asset-conversion/ops/src/lib.rs | 4 +++- .../frame/support/src/traits/tokens/fungibles/lifetime.rs | 6 +++++- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5fb22c7f1b32..c39af2f12df2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9518,7 +9518,7 @@ dependencies = [ [[package]] name = "pallet-asset-conversion-ops" -version = "0.0.1" +version = "0.1.0" dependencies = [ "frame-benchmarking", "frame-support", diff --git a/substrate/frame/asset-conversion/ops/Cargo.toml b/substrate/frame/asset-conversion/ops/Cargo.toml index 56a12c6bf0f5..e421e904a3a1 100644 --- a/substrate/frame/asset-conversion/ops/Cargo.toml +++ b/substrate/frame/asset-conversion/ops/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pallet-asset-conversion-ops" -version = "0.0.1" +version = "0.1.0" authors.workspace = true edition.workspace = true license = "Apache-2.0" diff --git a/substrate/frame/asset-conversion/ops/src/lib.rs b/substrate/frame/asset-conversion/ops/src/lib.rs index bf44dd75bd78..6ad0a7e21cd7 100644 --- a/substrate/frame/asset-conversion/ops/src/lib.rs +++ b/substrate/frame/asset-conversion/ops/src/lib.rs @@ -25,7 +25,9 @@ //! ## Overview //! //! This suite allows you to perform the following operations: -//! - Perform migration to update account ID derivation methods for existing pools. +//! - Perform migration to update account ID derivation methods for existing pools. The migration +//! operation ensures that the required accounts are created, existing account deposits are +//! transferred, and liquidity is moved to the new accounts. #![deny(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] diff --git a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs index 07f41c885cd5..4a9c8ab1c047 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs @@ -53,7 +53,11 @@ pub trait ResetTeam: Inspect { ) -> DispatchResult; } -/// Trait for refunding the deposit of a target asset account. +/// Trait for refunding the existence deposit of a target asset account. +/// +/// The existence deposit might by necessary and present in cases where the asset held by the +/// account is insufficient for the required storage, or when the system cannot provide a consumer +/// reference for any reason. pub trait Refund { /// Means of identifying one asset class from another. type AssetId: AssetId; From 496e2d76bf1df4160971542e41be9d6dd7c38702 Mon Sep 17 00:00:00 2001 From: muharem Date: Tue, 16 Apr 2024 17:32:56 +0200 Subject: [PATCH 42/42] move reset team trait to roles module --- prdoc/pr_3250.prdoc | 2 +- .../frame/asset-conversion/ops/src/lib.rs | 2 +- substrate/frame/assets/src/impl_fungibles.rs | 2 +- .../src/traits/tokens/fungibles/lifetime.rs | 19 ----------------- .../src/traits/tokens/fungibles/mod.rs | 2 +- .../src/traits/tokens/fungibles/roles.rs | 21 +++++++++++++++++++ 6 files changed, 25 insertions(+), 23 deletions(-) diff --git a/prdoc/pr_3250.prdoc b/prdoc/pr_3250.prdoc index dbf1b8aeba8e..77ea725073e6 100644 --- a/prdoc/pr_3250.prdoc +++ b/prdoc/pr_3250.prdoc @@ -8,7 +8,7 @@ doc: description: | Introduce PalletId as an additional seed parameter for pool's account id derivation. The PR also introduces the `pallet_asset_conversion_ops` pallet with a call to migrate - a pool to the new account. Additionally `fungibles::lifetime::ResetTeam` and + a pool to the new account. Additionally `fungibles::roles::ResetTeam` and `fungible::lifetime::Refund` traits, to facilitate the migration functionality. crates: diff --git a/substrate/frame/asset-conversion/ops/src/lib.rs b/substrate/frame/asset-conversion/ops/src/lib.rs index 6ad0a7e21cd7..6cc7bfa2e996 100644 --- a/substrate/frame/asset-conversion/ops/src/lib.rs +++ b/substrate/frame/asset-conversion/ops/src/lib.rs @@ -44,7 +44,7 @@ pub use weights::WeightInfo; use frame_support::traits::{ fungible::{Inspect as FungibleInspect, Mutate as FungibleMutate}, - fungibles::{Inspect, Mutate, Refund, ResetTeam}, + fungibles::{roles::ResetTeam, Inspect, Mutate, Refund}, tokens::{Fortitude, Precision, Preservation}, AccountTouch, }; diff --git a/substrate/frame/assets/src/impl_fungibles.rs b/substrate/frame/assets/src/impl_fungibles.rs index e4cdc670c179..9f837a604341 100644 --- a/substrate/frame/assets/src/impl_fungibles.rs +++ b/substrate/frame/assets/src/impl_fungibles.rs @@ -309,7 +309,7 @@ impl, I: 'static> fungibles::InspectEnumerable for Pa } } -impl, I: 'static> fungibles::ResetTeam for Pallet { +impl, I: 'static> fungibles::roles::ResetTeam for Pallet { fn reset_team( id: T::AssetId, owner: T::AccountId, diff --git a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs index 4a9c8ab1c047..7f882c1fc4fe 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/lifetime.rs @@ -34,25 +34,6 @@ pub trait Create: Inspect { ) -> DispatchResult; } -/// Trait for resetting the team configuration of an existing fungible asset. -pub trait ResetTeam: Inspect { - /// Reset the team for the asset with the given `id`. - /// - /// ### Parameters - /// - `id`: The identifier of the asset for which the team is being reset. - /// - `owner`: The new `owner` account for the asset. - /// - `admin`: The new `admin` account for the asset. - /// - `issuer`: The new `issuer` account for the asset. - /// - `freezer`: The new `freezer` account for the asset. - fn reset_team( - id: Self::AssetId, - owner: AccountId, - admin: AccountId, - issuer: AccountId, - freezer: AccountId, - ) -> DispatchResult; -} - /// Trait for refunding the existence deposit of a target asset account. /// /// The existence deposit might by necessary and present in cases where the asset held by the diff --git a/substrate/frame/support/src/traits/tokens/fungibles/mod.rs b/substrate/frame/support/src/traits/tokens/fungibles/mod.rs index b6d50066a3e7..8b4ea4d13cf9 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/mod.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/mod.rs @@ -44,7 +44,7 @@ pub use hold::{ Unbalanced as UnbalancedHold, }; pub use imbalance::{Credit, Debt, HandleImbalanceDrop, Imbalance}; -pub use lifetime::{Create, Destroy, Refund, ResetTeam}; +pub use lifetime::{Create, Destroy, Refund}; pub use regular::{ Balanced, DecreaseIssuance, Dust, IncreaseIssuance, Inspect, Mutate, Unbalanced, }; diff --git a/substrate/frame/support/src/traits/tokens/fungibles/roles.rs b/substrate/frame/support/src/traits/tokens/fungibles/roles.rs index 4f95ad8368c2..3e68d6b94518 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/roles.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/roles.rs @@ -19,6 +19,8 @@ //! //! See the [`crate::traits::fungibles`] doc for more information about fungibles traits. +use sp_runtime::DispatchResult; + pub trait Inspect: super::Inspect { // Get owner for an AssetId. fn owner(asset: Self::AssetId) -> Option; @@ -29,3 +31,22 @@ pub trait Inspect: super::Inspect { // Get freezer for an AssetId. fn freezer(asset: Self::AssetId) -> Option; } + +/// Trait for resetting the team configuration of an existing fungible asset. +pub trait ResetTeam: super::Inspect { + /// Reset the team for the asset with the given `id`. + /// + /// ### Parameters + /// - `id`: The identifier of the asset for which the team is being reset. + /// - `owner`: The new `owner` account for the asset. + /// - `admin`: The new `admin` account for the asset. + /// - `issuer`: The new `issuer` account for the asset. + /// - `freezer`: The new `freezer` account for the asset. + fn reset_team( + id: Self::AssetId, + owner: AccountId, + admin: AccountId, + issuer: AccountId, + freezer: AccountId, + ) -> DispatchResult; +}