difftreelog
fix use xcm::v2 in storages
in: master
2 files changed
pallets/configuration/src/lib.rsdiffbeforeafterboth--- a/pallets/configuration/src/lib.rs
+++ b/pallets/configuration/src/lib.rs
@@ -116,7 +116,7 @@
#[pallet::storage]
pub type XcmAllowedLocationsOverride<T: Config> = StorageValue<
- Value = BoundedVec<MultiLocation, T::MaxXcmAllowedLocations>,
+ Value = BoundedVec<xcm::v2::MultiLocation, T::MaxXcmAllowedLocations>,
QueryKind = OptionQuery,
>;
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::{38 dispatch::DispatchResult,39 ensure,40 pallet_prelude::*,41 traits::{fungible, fungibles, Currency, EnsureOrigin},42 RuntimeDebug,43};44use frame_system::pallet_prelude::*;45use up_data_structs::{CollectionMode};46use pallet_fungible::{Pallet as PalletFungible};47use scale_info::{TypeInfo};48use sp_runtime::{49 traits::{One, Zero},50 ArithmeticError,51};52use sp_std::{boxed::Box, vec::Vec};53use up_data_structs::{CollectionId, TokenId, CreateCollectionData};5455// NOTE: MultiLocation is used in storages, we will need to do migration if upgrade the56// MultiLocation to the XCM v3.57use xcm::opaque::latest::{prelude::XcmError, Weight};58use xcm::{latest::MultiLocation, VersionedMultiLocation};59use xcm_executor::{traits::WeightTrader, Assets};6061use pallet_common::erc::CrossAccountId;6263#[cfg(feature = "std")]64use serde::{Deserialize, Serialize};6566// TODO: Move to primitives67// Id of native currency.68// 0 - QTZ\UNQ69// 1 - KSM\DOT70#[derive(71 Clone,72 Copy,73 Eq,74 PartialEq,75 PartialOrd,76 Ord,77 MaxEncodedLen,78 RuntimeDebug,79 Encode,80 Decode,81 TypeInfo,82)]83#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]84pub enum NativeCurrency {85 Here = 0,86 Parent = 1,87}8889#[derive(90 Clone,91 Copy,92 Eq,93 PartialEq,94 PartialOrd,95 Ord,96 MaxEncodedLen,97 RuntimeDebug,98 Encode,99 Decode,100 TypeInfo,101)]102#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]103pub enum AssetIds {104 ForeignAssetId(ForeignAssetId),105 NativeAssetId(NativeCurrency),106}107108pub trait TryAsForeign<T, F> {109 fn try_as_foreign(asset: T) -> Option<F>;110}111112impl TryAsForeign<AssetIds, ForeignAssetId> for AssetIds {113 fn try_as_foreign(asset: AssetIds) -> Option<ForeignAssetId> {114 match asset {115 AssetIds::ForeignAssetId(id) => Some(id),116 _ => None,117 }118 }119}120121pub type ForeignAssetId = u32;122pub type CurrencyId = AssetIds;123124mod impl_fungibles;125pub mod weights;126127#[cfg(feature = "runtime-benchmarks")]128mod benchmarking;129130pub use module::*;131pub use weights::WeightInfo;132133/// Type alias for currency balance.134pub type BalanceOf<T> =135 <<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;136137/// A mapping between ForeignAssetId and AssetMetadata.138pub trait AssetIdMapping<ForeignAssetId, MultiLocation, AssetMetadata> {139 /// Returns the AssetMetadata associated with a given ForeignAssetId.140 fn get_asset_metadata(foreign_asset_id: ForeignAssetId) -> Option<AssetMetadata>;141 /// Returns the MultiLocation associated with a given ForeignAssetId.142 fn get_multi_location(foreign_asset_id: ForeignAssetId) -> Option<MultiLocation>;143 /// Returns the CurrencyId associated with a given MultiLocation.144 fn get_currency_id(multi_location: MultiLocation) -> Option<CurrencyId>;145}146147pub struct XcmForeignAssetIdMapping<T>(sp_std::marker::PhantomData<T>);148149impl<T: Config> AssetIdMapping<ForeignAssetId, MultiLocation, AssetMetadata<BalanceOf<T>>>150 for XcmForeignAssetIdMapping<T>151{152 fn get_asset_metadata(foreign_asset_id: ForeignAssetId) -> Option<AssetMetadata<BalanceOf<T>>> {153 log::trace!(target: "fassets::asset_metadatas", "call");154 Pallet::<T>::asset_metadatas(AssetIds::ForeignAssetId(foreign_asset_id))155 }156157 fn get_multi_location(foreign_asset_id: ForeignAssetId) -> Option<MultiLocation> {158 log::trace!(target: "fassets::get_multi_location", "call");159 Pallet::<T>::foreign_asset_locations(foreign_asset_id)160 }161162 fn get_currency_id(multi_location: MultiLocation) -> Option<CurrencyId> {163 log::trace!(target: "fassets::get_currency_id", "call");164 Pallet::<T>::location_to_currency_ids(multi_location).map(|id| AssetIds::ForeignAssetId(id))165 }166}167168#[frame_support::pallet]169pub mod module {170 use super::*;171172 #[pallet::config]173 pub trait Config:174 frame_system::Config175 + pallet_common::Config176 + pallet_fungible::Config177 + orml_tokens::Config178 + pallet_balances::Config179 {180 /// The overarching event type.181 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;182183 /// Currency type for withdraw and balance storage.184 type Currency: Currency<Self::AccountId>;185186 /// Required origin for registering asset.187 type RegisterOrigin: EnsureOrigin<Self::RuntimeOrigin>;188189 /// Weight information for the extrinsics in this module.190 type WeightInfo: WeightInfo;191 }192193 #[derive(Clone, Eq, PartialEq, RuntimeDebug, Encode, Decode, TypeInfo)]194 pub struct AssetMetadata<Balance> {195 pub name: Vec<u8>,196 pub symbol: Vec<u8>,197 pub decimals: u8,198 pub minimal_balance: Balance,199 }200201 #[pallet::error]202 pub enum Error<T> {203 /// The given location could not be used (e.g. because it cannot be expressed in the204 /// desired version of XCM).205 BadLocation,206 /// MultiLocation existed207 MultiLocationExisted,208 /// AssetId not exists209 AssetIdNotExists,210 /// AssetId exists211 AssetIdExisted,212 }213214 #[pallet::event]215 #[pallet::generate_deposit(fn deposit_event)]216 pub enum Event<T: Config> {217 /// The foreign asset registered.218 ForeignAssetRegistered {219 asset_id: ForeignAssetId,220 asset_address: MultiLocation,221 metadata: AssetMetadata<BalanceOf<T>>,222 },223 /// The foreign asset updated.224 ForeignAssetUpdated {225 asset_id: ForeignAssetId,226 asset_address: MultiLocation,227 metadata: AssetMetadata<BalanceOf<T>>,228 },229 /// The asset registered.230 AssetRegistered {231 asset_id: AssetIds,232 metadata: AssetMetadata<BalanceOf<T>>,233 },234 /// The asset updated.235 AssetUpdated {236 asset_id: AssetIds,237 metadata: AssetMetadata<BalanceOf<T>>,238 },239 }240241 /// Next available Foreign AssetId ID.242 ///243 /// NextForeignAssetId: ForeignAssetId244 #[pallet::storage]245 #[pallet::getter(fn next_foreign_asset_id)]246 pub type NextForeignAssetId<T: Config> = StorageValue<_, ForeignAssetId, ValueQuery>;247 /// The storages for MultiLocations.248 ///249 /// ForeignAssetLocations: map ForeignAssetId => Option<MultiLocation>250 #[pallet::storage]251 #[pallet::getter(fn foreign_asset_locations)]252 pub type ForeignAssetLocations<T: Config> =253 StorageMap<_, Twox64Concat, ForeignAssetId, MultiLocation, OptionQuery>;254255 /// The storages for CurrencyIds.256 ///257 /// LocationToCurrencyIds: map MultiLocation => Option<ForeignAssetId>258 #[pallet::storage]259 #[pallet::getter(fn location_to_currency_ids)]260 pub type LocationToCurrencyIds<T: Config> =261 StorageMap<_, Twox64Concat, MultiLocation, ForeignAssetId, OptionQuery>;262263 /// The storages for AssetMetadatas.264 ///265 /// AssetMetadatas: map AssetIds => Option<AssetMetadata>266 #[pallet::storage]267 #[pallet::getter(fn asset_metadatas)]268 pub type AssetMetadatas<T: Config> =269 StorageMap<_, Twox64Concat, AssetIds, AssetMetadata<BalanceOf<T>>, OptionQuery>;270271 /// The storages for assets to fungible collection binding272 ///273 #[pallet::storage]274 #[pallet::getter(fn asset_binding)]275 pub type AssetBinding<T: Config> =276 StorageMap<_, Twox64Concat, ForeignAssetId, CollectionId, OptionQuery>;277278 #[pallet::pallet]279 #[pallet::without_storage_info]280 pub struct Pallet<T>(_);281282 #[pallet::call]283 impl<T: Config> Pallet<T> {284 #[pallet::call_index(0)]285 #[pallet::weight(<T as Config>::WeightInfo::register_foreign_asset())]286 pub fn register_foreign_asset(287 origin: OriginFor<T>,288 owner: T::AccountId,289 location: Box<VersionedMultiLocation>,290 metadata: Box<AssetMetadata<BalanceOf<T>>>,291 ) -> DispatchResult {292 T::RegisterOrigin::ensure_origin(origin.clone())?;293294 let location: MultiLocation = (*location)295 .try_into()296 .map_err(|()| Error::<T>::BadLocation)?;297298 let md = metadata.clone();299 let name: Vec<u16> = md.name.into_iter().map(|x| x as u16).collect::<Vec<u16>>();300 let mut description: Vec<u16> = "Foreign assets collection for "301 .encode_utf16()302 .collect::<Vec<u16>>();303 description.append(&mut name.clone());304305 let data: CreateCollectionData<T::AccountId> = CreateCollectionData {306 name: name.try_into().unwrap(),307 description: description.try_into().unwrap(),308 mode: CollectionMode::Fungible(md.decimals),309 ..Default::default()310 };311 let owner = T::CrossAccountId::from_sub(owner);312 let bounded_collection_id =313 <PalletFungible<T>>::init_foreign_collection(owner.clone(), owner, data)?;314 let foreign_asset_id =315 Self::do_register_foreign_asset(&location, &metadata, bounded_collection_id)?;316317 Self::deposit_event(Event::<T>::ForeignAssetRegistered {318 asset_id: foreign_asset_id,319 asset_address: location,320 metadata: *metadata,321 });322 Ok(())323 }324325 #[pallet::call_index(1)]326 #[pallet::weight(<T as Config>::WeightInfo::update_foreign_asset())]327 pub fn update_foreign_asset(328 origin: OriginFor<T>,329 foreign_asset_id: ForeignAssetId,330 location: Box<VersionedMultiLocation>,331 metadata: Box<AssetMetadata<BalanceOf<T>>>,332 ) -> DispatchResult {333 T::RegisterOrigin::ensure_origin(origin)?;334335 let location: MultiLocation = (*location)336 .try_into()337 .map_err(|()| Error::<T>::BadLocation)?;338 Self::do_update_foreign_asset(foreign_asset_id, &location, &metadata)?;339340 Self::deposit_event(Event::<T>::ForeignAssetUpdated {341 asset_id: foreign_asset_id,342 asset_address: location,343 metadata: *metadata,344 });345 Ok(())346 }347 }348}349350impl<T: Config> Pallet<T> {351 fn get_next_foreign_asset_id() -> Result<ForeignAssetId, DispatchError> {352 NextForeignAssetId::<T>::try_mutate(|current| -> Result<ForeignAssetId, DispatchError> {353 let id = *current;354 *current = current355 .checked_add(One::one())356 .ok_or(ArithmeticError::Overflow)?;357 Ok(id)358 })359 }360361 fn do_register_foreign_asset(362 location: &MultiLocation,363 metadata: &AssetMetadata<BalanceOf<T>>,364 bounded_collection_id: CollectionId,365 ) -> Result<ForeignAssetId, DispatchError> {366 let foreign_asset_id = Self::get_next_foreign_asset_id()?;367 LocationToCurrencyIds::<T>::try_mutate(location, |maybe_currency_ids| -> DispatchResult {368 ensure!(369 maybe_currency_ids.is_none(),370 Error::<T>::MultiLocationExisted371 );372 *maybe_currency_ids = Some(foreign_asset_id);373 // *maybe_currency_ids = Some(CurrencyId::ForeignAsset(foreign_asset_id));374375 ForeignAssetLocations::<T>::try_mutate(376 foreign_asset_id,377 |maybe_location| -> DispatchResult {378 ensure!(maybe_location.is_none(), Error::<T>::MultiLocationExisted);379 *maybe_location = Some(location.clone());380381 AssetMetadatas::<T>::try_mutate(382 AssetIds::ForeignAssetId(foreign_asset_id),383 |maybe_asset_metadatas| -> DispatchResult {384 ensure!(maybe_asset_metadatas.is_none(), Error::<T>::AssetIdExisted);385 *maybe_asset_metadatas = Some(metadata.clone());386 Ok(())387 },388 )389 },390 )?;391392 AssetBinding::<T>::try_mutate(foreign_asset_id, |collection_id| -> DispatchResult {393 *collection_id = Some(bounded_collection_id);394 Ok(())395 })396 })?;397398 Ok(foreign_asset_id)399 }400401 fn do_update_foreign_asset(402 foreign_asset_id: ForeignAssetId,403 location: &MultiLocation,404 metadata: &AssetMetadata<BalanceOf<T>>,405 ) -> DispatchResult {406 ForeignAssetLocations::<T>::try_mutate(407 foreign_asset_id,408 |maybe_multi_locations| -> DispatchResult {409 let old_multi_locations = maybe_multi_locations410 .as_mut()411 .ok_or(Error::<T>::AssetIdNotExists)?;412413 AssetMetadatas::<T>::try_mutate(414 AssetIds::ForeignAssetId(foreign_asset_id),415 |maybe_asset_metadatas| -> DispatchResult {416 ensure!(417 maybe_asset_metadatas.is_some(),418 Error::<T>::AssetIdNotExists419 );420421 // modify location422 if location != old_multi_locations {423 LocationToCurrencyIds::<T>::remove(old_multi_locations.clone());424 LocationToCurrencyIds::<T>::try_mutate(425 location,426 |maybe_currency_ids| -> DispatchResult {427 ensure!(428 maybe_currency_ids.is_none(),429 Error::<T>::MultiLocationExisted430 );431 // *maybe_currency_ids = Some(CurrencyId::ForeignAsset(foreign_asset_id));432 *maybe_currency_ids = Some(foreign_asset_id);433 Ok(())434 },435 )?;436 }437 *maybe_asset_metadatas = Some(metadata.clone());438 *old_multi_locations = location.clone();439 Ok(())440 },441 )442 },443 )444 }445}446447pub use frame_support::{448 traits::{449 fungibles::{Balanced, CreditOf},450 tokens::currency::Currency as CurrencyT,451 OnUnbalanced as OnUnbalancedT,452 },453 weights::{WeightToFeePolynomial, WeightToFee},454};455456pub struct FreeForAll<457 WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,458 AssetId: Get<MultiLocation>,459 AccountId,460 Currency: CurrencyT<AccountId>,461 OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,462>(463 Weight,464 Currency::Balance,465 PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>,466);467468impl<469 WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,470 AssetId: Get<MultiLocation>,471 AccountId,472 Currency: CurrencyT<AccountId>,473 OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,474 > WeightTrader for FreeForAll<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>475{476 fn new() -> Self {477 Self(0, Zero::zero(), PhantomData)478 }479480 fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, XcmError> {481 log::trace!(target: "fassets::weight", "buy_weight weight: {:?}, payment: {:?}", weight, payment);482 Ok(payment)483 }484}485impl<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced> Drop486 for FreeForAll<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>487where488 WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,489 AssetId: Get<MultiLocation>,490 Currency: CurrencyT<AccountId>,491 OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,492{493 fn drop(&mut self) {494 OnUnbalanced::on_unbalanced(Currency::issue(self.1));495 }496}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//! 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::{38 dispatch::DispatchResult,39 ensure,40 pallet_prelude::*,41 traits::{fungible, fungibles, Currency, EnsureOrigin},42 RuntimeDebug,43};44use frame_system::pallet_prelude::*;45use up_data_structs::{CollectionMode};46use pallet_fungible::{Pallet as PalletFungible};47use scale_info::{TypeInfo};48use sp_runtime::{49 traits::{One, Zero},50 ArithmeticError,51};52use sp_std::{boxed::Box, vec::Vec};53use up_data_structs::{CollectionId, TokenId, CreateCollectionData};5455// NOTE: MultiLocation is used in storages, we will need to do migration if upgrade the56// MultiLocation to the XCM v3.57use xcm::opaque::latest::{prelude::XcmError, Weight};58use xcm::{latest::MultiLocation, VersionedMultiLocation};59use xcm_executor::{traits::WeightTrader, Assets};6061use pallet_common::erc::CrossAccountId;6263#[cfg(feature = "std")]64use serde::{Deserialize, Serialize};6566// TODO: Move to primitives67// Id of native currency.68// 0 - QTZ\UNQ69// 1 - KSM\DOT70#[derive(71 Clone,72 Copy,73 Eq,74 PartialEq,75 PartialOrd,76 Ord,77 MaxEncodedLen,78 RuntimeDebug,79 Encode,80 Decode,81 TypeInfo,82)]83#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]84pub enum NativeCurrency {85 Here = 0,86 Parent = 1,87}8889#[derive(90 Clone,91 Copy,92 Eq,93 PartialEq,94 PartialOrd,95 Ord,96 MaxEncodedLen,97 RuntimeDebug,98 Encode,99 Decode,100 TypeInfo,101)]102#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]103pub enum AssetIds {104 ForeignAssetId(ForeignAssetId),105 NativeAssetId(NativeCurrency),106}107108pub trait TryAsForeign<T, F> {109 fn try_as_foreign(asset: T) -> Option<F>;110}111112impl TryAsForeign<AssetIds, ForeignAssetId> for AssetIds {113 fn try_as_foreign(asset: AssetIds) -> Option<ForeignAssetId> {114 match asset {115 AssetIds::ForeignAssetId(id) => Some(id),116 _ => None,117 }118 }119}120121pub type ForeignAssetId = u32;122pub type CurrencyId = AssetIds;123124mod impl_fungibles;125pub mod weights;126127#[cfg(feature = "runtime-benchmarks")]128mod benchmarking;129130pub use module::*;131pub use weights::WeightInfo;132133/// Type alias for currency balance.134pub type BalanceOf<T> =135 <<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;136137/// A mapping between ForeignAssetId and AssetMetadata.138pub trait AssetIdMapping<ForeignAssetId, MultiLocation, AssetMetadata> {139 /// Returns the AssetMetadata associated with a given ForeignAssetId.140 fn get_asset_metadata(foreign_asset_id: ForeignAssetId) -> Option<AssetMetadata>;141 /// Returns the MultiLocation associated with a given ForeignAssetId.142 fn get_multi_location(foreign_asset_id: ForeignAssetId) -> Option<MultiLocation>;143 /// Returns the CurrencyId associated with a given MultiLocation.144 fn get_currency_id(multi_location: MultiLocation) -> Option<CurrencyId>;145}146147pub struct XcmForeignAssetIdMapping<T>(sp_std::marker::PhantomData<T>);148149impl<T: Config> AssetIdMapping<ForeignAssetId, MultiLocation, AssetMetadata<BalanceOf<T>>>150 for XcmForeignAssetIdMapping<T>151{152 fn get_asset_metadata(foreign_asset_id: ForeignAssetId) -> Option<AssetMetadata<BalanceOf<T>>> {153 log::trace!(target: "fassets::asset_metadatas", "call");154 Pallet::<T>::asset_metadatas(AssetIds::ForeignAssetId(foreign_asset_id))155 }156157 fn get_multi_location(foreign_asset_id: ForeignAssetId) -> Option<MultiLocation> {158 log::trace!(target: "fassets::get_multi_location", "call");159 Pallet::<T>::foreign_asset_locations(foreign_asset_id)160 }161162 fn get_currency_id(multi_location: MultiLocation) -> Option<CurrencyId> {163 log::trace!(target: "fassets::get_currency_id", "call");164 Pallet::<T>::location_to_currency_ids(multi_location).map(|id| AssetIds::ForeignAssetId(id))165 }166}167168#[frame_support::pallet]169pub mod module {170 use super::*;171172 #[pallet::config]173 pub trait Config:174 frame_system::Config175 + pallet_common::Config176 + pallet_fungible::Config177 + orml_tokens::Config178 + pallet_balances::Config179 {180 /// The overarching event type.181 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;182183 /// Currency type for withdraw and balance storage.184 type Currency: Currency<Self::AccountId>;185186 /// Required origin for registering asset.187 type RegisterOrigin: EnsureOrigin<Self::RuntimeOrigin>;188189 /// Weight information for the extrinsics in this module.190 type WeightInfo: WeightInfo;191 }192193 #[derive(Clone, Eq, PartialEq, RuntimeDebug, Encode, Decode, TypeInfo)]194 pub struct AssetMetadata<Balance> {195 pub name: Vec<u8>,196 pub symbol: Vec<u8>,197 pub decimals: u8,198 pub minimal_balance: Balance,199 }200201 #[pallet::error]202 pub enum Error<T> {203 /// The given location could not be used (e.g. because it cannot be expressed in the204 /// desired version of XCM).205 BadLocation,206 /// MultiLocation existed207 MultiLocationExisted,208 /// AssetId not exists209 AssetIdNotExists,210 /// AssetId exists211 AssetIdExisted,212 }213214 #[pallet::event]215 #[pallet::generate_deposit(fn deposit_event)]216 pub enum Event<T: Config> {217 /// The foreign asset registered.218 ForeignAssetRegistered {219 asset_id: ForeignAssetId,220 asset_address: MultiLocation,221 metadata: AssetMetadata<BalanceOf<T>>,222 },223 /// The foreign asset updated.224 ForeignAssetUpdated {225 asset_id: ForeignAssetId,226 asset_address: MultiLocation,227 metadata: AssetMetadata<BalanceOf<T>>,228 },229 /// The asset registered.230 AssetRegistered {231 asset_id: AssetIds,232 metadata: AssetMetadata<BalanceOf<T>>,233 },234 /// The asset updated.235 AssetUpdated {236 asset_id: AssetIds,237 metadata: AssetMetadata<BalanceOf<T>>,238 },239 }240241 /// Next available Foreign AssetId ID.242 ///243 /// NextForeignAssetId: ForeignAssetId244 #[pallet::storage]245 #[pallet::getter(fn next_foreign_asset_id)]246 pub type NextForeignAssetId<T: Config> = StorageValue<_, ForeignAssetId, ValueQuery>;247 /// The storages for MultiLocations.248 ///249 /// ForeignAssetLocations: map ForeignAssetId => Option<MultiLocation>250 #[pallet::storage]251 #[pallet::getter(fn foreign_asset_locations)]252 pub type ForeignAssetLocations<T: Config> =253 StorageMap<_, Twox64Concat, ForeignAssetId, xcm::v2::MultiLocation, OptionQuery>;254255 /// The storages for CurrencyIds.256 ///257 /// LocationToCurrencyIds: map MultiLocation => Option<ForeignAssetId>258 #[pallet::storage]259 #[pallet::getter(fn location_to_currency_ids)]260 pub type LocationToCurrencyIds<T: Config> =261 StorageMap<_, Twox64Concat, xcm::v2::MultiLocation, ForeignAssetId, OptionQuery>;262263 /// The storages for AssetMetadatas.264 ///265 /// AssetMetadatas: map AssetIds => Option<AssetMetadata>266 #[pallet::storage]267 #[pallet::getter(fn asset_metadatas)]268 pub type AssetMetadatas<T: Config> =269 StorageMap<_, Twox64Concat, AssetIds, AssetMetadata<BalanceOf<T>>, OptionQuery>;270271 /// The storages for assets to fungible collection binding272 ///273 #[pallet::storage]274 #[pallet::getter(fn asset_binding)]275 pub type AssetBinding<T: Config> =276 StorageMap<_, Twox64Concat, ForeignAssetId, CollectionId, OptionQuery>;277278 #[pallet::pallet]279 #[pallet::without_storage_info]280 pub struct Pallet<T>(_);281282 #[pallet::call]283 impl<T: Config> Pallet<T> {284 #[pallet::call_index(0)]285 #[pallet::weight(<T as Config>::WeightInfo::register_foreign_asset())]286 pub fn register_foreign_asset(287 origin: OriginFor<T>,288 owner: T::AccountId,289 location: Box<VersionedMultiLocation>,290 metadata: Box<AssetMetadata<BalanceOf<T>>>,291 ) -> DispatchResult {292 T::RegisterOrigin::ensure_origin(origin.clone())?;293294 let location: MultiLocation = (*location)295 .try_into()296 .map_err(|()| Error::<T>::BadLocation)?;297298 let md = metadata.clone();299 let name: Vec<u16> = md.name.into_iter().map(|x| x as u16).collect::<Vec<u16>>();300 let mut description: Vec<u16> = "Foreign assets collection for "301 .encode_utf16()302 .collect::<Vec<u16>>();303 description.append(&mut name.clone());304305 let data: CreateCollectionData<T::AccountId> = CreateCollectionData {306 name: name.try_into().unwrap(),307 description: description.try_into().unwrap(),308 mode: CollectionMode::Fungible(md.decimals),309 ..Default::default()310 };311 let owner = T::CrossAccountId::from_sub(owner);312 let bounded_collection_id =313 <PalletFungible<T>>::init_foreign_collection(owner.clone(), owner, data)?;314 let foreign_asset_id =315 Self::do_register_foreign_asset(&location, &metadata, bounded_collection_id)?;316317 Self::deposit_event(Event::<T>::ForeignAssetRegistered {318 asset_id: foreign_asset_id,319 asset_address: location,320 metadata: *metadata,321 });322 Ok(())323 }324325 #[pallet::call_index(1)]326 #[pallet::weight(<T as Config>::WeightInfo::update_foreign_asset())]327 pub fn update_foreign_asset(328 origin: OriginFor<T>,329 foreign_asset_id: ForeignAssetId,330 location: Box<VersionedMultiLocation>,331 metadata: Box<AssetMetadata<BalanceOf<T>>>,332 ) -> DispatchResult {333 T::RegisterOrigin::ensure_origin(origin)?;334335 let location: MultiLocation = (*location)336 .try_into()337 .map_err(|()| Error::<T>::BadLocation)?;338 Self::do_update_foreign_asset(foreign_asset_id, &location, &metadata)?;339340 Self::deposit_event(Event::<T>::ForeignAssetUpdated {341 asset_id: foreign_asset_id,342 asset_address: location,343 metadata: *metadata,344 });345 Ok(())346 }347 }348}349350impl<T: Config> Pallet<T> {351 fn get_next_foreign_asset_id() -> Result<ForeignAssetId, DispatchError> {352 NextForeignAssetId::<T>::try_mutate(|current| -> Result<ForeignAssetId, DispatchError> {353 let id = *current;354 *current = current355 .checked_add(One::one())356 .ok_or(ArithmeticError::Overflow)?;357 Ok(id)358 })359 }360361 fn do_register_foreign_asset(362 location: &MultiLocation,363 metadata: &AssetMetadata<BalanceOf<T>>,364 bounded_collection_id: CollectionId,365 ) -> Result<ForeignAssetId, DispatchError> {366 let foreign_asset_id = Self::get_next_foreign_asset_id()?;367 LocationToCurrencyIds::<T>::try_mutate(location, |maybe_currency_ids| -> DispatchResult {368 ensure!(369 maybe_currency_ids.is_none(),370 Error::<T>::MultiLocationExisted371 );372 *maybe_currency_ids = Some(foreign_asset_id);373 // *maybe_currency_ids = Some(CurrencyId::ForeignAsset(foreign_asset_id));374375 ForeignAssetLocations::<T>::try_mutate(376 foreign_asset_id,377 |maybe_location| -> DispatchResult {378 ensure!(maybe_location.is_none(), Error::<T>::MultiLocationExisted);379 *maybe_location = Some(location.clone());380381 AssetMetadatas::<T>::try_mutate(382 AssetIds::ForeignAssetId(foreign_asset_id),383 |maybe_asset_metadatas| -> DispatchResult {384 ensure!(maybe_asset_metadatas.is_none(), Error::<T>::AssetIdExisted);385 *maybe_asset_metadatas = Some(metadata.clone());386 Ok(())387 },388 )389 },390 )?;391392 AssetBinding::<T>::try_mutate(foreign_asset_id, |collection_id| -> DispatchResult {393 *collection_id = Some(bounded_collection_id);394 Ok(())395 })396 })?;397398 Ok(foreign_asset_id)399 }400401 fn do_update_foreign_asset(402 foreign_asset_id: ForeignAssetId,403 location: &MultiLocation,404 metadata: &AssetMetadata<BalanceOf<T>>,405 ) -> DispatchResult {406 ForeignAssetLocations::<T>::try_mutate(407 foreign_asset_id,408 |maybe_multi_locations| -> DispatchResult {409 let old_multi_locations = maybe_multi_locations410 .as_mut()411 .ok_or(Error::<T>::AssetIdNotExists)?;412413 AssetMetadatas::<T>::try_mutate(414 AssetIds::ForeignAssetId(foreign_asset_id),415 |maybe_asset_metadatas| -> DispatchResult {416 ensure!(417 maybe_asset_metadatas.is_some(),418 Error::<T>::AssetIdNotExists419 );420421 // modify location422 if location != old_multi_locations {423 LocationToCurrencyIds::<T>::remove(old_multi_locations.clone());424 LocationToCurrencyIds::<T>::try_mutate(425 location,426 |maybe_currency_ids| -> DispatchResult {427 ensure!(428 maybe_currency_ids.is_none(),429 Error::<T>::MultiLocationExisted430 );431 // *maybe_currency_ids = Some(CurrencyId::ForeignAsset(foreign_asset_id));432 *maybe_currency_ids = Some(foreign_asset_id);433 Ok(())434 },435 )?;436 }437 *maybe_asset_metadatas = Some(metadata.clone());438 *old_multi_locations = location.clone();439 Ok(())440 },441 )442 },443 )444 }445}446447pub use frame_support::{448 traits::{449 fungibles::{Balanced, CreditOf},450 tokens::currency::Currency as CurrencyT,451 OnUnbalanced as OnUnbalancedT,452 },453 weights::{WeightToFeePolynomial, WeightToFee},454};455456pub struct FreeForAll<457 WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,458 AssetId: Get<MultiLocation>,459 AccountId,460 Currency: CurrencyT<AccountId>,461 OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,462>(463 Weight,464 Currency::Balance,465 PhantomData<(WeightToFee, AssetId, AccountId, Currency, OnUnbalanced)>,466);467468impl<469 WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,470 AssetId: Get<MultiLocation>,471 AccountId,472 Currency: CurrencyT<AccountId>,473 OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,474 > WeightTrader for FreeForAll<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>475{476 fn new() -> Self {477 Self(0, Zero::zero(), PhantomData)478 }479480 fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, XcmError> {481 log::trace!(target: "fassets::weight", "buy_weight weight: {:?}, payment: {:?}", weight, payment);482 Ok(payment)483 }484}485impl<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced> Drop486 for FreeForAll<WeightToFee, AssetId, AccountId, Currency, OnUnbalanced>487where488 WeightToFee: WeightToFeePolynomial<Balance = Currency::Balance>,489 AssetId: Get<MultiLocation>,490 Currency: CurrencyT<AccountId>,491 OnUnbalanced: OnUnbalancedT<Currency::NegativeImbalance>,492{493 fn drop(&mut self) {494 OnUnbalanced::on_unbalanced(Currency::issue(self.1));495 }496}