git.delta.rocks / unique-network / refs/commits / b708529f9e77

difftreelog

refactor use collection-locality

Daniel Shiposha2023-11-01parent: #2840b3d.patch.diff
in: master

1 file changed

modifiedpallets/foreign-assets/src/lib.rsdiffbeforeafterboth
23#![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)]
25
26use core::ops::Deref;
2527
26use 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();
252256
253 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_location
257 .interior261 .interior
262266
263 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 }
273277
274 /// 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 corresponding
277 /// 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 check
280 /// 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 };
288293
289 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 }
313313
314 /// 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 collection
317 /// 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 }
336326
337 /// 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);
378
387 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;
393384
394 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 };
398394
399 deposit_result395 deposit_result
400 .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)?;
414410
415 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)?;
450446
451 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)?;
454450
455 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")),
468464
469 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)?;
482478
483 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)?;
486482
487 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"))?,
494490
495 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 }
499495
512 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)?;
514510
515 let collection_id = Self::asset_to_collection(&what.id)?;511 let collection_locality = Self::asset_to_collection(&what.id)?;
516512
517 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)?;
521517
533 }529 }
534530
535 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)?;
538534
539 amount = 1;535 amount = 1;
549 }545 }
550}546}
547
548#[derive(Clone, Copy)]
549pub enum CollectionLocality {
550 Local(CollectionId),
551 Foreign(CollectionId),
552}
553
554impl Deref for CollectionLocality {
555 type Target = CollectionId;
556
557 fn deref(&self) -> &Self::Target {
558 match self {
559 Self::Local(id) => id,
560 Self::Foreign(id) => id,
561 }
562 }
563}
551564
552pub 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}
568
569pub use frame_support::{
570 traits::{
571 fungibles::Balanced, tokens::currency::Currency as CurrencyT, OnUnbalanced as OnUnbalancedT,
572 },
573 weights::{WeightToFee, WeightToFeePolynomial},
574};
575581
576#[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 {