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>
This commit is contained in:
Sergej Sakac
2024-01-19 16:14:26 +01:00
committed by GitHub
parent 66b2fa2e59
commit 50a2e28b00
7 changed files with 122 additions and 32 deletions
+6
View File
@@ -67,6 +67,12 @@ mod types {
// Id used for identifying assets. // Id used for identifying assets.
pub type AssetIdForTrustBackedAssets = u32; 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. /// Common constants of parachains.
@@ -76,9 +76,9 @@ use parachains_common::{
impls::DealWithFees, impls::DealWithFees,
message_queue::{NarrowOriginToSibling, ParaIdToSibling}, message_queue::{NarrowOriginToSibling, ParaIdToSibling},
rococo::{consensus::*, currency::*, fee::WeightToFee}, rococo::{consensus::*, currency::*, fee::WeightToFee},
AccountId, AssetIdForTrustBackedAssets, AuraId, Balance, BlockNumber, Hash, Header, Nonce, AccountId, AssetIdForTrustBackedAssets, AuraId, Balance, BlockNumber, CollectionId, Hash,
Signature, AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS, MAXIMUM_BLOCK_WEIGHT, Header, ItemId, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS,
NORMAL_DISPATCH_RATIO, SLOT_DURATION, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION,
}; };
use sp_runtime::{Perbill, RuntimeDebug}; use sp_runtime::{Perbill, RuntimeDebug};
use xcm_config::{ use xcm_config::{
@@ -773,8 +773,8 @@ parameter_types! {
impl pallet_uniques::Config for Runtime { impl pallet_uniques::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type CollectionId = u32; type CollectionId = CollectionId;
type ItemId = u32; type ItemId = ItemId;
type Currency = Balances; type Currency = Balances;
type ForceOrigin = AssetsForceOrigin; type ForceOrigin = AssetsForceOrigin;
type CollectionDeposit = UniquesCollectionDeposit; type CollectionDeposit = UniquesCollectionDeposit;
@@ -831,8 +831,8 @@ parameter_types! {
impl pallet_nfts::Config for Runtime { impl pallet_nfts::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type CollectionId = u32; type CollectionId = CollectionId;
type ItemId = u32; type ItemId = ItemId;
type Currency = Balances; type Currency = Balances;
type CreateOrigin = AsEnsureOriginWithArg<EnsureSigned<AccountId>>; type CreateOrigin = AsEnsureOriginWithArg<EnsureSigned<AccountId>>;
type ForceOrigin = AssetsForceOrigin; type ForceOrigin = AssetsForceOrigin;
@@ -17,7 +17,8 @@ use super::{
AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, BaseDeliveryFee, AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, BaseDeliveryFee,
CollatorSelection, FeeAssetId, ForeignAssets, ForeignAssetsInstance, ParachainInfo, CollatorSelection, FeeAssetId, ForeignAssets, ForeignAssetsInstance, ParachainInfo,
ParachainSystem, PolkadotXcm, PoolAssets, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, ParachainSystem, PolkadotXcm, PoolAssets, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin,
ToWestendXcmRouter, TransactionByteFee, TrustBackedAssetsInstance, WeightToFee, XcmpQueue, ToWestendXcmRouter, TransactionByteFee, TrustBackedAssetsInstance, Uniques, WeightToFee,
XcmpQueue,
}; };
use assets_common::{ use assets_common::{
local_and_foreign_assets::MatchesLocalAndForeignAssetsLocation, local_and_foreign_assets::MatchesLocalAndForeignAssetsLocation,
@@ -54,12 +55,12 @@ use xcm_builder::{
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain,
DenyThenTry, DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin, FungiblesAdapter, DenyThenTry, DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin, FungiblesAdapter,
GlobalConsensusParachainConvertsFor, HashedDescription, IsConcrete, LocalMint, GlobalConsensusParachainConvertsFor, HashedDescription, IsConcrete, LocalMint,
NetworkExportTableItem, NoChecking, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, NetworkExportTableItem, NoChecking, NonFungiblesAdapter, ParentAsSuperuser, ParentIsPreset,
SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
SignedToAccountId32, SovereignPaidRemoteExporter, SovereignSignedViaLocation, StartsWith, SignedAccountId32AsNative, SignedToAccountId32, SovereignPaidRemoteExporter,
StartsWithExplicitGlobalConsensus, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit,
WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
XcmFeeToAccount, XcmFeeManagerFromComponents, XcmFeeToAccount,
}; };
use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
@@ -80,6 +81,8 @@ parameter_types! {
PalletInstance(<ForeignAssets as PalletInfoAccess>::index() as u8).into(); PalletInstance(<ForeignAssets as PalletInfoAccess>::index() as u8).into();
pub PoolAssetsPalletLocation: Location = pub PoolAssetsPalletLocation: Location =
PalletInstance(<PoolAssets as PalletInfoAccess>::index() as u8).into(); PalletInstance(<PoolAssets as PalletInfoAccess>::index() as u8).into();
pub UniquesPalletLocation: Location =
PalletInstance(<Uniques as PalletInfoAccess>::index() as u8).into();
pub PoolAssetsPalletLocationV3: xcm::v3::Location = pub PoolAssetsPalletLocationV3: xcm::v3::Location =
xcm::v3::Junction::PalletInstance(<PoolAssets as PalletInfoAccess>::index() as u8).into(); xcm::v3::Junction::PalletInstance(<PoolAssets as PalletInfoAccess>::index() as u8).into();
pub CheckingAccount: AccountId = PolkadotXcm::check_account(); pub CheckingAccount: AccountId = PolkadotXcm::check_account();
@@ -145,6 +148,26 @@ pub type FungiblesTransactor = FungiblesAdapter<
CheckingAccount, CheckingAccount,
>; >;
/// Matcher for converting `ClassId`/`InstanceId` into a uniques asset.
pub type UniquesConvertedConcreteId =
assets_common::UniquesConvertedConcreteId<UniquesPalletLocation>;
/// 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`. /// `AssetId`/`Balance` converter for `ForeignAssets`.
pub type ForeignAssetsConvertedConcreteId = assets_common::ForeignAssetsConvertedConcreteId< pub type ForeignAssetsConvertedConcreteId = assets_common::ForeignAssetsConvertedConcreteId<
( (
@@ -198,8 +221,13 @@ pub type PoolFungiblesTransactor = FungiblesAdapter<
>; >;
/// Means for transacting assets on this chain. /// Means for transacting assets on this chain.
pub type AssetTransactors = pub type AssetTransactors = (
(CurrencyTransactor, FungiblesTransactor, ForeignFungiblesTransactor, PoolFungiblesTransactor); CurrencyTransactor,
FungiblesTransactor,
ForeignFungiblesTransactor,
PoolFungiblesTransactor,
UniquesTransactor,
);
/// Simple `Location` matcher for Local and Foreign asset `Location`. /// Simple `Location` matcher for Local and Foreign asset `Location`.
pub struct LocalAndForeignAssetsLocationMatcher; pub struct LocalAndForeignAssetsLocationMatcher;
@@ -60,9 +60,9 @@ use parachains_common::{
impls::DealWithFees, impls::DealWithFees,
message_queue::*, message_queue::*,
westend::{consensus::*, currency::*, fee::WeightToFee}, westend::{consensus::*, currency::*, fee::WeightToFee},
AccountId, AssetIdForTrustBackedAssets, AuraId, Balance, BlockNumber, Hash, Header, Nonce, AccountId, AssetIdForTrustBackedAssets, AuraId, Balance, BlockNumber, CollectionId, Hash,
Signature, AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS, MAXIMUM_BLOCK_WEIGHT, Header, ItemId, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, DAYS, HOURS,
NORMAL_DISPATCH_RATIO, SLOT_DURATION, MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO, SLOT_DURATION,
}; };
use sp_api::impl_runtime_apis; use sp_api::impl_runtime_apis;
use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
@@ -748,8 +748,8 @@ parameter_types! {
impl pallet_uniques::Config for Runtime { impl pallet_uniques::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type CollectionId = u32; type CollectionId = CollectionId;
type ItemId = u32; type ItemId = ItemId;
type Currency = Balances; type Currency = Balances;
type ForceOrigin = AssetsForceOrigin; type ForceOrigin = AssetsForceOrigin;
type CollectionDeposit = UniquesCollectionDeposit; type CollectionDeposit = UniquesCollectionDeposit;
@@ -806,8 +806,8 @@ parameter_types! {
impl pallet_nfts::Config for Runtime { impl pallet_nfts::Config for Runtime {
type RuntimeEvent = RuntimeEvent; type RuntimeEvent = RuntimeEvent;
type CollectionId = u32; type CollectionId = CollectionId;
type ItemId = u32; type ItemId = ItemId;
type Currency = Balances; type Currency = Balances;
type CreateOrigin = AsEnsureOriginWithArg<EnsureSigned<AccountId>>; type CreateOrigin = AsEnsureOriginWithArg<EnsureSigned<AccountId>>;
type ForceOrigin = AssetsForceOrigin; type ForceOrigin = AssetsForceOrigin;
@@ -17,7 +17,8 @@ use super::{
AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, BaseDeliveryFee, AccountId, AllPalletsWithSystem, Assets, Authorship, Balance, Balances, BaseDeliveryFee,
CollatorSelection, FeeAssetId, ForeignAssets, ForeignAssetsInstance, ParachainInfo, CollatorSelection, FeeAssetId, ForeignAssets, ForeignAssetsInstance, ParachainInfo,
ParachainSystem, PolkadotXcm, PoolAssets, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, ParachainSystem, PolkadotXcm, PoolAssets, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin,
ToRococoXcmRouter, TransactionByteFee, TrustBackedAssetsInstance, WeightToFee, XcmpQueue, ToRococoXcmRouter, TransactionByteFee, TrustBackedAssetsInstance, Uniques, WeightToFee,
XcmpQueue,
}; };
use assets_common::{ use assets_common::{
local_and_foreign_assets::MatchesLocalAndForeignAssetsLocation, local_and_foreign_assets::MatchesLocalAndForeignAssetsLocation,
@@ -52,11 +53,12 @@ use xcm_builder::{
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain,
DenyThenTry, DescribeFamily, DescribePalletTerminal, EnsureXcmOrigin, FungiblesAdapter, DenyThenTry, DescribeFamily, DescribePalletTerminal, EnsureXcmOrigin, FungiblesAdapter,
GlobalConsensusParachainConvertsFor, HashedDescription, IsConcrete, LocalMint, GlobalConsensusParachainConvertsFor, HashedDescription, IsConcrete, LocalMint,
NetworkExportTableItem, NoChecking, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, NetworkExportTableItem, NoChecking, NonFungiblesAdapter, ParentAsSuperuser, ParentIsPreset,
SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
SignedToAccountId32, SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, StartsWith,
TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, StartsWithExplicitGlobalConsensus, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
WithUniqueTopic, XcmFeeManagerFromComponents, XcmFeeToAccount, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents,
XcmFeeToAccount,
}; };
use xcm_executor::{traits::WithOriginFilter, XcmExecutor}; use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
@@ -77,6 +79,8 @@ parameter_types! {
PalletInstance(<ForeignAssets as PalletInfoAccess>::index() as u8).into(); PalletInstance(<ForeignAssets as PalletInfoAccess>::index() as u8).into();
pub PoolAssetsPalletLocation: Location = pub PoolAssetsPalletLocation: Location =
PalletInstance(<PoolAssets as PalletInfoAccess>::index() as u8).into(); PalletInstance(<PoolAssets as PalletInfoAccess>::index() as u8).into();
pub UniquesPalletLocation: Location =
PalletInstance(<Uniques as PalletInfoAccess>::index() as u8).into();
pub PoolAssetsPalletLocationV3: xcm::v3::Location = pub PoolAssetsPalletLocationV3: xcm::v3::Location =
xcm::v3::Junction::PalletInstance(<PoolAssets as PalletInfoAccess>::index() as u8).into(); xcm::v3::Junction::PalletInstance(<PoolAssets as PalletInfoAccess>::index() as u8).into();
pub CheckingAccount: AccountId = PolkadotXcm::check_account(); pub CheckingAccount: AccountId = PolkadotXcm::check_account();
@@ -139,6 +143,26 @@ pub type FungiblesTransactor = FungiblesAdapter<
CheckingAccount, CheckingAccount,
>; >;
/// Matcher for converting `ClassId`/`InstanceId` into a uniques asset.
pub type UniquesConvertedConcreteId =
assets_common::UniquesConvertedConcreteId<UniquesPalletLocation>;
/// 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`. /// `AssetId`/`Balance` converter for `ForeignAssets`.
pub type ForeignAssetsConvertedConcreteId = assets_common::ForeignAssetsConvertedConcreteId< pub type ForeignAssetsConvertedConcreteId = assets_common::ForeignAssetsConvertedConcreteId<
( (
@@ -192,8 +216,13 @@ pub type PoolFungiblesTransactor = FungiblesAdapter<
>; >;
/// Means for transacting assets on this chain. /// Means for transacting assets on this chain.
pub type AssetTransactors = pub type AssetTransactors = (
(CurrencyTransactor, FungiblesTransactor, ForeignFungiblesTransactor, PoolFungiblesTransactor); CurrencyTransactor,
FungiblesTransactor,
ForeignFungiblesTransactor,
PoolFungiblesTransactor,
UniquesTransactor,
);
/// Simple `Location` matcher for Local and Foreign asset `Location`. /// Simple `Location` matcher for Local and Foreign asset `Location`.
pub struct LocalAndForeignAssetsLocationMatcher; pub struct LocalAndForeignAssetsLocationMatcher;
@@ -25,7 +25,7 @@ pub mod runtime_api;
use crate::matching::{LocalLocationPattern, ParentLocation}; use crate::matching::{LocalLocationPattern, ParentLocation};
use frame_support::traits::{Equals, EverythingBut}; use frame_support::traits::{Equals, EverythingBut};
use parachains_common::AssetIdForTrustBackedAssets; use parachains_common::{AssetIdForTrustBackedAssets, CollectionId, ItemId};
use xcm_builder::{ use xcm_builder::{
AsPrefixedGeneralIndex, MatchedConvertedConcreteId, StartsWith, V4V3LocationConverter, AsPrefixedGeneralIndex, MatchedConvertedConcreteId, StartsWith, V4V3LocationConverter,
}; };
@@ -43,6 +43,10 @@ pub type AssetIdForTrustBackedAssetsConvert<TrustBackedAssetsPalletLocation> =
pub type AssetIdForTrustBackedAssetsConvertLatest<TrustBackedAssetsPalletLocation> = pub type AssetIdForTrustBackedAssetsConvertLatest<TrustBackedAssetsPalletLocation> =
AsPrefixedGeneralIndex<TrustBackedAssetsPalletLocation, AssetIdForTrustBackedAssets, JustTry>; AsPrefixedGeneralIndex<TrustBackedAssetsPalletLocation, AssetIdForTrustBackedAssets, JustTry>;
/// `Location` vs `CollectionId` converter for `Uniques`
pub type CollectionIdForUniquesConvert<UniquesPalletLocation> =
AsPrefixedGeneralIndex<UniquesPalletLocation, CollectionId, JustTry>;
/// [`MatchedConvertedConcreteId`] converter dedicated for `TrustBackedAssets` /// [`MatchedConvertedConcreteId`] converter dedicated for `TrustBackedAssets`
pub type TrustBackedAssetsConvertedConcreteId<TrustBackedAssetsPalletLocation, Balance> = pub type TrustBackedAssetsConvertedConcreteId<TrustBackedAssetsPalletLocation, Balance> =
MatchedConvertedConcreteId< MatchedConvertedConcreteId<
@@ -53,6 +57,17 @@ pub type TrustBackedAssetsConvertedConcreteId<TrustBackedAssetsPalletLocation, B
JustTry, JustTry,
>; >;
/// [`MatchedConvertedConcreteId`] converter dedicated for `Uniques`
pub type UniquesConvertedConcreteId<UniquesPalletLocation> = 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<UniquesPalletLocation>,
CollectionIdForUniquesConvert<UniquesPalletLocation>,
JustTry,
>;
/// [`MatchedConvertedConcreteId`] converter dedicated for storing `AssetId` as `Location`. /// [`MatchedConvertedConcreteId`] converter dedicated for storing `AssetId` as `Location`.
pub type LocationConvertedConcreteId<LocationFilter, Balance> = MatchedConvertedConcreteId< pub type LocationConvertedConcreteId<LocationFilter, Balance> = MatchedConvertedConcreteId<
xcm::v3::Location, xcm::v3::Location,
+12
View File
@@ -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"