From e2da42b8b0243731ab070cbbfe9ce58cb0c6434c Mon Sep 17 00:00:00 2001 From: Daniel Shiposha Date: Wed, 18 Oct 2023 12:58:06 +0000 Subject: [PATCH] feat: xcm nft support --- --- a/pallets/common/src/lib.rs +++ b/pallets/common/src/lib.rs @@ -2351,6 +2351,11 @@ /// Is the collection a foreign one? fn is_foreign(&self) -> bool; + /// Does the token have children? + fn token_has_children(&self, _token: TokenId) -> bool { + false + } + /// Create a collection's item using a transaction. /// /// This function performs additional XCM-related checks before the actual creation. --- a/pallets/foreign-assets/src/lib.rs +++ b/pallets/foreign-assets/src/lib.rs @@ -364,7 +364,7 @@ fn check_out(_dest: &MultiLocation, _what: &MultiAsset, _context: &XcmContext) {} - fn deposit_asset(what: &MultiAsset, to: &MultiLocation, context: &XcmContext) -> XcmResult { + fn deposit_asset(what: &MultiAsset, to: &MultiLocation, _context: &XcmContext) -> XcmResult { let collection_id = Self::multiasset_to_collection(what)?; let dispatch = T::CollectionDispatch::dispatch(collection_id).map_err(|_| XcmError::AssetNotFound)?; @@ -397,7 +397,42 @@ from: &MultiLocation, _maybe_context: Option<&XcmContext>, ) -> Result { - Err(XcmError::Unimplemented) + let from = T::LocationToAccountId::convert_location(from) + .ok_or(XcmExecutorError::AccountIdConversionFailed)?; + + let collection_id = Self::multiasset_to_collection(what)?; + let dispatch = + T::CollectionDispatch::dispatch(collection_id).map_err(|_| XcmError::AssetNotFound)?; + + let collection = dispatch.as_dyn(); + let xcm_ext = collection.xcm_extensions().ok_or(XcmError::NoPermission)?; + + match what.fun { + Fungibility::Fungible(amount) => xcm_ext + .burn_item(from, TokenId::default(), amount) + .map_err(|_| XcmError::FailedToTransactAsset("fungible item withdraw failed"))?, + + Fungibility::NonFungible(asset_instance) => { + let token_id = + Self::asset_instance_to_token_id(xcm_ext, collection_id, &asset_instance)? + .ok_or(XcmError::AssetNotFound)?; + + if xcm_ext.token_has_children(token_id) { + return Err(XcmError::Unimplemented); + } + + let depositor = &from; + let to = Self::pallet_account(); + let amount = 1; + xcm_ext + .transfer_item(depositor, &from, &to, token_id, amount, &ZeroBudget) + .map_err(|_| { + XcmError::FailedToTransactAsset("nonfungible item withdraw failed") + })?; + } + } + + Ok(what.clone().into()) } fn internal_transfer_asset( @@ -406,7 +441,49 @@ to: &MultiLocation, _context: &XcmContext, ) -> Result { - Err(XcmError::Unimplemented) + let collection_id = Self::multiasset_to_collection(what)?; + + let dispatch = + T::CollectionDispatch::dispatch(collection_id).map_err(|_| XcmError::AssetNotFound)?; + let collection = dispatch.as_dyn(); + let xcm_ext = collection.xcm_extensions().ok_or(XcmError::NoPermission)?; + + let from = T::LocationToAccountId::convert_location(from) + .ok_or(XcmExecutorError::AccountIdConversionFailed)?; + + let to = T::LocationToAccountId::convert_location(to) + .ok_or(XcmExecutorError::AccountIdConversionFailed)?; + + let depositor = &from; + + match what.fun { + Fungibility::Fungible(amount) => xcm_ext + .transfer_item( + depositor, + &from, + &to, + TokenId::default(), + amount, + &ZeroBudget, + ) + .map_err(|_| XcmError::FailedToTransactAsset("fungible item transfer failed"))?, + + Fungibility::NonFungible(asset_instance) => { + let token_id = + Self::asset_instance_to_token_id(xcm_ext, collection_id, &asset_instance)? + .ok_or(XcmError::AssetNotFound)?; + + let amount = 1; + + xcm_ext + .transfer_item(depositor, &from, &to, token_id, amount, &ZeroBudget) + .map_err(|_| { + XcmError::FailedToTransactAsset("nonfungible item transfer failed") + })?; + } + } + + Ok(what.clone().into()) } } --- a/pallets/fungible/src/lib.rs +++ b/pallets/fungible/src/lib.rs @@ -95,9 +95,8 @@ use sp_runtime::{ArithmeticError, DispatchError, DispatchResult}; use sp_std::{collections::btree_map::BTreeMap, vec::Vec}; use up_data_structs::{ - budget::{Budget, ZeroBudget}, - mapping::TokenAddressMapping, - AccessMode, CollectionId, CreateCollectionData, Property, PropertyKey, TokenId, + budget::Budget, mapping::TokenAddressMapping, AccessMode, CollectionId, Property, PropertyKey, + TokenId, }; use weights::WeightInfo; --- a/pallets/nonfungible/src/common.rs +++ b/pallets/nonfungible/src/common.rs @@ -576,6 +576,10 @@ self.flags.foreign } + fn token_has_children(&self, token: TokenId) -> bool { + >::token_has_children(self.id, token) + } + fn create_item_internal( &self, depositor: &::CrossAccountId, --- a/pallets/nonfungible/src/lib.rs +++ b/pallets/nonfungible/src/lib.rs @@ -117,8 +117,8 @@ use sp_std::{collections::btree_map::BTreeMap, vec, vec::Vec}; use up_data_structs::{ budget::Budget, mapping::TokenAddressMapping, AccessMode, AuxPropertyValue, CollectionId, - CreateCollectionData, CreateNftExData, CustomDataLimit, PropertiesPermissionMap, Property, - PropertyKey, PropertyKeyPermission, PropertyScope, PropertyValue, TokenChild, TokenId, + CreateNftExData, CustomDataLimit, PropertiesPermissionMap, Property, PropertyKey, + PropertyKeyPermission, PropertyScope, PropertyValue, TokenChild, TokenId, TokenProperties as TokenPropertiesT, }; use weights::WeightInfo; -- gitstuff