diff --git a/polkadot/xcm/xcm-builder/src/lib.rs b/polkadot/xcm/xcm-builder/src/lib.rs
index e3907eee01..42522c64d8 100644
--- a/polkadot/xcm/xcm-builder/src/lib.rs
+++ b/polkadot/xcm/xcm-builder/src/lib.rs
@@ -94,6 +94,11 @@ pub use nonfungibles_adapter::{
NonFungiblesAdapter, NonFungiblesMutateAdapter, NonFungiblesTransferAdapter,
};
+mod nonfungible_adapter;
+pub use nonfungible_adapter::{
+ NonFungibleAdapter, NonFungibleMutateAdapter, NonFungibleTransferAdapter,
+};
+
mod origin_aliases;
pub use origin_aliases::AliasForeignAccountId32;
diff --git a/polkadot/xcm/xcm-builder/src/nonfungible_adapter.rs b/polkadot/xcm/xcm-builder/src/nonfungible_adapter.rs
new file mode 100644
index 0000000000..b69002eafc
--- /dev/null
+++ b/polkadot/xcm/xcm-builder/src/nonfungible_adapter.rs
@@ -0,0 +1,326 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot. If not, see .
+
+//! Adapters to work with [`frame_support::traits::tokens::nonfungible`] through XCM.
+
+use crate::MintLocation;
+use frame_support::{
+ ensure,
+ traits::{tokens::nonfungible, Get},
+};
+use sp_std::{marker::PhantomData, prelude::*, result};
+use xcm::latest::prelude::*;
+use xcm_executor::traits::{
+ ConvertLocation, Error as MatchError, MatchesNonFungible, TransactAsset,
+};
+
+const LOG_TARGET: &str = "xcm::nonfungible_adapter";
+
+/// [`TransactAsset`] implementation that allows the use of a [`nonfungible`] implementation for
+/// handling an asset in the XCM executor.
+/// Only works for transfers.
+pub struct NonFungibleTransferAdapter(
+ PhantomData<(NonFungible, Matcher, AccountIdConverter, AccountId)>,
+);
+impl<
+ NonFungible: nonfungible::Transfer,
+ Matcher: MatchesNonFungible,
+ AccountIdConverter: ConvertLocation,
+ AccountId: Clone, // can't get away without it since Currency is generic over it.
+ > TransactAsset
+ for NonFungibleTransferAdapter
+{
+ fn transfer_asset(
+ what: &Asset,
+ from: &Location,
+ to: &Location,
+ context: &XcmContext,
+ ) -> result::Result {
+ log::trace!(
+ target: LOG_TARGET,
+ "transfer_asset what: {:?}, from: {:?}, to: {:?}, context: {:?}",
+ what,
+ from,
+ to,
+ context,
+ );
+ // Check we handle this asset.
+ let instance = Matcher::matches_nonfungible(what).ok_or(MatchError::AssetNotHandled)?;
+ let destination = AccountIdConverter::convert_location(to)
+ .ok_or(MatchError::AccountIdConversionFailed)?;
+ NonFungible::transfer(&instance, &destination)
+ .map_err(|e| XcmError::FailedToTransactAsset(e.into()))?;
+ Ok(what.clone().into())
+ }
+}
+
+/// [`TransactAsset`] implementation that allows the use of a [`nonfungible`] implementation for
+/// handling an asset in the XCM executor.
+/// Works for teleport bookkeeping.
+pub struct NonFungibleMutateAdapter<
+ NonFungible,
+ Matcher,
+ AccountIdConverter,
+ AccountId,
+ CheckingAccount,
+>(PhantomData<(NonFungible, Matcher, AccountIdConverter, AccountId, CheckingAccount)>);
+
+impl<
+ NonFungible: nonfungible::Mutate,
+ Matcher: MatchesNonFungible,
+ AccountIdConverter: ConvertLocation,
+ AccountId: Clone + Eq, // can't get away without it since Currency is generic over it.
+ CheckingAccount: Get