From 51e15a07c4a1a560436db619c327446c24d1a216 Mon Sep 17 00:00:00 2001 From: Daniel Shiposha Date: Thu, 30 Jun 2022 08:27:50 +0000 Subject: [PATCH] fix(rmrk): include pending children into nft_children RPC --- --- a/pallets/proxy-rmrk-core/src/lib.rs +++ b/pallets/proxy-rmrk-core/src/lib.rs @@ -16,10 +16,15 @@ #![cfg_attr(not(feature = "std"), no_std)] -use frame_support::{pallet_prelude::*, transactional, BoundedVec, dispatch::DispatchResult}; +use frame_support::{ + pallet_prelude::*, + transactional, + BoundedVec, + dispatch::DispatchResult, +}; use frame_system::{pallet_prelude::*, ensure_signed}; use sp_runtime::{DispatchError, Permill, traits::StaticLookup}; -use sp_std::vec::Vec; +use sp_std::{vec::Vec, collections::btree_set::BTreeSet}; use up_data_structs::{*, mapping::TokenAddressMapping}; use pallet_common::{ Pallet as PalletCommon, Error as CommonError, CollectionHandle, CommonCollectionOperations, @@ -48,6 +53,10 @@ pub const NESTING_BUDGET: u32 = 5; +type PendingTarget = (CollectionId, TokenId); +type PendingChild = (RmrkCollectionId, RmrkNftId); +type PendingChildrenMap = BTreeSet; + #[frame_support::pallet] pub mod pallet { use super::*; @@ -383,12 +392,13 @@ [ Self::rmrk_property(TokenType, &NftType::Regular)?, Self::rmrk_property(Transferable, &transferable)?, - Self::rmrk_property(PendingNftAccept, &false)?, + Self::rmrk_property(PendingNftAccept, &None::)?, Self::rmrk_property(RoyaltyInfo, &royalty_info)?, Self::rmrk_property(Metadata, &metadata)?, Self::rmrk_property(Equipped, &false)?, Self::rmrk_property(ResourcePriorities, &>::new())?, Self::rmrk_property(NextResourceId, &(0 as RmrkResourceId))?, + Self::rmrk_property(PendingChildren, &PendingChildrenMap::new())?, ] .into_iter(), ) @@ -483,11 +493,11 @@ ); ensure!( - !Self::get_nft_property_decoded( + Self::get_nft_property_decoded::>( collection_id, nft_id, RmrkProperty::PendingNftAccept - )?, + )?.is_none(), >::NoPermission ); @@ -524,7 +534,15 @@ collection.id, nft_id, PropertyScope::Rmrk, - Self::rmrk_property(PendingNftAccept, &approval_required)?, + Self::rmrk_property::>( + PendingNftAccept, + &Some((target_collection_id, target_nft_id.into())) + )?, + )?; + + Self::insert_pending_child( + (target_collection_id, target_nft_id.into()), + (rmrk_collection_id, rmrk_nft_id), )?; } else { target_owner = T::CrossTokenAddressMapping::token_to_address( @@ -618,13 +636,23 @@ } })?; - >::set_scoped_token_property( - collection.id, + let pending_target = Self::get_nft_property_decoded::>( + collection_id, nft_id, - PropertyScope::Rmrk, - Self::rmrk_property(PendingNftAccept, &false)?, + RmrkProperty::PendingNftAccept )?; + if let Some(pending_target) = pending_target { + Self::remove_pending_child(pending_target, (rmrk_collection_id, rmrk_nft_id))?; + + >::set_scoped_token_property( + collection.id, + nft_id, + PropertyScope::Rmrk, + Self::rmrk_property(PendingNftAccept, &None::)?, + )?; + } + Self::deposit_event(Event::NFTAccepted { sender, recipient: new_owner, @@ -663,15 +691,18 @@ >::NoAvailableNftId ); - ensure!( - Self::get_nft_property_decoded( - collection_id, - nft_id, - RmrkProperty::PendingNftAccept - )?, - >::CannotRejectNonPendingNft - ); + let pending_target = Self::get_nft_property_decoded::>( + collection_id, + nft_id, + RmrkProperty::PendingNftAccept + )?; + + match pending_target { + Some(pending_target) => Self::remove_pending_child(pending_target, (rmrk_collection_id, rmrk_nft_id))?, + None => return Err(>::CannotRejectNonPendingNft.into()), + } + Self::destroy_nft( cross_sender, collection_id, @@ -1147,6 +1178,64 @@ ) } + fn insert_pending_child( + target: (CollectionId, TokenId), + child: (RmrkCollectionId, RmrkNftId), + ) -> DispatchResult { + Self::mutate_pending_child(target, |pending_children| { + pending_children.insert(child); + }) + } + + fn remove_pending_child( + target: (CollectionId, TokenId), + child: (RmrkCollectionId, RmrkNftId), + ) -> DispatchResult { + Self::mutate_pending_child(target, |pending_children| { + pending_children.remove(&child); + }) + } + + fn mutate_pending_child( + (target_collection_id, target_nft_id): (CollectionId, TokenId), + f: impl FnOnce(&mut PendingChildrenMap), + ) -> DispatchResult { + >::try_mutate_token_aux_property( + target_collection_id, + target_nft_id, + PropertyScope::Rmrk, + Self::rmrk_property_key(PendingChildren)?, + |pending_children| -> DispatchResult { + let mut map = match pending_children { + Some(map) => Self::decode_property(map)?, + None => PendingChildrenMap::new(), + }; + + f(&mut map); + + *pending_children = Some(Self::encode_property(&map)?); + + Ok(()) + }, + ) + } + + fn iterate_pending_children(collection_id: CollectionId, nft_id: TokenId) -> Result, DispatchError> { + let property = >::token_aux_property(( + collection_id, + nft_id, + PropertyScope::Rmrk, + Self::rmrk_property_key(PendingChildren)? + )); + + let pending_children = match property { + Some(map) => Self::decode_property(&map)?, + None => PendingChildrenMap::new(), + }; + + Ok(pending_children.into_iter()) + } + fn acquire_next_resource_id( collection_id: CollectionId, nft_id: TokenId, @@ -1526,15 +1615,13 @@ Value: Decode + Default, Mapper: Fn(Key, Value) -> R, { - let key_prefix = Self::rmrk_property_key(UserProperty(b""))?; - let properties = match token_id { Some(token_id) => >::token_properties((collection_id, token_id)), None => >::collection_properties(collection_id), }; let properties = properties.into_iter().filter_map(move |(key, value)| { - let key = key.as_slice().strip_prefix(key_prefix.as_slice())?; + let key = strip_key_prefix(&key, USER_PROPERTY_PREFIX)?; let key: Key = key.to_vec().try_into().ok()?; let value: Value = value.decode().ok()?; --- a/pallets/proxy-rmrk-core/src/property.rs +++ b/pallets/proxy-rmrk-core/src/property.rs @@ -15,9 +15,11 @@ // along with Unique Network. If not, see . use super::*; +use up_data_structs::PropertyScope; use core::convert::AsRef; -const RESOURCE_ID_PREFIX: &str = "rsid-"; +pub const RESOURCE_ID_PREFIX: &str = "rsid-"; +pub const USER_PROPERTY_PREFIX: &str = "userprop-"; pub enum RmrkProperty<'r> { Metadata, @@ -31,6 +33,7 @@ NextResourceId, ResourceId(RmrkResourceId), PendingNftAccept, + PendingChildren, Parts, Base, Src, @@ -73,6 +76,7 @@ Self::NextResourceId => key!("next-resource-id"), Self::ResourceId(id) => key!(RESOURCE_ID_PREFIX, id.to_le_bytes()), Self::PendingNftAccept => key!("pending-nft-accept"), + Self::PendingChildren => key!("pending-children"), Self::Parts => key!("parts"), Self::Base => key!("base"), Self::Src => key!("src"), @@ -83,7 +87,19 @@ Self::ZIndex => key!("z-index"), Self::ThemeName => key!("theme-name"), Self::ThemeInherit => key!("theme-inherit"), - Self::UserProperty(name) => key!("userprop-", name), + Self::UserProperty(name) => key!(USER_PROPERTY_PREFIX, name), } } } + +pub fn strip_key_prefix(key: &PropertyKey, prefix: &str) -> Option { + let key_prefix = PropertyKey::try_from(prefix.as_bytes().to_vec()).ok()?; + let key_prefix = PropertyScope::Rmrk.apply(key_prefix).ok()?; + + key.as_slice().strip_prefix(key_prefix.as_slice())? + .to_vec().try_into().ok() +} + +pub fn is_valid_key_prefix(key: &PropertyKey, prefix: &str) -> bool { + strip_key_prefix(key, prefix).is_some() +} --- a/pallets/proxy-rmrk-core/src/rpc.rs +++ b/pallets/proxy-rmrk-core/src/rpc.rs @@ -132,17 +132,6 @@ Ok( pallet_nonfungible::TokenChildren::::iter_prefix((collection_id, nft_id)) .filter_map(|((child_collection, child_token), _)| { - let is_pending = >::get_nft_property_decoded( - child_collection, - child_token, - RmrkProperty::PendingNftAccept, - ) - .ok()?; - - if is_pending { - return None; - } - let rmrk_child_collection = >::rmrk_collection_id(child_collection).ok()?; @@ -151,6 +140,13 @@ nft_id: child_token.0, }) }) + .chain( + >::iterate_pending_children(collection_id, nft_id)? + .map(|(child_collection, child_nft_id)| RmrkNftChild { + collection_id: child_collection, + nft_id: child_nft_id, + }) + ) .collect(), ) } @@ -224,7 +220,11 @@ nft_id, PropertyScope::Rmrk, ) - .filter_map(|(_, value)| { + .filter_map(|(key, value)| { + if !is_valid_key_prefix(&key, RESOURCE_ID_PREFIX) { + return None; + } + let resource_info: RmrkResourceInfo = >::decode_property(&value).ok()?; Some(resource_info) -- gitstuff