diff --git a/substrate/frame/asset-conversion/src/benchmarking.rs b/substrate/frame/asset-conversion/src/benchmarking.rs index 54c634c0f1..87b541cd47 100644 --- a/substrate/frame/asset-conversion/src/benchmarking.rs +++ b/substrate/frame/asset-conversion/src/benchmarking.rs @@ -55,7 +55,9 @@ where { let caller: T::AccountId = whitelisted_caller(); let caller_lookup = T::Lookup::unlookup(caller.clone()); - if let Ok(asset_id) = T::MultiAssetIdConverter::try_convert(asset) { + if let MultiAssetIdConversionResult::Converted(asset_id) = + T::MultiAssetIdConverter::try_convert(asset) + { T::Currency::set_balance(&caller, BalanceOf::::max_value().div(1000u32.into())); assert_ok!(T::Assets::create(asset_id.clone(), caller.clone(), true, 1.into())); assert_ok!(T::Assets::mint_into(asset_id, &caller, INITIAL_ASSET_BALANCE.into())); @@ -106,18 +108,23 @@ benchmarks! { create_pool { let asset1 = T::MultiAssetIdConverter::get_native(); - let asset2 = T::MultiAssetIdConverter::into_multiasset_id(&T::BenchmarkHelper::asset_id(0_u32)); + let asset2 = T::BenchmarkHelper::multiasset_id(0); let (caller, _) = create_asset::(&asset2); }: _(SystemOrigin::Signed(caller.clone()), asset1.clone(), asset2.clone()) verify { let lp_token = get_lp_token_id::(); let pool_id = (asset1.clone(), asset2.clone()); - assert_last_event::(Event::PoolCreated { creator: caller.clone(), pool_id, lp_token }.into()); + assert_last_event::(Event::PoolCreated { + creator: caller.clone(), + pool_account: AssetConversion::::get_pool_account(&pool_id), + pool_id, + lp_token, + }.into()); } add_liquidity { let asset1 = T::MultiAssetIdConverter::get_native(); - let asset2 = T::MultiAssetIdConverter::into_multiasset_id(&T::BenchmarkHelper::asset_id(0)); + let asset2 = T::BenchmarkHelper::multiasset_id(0); let (lp_token, caller, _) = create_asset_and_pool::(&asset1, &asset2); let ed: u128 = T::Currency::minimum_balance().into(); let add_amount = 1000 + ed; @@ -141,7 +148,7 @@ benchmarks! { remove_liquidity { let asset1 = T::MultiAssetIdConverter::get_native(); - let asset2 = T::MultiAssetIdConverter::into_multiasset_id(&T::BenchmarkHelper::asset_id(0)); + let asset2 = T::BenchmarkHelper::multiasset_id(0); let (lp_token, caller, _) = create_asset_and_pool::(&asset1, &asset2); let ed: u128 = T::Currency::minimum_balance().into(); let add_amount = 100 * ed; @@ -170,8 +177,8 @@ benchmarks! { swap_exact_tokens_for_tokens { let native = T::MultiAssetIdConverter::get_native(); - let asset1 = T::MultiAssetIdConverter::into_multiasset_id(&T::BenchmarkHelper::asset_id(1)); - let asset2 = T::MultiAssetIdConverter::into_multiasset_id(&T::BenchmarkHelper::asset_id(2)); + let asset1 = T::BenchmarkHelper::multiasset_id(1); + let asset2 = T::BenchmarkHelper::multiasset_id(2); let (_, caller, _) = create_asset_and_pool::(&native, &asset1); let (_, _) = create_asset::(&asset2); let ed: u128 = T::Currency::minimum_balance().into(); @@ -187,6 +194,87 @@ benchmarks! { caller.clone(), )?; + let path; + let swap_amount; + // if we only allow the native-asset pools, then the worst case scenario would be to swap + // asset1-native-asset2 + if !T::AllowMultiAssetPools::get() { + AssetConversion::::create_pool(SystemOrigin::Signed(caller.clone()).into(), native.clone(), asset2.clone())?; + AssetConversion::::add_liquidity( + SystemOrigin::Signed(caller.clone()).into(), + native.clone(), + asset2.clone(), + (500 * ed).into(), + 1000.into(), + 0.into(), + 0.into(), + caller.clone(), + )?; + path = vec![asset1.clone(), native.clone(), asset2.clone()]; + swap_amount = 100.into(); + } else { + let asset3 = T::BenchmarkHelper::multiasset_id(3); + AssetConversion::::create_pool(SystemOrigin::Signed(caller.clone()).into(), asset1.clone(), asset2.clone())?; + let (_, _) = create_asset::(&asset3); + AssetConversion::::create_pool(SystemOrigin::Signed(caller.clone()).into(), asset2.clone(), asset3.clone())?; + + AssetConversion::::add_liquidity( + SystemOrigin::Signed(caller.clone()).into(), + asset1.clone(), + asset2.clone(), + 200.into(), + 2000.into(), + 0.into(), + 0.into(), + caller.clone(), + )?; + AssetConversion::::add_liquidity( + SystemOrigin::Signed(caller.clone()).into(), + asset2.clone(), + asset3.clone(), + 2000.into(), + 2000.into(), + 0.into(), + 0.into(), + caller.clone(), + )?; + path = vec![native.clone(), asset1.clone(), asset2.clone(), asset3.clone()]; + swap_amount = ed.into(); + } + + let path: BoundedVec<_, T::MaxSwapPathLength> = BoundedVec::try_from(path).unwrap(); + let native_balance = T::Currency::balance(&caller); + let asset1_balance = T::Assets::balance(T::BenchmarkHelper::asset_id(1), &caller); + }: _(SystemOrigin::Signed(caller.clone()), path, swap_amount, 1.into(), caller.clone(), false) + verify { + if !T::AllowMultiAssetPools::get() { + let new_asset1_balance = T::Assets::balance(T::BenchmarkHelper::asset_id(1), &caller); + assert_eq!(new_asset1_balance, asset1_balance - 100.into()); + } else { + let new_native_balance = T::Currency::balance(&caller); + assert_eq!(new_native_balance, native_balance - ed.into()); + } + } + + swap_tokens_for_exact_tokens { + let native = T::MultiAssetIdConverter::get_native(); + let asset1 = T::BenchmarkHelper::multiasset_id(1); + let asset2 = T::BenchmarkHelper::multiasset_id(2); + let (_, caller, _) = create_asset_and_pool::(&native, &asset1); + let (_, _) = create_asset::(&asset2); + let ed: u128 = T::Currency::minimum_balance().into(); + + AssetConversion::::add_liquidity( + SystemOrigin::Signed(caller.clone()).into(), + native.clone(), + asset1.clone(), + (1000 * ed).into(), + 500.into(), + 0.into(), + 0.into(), + caller.clone(), + )?; + let path; // if we only allow the native-asset pools, then the worst case scenario would be to swap // asset1-native-asset2 @@ -204,8 +292,8 @@ benchmarks! { )?; path = vec![asset1.clone(), native.clone(), asset2.clone()]; } else { - let asset3 = T::MultiAssetIdConverter::into_multiasset_id(&T::BenchmarkHelper::asset_id(3)); AssetConversion::::create_pool(SystemOrigin::Signed(caller.clone()).into(), asset1.clone(), asset2.clone())?; + let asset3 = T::BenchmarkHelper::multiasset_id(3); let (_, _) = create_asset::(&asset3); AssetConversion::::create_pool(SystemOrigin::Signed(caller.clone()).into(), asset2.clone(), asset3.clone())?; @@ -213,86 +301,7 @@ benchmarks! { SystemOrigin::Signed(caller.clone()).into(), asset1.clone(), asset2.clone(), - 200.into(), 2000.into(), - 0.into(), - 0.into(), - caller.clone(), - )?; - AssetConversion::::add_liquidity( - SystemOrigin::Signed(caller.clone()).into(), - asset2.clone(), - asset3.clone(), - 2000.into(), - 2000.into(), - 0.into(), - 0.into(), - caller.clone(), - )?; - path = vec![native.clone(), asset1.clone(), asset2.clone(), asset3.clone()]; - } - - let path: BoundedVec<_, T::MaxSwapPathLength> = BoundedVec::try_from(path).unwrap(); - let native_balance = T::Currency::balance(&caller); - let asset1_balance = T::Assets::balance(T::BenchmarkHelper::asset_id(1), &caller); - }: _(SystemOrigin::Signed(caller.clone()), path, ed.into(), 1.into(), caller.clone(), false) - verify { - if !T::AllowMultiAssetPools::get() { - let new_asset1_balance = T::Assets::balance(T::BenchmarkHelper::asset_id(1), &caller); - assert_eq!(new_asset1_balance, asset1_balance - 100.into()); - } else { - let new_native_balance = T::Currency::balance(&caller); - assert_eq!(new_native_balance, native_balance - ed.into()); - } - } - - swap_tokens_for_exact_tokens { - let native = T::MultiAssetIdConverter::get_native(); - let asset1 = T::MultiAssetIdConverter::into_multiasset_id(&T::BenchmarkHelper::asset_id(1)); - let asset2 = T::MultiAssetIdConverter::into_multiasset_id(&T::BenchmarkHelper::asset_id(2)); - let (_, caller, _) = create_asset_and_pool::(&native, &asset1); - let (_, _) = create_asset::(&asset2); - let ed: u128 = T::Currency::minimum_balance().into(); - let add_native = 1000 + ed; - - AssetConversion::::add_liquidity( - SystemOrigin::Signed(caller.clone()).into(), - native.clone(), - asset1.clone(), - add_native.into(), - 200.into(), - 0.into(), - 0.into(), - caller.clone(), - )?; - - let path; - // if we only allow the native-asset pools, then the worst case scenario would be to swap - // asset1-native-asset2 - if !T::AllowMultiAssetPools::get() { - AssetConversion::::create_pool(SystemOrigin::Signed(caller.clone()).into(), native.clone(), asset2.clone())?; - AssetConversion::::add_liquidity( - SystemOrigin::Signed(caller.clone()).into(), - native.clone(), - asset2.clone(), - (500 + ed).into(), - 1000.into(), - 0.into(), - 0.into(), - caller.clone(), - )?; - path = vec![asset1.clone(), native.clone(), asset2.clone()]; - } else { - AssetConversion::::create_pool(SystemOrigin::Signed(caller.clone()).into(), asset1.clone(), asset2.clone())?; - let asset3 = T::MultiAssetIdConverter::into_multiasset_id(&T::BenchmarkHelper::asset_id(3)); - let (_, _) = create_asset::(&asset3); - AssetConversion::::create_pool(SystemOrigin::Signed(caller.clone()).into(), asset2.clone(), asset3.clone())?; - - AssetConversion::::add_liquidity( - SystemOrigin::Signed(caller.clone()).into(), - asset1.clone(), - asset2.clone(), - 200.into(), 2000.into(), 0.into(), 0.into(), @@ -314,7 +323,7 @@ benchmarks! { let path: BoundedVec<_, T::MaxSwapPathLength> = BoundedVec::try_from(path).unwrap(); let asset2_balance = T::Assets::balance(T::BenchmarkHelper::asset_id(2), &caller); let asset3_balance = T::Assets::balance(T::BenchmarkHelper::asset_id(3), &caller); - }: _(SystemOrigin::Signed(caller.clone()), path.clone(), 100.into(), add_native.into(), caller.clone(), false) + }: _(SystemOrigin::Signed(caller.clone()), path.clone(), 100.into(), (1000 * ed).into(), caller.clone(), false) verify { if !T::AllowMultiAssetPools::get() { let new_asset2_balance = T::Assets::balance(T::BenchmarkHelper::asset_id(2), &caller); diff --git a/substrate/frame/asset-conversion/src/lib.rs b/substrate/frame/asset-conversion/src/lib.rs index 73f193c7ff..f442e7b7d0 100644 --- a/substrate/frame/asset-conversion/src/lib.rs +++ b/substrate/frame/asset-conversion/src/lib.rs @@ -143,9 +143,10 @@ pub mod pallet { /// Identifier for the class of non-native asset. /// Note: A `From` bound here would prevent `MultiLocation` from being used as an /// `AssetId`. - type AssetId: AssetId + PartialOrd; + type AssetId: AssetId; /// Type that identifies either the native currency or a token class from `Assets`. + /// `Ord` is added because of `get_pool_id`. type MultiAssetId: AssetId + Ord + From; /// Type to convert an `AssetId` into `MultiAssetId`. @@ -203,7 +204,7 @@ pub mod pallet { /// The benchmarks need a way to create asset ids from u32s. #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper: BenchmarkHelper; + type BenchmarkHelper: BenchmarkHelper; } /// Map from `PoolAssetId` to `PoolInfo`. This establishes whether a pool has been officially @@ -228,6 +229,8 @@ pub mod pallet { /// The pool id associated with the pool. Note that the order of the assets may not be /// the same as the order specified in the create pool extrinsic. pool_id: PoolIdOf, + /// The account ID of the pool. + pool_account: T::AccountId, /// The id of the liquidity tokens that will be minted when assets are added to this /// pool. lp_token: T::PoolAssetId, @@ -302,6 +305,8 @@ pub mod pallet { pub enum Error { /// Provided assets are equal. EqualAssets, + /// Provided asset is not supported for pool. + UnsupportedAsset, /// Pool already exists. PoolExists, /// Desired amount can't be zero. @@ -384,15 +389,14 @@ pub mod pallet { let sender = ensure_signed(origin)?; ensure!(asset1 != asset2, Error::::EqualAssets); - let pool_id = Self::get_pool_id(asset1.clone(), asset2.clone()); - let (asset1, asset2) = pool_id.clone(); - - if !T::AllowMultiAssetPools::get() && !T::MultiAssetIdConverter::is_native(&asset1) { + // prepare pool_id + let pool_id = Self::get_pool_id(asset1, asset2); + ensure!(!Pools::::contains_key(&pool_id), Error::::PoolExists); + let (asset1, asset2) = &pool_id; + if !T::AllowMultiAssetPools::get() && !T::MultiAssetIdConverter::is_native(asset1) { Err(Error::::PoolMustContainNativeCurrency)?; } - ensure!(!Pools::::contains_key(&pool_id), Error::::PoolExists); - let pool_account = Self::get_pool_account(&pool_id); frame_system::Pallet::::inc_providers(&pool_account); @@ -404,15 +408,22 @@ pub mod pallet { Preserve, )?; - if let Ok(asset) = T::MultiAssetIdConverter::try_convert(&asset1) { - if !T::Assets::contains(&asset, &pool_account) { - T::Assets::touch(asset, pool_account.clone(), sender.clone())?; - } + // try to convert both assets + match T::MultiAssetIdConverter::try_convert(asset1) { + MultiAssetIdConversionResult::Converted(asset) => + if !T::Assets::contains(&asset, &pool_account) { + T::Assets::touch(asset, pool_account.clone(), sender.clone())? + }, + MultiAssetIdConversionResult::Unsupported(_) => Err(Error::::UnsupportedAsset)?, + MultiAssetIdConversionResult::Native => (), } - if let Ok(asset) = T::MultiAssetIdConverter::try_convert(&asset2) { - if !T::Assets::contains(&asset, &pool_account) { - T::Assets::touch(asset, pool_account.clone(), sender.clone())?; - } + match T::MultiAssetIdConverter::try_convert(asset2) { + MultiAssetIdConversionResult::Converted(asset) => + if !T::Assets::contains(&asset, &pool_account) { + T::Assets::touch(asset, pool_account.clone(), sender.clone())? + }, + MultiAssetIdConversionResult::Unsupported(_) => Err(Error::::UnsupportedAsset)?, + MultiAssetIdConversionResult::Native => (), } let lp_token = NextPoolAssetId::::get().unwrap_or(T::PoolAssetId::initial_value()); @@ -425,7 +436,12 @@ pub mod pallet { let pool_info = PoolInfo { lp_token: lp_token.clone() }; Pools::::insert(pool_id.clone(), pool_info); - Self::deposit_event(Event::PoolCreated { creator: sender, pool_id, lp_token }); + Self::deposit_event(Event::PoolCreated { + creator: sender, + pool_id, + pool_account, + lp_token, + }); Ok(()) } @@ -767,34 +783,35 @@ pub mod pallet { amount: T::AssetBalance, keep_alive: bool, ) -> Result { - Self::deposit_event(Event::Transfer { - from: from.clone(), - to: to.clone(), - asset: (*asset_id).clone(), - amount, - }); - if T::MultiAssetIdConverter::is_native(asset_id) { - let preservation = match keep_alive { - true => Preserve, - false => Expendable, - }; - let amount = Self::convert_asset_balance_to_native_balance(amount)?; - Ok(Self::convert_native_balance_to_asset_balance(T::Currency::transfer( - from, - to, + let result = match T::MultiAssetIdConverter::try_convert(asset_id) { + MultiAssetIdConversionResult::Converted(asset_id) => + T::Assets::transfer(asset_id, from, to, amount, Expendable), + MultiAssetIdConversionResult::Native => { + let preservation = match keep_alive { + true => Preserve, + false => Expendable, + }; + let amount = Self::convert_asset_balance_to_native_balance(amount)?; + Ok(Self::convert_native_balance_to_asset_balance(T::Currency::transfer( + from, + to, + amount, + preservation, + )?)?) + }, + MultiAssetIdConversionResult::Unsupported(_) => + Err(Error::::UnsupportedAsset.into()), + }; + + if result.is_ok() { + Self::deposit_event(Event::Transfer { + from: from.clone(), + to: to.clone(), + asset: (*asset_id).clone(), amount, - preservation, - )?)?) - } else { - T::Assets::transfer( - T::MultiAssetIdConverter::try_convert(&asset_id) - .map_err(|_| Error::::Overflow)?, - from, - to, - amount, - Expendable, - ) + }); } + result } /// Convert a `Balance` type to an `AssetBalance`. @@ -898,28 +915,40 @@ pub mod pallet { owner: &T::AccountId, asset: &T::MultiAssetId, ) -> Result> { - if T::MultiAssetIdConverter::is_native(asset) { - Self::convert_native_balance_to_asset_balance( - <::Currency>::reducible_balance(owner, Expendable, Polite), - ) - } else { - Ok(<::Assets>::reducible_balance( - T::MultiAssetIdConverter::try_convert(asset) - .map_err(|_| Error::::Overflow)?, - owner, - Expendable, - Polite, - )) + match T::MultiAssetIdConverter::try_convert(asset) { + MultiAssetIdConversionResult::Converted(asset_id) => Ok( + <::Assets>::reducible_balance(asset_id, owner, Expendable, Polite), + ), + MultiAssetIdConversionResult::Native => + Self::convert_native_balance_to_asset_balance( + <::Currency>::reducible_balance(owner, Expendable, Polite), + ), + MultiAssetIdConversionResult::Unsupported(_) => + Err(Error::::UnsupportedAsset.into()), } } - /// Returns a pool id constructed from 2 sorted assets. - /// Native asset should be lower than the other asset ids. + /// Returns a pool id constructed from 2 assets. + /// 1. Native asset should be lower than the other asset ids. + /// 2. Two native or two non-native assets are compared by their `Ord` implementation. + /// + /// We expect deterministic order, so (asset1, asset2) or (asset2, asset1) returns the same + /// result. pub fn get_pool_id(asset1: T::MultiAssetId, asset2: T::MultiAssetId) -> PoolIdOf { - if asset1 <= asset2 { - (asset1, asset2) - } else { - (asset2, asset1) + match ( + T::MultiAssetIdConverter::is_native(&asset1), + T::MultiAssetIdConverter::is_native(&asset2), + ) { + (true, false) => return (asset1, asset2), + (false, true) => return (asset2, asset1), + _ => { + // else we want to be deterministic based on `Ord` implementation + if asset1 <= asset2 { + (asset1, asset2) + } else { + (asset2, asset1) + } + }, } } @@ -1161,7 +1190,9 @@ pub mod pallet { () ); } else { - let asset_id = T::MultiAssetIdConverter::try_convert(asset).map_err(|_| ())?; + let MultiAssetIdConversionResult::Converted(asset_id) = T::MultiAssetIdConverter::try_convert(asset) else { + return Err(()) + }; let minimal = T::Assets::minimum_balance(asset_id); ensure!(value >= minimal, ()); } @@ -1179,7 +1210,8 @@ pub mod pallet { for assets_pair in path.windows(2) { if let [asset1, asset2] = assets_pair { let pool_id = Self::get_pool_id(asset1.clone(), asset2.clone()); - let new_element = pools.try_insert(pool_id).expect("can't get here"); + let new_element = + pools.try_insert(pool_id).map_err(|_| Error::::Overflow)?; if !new_element { return Err(Error::::NonUniquePath.into()) } diff --git a/substrate/frame/asset-conversion/src/mock.rs b/substrate/frame/asset-conversion/src/mock.rs index 2b587161f1..7fe81b8140 100644 --- a/substrate/frame/asset-conversion/src/mock.rs +++ b/substrate/frame/asset-conversion/src/mock.rs @@ -34,6 +34,7 @@ use sp_runtime::{ traits::{AccountIdConversion, BlakeTwo256, IdentityLookup}, BuildStorage, }; + type Block = frame_system::mocking::MockBlock; construct_runtime!( diff --git a/substrate/frame/asset-conversion/src/tests.rs b/substrate/frame/asset-conversion/src/tests.rs index a4c02f365b..80faf5363b 100644 --- a/substrate/frame/asset-conversion/src/tests.rs +++ b/substrate/frame/asset-conversion/src/tests.rs @@ -66,13 +66,8 @@ fn pool_assets() -> Vec { fn create_tokens(owner: u128, tokens: Vec>) { for token_id in tokens { - assert_ok!(Assets::force_create( - RuntimeOrigin::root(), - NativeOrAssetIdConverter::try_convert(&token_id).unwrap(), - owner, - false, - 1 - )); + let MultiAssetIdConversionResult::Converted(asset_id) = NativeOrAssetIdConverter::try_convert(&token_id) else { unreachable!("invalid token") }; + assert_ok!(Assets::force_create(RuntimeOrigin::root(), asset_id, owner, false, 1)); } } @@ -157,7 +152,15 @@ fn can_create_pool() { assert_eq!(balance(pool_account, NativeOrAssetId::Native), setup_fee); assert_eq!(lp_token + 1, AssetConversion::get_next_pool_asset_id()); - assert_eq!(events(), [Event::::PoolCreated { creator: user, pool_id, lp_token }]); + assert_eq!( + events(), + [Event::::PoolCreated { + creator: user, + pool_id, + pool_account: AssetConversion::get_pool_account(&pool_id), + lp_token + }] + ); assert_eq!(pools(), vec![pool_id]); assert_eq!(assets(), vec![token_2]); assert_eq!(pool_assets(), vec![lp_token]); @@ -236,6 +239,7 @@ fn different_pools_should_have_different_lp_tokens() { [Event::::PoolCreated { creator: user, pool_id: pool_id_1_2, + pool_account: AssetConversion::get_pool_account(&pool_id_1_2), lp_token: lp_token2_1 }] ); @@ -246,6 +250,7 @@ fn different_pools_should_have_different_lp_tokens() { [Event::::PoolCreated { creator: user, pool_id: pool_id_1_3, + pool_account: AssetConversion::get_pool_account(&pool_id_1_3), lp_token: lp_token3_1, }] ); diff --git a/substrate/frame/asset-conversion/src/types.rs b/substrate/frame/asset-conversion/src/types.rs index 0612e363f0..7cd9743ff0 100644 --- a/substrate/frame/asset-conversion/src/types.rs +++ b/substrate/frame/asset-conversion/src/types.rs @@ -16,11 +16,10 @@ // limitations under the License. use super::*; -use core::marker::PhantomData; -use sp_std::cmp::Ordering; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; +use sp_std::{cmp::Ordering, marker::PhantomData}; pub(super) type PoolIdOf = (::MultiAssetId, ::MultiAssetId); @@ -40,96 +39,43 @@ pub trait MultiAssetIdConverter { fn is_native(asset: &MultiAssetId) -> bool; /// If it's not native, returns the AssetId for the given MultiAssetId. - fn try_convert(asset: &MultiAssetId) -> Result; + fn try_convert(asset: &MultiAssetId) -> MultiAssetIdConversionResult; +} - /// Wraps an AssetId as a MultiAssetId. - fn into_multiasset_id(asset: &AssetId) -> MultiAssetId; +/// Result of `MultiAssetIdConverter::try_convert`. +#[cfg_attr(feature = "std", derive(PartialEq, Debug))] +pub enum MultiAssetIdConversionResult { + /// Input asset is successfully converted. Means that converted asset is supported. + Converted(AssetId), + /// Means that input asset is the chain's native asset, if it has one, so no conversion (see + /// `MultiAssetIdConverter::get_native`). + Native, + /// Means input asset is not supported for pool. + Unsupported(MultiAssetId), } /// Benchmark Helper #[cfg(feature = "runtime-benchmarks")] -pub trait BenchmarkHelper { - /// Returns an asset id from a given integer. +pub trait BenchmarkHelper { + /// Returns an `AssetId` from a given integer. fn asset_id(asset_id: u32) -> AssetId; + + /// Returns a `MultiAssetId` from a given integer. + fn multiasset_id(asset_id: u32) -> MultiAssetId; } #[cfg(feature = "runtime-benchmarks")] -impl BenchmarkHelper for () +impl BenchmarkHelper for () where AssetId: From, + MultiAssetId: From, { fn asset_id(asset_id: u32) -> AssetId { asset_id.into() } -} -/// An implementation of MultiAssetId that can be either Native or an asset. -#[derive(Decode, Encode, Default, MaxEncodedLen, TypeInfo, Clone, Copy, Debug)] -pub enum NativeOrAssetId -where - AssetId: Ord, -{ - /// Native asset. For example, on statemint this would be dot. - #[default] - Native, - /// A non-native asset id. - Asset(AssetId), -} - -impl From for NativeOrAssetId { - fn from(asset: AssetId) -> Self { - Self::Asset(asset) - } -} - -impl Ord for NativeOrAssetId { - fn cmp(&self, other: &Self) -> Ordering { - match (self, other) { - (Self::Native, Self::Native) => Ordering::Equal, - (Self::Native, Self::Asset(_)) => Ordering::Less, - (Self::Asset(_), Self::Native) => Ordering::Greater, - (Self::Asset(id1), Self::Asset(id2)) => ::cmp(id1, id2), - } - } -} -impl PartialOrd for NativeOrAssetId { - fn partial_cmp(&self, other: &Self) -> Option { - Some(::cmp(self, other)) - } -} -impl PartialEq for NativeOrAssetId { - fn eq(&self, other: &Self) -> bool { - self.cmp(other) == Ordering::Equal - } -} -impl Eq for NativeOrAssetId {} - -/// Converts between a MultiAssetId and an AssetId -/// (or the native currency). -pub struct NativeOrAssetIdConverter { - _phantom: PhantomData, -} - -impl MultiAssetIdConverter, AssetId> - for NativeOrAssetIdConverter -{ - fn get_native() -> NativeOrAssetId { - NativeOrAssetId::Native - } - - fn is_native(asset: &NativeOrAssetId) -> bool { - *asset == Self::get_native() - } - - fn try_convert(asset: &NativeOrAssetId) -> Result { - match asset { - NativeOrAssetId::Asset(asset) => Ok(asset.clone()), - NativeOrAssetId::Native => Err(()), - } - } - - fn into_multiasset_id(asset: &AssetId) -> NativeOrAssetId { - NativeOrAssetId::Asset((*asset).clone()) + fn multiasset_id(asset_id: u32) -> MultiAssetId { + asset_id.into() } } @@ -169,3 +115,70 @@ pub trait Swap { keep_alive: bool, ) -> Result; } + +/// An implementation of MultiAssetId that can be either Native or an asset. +#[derive(Decode, Encode, Default, MaxEncodedLen, TypeInfo, Clone, Copy, Debug)] +pub enum NativeOrAssetId +where + AssetId: Ord, +{ + /// Native asset. For example, on the Polkadot Asset Hub this would be DOT. + #[default] + Native, + /// A non-native asset id. + Asset(AssetId), +} + +impl From for NativeOrAssetId { + fn from(asset: AssetId) -> Self { + Self::Asset(asset) + } +} + +impl Ord for NativeOrAssetId { + fn cmp(&self, other: &Self) -> Ordering { + match (self, other) { + (Self::Native, Self::Native) => Ordering::Equal, + (Self::Native, Self::Asset(_)) => Ordering::Less, + (Self::Asset(_), Self::Native) => Ordering::Greater, + (Self::Asset(id1), Self::Asset(id2)) => ::cmp(id1, id2), + } + } +} +impl PartialOrd for NativeOrAssetId { + fn partial_cmp(&self, other: &Self) -> Option { + Some(::cmp(self, other)) + } +} +impl PartialEq for NativeOrAssetId { + fn eq(&self, other: &Self) -> bool { + self.cmp(other) == Ordering::Equal + } +} +impl Eq for NativeOrAssetId {} + +/// Converts between a MultiAssetId and an AssetId (or the native currency). +pub struct NativeOrAssetIdConverter { + _phantom: PhantomData, +} + +impl MultiAssetIdConverter, AssetId> + for NativeOrAssetIdConverter +{ + fn get_native() -> NativeOrAssetId { + NativeOrAssetId::Native + } + + fn is_native(asset: &NativeOrAssetId) -> bool { + *asset == Self::get_native() + } + + fn try_convert( + asset: &NativeOrAssetId, + ) -> MultiAssetIdConversionResult, AssetId> { + match asset { + NativeOrAssetId::Asset(asset) => MultiAssetIdConversionResult::Converted(asset.clone()), + NativeOrAssetId::Native => MultiAssetIdConversionResult::Native, + } + } +} diff --git a/substrate/frame/asset-conversion/src/weights.rs b/substrate/frame/asset-conversion/src/weights.rs index 6820050762..550878ba0b 100644 --- a/substrate/frame/asset-conversion/src/weights.rs +++ b/substrate/frame/asset-conversion/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_asset_conversion //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-17, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-07-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner-gghbxkbs-project-145-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` @@ -77,8 +77,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `729` // Estimated: `6196` - // Minimum execution time: 131_549_000 picoseconds. - Weight::from_parts(134_287_000, 6196) + // Minimum execution time: 131_688_000 picoseconds. + Weight::from_parts(134_092_000, 6196) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(8_u64)) } @@ -98,8 +98,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1382` // Estimated: `6208` - // Minimum execution time: 156_395_000 picoseconds. - Weight::from_parts(157_952_000, 6208) + // Minimum execution time: 157_310_000 picoseconds. + Weight::from_parts(161_547_000, 6208) .saturating_add(T::DbWeight::get().reads(8_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -119,8 +119,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1371` // Estimated: `6208` - // Minimum execution time: 140_295_000 picoseconds. - Weight::from_parts(143_452_000, 6208) + // Minimum execution time: 142_769_000 picoseconds. + Weight::from_parts(145_139_000, 6208) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -134,8 +134,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1738` // Estimated: `16644` - // Minimum execution time: 214_657_000 picoseconds. - Weight::from_parts(217_657_000, 16644) + // Minimum execution time: 213_186_000 picoseconds. + Weight::from_parts(217_471_000, 16644) .saturating_add(T::DbWeight::get().reads(10_u64)) .saturating_add(T::DbWeight::get().writes(10_u64)) } @@ -149,8 +149,8 @@ impl WeightInfo for SubstrateWeight { // Proof Size summary in bytes: // Measured: `1738` // Estimated: `16644` - // Minimum execution time: 215_319_000 picoseconds. - Weight::from_parts(218_299_000, 16644) + // Minimum execution time: 213_793_000 picoseconds. + Weight::from_parts(218_584_000, 16644) .saturating_add(T::DbWeight::get().reads(10_u64)) .saturating_add(T::DbWeight::get().writes(10_u64)) } @@ -176,8 +176,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `729` // Estimated: `6196` - // Minimum execution time: 131_549_000 picoseconds. - Weight::from_parts(134_287_000, 6196) + // Minimum execution time: 131_688_000 picoseconds. + Weight::from_parts(134_092_000, 6196) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(8_u64)) } @@ -197,8 +197,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1382` // Estimated: `6208` - // Minimum execution time: 156_395_000 picoseconds. - Weight::from_parts(157_952_000, 6208) + // Minimum execution time: 157_310_000 picoseconds. + Weight::from_parts(161_547_000, 6208) .saturating_add(RocksDbWeight::get().reads(8_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -218,8 +218,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1371` // Estimated: `6208` - // Minimum execution time: 140_295_000 picoseconds. - Weight::from_parts(143_452_000, 6208) + // Minimum execution time: 142_769_000 picoseconds. + Weight::from_parts(145_139_000, 6208) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -233,8 +233,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1738` // Estimated: `16644` - // Minimum execution time: 214_657_000 picoseconds. - Weight::from_parts(217_657_000, 16644) + // Minimum execution time: 213_186_000 picoseconds. + Weight::from_parts(217_471_000, 16644) .saturating_add(RocksDbWeight::get().reads(10_u64)) .saturating_add(RocksDbWeight::get().writes(10_u64)) } @@ -248,8 +248,8 @@ impl WeightInfo for () { // Proof Size summary in bytes: // Measured: `1738` // Estimated: `16644` - // Minimum execution time: 215_319_000 picoseconds. - Weight::from_parts(218_299_000, 16644) + // Minimum execution time: 213_793_000 picoseconds. + Weight::from_parts(218_584_000, 16644) .saturating_add(RocksDbWeight::get().reads(10_u64)) .saturating_add(RocksDbWeight::get().writes(10_u64)) } diff --git a/substrate/frame/assets/src/impl_fungibles.rs b/substrate/frame/assets/src/impl_fungibles.rs index a7df3d154c..123abeba82 100644 --- a/substrate/frame/assets/src/impl_fungibles.rs +++ b/substrate/frame/assets/src/impl_fungibles.rs @@ -257,6 +257,7 @@ impl, I: 'static> fungibles::approvals::Inspect< impl, I: 'static> fungibles::approvals::Mutate<::AccountId> for Pallet { + // Approve spending tokens from a given account fn approve( asset: T::AssetId, owner: &::AccountId, @@ -266,7 +267,6 @@ impl, I: 'static> fungibles::approvals::Mutate<: Self::do_approve_transfer(asset, owner, delegate, amount) } - // Aprove spending tokens from a given account fn transfer_from( asset: T::AssetId, owner: &::AccountId, diff --git a/substrate/frame/support/src/traits/tokens/fungibles/regular.rs b/substrate/frame/support/src/traits/tokens/fungibles/regular.rs index 5570659e81..e17dfed0f3 100644 --- a/substrate/frame/support/src/traits/tokens/fungibles/regular.rs +++ b/substrate/frame/support/src/traits/tokens/fungibles/regular.rs @@ -62,7 +62,8 @@ pub trait Inspect: Sized { /// The minimum balance any single account may have. fn minimum_balance(asset: Self::AssetId) -> Self::Balance; - /// Get the total amount of funds whose ultimate bneficial ownership can be determined as `who`. + /// Get the total amount of funds whose ultimate beneficial ownership can be determined as + /// `who`. /// /// This may include funds which are wholly inaccessible to `who`, either temporarily or even /// indefinitely.