difftreelog
feat(rmrk-rpc) nft resources and priorities
in: master
6 files changed
pallets/proxy-rmrk-core/src/lib.rsdiffbeforeafterboth--- a/pallets/proxy-rmrk-core/src/lib.rs
+++ b/pallets/proxy-rmrk-core/src/lib.rs
@@ -486,9 +486,8 @@
}
}
- // should this even be here, might displace it to common/nonfungible -- but they did not need it, only rmrk does
pub fn collection_exists(collection_id: CollectionId) -> bool {
- <pallet_common::CollectionById<T>>::contains_key(collection_id)
+ <CollectionHandle<T>>::try_get(collection_id).is_ok()
}
pub fn nft_exists(collection_id: CollectionId, nft_id: TokenId) -> bool {
pallets/proxy-rmrk-core/src/misc.rsdiffbeforeafterboth1use super::*;2use codec::{Encode, Decode};34#[macro_export]5macro_rules! map_common_err_to_proxy {6 (match $err:ident { $($common_err:ident => $proxy_err:ident),+ }) => {7 $(8 if $err == <CommonError<T>>::$common_err.into() {9 return <Error<T>>::$proxy_err.into()10 } else11 )+ {12 $err13 }14 };15}1617pub trait RmrkDecode<T: Decode + Default, S> {18 fn decode_or_default(&self) -> T;19}2021impl<T: Decode + Default, S> RmrkDecode<T, S> for BoundedVec<u8, S> {22 fn decode_or_default(&self) -> T {23 let mut value = self.as_slice();2425 T::decode(&mut value).unwrap_or_default()26 }27}2829pub trait RmrkRebind<T, S> {30 fn rebind(&self) -> BoundedVec<u8, S>;31}3233impl<T, S> RmrkRebind<T, S> for BoundedVec<u8, T> where BoundedVec<u8, S>: TryFrom<Vec<u8>> {34 fn rebind(&self) -> BoundedVec<u8, S> {35 BoundedVec::<u8, S>::try_from(36 self.clone().into_inner()37 ).unwrap_or_default()38 }39}4041#[derive(Encode, Decode, PartialEq, Eq)]42pub enum CollectionType {43 Regular,44 Resource,45 Base,46}4748#[derive(Encode, Decode, PartialEq, Eq)]49pub enum NftType {50 Regular,51 Resource,52 FixedPart,53 SlotPart,54 Theme55}1use super::*;2use codec::{Encode, Decode};34#[macro_export]5macro_rules! map_common_err_to_proxy {6 (match $err:ident { $($common_err:ident => $proxy_err:ident),+ }) => {7 $(8 if $err == <CommonError<T>>::$common_err.into() {9 return <Error<T>>::$proxy_err.into()10 } else11 )+ {12 $err13 }14 };15}1617pub trait RmrkDecode<T: Decode + Default, S> {18 fn decode_or_default(&self) -> T;19}2021impl<T: Decode + Default, S> RmrkDecode<T, S> for BoundedVec<u8, S> {22 fn decode_or_default(&self) -> T {23 let mut value = self.as_slice();2425 T::decode(&mut value).unwrap_or_default()26 }27}2829#[derive(Encode, Decode, PartialEq, Eq)]30pub enum CollectionType {31 Regular,32 Resource,33 Base,34}3536#[derive(Encode, Decode, PartialEq, Eq)]37pub enum NftType {38 Regular,39 Resource,40 FixedPart,41 SlotPart,42 Theme43}primitives/data-structs/src/lib.rsdiffbeforeafterboth--- a/primitives/data-structs/src/lib.rs
+++ b/primitives/data-structs/src/lib.rs
@@ -49,6 +49,7 @@
},
NftChild as RmrkNftChild, AccountIdOrCollectionNftTuple as RmrkAccountIdOrCollectionNftTuple,
FixedPart as RmrkFixedPart, SlotPart as RmrkSlotPart, EquippableList as RmrkEquippableList,
+ BasicResource as RmrkBasicResource, ComposableResource as RmrkComposableResource, SlotResource as RmrkSlotResource,
};
mod bounded;
@@ -925,17 +926,14 @@
}
}
-pub type RmrkCollectionSymbol = BoundedVec<u8, RmrkCollectionSymbolLimit>;
pub type RmrkCollectionInfo<AccountId> =
CollectionInfo<RmrkString, RmrkCollectionSymbol, AccountId>;
pub type RmrkInstanceInfo<AccountId> = NftInfo<AccountId, Permill, RmrkString>;
pub type RmrkResourceInfo = ResourceInfo<
- BoundedVec<u8, RmrkResourceSymbolLimit>,
+ RmrkBoundedResource,
RmrkString,
- BoundedVec<RmrkPartId, RmrkPartsLimit>,
+ RmrkBoundedParts,
>;
-pub type RmrkKeyString = BoundedVec<u8, RmrkKeyLimit>;
-pub type RmrkValueString = BoundedVec<u8, RmrkValueLimit>;
pub type RmrkPropertyInfo = PropertyInfo<RmrkKeyString, RmrkValueString>;
pub type RmrkBaseInfo<AccountId> = BaseInfo<AccountId, RmrkString>;
pub type RmrkPartType =
@@ -943,6 +941,13 @@
pub type RmrkThemeProperty = ThemeProperty<RmrkString>;
pub type RmrkTheme = Theme<RmrkString, Vec<RmrkThemeProperty>>;
+pub type RmrkCollectionSymbol = BoundedVec<u8, RmrkCollectionSymbolLimit>;
+pub type RmrkKeyString = BoundedVec<u8, RmrkKeyLimit>;
+pub type RmrkValueString = BoundedVec<u8, RmrkValueLimit>;
+
+type RmrkBoundedResource = BoundedVec<u8, RmrkResourceSymbolLimit>;
+type RmrkBoundedParts = BoundedVec<RmrkPartId, RmrkPartsLimit>;
+
pub type RmrkRpcString = Vec<u8>;
pub type RmrkThemeName = RmrkRpcString;
pub type RmrkPropertyKey = RmrkRpcString;
primitives/data-structs/src/rmrk.rsdiffbeforeafterboth--- a/primitives/data-structs/src/rmrk.rs
+++ b/primitives/data-structs/src/rmrk.rs
@@ -154,7 +154,7 @@
pub value: BoundedValue,
}
-#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)]
+#[derive(Encode, Decode, Default, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)]
#[cfg_attr(feature = "std", derive(Serialize))]
#[cfg_attr(
feature = "std",
@@ -275,7 +275,7 @@
pub thumb: Option<BoundedString>,
}
-#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)]
+#[derive(Encode, Decode, Derivative, Eq, PartialEq, Clone, Debug, TypeInfo, MaxEncodedLen)]
#[cfg_attr(feature = "std", derive(Serialize))]
#[cfg_attr(
feature = "std",
@@ -286,7 +286,9 @@
"#
)
)]
-pub enum ResourceTypes<BoundedString, BoundedParts> {
+#[derivative(Default(bound=""))]
+pub enum ResourceTypes<BoundedString: Default, BoundedParts> {
+ #[derivative(Default)]
Basic(BasicResource<BoundedString>),
Composable(ComposableResource<BoundedString, BoundedParts>),
Slot(SlotResource<BoundedString>),
@@ -305,7 +307,7 @@
"#
)
)]
-pub struct ResourceInfo<BoundedResource, BoundedString, BoundedParts> {
+pub struct ResourceInfo<BoundedResource, BoundedString: Default, BoundedParts> {
/// id is a 5-character string of reasonable uniqueness.
/// The combination of base ID and resource id should be unique across the entire RMRK
/// ecosystem which
runtime/common/src/runtime_apis.rsdiffbeforeafterboth--- a/runtime/common/src/runtime_apis.rs
+++ b/runtime/common/src/runtime_apis.rs
@@ -146,9 +146,7 @@
}
fn collection_by_id(collection_id: RmrkCollectionId) -> Result<Option<RmrkCollectionInfo<AccountId>>, DispatchError> {
- use frame_support::BoundedVec;
- use scale_info::prelude::string::String;
- use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, RmrkRebind, RmrkDecode}};
+ use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, RmrkDecode}};
let collection_id = CollectionId(collection_id);
let collection = match RmrkCore::get_typed_nft_collection(collection_id, CollectionType::Regular) {
@@ -156,20 +154,18 @@
Err(_) => return Ok(None),
};
- let nfts_count = (dispatch_unique_runtime!(collection_id.total_supply()) as Result<u32, DispatchError>)?;
- //<Runtime as up_rpc::UniqueApi>::total_supply(collection_id); // todo can't find UniqueApi with disabled default features
+ let nfts_count = dispatch_unique_runtime!(collection_id.total_supply())?;
Ok(Some(RmrkCollectionInfo {
issuer: collection.owner.clone(),
metadata: RmrkCore::get_collection_property(collection_id, RmrkProperty::Metadata)?.decode_or_default(),
max: collection.limits.token_limit,
- symbol: collection.token_prefix.rebind(), // change
+ symbol: collection.token_prefix.decode_or_default(),
nfts_count
}))
}
fn nft_by_id(collection_id: RmrkCollectionId, nft_by_id: RmrkNftId) -> Result<Option<RmrkInstanceInfo<AccountId>>, DispatchError> {
- use frame_support::BoundedVec;
use up_data_structs::mapping::TokenAddressMapping;
use pallet_proxy_rmrk_core::{RmrkProperty, misc::RmrkDecode};
@@ -177,7 +173,7 @@
let nft_id = TokenId(nft_by_id);
if !RmrkCore::nft_exists(collection_id, nft_id) { return Ok(None); }
- let owner = match (dispatch_unique_runtime!(collection_id.token_owner(nft_id)) as Result<Option<CrossAccountId>, DispatchError>)? {
+ let owner = match dispatch_unique_runtime!(collection_id.token_owner(nft_id))? {
Some(owner) => match <Runtime as pallet_common::Config>::CrossTokenAddressMapping::address_to_token(&owner) {
Some((col, tok)) => RmrkAccountIdOrCollectionNftTuple::CollectionAndNftTuple(col.0, tok.0),
None => RmrkAccountIdOrCollectionNftTuple::AccountId(owner.as_sub().clone())
@@ -197,16 +193,17 @@
}
fn account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Result<Vec<RmrkNftId>, DispatchError> {
+ use pallet_proxy_rmrk_core::misc::CollectionType;
+
let cross_account_id = CrossAccountId::from_sub(account_id);
let collection_id = CollectionId(collection_id);
- if !RmrkCore::collection_exists(collection_id) { return Ok(Vec::new()); }
+ if RmrkCore::ensure_collection_type(collection_id, CollectionType::Regular).is_err() { return Ok(Vec::new()); }
Ok(
- (dispatch_unique_runtime!(collection_id.account_tokens(cross_account_id)) as Result<Vec<TokenId>, DispatchError>)?
- //<Runtime as up_rpc::UniqueApi<Block, CrossAccountId, AccountId>>::account_tokens(collection_id, cross_account_id)?
+ dispatch_unique_runtime!(collection_id.account_tokens(cross_account_id))?
.into_iter()
.map(|token| token.0)
- .collect::<Vec<_>>()
+ .collect()
)
}
@@ -226,8 +223,7 @@
.map(|(child_id, _)| RmrkNftChild {
collection_id: collection_id.0, // todo make sure they're always from this collection // spoiler: they're not
nft_id: child_id.0,
- })
- .collect()
+ }).collect()
)
}
@@ -277,28 +273,70 @@
fn nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkResourceInfo>, DispatchError> {
use frame_support::BoundedVec;
- use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType}};
+ use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType, RmrkDecode}};
let collection_id = CollectionId(collection_id);
- if RmrkCore::ensure_collection_type(collection_id, CollectionType::Resource).is_err() { return Ok(Vec::new()); }
+ if !RmrkCore::collection_exists(collection_id) { return Ok(Vec::new()); } // todo make sure the collection type doesn't matter
let nft_id = TokenId(nft_id);
if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Resource).is_err() { return Ok(Vec::new()); }
- Ok(Vec::new(/*[RmrkResourceInfo {
+ let resource_collection_id: CollectionId = RmrkCore::get_nft_property(collection_id, nft_id, RmrkProperty::ResourceCollection)
+ .unwrap()
+ .decode_or_default();
+ if RmrkCore::ensure_collection_type(collection_id, CollectionType::Resource).is_err() { return Ok(Vec::new()); }
- }]*/))
+ let resources = pallet_nonfungible::TokenProperties::<Runtime>::iter_prefix((resource_collection_id,))
+ .filter_map(|(resource_id, properties)| Some(RmrkResourceInfo {
+ id: BoundedVec::default(), // todo ResourceId property
+ pending: RmrkCore::get_nft_property(resource_collection_id, resource_id, RmrkProperty::PendingResourceAccept).unwrap().decode_or_default(),
+ pending_removal: RmrkCore::get_nft_property(resource_collection_id, resource_id, RmrkProperty::PendingResourceRemoval).unwrap().decode_or_default(),
+ resource: RmrkCore::get_nft_property(resource_collection_id, resource_id, RmrkProperty::ResourceType).unwrap().decode_or_default(),/* {
+ RmrkResourceTypes::Basic(resource) => RmrkResourceTypes::Basic(),/*(RmrkBasicResource {
+ src: RmrkCore::get_nft_property_inner(properties, RmrkProperty::Src).unwrap().decode_or_default(),
+ metadata: RmrkCore::get_nft_property_inner(properties, RmrkProperty::Metadata).unwrap().decode_or_default(),
+ license: RmrkCore::get_nft_property_inner(properties, RmrkProperty::License).unwrap().decode_or_default(),
+ thumb: RmrkCore::get_nft_property_inner(properties, RmrkProperty::Thumb).unwrap().decode_or_default(),
+ },*///BasicResource<BoundedString>)
+ _ => todo!(), //RmrkResourceTypes::Composable(ComposableResource<BoundedString, BoundedParts>),
+ //RmrkResourceTypes::Slot(SlotResource<BoundedString>),
+ },*/
+ }))
+ .collect();
+
+ Ok(resources)
}
fn nft_resource_priorities(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Result<Vec<RmrkResourceId>, DispatchError> {
- todo!()
+ use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType, RmrkDecode}};
+
+ let collection_id = CollectionId(collection_id);
+ if !RmrkCore::collection_exists(collection_id) { return Ok(Vec::new()); } // todo ensure the collection type doesn't matter
+
+ let nft_id = TokenId(nft_id);
+ if RmrkCore::ensure_nft_type(collection_id, nft_id, NftType::Resource).is_err() { return Ok(Vec::new()); }
+
+ /*let resource_collection_id: CollectionId = RmrkCore::get_nft_property(collection_id, nft_id, RmrkProperty::ResourceCollection)
+ .unwrap()
+ .decode_or_default();
+ if RmrkCore::ensure_collection_type(collection_id, CollectionType::Resource).is_err() { return Ok(Vec::new()); }
+
+ let resources = pallet_nonfungible::TokenProperties::<Runtime>::iter_prefix((resource_collection_id,))
+ .filter_map(|(resource_id, properties)| Some((
+ resource_id, // ResourceId property
+ RmrkCore::get_nft_property(resource_collection_id, resource_id, RmrkProperty::Priority).unwrap().decode_or_default(),
+ )))
+ .collect()
+ .sort_by_key(|(_, index)| *index)
+ .into_iter().map(|(resource_id, _)| resource_id)*/
+ let priorities = RmrkCore::get_nft_property(collection_id, nft_id, RmrkProperty::ResourcePriorities)?.decode_or_default();
+
+ Ok(priorities)
}
fn base(base_id: RmrkBaseId) -> Result<Option<RmrkBaseInfo<AccountId>>, DispatchError> {
- use frame_support::BoundedVec;
- use scale_info::prelude::string::String;
use pallet_proxy_rmrk_core::{
- RmrkProperty, misc::{CollectionType, RmrkRebind, RmrkDecode},
+ RmrkProperty, misc::{CollectionType, RmrkDecode},
};
let collection_id = CollectionId(base_id);
@@ -310,18 +348,17 @@
Ok(Some(RmrkBaseInfo {
issuer: collection.owner.clone(),
base_type: RmrkCore::get_collection_property(collection_id, RmrkProperty::BaseType)?.decode_or_default(),
- symbol: collection.token_prefix.rebind(),
+ symbol: collection.token_prefix.decode_or_default(),
}))
}
fn base_parts(base_id: RmrkBaseId) -> Result<Vec<RmrkPartType>, DispatchError> {
- use frame_support::BoundedVec;
use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, NftType, RmrkDecode}};
let collection_id = CollectionId(base_id);
if RmrkCore::ensure_collection_type(collection_id, CollectionType::Base).is_err() { return Ok(Vec::new()); }
- let parts = (dispatch_unique_runtime!(collection_id.collection_tokens()))?
+ let parts = dispatch_unique_runtime!(collection_id.collection_tokens())?
.into_iter()
.filter_map(|token_id| {
let nft_type = RmrkCore::get_nft_type(collection_id, token_id).ok()?;
@@ -347,7 +384,6 @@
}
fn theme_names(base_id: RmrkBaseId) -> Result<Vec<RmrkThemeName>, DispatchError> {
- use frame_support::BoundedVec;
use pallet_proxy_rmrk_core::{RmrkProperty, misc::{CollectionType, RmrkDecode}};
let collection_id = CollectionId(base_id);
@@ -355,7 +391,7 @@
return Ok(Vec::new());
}
- let theme_names = (dispatch_unique_runtime!(collection_id.collection_tokens()))?
+ let theme_names = dispatch_unique_runtime!(collection_id.collection_tokens())?
.iter()
.filter_map(|token_id| {
let nft_type = RmrkCore::get_nft_type(collection_id, *token_id).unwrap();
@@ -373,7 +409,6 @@
}
fn theme(base_id: RmrkBaseId, theme_name: RmrkThemeName, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Result<Option<RmrkTheme>, DispatchError> {
- use frame_support::BoundedVec;
use pallet_proxy_rmrk_core::{
RmrkProperty,
misc::{CollectionType, NftType, RmrkDecode}
@@ -384,7 +419,7 @@
return Ok(None);
}
- let theme_info = (dispatch_unique_runtime!(collection_id.collection_tokens()))?
+ let theme_info = dispatch_unique_runtime!(collection_id.collection_tokens())?
.into_iter()
.find_map(|token_id| {
RmrkCore::ensure_nft_type(collection_id, token_id, NftType::Theme).ok()?;
tests/src/nesting/properties.test.tsdiffbeforeafterboth--- a/tests/src/nesting/properties.test.ts
+++ b/tests/src/nesting/properties.test.ts
@@ -711,7 +711,7 @@
});
});
- it('Forbids changing/deleting properties of a token if the property is permanent (constant)', async () => {
+ it('Forbids changing/deleting properties of a token if the property is permanent (immutable)', async () => {
await usingApi(async api => {
let i = -1;
for (const permission of constitution) {