difftreelog
Add token_data RPC
in: master
10 files changed
client/rpc/src/lib.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617use std::sync::Arc;1819use codec::Decode;20use jsonrpc_core::{Error as RpcError, ErrorCode, Result};21use jsonrpc_derive::rpc;22use up_data_structs::{23 RpcCollection, CollectionId, CollectionStats, CollectionLimits, TokenId, Property,24 PropertyKeyPermission,25};26use sp_api::{BlockId, BlockT, ProvideRuntimeApi, ApiExt};27use sp_blockchain::HeaderBackend;28use up_rpc::UniqueApi as UniqueRuntimeApi;2930#[rpc]31pub trait UniqueApi<BlockHash, CrossAccountId, AccountId> {32 #[rpc(name = "unique_accountTokens")]33 fn account_tokens(34 &self,35 collection: CollectionId,36 account: CrossAccountId,37 at: Option<BlockHash>,38 ) -> Result<Vec<TokenId>>;39 #[rpc(name = "unique_collectionTokens")]40 fn collection_tokens(41 &self,42 collection: CollectionId,43 at: Option<BlockHash>,44 ) -> Result<Vec<TokenId>>;45 #[rpc(name = "unique_tokenExists")]46 fn token_exists(47 &self,48 collection: CollectionId,49 token: TokenId,50 at: Option<BlockHash>,51 ) -> Result<bool>;5253 #[rpc(name = "unique_tokenOwner")]54 fn token_owner(55 &self,56 collection: CollectionId,57 token: TokenId,58 at: Option<BlockHash>,59 ) -> Result<Option<CrossAccountId>>;60 #[rpc(name = "unique_topmostTokenOwner")]61 fn topmost_token_owner(62 &self,63 collection: CollectionId,64 token: TokenId,65 at: Option<BlockHash>,66 ) -> Result<Option<CrossAccountId>>;67 #[rpc(name = "unique_constMetadata")]68 fn const_metadata(69 &self,70 collection: CollectionId,71 token: TokenId,72 at: Option<BlockHash>,73 ) -> Result<Vec<u8>>;74 #[rpc(name = "unique_variableMetadata")]75 fn variable_metadata(76 &self,77 collection: CollectionId,78 token: TokenId,79 at: Option<BlockHash>,80 ) -> Result<Vec<u8>>;8182 #[rpc(name = "unique_collectionProperties")]83 fn collection_properties(84 &self,85 collection: CollectionId,86 keys: Vec<String>,87 at: Option<BlockHash>,88 ) -> Result<Vec<Property>>;8990 #[rpc(name = "unique_tokenProperties")]91 fn token_properties(92 &self,93 collection: CollectionId,94 token_id: TokenId,95 properties: Vec<String>,96 at: Option<BlockHash>,97 ) -> Result<Vec<Property>>;9899 #[rpc(name = "unique_propertyPermissions")]100 fn property_permissions(101 &self,102 collection: CollectionId,103 keys: Vec<String>,104 at: Option<BlockHash>,105 ) -> Result<Vec<PropertyKeyPermission>>;106107 #[rpc(name = "unique_totalSupply")]108 fn total_supply(&self, collection: CollectionId, at: Option<BlockHash>) -> Result<u32>;109 #[rpc(name = "unique_accountBalance")]110 fn account_balance(111 &self,112 collection: CollectionId,113 account: CrossAccountId,114 at: Option<BlockHash>,115 ) -> Result<u32>;116 #[rpc(name = "unique_balance")]117 fn balance(118 &self,119 collection: CollectionId,120 account: CrossAccountId,121 token: TokenId,122 at: Option<BlockHash>,123 ) -> Result<String>;124 #[rpc(name = "unique_allowance")]125 fn allowance(126 &self,127 collection: CollectionId,128 sender: CrossAccountId,129 spender: CrossAccountId,130 token: TokenId,131 at: Option<BlockHash>,132 ) -> Result<String>;133134 #[rpc(name = "unique_adminlist")]135 fn adminlist(136 &self,137 collection: CollectionId,138 at: Option<BlockHash>,139 ) -> Result<Vec<CrossAccountId>>;140 #[rpc(name = "unique_allowlist")]141 fn allowlist(142 &self,143 collection: CollectionId,144 at: Option<BlockHash>,145 ) -> Result<Vec<CrossAccountId>>;146 #[rpc(name = "unique_allowed")]147 fn allowed(148 &self,149 collection: CollectionId,150 user: CrossAccountId,151 at: Option<BlockHash>,152 ) -> Result<bool>;153 #[rpc(name = "unique_lastTokenId")]154 fn last_token_id(&self, collection: CollectionId, at: Option<BlockHash>) -> Result<TokenId>;155 #[rpc(name = "unique_collectionById")]156 fn collection_by_id(157 &self,158 collection: CollectionId,159 at: Option<BlockHash>,160 ) -> Result<Option<RpcCollection<AccountId>>>;161 #[rpc(name = "unique_collectionStats")]162 fn collection_stats(&self, at: Option<BlockHash>) -> Result<CollectionStats>;163164 #[rpc(name = "unique_nextSponsored")]165 fn next_sponsored(166 &self,167 collection: CollectionId,168 account: CrossAccountId,169 token: TokenId,170 at: Option<BlockHash>,171 ) -> Result<Option<u64>>;172 #[rpc(name = "unique_effectiveCollectionLimits")]173 fn effective_collection_limits(174 &self,175 collection_id: CollectionId,176 at: Option<BlockHash>,177 ) -> Result<Option<CollectionLimits>>;178}179180pub struct Unique<C, P> {181 client: Arc<C>,182 _marker: std::marker::PhantomData<P>,183}184185impl<C, P> Unique<C, P> {186 pub fn new(client: Arc<C>) -> Self {187 Self {188 client,189 _marker: Default::default(),190 }191 }192}193194pub enum Error {195 RuntimeError,196}197198impl From<Error> for i64 {199 fn from(e: Error) -> i64 {200 match e {201 Error::RuntimeError => 1,202 }203 }204}205206macro_rules! pass_method {207 (208 $method_name:ident(209 $($(#[map(|$map_arg:ident| $map:expr)])? $name:ident: $ty:ty),* $(,)?210 ) -> $result:ty $(=> $mapper:expr)?211 $(; changed_in $ver:expr, $changed_method_name:ident ($($changed_name:expr), * $(,)?) => $fixer:expr)*212 ) => {213 fn $method_name(214 &self,215 $(216 $name: $ty,217 )*218 at: Option<<Block as BlockT>::Hash>,219 ) -> Result<$result> {220 let api = self.client.runtime_api();221 let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash));222 let _api_version = if let Ok(Some(api_version)) =223 api.api_version::<dyn UniqueRuntimeApi<Block, CrossAccountId, AccountId>>(&at)224 {225 api_version226 } else {227 // unreachable for our runtime228 return Err(RpcError {229 code: ErrorCode::InvalidParams,230 message: "Api is not available".into(),231 data: None,232 })233 };234235 let result = $(if _api_version < $ver {236 api.$changed_method_name(&at, $($changed_name),*).map(|r| r.map($fixer))237 } else)*238 { api.$method_name(&at, $($((|$map_arg: $ty| $map))? ($name)),*) };239240 let result = result.map_err(|e| RpcError {241 code: ErrorCode::ServerError(Error::RuntimeError.into()),242 message: "Unable to query".into(),243 data: Some(format!("{:?}", e).into()),244 })?;245 result.map_err(|e| RpcError {246 code: ErrorCode::InvalidParams,247 message: "Runtime returned error".into(),248 data: Some(format!("{:?}", e).into()),249 })$(.map($mapper))?250 }251 };252}253254#[allow(deprecated)]255impl<C, Block, CrossAccountId, AccountId>256 UniqueApi<<Block as BlockT>::Hash, CrossAccountId, AccountId> for Unique<C, Block>257where258 Block: BlockT,259 AccountId: Decode,260 C: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,261 C::Api: UniqueRuntimeApi<Block, CrossAccountId, AccountId>,262 CrossAccountId: pallet_evm::account::CrossAccountId<AccountId>,263{264 pass_method!(account_tokens(collection: CollectionId, account: CrossAccountId) -> Vec<TokenId>);265 pass_method!(collection_tokens(collection: CollectionId) -> Vec<TokenId>);266 pass_method!(token_exists(collection: CollectionId, token: TokenId) -> bool);267 pass_method!(268 token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>;269 changed_in 2, token_owner_before_version_2(collection, token) => |u| Some(u)270 );271 pass_method!(topmost_token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>);272 pass_method!(const_metadata(collection: CollectionId, token: TokenId) -> Vec<u8>);273 pass_method!(variable_metadata(collection: CollectionId, token: TokenId) -> Vec<u8>);274275 pass_method!(collection_properties(276 collection: CollectionId,277278 #[map(|keys| string_keys_to_bytes_keys(keys))]279 keys: Vec<String>280 ) -> Vec<Property>);281282 pass_method!(token_properties(283 collection: CollectionId,284 token_id: TokenId,285286 #[map(|keys| string_keys_to_bytes_keys(keys))]287 properties: Vec<String>288 ) -> Vec<Property>);289290 pass_method!(property_permissions(291 collection: CollectionId,292293 #[map(|keys| string_keys_to_bytes_keys(keys))]294 keys: Vec<String>295 ) -> Vec<PropertyKeyPermission>);296297 pass_method!(total_supply(collection: CollectionId) -> u32);298 pass_method!(account_balance(collection: CollectionId, account: CrossAccountId) -> u32);299 pass_method!(balance(collection: CollectionId, account: CrossAccountId, token: TokenId) -> String => |v| v.to_string());300 pass_method!(allowance(collection: CollectionId, sender: CrossAccountId, spender: CrossAccountId, token: TokenId) -> String => |v| v.to_string());301302 pass_method!(adminlist(collection: CollectionId) -> Vec<CrossAccountId>);303 pass_method!(allowlist(collection: CollectionId) -> Vec<CrossAccountId>);304 pass_method!(allowed(collection: CollectionId, user: CrossAccountId) -> bool);305 pass_method!(last_token_id(collection: CollectionId) -> TokenId);306 pass_method!(collection_by_id(collection: CollectionId) -> Option<RpcCollection<AccountId>>);307 pass_method!(collection_stats() -> CollectionStats);308 pass_method!(next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Option<u64>);309 pass_method!(effective_collection_limits(collection_id: CollectionId) -> Option<CollectionLimits>);310}311312fn string_keys_to_bytes_keys(keys: Vec<String>) -> Vec<Vec<u8>> {313 keys.into_iter().map(|key| key.into_bytes()).collect()314}1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617use std::sync::Arc;1819use codec::Decode;20use jsonrpc_core::{Error as RpcError, ErrorCode, Result};21use jsonrpc_derive::rpc;22use up_data_structs::{23 RpcCollection, CollectionId, CollectionStats, CollectionLimits, TokenId, Property,24 PropertyKeyPermission, TokenData,25};26use sp_api::{BlockId, BlockT, ProvideRuntimeApi, ApiExt};27use sp_blockchain::HeaderBackend;28use up_rpc::UniqueApi as UniqueRuntimeApi;2930#[rpc]31pub trait UniqueApi<BlockHash, CrossAccountId, AccountId> {32 #[rpc(name = "unique_accountTokens")]33 fn account_tokens(34 &self,35 collection: CollectionId,36 account: CrossAccountId,37 at: Option<BlockHash>,38 ) -> Result<Vec<TokenId>>;39 #[rpc(name = "unique_collectionTokens")]40 fn collection_tokens(41 &self,42 collection: CollectionId,43 at: Option<BlockHash>,44 ) -> Result<Vec<TokenId>>;45 #[rpc(name = "unique_tokenExists")]46 fn token_exists(47 &self,48 collection: CollectionId,49 token: TokenId,50 at: Option<BlockHash>,51 ) -> Result<bool>;5253 #[rpc(name = "unique_tokenOwner")]54 fn token_owner(55 &self,56 collection: CollectionId,57 token: TokenId,58 at: Option<BlockHash>,59 ) -> Result<Option<CrossAccountId>>;60 #[rpc(name = "unique_topmostTokenOwner")]61 fn topmost_token_owner(62 &self,63 collection: CollectionId,64 token: TokenId,65 at: Option<BlockHash>,66 ) -> Result<Option<CrossAccountId>>;67 #[rpc(name = "unique_constMetadata")]68 fn const_metadata(69 &self,70 collection: CollectionId,71 token: TokenId,72 at: Option<BlockHash>,73 ) -> Result<Vec<u8>>;74 #[rpc(name = "unique_variableMetadata")]75 fn variable_metadata(76 &self,77 collection: CollectionId,78 token: TokenId,79 at: Option<BlockHash>,80 ) -> Result<Vec<u8>>;8182 #[rpc(name = "unique_collectionProperties")]83 fn collection_properties(84 &self,85 collection: CollectionId,86 keys: Vec<String>,87 at: Option<BlockHash>,88 ) -> Result<Vec<Property>>;8990 #[rpc(name = "unique_tokenProperties")]91 fn token_properties(92 &self,93 collection: CollectionId,94 token_id: TokenId,95 properties: Vec<String>,96 at: Option<BlockHash>,97 ) -> Result<Vec<Property>>;9899 #[rpc(name = "unique_propertyPermissions")]100 fn property_permissions(101 &self,102 collection: CollectionId,103 keys: Vec<String>,104 at: Option<BlockHash>,105 ) -> Result<Vec<PropertyKeyPermission>>;106107 #[rpc(name = "unique_tokenData")]108 fn token_data(109 &self,110 collection: CollectionId,111 token_id: TokenId,112 keys: Vec<String>,113 at: Option<BlockHash>,114 ) -> Result<TokenData<CrossAccountId>>;115116 #[rpc(name = "unique_totalSupply")]117 fn total_supply(&self, collection: CollectionId, at: Option<BlockHash>) -> Result<u32>;118 #[rpc(name = "unique_accountBalance")]119 fn account_balance(120 &self,121 collection: CollectionId,122 account: CrossAccountId,123 at: Option<BlockHash>,124 ) -> Result<u32>;125 #[rpc(name = "unique_balance")]126 fn balance(127 &self,128 collection: CollectionId,129 account: CrossAccountId,130 token: TokenId,131 at: Option<BlockHash>,132 ) -> Result<String>;133 #[rpc(name = "unique_allowance")]134 fn allowance(135 &self,136 collection: CollectionId,137 sender: CrossAccountId,138 spender: CrossAccountId,139 token: TokenId,140 at: Option<BlockHash>,141 ) -> Result<String>;142143 #[rpc(name = "unique_adminlist")]144 fn adminlist(145 &self,146 collection: CollectionId,147 at: Option<BlockHash>,148 ) -> Result<Vec<CrossAccountId>>;149 #[rpc(name = "unique_allowlist")]150 fn allowlist(151 &self,152 collection: CollectionId,153 at: Option<BlockHash>,154 ) -> Result<Vec<CrossAccountId>>;155 #[rpc(name = "unique_allowed")]156 fn allowed(157 &self,158 collection: CollectionId,159 user: CrossAccountId,160 at: Option<BlockHash>,161 ) -> Result<bool>;162 #[rpc(name = "unique_lastTokenId")]163 fn last_token_id(&self, collection: CollectionId, at: Option<BlockHash>) -> Result<TokenId>;164 #[rpc(name = "unique_collectionById")]165 fn collection_by_id(166 &self,167 collection: CollectionId,168 at: Option<BlockHash>,169 ) -> Result<Option<RpcCollection<AccountId>>>;170 #[rpc(name = "unique_collectionStats")]171 fn collection_stats(&self, at: Option<BlockHash>) -> Result<CollectionStats>;172173 #[rpc(name = "unique_nextSponsored")]174 fn next_sponsored(175 &self,176 collection: CollectionId,177 account: CrossAccountId,178 token: TokenId,179 at: Option<BlockHash>,180 ) -> Result<Option<u64>>;181 #[rpc(name = "unique_effectiveCollectionLimits")]182 fn effective_collection_limits(183 &self,184 collection_id: CollectionId,185 at: Option<BlockHash>,186 ) -> Result<Option<CollectionLimits>>;187}188189pub struct Unique<C, P> {190 client: Arc<C>,191 _marker: std::marker::PhantomData<P>,192}193194impl<C, P> Unique<C, P> {195 pub fn new(client: Arc<C>) -> Self {196 Self {197 client,198 _marker: Default::default(),199 }200 }201}202203pub enum Error {204 RuntimeError,205}206207impl From<Error> for i64 {208 fn from(e: Error) -> i64 {209 match e {210 Error::RuntimeError => 1,211 }212 }213}214215macro_rules! pass_method {216 (217 $method_name:ident(218 $($(#[map(|$map_arg:ident| $map:expr)])? $name:ident: $ty:ty),* $(,)?219 ) -> $result:ty $(=> $mapper:expr)?220 $(; changed_in $ver:expr, $changed_method_name:ident ($($changed_name:expr), * $(,)?) => $fixer:expr)*221 ) => {222 fn $method_name(223 &self,224 $(225 $name: $ty,226 )*227 at: Option<<Block as BlockT>::Hash>,228 ) -> Result<$result> {229 let api = self.client.runtime_api();230 let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash));231 let _api_version = if let Ok(Some(api_version)) =232 api.api_version::<dyn UniqueRuntimeApi<Block, CrossAccountId, AccountId>>(&at)233 {234 api_version235 } else {236 // unreachable for our runtime237 return Err(RpcError {238 code: ErrorCode::InvalidParams,239 message: "Api is not available".into(),240 data: None,241 })242 };243244 let result = $(if _api_version < $ver {245 api.$changed_method_name(&at, $($changed_name),*).map(|r| r.map($fixer))246 } else)*247 { api.$method_name(&at, $($((|$map_arg: $ty| $map))? ($name)),*) };248249 let result = result.map_err(|e| RpcError {250 code: ErrorCode::ServerError(Error::RuntimeError.into()),251 message: "Unable to query".into(),252 data: Some(format!("{:?}", e).into()),253 })?;254 result.map_err(|e| RpcError {255 code: ErrorCode::InvalidParams,256 message: "Runtime returned error".into(),257 data: Some(format!("{:?}", e).into()),258 })$(.map($mapper))?259 }260 };261}262263#[allow(deprecated)]264impl<C, Block, CrossAccountId, AccountId>265 UniqueApi<<Block as BlockT>::Hash, CrossAccountId, AccountId> for Unique<C, Block>266where267 Block: BlockT,268 AccountId: Decode,269 C: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,270 C::Api: UniqueRuntimeApi<Block, CrossAccountId, AccountId>,271 CrossAccountId: pallet_evm::account::CrossAccountId<AccountId>,272{273 pass_method!(account_tokens(collection: CollectionId, account: CrossAccountId) -> Vec<TokenId>);274 pass_method!(collection_tokens(collection: CollectionId) -> Vec<TokenId>);275 pass_method!(token_exists(collection: CollectionId, token: TokenId) -> bool);276 pass_method!(277 token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>;278 changed_in 2, token_owner_before_version_2(collection, token) => |u| Some(u)279 );280 pass_method!(topmost_token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>);281 pass_method!(const_metadata(collection: CollectionId, token: TokenId) -> Vec<u8>);282 pass_method!(variable_metadata(collection: CollectionId, token: TokenId) -> Vec<u8>);283284 pass_method!(collection_properties(285 collection: CollectionId,286287 #[map(|keys| string_keys_to_bytes_keys(keys))]288 keys: Vec<String>289 ) -> Vec<Property>);290291 pass_method!(token_properties(292 collection: CollectionId,293 token_id: TokenId,294295 #[map(|keys| string_keys_to_bytes_keys(keys))]296 properties: Vec<String>297 ) -> Vec<Property>);298299 pass_method!(property_permissions(300 collection: CollectionId,301302 #[map(|keys| string_keys_to_bytes_keys(keys))]303 keys: Vec<String>304 ) -> Vec<PropertyKeyPermission>);305306 pass_method!(token_data(307 collection: CollectionId,308 token_id: TokenId,309310 #[map(|keys| string_keys_to_bytes_keys(keys))]311 keys: Vec<String>,312 ) -> TokenData<CrossAccountId>);313314 pass_method!(total_supply(collection: CollectionId) -> u32);315 pass_method!(account_balance(collection: CollectionId, account: CrossAccountId) -> u32);316 pass_method!(balance(collection: CollectionId, account: CrossAccountId, token: TokenId) -> String => |v| v.to_string());317 pass_method!(allowance(collection: CollectionId, sender: CrossAccountId, spender: CrossAccountId, token: TokenId) -> String => |v| v.to_string());318319 pass_method!(adminlist(collection: CollectionId) -> Vec<CrossAccountId>);320 pass_method!(allowlist(collection: CollectionId) -> Vec<CrossAccountId>);321 pass_method!(allowed(collection: CollectionId, user: CrossAccountId) -> bool);322 pass_method!(last_token_id(collection: CollectionId) -> TokenId);323 pass_method!(collection_by_id(collection: CollectionId) -> Option<RpcCollection<AccountId>>);324 pass_method!(collection_stats() -> CollectionStats);325 pass_method!(next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Option<u64>);326 pass_method!(effective_collection_limits(collection_id: CollectionId) -> Option<CollectionLimits>);327}328329fn string_keys_to_bytes_keys(keys: Vec<String>) -> Vec<Vec<u8>> {330 keys.into_iter().map(|key| key.into_bytes()).collect()331}pallets/common/src/lib.rsdiffbeforeafterboth--- 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<TokenData<T::CrossAccountId>>,
PhantomType<RpcCollection<T::AccountId>>,
),
QueryKind = OptionQuery,
@@ -843,6 +844,57 @@
Ok(())
}
+ pub fn bytes_keys_to_property_keys(keys: Vec<Vec<u8>>) -> Result<Vec<PropertyKey>, DispatchError> {
+ keys.into_iter()
+ .map(|key| -> Result<PropertyKey, DispatchError> {
+ // TODO Fix error
+ key.try_into().map_err(|_| DispatchError::Other("Can't read property key"))
+ })
+ .collect::<Result<Vec<PropertyKey>, DispatchError>>()
+ }
+
+ pub fn filter_collection_properties(
+ collection_id: CollectionId,
+ keys: Vec<PropertyKey>
+ ) -> Result<Vec<Property>, 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<PropertyKey>
+ ) -> Result<Vec<PropertyKeyPermission>, 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<T::CrossAccountId>;
fn const_metadata(&self, token: TokenId) -> Vec<u8>;
fn variable_metadata(&self, token: TokenId) -> Vec<u8>;
-
+ fn token_properties(
+ &self,
+ token_id: TokenId,
+ keys: Vec<PropertyKey>
+ ) -> Vec<Property>;
/// Amount of unique collection tokens
fn total_supply(&self) -> u32;
/// Amount of different tokens account has (Applicable to nonfungible/refungible)
pallets/fungible/src/common.rsdiffbeforeafterboth--- a/pallets/fungible/src/common.rs
+++ b/pallets/fungible/src/common.rs
@@ -250,7 +250,7 @@
_sender: T::CrossAccountId,
_property: Vec<Property>,
) -> DispatchResultWithPostInfo {
- fail!(<Error<T>>::PropertiesNotAllowed)
+ fail!(<Error<T>>::SettingPropertiesNotAllowed)
}
fn delete_collection_properties(
@@ -258,7 +258,7 @@
_sender: &T::CrossAccountId,
_property_keys: Vec<PropertyKey>,
) -> DispatchResultWithPostInfo {
- fail!(<Error<T>>::PropertiesNotAllowed)
+ fail!(<Error<T>>::SettingPropertiesNotAllowed)
}
fn set_token_properties(
@@ -267,7 +267,7 @@
_token_id: TokenId,
_property: Vec<Property>,
) -> DispatchResultWithPostInfo {
- fail!(<Error<T>>::PropertiesNotAllowed)
+ fail!(<Error<T>>::SettingPropertiesNotAllowed)
}
fn set_property_permissions(
@@ -275,7 +275,7 @@
_sender: &T::CrossAccountId,
_property_permissions: Vec<PropertyKeyPermission>,
) -> DispatchResultWithPostInfo {
- fail!(<Error<T>>::PropertiesNotAllowed)
+ fail!(<Error<T>>::SettingPropertiesNotAllowed)
}
fn delete_token_properties(
@@ -284,7 +284,7 @@
_token_id: TokenId,
_property_keys: Vec<PropertyKey>,
) -> DispatchResultWithPostInfo {
- fail!(<Error<T>>::PropertiesNotAllowed)
+ fail!(<Error<T>>::SettingPropertiesNotAllowed)
}
fn set_variable_metadata(
@@ -336,6 +336,14 @@
Vec::new()
}
+ fn token_properties(
+ &self,
+ _token_id: TokenId,
+ _keys: Vec<PropertyKey>
+ ) -> Vec<Property> {
+ Vec::new()
+ }
+
fn total_supply(&self) -> u32 {
1
}
pallets/fungible/src/lib.rsdiffbeforeafterboth--- 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]
pallets/nonfungible/src/common.rsdiffbeforeafterboth--- 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<PropertyKey>
+ ) -> Vec<Property> {
+ let properties = <Pallet<T>>::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 {
<Pallet<T>>::total_supply(self)
}
pallets/refungible/src/common.rsdiffbeforeafterboth--- a/pallets/refungible/src/common.rs
+++ b/pallets/refungible/src/common.rs
@@ -269,7 +269,7 @@
_sender: T::CrossAccountId,
_property: Vec<Property>,
) -> DispatchResultWithPostInfo {
- fail!(<Error<T>>::PropertiesNotAllowed)
+ fail!(<Error<T>>::SettingPropertiesNotAllowed)
}
fn delete_collection_properties(
@@ -277,7 +277,7 @@
_sender: &T::CrossAccountId,
_property_keys: Vec<PropertyKey>,
) -> DispatchResultWithPostInfo {
- fail!(<Error<T>>::PropertiesNotAllowed)
+ fail!(<Error<T>>::SettingPropertiesNotAllowed)
}
fn set_token_properties(
@@ -286,7 +286,7 @@
_token_id: TokenId,
_property: Vec<Property>,
) -> DispatchResultWithPostInfo {
- fail!(<Error<T>>::PropertiesNotAllowed)
+ fail!(<Error<T>>::SettingPropertiesNotAllowed)
}
fn set_property_permissions(
@@ -294,7 +294,7 @@
_sender: &T::CrossAccountId,
_property_permissions: Vec<PropertyKeyPermission>,
) -> DispatchResultWithPostInfo {
- fail!(<Error<T>>::PropertiesNotAllowed)
+ fail!(<Error<T>>::SettingPropertiesNotAllowed)
}
fn delete_token_properties(
@@ -303,7 +303,7 @@
_token_id: TokenId,
_property_keys: Vec<PropertyKey>,
) -> DispatchResultWithPostInfo {
- fail!(<Error<T>>::PropertiesNotAllowed)
+ fail!(<Error<T>>::SettingPropertiesNotAllowed)
}
fn set_variable_metadata(
@@ -363,6 +363,14 @@
.into_inner()
}
+ fn token_properties(
+ &self,
+ _token_id: TokenId,
+ _keys: Vec<PropertyKey>
+ ) -> Vec<Property> {
+ Vec::new()
+ }
+
fn total_supply(&self) -> u32 {
<Pallet<T>>::total_supply(self)
}
pallets/refungible/src/lib.rsdiffbeforeafterboth--- 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]
primitives/data-structs/src/lib.rsdiffbeforeafterboth--- 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<CrossAccountId> {
+ pub const_data: Vec<u8>,
+ pub properties: Vec<Property>,
+ pub owner: Option<CrossAccountId>,
+}
+
pub struct OverflowError;
impl From<OverflowError> for &'static str {
fn from(_: OverflowError) -> Self {
primitives/rpc/src/lib.rsdiffbeforeafterboth--- 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<Vec<u8>>
) -> Result<Vec<PropertyKeyPermission>>;
+ fn token_data(collection: CollectionId, token_id: TokenId, keys: Vec<Vec<u8>>) -> Result<TokenData<CrossAccountId>>;
+
fn total_supply(collection: CollectionId) -> Result<u32>;
fn account_balance(collection: CollectionId, account: CrossAccountId) -> Result<u32>;
fn balance(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Result<u128>;
runtime/common/src/runtime_apis.rsdiffbeforeafterboth--- 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<Vec<u8>>) -> Result<Vec<PropertyKey>, DispatchError> {
- keys.into_iter()
- .map(|key| -> Result<PropertyKey, DispatchError> {
- key.try_into().map_err(|_| DispatchError::Other("Can't read property key"))
- })
- .collect::<Result<Vec<PropertyKey>, DispatchError>>()
- }
-
impl_runtime_apis! {
$($($custom_apis)+)?
@@ -48,23 +40,9 @@
collection: CollectionId,
keys: Vec<Vec<u8>>
) -> Result<Vec<Property>, DispatchError> {
- let keys = bytes_keys_to_property_keys(keys)?;
-
- let properties = pallet_common::Pallet::<Runtime>::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::<Runtime>::bytes_keys_to_property_keys(keys)?;
- Ok(properties)
+ pallet_common::Pallet::<Runtime>::filter_collection_properties(collection, keys)
}
fn token_properties(
@@ -72,46 +50,31 @@
token_id: TokenId,
keys: Vec<Vec<u8>>
) -> Result<Vec<Property>, DispatchError> {
- let keys = bytes_keys_to_property_keys(keys)?;
-
- let properties = pallet_nonfungible::Pallet::<Runtime>::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::<Runtime>::bytes_keys_to_property_keys(keys)?;
+ dispatch_unique_runtime!(collection.token_properties(token_id, keys))
}
fn property_permissions(
collection: CollectionId,
keys: Vec<Vec<u8>>
) -> Result<Vec<PropertyKeyPermission>, DispatchError> {
- let keys = bytes_keys_to_property_keys(keys)?;
+ let keys = pallet_common::Pallet::<Runtime>::bytes_keys_to_property_keys(keys)?;
- let permissions = pallet_common::Pallet::<Runtime>::property_permissions(collection);
+ pallet_common::Pallet::<Runtime>::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<Vec<u8>>
+ ) -> Result<TokenData<CrossAccountId>, 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<u32, DispatchError> {