mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 04:41:03 +00:00
Asset conversion nits (#2860)
* [asset-conv] Unused Balances type
* [asset-conv] native asset change
* Dedicated `AssetBalance` type for `pallet_assets` instances
* Improved local vs foreign asset handling + test for not allowing pool_assets in pool
* Removed `into_multiasset_id`
* Fix
* Refactor
* Fixed create_pool for benchmark with LocalAndForeignAssets (finally found it)
* ".git/.scripts/commands/fmt/fmt.sh"
* Revert
* fmt
* Migrates pools with `MultiLocation { parents: 0, interior: Here }` to `MultiLocation { parents: 1, interior: Here }`
* Allow `set_storage` for `AllowMultiAssetPools` / `LiquidityWithdrawalFee`
* Benchmarks work
* Removed comment + more defensive migration
* `T::Currency::transfer` -> `Balances::transfer_all` in migration
* Change pool_id in migration
* Update parachains/runtimes/assets/asset-hub-westend/src/lib.rs
* Bump substrate (manually)
* Bump polkadot
* Fixes from polkadot + clippy
* Fix for xcm-emulator tests (thank you Nacho)
---------
Co-authored-by: command-bot <>
Co-authored-by: Jegor Sidorenko <5252494+jsidorenko@users.noreply.github.com>
This commit is contained in:
@@ -9,6 +9,7 @@ description = "Assets common utilities"
|
||||
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] }
|
||||
scale-info = { version = "2.9.0", default-features = false, features = ["derive"] }
|
||||
log = { version = "0.4.19", default-features = false }
|
||||
impl-trait-for-tuples = "0.2.2"
|
||||
|
||||
# Substrate
|
||||
frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
|
||||
|
||||
@@ -37,6 +37,19 @@ where
|
||||
) -> Result<MultiAsset, FungiblesAccessError>;
|
||||
}
|
||||
|
||||
/// Checks for `MultiLocation`.
|
||||
pub trait MatchesMultiLocation<AssetId, Balance, MatchAssetId, ConvertAssetId, ConvertBalance>:
|
||||
MatchesFungibles<AssetId, Balance>
|
||||
where
|
||||
AssetId: Clone,
|
||||
Balance: Clone,
|
||||
MatchAssetId: Contains<MultiLocation>,
|
||||
ConvertAssetId: MaybeEquivalence<MultiLocation, AssetId>,
|
||||
ConvertBalance: MaybeEquivalence<u128, Balance>,
|
||||
{
|
||||
fn contains(location: &MultiLocation) -> bool;
|
||||
}
|
||||
|
||||
impl<
|
||||
AssetId: Clone,
|
||||
Balance: Clone,
|
||||
@@ -82,6 +95,38 @@ impl<
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
AssetId: Clone,
|
||||
Balance: Clone,
|
||||
MatchAssetId: Contains<MultiLocation>,
|
||||
ConvertAssetId: MaybeEquivalence<MultiLocation, AssetId>,
|
||||
ConvertBalance: MaybeEquivalence<u128, Balance>,
|
||||
> MatchesMultiLocation<AssetId, Balance, MatchAssetId, ConvertAssetId, ConvertBalance>
|
||||
for MatchedConvertedConcreteId<AssetId, Balance, MatchAssetId, ConvertAssetId, ConvertBalance>
|
||||
{
|
||||
fn contains(location: &MultiLocation) -> bool {
|
||||
MatchAssetId::contains(location)
|
||||
}
|
||||
}
|
||||
|
||||
#[impl_trait_for_tuples::impl_for_tuples(30)]
|
||||
impl<
|
||||
AssetId: Clone,
|
||||
Balance: Clone,
|
||||
MatchAssetId: Contains<MultiLocation>,
|
||||
ConvertAssetId: MaybeEquivalence<MultiLocation, AssetId>,
|
||||
ConvertBalance: MaybeEquivalence<u128, Balance>,
|
||||
> MatchesMultiLocation<AssetId, Balance, MatchAssetId, ConvertAssetId, ConvertBalance> for Tuple
|
||||
{
|
||||
fn contains(location: &MultiLocation) -> bool {
|
||||
for_tuples!( #(
|
||||
match Tuple::contains(location) { o @ true => return o, _ => () }
|
||||
)* );
|
||||
log::trace!(target: "xcm::contains", "did not match location: {:?}", &location);
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper function to convert collections with [`(AssetId, Balance)`] to [`MultiAsset`]
|
||||
pub fn convert<'a, AssetId, Balance, ConvertAssetId, ConvertBalance, Converter>(
|
||||
items: impl Iterator<Item = &'a (AssetId, Balance)>,
|
||||
|
||||
@@ -13,92 +13,81 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::local_and_foreign_assets::fungibles::Inspect;
|
||||
use cumulus_primitives_core::InteriorMultiLocation;
|
||||
use frame_support::{
|
||||
pallet_prelude::DispatchError,
|
||||
traits::{
|
||||
fungibles::{
|
||||
self, Balanced, Create, HandleImbalanceDrop, Mutate as MutateFungible, Unbalanced,
|
||||
fungibles::{Balanced, Create, HandleImbalanceDrop, Inspect, Mutate, Unbalanced},
|
||||
tokens::{
|
||||
DepositConsequence, Fortitude, Precision, Preservation, Provenance, WithdrawConsequence,
|
||||
},
|
||||
tokens::{DepositConsequence, Fortitude, Preservation, Provenance, WithdrawConsequence},
|
||||
AccountTouch, ContainsPair, Get, PalletInfoAccess,
|
||||
AccountTouch, Contains, ContainsPair, Get, PalletInfoAccess,
|
||||
},
|
||||
};
|
||||
use pallet_asset_conversion::MultiAssetIdConverter;
|
||||
use parachains_common::{AccountId, AssetIdForTrustBackedAssets};
|
||||
use pallet_asset_conversion::{MultiAssetIdConversionResult, MultiAssetIdConverter};
|
||||
use parachains_common::AccountId;
|
||||
use sp_runtime::{traits::MaybeEquivalence, DispatchResult};
|
||||
use sp_std::{boxed::Box, marker::PhantomData};
|
||||
use xcm::{latest::MultiLocation, opaque::lts::Junctions::Here};
|
||||
use xcm_builder::AsPrefixedGeneralIndex;
|
||||
use xcm_executor::traits::JustTry;
|
||||
use xcm::latest::MultiLocation;
|
||||
|
||||
/// Whether the multilocation refers to an asset in the local assets pallet or not,
|
||||
/// and if return the asset id.
|
||||
fn is_local<TrustBackedAssetsPalletLocation: Get<MultiLocation>>(
|
||||
multilocation: MultiLocation,
|
||||
) -> Option<u32> {
|
||||
AsPrefixedGeneralIndex::<TrustBackedAssetsPalletLocation, AssetIdForTrustBackedAssets, JustTry>::convert(&multilocation)
|
||||
pub struct MultiLocationConverter<NativeAssetLocation: Get<MultiLocation>, MultiLocationMatcher> {
|
||||
_phantom: PhantomData<(NativeAssetLocation, MultiLocationMatcher)>,
|
||||
}
|
||||
|
||||
pub struct MultiLocationConverter<Balances, ParachainLocation: Get<InteriorMultiLocation>> {
|
||||
_phantom: PhantomData<(Balances, ParachainLocation)>,
|
||||
}
|
||||
|
||||
impl<Balances, ParachainLocation> MultiAssetIdConverter<Box<MultiLocation>, MultiLocation>
|
||||
for MultiLocationConverter<Balances, ParachainLocation>
|
||||
impl<NativeAssetLocation, MultiLocationMatcher>
|
||||
MultiAssetIdConverter<Box<MultiLocation>, MultiLocation>
|
||||
for MultiLocationConverter<NativeAssetLocation, MultiLocationMatcher>
|
||||
where
|
||||
Balances: PalletInfoAccess,
|
||||
ParachainLocation: Get<InteriorMultiLocation>,
|
||||
NativeAssetLocation: Get<MultiLocation>,
|
||||
MultiLocationMatcher: Contains<MultiLocation>,
|
||||
{
|
||||
fn get_native() -> Box<MultiLocation> {
|
||||
Box::new(MultiLocation { parents: 0, interior: Here })
|
||||
Box::new(NativeAssetLocation::get())
|
||||
}
|
||||
|
||||
fn is_native(asset_id: &Box<MultiLocation>) -> bool {
|
||||
let mut asset_id = asset_id.clone();
|
||||
asset_id.simplify(&ParachainLocation::get());
|
||||
*asset_id == *Self::get_native()
|
||||
*asset_id == Self::get_native()
|
||||
}
|
||||
|
||||
fn try_convert(asset_id: &Box<MultiLocation>) -> Result<MultiLocation, ()> {
|
||||
let mut asset_id = asset_id.clone();
|
||||
asset_id.simplify(&ParachainLocation::get());
|
||||
fn try_convert(
|
||||
asset_id: &Box<MultiLocation>,
|
||||
) -> MultiAssetIdConversionResult<Box<MultiLocation>, MultiLocation> {
|
||||
if Self::is_native(&asset_id) {
|
||||
// Otherwise it will try and touch the asset to create an account.
|
||||
return Err(())
|
||||
return MultiAssetIdConversionResult::Native
|
||||
}
|
||||
// Return simplified MultiLocation:
|
||||
Ok(*asset_id)
|
||||
}
|
||||
|
||||
fn into_multiasset_id(asset_id: &MultiLocation) -> Box<MultiLocation> {
|
||||
let mut asset_id = *asset_id;
|
||||
asset_id.simplify(&ParachainLocation::get());
|
||||
Box::new(asset_id)
|
||||
if MultiLocationMatcher::contains(&asset_id) {
|
||||
MultiAssetIdConversionResult::Converted(*asset_id.clone())
|
||||
} else {
|
||||
MultiAssetIdConversionResult::Unsupported(asset_id.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LocalAndForeignAssets<Assets, ForeignAssets, Location> {
|
||||
_phantom: PhantomData<(Assets, ForeignAssets, Location)>,
|
||||
pub trait MatchesLocalAndForeignAssetsMultiLocation {
|
||||
fn is_local(location: &MultiLocation) -> bool;
|
||||
fn is_foreign(location: &MultiLocation) -> bool;
|
||||
}
|
||||
|
||||
impl<Assets, ForeignAssets, Location> Unbalanced<AccountId>
|
||||
for LocalAndForeignAssets<Assets, ForeignAssets, Location>
|
||||
pub struct LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets> {
|
||||
_phantom: PhantomData<(Assets, LocalAssetIdConverter, ForeignAssets)>,
|
||||
}
|
||||
|
||||
impl<Assets, LocalAssetIdConverter, ForeignAssets> Unbalanced<AccountId>
|
||||
for LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets>
|
||||
where
|
||||
Location: Get<MultiLocation>,
|
||||
ForeignAssets: Inspect<AccountId, Balance = u128, AssetId = MultiLocation>
|
||||
+ Unbalanced<AccountId>
|
||||
+ Balanced<AccountId>,
|
||||
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) = is_local::<Location>(credit.asset()) {
|
||||
if let Some(asset) = LocalAssetIdConverter::convert(&credit.asset()) {
|
||||
Assets::handle_raw_dust(asset, credit.peek());
|
||||
} else {
|
||||
ForeignAssets::handle_raw_dust(credit.asset(), credit.peek());
|
||||
@@ -109,14 +98,11 @@ where
|
||||
}
|
||||
|
||||
fn write_balance(
|
||||
asset: <Self as frame_support::traits::fungibles::Inspect<AccountId>>::AssetId,
|
||||
asset: <Self as Inspect<AccountId>>::AssetId,
|
||||
who: &AccountId,
|
||||
amount: <Self as frame_support::traits::fungibles::Inspect<AccountId>>::Balance,
|
||||
) -> Result<
|
||||
Option<<Self as frame_support::traits::fungibles::Inspect<AccountId>>::Balance>,
|
||||
sp_runtime::DispatchError,
|
||||
> {
|
||||
if let Some(asset) = is_local::<Location>(asset) {
|
||||
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)
|
||||
@@ -125,27 +111,55 @@ where
|
||||
|
||||
/// Set the total issuance of `asset` to `amount`.
|
||||
fn set_total_issuance(asset: Self::AssetId, amount: Self::Balance) {
|
||||
if let Some(asset) = is_local::<Location>(asset) {
|
||||
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, ForeignAssets, Location> Inspect<AccountId>
|
||||
for LocalAndForeignAssets<Assets, ForeignAssets, Location>
|
||||
impl<Assets, LocalAssetIdConverter, ForeignAssets> Inspect<AccountId>
|
||||
for LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets>
|
||||
where
|
||||
Location: Get<MultiLocation>,
|
||||
ForeignAssets: Inspect<AccountId, Balance = u128, AssetId = MultiLocation>,
|
||||
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) = is_local::<Location>(asset) {
|
||||
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||
Assets::total_issuance(asset)
|
||||
} else {
|
||||
ForeignAssets::total_issuance(asset)
|
||||
@@ -154,16 +168,27 @@ where
|
||||
|
||||
/// The minimum balance any single account may have.
|
||||
fn minimum_balance(asset: Self::AssetId) -> Self::Balance {
|
||||
if let Some(asset) = is_local::<Location>(asset) {
|
||||
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) = is_local::<Location>(asset) {
|
||||
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||
Assets::balance(asset, who)
|
||||
} else {
|
||||
ForeignAssets::balance(asset, who)
|
||||
@@ -177,7 +202,7 @@ where
|
||||
presevation: Preservation,
|
||||
fortitude: Fortitude,
|
||||
) -> Self::Balance {
|
||||
if let Some(asset) = is_local::<Location>(asset) {
|
||||
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||
Assets::reducible_balance(asset, who, presevation, fortitude)
|
||||
} else {
|
||||
ForeignAssets::reducible_balance(asset, who, presevation, fortitude)
|
||||
@@ -196,7 +221,7 @@ where
|
||||
amount: Self::Balance,
|
||||
mint: Provenance,
|
||||
) -> DepositConsequence {
|
||||
if let Some(asset) = is_local::<Location>(asset) {
|
||||
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||
Assets::can_deposit(asset, who, amount, mint)
|
||||
} else {
|
||||
ForeignAssets::can_deposit(asset, who, amount, mint)
|
||||
@@ -210,7 +235,7 @@ where
|
||||
who: &AccountId,
|
||||
amount: Self::Balance,
|
||||
) -> WithdrawConsequence<Self::Balance> {
|
||||
if let Some(asset) = is_local::<Location>(asset) {
|
||||
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||
Assets::can_withdraw(asset, who, amount)
|
||||
} else {
|
||||
ForeignAssets::can_withdraw(asset, who, amount)
|
||||
@@ -219,36 +244,25 @@ where
|
||||
|
||||
/// Returns `true` if an `asset` exists.
|
||||
fn asset_exists(asset: Self::AssetId) -> bool {
|
||||
if let Some(asset) = is_local::<Location>(asset) {
|
||||
if let Some(asset) = LocalAssetIdConverter::convert(&asset) {
|
||||
Assets::asset_exists(asset)
|
||||
} else {
|
||||
ForeignAssets::asset_exists(asset)
|
||||
}
|
||||
}
|
||||
|
||||
fn total_balance(
|
||||
asset: <Self as frame_support::traits::fungibles::Inspect<AccountId>>::AssetId,
|
||||
account: &AccountId,
|
||||
) -> <Self as frame_support::traits::fungibles::Inspect<AccountId>>::Balance {
|
||||
if let Some(asset) = is_local::<Location>(asset) {
|
||||
Assets::total_balance(asset, account)
|
||||
} else {
|
||||
ForeignAssets::total_balance(asset, account)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Assets, ForeignAssets, Location> MutateFungible<AccountId>
|
||||
for LocalAndForeignAssets<Assets, ForeignAssets, Location>
|
||||
impl<Assets, LocalAssetIdConverter, ForeignAssets> Mutate<AccountId>
|
||||
for LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets>
|
||||
where
|
||||
Location: Get<MultiLocation>,
|
||||
ForeignAssets: MutateFungible<AccountId, Balance = u128>
|
||||
+ Inspect<AccountId, Balance = u128, AssetId = MultiLocation>
|
||||
+ Balanced<AccountId>,
|
||||
Assets: MutateFungible<AccountId>
|
||||
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(
|
||||
@@ -258,7 +272,7 @@ where
|
||||
amount: Self::Balance,
|
||||
keep_alive: Preservation,
|
||||
) -> Result<Self::Balance, DispatchError> {
|
||||
if let Some(asset_id) = is_local::<Location>(asset) {
|
||||
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)
|
||||
@@ -266,12 +280,12 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Assets, ForeignAssets, Location> Create<AccountId>
|
||||
for LocalAndForeignAssets<Assets, ForeignAssets, Location>
|
||||
impl<Assets, LocalAssetIdConverter, ForeignAssets> Create<AccountId>
|
||||
for LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets>
|
||||
where
|
||||
Location: Get<MultiLocation>,
|
||||
ForeignAssets: Create<AccountId> + Inspect<AccountId, Balance = u128, AssetId = MultiLocation>,
|
||||
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(
|
||||
@@ -280,7 +294,7 @@ where
|
||||
is_sufficient: bool,
|
||||
min_balance: Self::Balance,
|
||||
) -> DispatchResult {
|
||||
if let Some(asset_id) = is_local::<Location>(asset_id) {
|
||||
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)
|
||||
@@ -288,19 +302,19 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Assets, ForeignAssets, Location> AccountTouch<MultiLocation, AccountId>
|
||||
for LocalAndForeignAssets<Assets, ForeignAssets, Location>
|
||||
impl<Assets, LocalAssetIdConverter, ForeignAssets> AccountTouch<MultiLocation, AccountId>
|
||||
for LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets>
|
||||
where
|
||||
Location: Get<MultiLocation>,
|
||||
ForeignAssets: AccountTouch<MultiLocation, AccountId, Balance = u128>,
|
||||
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) = is_local::<Location>(asset_id) {
|
||||
if let Some(asset_id) = LocalAssetIdConverter::convert(&asset_id) {
|
||||
Assets::deposit_required(asset_id)
|
||||
} else {
|
||||
ForeignAssets::deposit_required(asset_id)
|
||||
@@ -311,8 +325,8 @@ where
|
||||
asset_id: MultiLocation,
|
||||
who: AccountId,
|
||||
depositor: AccountId,
|
||||
) -> Result<(), sp_runtime::DispatchError> {
|
||||
if let Some(asset_id) = is_local::<Location>(asset_id) {
|
||||
) -> Result<(), DispatchError> {
|
||||
if let Some(asset_id) = LocalAssetIdConverter::convert(&asset_id) {
|
||||
Assets::touch(asset_id, who, depositor)
|
||||
} else {
|
||||
ForeignAssets::touch(asset_id, who, depositor)
|
||||
@@ -321,16 +335,16 @@ where
|
||||
}
|
||||
|
||||
/// Implements [`ContainsPair`] trait for a pair of asset and account IDs.
|
||||
impl<Assets, ForeignAssets, Location> ContainsPair<MultiLocation, AccountId>
|
||||
for LocalAndForeignAssets<Assets, ForeignAssets, Location>
|
||||
impl<Assets, LocalAssetIdConverter, ForeignAssets> ContainsPair<MultiLocation, AccountId>
|
||||
for LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets>
|
||||
where
|
||||
Location: Get<MultiLocation>,
|
||||
ForeignAssets: ContainsPair<MultiLocation, AccountId>,
|
||||
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) = is_local::<Location>(*asset_id) {
|
||||
if let Some(asset_id) = LocalAssetIdConverter::convert(asset_id) {
|
||||
Assets::contains(&asset_id, &who)
|
||||
} else {
|
||||
ForeignAssets::contains(&asset_id, &who)
|
||||
@@ -338,33 +352,33 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<Assets, ForeignAssets, Location> Balanced<AccountId>
|
||||
for LocalAndForeignAssets<Assets, ForeignAssets, Location>
|
||||
impl<Assets, LocalAssetIdConverter, ForeignAssets> Balanced<AccountId>
|
||||
for LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets>
|
||||
where
|
||||
Location: Get<MultiLocation>,
|
||||
ForeignAssets:
|
||||
Balanced<AccountId> + Inspect<AccountId, Balance = u128, AssetId = MultiLocation>,
|
||||
Assets:
|
||||
Balanced<AccountId> + Inspect<AccountId, Balance = u128, AssetId = u32> + PalletInfoAccess,
|
||||
{
|
||||
type OnDropDebt = DebtDropIndirection<Assets, ForeignAssets, Location>;
|
||||
type OnDropCredit = CreditDropIndirection<Assets, ForeignAssets, Location>;
|
||||
}
|
||||
|
||||
pub struct DebtDropIndirection<Assets, ForeignAssets, Location> {
|
||||
_phantom: PhantomData<LocalAndForeignAssets<Assets, ForeignAssets, Location>>,
|
||||
}
|
||||
|
||||
impl<Assets, ForeignAssets, Location> HandleImbalanceDrop<MultiLocation, u128>
|
||||
for DebtDropIndirection<Assets, ForeignAssets, Location>
|
||||
where
|
||||
Location: Get<MultiLocation>,
|
||||
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) = is_local::<Location>(asset) {
|
||||
if let Some(asset_id) = LocalAssetIdConverter::convert(&asset) {
|
||||
Assets::OnDropDebt::handle(asset_id, amount);
|
||||
} else {
|
||||
ForeignAssets::OnDropDebt::handle(asset, amount);
|
||||
@@ -372,23 +386,87 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CreditDropIndirection<Assets, ForeignAssets, Location> {
|
||||
_phantom: PhantomData<LocalAndForeignAssets<Assets, ForeignAssets, Location>>,
|
||||
pub struct CreditDropIndirection<Assets, LocalAssetIdConverter, ForeignAssets> {
|
||||
_phantom: PhantomData<LocalAndForeignAssets<Assets, LocalAssetIdConverter, ForeignAssets>>,
|
||||
}
|
||||
|
||||
impl<Assets, ForeignAssets, Location> HandleImbalanceDrop<MultiLocation, u128>
|
||||
for CreditDropIndirection<Assets, ForeignAssets, Location>
|
||||
impl<Assets, LocalAssetIdConverter, ForeignAssets> HandleImbalanceDrop<MultiLocation, u128>
|
||||
for CreditDropIndirection<Assets, LocalAssetIdConverter, ForeignAssets>
|
||||
where
|
||||
Location: Get<MultiLocation>,
|
||||
Assets: Balanced<AccountId> + Inspect<AccountId, Balance = u128, AssetId = u32>,
|
||||
LocalAssetIdConverter: MaybeEquivalence<MultiLocation, u32>,
|
||||
ForeignAssets:
|
||||
Balanced<AccountId> + Inspect<AccountId, Balance = u128, AssetId = MultiLocation>,
|
||||
Assets: Balanced<AccountId> + Inspect<AccountId, Balance = u128, AssetId = u32>,
|
||||
{
|
||||
fn handle(asset: MultiLocation, amount: u128) {
|
||||
if let Some(asset_id) = is_local::<Location>(asset) {
|
||||
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, matching::StartsWith,
|
||||
AssetIdForPoolAssetsConvert, AssetIdForTrustBackedAssetsConvert,
|
||||
};
|
||||
use frame_support::traits::EverythingBut;
|
||||
use pallet_asset_conversion::{MultiAssetIdConversionResult, MultiAssetIdConverter};
|
||||
use sp_runtime::traits::MaybeEquivalence;
|
||||
use xcm::latest::prelude::*;
|
||||
|
||||
#[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(&Box::new(native_asset)));
|
||||
assert!(!C::is_native(&Box::new(local_asset)));
|
||||
assert!(!C::is_native(&Box::new(pool_asset)));
|
||||
assert!(!C::is_native(&Box::new(foreign_asset1)));
|
||||
assert!(!C::is_native(&Box::new(foreign_asset2)));
|
||||
|
||||
assert_eq!(C::try_convert(&Box::new(native_asset)), MultiAssetIdConversionResult::Native);
|
||||
assert_eq!(
|
||||
C::try_convert(&Box::new(local_asset)),
|
||||
MultiAssetIdConversionResult::Converted(local_asset)
|
||||
);
|
||||
assert_eq!(
|
||||
C::try_convert(&Box::new(pool_asset)),
|
||||
MultiAssetIdConversionResult::Unsupported(Box::new(pool_asset))
|
||||
);
|
||||
assert_eq!(
|
||||
C::try_convert(&Box::new(foreign_asset1)),
|
||||
MultiAssetIdConversionResult::Converted(foreign_asset1)
|
||||
);
|
||||
assert_eq!(
|
||||
C::try_convert(&Box::new(foreign_asset2)),
|
||||
MultiAssetIdConversionResult::Converted(foreign_asset2)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user