From ed591baa5c512aa1c70f87dfa0ea014b2c1ec76d Mon Sep 17 00:00:00 2001 From: kozyrevdev <73348153+kozyrevdev@users.noreply.github.com> Date: Tue, 14 Jun 2022 17:36:58 +0000 Subject: [PATCH] Merge pull request #385 from UniqueNetwork/feature/conditional-rmrk feat(rmrk): remove RMRK proxy from unique runtime --- --- a/node/rpc/Cargo.toml +++ b/node/rpc/Cargo.toml @@ -63,3 +63,4 @@ [features] default = [] std = [] +unique-runtime = [] --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -169,7 +169,11 @@ Eth, EthApiServer, EthDevSigner, EthFilter, EthFilterApiServer, EthPubSub, EthPubSubApiServer, EthSigner, Net, NetApiServer, Web3, Web3ApiServer, }; - use uc_rpc::{UniqueApiServer, Unique, RmrkApiServer, Rmrk}; + use uc_rpc::{UniqueApiServer, Unique}; + + #[cfg(not(feature = "unique-runtime"))] + use uc_rpc::{RmrkApiServer, Rmrk}; + // use pallet_contracts_rpc::{Contracts, ContractsApi}; use pallet_transaction_payment_rpc::{TransactionPaymentRpc, TransactionPaymentApiServer}; use substrate_frame_rpc_system::{SystemRpc, SystemApiServer}; @@ -223,6 +227,8 @@ )?; io.merge(Unique::new(client.clone()).into_rpc())?; + + #[cfg(not(feature = "unique-runtime"))] io.merge(Rmrk::new(client.clone()).into_rpc())?; if let Some(filter_pool) = filter_pool { --- a/runtime/common/src/runtime_apis.rs +++ b/runtime/common/src/runtime_apis.rs @@ -144,402 +144,6 @@ } } - impl rmrk_rpc::RmrkApi< - Block, - AccountId, - RmrkCollectionInfo, - RmrkInstanceInfo, - RmrkResourceInfo, - RmrkPropertyInfo, - RmrkBaseInfo, - RmrkPartType, - RmrkTheme - > for Runtime { - fn last_collection_idx() -> Result { - Ok(RmrkCore::last_collection_idx()) - } - - fn collection_by_id(collection_id: RmrkCollectionId) -> Result>, DispatchError> { - use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType}; - use pallet_common::CommonCollectionOperations; - - let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(collection_id, CollectionType::Regular) { - Ok(c) => c, - Err(_) => return Ok(None), - }; - - let nfts_count = collection.total_supply(); - - Ok(Some(RmrkCollectionInfo { - issuer: collection.owner.clone(), - metadata: RmrkCore::get_collection_property_decoded(collection_id, RmrkProperty::Metadata)?, - max: collection.limits.token_limit, - symbol: RmrkCore::rebind(&collection.token_prefix)?, - nfts_count - })) - } - - fn nft_by_id(collection_id: RmrkCollectionId, nft_by_id: RmrkNftId) -> Result>, DispatchError> { - use up_data_structs::mapping::TokenAddressMapping; - use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType}; - use pallet_common::CommonCollectionOperations; - - let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(collection_id, CollectionType::Regular) { - Ok(c) => c, - Err(_) => return Ok(None), - }; - - let nft_id = TokenId(nft_by_id); - if !RmrkCore::nft_exists(collection_id, nft_id) { return Ok(None); } - - let owner = match collection.token_owner(nft_id) { - Some(owner) => match ::CrossTokenAddressMapping::address_to_token(&owner) { - Some((col, tok)) => { - let rmrk_collection = RmrkCore::rmrk_collection_id(col)?; - - RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple(rmrk_collection, tok.0) - } - None => RmrkAccountIdOrCollectionNftTuple::AccountId(owner.as_sub().clone()) - }, - None => return Ok(None) - }; - - Ok(Some(RmrkInstanceInfo { - owner: owner, - royalty: RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::RoyaltyInfo)?, - metadata: RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::Metadata)?, - equipped: RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::Equipped)?, - pending: RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::PendingNftAccept)?, - })) - } - - fn account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Result, DispatchError> { - use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType}; - use pallet_common::CommonCollectionOperations; - - let cross_account_id = CrossAccountId::from_sub(account_id); - - let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(collection_id, CollectionType::Regular) { - Ok(c) => c, - Err(_) => return Ok(Vec::new()), - }; - - let tokens = collection.account_tokens(cross_account_id) - .into_iter() - .filter(|token| { - let is_pending = RmrkCore::get_nft_property_decoded( - collection_id, - *token, - RmrkProperty::PendingNftAccept - ).unwrap_or(true); - - !is_pending - }) - .map(|token| token.0) - .collect(); - - Ok(tokens) - } - - fn nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result, DispatchError> { - use pallet_proxy_rmrk_core::RmrkProperty; - - let collection_id = match RmrkCore::unique_collection_id(collection_id) { - Ok(id) => id, - Err(_) => return Ok(Vec::new()) - }; - let nft_id = TokenId(nft_id); - if !RmrkCore::nft_exists(collection_id, nft_id) { return Ok(Vec::new()); } - - Ok( - pallet_nonfungible::TokenChildren::::iter_prefix((collection_id, nft_id)) - .filter_map(|((child_collection, child_token), _)| { - let is_pending = RmrkCore::get_nft_property_decoded( - child_collection, - child_token, - RmrkProperty::PendingNftAccept - ).ok()?; - - if is_pending { - return None; - } - - let rmrk_child_collection = RmrkCore::rmrk_collection_id( - child_collection - ).ok()?; - - Some(RmrkNftChild { - collection_id: rmrk_child_collection, - nft_id: child_token.0, - }) - }).collect() - ) - } - - fn collection_properties(collection_id: RmrkCollectionId, filter_keys: Option>) -> Result, DispatchError> { - use pallet_proxy_rmrk_core::misc::CollectionType; - - let collection_id = match RmrkCore::unique_collection_id(collection_id) { - Ok(id) => id, - Err(_) => return Ok(Vec::new()) - }; - if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() { - return Ok(Vec::new()); - } - - let properties = RmrkCore::filter_user_properties( - collection_id, - /* token_id = */ None, - filter_keys, - |key, value| RmrkPropertyInfo { - key, - value - } - )?; - - Ok(properties) - } - - fn nft_properties(collection_id: RmrkCollectionId, nft_id: RmrkNftId, filter_keys: Option>) -> Result, DispatchError> { - use pallet_proxy_rmrk_core::misc::NftType; - - let collection_id = match RmrkCore::unique_collection_id(collection_id) { - Ok(id) => id, - Err(_) => return Ok(Vec::new()) - }; - let token_id = TokenId(nft_id); - - if RmrkCore::ensure_nft_type(collection_id, token_id, NftType::Regular).is_err() { - return Ok(Vec::new()); - } - - let properties = RmrkCore::filter_user_properties( - collection_id, - Some(token_id), - filter_keys, - |key, value| RmrkPropertyInfo { - key, - value - } - )?; - - Ok(properties) - } - - fn nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result, DispatchError> { - use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType, ResourceType}}; - use pallet_common::CommonCollectionOperations; - - let collection_id = match RmrkCore::unique_collection_id(collection_id) { - Ok(id) => id, - Err(_) => return Ok(Vec::new()) - }; - if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() { return Ok(Vec::new()); } - - let nft_id = TokenId(nft_id); - if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { return Ok(Vec::new()); } - - let res_collection_id: Option = RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::ResourceCollection)?; - - let res_collection_id = match res_collection_id { - Some(id) => id, - None => return Ok(Vec::new()) - }; - - let resource_collection = RmrkCore::get_typed_nft_collection(res_collection_id, CollectionType::Resource)?; - - let resources = resource_collection - .collection_tokens() - .iter() - .filter_map(|(res_id)| Some(RmrkResourceInfo { - id: res_id.0, - pending: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::PendingResourceAccept).ok()?, - pending_removal: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::PendingResourceRemoval).ok()?, - resource: match RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::ResourceType).ok()? { - ResourceType::Basic => RmrkResourceTypes::Basic(RmrkBasicResource { - src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).ok()?, - metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).ok()?, - license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).ok()?, - thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).ok()?, - }), - ResourceType::Composable => RmrkResourceTypes::Composable(RmrkComposableResource { - parts: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Parts).ok()?, - base: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Base).ok()?, - src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).ok()?, - metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).ok()?, - license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).ok()?, - thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).ok()?, - }), - ResourceType::Slot => RmrkResourceTypes::Slot(RmrkSlotResource { - base: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Base).ok()?, - src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).ok()?, - metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).ok()?, - slot: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Slot).ok()?, - license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).ok()?, - thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).ok()?, - }), - }, - })) - .collect(); - - Ok(resources) - } - - fn nft_resource_priority(collection_id: RmrkCollectionId, nft_id: RmrkNftId, resource_id: RmrkResourceId) -> Result, DispatchError> { - use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType}}; - - let collection_id = match RmrkCore::unique_collection_id(collection_id) { - Ok(id) => id, - Err(_) => return Ok(None) - }; - if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() { return Ok(None); } - - let nft_id = TokenId(nft_id); - if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { return Ok(None); } - - let priorities: Vec<_> = RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::ResourcePriorities)?; - Ok( - priorities.into_iter() - .enumerate() - .find(|(_, id)| *id == resource_id) - .map(|(priority, _): (usize, RmrkResourceId)| priority as u32) - ) - } - - fn base(base_id: RmrkBaseId) -> Result>, DispatchError> { - use pallet_proxy_rmrk_core::{ - RmrkProperty, misc::{CollectionType}, - }; - - let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(base_id, CollectionType::Base) { - Ok(c) => c, - Err(_) => return Ok(None), - }; - - Ok(Some(RmrkBaseInfo { - issuer: collection.owner.clone(), - base_type: RmrkCore::get_collection_property_decoded(collection_id, RmrkProperty::BaseType)?, - symbol: RmrkCore::rebind(&collection.token_prefix)?, - })) - } - - fn base_parts(base_id: RmrkBaseId) -> Result, DispatchError> { - use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType}}; - use pallet_common::CommonCollectionOperations; - - let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(base_id, CollectionType::Base) { - Ok(c) => c, - Err(_) => return Ok(Vec::new()), - }; - - let parts = collection.collection_tokens() - .into_iter() - .filter_map(|token_id| { - let nft_type = RmrkCore::get_nft_type(collection_id, token_id).ok()?; - - match nft_type { - NftType::FixedPart => Some(RmrkPartType::FixedPart(RmrkFixedPart { - id: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ExternalPartId).ok()?, - src: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::Src).ok()?, - z: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ZIndex).ok()?, - })), - NftType::SlotPart => Some(RmrkPartType::SlotPart(RmrkSlotPart { - id: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ExternalPartId).ok()?, - src: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::Src).ok()?, - z: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ZIndex).ok()?, - equippable: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::EquippableList).ok()?, - })), - _ => None - } - }) - .collect(); - - Ok(parts) - } - - fn theme_names(base_id: RmrkBaseId) -> Result, DispatchError> { - use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType}; - use pallet_common::CommonCollectionOperations; - - let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(base_id, CollectionType::Base) { - Ok(c) => c, - Err(_) => return Ok(Vec::new()), - }; - - let theme_names = collection.collection_tokens() - .iter() - .filter_map(|token_id| { - let nft_type = RmrkCore::get_nft_type(collection_id, *token_id).ok()?; - - match nft_type { - Theme => RmrkCore::get_nft_property_decoded(collection_id, *token_id, RmrkProperty::ThemeName).ok(), - _ => None - } - }) - .collect(); - - Ok(theme_names) - } - - fn theme(base_id: RmrkBaseId, theme_name: RmrkThemeName, filter_keys: Option>) -> Result, DispatchError> { - use pallet_proxy_rmrk_core::{ - RmrkProperty, - misc::{CollectionType, NftType} - }; - use pallet_common::CommonCollectionOperations; - - let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(base_id, CollectionType::Base) { - Ok(c) => c, - Err(_) => return Ok(None), - }; - - let theme_info = collection.collection_tokens() - .into_iter() - .find_map(|token_id| { - RmrkCore::ensure_nft_type(collection_id, token_id, NftType::Theme).ok()?; - - let name: RmrkString = RmrkCore::get_nft_property_decoded( - collection_id, token_id, RmrkProperty::ThemeName - ).ok()?; - - if name == theme_name { - Some((name, token_id)) - } else { - None - } - }); - - let (name, theme_id) = match theme_info { - Some((name, theme_id)) => (name, theme_id), - None => return Ok(None) - }; - - let properties = RmrkCore::filter_user_properties( - collection_id, - Some(theme_id), - filter_keys, - |key, value| RmrkThemeProperty { - key, - value - } - )?; - - let inherit = RmrkCore::get_nft_property_decoded( - collection_id, - theme_id, - RmrkProperty::ThemeInherit - )?; - - let theme = RmrkTheme { - name, - properties, - inherit, - }; - - Ok(Some(theme)) - } - } - impl sp_api::Core for Runtime { fn version() -> RuntimeVersion { VERSION --- a/runtime/opal/src/lib.rs +++ b/runtime/opal/src/lib.rs @@ -1315,7 +1315,405 @@ }}; } -impl_common_runtime_apis!(); +impl_common_runtime_apis! { + #![custom_apis] + + impl rmrk_rpc::RmrkApi< + Block, + AccountId, + RmrkCollectionInfo, + RmrkInstanceInfo, + RmrkResourceInfo, + RmrkPropertyInfo, + RmrkBaseInfo, + RmrkPartType, + RmrkTheme + > for Runtime { + fn last_collection_idx() -> Result { + Ok(RmrkCore::last_collection_idx()) + } + + fn collection_by_id(collection_id: RmrkCollectionId) -> Result>, DispatchError> { + use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType}; + use pallet_common::CommonCollectionOperations; + + let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(collection_id, CollectionType::Regular) { + Ok(c) => c, + Err(_) => return Ok(None), + }; + + let nfts_count = collection.total_supply(); + + Ok(Some(RmrkCollectionInfo { + issuer: collection.owner.clone(), + metadata: RmrkCore::get_collection_property_decoded(collection_id, RmrkProperty::Metadata)?, + max: collection.limits.token_limit, + symbol: RmrkCore::rebind(&collection.token_prefix)?, + nfts_count + })) + } + + fn nft_by_id(collection_id: RmrkCollectionId, nft_by_id: RmrkNftId) -> Result>, DispatchError> { + use up_data_structs::mapping::TokenAddressMapping; + use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType}; + use pallet_common::CommonCollectionOperations; + + let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(collection_id, CollectionType::Regular) { + Ok(c) => c, + Err(_) => return Ok(None), + }; + + let nft_id = TokenId(nft_by_id); + if !RmrkCore::nft_exists(collection_id, nft_id) { return Ok(None); } + + let owner = match collection.token_owner(nft_id) { + Some(owner) => match ::CrossTokenAddressMapping::address_to_token(&owner) { + Some((col, tok)) => { + let rmrk_collection = RmrkCore::rmrk_collection_id(col)?; + + RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple(rmrk_collection, tok.0) + } + None => RmrkAccountIdOrCollectionNftTuple::AccountId(owner.as_sub().clone()) + }, + None => return Ok(None) + }; + + Ok(Some(RmrkInstanceInfo { + owner: owner, + royalty: RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::RoyaltyInfo)?, + metadata: RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::Metadata)?, + equipped: RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::Equipped)?, + pending: RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::PendingNftAccept)?, + })) + } + + fn account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Result, DispatchError> { + use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType}; + use pallet_common::CommonCollectionOperations; + + let cross_account_id = CrossAccountId::from_sub(account_id); + + let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(collection_id, CollectionType::Regular) { + Ok(c) => c, + Err(_) => return Ok(Vec::new()), + }; + + let tokens = collection.account_tokens(cross_account_id) + .into_iter() + .filter(|token| { + let is_pending = RmrkCore::get_nft_property_decoded( + collection_id, + *token, + RmrkProperty::PendingNftAccept + ).unwrap_or(true); + + !is_pending + }) + .map(|token| token.0) + .collect(); + + Ok(tokens) + } + + fn nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result, DispatchError> { + use pallet_proxy_rmrk_core::RmrkProperty; + + let collection_id = match RmrkCore::unique_collection_id(collection_id) { + Ok(id) => id, + Err(_) => return Ok(Vec::new()) + }; + let nft_id = TokenId(nft_id); + if !RmrkCore::nft_exists(collection_id, nft_id) { return Ok(Vec::new()); } + + Ok( + pallet_nonfungible::TokenChildren::::iter_prefix((collection_id, nft_id)) + .filter_map(|((child_collection, child_token), _)| { + let is_pending = RmrkCore::get_nft_property_decoded( + child_collection, + child_token, + RmrkProperty::PendingNftAccept + ).ok()?; + + if is_pending { + return None; + } + + let rmrk_child_collection = RmrkCore::rmrk_collection_id( + child_collection + ).ok()?; + + Some(RmrkNftChild { + collection_id: rmrk_child_collection, + nft_id: child_token.0, + }) + }).collect() + ) + } + + fn collection_properties(collection_id: RmrkCollectionId, filter_keys: Option>) -> Result, DispatchError> { + use pallet_proxy_rmrk_core::misc::CollectionType; + + let collection_id = match RmrkCore::unique_collection_id(collection_id) { + Ok(id) => id, + Err(_) => return Ok(Vec::new()) + }; + if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() { + return Ok(Vec::new()); + } + + let properties = RmrkCore::filter_user_properties( + collection_id, + /* token_id = */ None, + filter_keys, + |key, value| RmrkPropertyInfo { + key, + value + } + )?; + + Ok(properties) + } + + fn nft_properties(collection_id: RmrkCollectionId, nft_id: RmrkNftId, filter_keys: Option>) -> Result, DispatchError> { + use pallet_proxy_rmrk_core::misc::NftType; + + let collection_id = match RmrkCore::unique_collection_id(collection_id) { + Ok(id) => id, + Err(_) => return Ok(Vec::new()) + }; + let token_id = TokenId(nft_id); + + if RmrkCore::ensure_nft_type(collection_id, token_id, NftType::Regular).is_err() { + return Ok(Vec::new()); + } + + let properties = RmrkCore::filter_user_properties( + collection_id, + Some(token_id), + filter_keys, + |key, value| RmrkPropertyInfo { + key, + value + } + )?; + + Ok(properties) + } + + fn nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result, DispatchError> { + use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType, ResourceType}}; + use pallet_common::CommonCollectionOperations; + + let collection_id = match RmrkCore::unique_collection_id(collection_id) { + Ok(id) => id, + Err(_) => return Ok(Vec::new()) + }; + if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() { return Ok(Vec::new()); } + + let nft_id = TokenId(nft_id); + if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { return Ok(Vec::new()); } + + let res_collection_id: Option = RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::ResourceCollection)?; + + let res_collection_id = match res_collection_id { + Some(id) => id, + None => return Ok(Vec::new()) + }; + + let resource_collection = RmrkCore::get_typed_nft_collection(res_collection_id, CollectionType::Resource)?; + + let resources = resource_collection + .collection_tokens() + .iter() + .filter_map(|res_id| Some(RmrkResourceInfo { + id: res_id.0, + pending: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::PendingResourceAccept).ok()?, + pending_removal: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::PendingResourceRemoval).ok()?, + resource: match RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::ResourceType).ok()? { + ResourceType::Basic => RmrkResourceTypes::Basic(RmrkBasicResource { + src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).ok()?, + metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).ok()?, + license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).ok()?, + thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).ok()?, + }), + ResourceType::Composable => RmrkResourceTypes::Composable(RmrkComposableResource { + parts: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Parts).ok()?, + base: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Base).ok()?, + src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).ok()?, + metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).ok()?, + license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).ok()?, + thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).ok()?, + }), + ResourceType::Slot => RmrkResourceTypes::Slot(RmrkSlotResource { + base: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Base).ok()?, + src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).ok()?, + metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).ok()?, + slot: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Slot).ok()?, + license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).ok()?, + thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).ok()?, + }), + }, + })) + .collect(); + + Ok(resources) + } + + fn nft_resource_priority(collection_id: RmrkCollectionId, nft_id: RmrkNftId, resource_id: RmrkResourceId) -> Result, DispatchError> { + use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType}}; + + let collection_id = match RmrkCore::unique_collection_id(collection_id) { + Ok(id) => id, + Err(_) => return Ok(None) + }; + if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() { return Ok(None); } + + let nft_id = TokenId(nft_id); + if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { return Ok(None); } + + let priorities: Vec<_> = RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::ResourcePriorities)?; + Ok( + priorities.into_iter() + .enumerate() + .find(|(_, id)| *id == resource_id) + .map(|(priority, _): (usize, RmrkResourceId)| priority as u32) + ) + } + + fn base(base_id: RmrkBaseId) -> Result>, DispatchError> { + use pallet_proxy_rmrk_core::{ + RmrkProperty, misc::{CollectionType}, + }; + + let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(base_id, CollectionType::Base) { + Ok(c) => c, + Err(_) => return Ok(None), + }; + + Ok(Some(RmrkBaseInfo { + issuer: collection.owner.clone(), + base_type: RmrkCore::get_collection_property_decoded(collection_id, RmrkProperty::BaseType)?, + symbol: RmrkCore::rebind(&collection.token_prefix)?, + })) + } + + fn base_parts(base_id: RmrkBaseId) -> Result, DispatchError> { + use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType}}; + use pallet_common::CommonCollectionOperations; + + let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(base_id, CollectionType::Base) { + Ok(c) => c, + Err(_) => return Ok(Vec::new()), + }; + + let parts = collection.collection_tokens() + .into_iter() + .filter_map(|token_id| { + let nft_type = RmrkCore::get_nft_type(collection_id, token_id).ok()?; + + match nft_type { + NftType::FixedPart => Some(RmrkPartType::FixedPart(RmrkFixedPart { + id: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ExternalPartId).ok()?, + src: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::Src).ok()?, + z: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ZIndex).ok()?, + })), + NftType::SlotPart => Some(RmrkPartType::SlotPart(RmrkSlotPart { + id: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ExternalPartId).ok()?, + src: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::Src).ok()?, + z: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ZIndex).ok()?, + equippable: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::EquippableList).ok()?, + })), + _ => None + } + }) + .collect(); + + Ok(parts) + } + + fn theme_names(base_id: RmrkBaseId) -> Result, DispatchError> { + use pallet_proxy_rmrk_core::{RmrkProperty, misc::{NftType, CollectionType}}; + use pallet_common::CommonCollectionOperations; + + let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(base_id, CollectionType::Base) { + Ok(c) => c, + Err(_) => return Ok(Vec::new()), + }; + + let theme_names = collection.collection_tokens() + .iter() + .filter_map(|token_id| { + let nft_type = RmrkCore::get_nft_type(collection_id, *token_id).ok()?; + + match nft_type { + NftType::Theme => RmrkCore::get_nft_property_decoded(collection_id, *token_id, RmrkProperty::ThemeName).ok(), + _ => None + } + }) + .collect(); + + Ok(theme_names) + } + + fn theme(base_id: RmrkBaseId, theme_name: RmrkThemeName, filter_keys: Option>) -> Result, DispatchError> { + use pallet_proxy_rmrk_core::{ + RmrkProperty, + misc::{CollectionType, NftType} + }; + use pallet_common::CommonCollectionOperations; + + let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(base_id, CollectionType::Base) { + Ok(c) => c, + Err(_) => return Ok(None), + }; + + let theme_info = collection.collection_tokens() + .into_iter() + .find_map(|token_id| { + RmrkCore::ensure_nft_type(collection_id, token_id, NftType::Theme).ok()?; + + let name: RmrkString = RmrkCore::get_nft_property_decoded( + collection_id, token_id, RmrkProperty::ThemeName + ).ok()?; + + if name == theme_name { + Some((name, token_id)) + } else { + None + } + }); + + let (name, theme_id) = match theme_info { + Some((name, theme_id)) => (name, theme_id), + None => return Ok(None) + }; + + let properties = RmrkCore::filter_user_properties( + collection_id, + Some(theme_id), + filter_keys, + |key, value| RmrkThemeProperty { + key, + value + } + )?; + + let inherit = RmrkCore::get_nft_property_decoded( + collection_id, + theme_id, + RmrkProperty::ThemeInherit + )?; + + let theme = RmrkTheme { + name, + properties, + inherit, + }; + + Ok(Some(theme)) + } + } +} struct CheckInherents; --- a/runtime/quartz/src/lib.rs +++ b/runtime/quartz/src/lib.rs @@ -1315,7 +1315,405 @@ }}; } -impl_common_runtime_apis!(); +impl_common_runtime_apis! { + #![custom_apis] + + impl rmrk_rpc::RmrkApi< + Block, + AccountId, + RmrkCollectionInfo, + RmrkInstanceInfo, + RmrkResourceInfo, + RmrkPropertyInfo, + RmrkBaseInfo, + RmrkPartType, + RmrkTheme + > for Runtime { + fn last_collection_idx() -> Result { + Ok(RmrkCore::last_collection_idx()) + } + + fn collection_by_id(collection_id: RmrkCollectionId) -> Result>, DispatchError> { + use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType}; + use pallet_common::CommonCollectionOperations; + + let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(collection_id, CollectionType::Regular) { + Ok(c) => c, + Err(_) => return Ok(None), + }; + + let nfts_count = collection.total_supply(); + + Ok(Some(RmrkCollectionInfo { + issuer: collection.owner.clone(), + metadata: RmrkCore::get_collection_property_decoded(collection_id, RmrkProperty::Metadata)?, + max: collection.limits.token_limit, + symbol: RmrkCore::rebind(&collection.token_prefix)?, + nfts_count + })) + } + + fn nft_by_id(collection_id: RmrkCollectionId, nft_by_id: RmrkNftId) -> Result>, DispatchError> { + use up_data_structs::mapping::TokenAddressMapping; + use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType}; + use pallet_common::CommonCollectionOperations; + + let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(collection_id, CollectionType::Regular) { + Ok(c) => c, + Err(_) => return Ok(None), + }; + + let nft_id = TokenId(nft_by_id); + if !RmrkCore::nft_exists(collection_id, nft_id) { return Ok(None); } + + let owner = match collection.token_owner(nft_id) { + Some(owner) => match ::CrossTokenAddressMapping::address_to_token(&owner) { + Some((col, tok)) => { + let rmrk_collection = RmrkCore::rmrk_collection_id(col)?; + + RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple(rmrk_collection, tok.0) + } + None => RmrkAccountIdOrCollectionNftTuple::AccountId(owner.as_sub().clone()) + }, + None => return Ok(None) + }; + + Ok(Some(RmrkInstanceInfo { + owner: owner, + royalty: RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::RoyaltyInfo)?, + metadata: RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::Metadata)?, + equipped: RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::Equipped)?, + pending: RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::PendingNftAccept)?, + })) + } + + fn account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Result, DispatchError> { + use pallet_proxy_rmrk_core::{RmrkProperty, misc::CollectionType}; + use pallet_common::CommonCollectionOperations; + + let cross_account_id = CrossAccountId::from_sub(account_id); + + let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(collection_id, CollectionType::Regular) { + Ok(c) => c, + Err(_) => return Ok(Vec::new()), + }; + + let tokens = collection.account_tokens(cross_account_id) + .into_iter() + .filter(|token| { + let is_pending = RmrkCore::get_nft_property_decoded( + collection_id, + *token, + RmrkProperty::PendingNftAccept + ).unwrap_or(true); + + !is_pending + }) + .map(|token| token.0) + .collect(); + + Ok(tokens) + } + + fn nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result, DispatchError> { + use pallet_proxy_rmrk_core::RmrkProperty; + + let collection_id = match RmrkCore::unique_collection_id(collection_id) { + Ok(id) => id, + Err(_) => return Ok(Vec::new()) + }; + let nft_id = TokenId(nft_id); + if !RmrkCore::nft_exists(collection_id, nft_id) { return Ok(Vec::new()); } + + Ok( + pallet_nonfungible::TokenChildren::::iter_prefix((collection_id, nft_id)) + .filter_map(|((child_collection, child_token), _)| { + let is_pending = RmrkCore::get_nft_property_decoded( + child_collection, + child_token, + RmrkProperty::PendingNftAccept + ).ok()?; + + if is_pending { + return None; + } + + let rmrk_child_collection = RmrkCore::rmrk_collection_id( + child_collection + ).ok()?; + + Some(RmrkNftChild { + collection_id: rmrk_child_collection, + nft_id: child_token.0, + }) + }).collect() + ) + } + + fn collection_properties(collection_id: RmrkCollectionId, filter_keys: Option>) -> Result, DispatchError> { + use pallet_proxy_rmrk_core::misc::CollectionType; + + let collection_id = match RmrkCore::unique_collection_id(collection_id) { + Ok(id) => id, + Err(_) => return Ok(Vec::new()) + }; + if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() { + return Ok(Vec::new()); + } + + let properties = RmrkCore::filter_user_properties( + collection_id, + /* token_id = */ None, + filter_keys, + |key, value| RmrkPropertyInfo { + key, + value + } + )?; + + Ok(properties) + } + + fn nft_properties(collection_id: RmrkCollectionId, nft_id: RmrkNftId, filter_keys: Option>) -> Result, DispatchError> { + use pallet_proxy_rmrk_core::misc::NftType; + + let collection_id = match RmrkCore::unique_collection_id(collection_id) { + Ok(id) => id, + Err(_) => return Ok(Vec::new()) + }; + let token_id = TokenId(nft_id); + + if RmrkCore::ensure_nft_type(collection_id, token_id, NftType::Regular).is_err() { + return Ok(Vec::new()); + } + + let properties = RmrkCore::filter_user_properties( + collection_id, + Some(token_id), + filter_keys, + |key, value| RmrkPropertyInfo { + key, + value + } + )?; + + Ok(properties) + } + + fn nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result, DispatchError> { + use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType, ResourceType}}; + use pallet_common::CommonCollectionOperations; + + let collection_id = match RmrkCore::unique_collection_id(collection_id) { + Ok(id) => id, + Err(_) => return Ok(Vec::new()) + }; + if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() { return Ok(Vec::new()); } + + let nft_id = TokenId(nft_id); + if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { return Ok(Vec::new()); } + + let res_collection_id: Option = RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::ResourceCollection)?; + + let res_collection_id = match res_collection_id { + Some(id) => id, + None => return Ok(Vec::new()) + }; + + let resource_collection = RmrkCore::get_typed_nft_collection(res_collection_id, CollectionType::Resource)?; + + let resources = resource_collection + .collection_tokens() + .iter() + .filter_map(|res_id| Some(RmrkResourceInfo { + id: res_id.0, + pending: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::PendingResourceAccept).ok()?, + pending_removal: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::PendingResourceRemoval).ok()?, + resource: match RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::ResourceType).ok()? { + ResourceType::Basic => RmrkResourceTypes::Basic(RmrkBasicResource { + src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).ok()?, + metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).ok()?, + license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).ok()?, + thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).ok()?, + }), + ResourceType::Composable => RmrkResourceTypes::Composable(RmrkComposableResource { + parts: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Parts).ok()?, + base: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Base).ok()?, + src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).ok()?, + metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).ok()?, + license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).ok()?, + thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).ok()?, + }), + ResourceType::Slot => RmrkResourceTypes::Slot(RmrkSlotResource { + base: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Base).ok()?, + src: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Src).ok()?, + metadata: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Metadata).ok()?, + slot: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Slot).ok()?, + license: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::License).ok()?, + thumb: RmrkCore::get_nft_property_decoded(res_collection_id, *res_id, RmrkProperty::Thumb).ok()?, + }), + }, + })) + .collect(); + + Ok(resources) + } + + fn nft_resource_priority(collection_id: RmrkCollectionId, nft_id: RmrkNftId, resource_id: RmrkResourceId) -> Result, DispatchError> { + use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType}}; + + let collection_id = match RmrkCore::unique_collection_id(collection_id) { + Ok(id) => id, + Err(_) => return Ok(None) + }; + if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() { return Ok(None); } + + let nft_id = TokenId(nft_id); + if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Regular).is_err() { return Ok(None); } + + let priorities: Vec<_> = RmrkCore::get_nft_property_decoded(collection_id, nft_id, RmrkProperty::ResourcePriorities)?; + Ok( + priorities.into_iter() + .enumerate() + .find(|(_, id)| *id == resource_id) + .map(|(priority, _): (usize, RmrkResourceId)| priority as u32) + ) + } + + fn base(base_id: RmrkBaseId) -> Result>, DispatchError> { + use pallet_proxy_rmrk_core::{ + RmrkProperty, misc::{CollectionType}, + }; + + let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(base_id, CollectionType::Base) { + Ok(c) => c, + Err(_) => return Ok(None), + }; + + Ok(Some(RmrkBaseInfo { + issuer: collection.owner.clone(), + base_type: RmrkCore::get_collection_property_decoded(collection_id, RmrkProperty::BaseType)?, + symbol: RmrkCore::rebind(&collection.token_prefix)?, + })) + } + + fn base_parts(base_id: RmrkBaseId) -> Result, DispatchError> { + use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType}}; + use pallet_common::CommonCollectionOperations; + + let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(base_id, CollectionType::Base) { + Ok(c) => c, + Err(_) => return Ok(Vec::new()), + }; + + let parts = collection.collection_tokens() + .into_iter() + .filter_map(|token_id| { + let nft_type = RmrkCore::get_nft_type(collection_id, token_id).ok()?; + + match nft_type { + NftType::FixedPart => Some(RmrkPartType::FixedPart(RmrkFixedPart { + id: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ExternalPartId).ok()?, + src: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::Src).ok()?, + z: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ZIndex).ok()?, + })), + NftType::SlotPart => Some(RmrkPartType::SlotPart(RmrkSlotPart { + id: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ExternalPartId).ok()?, + src: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::Src).ok()?, + z: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::ZIndex).ok()?, + equippable: RmrkCore::get_nft_property_decoded(collection_id, token_id, RmrkProperty::EquippableList).ok()?, + })), + _ => None + } + }) + .collect(); + + Ok(parts) + } + + fn theme_names(base_id: RmrkBaseId) -> Result, DispatchError> { + use pallet_proxy_rmrk_core::{RmrkProperty, misc::{NftType, CollectionType}}; + use pallet_common::CommonCollectionOperations; + + let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(base_id, CollectionType::Base) { + Ok(c) => c, + Err(_) => return Ok(Vec::new()), + }; + + let theme_names = collection.collection_tokens() + .iter() + .filter_map(|token_id| { + let nft_type = RmrkCore::get_nft_type(collection_id, *token_id).ok()?; + + match nft_type { + NftType::Theme => RmrkCore::get_nft_property_decoded(collection_id, *token_id, RmrkProperty::ThemeName).ok(), + _ => None + } + }) + .collect(); + + Ok(theme_names) + } + + fn theme(base_id: RmrkBaseId, theme_name: RmrkThemeName, filter_keys: Option>) -> Result, DispatchError> { + use pallet_proxy_rmrk_core::{ + RmrkProperty, + misc::{CollectionType, NftType} + }; + use pallet_common::CommonCollectionOperations; + + let (collection, collection_id) = match RmrkCore::get_typed_nft_collection_mapped(base_id, CollectionType::Base) { + Ok(c) => c, + Err(_) => return Ok(None), + }; + + let theme_info = collection.collection_tokens() + .into_iter() + .find_map(|token_id| { + RmrkCore::ensure_nft_type(collection_id, token_id, NftType::Theme).ok()?; + + let name: RmrkString = RmrkCore::get_nft_property_decoded( + collection_id, token_id, RmrkProperty::ThemeName + ).ok()?; + + if name == theme_name { + Some((name, token_id)) + } else { + None + } + }); + + let (name, theme_id) = match theme_info { + Some((name, theme_id)) => (name, theme_id), + None => return Ok(None) + }; + + let properties = RmrkCore::filter_user_properties( + collection_id, + Some(theme_id), + filter_keys, + |key, value| RmrkThemeProperty { + key, + value + } + )?; + + let inherit = RmrkCore::get_nft_property_decoded( + collection_id, + theme_id, + RmrkProperty::ThemeInherit + )?; + + let theme = RmrkTheme { + name, + properties, + inherit, + }; + + Ok(Some(theme)) + } + } +} struct CheckInherents; --- a/runtime/unique/src/lib.rs +++ b/runtime/unique/src/lib.rs @@ -74,10 +74,9 @@ CollectionStats, RpcCollection, mapping::{EvmTokenAddressMapping, CrossTokenAddressMapping}, TokenChild, RmrkCollectionInfo, RmrkInstanceInfo, RmrkResourceInfo, RmrkPropertyInfo, - RmrkBaseInfo, RmrkPartType, RmrkTheme, RmrkThemeName, RmrkThemeProperty, RmrkCollectionId, - RmrkNftId, RmrkAccountIdOrCollectionNftTuple, RmrkNftChild, RmrkPropertyKey, RmrkResourceTypes, - RmrkBasicResource, RmrkComposableResource, RmrkSlotResource, RmrkResourceId, RmrkBaseId, - RmrkFixedPart, RmrkSlotPart, RmrkString, + RmrkBaseInfo, RmrkPartType, RmrkTheme, RmrkThemeName, RmrkCollectionId, + RmrkNftId, RmrkNftChild, RmrkPropertyKey, + RmrkResourceId, RmrkBaseId, }; // use pallet_contracts::weights::WeightInfo; @@ -914,15 +913,6 @@ } impl pallet_nonfungible::Config for Runtime { type WeightInfo = pallet_nonfungible::weights::SubstrateWeight; -} - -impl pallet_proxy_rmrk_core::Config for Runtime { - type WeightInfo = pallet_proxy_rmrk_core::weights::SubstrateWeight; - type Event = Event; -} - -impl pallet_proxy_rmrk_equip::Config for Runtime { - type Event = Event; } impl pallet_unique::Config for Runtime { @@ -1164,8 +1154,6 @@ Refungible: pallet_refungible::{Pallet, Storage} = 68, Nonfungible: pallet_nonfungible::{Pallet, Storage} = 69, Structure: pallet_structure::{Pallet, Call, Storage, Event} = 70, - RmrkCore: pallet_proxy_rmrk_core::{Pallet, Call, Storage, Event} = 71, - RmrkEquip: pallet_proxy_rmrk_equip::{Pallet, Call, Storage, Event} = 72, // Frontier EVM: pallet_evm::{Pallet, Config, Call, Storage, Event} = 100, @@ -1313,7 +1301,73 @@ }}; } -impl_common_runtime_apis!(); +impl_common_runtime_apis! { + #![custom_apis] + + impl rmrk_rpc::RmrkApi< + Block, + AccountId, + RmrkCollectionInfo, + RmrkInstanceInfo, + RmrkResourceInfo, + RmrkPropertyInfo, + RmrkBaseInfo, + RmrkPartType, + RmrkTheme + > for Runtime { + fn last_collection_idx() -> Result { + Ok(Default::default()) + } + + fn collection_by_id(_collection_id: RmrkCollectionId) -> Result>, DispatchError> { + Ok(Default::default()) + } + + fn nft_by_id(_collection_id: RmrkCollectionId, _nft_by_id: RmrkNftId) -> Result>, DispatchError> { + Ok(Default::default()) + } + + fn account_tokens(_account_id: AccountId, _collection_id: RmrkCollectionId) -> Result, DispatchError> { + Ok(Default::default()) + } + + fn nft_children(_collection_id: RmrkCollectionId, _nft_id: RmrkNftId) -> Result, DispatchError> { + Ok(Default::default()) + } + + fn collection_properties(_collection_id: RmrkCollectionId, _filter_keys: Option>) -> Result, DispatchError> { + Ok(Default::default()) + } + + fn nft_properties(_collection_id: RmrkCollectionId, _nft_id: RmrkNftId, _filter_keys: Option>) -> Result, DispatchError> { + Ok(Default::default()) + } + + fn nft_resources(_collection_id: RmrkCollectionId, _nft_id: RmrkNftId) -> Result, DispatchError> { + Ok(Default::default()) + } + + fn nft_resource_priority(_collection_id: RmrkCollectionId, _nft_id: RmrkNftId, _resource_id: RmrkResourceId) -> Result, DispatchError> { + Ok(Default::default()) + } + + fn base(_base_id: RmrkBaseId) -> Result>, DispatchError> { + Ok(Default::default()) + } + + fn base_parts(_base_id: RmrkBaseId) -> Result, DispatchError> { + Ok(Default::default()) + } + + fn theme_names(_base_id: RmrkBaseId) -> Result, DispatchError> { + Ok(Default::default()) + } + + fn theme(_base_id: RmrkBaseId, _theme_name: RmrkThemeName, _filter_keys: Option>) -> Result, DispatchError> { + Ok(Default::default()) + } + } +} struct CheckInherents; --- a/tests/src/eth/nesting/nest.test.ts +++ b/tests/src/eth/nesting/nest.test.ts @@ -29,34 +29,37 @@ const {collectionId, contract} = await createNestingCollection(api, web3, owner); // Create a token to be nested - const nftTokenId = await contract.methods.nextTokenId().call(); + const targetNFTTokenId = await contract.methods.nextTokenId().call(); await contract.methods.mint( owner, - nftTokenId, + targetNFTTokenId, ).send({from: owner}); - // Nest into a token - const firstTargetNftTokenId = await contract.methods.nextTokenId().call(); + const targetNftTokenAddress = tokenIdToAddress(collectionId, targetNFTTokenId); + + // Create a nested token + const firstTokenId = await contract.methods.nextTokenId().call(); await contract.methods.mint( - owner, - firstTargetNftTokenId, + targetNftTokenAddress, + firstTokenId, ).send({from: owner}); - - const targetNftTokenAddress = tokenIdToAddress(collectionId, firstTargetNftTokenId); - await contract.methods.transfer(targetNftTokenAddress, nftTokenId).send({from: owner}); - expect(await contract.methods.ownerOf(nftTokenId).call()).to.be.equal(targetNftTokenAddress); + expect(await contract.methods.ownerOf(firstTokenId).call()).to.be.equal(targetNftTokenAddress); - // Re-nest into another - const secondTargetNftTokenId = await contract.methods.nextTokenId().call(); + // Create a token to be nested and nest + const secondTokenId = await contract.methods.nextTokenId().call(); await contract.methods.mint( owner, - secondTargetNftTokenId, + secondTokenId, ).send({from: owner}); - const nextNftTokenAddress = tokenIdToAddress(collectionId, secondTargetNftTokenId); - await contract.methods.transfer(nextNftTokenAddress, nftTokenId).send({from: owner}); - expect(await contract.methods.ownerOf(nftTokenId).call()).to.be.equal(nextNftTokenAddress); + await contract.methods.transfer(targetNftTokenAddress, secondTokenId).send({from: owner}); + + expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(targetNftTokenAddress); + + // Unnest token back + await contract.methods.transferFrom(targetNftTokenAddress, owner, secondTokenId).send({from: owner}); + expect(await contract.methods.ownerOf(secondTokenId).call()).to.be.equal(owner); }); itWeb3('NFT: allows an Owner to nest/unnest their token (Restricted nesting)', async ({api, web3, privateKeyWrapper}) => { @@ -125,7 +128,7 @@ .transfer(targetNftTokenAddress, nftTokenId) .call({from: owner})).to.be.rejectedWith('UserIsNotAllowedToNest'); }); - + itWeb3('NFT: disallows a non-Owner to nest someone else\'s token', async ({api, web3, privateKeyWrapper}) => { const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); const malignant = await createEthAccountWithBalance(api, web3, privateKeyWrapper); @@ -139,20 +142,20 @@ targetTokenId, ).send({from: owner}); const targetTokenAddress = tokenIdToAddress(collectionId, targetTokenId); - + // Mint a token belonging to a different account const tokenId = await contract.methods.nextTokenId().call(); await contract.methods.mint( malignant, tokenId, ).send({from: owner}); - + // Try to nest one token in another as a non-owner account await expect(contract.methods .transfer(targetTokenAddress, tokenId) .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest'); }); - + itWeb3('NFT: disallows a non-Owner to nest someone else\'s token (Restricted nesting)', async ({api, web3, privateKeyWrapper}) => { const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); const malignant = await createEthAccountWithBalance(api, web3, privateKeyWrapper); @@ -182,7 +185,7 @@ .transfer(nftTokenAddressA, nftTokenIdB) .call({from: malignant})).to.be.rejectedWith('UserIsNotAllowedToNest'); }); - + itWeb3('NFT: disallows to nest token in an unlisted collection', async ({api, web3, privateKeyWrapper}) => { const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper); --- a/tests/src/nesting/nest.test.ts +++ b/tests/src/nesting/nest.test.ts @@ -454,6 +454,7 @@ it('Admin (NFT): disallows an Admin to nest and unnest someone else\'s token', async () => { await usingApi(async api => { const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}}); + await setCollectionLimitsExpectSuccess(alice, collection, {ownerCanTransfer: true}); await setCollectionPermissionsExpectSuccess(alice, collection, {nesting: {collectionAdmin: true}}); await addToAllowListExpectSuccess(alice, collection, bob.address); --- a/tests/src/pallet-presence.test.ts +++ b/tests/src/pallet-presence.test.ts @@ -50,8 +50,6 @@ 'unique', 'nonfungible', 'refungible', - 'rmrkcore', - 'rmrkequip', 'scheduler', 'charging', ]; @@ -64,6 +62,16 @@ ]; describe('Pallet presence', () => { + before(async () => { + await usingApi(async api => { + const chain = await api.rpc.system.chain(); + + if (!chain.eq('UNIQUE')) { + requiredPallets.push(...['rmrkcore', 'rmrkequip']); + } + }); + }); + it('Required pallets are present', async () => { await usingApi(async api => { for (let i=0; i { +async function isUnique(): Promise { + return usingApi(async api => { + const chain = await api.rpc.system.chain(); + + return chain.eq('UNIQUE'); + }); +} + +describe('RMRK External Integration Test', async () => { + const it_rmrk = (await isUnique() ? it : it.skip); + before(async () => { await usingApi(async (api, privateKeyWrapper) => { alice = privateKeyWrapper('//Alice'); + + }); }); - it('Creates a new RMRK collection that is mapped to a different ID and is tagged as external', async () => { + it_rmrk('Creates a new RMRK collection that is mapped to a different ID and is tagged as external', async () => { await usingApi(async api => { // throwaway collection to bump last Unique collection ID to test ID mapping await createCollectionExpectSuccess(); @@ -70,11 +83,13 @@ }); }); -describe('Negative Integration Test: External Collections, Internal Ops', () => { +describe('Negative Integration Test: External Collections, Internal Ops', async () => { let uniqueCollectionId: number; let rmrkCollectionId: number; let rmrkNftId: number; + const it_rmrk = (await isUnique() ? it : it.skip); + before(async () => { await usingApi(async (api, privateKeyWrapper) => { alice = privateKeyWrapper('//Alice'); @@ -88,7 +103,7 @@ }); }); - it('[Negative] Forbids Unique operations with an external collection, handled by dispatch_call', async () => { + it_rmrk('[Negative] Forbids Unique operations with an external collection, handled by dispatch_call', async () => { await usingApi(async api => { // Collection item creation @@ -147,7 +162,7 @@ }); }); - it('[Negative] Forbids Unique collection operations with an external collection', async () => { + it_rmrk('[Negative] Forbids Unique collection operations with an external collection', async () => { await usingApi(async api => { const txDestroyCollection = api.tx.unique.destroyCollection(uniqueCollectionId); await expect(executeTransaction(api, alice, txDestroyCollection), 'destroying collection') @@ -206,10 +221,12 @@ }); }); -describe('Negative Integration Test: Internal Collections, External Ops', () => { +describe('Negative Integration Test: Internal Collections, External Ops', async () => { let collectionId: number; let nftId: number; + const it_rmrk = (await isUnique() ? it : it.skip); + before(async () => { await usingApi(async (api, privateKeyWrapper) => { alice = privateKeyWrapper('//Alice'); @@ -220,7 +237,7 @@ }); }); - it('[Negative] Forbids RMRK operations with the internal collection and NFT (due to the lack of mapping)', async () => { + it_rmrk('[Negative] Forbids RMRK operations with the internal collection and NFT (due to the lack of mapping)', async () => { await usingApi(async api => { const txChangeOwner = api.tx.rmrkCore.changeCollectionIssuer(collectionId, bob.address); await expect(executeTransaction(api, alice, txChangeOwner), 'changing collection issuer') -- gitstuff