From 50a2e28b00196453966ac9858640ee1c4356ef8e Mon Sep 17 00:00:00 2001 From: Sergej Sakac <73715684+Szegoo@users.noreply.github.com> Date: Fri, 19 Jan 2024 16:14:26 +0100 Subject: [PATCH] Enable cross-chain NFT transfers on asset-hub (#2796) This PR introduces the following changes: - [x] Adds a `UniquesTransactor` to asset-hub-rococo - [x] Adds a `UniquesTransactor` to asset-hub-westend We can't add a transactor for `pallet-nfts` like we do for `pallet-uniques` because `pallet-nfts` uses `nonfungibles_v2::Mutate` instead of `nonfungibles::Mutate`, and making that work would be out of scope of this PR. With these modifications, reserve-based NFT cross-chain transfers can be performed on asset-hub. --------- Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com> --- cumulus/parachains/common/src/lib.rs | 6 +++ .../assets/asset-hub-rococo/src/lib.rs | 14 +++--- .../assets/asset-hub-rococo/src/xcm_config.rs | 46 +++++++++++++++---- .../assets/asset-hub-westend/src/lib.rs | 14 +++--- .../asset-hub-westend/src/xcm_config.rs | 45 ++++++++++++++---- .../runtimes/assets/common/src/lib.rs | 17 ++++++- prdoc/pr_2796.prdoc | 12 +++++ 7 files changed, 122 insertions(+), 32 deletions(-) create mode 100644 prdoc/pr_2796.prdoc diff --git a/cumulus/parachains/common/src/lib.rs b/cumulus/parachains/common/src/lib.rs index eab5d7f457..68ba10094c 100644 --- a/cumulus/parachains/common/src/lib.rs +++ b/cumulus/parachains/common/src/lib.rs @@ -67,6 +67,12 @@ mod types { // Id used for identifying assets. pub type AssetIdForTrustBackedAssets = u32; + + // Id used for identifying non-fungible collections. + pub type CollectionId = u32; + + // Id used for identifying non-fungible items. + pub type ItemId = u32; } /// Common constants of parachains. diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs index 494ca3d124..0f379a6f7b 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -76,9 +76,9 @@ use parachains_common::{ impls::DealWithFees, message_queue::{NarrowOriginToSibling, ParaIdToSibling}, rococo::{consensus::*, currency::*, fee::WeightToFee}, - AccountId, AssetIdForTrustBackedAssets, AuraId, Balance, BlockNumber, Hash, Header, Nonce, - Signature, AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS, MAXIMUM_BLOCK_WEIGHT, - NORMAL_DISPATCH_RATIO, SLOT_DURATION, + AccountId, AssetIdForTrustBackedAssets, AuraId, Balance, BlockNumber, CollectionId, Hash, + Header, ItemId, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS, + MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION, }; use sp_runtime::{Perbill, RuntimeDebug}; use xcm_config::{ @@ -773,8 +773,8 @@ parameter_types! { impl pallet_uniques::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type CollectionId = u32; - type ItemId = u32; + type CollectionId = CollectionId; + type ItemId = ItemId; type Currency = Balances; type ForceOrigin = AssetsForceOrigin; type CollectionDeposit = UniquesCollectionDeposit; @@ -831,8 +831,8 @@ parameter_types! { impl pallet_nfts::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type CollectionId = u32; - type ItemId = u32; + type CollectionId = CollectionId; + type ItemId = ItemId; type Currency = Balances; type CreateOrigin = AsEnsureOriginWithArg>; type ForceOrigin = AssetsForceOrigin; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index b9b9025b69..9e1affb533 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -17,7 +17,8 @@ use super::{ AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, BaseDeliveryFee, CollatorSelection, FeeAssetId, ForeignAssets, ForeignAssetsInstance, ParachainInfo, ParachainSystem, PolkadotXcm, PoolAssets, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - ToWestendXcmRouter, TransactionByteFee, TrustBackedAssetsInstance, WeightToFee, XcmpQueue, + ToWestendXcmRouter, TransactionByteFee, TrustBackedAssetsInstance, Uniques, WeightToFee, + XcmpQueue, }; use assets_common::{ local_and_foreign_assets::MatchesLocalAndForeignAssetsLocation, @@ -54,12 +55,12 @@ use xcm_builder::{ AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin, FungiblesAdapter, GlobalConsensusParachainConvertsFor, HashedDescription, IsConcrete, LocalMint, - NetworkExportTableItem, NoChecking, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, - SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, - SignedToAccountId32, SovereignPaidRemoteExporter, SovereignSignedViaLocation, StartsWith, - StartsWithExplicitGlobalConsensus, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, - WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, - XcmFeeToAccount, + NetworkExportTableItem, NoChecking, NonFungiblesAdapter, ParentAsSuperuser, ParentIsPreset, + RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SovereignPaidRemoteExporter, + SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + XcmFeeManagerFromComponents, XcmFeeToAccount, }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; @@ -80,6 +81,8 @@ parameter_types! { PalletInstance(::index() as u8).into(); pub PoolAssetsPalletLocation: Location = PalletInstance(::index() as u8).into(); + pub UniquesPalletLocation: Location = + PalletInstance(::index() as u8).into(); pub PoolAssetsPalletLocationV3: xcm::v3::Location = xcm::v3::Junction::PalletInstance(::index() as u8).into(); pub CheckingAccount: AccountId = PolkadotXcm::check_account(); @@ -145,6 +148,26 @@ pub type FungiblesTransactor = FungiblesAdapter< CheckingAccount, >; +/// Matcher for converting `ClassId`/`InstanceId` into a uniques asset. +pub type UniquesConvertedConcreteId = + assets_common::UniquesConvertedConcreteId; + +/// Means for transacting unique assets. +pub type UniquesTransactor = NonFungiblesAdapter< + // Use this non-fungibles implementation: + Uniques, + // This adapter will handle any non-fungible asset from the uniques pallet. + UniquesConvertedConcreteId, + // Convert an XCM Location into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // Does not check teleports. + NoChecking, + // The account to use for tracking teleports. + CheckingAccount, +>; + /// `AssetId`/`Balance` converter for `ForeignAssets`. pub type ForeignAssetsConvertedConcreteId = assets_common::ForeignAssetsConvertedConcreteId< ( @@ -198,8 +221,13 @@ pub type PoolFungiblesTransactor = FungiblesAdapter< >; /// Means for transacting assets on this chain. -pub type AssetTransactors = - (CurrencyTransactor, FungiblesTransactor, ForeignFungiblesTransactor, PoolFungiblesTransactor); +pub type AssetTransactors = ( + CurrencyTransactor, + FungiblesTransactor, + ForeignFungiblesTransactor, + PoolFungiblesTransactor, + UniquesTransactor, +); /// Simple `Location` matcher for Local and Foreign asset `Location`. pub struct LocalAndForeignAssetsLocationMatcher; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs index 5950173d90..310726349f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -60,9 +60,9 @@ use parachains_common::{ impls::DealWithFees, message_queue::*, westend::{consensus::*, currency::*, fee::WeightToFee}, - AccountId, AssetIdForTrustBackedAssets, AuraId, Balance, BlockNumber, Hash, Header, Nonce, - Signature, AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS, MAXIMUM_BLOCK_WEIGHT, - NORMAL_DISPATCH_RATIO, SLOT_DURATION, + AccountId, AssetIdForTrustBackedAssets, AuraId, Balance, BlockNumber, CollectionId, Hash, + Header, ItemId, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS, + MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION, }; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; @@ -748,8 +748,8 @@ parameter_types! { impl pallet_uniques::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type CollectionId = u32; - type ItemId = u32; + type CollectionId = CollectionId; + type ItemId = ItemId; type Currency = Balances; type ForceOrigin = AssetsForceOrigin; type CollectionDeposit = UniquesCollectionDeposit; @@ -806,8 +806,8 @@ parameter_types! { impl pallet_nfts::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type CollectionId = u32; - type ItemId = u32; + type CollectionId = CollectionId; + type ItemId = ItemId; type Currency = Balances; type CreateOrigin = AsEnsureOriginWithArg>; type ForceOrigin = AssetsForceOrigin; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs index 70522eda4b..0f4ce360ee 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs @@ -17,7 +17,8 @@ use super::{ AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, BaseDeliveryFee, CollatorSelection, FeeAssetId, ForeignAssets, ForeignAssetsInstance, ParachainInfo, ParachainSystem, PolkadotXcm, PoolAssets, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - ToRococoXcmRouter, TransactionByteFee, TrustBackedAssetsInstance, WeightToFee, XcmpQueue, + ToRococoXcmRouter, TransactionByteFee, TrustBackedAssetsInstance, Uniques, WeightToFee, + XcmpQueue, }; use assets_common::{ local_and_foreign_assets::MatchesLocalAndForeignAssetsLocation, @@ -52,11 +53,12 @@ use xcm_builder::{ AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, DenyThenTry, DescribeFamily, DescribePalletTerminal, EnsureXcmOrigin, FungiblesAdapter, GlobalConsensusParachainConvertsFor, HashedDescription, IsConcrete, LocalMint, - NetworkExportTableItem, NoChecking, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, - SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, - TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, - WithUniqueTopic, XcmFeeManagerFromComponents, XcmFeeToAccount, + NetworkExportTableItem, NoChecking, NonFungiblesAdapter, ParentAsSuperuser, ParentIsPreset, + RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, StartsWith, + StartsWithExplicitGlobalConsensus, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, + WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, + XcmFeeToAccount, }; use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; @@ -77,6 +79,8 @@ parameter_types! { PalletInstance(::index() as u8).into(); pub PoolAssetsPalletLocation: Location = PalletInstance(::index() as u8).into(); + pub UniquesPalletLocation: Location = + PalletInstance(::index() as u8).into(); pub PoolAssetsPalletLocationV3: xcm::v3::Location = xcm::v3::Junction::PalletInstance(::index() as u8).into(); pub CheckingAccount: AccountId = PolkadotXcm::check_account(); @@ -139,6 +143,26 @@ pub type FungiblesTransactor = FungiblesAdapter< CheckingAccount, >; +/// Matcher for converting `ClassId`/`InstanceId` into a uniques asset. +pub type UniquesConvertedConcreteId = + assets_common::UniquesConvertedConcreteId; + +/// Means for transacting unique assets. +pub type UniquesTransactor = NonFungiblesAdapter< + // Use this non-fungibles implementation: + Uniques, + // This adapter will handle any non-fungible asset from the uniques pallet. + UniquesConvertedConcreteId, + // Convert an XCM Location into a local account id: + LocationToAccountId, + // Our chain's account ID type (we can't get away without mentioning it explicitly): + AccountId, + // Does not check teleports. + NoChecking, + // The account to use for tracking teleports. + CheckingAccount, +>; + /// `AssetId`/`Balance` converter for `ForeignAssets`. pub type ForeignAssetsConvertedConcreteId = assets_common::ForeignAssetsConvertedConcreteId< ( @@ -192,8 +216,13 @@ pub type PoolFungiblesTransactor = FungiblesAdapter< >; /// Means for transacting assets on this chain. -pub type AssetTransactors = - (CurrencyTransactor, FungiblesTransactor, ForeignFungiblesTransactor, PoolFungiblesTransactor); +pub type AssetTransactors = ( + CurrencyTransactor, + FungiblesTransactor, + ForeignFungiblesTransactor, + PoolFungiblesTransactor, + UniquesTransactor, +); /// Simple `Location` matcher for Local and Foreign asset `Location`. pub struct LocalAndForeignAssetsLocationMatcher; diff --git a/cumulus/parachains/runtimes/assets/common/src/lib.rs b/cumulus/parachains/runtimes/assets/common/src/lib.rs index f21e176643..a0c912b6f0 100644 --- a/cumulus/parachains/runtimes/assets/common/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/common/src/lib.rs @@ -25,7 +25,7 @@ pub mod runtime_api; use crate::matching::{LocalLocationPattern, ParentLocation}; use frame_support::traits::{Equals, EverythingBut}; -use parachains_common::AssetIdForTrustBackedAssets; +use parachains_common::{AssetIdForTrustBackedAssets, CollectionId, ItemId}; use xcm_builder::{ AsPrefixedGeneralIndex, MatchedConvertedConcreteId, StartsWith, V4V3LocationConverter, }; @@ -43,6 +43,10 @@ pub type AssetIdForTrustBackedAssetsConvert = pub type AssetIdForTrustBackedAssetsConvertLatest = AsPrefixedGeneralIndex; +/// `Location` vs `CollectionId` converter for `Uniques` +pub type CollectionIdForUniquesConvert = + AsPrefixedGeneralIndex; + /// [`MatchedConvertedConcreteId`] converter dedicated for `TrustBackedAssets` pub type TrustBackedAssetsConvertedConcreteId = MatchedConvertedConcreteId< @@ -53,6 +57,17 @@ pub type TrustBackedAssetsConvertedConcreteId; +/// [`MatchedConvertedConcreteId`] converter dedicated for `Uniques` +pub type UniquesConvertedConcreteId = MatchedConvertedConcreteId< + CollectionId, + ItemId, + // The asset starts with the uniques pallet. The `CollectionId` of the asset is specified as a + // junction within the pallet itself. + StartsWith, + CollectionIdForUniquesConvert, + JustTry, +>; + /// [`MatchedConvertedConcreteId`] converter dedicated for storing `AssetId` as `Location`. pub type LocationConvertedConcreteId = MatchedConvertedConcreteId< xcm::v3::Location, diff --git a/prdoc/pr_2796.prdoc b/prdoc/pr_2796.prdoc new file mode 100644 index 0000000000..15cb005d28 --- /dev/null +++ b/prdoc/pr_2796.prdoc @@ -0,0 +1,12 @@ +title: Rococo and Westend Asset-Hub: XCM Transfers with Pallet-Uniques + +doc: + - audience: Runtime User + description: | + With the added `UniquesTransactor` Rococo and Westend Asset-Hub are now capable of handling + XCM transfers with pallet-uniques. + +crates: + - name: "asset-hub-rococo-runtime" + - name: "asset-hub-westend-runtime" + - name: "assets-common"