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>;122123 #[rpc(name = "unique_nextSponsored")]124 fn next_sponsored(125 &self,126 collection: CollectionId,127 account: CrossAccountId,128 token: TokenId,129 at: Option<BlockHash>,130 ) -> Result<Option<u64>>;131 #[rpc(name = "unique_effectiveCollectionLimits")]132 fn effective_collection_limits(133 &self,134 collection_id: CollectionId,135 at: Option<BlockHash>,136 ) -> Result<Option<CollectionLimits>>;137}138139pub struct Unique<C, P> {140 client: Arc<C>,141 _marker: std::marker::PhantomData<P>,142}143144impl<C, P> Unique<C, P> {145 pub fn new(client: Arc<C>) -> Self {146 Self {147 client,148 _marker: Default::default(),149 }150 }151}152153pub enum Error {154 RuntimeError,155}156157impl From<Error> for i64 {158 fn from(e: Error) -> i64 {159 match e {160 Error::RuntimeError => 1,161 }162 }163}164165macro_rules! pass_method {166 (167 $method_name:ident($($name:ident: $ty:ty),* $(,)?) -> $result:ty $(=> $mapper:expr)?168 $(; changed_in $ver:expr, $changed_method_name:ident ($($changed_name:expr), * $(,)?) => $fixer:expr)*169 ) => {170 fn $method_name(171 &self,172 $(173 $name: $ty,174 )*175 at: Option<<Block as BlockT>::Hash>,176 ) -> Result<$result> {177 let api = self.client.runtime_api();178 let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash));179 let _api_version = if let Ok(Some(api_version)) =180 api.api_version::<dyn UniqueRuntimeApi<Block, CrossAccountId, AccountId>>(&at)181 {182 api_version183 } else {184 185 return Err(RpcError {186 code: ErrorCode::InvalidParams,187 message: "Api is not available".into(),188 data: None,189 })190 };191192 let result = $(if _api_version < $ver {193 api.$changed_method_name(&at, $($changed_name),*).map(|r| r.map($fixer))194 } else)*195 { api.$method_name(&at, $($name),*) };196197 let result = result.map_err(|e| RpcError {198 code: ErrorCode::ServerError(Error::RuntimeError.into()),199 message: "Unable to query".into(),200 data: Some(format!("{:?}", e).into()),201 })?;202 result.map_err(|e| RpcError {203 code: ErrorCode::InvalidParams,204 message: "Runtime returned error".into(),205 data: Some(format!("{:?}", e).into()),206 })$(.map($mapper))?207 }208 };209}210211#[allow(deprecated)]212impl<C, Block, CrossAccountId, AccountId>213 UniqueApi<<Block as BlockT>::Hash, CrossAccountId, AccountId> for Unique<C, Block>214where215 Block: BlockT,216 AccountId: Decode,217 C: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,218 C::Api: UniqueRuntimeApi<Block, CrossAccountId, AccountId>,219 CrossAccountId: pallet_evm::account::CrossAccountId<AccountId>,220{221 pass_method!(account_tokens(collection: CollectionId, account: CrossAccountId) -> Vec<TokenId>);222 pass_method!(token_exists(collection: CollectionId, token: TokenId) -> bool);223 pass_method!(224 token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>;225 changed_in 2, token_owner_before_version_2(collection, token) => |u| Some(u)226 );227 pass_method!(const_metadata(collection: CollectionId, token: TokenId) -> Vec<u8>);228 pass_method!(variable_metadata(collection: CollectionId, token: TokenId) -> Vec<u8>);229 pass_method!(collection_tokens(collection: CollectionId) -> u32);230 pass_method!(account_balance(collection: CollectionId, account: CrossAccountId) -> u32);231 pass_method!(balance(collection: CollectionId, account: CrossAccountId, token: TokenId) -> String => |v| v.to_string());232 pass_method!(allowance(collection: CollectionId, sender: CrossAccountId, spender: CrossAccountId, token: TokenId) -> String => |v| v.to_string());233234 pass_method!(adminlist(collection: CollectionId) -> Vec<CrossAccountId>);235 pass_method!(allowlist(collection: CollectionId) -> Vec<CrossAccountId>);236 pass_method!(allowed(collection: CollectionId, user: CrossAccountId) -> bool);237 pass_method!(last_token_id(collection: CollectionId) -> TokenId);238 pass_method!(collection_by_id(collection: CollectionId) -> Option<Collection<AccountId>>);239 pass_method!(collection_stats() -> CollectionStats);240 pass_method!(next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Option<u64>);241 pass_method!(effective_collection_limits(collection_id: CollectionId) -> Option<CollectionLimits>);242}