--- a/client/rpc/src/lib.rs +++ b/client/rpc/src/lib.rs @@ -21,7 +21,7 @@ use jsonrpc_derive::rpc; use up_data_structs::{ RpcCollection, CollectionId, CollectionStats, CollectionLimits, TokenId, Property, - PropertyKeyPermission, + PropertyKeyPermission, TokenData, }; use sp_api::{BlockId, BlockT, ProvideRuntimeApi, ApiExt}; use sp_blockchain::HeaderBackend; @@ -104,6 +104,15 @@ at: Option, ) -> Result>; + #[rpc(name = "unique_tokenData")] + fn token_data( + &self, + collection: CollectionId, + token_id: TokenId, + keys: Vec, + at: Option, + ) -> Result>; + #[rpc(name = "unique_totalSupply")] fn total_supply(&self, collection: CollectionId, at: Option) -> Result; #[rpc(name = "unique_accountBalance")] @@ -294,6 +303,14 @@ keys: Vec ) -> Vec); + pass_method!(token_data( + collection: CollectionId, + token_id: TokenId, + + #[map(|keys| string_keys_to_bytes_keys(keys))] + keys: Vec, + ) -> TokenData); + pass_method!(total_supply(collection: CollectionId) -> u32); pass_method!(account_balance(collection: CollectionId, account: CrossAccountId) -> u32); pass_method!(balance(collection: CollectionId, account: CrossAccountId, token: TokenId) -> String => |v| v.to_string()); --- a/pallets/common/src/lib.rs +++ b/pallets/common/src/lib.rs @@ -36,7 +36,7 @@ CUSTOM_DATA_LIMIT, CollectionLimits, CustomDataLimit, CreateCollectionData, SponsorshipState, CreateItemExData, SponsoringRateLimit, budget::Budget, COLLECTION_FIELD_LIMIT, CollectionField, PhantomType, Property, Properties, PropertiesPermissionMap, PropertyKey, PropertyPermission, - PropertiesError, PropertyKeyPermission, + PropertiesError, PropertyKeyPermission, TokenData, }; pub use pallet::*; use sp_core::H160; @@ -454,6 +454,7 @@ CollectionStats, CollectionId, TokenId, + PhantomType>, PhantomType>, ), QueryKind = OptionQuery, @@ -843,6 +844,57 @@ Ok(()) } + pub fn bytes_keys_to_property_keys(keys: Vec>) -> Result, DispatchError> { + keys.into_iter() + .map(|key| -> Result { + // TODO Fix error + key.try_into().map_err(|_| DispatchError::Other("Can't read property key")) + }) + .collect::, DispatchError>>() + } + + pub fn filter_collection_properties( + collection_id: CollectionId, + keys: Vec + ) -> Result, DispatchError> { + let properties = Self::collection_properties(collection_id); + + let properties = keys.into_iter() + .filter_map(|key| { + properties.get_property(&key) + .map(|value| { + Property { + key, + value: value.clone() + } + }) + }) + .collect(); + + Ok(properties) + } + + pub fn filter_property_permissions( + collection_id: CollectionId, + keys: Vec + ) -> Result, DispatchError> { + let permissions = Self::property_permissions(collection_id); + + let key_permissions = keys.into_iter() + .filter_map(|key| { + permissions.get(&key) + .map(|permission| { + PropertyKeyPermission { + key, + permission: permission.clone() + } + }) + }) + .collect(); + + Ok(key_permissions) + } + fn set_field_raw( collection_id: CollectionId, field: CollectionField, @@ -1117,7 +1169,11 @@ fn token_owner(&self, token: TokenId) -> Option; fn const_metadata(&self, token: TokenId) -> Vec; fn variable_metadata(&self, token: TokenId) -> Vec; - + fn token_properties( + &self, + token_id: TokenId, + keys: Vec + ) -> Vec; /// Amount of unique collection tokens fn total_supply(&self) -> u32; /// Amount of different tokens account has (Applicable to nonfungible/refungible) --- a/pallets/fungible/src/common.rs +++ b/pallets/fungible/src/common.rs @@ -250,7 +250,7 @@ _sender: T::CrossAccountId, _property: Vec, ) -> DispatchResultWithPostInfo { - fail!(>::PropertiesNotAllowed) + fail!(>::SettingPropertiesNotAllowed) } fn delete_collection_properties( @@ -258,7 +258,7 @@ _sender: &T::CrossAccountId, _property_keys: Vec, ) -> DispatchResultWithPostInfo { - fail!(>::PropertiesNotAllowed) + fail!(>::SettingPropertiesNotAllowed) } fn set_token_properties( @@ -267,7 +267,7 @@ _token_id: TokenId, _property: Vec, ) -> DispatchResultWithPostInfo { - fail!(>::PropertiesNotAllowed) + fail!(>::SettingPropertiesNotAllowed) } fn set_property_permissions( @@ -275,7 +275,7 @@ _sender: &T::CrossAccountId, _property_permissions: Vec, ) -> DispatchResultWithPostInfo { - fail!(>::PropertiesNotAllowed) + fail!(>::SettingPropertiesNotAllowed) } fn delete_token_properties( @@ -284,7 +284,7 @@ _token_id: TokenId, _property_keys: Vec, ) -> DispatchResultWithPostInfo { - fail!(>::PropertiesNotAllowed) + fail!(>::SettingPropertiesNotAllowed) } fn set_variable_metadata( @@ -336,6 +336,14 @@ Vec::new() } + fn token_properties( + &self, + _token_id: TokenId, + _keys: Vec + ) -> Vec { + Vec::new() + } + fn total_supply(&self) -> u32 { 1 } --- a/pallets/fungible/src/lib.rs +++ b/pallets/fungible/src/lib.rs @@ -61,8 +61,8 @@ FungibleItemsDontHaveData, /// Fungible token does not support nested FungibleDisallowsNesting, - /// Item properties are not allowed - PropertiesNotAllowed, + /// Setting item properties is not allowed + SettingPropertiesNotAllowed, } #[pallet::config] --- a/pallets/nonfungible/src/common.rs +++ b/pallets/nonfungible/src/common.rs @@ -386,6 +386,26 @@ .into_inner() } + fn token_properties( + &self, + token_id: TokenId, + keys: Vec + ) -> Vec { + let properties = >::token_properties((self.id, token_id)); + + keys.into_iter() + .filter_map(|key| { + properties.get_property(&key) + .map(|value| { + Property { + key, + value: value.clone() + } + }) + }) + .collect() + } + fn total_supply(&self) -> u32 { >::total_supply(self) } --- a/pallets/refungible/src/common.rs +++ b/pallets/refungible/src/common.rs @@ -269,7 +269,7 @@ _sender: T::CrossAccountId, _property: Vec, ) -> DispatchResultWithPostInfo { - fail!(>::PropertiesNotAllowed) + fail!(>::SettingPropertiesNotAllowed) } fn delete_collection_properties( @@ -277,7 +277,7 @@ _sender: &T::CrossAccountId, _property_keys: Vec, ) -> DispatchResultWithPostInfo { - fail!(>::PropertiesNotAllowed) + fail!(>::SettingPropertiesNotAllowed) } fn set_token_properties( @@ -286,7 +286,7 @@ _token_id: TokenId, _property: Vec, ) -> DispatchResultWithPostInfo { - fail!(>::PropertiesNotAllowed) + fail!(>::SettingPropertiesNotAllowed) } fn set_property_permissions( @@ -294,7 +294,7 @@ _sender: &T::CrossAccountId, _property_permissions: Vec, ) -> DispatchResultWithPostInfo { - fail!(>::PropertiesNotAllowed) + fail!(>::SettingPropertiesNotAllowed) } fn delete_token_properties( @@ -303,7 +303,7 @@ _token_id: TokenId, _property_keys: Vec, ) -> DispatchResultWithPostInfo { - fail!(>::PropertiesNotAllowed) + fail!(>::SettingPropertiesNotAllowed) } fn set_variable_metadata( @@ -363,6 +363,14 @@ .into_inner() } + fn token_properties( + &self, + _token_id: TokenId, + _keys: Vec + ) -> Vec { + Vec::new() + } + fn total_supply(&self) -> u32 { >::total_supply(self) } --- a/pallets/refungible/src/lib.rs +++ b/pallets/refungible/src/lib.rs @@ -62,8 +62,8 @@ WrongRefungiblePieces, /// Refungible token can't nest other tokens RefungibleDisallowsNesting, - /// Item properties are not allowed - PropertiesNotAllowed, + /// Setting item properties is not allowed + SettingPropertiesNotAllowed, } #[pallet::config] --- a/primitives/data-structs/src/lib.rs +++ b/primitives/data-structs/src/lib.rs @@ -173,6 +173,14 @@ } } +#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +pub struct TokenData { + pub const_data: Vec, + pub properties: Vec, + pub owner: Option, +} + pub struct OverflowError; impl From for &'static str { fn from(_: OverflowError) -> Self { --- a/primitives/rpc/src/lib.rs +++ b/primitives/rpc/src/lib.rs @@ -18,7 +18,7 @@ use up_data_structs::{ CollectionId, TokenId, RpcCollection, CollectionStats, CollectionLimits, Property, - PropertyKeyPermission, + PropertyKeyPermission, TokenData, }; use sp_std::vec::Vec; use codec::Decode; @@ -57,6 +57,8 @@ properties: Vec> ) -> Result>; + fn token_data(collection: CollectionId, token_id: TokenId, keys: Vec>) -> Result>; + fn total_supply(collection: CollectionId) -> Result; fn account_balance(collection: CollectionId, account: CrossAccountId) -> Result; fn balance(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Result; --- a/runtime/common/src/runtime_apis.rs +++ b/runtime/common/src/runtime_apis.rs @@ -7,14 +7,6 @@ $($custom_apis:tt)+ )? ) => { - fn bytes_keys_to_property_keys(keys: Vec>) -> Result, DispatchError> { - keys.into_iter() - .map(|key| -> Result { - key.try_into().map_err(|_| DispatchError::Other("Can't read property key")) - }) - .collect::, DispatchError>>() - } - impl_runtime_apis! { $($($custom_apis)+)? @@ -48,23 +40,9 @@ collection: CollectionId, keys: Vec> ) -> Result, DispatchError> { - let keys = bytes_keys_to_property_keys(keys)?; - - let properties = pallet_common::Pallet::::collection_properties(collection); - - let properties = keys.into_iter() - .filter_map(|key| { - properties.get_property(&key) - .map(|value| { - Property { - key, - value: value.clone() - } - }) - }) - .collect(); + let keys = pallet_common::Pallet::::bytes_keys_to_property_keys(keys)?; - Ok(properties) + pallet_common::Pallet::::filter_collection_properties(collection, keys) } fn token_properties( @@ -72,46 +50,31 @@ token_id: TokenId, keys: Vec> ) -> Result, DispatchError> { - let keys = bytes_keys_to_property_keys(keys)?; - - let properties = pallet_nonfungible::Pallet::::token_properties((collection, token_id)); - - let properties = keys.into_iter() - .filter_map(|key| { - properties.get_property(&key) - .map(|value| { - Property { - key, - value: value.clone() - } - }) - }) - .collect(); - - Ok(properties) + let keys = pallet_common::Pallet::::bytes_keys_to_property_keys(keys)?; + dispatch_unique_runtime!(collection.token_properties(token_id, keys)) } fn property_permissions( collection: CollectionId, keys: Vec> ) -> Result, DispatchError> { - let keys = bytes_keys_to_property_keys(keys)?; + let keys = pallet_common::Pallet::::bytes_keys_to_property_keys(keys)?; - let permissions = pallet_common::Pallet::::property_permissions(collection); + pallet_common::Pallet::::filter_property_permissions(collection, keys) + } - let key_permissions = keys.into_iter() - .filter_map(|key| { - permissions.get(&key) - .map(|permission| { - PropertyKeyPermission { - key, - permission: permission.clone() - } - }) - }) - .collect(); + fn token_data( + collection: CollectionId, + token_id: TokenId, + keys: Vec> + ) -> Result, DispatchError> { + let token_data = TokenData { + const_data: Self::const_metadata(collection, token_id)?, + properties: Self::token_properties(collection, token_id, keys)?, + owner: Self::token_owner(collection, token_id)? + }; - Ok(key_permissions) + Ok(token_data) } fn total_supply(collection: CollectionId) -> Result {