Asset conversion get_pool_id fix (Ord does not count with is_native flag) (#14572)

* Asset conversion `get_pool_id` fix (`Ord` does not count with `is_native` flag)

* Removed unnecessery clones + added `pool_account` to `PoolCreated` event

* Fix bench compile

* Fix bench

* Improved `MultiAssetIdConverter::try_convert`

* Removed `into_multiasset_id` from converter and moved to `BenchmarkHelper`

* ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_asset_conversion

* Fixed doc

* Typo

* Removed `NativeOrAssetId` (test/mock) impl from types.rs to mock.rs...

* Typo + 0u32 -> 0

* Update frame/asset-conversion/src/benchmarking.rs

Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com>

* Typo

* ".git/.scripts/commands/fmt/fmt.sh"

* Fix from Jegor

* Try to fix the other failing benchmark

* ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_asset_conversion

* Update frame/asset-conversion/src/lib.rs

Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com>

* Update frame/asset-conversion/src/types.rs

Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com>

* Update frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs

Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com>

* Update frame/asset-conversion/src/mock.rs

Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com>

* Update bin/node/runtime/src/impls.rs

Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com>

* Update frame/asset-conversion/src/lib.rs

Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com>

* Update bin/node/runtime/src/impls.rs

Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com>

* Reverted NativeOrAssetId

---------

Co-authored-by: command-bot <>
Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com>
Co-authored-by: Jegor Sidorenko <jegor@parity.io>
Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com>
This commit is contained in:
Branislav Kontur
2023-07-21 15:06:32 +02:00
committed by GitHub
parent e71cca3c0d
commit 649be3aaaa
8 changed files with 319 additions and 258 deletions
@@ -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::<T>::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::<T>(&asset2);
}: _(SystemOrigin::Signed(caller.clone()), asset1.clone(), asset2.clone())
verify {
let lp_token = get_lp_token_id::<T>();
let pool_id = (asset1.clone(), asset2.clone());
assert_last_event::<T>(Event::PoolCreated { creator: caller.clone(), pool_id, lp_token }.into());
assert_last_event::<T>(Event::PoolCreated {
creator: caller.clone(),
pool_account: AssetConversion::<T>::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::<T>(&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::<T>(&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::<T>(&native, &asset1);
let (_, _) = create_asset::<T>(&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::<T>::create_pool(SystemOrigin::Signed(caller.clone()).into(), native.clone(), asset2.clone())?;
AssetConversion::<T>::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::<T>::create_pool(SystemOrigin::Signed(caller.clone()).into(), asset1.clone(), asset2.clone())?;
let (_, _) = create_asset::<T>(&asset3);
AssetConversion::<T>::create_pool(SystemOrigin::Signed(caller.clone()).into(), asset2.clone(), asset3.clone())?;
AssetConversion::<T>::add_liquidity(
SystemOrigin::Signed(caller.clone()).into(),
asset1.clone(),
asset2.clone(),
200.into(),
2000.into(),
0.into(),
0.into(),
caller.clone(),
)?;
AssetConversion::<T>::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::<T>(&native, &asset1);
let (_, _) = create_asset::<T>(&asset2);
let ed: u128 = T::Currency::minimum_balance().into();
AssetConversion::<T>::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::<T>::create_pool(SystemOrigin::Signed(caller.clone()).into(), asset1.clone(), asset2.clone())?;
let asset3 = T::BenchmarkHelper::multiasset_id(3);
let (_, _) = create_asset::<T>(&asset3);
AssetConversion::<T>::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::<T>::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::<T>(&native, &asset1);
let (_, _) = create_asset::<T>(&asset2);
let ed: u128 = T::Currency::minimum_balance().into();
let add_native = 1000 + ed;
AssetConversion::<T>::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::<T>::create_pool(SystemOrigin::Signed(caller.clone()).into(), native.clone(), asset2.clone())?;
AssetConversion::<T>::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::<T>::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::<T>(&asset3);
AssetConversion::<T>::create_pool(SystemOrigin::Signed(caller.clone()).into(), asset2.clone(), asset3.clone())?;
AssetConversion::<T>::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);
+95 -63
View File
@@ -143,9 +143,10 @@ pub mod pallet {
/// Identifier for the class of non-native asset.
/// Note: A `From<u32>` 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<Self::AssetId>;
/// 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<Self::AssetId>;
type BenchmarkHelper: BenchmarkHelper<Self::AssetId, Self::MultiAssetId>;
}
/// 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<T>,
/// 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<T> {
/// 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::<T>::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::<T>::contains_key(&pool_id), Error::<T>::PoolExists);
let (asset1, asset2) = &pool_id;
if !T::AllowMultiAssetPools::get() && !T::MultiAssetIdConverter::is_native(asset1) {
Err(Error::<T>::PoolMustContainNativeCurrency)?;
}
ensure!(!Pools::<T>::contains_key(&pool_id), Error::<T>::PoolExists);
let pool_account = Self::get_pool_account(&pool_id);
frame_system::Pallet::<T>::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::<T>::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::<T>::UnsupportedAsset)?,
MultiAssetIdConversionResult::Native => (),
}
let lp_token = NextPoolAssetId::<T>::get().unwrap_or(T::PoolAssetId::initial_value());
@@ -425,7 +436,12 @@ pub mod pallet {
let pool_info = PoolInfo { lp_token: lp_token.clone() };
Pools::<T>::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<T::AssetBalance, DispatchError> {
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::<T>::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::<T>::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<T::AssetBalance, Error<T>> {
if T::MultiAssetIdConverter::is_native(asset) {
Self::convert_native_balance_to_asset_balance(
<<T as Config>::Currency>::reducible_balance(owner, Expendable, Polite),
)
} else {
Ok(<<T as Config>::Assets>::reducible_balance(
T::MultiAssetIdConverter::try_convert(asset)
.map_err(|_| Error::<T>::Overflow)?,
owner,
Expendable,
Polite,
))
match T::MultiAssetIdConverter::try_convert(asset) {
MultiAssetIdConversionResult::Converted(asset_id) => Ok(
<<T as Config>::Assets>::reducible_balance(asset_id, owner, Expendable, Polite),
),
MultiAssetIdConversionResult::Native =>
Self::convert_native_balance_to_asset_balance(
<<T as Config>::Currency>::reducible_balance(owner, Expendable, Polite),
),
MultiAssetIdConversionResult::Unsupported(_) =>
Err(Error::<T>::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<T> {
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::<T>::Overflow)?;
if !new_element {
return Err(Error::<T>::NonUniquePath.into())
}
@@ -34,6 +34,7 @@ use sp_runtime::{
traits::{AccountIdConversion, BlakeTwo256, IdentityLookup},
BuildStorage,
};
type Block = frame_system::mocking::MockBlock<Test>;
construct_runtime!(
+13 -8
View File
@@ -66,13 +66,8 @@ fn pool_assets() -> Vec<u32> {
fn create_tokens(owner: u128, tokens: Vec<NativeOrAssetId<u32>>) {
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::<Test>::PoolCreated { creator: user, pool_id, lp_token }]);
assert_eq!(
events(),
[Event::<Test>::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::<Test>::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::<Test>::PoolCreated {
creator: user,
pool_id: pool_id_1_3,
pool_account: AssetConversion::get_pool_account(&pool_id_1_3),
lp_token: lp_token3_1,
}]
);
+89 -76
View File
@@ -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<T> = (<T as Config>::MultiAssetId, <T as Config>::MultiAssetId);
@@ -40,96 +39,43 @@ pub trait MultiAssetIdConverter<MultiAssetId, AssetId> {
fn is_native(asset: &MultiAssetId) -> bool;
/// If it's not native, returns the AssetId for the given MultiAssetId.
fn try_convert(asset: &MultiAssetId) -> Result<AssetId, ()>;
fn try_convert(asset: &MultiAssetId) -> MultiAssetIdConversionResult<MultiAssetId, AssetId>;
}
/// 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<MultiAssetId, AssetId> {
/// 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<AssetId> {
/// Returns an asset id from a given integer.
pub trait BenchmarkHelper<AssetId, MultiAssetId> {
/// 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<AssetId> BenchmarkHelper<AssetId> for ()
impl<AssetId, MultiAssetId> BenchmarkHelper<AssetId, MultiAssetId> for ()
where
AssetId: From<u32>,
MultiAssetId: From<u32>,
{
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<AssetId>
where
AssetId: Ord,
{
/// Native asset. For example, on statemint this would be dot.
#[default]
Native,
/// A non-native asset id.
Asset(AssetId),
}
impl<AssetId: Ord> From<AssetId> for NativeOrAssetId<AssetId> {
fn from(asset: AssetId) -> Self {
Self::Asset(asset)
}
}
impl<AssetId: Ord> Ord for NativeOrAssetId<AssetId> {
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)) => <AssetId as Ord>::cmp(id1, id2),
}
}
}
impl<AssetId: Ord> PartialOrd for NativeOrAssetId<AssetId> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(<Self as Ord>::cmp(self, other))
}
}
impl<AssetId: Ord> PartialEq for NativeOrAssetId<AssetId> {
fn eq(&self, other: &Self) -> bool {
self.cmp(other) == Ordering::Equal
}
}
impl<AssetId: Ord> Eq for NativeOrAssetId<AssetId> {}
/// Converts between a MultiAssetId and an AssetId
/// (or the native currency).
pub struct NativeOrAssetIdConverter<AssetId> {
_phantom: PhantomData<AssetId>,
}
impl<AssetId: Ord + Clone> MultiAssetIdConverter<NativeOrAssetId<AssetId>, AssetId>
for NativeOrAssetIdConverter<AssetId>
{
fn get_native() -> NativeOrAssetId<AssetId> {
NativeOrAssetId::Native
}
fn is_native(asset: &NativeOrAssetId<AssetId>) -> bool {
*asset == Self::get_native()
}
fn try_convert(asset: &NativeOrAssetId<AssetId>) -> Result<AssetId, ()> {
match asset {
NativeOrAssetId::Asset(asset) => Ok(asset.clone()),
NativeOrAssetId::Native => Err(()),
}
}
fn into_multiasset_id(asset: &AssetId) -> NativeOrAssetId<AssetId> {
NativeOrAssetId::Asset((*asset).clone())
fn multiasset_id(asset_id: u32) -> MultiAssetId {
asset_id.into()
}
}
@@ -169,3 +115,70 @@ pub trait Swap<AccountId, Balance, MultiAssetId> {
keep_alive: bool,
) -> Result<Balance, DispatchError>;
}
/// An implementation of MultiAssetId that can be either Native or an asset.
#[derive(Decode, Encode, Default, MaxEncodedLen, TypeInfo, Clone, Copy, Debug)]
pub enum NativeOrAssetId<AssetId>
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<AssetId: Ord> From<AssetId> for NativeOrAssetId<AssetId> {
fn from(asset: AssetId) -> Self {
Self::Asset(asset)
}
}
impl<AssetId: Ord> Ord for NativeOrAssetId<AssetId> {
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)) => <AssetId as Ord>::cmp(id1, id2),
}
}
}
impl<AssetId: Ord> PartialOrd for NativeOrAssetId<AssetId> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(<Self as Ord>::cmp(self, other))
}
}
impl<AssetId: Ord> PartialEq for NativeOrAssetId<AssetId> {
fn eq(&self, other: &Self) -> bool {
self.cmp(other) == Ordering::Equal
}
}
impl<AssetId: Ord> Eq for NativeOrAssetId<AssetId> {}
/// Converts between a MultiAssetId and an AssetId (or the native currency).
pub struct NativeOrAssetIdConverter<AssetId> {
_phantom: PhantomData<AssetId>,
}
impl<AssetId: Ord + Clone> MultiAssetIdConverter<NativeOrAssetId<AssetId>, AssetId>
for NativeOrAssetIdConverter<AssetId>
{
fn get_native() -> NativeOrAssetId<AssetId> {
NativeOrAssetId::Native
}
fn is_native(asset: &NativeOrAssetId<AssetId>) -> bool {
*asset == Self::get_native()
}
fn try_convert(
asset: &NativeOrAssetId<AssetId>,
) -> MultiAssetIdConversionResult<NativeOrAssetId<AssetId>, AssetId> {
match asset {
NativeOrAssetId::Asset(asset) => MultiAssetIdConversionResult::Converted(asset.clone()),
NativeOrAssetId::Native => MultiAssetIdConversionResult::Native,
}
}
}
+21 -21
View File
@@ -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<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
// 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<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
// 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<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
// 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<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
// 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<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
// 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))
}
+1 -1
View File
@@ -257,6 +257,7 @@ impl<T: Config<I>, I: 'static> fungibles::approvals::Inspect<<T as SystemConfig>
impl<T: Config<I>, I: 'static> fungibles::approvals::Mutate<<T as SystemConfig>::AccountId>
for Pallet<T, I>
{
// Approve spending tokens from a given account
fn approve(
asset: T::AssetId,
owner: &<T as SystemConfig>::AccountId,
@@ -266,7 +267,6 @@ impl<T: Config<I>, I: 'static> fungibles::approvals::Mutate<<T as SystemConfig>:
Self::do_approve_transfer(asset, owner, delegate, amount)
}
// Aprove spending tokens from a given account
fn transfer_from(
asset: T::AssetId,
owner: &<T as SystemConfig>::AccountId,
@@ -62,7 +62,8 @@ pub trait Inspect<AccountId>: 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.