Skip to content

Commit c7fde71

Browse files
mrshiposhaPraetorP
andauthored
[XNFT PoC] xnft module - XCM asset transactor for module nft (#2649)
* feat: xnft module - XCM asset transactor for module nft * fix: move xnft PalletId to Config * fix: use Blake2 with asset-instance * fix: xnft try-runtime * fix: use versioned asset ID in register_asset * fix: remove Default from TokenData * refactor: use class_locality * fix: import sp_std vec * fix: xnft xcm deps --------- Co-authored-by: PraetorP <praetorian281@gmail.com>
1 parent 10ec5a9 commit c7fde71

File tree

12 files changed

+521
-12
lines changed

12 files changed

+521
-12
lines changed

Cargo.lock

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ module-incentives = { path = "modules/incentives", default-features = false }
210210
module-liquid-crowdloan = { path = "modules/liquid-crowdloan", default-features = false }
211211
module-loans = { path = "modules/loans", default-features = false }
212212
module-nft = { path = "modules/nft", default-features = false }
213+
module-xnft = { path = "modules/xnft", default-features = false }
213214
module-nominees-election = { path = "modules/nominees-election", default-features = false }
214215
module-prices = { path = "modules/prices", default-features = false }
215216
module-relaychain = { path = "modules/relaychain", default-features = false }

modules/nft/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ pub mod module {
388388

389389
impl<T: Config> Pallet<T> {
390390
#[require_transactional]
391-
fn do_transfer(from: &T::AccountId, to: &T::AccountId, token: (ClassIdOf<T>, TokenIdOf<T>)) -> DispatchResult {
391+
pub fn do_transfer(from: &T::AccountId, to: &T::AccountId, token: (ClassIdOf<T>, TokenIdOf<T>)) -> DispatchResult {
392392
let class_info = orml_nft::Pallet::<T>::classes(token.0).ok_or(Error::<T>::ClassIdNotFound)?;
393393
let data = class_info.data;
394394
ensure!(

modules/xnft/Cargo.toml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
[package]
2+
name = "module-xnft"
3+
description = "XCM NFT PoC"
4+
version = "0.1.0-dev"
5+
authors = ["Unique Network Developers"]
6+
edition = "2021"
7+
8+
[dependencies]
9+
parity-scale-codec = { workspace = true }
10+
scale-info = { workspace = true }
11+
12+
frame-support = { workspace = true }
13+
frame-system = { workspace = true }
14+
sp-runtime = { workspace = true }
15+
sp-std = { workspace = true }
16+
cumulus-primitives-core = { workspace = true }
17+
18+
xcm = { workspace = true }
19+
xcm-executor = { workspace = true }
20+
21+
primitives = { workspace = true }
22+
23+
module-nft = { workspace = true }
24+
orml-nft = { workspace = true }
25+
26+
log = { workspace = true }
27+
28+
[features]
29+
default = ["std"]
30+
std = [
31+
"parity-scale-codec/std",
32+
"frame-support/std",
33+
"frame-system/std",
34+
"sp-runtime/std",
35+
"scale-info/std",
36+
"sp-std/std",
37+
"xcm-executor/std",
38+
"xcm/std",
39+
"module-nft/std",
40+
"orml-nft/std",
41+
"cumulus-primitives-core/std",
42+
]
43+
try-runtime = ["frame-support/try-runtime", "frame-system/try-runtime"]

modules/xnft/src/impl_transactor.rs

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
// This file is part of Acala.
2+
3+
// Copyright (C) 2023 Unique Network.
4+
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5+
6+
// This program is free software: you can redistribute it and/or modify
7+
// it under the terms of the GNU General Public License as published by
8+
// the Free Software Foundation, either version 3 of the License, or
9+
// (at your option) any later version.
10+
11+
// This program is distributed in the hope that it will be useful,
12+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
// GNU General Public License for more details.
15+
16+
// You should have received a copy of the GNU General Public License
17+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
18+
19+
use crate::{xcm_helpers::ClassLocality, *};
20+
21+
const LOG_TARGET: &str = "xcm::module_xnft::transactor";
22+
23+
impl<T: Config> TransactAsset for Pallet<T>
24+
where
25+
TokenIdOf<T>: TryFrom<u128>,
26+
ClassIdOf<T>: TryFrom<u128>,
27+
{
28+
fn can_check_in(
29+
_origin: &xcm::v3::MultiLocation,
30+
_what: &MultiAsset,
31+
_context: &xcm::v3::XcmContext,
32+
) -> xcm::v3::Result {
33+
Err(xcm::v3::Error::Unimplemented)
34+
}
35+
36+
fn check_in(_origin: &xcm::v3::MultiLocation, _what: &MultiAsset, _context: &xcm::v3::XcmContext) {}
37+
38+
fn can_check_out(
39+
_dest: &xcm::v3::MultiLocation,
40+
_what: &MultiAsset,
41+
_context: &xcm::v3::XcmContext,
42+
) -> xcm::v3::Result {
43+
Err(xcm::v3::Error::Unimplemented)
44+
}
45+
46+
fn check_out(_dest: &xcm::v3::MultiLocation, _what: &MultiAsset, _context: &xcm::v3::XcmContext) {}
47+
48+
fn deposit_asset(
49+
what: &MultiAsset,
50+
who: &xcm::v3::MultiLocation,
51+
context: Option<&xcm::v3::XcmContext>,
52+
) -> XcmResult {
53+
log::trace!(
54+
target: LOG_TARGET,
55+
"deposit_asset what: {:?}, who: {:?}, context: {:?}",
56+
what,
57+
who,
58+
context,
59+
);
60+
61+
let Fungibility::NonFungible(asset_instance) = what.fun else {
62+
return Err(XcmExecutorError::AssetNotHandled.into());
63+
};
64+
65+
let class_locality = Self::asset_to_collection(&what.id)?;
66+
67+
let to = <ConverterOf<T>>::convert_location(who).ok_or(XcmExecutorError::AccountIdConversionFailed)?;
68+
69+
match class_locality {
70+
ClassLocality::Foreign(class_id) => Self::deposit_foreign_asset(&to, class_id, &asset_instance),
71+
ClassLocality::Local(class_id) => Self::deposit_local_asset(&to, class_id, &asset_instance),
72+
}
73+
}
74+
75+
fn withdraw_asset(
76+
what: &MultiAsset,
77+
who: &xcm::v3::MultiLocation,
78+
maybe_context: Option<&xcm::v3::XcmContext>,
79+
) -> Result<xcm_executor::Assets, xcm::v3::Error> {
80+
log::trace!(
81+
target: LOG_TARGET,
82+
"withdraw_asset what: {:?}, who: {:?}, maybe_context: {:?}",
83+
what,
84+
who,
85+
maybe_context,
86+
);
87+
88+
let Fungibility::NonFungible(asset_instance) = what.fun else {
89+
return Err(XcmExecutorError::AssetNotHandled.into());
90+
};
91+
92+
let class_locality = Self::asset_to_collection(&what.id)?;
93+
94+
let from = <ConverterOf<T>>::convert_location(who).ok_or(XcmExecutorError::AccountIdConversionFailed)?;
95+
96+
let token = Self::asset_instance_to_token(class_locality, &asset_instance)
97+
.ok_or(XcmExecutorError::InstanceConversionFailed)?;
98+
99+
<ModuleNftPallet<T>>::do_transfer(&from, &Self::account_id(), token)
100+
.map(|_| what.clone().into())
101+
.map_err(|_| XcmError::FailedToTransactAsset("non-fungible item withdraw failed"))
102+
}
103+
104+
fn internal_transfer_asset(
105+
asset: &MultiAsset,
106+
from: &xcm::v3::MultiLocation,
107+
to: &xcm::v3::MultiLocation,
108+
context: &xcm::v3::XcmContext,
109+
) -> Result<xcm_executor::Assets, xcm::v3::Error> {
110+
log::trace!(
111+
target: LOG_TARGET,
112+
"internal_transfer_asset: {:?}, from: {:?}, to: {:?}, context: {:?}",
113+
asset,
114+
from,
115+
to,
116+
context
117+
);
118+
119+
let Fungibility::NonFungible(asset_instance) = asset.fun else {
120+
return Err(XcmExecutorError::AssetNotHandled.into());
121+
};
122+
123+
let class_locality = Self::asset_to_collection(&asset.id)?;
124+
125+
let from = <ConverterOf<T>>::convert_location(from).ok_or(XcmExecutorError::AccountIdConversionFailed)?;
126+
let to = <ConverterOf<T>>::convert_location(to).ok_or(XcmExecutorError::AccountIdConversionFailed)?;
127+
128+
let token = Self::asset_instance_to_token(class_locality, &asset_instance)
129+
.ok_or(XcmExecutorError::InstanceConversionFailed)?;
130+
131+
<ModuleNftPallet<T>>::do_transfer(&from, &to, token)
132+
.map(|_| asset.clone().into())
133+
.map_err(|_| XcmError::FailedToTransactAsset("non-fungible item internal transfer failed"))
134+
}
135+
}

0 commit comments

Comments
 (0)