difftreelog
refactor use collection-locality
in: master
1 file changed
pallets/foreign-assets/src/lib.rsdiffbeforeafterboth23#![cfg_attr(not(feature = "std"), no_std)]23#![cfg_attr(not(feature = "std"), no_std)]24#![allow(clippy::unused_unit)]24#![allow(clippy::unused_unit)]2526use core::ops::Deref;252726use frame_support::{dispatch::DispatchResult, pallet_prelude::*, traits::EnsureOrigin, PalletId};28use frame_support::{dispatch::DispatchResult, pallet_prelude::*, traits::EnsureOrigin, PalletId};27use frame_system::pallet_prelude::*;29use frame_system::pallet_prelude::*;247 /// If the multilocation doesn't match the patterns listed above,249 /// If the multilocation doesn't match the patterns listed above,248 /// or the `<Collection ID>` points to a foreign collection,250 /// or the `<Collection ID>` points to a foreign collection,249 /// `None` is returned, identifying that the given multilocation doesn't correspond to a local collection.251 /// `None` is returned, identifying that the given multilocation doesn't correspond to a local collection.250 fn local_asset_location_to_collection(asset_location: &MultiLocation) -> Option<CollectionId> {252 fn local_asset_location_to_collection(253 asset_location: &MultiLocation,254 ) -> Option<CollectionLocality> {251 let self_location = T::SelfLocation::get();255 let self_location = T::SelfLocation::get();252256253 if *asset_location == Here.into() || *asset_location == self_location {257 if *asset_location == Here.into() || *asset_location == self_location {254 Some(NATIVE_FUNGIBLE_COLLECTION_ID)258 Some(CollectionLocality::Local(NATIVE_FUNGIBLE_COLLECTION_ID))255 } else if asset_location.parents == self_location.parents {259 } else if asset_location.parents == self_location.parents {256 match asset_location260 match asset_location257 .interior261 .interior262266263 Self::collection_to_foreign_reserve_location(collection_id)267 Self::collection_to_foreign_reserve_location(collection_id)264 .is_none()268 .is_none()265 .then_some(collection_id)269 .then_some(CollectionLocality::Local(collection_id))266 }270 }267 _ => None,271 _ => None,268 }272 }271 }275 }272 }276 }273277274 /// Converts an asset ID to a Unique Network's collection (either foreign or a local one).278 /// Converts an asset ID to a Unique Network's collection locality (either foreign or a local one).275 ///279 ///276 /// The function will check if the asset's reserve location has the corresponding280 /// The function will check if the asset's reserve location has the corresponding277 /// foreign collection on Unique Network, and will return the collection ID if found.281 /// foreign collection on Unique Network,282 /// and will return the "foreign" locality containing the collection ID if found.278 ///283 ///279 /// If no corresponding foreign collection is found, the function will check284 /// If no corresponding foreign collection is found, the function will check280 /// if the asset's reserve location corresponds to a local collection.285 /// if the asset's reserve location corresponds to a local collection.281 /// If the local collection is found, its ID is returned.286 /// If the local collection is found, the "local" locality with the collection ID is returned.282 ///287 ///283 /// If all of the above have failed, the `AssetIdConversionFailed` error will be returned.288 /// If all of the above have failed, the `AssetIdConversionFailed` error will be returned.284 fn asset_to_collection(asset_id: &AssetId) -> Result<CollectionId, XcmError> {289 fn asset_to_collection(asset_id: &AssetId) -> Result<CollectionLocality, XcmError> {285 let AssetId::Concrete(asset_reserve_location) = asset_id else {290 let AssetId::Concrete(asset_reserve_location) = asset_id else {286 return Err(XcmExecutorError::AssetNotHandled.into());291 return Err(XcmExecutorError::AssetNotHandled.into());287 };292 };288293289 Self::foreign_reserve_location_to_collection(asset_reserve_location)294 Self::foreign_reserve_location_to_collection(asset_reserve_location)295 .map(CollectionLocality::Foreign)290 .or_else(|| Self::local_asset_location_to_collection(asset_reserve_location))296 .or_else(|| Self::local_asset_location_to_collection(asset_reserve_location))291 .ok_or_else(|| XcmExecutorError::AssetIdConversionFailed.into())297 .ok_or_else(|| XcmExecutorError::AssetIdConversionFailed.into())292 }298 }297 /// `AssetInstance::Index(<token ID>)`.303 /// `AssetInstance::Index(<token ID>)`.298 ///304 ///299 /// If the asset instance is not in the valid format or the `<token ID>` can't fit into the valid token ID,305 /// If the asset instance is not in the valid format or the `<token ID>` can't fit into the valid token ID,300 /// the `AssetNotFound` error will be returned.306 /// `None` will be returned.301 fn local_asset_instance_to_token_id(307 fn local_asset_instance_to_token_id(asset_instance: &AssetInstance) -> Option<TokenId> {302 asset_instance: &AssetInstance,303 ) -> Result<TokenId, XcmError> {304 match asset_instance {308 match asset_instance {305 AssetInstance::Index(token_id) => Ok(TokenId(309 AssetInstance::Index(token_id) => Some(TokenId((*token_id).try_into().ok()?)),306 (*token_id)307 .try_into()308 .map_err(|_| XcmError::AssetNotFound)?,309 )),310 _ => Err(XcmError::AssetNotFound),310 _ => None,311 }311 }312 }312 }313313314 /// Obtains the token ID of the `asset_instance` in the collection.314 /// Obtains the token ID of the `asset_instance` in the collection.315 ///316 /// Returns `Ok(None)` only if the `asset_instance` is a part of a foreign collection317 /// and the item hasn't yet been created on this blockchain.318 ///319 /// If the `asset_instance` exists and it is a part of a foreign collection, the function will return `Ok(Some(<token ID>))`.320 ///321 /// If the `asset_instance` is a part of a local collection,322 /// the function will return either `Ok(Some(<token ID>))` or an error if the token is not found.323 fn asset_instance_to_token_id(315 fn asset_instance_to_token_id(324 collection_id: CollectionId,316 collection_locality: CollectionLocality,325 asset_instance: &AssetInstance,317 asset_instance: &AssetInstance,326 ) -> Result<Option<TokenId>, XcmError> {318 ) -> Option<TokenId> {319 match collection_locality {327 if <CollectionToForeignReserveLocation<T>>::contains_key(collection_id) {320 CollectionLocality::Local(_) => Self::local_asset_instance_to_token_id(asset_instance),321 CollectionLocality::Foreign(collection_id) => {328 Ok(Self::foreign_reserve_asset_instance_to_token_id(322 Self::foreign_reserve_asset_instance_to_token_id(collection_id, asset_instance)329 collection_id,330 asset_instance,331 ))332 } else {323 }333 Self::local_asset_instance_to_token_id(asset_instance).map(Some)324 }334 }335 }325 }336326337 /// Creates a foreign item in the the collection.327 /// Creates a foreign item in the the collection.380 /// or creates a foreign item.370 /// or creates a foreign item.381 fn deposit_asset_instance(371 fn deposit_asset_instance(382 xcm_ext: &dyn XcmExtensions<T>,372 xcm_ext: &dyn XcmExtensions<T>,383 collection_id: CollectionId,373 collection_locality: CollectionLocality,384 asset_instance: &AssetInstance,374 asset_instance: &AssetInstance,385 to: T::CrossAccountId,375 to: T::CrossAccountId,386 ) -> XcmResult {376 ) -> XcmResult {377 let token_id = Self::asset_instance_to_token_id(collection_locality, asset_instance);378387 let deposit_result = if let Some(token_id) =379 let deposit_result = match (collection_locality, token_id) {388 Self::asset_instance_to_token_id(collection_id, asset_instance)?389 {380 (_, Some(token_id)) => {390 let depositor = &Self::pallet_account();381 let depositor = &Self::pallet_account();391 let from = depositor;382 let from = depositor;392 let amount = 1;383 let amount = 1;393384394 xcm_ext.transfer_item(depositor, from, &to, token_id, amount, &ZeroBudget)385 xcm_ext.transfer_item(depositor, from, &to, token_id, amount, &ZeroBudget)395 } else {386 }387 (CollectionLocality::Foreign(collection_id), None) => {396 Self::create_foreign_asset_instance(xcm_ext, collection_id, asset_instance, to)388 Self::create_foreign_asset_instance(xcm_ext, collection_id, asset_instance, to)397 };389 }390 (CollectionLocality::Local(_), None) => {391 return Err(XcmError::AssetNotFound);392 }393 };398394399 deposit_result395 deposit_result400 .map_err(|_| XcmError::FailedToTransactAsset("non-fungible item deposit failed"))396 .map_err(|_| XcmError::FailedToTransactAsset("non-fungible item deposit failed"))405 /// Transfers the asset instance to the pallet's account.401 /// Transfers the asset instance to the pallet's account.406 fn withdraw_asset_instance(402 fn withdraw_asset_instance(407 xcm_ext: &dyn XcmExtensions<T>,403 xcm_ext: &dyn XcmExtensions<T>,408 collection_id: CollectionId,404 collection_locality: CollectionLocality,409 asset_instance: &AssetInstance,405 asset_instance: &AssetInstance,410 from: T::CrossAccountId,406 from: T::CrossAccountId,411 ) -> XcmResult {407 ) -> XcmResult {412 let token_id = Self::asset_instance_to_token_id(collection_id, asset_instance)?408 let token_id = Self::asset_instance_to_token_id(collection_locality, asset_instance)413 .ok_or(XcmError::AssetNotFound)?;409 .ok_or(XcmError::AssetNotFound)?;414410415 let depositor = &from;411 let depositor = &from;448 let to = T::LocationToAccountId::convert_location(to)444 let to = T::LocationToAccountId::convert_location(to)449 .ok_or(XcmExecutorError::AccountIdConversionFailed)?;445 .ok_or(XcmExecutorError::AccountIdConversionFailed)?;450446451 let collection_id = Self::asset_to_collection(&what.id)?;447 let collection_locality = Self::asset_to_collection(&what.id)?;452 let dispatch =448 let dispatch = T::CollectionDispatch::dispatch(*collection_locality)453 T::CollectionDispatch::dispatch(collection_id).map_err(|_| XcmError::AssetNotFound)?;449 .map_err(|_| XcmError::AssetNotFound)?;454450455 let collection = dispatch.as_dyn();451 let collection = dispatch.as_dyn();456 let xcm_ext = collection.xcm_extensions().ok_or(XcmError::Unimplemented)?;452 let xcm_ext = collection.xcm_extensions().ok_or(XcmError::Unimplemented)?;467 .map_err(|_| XcmError::FailedToTransactAsset("fungible item deposit failed")),463 .map_err(|_| XcmError::FailedToTransactAsset("fungible item deposit failed")),468464469 Fungibility::NonFungible(asset_instance) => {465 Fungibility::NonFungible(asset_instance) => {470 Self::deposit_asset_instance(xcm_ext, collection_id, &asset_instance, to)466 Self::deposit_asset_instance(xcm_ext, collection_locality, &asset_instance, to)471 }467 }472 }468 }473 }469 }480 let from = T::LocationToAccountId::convert_location(from)476 let from = T::LocationToAccountId::convert_location(from)481 .ok_or(XcmExecutorError::AccountIdConversionFailed)?;477 .ok_or(XcmExecutorError::AccountIdConversionFailed)?;482478483 let collection_id = Self::asset_to_collection(&what.id)?;479 let collection_locality = Self::asset_to_collection(&what.id)?;484 let dispatch =480 let dispatch = T::CollectionDispatch::dispatch(*collection_locality)485 T::CollectionDispatch::dispatch(collection_id).map_err(|_| XcmError::AssetNotFound)?;481 .map_err(|_| XcmError::AssetNotFound)?;486482487 let collection = dispatch.as_dyn();483 let collection = dispatch.as_dyn();488 let xcm_ext = collection.xcm_extensions().ok_or(XcmError::NoPermission)?;484 let xcm_ext = collection.xcm_extensions().ok_or(XcmError::NoPermission)?;493 .map_err(|_| XcmError::FailedToTransactAsset("fungible item withdraw failed"))?,489 .map_err(|_| XcmError::FailedToTransactAsset("fungible item withdraw failed"))?,494490495 Fungibility::NonFungible(asset_instance) => {491 Fungibility::NonFungible(asset_instance) => {496 Self::withdraw_asset_instance(xcm_ext, collection_id, &asset_instance, from)?;492 Self::withdraw_asset_instance(xcm_ext, collection_locality, &asset_instance, from)?;497 }493 }498 }494 }499495512 let to = T::LocationToAccountId::convert_location(to)508 let to = T::LocationToAccountId::convert_location(to)513 .ok_or(XcmExecutorError::AccountIdConversionFailed)?;509 .ok_or(XcmExecutorError::AccountIdConversionFailed)?;514510515 let collection_id = Self::asset_to_collection(&what.id)?;511 let collection_locality = Self::asset_to_collection(&what.id)?;516512517 let dispatch =513 let dispatch = T::CollectionDispatch::dispatch(*collection_locality)518 T::CollectionDispatch::dispatch(collection_id).map_err(|_| XcmError::AssetNotFound)?;514 .map_err(|_| XcmError::AssetNotFound)?;519 let collection = dispatch.as_dyn();515 let collection = dispatch.as_dyn();520 let xcm_ext = collection.xcm_extensions().ok_or(XcmError::NoPermission)?;516 let xcm_ext = collection.xcm_extensions().ok_or(XcmError::NoPermission)?;521517533 }529 }534530535 Fungibility::NonFungible(asset_instance) => {531 Fungibility::NonFungible(asset_instance) => {536 token_id = Self::asset_instance_to_token_id(collection_id, &asset_instance)?532 token_id = Self::asset_instance_to_token_id(collection_locality, &asset_instance)537 .ok_or(XcmError::AssetNotFound)?;533 .ok_or(XcmError::AssetNotFound)?;538534539 amount = 1;535 amount = 1;549 }545 }550}546}547548#[derive(Clone, Copy)]549pub enum CollectionLocality {550 Local(CollectionId),551 Foreign(CollectionId),552}553554impl Deref for CollectionLocality {555 type Target = CollectionId;556557 fn deref(&self) -> &Self::Target {558 match self {559 Self::Local(id) => id,560 Self::Foreign(id) => id,561 }562 }563}551564552pub struct CurrencyIdConvert<T: Config>(PhantomData<T>);565pub struct CurrencyIdConvert<T: Config>(PhantomData<T>);553impl<T: Config> sp_runtime::traits::Convert<CollectionId, Option<MultiLocation>>566impl<T: Config> sp_runtime::traits::Convert<CollectionId, Option<MultiLocation>>566 }579 }567}580}568569pub use frame_support::{570 traits::{571 fungibles::Balanced, tokens::currency::Currency as CurrencyT, OnUnbalanced as OnUnbalancedT,572 },573 weights::{WeightToFee, WeightToFeePolynomial},574};575581576#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]582#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]577pub enum ForeignCollectionMode {583pub enum ForeignCollectionMode {