Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into fix-ts-test
Browse files Browse the repository at this point in the history
  • Loading branch information
zjb0807 committed Nov 30, 2023
2 parents 161a9a1 + c7fde71 commit 39c8bb6
Show file tree
Hide file tree
Showing 12 changed files with 521 additions and 12 deletions.
20 changes: 20 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ module-incentives = { path = "modules/incentives", default-features = false }
module-liquid-crowdloan = { path = "modules/liquid-crowdloan", default-features = false }
module-loans = { path = "modules/loans", default-features = false }
module-nft = { path = "modules/nft", default-features = false }
module-xnft = { path = "modules/xnft", default-features = false }
module-nominees-election = { path = "modules/nominees-election", default-features = false }
module-prices = { path = "modules/prices", default-features = false }
module-relaychain = { path = "modules/relaychain", default-features = false }
Expand Down
2 changes: 1 addition & 1 deletion modules/nft/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ pub mod module {

impl<T: Config> Pallet<T> {
#[require_transactional]
fn do_transfer(from: &T::AccountId, to: &T::AccountId, token: (ClassIdOf<T>, TokenIdOf<T>)) -> DispatchResult {
pub fn do_transfer(from: &T::AccountId, to: &T::AccountId, token: (ClassIdOf<T>, TokenIdOf<T>)) -> DispatchResult {
let class_info = orml_nft::Pallet::<T>::classes(token.0).ok_or(Error::<T>::ClassIdNotFound)?;
let data = class_info.data;
ensure!(
Expand Down
43 changes: 43 additions & 0 deletions modules/xnft/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
[package]
name = "module-xnft"
description = "XCM NFT PoC"
version = "0.1.0-dev"
authors = ["Unique Network Developers"]
edition = "2021"

[dependencies]
parity-scale-codec = { workspace = true }
scale-info = { workspace = true }

frame-support = { workspace = true }
frame-system = { workspace = true }
sp-runtime = { workspace = true }
sp-std = { workspace = true }
cumulus-primitives-core = { workspace = true }

xcm = { workspace = true }
xcm-executor = { workspace = true }

primitives = { workspace = true }

module-nft = { workspace = true }
orml-nft = { workspace = true }

log = { workspace = true }

[features]
default = ["std"]
std = [
"parity-scale-codec/std",
"frame-support/std",
"frame-system/std",
"sp-runtime/std",
"scale-info/std",
"sp-std/std",
"xcm-executor/std",
"xcm/std",
"module-nft/std",
"orml-nft/std",
"cumulus-primitives-core/std",
]
try-runtime = ["frame-support/try-runtime", "frame-system/try-runtime"]
135 changes: 135 additions & 0 deletions modules/xnft/src/impl_transactor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// This file is part of Acala.

// Copyright (C) 2023 Unique Network.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0

// This program 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.

// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.

use crate::{xcm_helpers::ClassLocality, *};

const LOG_TARGET: &str = "xcm::module_xnft::transactor";

impl<T: Config> TransactAsset for Pallet<T>
where
TokenIdOf<T>: TryFrom<u128>,
ClassIdOf<T>: TryFrom<u128>,
{
fn can_check_in(
_origin: &xcm::v3::MultiLocation,
_what: &MultiAsset,
_context: &xcm::v3::XcmContext,
) -> xcm::v3::Result {
Err(xcm::v3::Error::Unimplemented)
}

fn check_in(_origin: &xcm::v3::MultiLocation, _what: &MultiAsset, _context: &xcm::v3::XcmContext) {}

fn can_check_out(
_dest: &xcm::v3::MultiLocation,
_what: &MultiAsset,
_context: &xcm::v3::XcmContext,
) -> xcm::v3::Result {
Err(xcm::v3::Error::Unimplemented)
}

fn check_out(_dest: &xcm::v3::MultiLocation, _what: &MultiAsset, _context: &xcm::v3::XcmContext) {}

fn deposit_asset(
what: &MultiAsset,
who: &xcm::v3::MultiLocation,
context: Option<&xcm::v3::XcmContext>,
) -> XcmResult {
log::trace!(
target: LOG_TARGET,
"deposit_asset what: {:?}, who: {:?}, context: {:?}",
what,
who,
context,
);

let Fungibility::NonFungible(asset_instance) = what.fun else {
return Err(XcmExecutorError::AssetNotHandled.into());
};

let class_locality = Self::asset_to_collection(&what.id)?;

let to = <ConverterOf<T>>::convert_location(who).ok_or(XcmExecutorError::AccountIdConversionFailed)?;

match class_locality {
ClassLocality::Foreign(class_id) => Self::deposit_foreign_asset(&to, class_id, &asset_instance),
ClassLocality::Local(class_id) => Self::deposit_local_asset(&to, class_id, &asset_instance),
}
}

fn withdraw_asset(
what: &MultiAsset,
who: &xcm::v3::MultiLocation,
maybe_context: Option<&xcm::v3::XcmContext>,
) -> Result<xcm_executor::Assets, xcm::v3::Error> {
log::trace!(
target: LOG_TARGET,
"withdraw_asset what: {:?}, who: {:?}, maybe_context: {:?}",
what,
who,
maybe_context,
);

let Fungibility::NonFungible(asset_instance) = what.fun else {
return Err(XcmExecutorError::AssetNotHandled.into());
};

let class_locality = Self::asset_to_collection(&what.id)?;

let from = <ConverterOf<T>>::convert_location(who).ok_or(XcmExecutorError::AccountIdConversionFailed)?;

let token = Self::asset_instance_to_token(class_locality, &asset_instance)
.ok_or(XcmExecutorError::InstanceConversionFailed)?;

<ModuleNftPallet<T>>::do_transfer(&from, &Self::account_id(), token)
.map(|_| what.clone().into())
.map_err(|_| XcmError::FailedToTransactAsset("non-fungible item withdraw failed"))
}

fn internal_transfer_asset(
asset: &MultiAsset,
from: &xcm::v3::MultiLocation,
to: &xcm::v3::MultiLocation,
context: &xcm::v3::XcmContext,
) -> Result<xcm_executor::Assets, xcm::v3::Error> {
log::trace!(
target: LOG_TARGET,
"internal_transfer_asset: {:?}, from: {:?}, to: {:?}, context: {:?}",
asset,
from,
to,
context
);

let Fungibility::NonFungible(asset_instance) = asset.fun else {
return Err(XcmExecutorError::AssetNotHandled.into());
};

let class_locality = Self::asset_to_collection(&asset.id)?;

let from = <ConverterOf<T>>::convert_location(from).ok_or(XcmExecutorError::AccountIdConversionFailed)?;
let to = <ConverterOf<T>>::convert_location(to).ok_or(XcmExecutorError::AccountIdConversionFailed)?;

let token = Self::asset_instance_to_token(class_locality, &asset_instance)
.ok_or(XcmExecutorError::InstanceConversionFailed)?;

<ModuleNftPallet<T>>::do_transfer(&from, &to, token)
.map(|_| asset.clone().into())
.map_err(|_| XcmError::FailedToTransactAsset("non-fungible item internal transfer failed"))
}
}
Loading

0 comments on commit 39c8bb6

Please sign in to comment.