difftreelog
feat draft xcm deposit_asset
in: master
8 files changed
pallets/balances-adapter/src/common.rsdiffbeforeafterboth--- a/pallets/balances-adapter/src/common.rs
+++ b/pallets/balances-adapter/src/common.rs
@@ -1,10 +1,16 @@
use alloc::{vec, vec::Vec};
use core::marker::PhantomData;
-use frame_support::{ensure, fail, weights::Weight};
+use frame_support::{
+ ensure, fail,
+ traits::tokens::{fungible::Mutate, Fortitude, Precision},
+ weights::Weight,
+};
use pallet_balances::{weights::SubstrateWeight as BalancesWeight, WeightInfo};
-use pallet_common::{CommonCollectionOperations, CommonWeightInfo, Error as CommonError};
-use up_data_structs::TokenId;
+use pallet_common::{
+ erc::CrossAccountId, CommonCollectionOperations, CommonWeightInfo, Error as CommonError,
+};
+use up_data_structs::{budget::Budget, TokenId};
use crate::{Config, NativeFungibleHandle, Pallet};
@@ -332,6 +338,10 @@
0
}
+ fn xcm_extensions(&self) -> Option<&dyn pallet_common::XcmExtensions<T>> {
+ Some(self)
+ }
+
fn set_allowance_for_all(
&self,
_owner: <T>::CrossAccountId,
@@ -356,3 +366,76 @@
fail!(<CommonError<T>>::UnsupportedOperation);
}
}
+
+impl<T: Config> pallet_common::XcmExtensions<T> for NativeFungibleHandle<T> {
+ fn is_foreign(&self) -> bool {
+ false
+ }
+
+ fn create_item_internal(
+ &self,
+ _depositor: &<T>::CrossAccountId,
+ to: <T>::CrossAccountId,
+ data: up_data_structs::CreateItemData,
+ _nesting_budget: &dyn Budget,
+ ) -> Result<TokenId, sp_runtime::DispatchError> {
+ match &data {
+ up_data_structs::CreateItemData::Fungible(fungible_data) => {
+ T::Mutate::mint_into(
+ to.as_sub(),
+ fungible_data
+ .value
+ .try_into()
+ .map_err(|_| sp_runtime::ArithmeticError::Overflow)?,
+ )?;
+
+ Ok(TokenId::default())
+ }
+ _ => {
+ fail!(<CommonError<T>>::NotFungibleDataUsedToMintFungibleCollectionToken)
+ }
+ }
+ }
+
+ fn transfer_item_internal(
+ &self,
+ _depositor: &<T>::CrossAccountId,
+ from: &<T>::CrossAccountId,
+ to: &<T>::CrossAccountId,
+ token: TokenId,
+ amount: u128,
+ _nesting_budget: &dyn Budget,
+ ) -> sp_runtime::DispatchResult {
+ ensure!(
+ token == TokenId::default(),
+ <CommonError<T>>::FungibleItemsHaveNoId
+ );
+
+ <Pallet<T>>::transfer(from, to, amount)
+ .map(|_| ())
+ .map_err(|post_info| post_info.error)
+ }
+
+ fn burn_item_internal(
+ &self,
+ from: T::CrossAccountId,
+ token: TokenId,
+ amount: u128,
+ ) -> sp_runtime::DispatchResult {
+ ensure!(
+ token == TokenId::default(),
+ <CommonError<T>>::FungibleItemsHaveNoId
+ );
+
+ T::Mutate::burn_from(
+ from.as_sub(),
+ amount
+ .try_into()
+ .map_err(|_| sp_runtime::ArithmeticError::Overflow)?,
+ Precision::Exact,
+ Fortitude::Polite,
+ )?;
+
+ Ok(())
+ }
+}
pallets/common/src/lib.rsdiffbeforeafterboth--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -80,15 +80,16 @@
use sp_std::vec::Vec;
use sp_weights::Weight;
use up_data_structs::{
- budget::Budget, AccessMode, Collection, CollectionId, CollectionLimits, CollectionMode,
- CollectionPermissions, CollectionProperties as CollectionPropertiesT, CollectionStats,
- CreateCollectionData, CreateItemData, CreateItemExData, PhantomType, PropertiesError,
- PropertiesPermissionMap, Property, PropertyKey, PropertyKeyPermission, PropertyPermission,
- PropertyScope, PropertyValue, RpcCollection, RpcCollectionFlags, SponsoringRateLimit,
- SponsorshipState, TokenChild, TokenData, TokenId, TokenOwnerError, TokenProperties,
- TrySetProperty, COLLECTION_ADMINS_LIMIT, COLLECTION_NUMBER_LIMIT, CUSTOM_DATA_LIMIT,
- FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, MAX_SPONSOR_TIMEOUT, MAX_TOKEN_OWNERSHIP,
- MAX_TOKEN_PREFIX_LENGTH, NFT_SPONSOR_TRANSFER_TIMEOUT, REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
+ budget::Budget, mapping::TokenAddressMapping, AccessMode, Collection, CollectionId,
+ CollectionLimits, CollectionMode, CollectionPermissions,
+ CollectionProperties as CollectionPropertiesT, CollectionStats, CreateCollectionData,
+ CreateItemData, CreateItemExData, PhantomType, PropertiesError, PropertiesPermissionMap,
+ Property, PropertyKey, PropertyKeyPermission, PropertyPermission, PropertyScope, PropertyValue,
+ RpcCollection, RpcCollectionFlags, SponsoringRateLimit, SponsorshipState, TokenChild,
+ TokenData, TokenId, TokenOwnerError, TokenProperties, TrySetProperty, COLLECTION_ADMINS_LIMIT,
+ COLLECTION_NUMBER_LIMIT, CUSTOM_DATA_LIMIT, FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
+ MAX_SPONSOR_TIMEOUT, MAX_TOKEN_OWNERSHIP, MAX_TOKEN_PREFIX_LENGTH,
+ NFT_SPONSOR_TRANSFER_TIMEOUT, REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
};
use up_pov_estimate_rpc::PovInfo;
@@ -786,6 +787,9 @@
/// Fungible tokens hold no ID, and the default value of TokenId for a fungible collection is 0.
FungibleItemsHaveNoId,
+
+ /// Not Fungible item data used to mint in Fungible collection.
+ NotFungibleDataUsedToMintFungibleCollectionToken,
}
/// Storage of the count of created collections. Essentially contains the last collection ID.
@@ -2347,24 +2351,77 @@
/// Is the collection a foreign one?
fn is_foreign(&self) -> bool;
- /// Create a collection's item.
+ /// Create a collection's item using a transaction.
+ ///
+ /// This function performs additional XCM-related checks before the actual creation.
+ #[transactional]
fn create_item(
&self,
+ depositor: &T::CrossAccountId,
+ to: T::CrossAccountId,
+ data: CreateItemData,
+ nesting_budget: &dyn Budget,
+ ) -> Result<TokenId, DispatchError> {
+ if T::CrossTokenAddressMapping::is_token_address(&to) {
+ return unsupported!(T);
+ }
+
+ self.create_item_internal(depositor, to, data, nesting_budget)
+ }
+
+ /// Create a collection's item.
+ fn create_item_internal(
+ &self,
+ depositor: &T::CrossAccountId,
to: T::CrossAccountId,
data: CreateItemData,
+ nesting_budget: &dyn Budget,
) -> Result<TokenId, DispatchError>;
+ /// Transfer an item from the `from` account to the `to` account using a transaction.
+ ///
+ /// This function performs additional XCM-related checks before the actual transfer.
+ #[transactional]
+ fn transfer_item(
+ &self,
+ depositor: &T::CrossAccountId,
+ from: &T::CrossAccountId,
+ to: &T::CrossAccountId,
+ token: TokenId,
+ amount: u128,
+ nesting_budget: &dyn Budget,
+ ) -> DispatchResult {
+ if T::CrossTokenAddressMapping::is_token_address(&to) {
+ return unsupported!(T);
+ }
+
+ self.transfer_item_internal(depositor, from, to, token, amount, nesting_budget)
+ }
+
/// Transfer an item from the `from` account to the `to` account.
- fn transfer(
+ fn transfer_item_internal(
&self,
- from: T::CrossAccountId,
- to: T::CrossAccountId,
+ depositor: &T::CrossAccountId,
+ from: &T::CrossAccountId,
+ to: &T::CrossAccountId,
token: TokenId,
amount: u128,
+ nesting_budget: &dyn Budget,
) -> DispatchResult;
+ /// Burn a collection's item using a transaction.
+ #[transactional]
+ fn burn_item(&self, from: T::CrossAccountId, token: TokenId, amount: u128) -> DispatchResult {
+ self.burn_item_internal(from, token, amount)
+ }
+
/// Burn a collection's item.
- fn burn(&self, from: T::CrossAccountId, token: TokenId, amount: u128) -> DispatchResult;
+ fn burn_item_internal(
+ &self,
+ from: T::CrossAccountId,
+ token: TokenId,
+ amount: u128,
+ ) -> DispatchResult;
}
/// Merge [`DispatchResult`] with [`Weight`] into [`DispatchResultWithPostInfo`].
pallets/foreign-assets/src/lib.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! # Foreign assets18//!19//! - [`Config`]20//! - [`Call`]21//! - [`Pallet`]22//!23//! ## Overview24//!25//! The foreign assests pallet provides functions for:26//!27//! - Local and foreign assets management. The foreign assets can be updated without runtime upgrade.28//! - Bounds between asset and target collection for cross chain transfer and inner transfers.29//!30//! ## Overview31//!32//! Under construction3334#![cfg_attr(not(feature = "std"), no_std)]35#![allow(clippy::unused_unit)]3637use frame_support::{dispatch::DispatchResult, pallet_prelude::*, traits::EnsureOrigin, PalletId};38use frame_system::pallet_prelude::*;39use pallet_common::{40 dispatch::CollectionDispatch, erc::CrossAccountId, NATIVE_FUNGIBLE_COLLECTION_ID,41};42use sp_runtime::traits::AccountIdConversion;43use sp_std::{vec, vec::Vec};44// NOTE: MultiLocation is used in storages, we will need to do migration if upgrade the45// MultiLocation to the XCM v3.46use staging_xcm::{47 opaque::latest::{prelude::XcmError, Weight},48 v3::{prelude::*, MultiAsset, XcmContext},49};50use staging_xcm_executor::{51 traits::{TransactAsset, WeightTrader},52 Assets,53};54use up_data_structs::{55 CollectionId, CollectionMode, CollectionName, CreateCollectionData, PropertyKey, TokenId,56};5758pub mod weights;5960#[cfg(feature = "runtime-benchmarks")]61mod benchmarking;6263pub use module::*;64pub use weights::WeightInfo;6566#[frame_support::pallet]67pub mod module {68 use up_data_structs::{69 CollectionDescription, Property, PropertyKeyPermission, PropertyPermission,70 };7172 use super::*;7374 #[pallet::config]75 pub trait Config:76 frame_system::Config77 + pallet_common::Config78 + pallet_fungible::Config79 + pallet_balances::Config80 {81 /// The overarching event type.82 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;8384 /// Origin for force registering of a foreign asset.85 type ForceRegisterOrigin: EnsureOrigin<Self::RuntimeOrigin>;8687 /// The ID of the foreign assets pallet.88 type PalletId: Get<PalletId>;8990 /// Weight information for the extrinsics in this module.91 type WeightInfo: WeightInfo;92 }9394 #[pallet::error]95 pub enum Error<T> {96 /// The foreign asset is already registered97 ForeignAssetAlreadyRegistered,98 }99100 #[pallet::event]101 #[pallet::generate_deposit(fn deposit_event)]102 pub enum Event<T: Config> {103 /// The foreign asset registered.104 ForeignAssetRegistered {105 asset_id: CollectionId,106 reserve_location: MultiLocation,107 },108 }109110 /// The corresponding collections of reserve locations.111 #[pallet::storage]112 #[pallet::getter(fn foreign_reserve_location_to_collection)]113 pub type ForeignReserveLocationToCollection<T: Config> =114 StorageMap<_, Twox64Concat, staging_xcm::v3::MultiLocation, CollectionId, OptionQuery>;115116 /// The correponding NFT token id of reserve NFTs117 #[pallet::storage]118 #[pallet::getter(fn foreign_reserve_asset_instance_to_token_id)]119 pub type ForeignReserveAssetInstanceToTokenId<T: Config> = StorageDoubleMap<120 Hasher1 = Twox64Concat,121 Key1 = CollectionId,122 Hasher2 = Twox64Concat,123 Key2 = staging_xcm::v3::AssetInstance,124 Value = TokenId,125 QueryKind = OptionQuery,126 >;127128 #[pallet::pallet]129 pub struct Pallet<T>(_);130131 #[pallet::call]132 impl<T: Config> Pallet<T> {133 #[pallet::call_index(0)]134 #[pallet::weight(<T as Config>::WeightInfo::register_foreign_asset())]135 pub fn force_register_foreign_asset(136 origin: OriginFor<T>,137 reserve_location: MultiLocation,138 name: CollectionName,139 mode: CollectionMode,140 ) -> DispatchResult {141 T::ForceRegisterOrigin::ensure_origin(origin.clone())?;142143 let foreign_collection_owner = Self::pallet_account();144145 let description: CollectionDescription = "Foreign Assets Collection"146 .encode_utf16()147 .collect::<Vec<_>>()148 .try_into()149 .expect("description length < max description length; qed");150151 let collection_id = T::CollectionDispatch::create_foreign(152 foreign_collection_owner,153 CreateCollectionData {154 name,155 description,156 mode,157158 properties: vec![Property {159 key: Self::reserve_location_property_key(),160 value: reserve_location161 .encode()162 .try_into()163 .expect("multilocation is less than 32k; qed"),164 }]165 .try_into()166 .expect("just one property can always be stored; qed"),167168 token_property_permissions: vec![PropertyKeyPermission {169 key: Self::reserve_asset_instance_property_key(),170 permission: PropertyPermission {171 mutable: false,172 collection_admin: true,173 token_owner: false,174 },175 }]176 .try_into()177 .expect("just one property permission can always be stored; qed"),178 ..Default::default()179 },180 )?;181182 <ForeignReserveLocationToCollection<T>>::insert(reserve_location, collection_id);183184 Self::deposit_event(Event::<T>::ForeignAssetRegistered {185 asset_id: collection_id,186 reserve_location,187 });188189 Ok(())190 }191 }192}193194impl<T: Config> Pallet<T> {195 fn pallet_account() -> T::CrossAccountId {196 let owner: T::AccountId = T::PalletId::get().into_account_truncating();197 T::CrossAccountId::from_sub(owner)198 }199200 fn reserve_location_property_key() -> PropertyKey {201 b"reserve-location"202 .to_vec()203 .try_into()204 .expect("key length < max property key length; qed")205 }206207 fn reserve_asset_instance_property_key() -> PropertyKey {208 b"reserve-asset-instance"209 .to_vec()210 .try_into()211 .expect("key length < max property key length; qed")212 }213}214215impl<T: Config> TransactAsset for Pallet<T> {216 fn can_check_in(217 _origin: &MultiLocation,218 _what: &MultiAsset,219 _context: &XcmContext,220 ) -> XcmResult {221 Err(XcmError::Unimplemented)222 }223224 fn check_in(_origin: &MultiLocation, _what: &MultiAsset, _context: &XcmContext) {}225226 fn can_check_out(227 _dest: &MultiLocation,228 _what: &MultiAsset,229 _context: &XcmContext,230 ) -> XcmResult {231 Err(XcmError::Unimplemented)232 }233234 fn check_out(_dest: &MultiLocation, _what: &MultiAsset, _context: &XcmContext) {}235236 fn deposit_asset(what: &MultiAsset, to: &MultiLocation, context: &XcmContext) -> XcmResult {237 Err(XcmError::Unimplemented)238 }239240 fn withdraw_asset(241 what: &MultiAsset,242 from: &MultiLocation,243 _maybe_context: Option<&XcmContext>,244 ) -> Result<staging_xcm_executor::Assets, XcmError> {245 Err(XcmError::Unimplemented)246 }247248 fn internal_transfer_asset(249 what: &MultiAsset,250 from: &MultiLocation,251 to: &MultiLocation,252 _context: &XcmContext,253 ) -> Result<staging_xcm_executor::Assets, XcmError> {254 Err(XcmError::Unimplemented)255 }256}257258pub struct CurrencyIdConvert<T: Config>(PhantomData<T>);259impl<T: Config> sp_runtime::traits::Convert<CollectionId, Option<MultiLocation>>260 for CurrencyIdConvert<T>261{262 fn convert(collection_id: CollectionId) -> Option<MultiLocation> {263 if collection_id == NATIVE_FUNGIBLE_COLLECTION_ID {264 Some(Here.into())265 } else {266 // let dispatch = T::CollectionDispatch::dispatch(collection_id).ok()?;267 // let collection = dispatch.as_dyn();268 // let xcm_ext = collection.xcm_extensions()?;269270 // if xcm_ext.is_foreign() {271 // let encoded_location =272 // collection.property(&<Pallet<T>>::reserve_location_property_key())?;273 // MultiLocation::decode(&mut &encoded_location[..]).ok()274 // } else {275 // T::SelfLocation::get()276 // .pushed_with_interior(GeneralIndex(collection_id.0.into()))277 // .ok()278 // }279 todo!()280 }281 }282}283284pub use frame_support::{285 traits::{286 fungibles::Balanced, tokens::currency::Currency as CurrencyT, OnUnbalanced as OnUnbalancedT,287 },288 weights::{WeightToFee, WeightToFeePolynomial},289};290291pub struct FreeForAll;292293impl WeightTrader for FreeForAll {294 fn new() -> Self {295 Self296 }297298 fn buy_weight(299 &mut self,300 weight: Weight,301 payment: Assets,302 _xcm: &XcmContext,303 ) -> Result<Assets, XcmError> {304 log::trace!(target: "fassets::weight", "buy_weight weight: {:?}, payment: {:?}", weight, payment);305 Ok(payment)306 }307}1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! # Foreign assets18//!19//! - [`Config`]20//! - [`Call`]21//! - [`Pallet`]22//!23//! ## Overview24//!25//! Under construction2627#![cfg_attr(not(feature = "std"), no_std)]28#![allow(clippy::unused_unit)]2930use frame_support::{dispatch::DispatchResult, pallet_prelude::*, traits::EnsureOrigin, PalletId};31use frame_system::pallet_prelude::*;32use pallet_common::{33 dispatch::CollectionDispatch, erc::CrossAccountId, XcmExtensions, NATIVE_FUNGIBLE_COLLECTION_ID,34};35use sp_runtime::traits::AccountIdConversion;36use sp_std::{vec, vec::Vec};37use staging_xcm::{38 opaque::latest::{prelude::XcmError, Weight},39 v3::{prelude::*, MultiAsset, XcmContext},40};41use staging_xcm_executor::{42 traits::{ConvertLocation, Error as XcmExecutorError, TransactAsset, WeightTrader},43 Assets,44};45use up_data_structs::{46 budget::ZeroBudget, CollectionId, CollectionMode, CollectionName, CreateCollectionData,47 CreateFungibleData, CreateItemData, CreateNftData, Property, PropertyKey, TokenId,48};4950pub mod weights;5152#[cfg(feature = "runtime-benchmarks")]53mod benchmarking;5455pub use module::*;56pub use weights::WeightInfo;5758#[frame_support::pallet]59pub mod module {60 use up_data_structs::{61 CollectionDescription, Property, PropertyKeyPermission, PropertyPermission,62 };6364 use super::*;6566 #[pallet::config]67 pub trait Config:68 frame_system::Config69 + pallet_common::Config70 + pallet_fungible::Config71 + pallet_balances::Config72 {73 /// The overarching event type.74 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;7576 /// Origin for force registering of a foreign asset.77 type ForceRegisterOrigin: EnsureOrigin<Self::RuntimeOrigin>;7879 /// The ID of the foreign assets pallet.80 type PalletId: Get<PalletId>;8182 /// Self-location of this parachain.83 type SelfLocation: Get<MultiLocation>;8485 /// The converter from a MultiLocation to a CrossAccountId.86 type LocationToAccountId: ConvertLocation<Self::CrossAccountId>;8788 /// Weight information for the extrinsics in this module.89 type WeightInfo: WeightInfo;90 }9192 #[pallet::error]93 pub enum Error<T> {94 /// The foreign asset is already registered95 ForeignAssetAlreadyRegistered,96 }9798 #[pallet::event]99 #[pallet::generate_deposit(fn deposit_event)]100 pub enum Event<T: Config> {101 /// The foreign asset registered.102 ForeignAssetRegistered {103 asset_id: CollectionId,104 reserve_location: MultiLocation,105 },106 }107108 /// The corresponding collections of reserve locations.109 #[pallet::storage]110 #[pallet::getter(fn foreign_reserve_location_to_collection)]111 pub type ForeignReserveLocationToCollection<T: Config> =112 StorageMap<_, Twox64Concat, staging_xcm::v3::MultiLocation, CollectionId, OptionQuery>;113114 /// The corresponding reserve location of collections.115 #[pallet::storage]116 #[pallet::getter(fn collection_to_foreign_reserve_location)]117 pub type CollectionToForeignReserveLocation<T: Config> =118 StorageMap<_, Twox64Concat, CollectionId, staging_xcm::v3::MultiLocation, OptionQuery>;119120 /// The correponding NFT token id of reserve NFTs121 #[pallet::storage]122 #[pallet::getter(fn foreign_reserve_asset_instance_to_token_id)]123 pub type ForeignReserveAssetInstanceToTokenId<T: Config> = StorageDoubleMap<124 Hasher1 = Twox64Concat,125 Key1 = CollectionId,126 Hasher2 = Twox64Concat,127 Key2 = staging_xcm::v3::AssetInstance,128 Value = TokenId,129 QueryKind = OptionQuery,130 >;131132 #[pallet::pallet]133 pub struct Pallet<T>(_);134135 #[pallet::call]136 impl<T: Config> Pallet<T> {137 #[pallet::call_index(0)]138 #[pallet::weight(<T as Config>::WeightInfo::register_foreign_asset())]139 pub fn force_register_foreign_asset(140 origin: OriginFor<T>,141 reserve_location: MultiLocation,142 name: CollectionName,143 mode: CollectionMode,144 ) -> DispatchResult {145 T::ForceRegisterOrigin::ensure_origin(origin.clone())?;146147 let foreign_collection_owner = Self::pallet_account();148149 let description: CollectionDescription = "Foreign Assets Collection"150 .encode_utf16()151 .collect::<Vec<_>>()152 .try_into()153 .expect("description length < max description length; qed");154155 let collection_id = T::CollectionDispatch::create_foreign(156 foreign_collection_owner,157 CreateCollectionData {158 name,159 description,160 mode,161162 properties: vec![Property {163 key: Self::reserve_location_property_key(),164 value: reserve_location165 .encode()166 .try_into()167 .expect("multilocation is less than 32k; qed"),168 }]169 .try_into()170 .expect("just one property can always be stored; qed"),171172 token_property_permissions: vec![PropertyKeyPermission {173 key: Self::reserve_asset_instance_property_key(),174 permission: PropertyPermission {175 mutable: false,176 collection_admin: true,177 token_owner: false,178 },179 }]180 .try_into()181 .expect("just one property permission can always be stored; qed"),182 ..Default::default()183 },184 )?;185186 <ForeignReserveLocationToCollection<T>>::insert(reserve_location, collection_id);187 <CollectionToForeignReserveLocation<T>>::insert(collection_id, reserve_location);188189 Self::deposit_event(Event::<T>::ForeignAssetRegistered {190 asset_id: collection_id,191 reserve_location,192 });193194 Ok(())195 }196 }197}198199impl<T: Config> Pallet<T> {200 fn pallet_account() -> T::CrossAccountId {201 let owner: T::AccountId = T::PalletId::get().into_account_truncating();202 T::CrossAccountId::from_sub(owner)203 }204205 fn reserve_location_property_key() -> PropertyKey {206 b"reserve-location"207 .to_vec()208 .try_into()209 .expect("key length < max property key length; qed")210 }211212 fn reserve_asset_instance_property_key() -> PropertyKey {213 b"reserve-asset-instance"214 .to_vec()215 .try_into()216 .expect("key length < max property key length; qed")217 }218219 fn native_asset_location_to_collection(220 asset_location: &MultiLocation,221 ) -> Result<Option<CollectionId>, XcmError> {222 let self_location = T::SelfLocation::get();223224 if *asset_location == Here.into() {225 Ok(Some(NATIVE_FUNGIBLE_COLLECTION_ID))226 } else if *asset_location == self_location {227 Ok(Some(NATIVE_FUNGIBLE_COLLECTION_ID))228 } else if asset_location.parents == self_location.parents {229 match asset_location230 .interior231 .match_and_split(&self_location.interior)232 {233 Some(GeneralIndex(collection_id)) => Ok(Some(CollectionId(234 (*collection_id)235 .try_into()236 .map_err(|_| XcmExecutorError::AssetIdConversionFailed)?,237 ))),238 _ => Ok(None),239 }240 } else {241 Ok(None)242 }243 }244245 fn multiasset_to_collection(asset: &MultiAsset) -> Result<CollectionId, XcmError> {246 let AssetId::Concrete(asset_reserve_location) = asset.id else {247 return Err(XcmExecutorError::AssetNotHandled.into());248 };249250 Self::native_asset_location_to_collection(&asset_reserve_location)?251 .or_else(|| Self::foreign_reserve_location_to_collection(asset_reserve_location))252 .ok_or_else(|| XcmExecutorError::AssetIdConversionFailed.into())253 }254255 fn native_asset_instance_to_token_id(256 asset_instance: &AssetInstance,257 ) -> Result<TokenId, XcmError> {258 match asset_instance {259 AssetInstance::Index(token_id) => Ok(TokenId(260 (*token_id)261 .try_into()262 .map_err(|_| XcmError::AssetNotFound)?,263 )),264 _ => Err(XcmError::AssetNotFound),265 }266 }267268 /// Obtains the token id of the `asset_instance` in the collection.269 ///270 /// Returns `Ok(None)` only if the `asset_instance` points to a foreign item271 /// and it haven't been created on this blockchain yet.272 ///273 /// If the `asset_instance` points to a native item, it cannot return `Ok(None)`.274 fn asset_instance_to_token_id(275 xcm_ext: &dyn XcmExtensions<T>,276 collection_id: CollectionId,277 asset_instance: &AssetInstance,278 ) -> Result<Option<TokenId>, XcmError> {279 if xcm_ext.is_foreign() {280 Ok(Self::foreign_reserve_asset_instance_to_token_id(281 collection_id,282 asset_instance,283 ))284 } else {285 Self::native_asset_instance_to_token_id(asset_instance).map(Some)286 }287 }288289 fn create_foreign_asset_instance(290 xcm_ext: &dyn XcmExtensions<T>,291 collection_id: CollectionId,292 asset_instance: &AssetInstance,293 to: T::CrossAccountId,294 ) -> XcmResult {295 let asset_instance_encoded = asset_instance.encode();296297 let derivative_token_id = xcm_ext298 .create_item(299 &Self::pallet_account(),300 to,301 CreateItemData::NFT(CreateNftData {302 properties: vec![Property {303 key: Self::reserve_asset_instance_property_key(),304 value: asset_instance_encoded305 .try_into()306 .expect("asset instance length <= 32 bytes which is less than value length limit; qed"),307 }]308 .try_into()309 .expect("just one property can always be stored; qed"),310 }),311 &ZeroBudget,312 )313 .map_err(|_| XcmError::FailedToTransactAsset("non-fungible item deposit failed"))?;314315 <ForeignReserveAssetInstanceToTokenId<T>>::insert(316 collection_id,317 asset_instance,318 derivative_token_id,319 );320321 Ok(())322 }323324 fn deposit_asset_instance(325 xcm_ext: &dyn XcmExtensions<T>,326 collection_id: CollectionId,327 to: T::CrossAccountId,328 asset_instance: &AssetInstance,329 ) -> XcmResult {330 if let Some(token_id) =331 Self::asset_instance_to_token_id(xcm_ext, collection_id, asset_instance)?332 {333 let depositor = &Self::pallet_account();334 let from = depositor;335 let amount = 1;336337 xcm_ext338 .transfer_item(depositor, from, &to, token_id, amount, &ZeroBudget)339 .map_err(|_| XcmError::FailedToTransactAsset("non-fungible item deposit failed"))340 } else {341 Self::create_foreign_asset_instance(xcm_ext, collection_id, asset_instance, to)342 }343 }344}345346impl<T: Config> TransactAsset for Pallet<T> {347 fn can_check_in(348 _origin: &MultiLocation,349 _what: &MultiAsset,350 _context: &XcmContext,351 ) -> XcmResult {352 Err(XcmError::Unimplemented)353 }354355 fn check_in(_origin: &MultiLocation, _what: &MultiAsset, _context: &XcmContext) {}356357 fn can_check_out(358 _dest: &MultiLocation,359 _what: &MultiAsset,360 _context: &XcmContext,361 ) -> XcmResult {362 Err(XcmError::Unimplemented)363 }364365 fn check_out(_dest: &MultiLocation, _what: &MultiAsset, _context: &XcmContext) {}366367 fn deposit_asset(what: &MultiAsset, to: &MultiLocation, context: &XcmContext) -> XcmResult {368 let collection_id = Self::multiasset_to_collection(what)?;369 let dispatch =370 T::CollectionDispatch::dispatch(collection_id).map_err(|_| XcmError::AssetNotFound)?;371372 let collection = dispatch.as_dyn();373 let xcm_ext = collection.xcm_extensions().ok_or(XcmError::Unimplemented)?;374375 let to = T::LocationToAccountId::convert_location(to)376 .ok_or(XcmExecutorError::AccountIdConversionFailed)?;377378 match what.fun {379 Fungibility::Fungible(amount) => xcm_ext380 .create_item(381 &Self::pallet_account(),382 to,383 CreateItemData::Fungible(CreateFungibleData { value: amount }),384 &ZeroBudget,385 )386 .map(|_| ())387 .map_err(|_| XcmError::FailedToTransactAsset("fungible item deposit failed")),388389 Fungibility::NonFungible(asset_instance) => {390 Self::deposit_asset_instance(xcm_ext, collection_id, to, &asset_instance)391 }392 }393 }394395 fn withdraw_asset(396 what: &MultiAsset,397 from: &MultiLocation,398 _maybe_context: Option<&XcmContext>,399 ) -> Result<staging_xcm_executor::Assets, XcmError> {400 Err(XcmError::Unimplemented)401 }402403 fn internal_transfer_asset(404 what: &MultiAsset,405 from: &MultiLocation,406 to: &MultiLocation,407 _context: &XcmContext,408 ) -> Result<staging_xcm_executor::Assets, XcmError> {409 Err(XcmError::Unimplemented)410 }411}412413pub struct CurrencyIdConvert<T: Config>(PhantomData<T>);414impl<T: Config> sp_runtime::traits::Convert<CollectionId, Option<MultiLocation>>415 for CurrencyIdConvert<T>416{417 fn convert(collection_id: CollectionId) -> Option<MultiLocation> {418 if collection_id == NATIVE_FUNGIBLE_COLLECTION_ID {419 Some(Here.into())420 } else {421 let dispatch = T::CollectionDispatch::dispatch(collection_id).ok()?;422 let collection = dispatch.as_dyn();423 let xcm_ext = collection.xcm_extensions()?;424425 if xcm_ext.is_foreign() {426 <Pallet<T>>::collection_to_foreign_reserve_location(collection_id)427 } else {428 T::SelfLocation::get()429 .pushed_with_interior(GeneralIndex(collection_id.0.into()))430 .ok()431 }432 }433 }434}435436pub use frame_support::{437 traits::{438 fungibles::Balanced, tokens::currency::Currency as CurrencyT, OnUnbalanced as OnUnbalancedT,439 },440 weights::{WeightToFee, WeightToFeePolynomial},441};442443pub struct FreeForAll;444445impl WeightTrader for FreeForAll {446 fn new() -> Self {447 Self448 }449450 fn buy_weight(451 &mut self,452 weight: Weight,453 payment: Assets,454 _xcm: &XcmContext,455 ) -> Result<Assets, XcmError> {456 log::trace!(target: "fassets::weight", "buy_weight weight: {:?}, payment: {:?}", weight, payment);457 Ok(payment)458 }459}pallets/fungible/src/common.rsdiffbeforeafterboth--- a/pallets/fungible/src/common.rs
+++ b/pallets/fungible/src/common.rs
@@ -19,7 +19,7 @@
use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight};
use pallet_common::{
weights::WeightInfo as _, with_weight, CommonCollectionOperations, CommonWeightInfo,
- Error as CommonError, RefungibleExtensions, SelfWeightOf as PalletCommonWeightOf,
+ Error as CommonError, SelfWeightOf as PalletCommonWeightOf, XcmExtensions,
};
use sp_runtime::{ArithmeticError, DispatchError};
use sp_std::{vec, vec::Vec};
@@ -114,7 +114,7 @@
<Pallet<T>>::create_item(self, &sender, (to, fungible_data.value), nesting_budget),
<CommonWeights<T>>::create_item(&data),
),
- _ => fail!(<Error<T>>::NotFungibleDataUsedToMintFungibleCollectionToken),
+ _ => fail!(<CommonError<T>>::NotFungibleDataUsedToMintFungibleCollectionToken),
}
}
@@ -133,7 +133,7 @@
.checked_add(data.value)
.ok_or(ArithmeticError::Overflow)?;
}
- _ => fail!(<Error<T>>::NotFungibleDataUsedToMintFungibleCollectionToken),
+ _ => fail!(<CommonError<T>>::NotFungibleDataUsedToMintFungibleCollectionToken),
}
}
@@ -152,7 +152,7 @@
let weight = <CommonWeights<T>>::create_multiple_items_ex(&data);
let data = match data {
up_data_structs::CreateItemExData::Fungible(f) => f,
- _ => fail!(<Error<T>>::NotFungibleDataUsedToMintFungibleCollectionToken),
+ _ => fail!(<CommonError<T>>::NotFungibleDataUsedToMintFungibleCollectionToken),
};
with_weight(
@@ -435,6 +435,10 @@
<TotalSupply<T>>::try_get(self.id).ok()
}
+ fn xcm_extensions(&self) -> Option<&dyn XcmExtensions<T>> {
+ Some(self)
+ }
+
fn set_allowance_for_all(
&self,
_owner: T::CrossAccountId,
@@ -453,3 +457,61 @@
fail!(<Error<T>>::FungibleTokensAreAlwaysValid)
}
}
+
+impl<T: Config> XcmExtensions<T> for FungibleHandle<T> {
+ fn is_foreign(&self) -> bool {
+ self.flags.foreign
+ }
+
+ fn create_item_internal(
+ &self,
+ depositor: &<T>::CrossAccountId,
+ to: <T>::CrossAccountId,
+ data: CreateItemData,
+ nesting_budget: &dyn Budget,
+ ) -> Result<TokenId, sp_runtime::DispatchError> {
+ match &data {
+ up_data_structs::CreateItemData::Fungible(fungible_data) => {
+ <Pallet<T>>::create_multiple_items(
+ self,
+ &depositor,
+ [(to, fungible_data.value)].into_iter().collect(),
+ nesting_budget,
+ )?
+ }
+ _ => fail!(<CommonError<T>>::NotFungibleDataUsedToMintFungibleCollectionToken),
+ }
+
+ Ok(TokenId::default())
+ }
+
+ fn transfer_item_internal(
+ &self,
+ depositor: &<T>::CrossAccountId,
+ from: &<T>::CrossAccountId,
+ to: &<T>::CrossAccountId,
+ token: TokenId,
+ amount: u128,
+ nesting_budget: &dyn Budget,
+ ) -> sp_runtime::DispatchResult {
+ ensure!(
+ token == TokenId::default(),
+ <CommonError<T>>::FungibleItemsHaveNoId
+ );
+
+ <Pallet<T>>::transfer_internal(self, &depositor, &from, &to, amount, nesting_budget)
+ .map(|_| ())
+ .map_err(|post_info| post_info.error)
+ }
+
+ fn burn_item_internal(
+ &self,
+ from: <T>::CrossAccountId,
+ token: TokenId,
+ amount: u128,
+ ) -> sp_runtime::DispatchResult {
+ <Self as CommonCollectionOperations<T>>::burn_item(&self, from, token, amount)
+ .map(|_| ())
+ .map_err(|post_info| post_info.error)
+ }
+}
pallets/fungible/src/lib.rsdiffbeforeafterboth--- a/pallets/fungible/src/lib.rs
+++ b/pallets/fungible/src/lib.rs
@@ -95,8 +95,9 @@
use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};
use sp_std::{collections::btree_map::BTreeMap, vec::Vec};
use up_data_structs::{
- budget::Budget, mapping::TokenAddressMapping, AccessMode, CollectionId, CreateCollectionData,
- Property, PropertyKey, TokenId,
+ budget::{Budget, ZeroBudget},
+ mapping::TokenAddressMapping,
+ AccessMode, CollectionId, CreateCollectionData, Property, PropertyKey, TokenId,
};
use weights::WeightInfo;
@@ -121,8 +122,6 @@
#[pallet::error]
pub enum Error<T> {
- /// Not Fungible item data used to mint in Fungible collection.
- NotFungibleDataUsedToMintFungibleCollectionToken,
/// Tried to set data for fungible item.
FungibleItemsDontHaveData,
/// Fungible token does not support nesting.
@@ -275,9 +274,6 @@
let balance = <Balance<T>>::get((collection.id, owner))
.checked_sub(amount)
.ok_or(<CommonError<T>>::TokenValueTooLow)?;
-
- // Foreign collection check
- ensure!(!collection.flags.foreign, <CommonError<T>>::NoPermission);
if collection.permissions.access() == AccessMode::AllowList {
collection.check_allowlist(owner)?;
@@ -309,47 +305,7 @@
));
Ok(())
}
-
- /// Burns the specified amount of the token.
- pub fn burn_foreign(
- collection: &FungibleHandle<T>,
- owner: &T::CrossAccountId,
- amount: u128,
- ) -> DispatchResult {
- let total_supply = <TotalSupply<T>>::get(collection.id)
- .checked_sub(amount)
- .ok_or(<CommonError<T>>::TokenValueTooLow)?;
-
- let balance = <Balance<T>>::get((collection.id, owner))
- .checked_sub(amount)
- .ok_or(<CommonError<T>>::TokenValueTooLow)?;
- // =========
- if balance == 0 {
- <Balance<T>>::remove((collection.id, owner));
- <PalletStructure<T>>::unnest_if_nested(owner, collection.id, TokenId::default());
- } else {
- <Balance<T>>::insert((collection.id, owner), balance);
- }
- <TotalSupply<T>>::insert(collection.id, total_supply);
-
- <PalletEvm<T>>::deposit_log(
- ERC20Events::Transfer {
- from: *owner.as_eth(),
- to: H160::default(),
- value: amount.into(),
- }
- .to_log(collection_id_to_address(collection.id)),
- );
- <PalletCommon<T>>::deposit_event(CommonEvent::ItemDestroyed(
- collection.id,
- TokenId::default(),
- owner.clone(),
- amount,
- ));
- Ok(())
- }
-
/// Transfers the specified amount of tokens. Will check that
/// the transfer is allowed for the token.
///
@@ -450,14 +406,25 @@
}
/// Minting tokens for multiple IDs.
- /// It is a utility function used in [`create_multiple_items`][`Pallet::create_multiple_items`]
- /// and [`create_multiple_items_foreign`][`Pallet::create_multiple_items_foreign`]
- pub fn create_multiple_items_common(
+ /// See [`create_item`][`Pallet::create_item`] for more details.
+ pub fn create_multiple_items(
collection: &FungibleHandle<T>,
- sender: &T::CrossAccountId,
+ depositor: &T::CrossAccountId,
data: BTreeMap<T::CrossAccountId, u128>,
nesting_budget: &dyn Budget,
) -> DispatchResult {
+ if !collection.is_owner_or_admin(depositor) {
+ ensure!(
+ collection.permissions.mint_mode(),
+ <CommonError<T>>::PublicMintingNotAllowed
+ );
+ collection.check_allowlist(depositor)?;
+
+ for (owner, _) in data.iter() {
+ collection.check_allowlist(owner)?;
+ }
+ }
+
let total_supply = data
.values()
.copied()
@@ -468,7 +435,7 @@
for (to, _) in data.iter() {
<PalletStructure<T>>::check_nesting(
- sender,
+ depositor,
to,
collection.id,
TokenId::default(),
@@ -514,44 +481,7 @@
Ok(())
}
-
- /// Minting tokens for multiple IDs.
- /// See [`create_item`][`Pallet::create_item`] for more details.
- pub fn create_multiple_items(
- collection: &FungibleHandle<T>,
- sender: &T::CrossAccountId,
- data: BTreeMap<T::CrossAccountId, u128>,
- nesting_budget: &dyn Budget,
- ) -> DispatchResult {
- // Foreign collection check
- ensure!(!collection.flags.foreign, <CommonError<T>>::NoPermission);
-
- if !collection.is_owner_or_admin(sender) {
- ensure!(
- collection.permissions.mint_mode(),
- <CommonError<T>>::PublicMintingNotAllowed
- );
- collection.check_allowlist(sender)?;
-
- for (owner, _) in data.iter() {
- collection.check_allowlist(owner)?;
- }
- }
- Self::create_multiple_items_common(collection, sender, data, nesting_budget)
- }
-
- /// Minting tokens for multiple IDs.
- /// See [`create_item_foreign`][`Pallet::create_item_foreign`] for more details.
- pub fn create_multiple_items_foreign(
- collection: &FungibleHandle<T>,
- sender: &T::CrossAccountId,
- data: BTreeMap<T::CrossAccountId, u128>,
- nesting_budget: &dyn Budget,
- ) -> DispatchResult {
- Self::create_multiple_items_common(collection, sender, data, nesting_budget)
- }
-
fn set_allowance_unchecked(
collection: &FungibleHandle<T>,
owner: &T::CrossAccountId,
@@ -777,24 +707,6 @@
nesting_budget: &dyn Budget,
) -> DispatchResult {
Self::create_multiple_items(
- collection,
- sender,
- [(data.0, data.1)].into_iter().collect(),
- nesting_budget,
- )
- }
-
- /// Creates fungible token.
- ///
- /// - `data`: Contains user who will become the owners of the tokens and amount
- /// of tokens he will receive.
- pub fn create_item_foreign(
- collection: &FungibleHandle<T>,
- sender: &T::CrossAccountId,
- data: CreateItemData<T>,
- nesting_budget: &dyn Budget,
- ) -> DispatchResult {
- Self::create_multiple_items_foreign(
collection,
sender,
[(data.0, data.1)].into_iter().collect(),
pallets/nonfungible/src/common.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/common.rs
+++ b/pallets/nonfungible/src/common.rs
@@ -19,8 +19,8 @@
use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight};
use pallet_common::{
weights::WeightInfo as _, with_weight, write_token_properties_total_weight,
- CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions,
- SelfWeightOf as PalletCommonWeightOf,
+ CommonCollectionOperations, CommonWeightInfo, SelfWeightOf as PalletCommonWeightOf,
+ XcmExtensions,
};
use pallet_structure::Pallet as PalletStructure;
use sp_runtime::DispatchError;
@@ -543,6 +543,10 @@
}
}
+ fn xcm_extensions(&self) -> Option<&dyn XcmExtensions<T>> {
+ Some(self)
+ }
+
fn set_allowance_for_all(
&self,
owner: T::CrossAccountId,
@@ -566,3 +570,53 @@
)
}
}
+
+impl<T: Config> XcmExtensions<T> for NonfungibleHandle<T> {
+ fn is_foreign(&self) -> bool {
+ self.flags.foreign
+ }
+
+ fn create_item_internal(
+ &self,
+ depositor: &<T>::CrossAccountId,
+ to: <T>::CrossAccountId,
+ data: up_data_structs::CreateItemData,
+ nesting_budget: &dyn Budget,
+ ) -> Result<TokenId, sp_runtime::DispatchError> {
+ <Pallet<T>>::create_multiple_items(
+ self,
+ &depositor,
+ vec![map_create_data::<T>(data, &to)?],
+ nesting_budget,
+ )?;
+
+ Ok(self.last_token_id())
+ }
+
+ fn transfer_item_internal(
+ &self,
+ depositor: &<T>::CrossAccountId,
+ from: &<T>::CrossAccountId,
+ to: &<T>::CrossAccountId,
+ token: TokenId,
+ amount: u128,
+ nesting_budget: &dyn Budget,
+ ) -> sp_runtime::DispatchResult {
+ ensure!(amount == 1, <Error<T>>::NonfungibleItemsHaveNoAmount);
+
+ <Pallet<T>>::transfer_internal(self, &depositor, &from, &to, token, nesting_budget)
+ .map(|_| ())
+ .map_err(|post_info| post_info.error)
+ }
+
+ fn burn_item_internal(
+ &self,
+ from: T::CrossAccountId,
+ token: TokenId,
+ amount: u128,
+ ) -> sp_runtime::DispatchResult {
+ ensure!(amount == 1, <Error<T>>::NonfungibleItemsHaveNoAmount);
+
+ <Pallet<T>>::burn(self, &from, token)
+ }
+}
primitives/data-structs/src/budget.rsdiffbeforeafterboth--- a/primitives/data-structs/src/budget.rs
+++ b/primitives/data-structs/src/budget.rs
@@ -36,3 +36,10 @@
true
}
}
+
+pub struct ZeroBudget;
+impl Budget for ZeroBudget {
+ fn consume_custom(&self, _calls: u32) -> bool {
+ false
+ }
+}
runtime/common/config/pallets/foreign_asset.rsdiffbeforeafterboth--- a/runtime/common/config/pallets/foreign_asset.rs
+++ b/runtime/common/config/pallets/foreign_asset.rs
@@ -1,14 +1,43 @@
use frame_support::{parameter_types, PalletId};
+use pallet_evm::account::CrossAccountId;
+use sp_core::H160;
+use staging_xcm::prelude::*;
+use staging_xcm_builder::AccountKey20Aliases;
-use crate::{runtime_common::config::governance, Runtime, RuntimeEvent};
+use crate::{
+ runtime_common::config::{
+ ethereum::CrossAccountId as ConfigCrossAccountId,
+ governance,
+ xcm::{LocationToAccountId, SelfLocation},
+ },
+ RelayNetwork, Runtime, RuntimeEvent,
+};
parameter_types! {
pub ForeignAssetPalletId: PalletId = PalletId(*b"frgnasts");
}
+pub struct LocationToCrossAccountId;
+impl staging_xcm_executor::traits::ConvertLocation<ConfigCrossAccountId>
+ for LocationToCrossAccountId
+{
+ fn convert_location(location: &MultiLocation) -> Option<ConfigCrossAccountId> {
+ LocationToAccountId::convert_location(location)
+ .map(|sub| ConfigCrossAccountId::from_sub(sub))
+ .or_else(|| {
+ let eth_address =
+ AccountKey20Aliases::<RelayNetwork, H160>::convert_location(location)?;
+
+ Some(ConfigCrossAccountId::from_eth(eth_address))
+ })
+ }
+}
+
impl pallet_foreign_assets::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type ForceRegisterOrigin = governance::RootOrTechnicalCommitteeMember;
type PalletId = ForeignAssetPalletId;
+ type SelfLocation = SelfLocation;
+ type LocationToAccountId = LocationToCrossAccountId;
type WeightInfo = pallet_foreign_assets::weights::SubstrateWeight<Self>;
}