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