mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 22:11:02 +00:00
pallet-asset-conversion: Decoupling Native Currency Dependancy (#2031)
closes https://github.com/paritytech/polkadot-sdk/issues/1842 Decoupling Pallet from the Concept of Native Currency Currently, the pallet is intrinsically linked with the concept of native currency, requiring users to provide implementations of the `fungible::*` and `fungibles::*` traits to interact with native and non native assets. This incapsulates some non-related to the pallet complexity and makes it less adaptable in contexts where the native currency concept is absent. With this PR, the dependence on `fungible::*` for liquidity-supplying assets has been removed. Instead, the native and non-native currencies' handling is now overseen by a single type that implements the `fungibles::*` traits. To simplify this integration, types have been introduced to facilitate the creation of a union between `fungible::*` and `fungibles::*` implementations, producing a unified `fungibles::*` type. One of the reasons driving these changes is the ambition to create a more user-friendly API for the `SwapCredit` implementation. Given that it interacts with two distinct credit types from `fungible` and `fungibles`, a unified type was introduced. Clients now manage potential conversion failures for those credit types. In certain contexts, it's vital to guarantee that operations are fail-safe, like in this impl - [PR](https://github.com/paritytech/polkadot-sdk/pull/1845), place in [code](https://github.com/paritytech/polkadot-sdk/blob/20b85a5fada8f55c98ba831964f5866ffeadf4da/cumulus/primitives/utility/src/lib.rs#L429). Additional Updates: - abstracted the pool ID and its account derivation logic via trait bounds, along with common implementation offerings; - removed `inc_providers` on a pool creation for the pool account; - benchmarks: -- swap complexity is N, not const; -- removed `From<u128> + Into<u128>` bound from `T::Balance`; -- removed swap/liquidity/.. amount constants, resolve them dynamically based on pallet configuration; -- migrated to v2 API; - `OnUnbalanced` handler for the pool creation fee, replacing direct transfers to a specified account ID; - renamed `MultiAssetId` to `AssetKind` aligning with naming across frame crates; related PRs: - (depends) https://github.com/paritytech/polkadot-sdk/pull/1677 - (caused) https://github.com/paritytech/polkadot-sdk/pull/2033 - (caused) https://github.com/paritytech/polkadot-sdk/pull/1876 --------- Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> Co-authored-by: Liam Aharon <liam.aharon@hotmail.com>
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use cumulus_primitives_core::ParaId;
|
||||
use sp_runtime::traits::Get;
|
||||
use sp_std::marker::PhantomData;
|
||||
use xcm::latest::prelude::*;
|
||||
|
||||
/// Creates asset pairs for liquidity pools with `Target` always being the first asset.
|
||||
pub struct AssetPairFactory<Target, SelfParaId, PalletId>(
|
||||
PhantomData<(Target, SelfParaId, PalletId)>,
|
||||
);
|
||||
impl<Target: Get<MultiLocation>, SelfParaId: Get<ParaId>, PalletId: Get<u32>>
|
||||
pallet_asset_conversion::BenchmarkHelper<MultiLocation>
|
||||
for AssetPairFactory<Target, SelfParaId, PalletId>
|
||||
{
|
||||
fn create_pair(seed1: u32, seed2: u32) -> (MultiLocation, MultiLocation) {
|
||||
let with_id = MultiLocation::new(
|
||||
1,
|
||||
X3(
|
||||
Parachain(SelfParaId::get().into()),
|
||||
PalletInstance(PalletId::get() as u8),
|
||||
GeneralIndex(seed2.into()),
|
||||
),
|
||||
);
|
||||
if seed1 % 2 == 0 {
|
||||
(with_id, Target::get())
|
||||
} else {
|
||||
(Target::get(), with_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
pub mod benchmarks;
|
||||
pub mod foreign_creators;
|
||||
pub mod fungible_conversion;
|
||||
pub mod local_and_foreign_assets;
|
||||
|
||||
@@ -13,48 +13,42 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use frame_support::traits::{
|
||||
fungibles::{Balanced, Create, HandleImbalanceDrop, Inspect, Mutate, Unbalanced},
|
||||
tokens::{
|
||||
DepositConsequence, Fortitude, Precision, Preservation, Provenance, WithdrawConsequence,
|
||||
},
|
||||
AccountTouch, Contains, ContainsPair, Get, PalletInfoAccess,
|
||||
use frame_support::traits::Get;
|
||||
use sp_runtime::{
|
||||
traits::{Convert, MaybeEquivalence},
|
||||
Either,
|
||||
Either::{Left, Right},
|
||||
};
|
||||
use pallet_asset_conversion::{MultiAssetIdConversionResult, MultiAssetIdConverter};
|
||||
use parachains_common::AccountId;
|
||||
use sp_runtime::{traits::MaybeEquivalence, DispatchError, DispatchResult};
|
||||
use sp_std::marker::PhantomData;
|
||||
use xcm::latest::MultiLocation;
|
||||
|
||||
pub struct MultiLocationConverter<NativeAssetLocation: Get<MultiLocation>, MultiLocationMatcher> {
|
||||
_phantom: PhantomData<(NativeAssetLocation, MultiLocationMatcher)>,
|
||||
/// Converts a given [`MultiLocation`] to [`Either::Left`] when equal to `Target`, or
|
||||
/// [`Either::Right`] otherwise.
|
||||
///
|
||||
/// Suitable for use as a `Criterion` with [`frame_support::traits::tokens::fungible::UnionOf`].
|
||||
pub struct TargetFromLeft<Target>(PhantomData<Target>);
|
||||
impl<Target: Get<MultiLocation>> Convert<MultiLocation, Either<(), MultiLocation>>
|
||||
for TargetFromLeft<Target>
|
||||
{
|
||||
fn convert(l: MultiLocation) -> Either<(), MultiLocation> {
|
||||
Target::get().eq(&l).then(|| Left(())).map_or(Right(l), |n| n)
|
||||
}
|
||||
}
|
||||
|
||||
impl<NativeAssetLocation, MultiLocationMatcher> MultiAssetIdConverter<MultiLocation, MultiLocation>
|
||||
for MultiLocationConverter<NativeAssetLocation, MultiLocationMatcher>
|
||||
/// Converts a given [`MultiLocation`] to [`Either::Left`] based on the `Equivalence` criteria.
|
||||
/// Returns [`Either::Right`] if not equivalent.
|
||||
///
|
||||
/// Suitable for use as a `Criterion` with [`frame_support::traits::tokens::fungibles::UnionOf`].
|
||||
pub struct LocalFromLeft<Equivalence, AssetId>(PhantomData<(Equivalence, AssetId)>);
|
||||
impl<Equivalence, AssetId> Convert<MultiLocation, Either<AssetId, MultiLocation>>
|
||||
for LocalFromLeft<Equivalence, AssetId>
|
||||
where
|
||||
NativeAssetLocation: Get<MultiLocation>,
|
||||
MultiLocationMatcher: Contains<MultiLocation>,
|
||||
Equivalence: MaybeEquivalence<MultiLocation, AssetId>,
|
||||
{
|
||||
fn get_native() -> MultiLocation {
|
||||
NativeAssetLocation::get()
|
||||
}
|
||||
|
||||
fn is_native(asset_id: &MultiLocation) -> bool {
|
||||
*asset_id == Self::get_native()
|
||||
}
|
||||
|
||||
fn try_convert(
|
||||
asset_id: &MultiLocation,
|
||||
) -> MultiAssetIdConversionResult<MultiLocation, MultiLocation> {
|
||||
if Self::is_native(asset_id) {
|
||||
return MultiAssetIdConversionResult::Native
|
||||
}
|
||||
|
||||
if MultiLocationMatcher::contains(asset_id) {
|
||||
MultiAssetIdConversionResult::Converted(*asset_id)
|
||||
} else {
|
||||
MultiAssetIdConversionResult::Unsupported(*asset_id)
|
||||
fn convert(l: MultiLocation) -> Either<AssetId, MultiLocation> {
|
||||
match Equivalence::convert(&l) {
|
||||
Some(id) => Left(id),
|
||||
None => Right(l),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,415 +57,3 @@ pub trait MatchesLocalAndForeignAssetsMultiLocation {
|
||||
fn is_local(location: &MultiLocation) -> bool;
|
||||
fn is_foreign(location: &MultiLocation) -> bool;
|
||||
}
|
||||
|
||||
pub struct LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets> {
|
||||
_phantom: PhantomData<(Assets, LocalAssetIdConverter, ForeignAssets)>,
|
||||
}
|
||||
|
||||
impl<Assets, LocalAssetIdConverter, ForeignAssets> Unbalanced<AccountId>
|
||||
for LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets>
|
||||
where
|
||||
Assets: Inspect<AccountId, Balance = u128, AssetId = u32>
|
||||
+ Unbalanced<AccountId>
|
||||
+ Balanced<AccountId>
|
||||
+ PalletInfoAccess,
|
||||
LocalAssetIdConverter: MaybeEquivalence<MultiLocation, u32>,
|
||||
ForeignAssets: Inspect<AccountId, Balance = u128, AssetId = MultiLocation>
|
||||
+ Unbalanced<AccountId>
|
||||
+ Balanced<AccountId>,
|
||||
{
|
||||
fn handle_dust(dust: frame_support::traits::fungibles::Dust<AccountId, Self>) {
|
||||
let credit = dust.into_credit();
|
||||
|
||||
if let Some(asset) = LocalAssetIdConverter::convert(&credit.asset()) {
|
||||
Assets::handle_raw_dust(asset, credit.peek());
|
||||
} else {
|
||||
ForeignAssets::handle_raw_dust(credit.asset(), credit.peek());
|
||||
}
|
||||
|
||||
// As we have already handled the dust, we must stop credit's drop from happening:
|
||||
sp_std::mem::forget(credit);
|
||||
}
|
||||
|
||||
fn write_balance(
|
||||
asset: <Self as Inspect<AccountId>>::AssetId,
|
||||
who: &AccountId,
|
||||
amount: <Self as Inspect<AccountId>>::Balance,
|
||||
) -> Result<Option<<Self as Inspect<AccountId>>::Balance>, DispatchError> {
|
||||
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||
Assets::write_balance(asset, who, amount)
|
||||
} else {
|
||||
ForeignAssets::write_balance(asset, who, amount)
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the total issuance of `asset` to `amount`.
|
||||
fn set_total_issuance(asset: Self::AssetId, amount: Self::Balance) {
|
||||
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||
Assets::set_total_issuance(asset, amount)
|
||||
} else {
|
||||
ForeignAssets::set_total_issuance(asset, amount)
|
||||
}
|
||||
}
|
||||
|
||||
fn decrease_balance(
|
||||
asset: Self::AssetId,
|
||||
who: &AccountId,
|
||||
amount: Self::Balance,
|
||||
precision: Precision,
|
||||
preservation: Preservation,
|
||||
force: Fortitude,
|
||||
) -> Result<Self::Balance, DispatchError> {
|
||||
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||
Assets::decrease_balance(asset, who, amount, precision, preservation, force)
|
||||
} else {
|
||||
ForeignAssets::decrease_balance(asset, who, amount, precision, preservation, force)
|
||||
}
|
||||
}
|
||||
|
||||
fn increase_balance(
|
||||
asset: Self::AssetId,
|
||||
who: &AccountId,
|
||||
amount: Self::Balance,
|
||||
precision: Precision,
|
||||
) -> Result<Self::Balance, DispatchError> {
|
||||
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||
Assets::increase_balance(asset, who, amount, precision)
|
||||
} else {
|
||||
ForeignAssets::increase_balance(asset, who, amount, precision)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Assets, LocalAssetIdConverter, ForeignAssets> Inspect<AccountId>
|
||||
for LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets>
|
||||
where
|
||||
Assets: Inspect<AccountId, Balance = u128, AssetId = u32>,
|
||||
LocalAssetIdConverter: MaybeEquivalence<MultiLocation, u32>,
|
||||
ForeignAssets: Inspect<AccountId, Balance = u128, AssetId = MultiLocation>,
|
||||
{
|
||||
type AssetId = MultiLocation;
|
||||
type Balance = u128;
|
||||
|
||||
/// The total amount of issuance in the system.
|
||||
fn total_issuance(asset: Self::AssetId) -> Self::Balance {
|
||||
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||
Assets::total_issuance(asset)
|
||||
} else {
|
||||
ForeignAssets::total_issuance(asset)
|
||||
}
|
||||
}
|
||||
|
||||
/// The minimum balance any single account may have.
|
||||
fn minimum_balance(asset: Self::AssetId) -> Self::Balance {
|
||||
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||
Assets::minimum_balance(asset)
|
||||
} else {
|
||||
ForeignAssets::minimum_balance(asset)
|
||||
}
|
||||
}
|
||||
|
||||
fn total_balance(
|
||||
asset: <Self as Inspect<AccountId>>::AssetId,
|
||||
account: &AccountId,
|
||||
) -> <Self as Inspect<AccountId>>::Balance {
|
||||
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||
Assets::total_balance(asset, account)
|
||||
} else {
|
||||
ForeignAssets::total_balance(asset, account)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the `asset` balance of `who`.
|
||||
fn balance(asset: Self::AssetId, who: &AccountId) -> Self::Balance {
|
||||
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||
Assets::balance(asset, who)
|
||||
} else {
|
||||
ForeignAssets::balance(asset, who)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the maximum amount of `asset` that `who` can withdraw/transfer successfully.
|
||||
fn reducible_balance(
|
||||
asset: Self::AssetId,
|
||||
who: &AccountId,
|
||||
presevation: Preservation,
|
||||
fortitude: Fortitude,
|
||||
) -> Self::Balance {
|
||||
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||
Assets::reducible_balance(asset, who, presevation, fortitude)
|
||||
} else {
|
||||
ForeignAssets::reducible_balance(asset, who, presevation, fortitude)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the `asset` balance of `who` may be increased by `amount`.
|
||||
///
|
||||
/// - `asset`: The asset that should be deposited.
|
||||
/// - `who`: The account of which the balance should be increased by `amount`.
|
||||
/// - `amount`: How much should the balance be increased?
|
||||
/// - `mint`: Will `amount` be minted to deposit it into `account`?
|
||||
fn can_deposit(
|
||||
asset: Self::AssetId,
|
||||
who: &AccountId,
|
||||
amount: Self::Balance,
|
||||
mint: Provenance,
|
||||
) -> DepositConsequence {
|
||||
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||
Assets::can_deposit(asset, who, amount, mint)
|
||||
} else {
|
||||
ForeignAssets::can_deposit(asset, who, amount, mint)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `Failed` if the `asset` balance of `who` may not be decreased by `amount`, otherwise
|
||||
/// the consequence.
|
||||
fn can_withdraw(
|
||||
asset: Self::AssetId,
|
||||
who: &AccountId,
|
||||
amount: Self::Balance,
|
||||
) -> WithdrawConsequence<Self::Balance> {
|
||||
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||
Assets::can_withdraw(asset, who, amount)
|
||||
} else {
|
||||
ForeignAssets::can_withdraw(asset, who, amount)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if an `asset` exists.
|
||||
fn asset_exists(asset: Self::AssetId) -> bool {
|
||||
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||
Assets::asset_exists(asset)
|
||||
} else {
|
||||
ForeignAssets::asset_exists(asset)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Assets, LocalAssetIdConverter, ForeignAssets> Mutate<AccountId>
|
||||
for LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets>
|
||||
where
|
||||
Assets: Mutate<AccountId>
|
||||
+ Inspect<AccountId, Balance = u128, AssetId = u32>
|
||||
+ Balanced<AccountId>
|
||||
+ PalletInfoAccess,
|
||||
LocalAssetIdConverter: MaybeEquivalence<MultiLocation, u32>,
|
||||
ForeignAssets: Mutate<AccountId, Balance = u128>
|
||||
+ Inspect<AccountId, Balance = u128, AssetId = MultiLocation>
|
||||
+ Balanced<AccountId>,
|
||||
{
|
||||
/// Transfer funds from one account into another.
|
||||
fn transfer(
|
||||
asset: MultiLocation,
|
||||
source: &AccountId,
|
||||
dest: &AccountId,
|
||||
amount: Self::Balance,
|
||||
keep_alive: Preservation,
|
||||
) -> Result<Self::Balance, DispatchError> {
|
||||
if let Some(asset_id) = LocalAssetIdConverter::convert(&asset) {
|
||||
Assets::transfer(asset_id, source, dest, amount, keep_alive)
|
||||
} else {
|
||||
ForeignAssets::transfer(asset, source, dest, amount, keep_alive)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Assets, LocalAssetIdConverter, ForeignAssets> Create<AccountId>
|
||||
for LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets>
|
||||
where
|
||||
Assets: Create<AccountId> + Inspect<AccountId, Balance = u128, AssetId = u32>,
|
||||
LocalAssetIdConverter: MaybeEquivalence<MultiLocation, u32>,
|
||||
ForeignAssets: Create<AccountId> + Inspect<AccountId, Balance = u128, AssetId = MultiLocation>,
|
||||
{
|
||||
/// Create a new fungible asset.
|
||||
fn create(
|
||||
asset_id: Self::AssetId,
|
||||
admin: AccountId,
|
||||
is_sufficient: bool,
|
||||
min_balance: Self::Balance,
|
||||
) -> DispatchResult {
|
||||
if let Some(asset_id) = LocalAssetIdConverter::convert(&asset_id) {
|
||||
Assets::create(asset_id, admin, is_sufficient, min_balance)
|
||||
} else {
|
||||
ForeignAssets::create(asset_id, admin, is_sufficient, min_balance)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Assets, LocalAssetIdConverter, ForeignAssets> AccountTouch<MultiLocation, AccountId>
|
||||
for LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets>
|
||||
where
|
||||
Assets: AccountTouch<u32, AccountId, Balance = u128>,
|
||||
LocalAssetIdConverter: MaybeEquivalence<MultiLocation, u32>,
|
||||
ForeignAssets: AccountTouch<MultiLocation, AccountId, Balance = u128>,
|
||||
{
|
||||
type Balance = u128;
|
||||
|
||||
fn deposit_required(
|
||||
asset_id: MultiLocation,
|
||||
) -> <Self as AccountTouch<MultiLocation, AccountId>>::Balance {
|
||||
if let Some(asset_id) = LocalAssetIdConverter::convert(&asset_id) {
|
||||
Assets::deposit_required(asset_id)
|
||||
} else {
|
||||
ForeignAssets::deposit_required(asset_id)
|
||||
}
|
||||
}
|
||||
|
||||
fn should_touch(asset_id: MultiLocation, who: &AccountId) -> bool {
|
||||
if let Some(asset_id) = LocalAssetIdConverter::convert(&asset_id) {
|
||||
Assets::should_touch(asset_id, who)
|
||||
} else {
|
||||
ForeignAssets::should_touch(asset_id, who)
|
||||
}
|
||||
}
|
||||
|
||||
fn touch(
|
||||
asset_id: MultiLocation,
|
||||
who: &AccountId,
|
||||
depositor: &AccountId,
|
||||
) -> Result<(), DispatchError> {
|
||||
if let Some(asset_id) = LocalAssetIdConverter::convert(&asset_id) {
|
||||
Assets::touch(asset_id, who, depositor)
|
||||
} else {
|
||||
ForeignAssets::touch(asset_id, who, depositor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Implements [`ContainsPair`] trait for a pair of asset and account IDs.
|
||||
impl<Assets, LocalAssetIdConverter, ForeignAssets> ContainsPair<MultiLocation, AccountId>
|
||||
for LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets>
|
||||
where
|
||||
Assets: PalletInfoAccess + ContainsPair<u32, AccountId>,
|
||||
LocalAssetIdConverter: MaybeEquivalence<MultiLocation, u32>,
|
||||
ForeignAssets: ContainsPair<MultiLocation, AccountId>,
|
||||
{
|
||||
/// Check if an account with the given asset ID and account address exists.
|
||||
fn contains(asset_id: &MultiLocation, who: &AccountId) -> bool {
|
||||
if let Some(asset_id) = LocalAssetIdConverter::convert(asset_id) {
|
||||
Assets::contains(&asset_id, &who)
|
||||
} else {
|
||||
ForeignAssets::contains(&asset_id, &who)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Assets, LocalAssetIdConverter, ForeignAssets> Balanced<AccountId>
|
||||
for LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets>
|
||||
where
|
||||
Assets:
|
||||
Balanced<AccountId> + Inspect<AccountId, Balance = u128, AssetId = u32> + PalletInfoAccess,
|
||||
LocalAssetIdConverter: MaybeEquivalence<MultiLocation, u32>,
|
||||
ForeignAssets:
|
||||
Balanced<AccountId> + Inspect<AccountId, Balance = u128, AssetId = MultiLocation>,
|
||||
{
|
||||
type OnDropDebt = DebtDropIndirection<Assets, LocalAssetIdConverter, ForeignAssets>;
|
||||
type OnDropCredit = CreditDropIndirection<Assets, LocalAssetIdConverter, ForeignAssets>;
|
||||
}
|
||||
|
||||
pub struct DebtDropIndirection<Assets, LocalAssetIdConverter, ForeignAssets> {
|
||||
_phantom: PhantomData<LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets>>,
|
||||
}
|
||||
|
||||
impl<Assets, LocalAssetIdConverter, ForeignAssets> HandleImbalanceDrop<MultiLocation, u128>
|
||||
for DebtDropIndirection<Assets, LocalAssetIdConverter, ForeignAssets>
|
||||
where
|
||||
Assets: Balanced<AccountId> + Inspect<AccountId, Balance = u128, AssetId = u32>,
|
||||
LocalAssetIdConverter: MaybeEquivalence<MultiLocation, u32>,
|
||||
ForeignAssets:
|
||||
Balanced<AccountId> + Inspect<AccountId, Balance = u128, AssetId = MultiLocation>,
|
||||
{
|
||||
fn handle(asset: MultiLocation, amount: u128) {
|
||||
if let Some(asset_id) = LocalAssetIdConverter::convert(&asset) {
|
||||
Assets::OnDropDebt::handle(asset_id, amount);
|
||||
} else {
|
||||
ForeignAssets::OnDropDebt::handle(asset, amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CreditDropIndirection<Assets, LocalAssetIdConverter, ForeignAssets> {
|
||||
_phantom: PhantomData<LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets>>,
|
||||
}
|
||||
|
||||
impl<Assets, LocalAssetIdConverter, ForeignAssets> HandleImbalanceDrop<MultiLocation, u128>
|
||||
for CreditDropIndirection<Assets, LocalAssetIdConverter, ForeignAssets>
|
||||
where
|
||||
Assets: Balanced<AccountId> + Inspect<AccountId, Balance = u128, AssetId = u32>,
|
||||
LocalAssetIdConverter: MaybeEquivalence<MultiLocation, u32>,
|
||||
ForeignAssets:
|
||||
Balanced<AccountId> + Inspect<AccountId, Balance = u128, AssetId = MultiLocation>,
|
||||
{
|
||||
fn handle(asset: MultiLocation, amount: u128) {
|
||||
if let Some(asset_id) = LocalAssetIdConverter::convert(&asset) {
|
||||
Assets::OnDropCredit::handle(asset_id, amount);
|
||||
} else {
|
||||
ForeignAssets::OnDropCredit::handle(asset, amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
local_and_foreign_assets::MultiLocationConverter, AssetIdForPoolAssetsConvert,
|
||||
AssetIdForTrustBackedAssetsConvert,
|
||||
};
|
||||
use frame_support::traits::EverythingBut;
|
||||
use pallet_asset_conversion::{MultiAssetIdConversionResult, MultiAssetIdConverter};
|
||||
use sp_runtime::traits::MaybeEquivalence;
|
||||
use xcm::latest::prelude::*;
|
||||
use xcm_builder::StartsWith;
|
||||
|
||||
#[test]
|
||||
fn test_multi_location_converter_works() {
|
||||
frame_support::parameter_types! {
|
||||
pub const WestendLocation: MultiLocation = MultiLocation::parent();
|
||||
pub TrustBackedAssetsPalletLocation: MultiLocation = PalletInstance(50_u8).into();
|
||||
pub PoolAssetsPalletLocation: MultiLocation = PalletInstance(55_u8).into();
|
||||
}
|
||||
|
||||
type C = MultiLocationConverter<
|
||||
WestendLocation,
|
||||
EverythingBut<StartsWith<PoolAssetsPalletLocation>>,
|
||||
>;
|
||||
|
||||
let native_asset = WestendLocation::get();
|
||||
let local_asset =
|
||||
AssetIdForTrustBackedAssetsConvert::<TrustBackedAssetsPalletLocation>::convert_back(
|
||||
&123,
|
||||
)
|
||||
.unwrap();
|
||||
let pool_asset =
|
||||
AssetIdForPoolAssetsConvert::<PoolAssetsPalletLocation>::convert_back(&456).unwrap();
|
||||
let foreign_asset1 = MultiLocation { parents: 1, interior: X1(Parachain(2222)) };
|
||||
let foreign_asset2 = MultiLocation {
|
||||
parents: 2,
|
||||
interior: X2(GlobalConsensus(ByGenesis([1; 32])), Parachain(2222)),
|
||||
};
|
||||
|
||||
assert!(C::is_native(&native_asset));
|
||||
assert!(!C::is_native(&local_asset));
|
||||
assert!(!C::is_native(&pool_asset));
|
||||
assert!(!C::is_native(&foreign_asset1));
|
||||
assert!(!C::is_native(&foreign_asset2));
|
||||
|
||||
assert_eq!(C::try_convert(&native_asset), MultiAssetIdConversionResult::Native);
|
||||
assert_eq!(
|
||||
C::try_convert(&local_asset),
|
||||
MultiAssetIdConversionResult::Converted(local_asset)
|
||||
);
|
||||
assert_eq!(
|
||||
C::try_convert(&pool_asset),
|
||||
MultiAssetIdConversionResult::Unsupported(pool_asset)
|
||||
);
|
||||
assert_eq!(
|
||||
C::try_convert(&foreign_asset1),
|
||||
MultiAssetIdConversionResult::Converted(foreign_asset1)
|
||||
);
|
||||
assert_eq!(
|
||||
C::try_convert(&foreign_asset2),
|
||||
MultiAssetIdConversionResult::Converted(foreign_asset2)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user