mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-01 01:57:56 +00:00
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:
@@ -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);
|
||||
|
||||
@@ -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!(
|
||||
|
||||
@@ -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,
|
||||
}]
|
||||
);
|
||||
|
||||
@@ -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
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user