1234567891011121314151617use std::sync::Arc;1819use codec::Decode;20use jsonrpc_core::{Error as RpcError, ErrorCode, Result};21use jsonrpc_derive::rpc;22use up_data_structs::{Collection, CollectionId, CollectionStats, CollectionLimits, TokenId};23use sp_api::{BlockId, BlockT, ProvideRuntimeApi, ApiExt};24use sp_blockchain::HeaderBackend;25use up_rpc::UniqueApi as UniqueRuntimeApi;2627#[rpc]28pub trait UniqueApi<BlockHash, CrossAccountId, AccountId> {29 #[rpc(name = "unique_accountTokens")]30 fn account_tokens(31 &self,32 collection: CollectionId,33 account: CrossAccountId,34 at: Option<BlockHash>,35 ) -> Result<Vec<TokenId>>;36 #[rpc(name = "unique_tokenExists")]37 fn token_exists(38 &self,39 collection: CollectionId,40 token: TokenId,41 at: Option<BlockHash>,42 ) -> Result<bool>;4344 #[rpc(name = "unique_tokenOwner")]45 fn token_owner(46 &self,47 collection: CollectionId,48 token: TokenId,49 at: Option<BlockHash>,50 ) -> Result<Option<CrossAccountId>>;51 #[rpc(name = "unique_constMetadata")]52 fn const_metadata(53 &self,54 collection: CollectionId,55 token: TokenId,56 at: Option<BlockHash>,57 ) -> Result<Vec<u8>>;58 #[rpc(name = "unique_variableMetadata")]59 fn variable_metadata(60 &self,61 collection: CollectionId,62 token: TokenId,63 at: Option<BlockHash>,64 ) -> Result<Vec<u8>>;6566 #[rpc(name = "unique_collectionTokens")]67 fn collection_tokens(&self, collection: CollectionId, at: Option<BlockHash>) -> Result<u32>;68 #[rpc(name = "unique_accountBalance")]69 fn account_balance(70 &self,71 collection: CollectionId,72 account: CrossAccountId,73 at: Option<BlockHash>,74 ) -> Result<u32>;75 #[rpc(name = "unique_balance")]76 fn balance(77 &self,78 collection: CollectionId,79 account: CrossAccountId,80 token: TokenId,81 at: Option<BlockHash>,82 ) -> Result<String>;83 #[rpc(name = "unique_allowance")]84 fn allowance(85 &self,86 collection: CollectionId,87 sender: CrossAccountId,88 spender: CrossAccountId,89 token: TokenId,90 at: Option<BlockHash>,91 ) -> Result<String>;9293 #[rpc(name = "unique_adminlist")]94 fn adminlist(95 &self,96 collection: CollectionId,97 at: Option<BlockHash>,98 ) -> Result<Vec<CrossAccountId>>;99 #[rpc(name = "unique_allowlist")]100 fn allowlist(101 &self,102 collection: CollectionId,103 at: Option<BlockHash>,104 ) -> Result<Vec<CrossAccountId>>;105 #[rpc(name = "unique_allowed")]106 fn allowed(107 &self,108 collection: CollectionId,109 user: CrossAccountId,110 at: Option<BlockHash>,111 ) -> Result<bool>;112 #[rpc(name = "unique_lastTokenId")]113 fn last_token_id(&self, collection: CollectionId, at: Option<BlockHash>) -> Result<TokenId>;114 #[rpc(name = "unique_collectionById")]115 fn collection_by_id(116 &self,117 collection: CollectionId,118 at: Option<BlockHash>,119 ) -> Result<Option<Collection<AccountId>>>;120 #[rpc(name = "unique_collectionStats")]121 fn collection_stats(&self, at: Option<BlockHash>) -> Result<CollectionStats>;122 #[rpc(name = "unique_effectiveCollectionLimits")]123 fn effective_collection_limits(124 &self,125 collection_id: CollectionId,126 at: Option<BlockHash>,127 ) -> Result<Option<CollectionLimits>>;128}129130pub struct Unique<C, P> {131 client: Arc<C>,132 _marker: std::marker::PhantomData<P>,133}134135impl<C, P> Unique<C, P> {136 pub fn new(client: Arc<C>) -> Self {137 Self {138 client,139 _marker: Default::default(),140 }141 }142}143144pub enum Error {145 RuntimeError,146}147148impl From<Error> for i64 {149 fn from(e: Error) -> i64 {150 match e {151 Error::RuntimeError => 1,152 }153 }154}155156macro_rules! pass_method {157 (158 $method_name:ident($($name:ident: $ty:ty),* $(,)?) -> $result:ty $(=> $mapper:expr)?159 $(; changed_in $ver:expr, $changed_method_name:ident ($($changed_name:expr), * $(,)?) => $fixer:expr)*160 ) => {161 fn $method_name(162 &self,163 $(164 $name: $ty,165 )*166 at: Option<<Block as BlockT>::Hash>,167 ) -> Result<$result> {168 let api = self.client.runtime_api();169 let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash));170 let _api_version = if let Ok(Some(api_version)) =171 api.api_version::<dyn UniqueRuntimeApi<Block, CrossAccountId, AccountId>>(&at)172 {173 api_version174 } else {175 176 return Err(RpcError {177 code: ErrorCode::InvalidParams,178 message: "Api is not available".into(),179 data: None,180 })181 };182183 let result = $(if _api_version < $ver {184 api.$changed_method_name(&at, $($changed_name),*).map(|r| r.map($fixer))185 } else)*186 { api.$method_name(&at, $($name),*) };187188 let result = result.map_err(|e| RpcError {189 code: ErrorCode::ServerError(Error::RuntimeError.into()),190 message: "Unable to query".into(),191 data: Some(format!("{:?}", e).into()),192 })?;193 result.map_err(|e| RpcError {194 code: ErrorCode::InvalidParams,195 message: "Runtime returned error".into(),196 data: Some(format!("{:?}", e).into()),197 })$(.map($mapper))?198 }199 };200}201202#[allow(deprecated)]203impl<C, Block, CrossAccountId, AccountId>204 UniqueApi<<Block as BlockT>::Hash, CrossAccountId, AccountId> for Unique<C, Block>205where206 Block: BlockT,207 AccountId: Decode,208 C: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,209 C::Api: UniqueRuntimeApi<Block, CrossAccountId, AccountId>,210 CrossAccountId: pallet_common::account::CrossAccountId<AccountId>,211{212 pass_method!(account_tokens(collection: CollectionId, account: CrossAccountId) -> Vec<TokenId>);213 pass_method!(token_exists(collection: CollectionId, token: TokenId) -> bool);214 pass_method!(215 token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>;216 changed_in 2, token_owner_before_version_2(collection, token) => |u| Some(u)217 );218 pass_method!(const_metadata(collection: CollectionId, token: TokenId) -> Vec<u8>);219 pass_method!(variable_metadata(collection: CollectionId, token: TokenId) -> Vec<u8>);220 pass_method!(collection_tokens(collection: CollectionId) -> u32);221 pass_method!(account_balance(collection: CollectionId, account: CrossAccountId) -> u32);222 pass_method!(balance(collection: CollectionId, account: CrossAccountId, token: TokenId) -> String => |v| v.to_string());223 pass_method!(allowance(collection: CollectionId, sender: CrossAccountId, spender: CrossAccountId, token: TokenId) -> String => |v| v.to_string());224225 pass_method!(adminlist(collection: CollectionId) -> Vec<CrossAccountId>);226 pass_method!(allowlist(collection: CollectionId) -> Vec<CrossAccountId>);227 pass_method!(allowed(collection: CollectionId, user: CrossAccountId) -> bool);228 pass_method!(last_token_id(collection: CollectionId) -> TokenId);229 pass_method!(collection_by_id(collection: CollectionId) -> Option<Collection<AccountId>>);230 pass_method!(collection_stats() -> CollectionStats);231 pass_method!(effective_collection_limits(collection_id: CollectionId) -> Option<CollectionLimits>);232}