git.delta.rocks / unique-network / refs/commits / 4d135e3fe0d2

difftreelog

source

client/rpc/src/lib.rs15.3 KiBsourcehistory
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, Encode};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, TokenChild,25};26use sp_api::{BlockId, BlockT, ProvideRuntimeApi, ApiExt};27use sp_blockchain::HeaderBackend;28use up_rpc::UniqueApi as UniqueRuntimeApi;2930// RMRK31use rmrk_rpc::RmrkApi as RmrkRuntimeApi;32use up_data_structs::{33	RmrkCollectionId, RmrkNftId, RmrkBaseId, RmrkNftChild, RmrkThemeName, RmrkResourceId,34};3536pub use rmrk_unique_rpc::RmrkApi;3738#[rpc]39pub trait UniqueApi<BlockHash, CrossAccountId, AccountId> {40	#[rpc(name = "unique_accountTokens")]41	fn account_tokens(42		&self,43		collection: CollectionId,44		account: CrossAccountId,45		at: Option<BlockHash>,46	) -> Result<Vec<TokenId>>;47	#[rpc(name = "unique_collectionTokens")]48	fn collection_tokens(49		&self,50		collection: CollectionId,51		at: Option<BlockHash>,52	) -> Result<Vec<TokenId>>;53	#[rpc(name = "unique_tokenExists")]54	fn token_exists(55		&self,56		collection: CollectionId,57		token: TokenId,58		at: Option<BlockHash>,59	) -> Result<bool>;6061	#[rpc(name = "unique_tokenOwner")]62	fn token_owner(63		&self,64		collection: CollectionId,65		token: TokenId,66		at: Option<BlockHash>,67	) -> Result<Option<CrossAccountId>>;68	#[rpc(name = "unique_topmostTokenOwner")]69	fn topmost_token_owner(70		&self,71		collection: CollectionId,72		token: TokenId,73		at: Option<BlockHash>,74	) -> Result<Option<CrossAccountId>>;75	#[rpc(name = "unique_tokenChildren")]76	fn token_children(77		&self,78		collection: CollectionId,79		token: TokenId,80		at: Option<BlockHash>,81	) -> Result<Vec<TokenChild>>;8283	#[rpc(name = "unique_collectionProperties")]84	fn collection_properties(85		&self,86		collection: CollectionId,87		keys: Option<Vec<String>>,88		at: Option<BlockHash>,89	) -> Result<Vec<Property>>;9091	#[rpc(name = "unique_tokenProperties")]92	fn token_properties(93		&self,94		collection: CollectionId,95		token_id: TokenId,96		keys: Option<Vec<String>>,97		at: Option<BlockHash>,98	) -> Result<Vec<Property>>;99100	#[rpc(name = "unique_propertyPermissions")]101	fn property_permissions(102		&self,103		collection: CollectionId,104		keys: Option<Vec<String>>,105		at: Option<BlockHash>,106	) -> Result<Vec<PropertyKeyPermission>>;107108	#[rpc(name = "unique_tokenData")]109	fn token_data(110		&self,111		collection: CollectionId,112		token_id: TokenId,113		keys: Option<Vec<String>>,114		at: Option<BlockHash>,115	) -> Result<TokenData<CrossAccountId>>;116117	#[rpc(name = "unique_totalSupply")]118	fn total_supply(&self, collection: CollectionId, at: Option<BlockHash>) -> Result<u32>;119	#[rpc(name = "unique_accountBalance")]120	fn account_balance(121		&self,122		collection: CollectionId,123		account: CrossAccountId,124		at: Option<BlockHash>,125	) -> Result<u32>;126	#[rpc(name = "unique_balance")]127	fn balance(128		&self,129		collection: CollectionId,130		account: CrossAccountId,131		token: TokenId,132		at: Option<BlockHash>,133	) -> Result<String>;134	#[rpc(name = "unique_allowance")]135	fn allowance(136		&self,137		collection: CollectionId,138		sender: CrossAccountId,139		spender: CrossAccountId,140		token: TokenId,141		at: Option<BlockHash>,142	) -> Result<String>;143144	#[rpc(name = "unique_adminlist")]145	fn adminlist(146		&self,147		collection: CollectionId,148		at: Option<BlockHash>,149	) -> Result<Vec<CrossAccountId>>;150	#[rpc(name = "unique_allowlist")]151	fn allowlist(152		&self,153		collection: CollectionId,154		at: Option<BlockHash>,155	) -> Result<Vec<CrossAccountId>>;156	#[rpc(name = "unique_allowed")]157	fn allowed(158		&self,159		collection: CollectionId,160		user: CrossAccountId,161		at: Option<BlockHash>,162	) -> Result<bool>;163	#[rpc(name = "unique_lastTokenId")]164	fn last_token_id(&self, collection: CollectionId, at: Option<BlockHash>) -> Result<TokenId>;165	#[rpc(name = "unique_collectionById")]166	fn collection_by_id(167		&self,168		collection: CollectionId,169		at: Option<BlockHash>,170	) -> Result<Option<RpcCollection<AccountId>>>;171	#[rpc(name = "unique_collectionStats")]172	fn collection_stats(&self, at: Option<BlockHash>) -> Result<CollectionStats>;173174	#[rpc(name = "unique_nextSponsored")]175	fn next_sponsored(176		&self,177		collection: CollectionId,178		account: CrossAccountId,179		token: TokenId,180		at: Option<BlockHash>,181	) -> Result<Option<u64>>;182	#[rpc(name = "unique_effectiveCollectionLimits")]183	fn effective_collection_limits(184		&self,185		collection_id: CollectionId,186		at: Option<BlockHash>,187	) -> Result<Option<CollectionLimits>>;188}189190mod rmrk_unique_rpc {191	use super::*;192193	#[rpc(server)]194	pub trait RmrkApi<195		BlockHash,196		AccountId,197		CollectionInfo,198		NftInfo,199		ResourceInfo,200		PropertyInfo,201		BaseInfo,202		PartType,203		Theme,204	>205	{206		#[rpc(name = "rmrk_lastCollectionIdx")]207		/// Get the latest created collection id208		fn last_collection_idx(&self, at: Option<BlockHash>) -> Result<RmrkCollectionId>;209210		#[rpc(name = "rmrk_collectionById")]211		/// Get collection by id212		fn collection_by_id(213			&self,214			id: RmrkCollectionId,215			at: Option<BlockHash>,216		) -> Result<Option<CollectionInfo>>;217218		#[rpc(name = "rmrk_nftById")]219		/// Get NFT by collection id and NFT id220		fn nft_by_id(221			&self,222			collection_id: RmrkCollectionId,223			nft_id: RmrkNftId,224			at: Option<BlockHash>,225		) -> Result<Option<NftInfo>>;226227		#[rpc(name = "rmrk_accountTokens")]228		/// Get tokens owned by an account in a collection229		fn account_tokens(230			&self,231			account_id: AccountId,232			collection_id: RmrkCollectionId,233			at: Option<BlockHash>,234		) -> Result<Vec<RmrkNftId>>;235236		#[rpc(name = "rmrk_nftChildren")]237		/// Get NFT children238		fn nft_children(239			&self,240			collection_id: RmrkCollectionId,241			nft_id: RmrkNftId,242			at: Option<BlockHash>,243		) -> Result<Vec<RmrkNftChild>>;244245		#[rpc(name = "rmrk_collectionProperties")]246		/// Get collection properties247		fn collection_properties(248			&self,249			collection_id: RmrkCollectionId,250			filter_keys: Option<Vec<String>>,251			at: Option<BlockHash>,252		) -> Result<Vec<PropertyInfo>>;253254		#[rpc(name = "rmrk_nftProperties")]255		/// Get NFT properties256		fn nft_properties(257			&self,258			collection_id: RmrkCollectionId,259			nft_id: RmrkNftId,260			filter_keys: Option<Vec<String>>,261			at: Option<BlockHash>,262		) -> Result<Vec<PropertyInfo>>;263264		#[rpc(name = "rmrk_nftResources")]265		/// Get NFT resources266		fn nft_resources(267			&self,268			collection_id: RmrkCollectionId,269			nft_id: RmrkNftId,270			at: Option<BlockHash>,271		) -> Result<Vec<ResourceInfo>>;272273		#[rpc(name = "rmrk_nftResourcePriorities")]274		/// Get NFT resource priorities275		fn nft_resource_priorities(276			&self,277			collection_id: RmrkCollectionId,278			nft_id: RmrkNftId,279			at: Option<BlockHash>,280		) -> Result<Vec<RmrkResourceId>>;281282		#[rpc(name = "rmrk_base")]283		/// Get base info284		fn base(&self, base_id: RmrkBaseId, at: Option<BlockHash>) -> Result<Option<BaseInfo>>;285286		#[rpc(name = "rmrk_baseParts")]287		/// Get all Base's parts288		fn base_parts(&self, base_id: RmrkBaseId, at: Option<BlockHash>) -> Result<Vec<PartType>>;289290		#[rpc(name = "rmrk_themeNames")]291		fn theme_names(292			&self,293			base_id: RmrkBaseId,294			at: Option<BlockHash>,295		) -> Result<Vec<RmrkThemeName>>;296297		#[rpc(name = "rmrk_themes")]298		fn theme(299			&self,300			base_id: RmrkBaseId,301			theme_name: String,302			filter_keys: Option<Vec<String>>,303			at: Option<BlockHash>,304		) -> Result<Option<Theme>>;305	}306}307308pub struct Unique<C, P> {309	client: Arc<C>,310	_marker: std::marker::PhantomData<P>,311}312313impl<C, P> Unique<C, P> {314	pub fn new(client: Arc<C>) -> Self {315		Self {316			client,317			_marker: Default::default(),318		}319	}320}321322pub enum Error {323	RuntimeError,324}325326impl From<Error> for i64 {327	fn from(e: Error) -> i64 {328		match e {329			Error::RuntimeError => 1,330		}331	}332}333334macro_rules! pass_method {335	(336		$method_name:ident(337			$($(#[map(|$map_arg:ident| $map:expr)])? $name:ident: $ty:ty),* $(,)?338		) -> $result:ty $(=> $mapper:expr)?,339		//$runtime_name:ident $(<$($lt: tt),+>)*340		$runtime_api_macro:ident341		$(; changed_in $ver:expr, $changed_method_name:ident ($($changed_name:expr), * $(,)?) => $fixer:expr)*342	) => {343		fn $method_name(344			&self,345			$(346				$name: $ty,347			)*348			at: Option<<Block as BlockT>::Hash>,349		) -> Result<$result> {350			let api = self.client.runtime_api();351			let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash));352			let _api_version = if let Ok(Some(api_version)) =353				api.api_version::<$runtime_api_macro!()>(&at)354			{355				api_version356			} else {357				// unreachable for our runtime358				return Err(RpcError {359					code: ErrorCode::InvalidParams,360					message: "Api is not available".into(),361					data: None,362				})363			};364365			let result = $(if _api_version < $ver {366				api.$changed_method_name(&at, $($changed_name),*).map(|r| r.map($fixer))367			} else)*368			{ api.$method_name(&at, $($((|$map_arg: $ty| $map))? ($name)),*) };369370			let result = result.map_err(|e| RpcError {371				code: ErrorCode::ServerError(Error::RuntimeError.into()),372				message: "Unable to query".into(),373				data: Some(format!("{:?}", e).into()),374			})?;375			result.map_err(|e| RpcError {376				code: ErrorCode::InvalidParams,377				message: "Runtime returned error".into(),378				data: Some(format!("{:?}", e).into()),379			})$(.map($mapper))?380		}381	};382}383384macro_rules! unique_api {385	() => {386		dyn UniqueRuntimeApi<Block, CrossAccountId, AccountId>387	};388}389390macro_rules! rmrk_api {391	() => {392		dyn RmrkRuntimeApi<Block, AccountId, CollectionInfo, NftInfo, ResourceInfo, PropertyInfo, BaseInfo, PartType, Theme>393	};394}395396#[allow(deprecated)]397impl<C, Block, CrossAccountId, AccountId>398	UniqueApi<<Block as BlockT>::Hash, CrossAccountId, AccountId> for Unique<C, Block>399where400	Block: BlockT,401	AccountId: Decode,402	C: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,403	C::Api: UniqueRuntimeApi<Block, CrossAccountId, AccountId>,404	CrossAccountId: pallet_evm::account::CrossAccountId<AccountId>,405{406	pass_method!(407		account_tokens(collection: CollectionId, account: CrossAccountId) -> Vec<TokenId>, unique_api408	);409	pass_method!(410		collection_tokens(collection: CollectionId) -> Vec<TokenId>, unique_api411	);412	pass_method!(413		token_exists(collection: CollectionId, token: TokenId) -> bool, unique_api414	);415	pass_method!(416		token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>, unique_api417	);418	pass_method!(419		topmost_token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>, unique_api420	);421	pass_method!(token_children(collection: CollectionId, token: TokenId) -> Vec<TokenChild>, unique_api);422	pass_method!(total_supply(collection: CollectionId) -> u32, unique_api);423	pass_method!(account_balance(collection: CollectionId, account: CrossAccountId) -> u32, unique_api);424	pass_method!(balance(collection: CollectionId, account: CrossAccountId, token: TokenId) -> String => |v| v.to_string(), unique_api);425	pass_method!(426		allowance(collection: CollectionId, sender: CrossAccountId, spender: CrossAccountId, token: TokenId) -> String => |v| v.to_string(),427		unique_api428	);429430	pass_method!(collection_properties(431		collection: CollectionId,432433		#[map(|keys| string_keys_to_bytes_keys(keys))]434		keys: Option<Vec<String>>435	) -> Vec<Property>, unique_api);436437	pass_method!(token_properties(438		collection: CollectionId,439		token_id: TokenId,440441		#[map(|keys| string_keys_to_bytes_keys(keys))]442		keys: Option<Vec<String>>443	) -> Vec<Property>, unique_api);444445	pass_method!(property_permissions(446		collection: CollectionId,447448		#[map(|keys| string_keys_to_bytes_keys(keys))]449		keys: Option<Vec<String>>450	) -> Vec<PropertyKeyPermission>, unique_api);451452	pass_method!(token_data(453		collection: CollectionId,454		token_id: TokenId,455456		#[map(|keys| string_keys_to_bytes_keys(keys))]457		keys: Option<Vec<String>>,458	) -> TokenData<CrossAccountId>, unique_api);459460	pass_method!(adminlist(collection: CollectionId) -> Vec<CrossAccountId>, unique_api);461	pass_method!(allowlist(collection: CollectionId) -> Vec<CrossAccountId>, unique_api);462	pass_method!(allowed(collection: CollectionId, user: CrossAccountId) -> bool, unique_api);463	pass_method!(last_token_id(collection: CollectionId) -> TokenId, unique_api);464	pass_method!(collection_by_id(collection: CollectionId) -> Option<RpcCollection<AccountId>>, unique_api);465	pass_method!(collection_stats() -> CollectionStats, unique_api);466	pass_method!(next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Option<u64>, unique_api);467	pass_method!(effective_collection_limits(collection_id: CollectionId) -> Option<CollectionLimits>, unique_api);468}469470#[allow(deprecated)]471impl<472		C,473		Block,474		AccountId,475		CollectionInfo,476		NftInfo,477		ResourceInfo,478		PropertyInfo,479		BaseInfo,480		PartType,481		Theme,482	>483	rmrk_unique_rpc::RmrkApi<484		<Block as BlockT>::Hash,485		AccountId,486		CollectionInfo,487		NftInfo,488		ResourceInfo,489		PropertyInfo,490		BaseInfo,491		PartType,492		Theme,493	> for Unique<C, Block>494where495	C: Send + Sync + 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,496	C::Api: RmrkRuntimeApi<497		Block,498		AccountId,499		CollectionInfo,500		NftInfo,501		ResourceInfo,502		PropertyInfo,503		BaseInfo,504		PartType,505		Theme,506	>,507	AccountId: Decode + Encode,508	CollectionInfo: Decode,509	NftInfo: Decode,510	ResourceInfo: Decode,511	PropertyInfo: Decode,512	BaseInfo: Decode,513	PartType: Decode,514	Theme: Decode,515	Block: BlockT,516{517	pass_method!(last_collection_idx() -> RmrkCollectionId, rmrk_api);518	pass_method!(collection_by_id(id: RmrkCollectionId) -> Option<CollectionInfo>, rmrk_api);519	pass_method!(nft_by_id(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Option<NftInfo>, rmrk_api);520	pass_method!(account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Vec<RmrkNftId>, rmrk_api);521	pass_method!(nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<RmrkNftChild>, rmrk_api);522	pass_method!(523		collection_properties(524			collection_id: RmrkCollectionId,525526			#[map(|keys| string_keys_to_bytes_keys(keys))]527			filter_keys: Option<Vec<String>>528		) -> Vec<PropertyInfo>,529		rmrk_api530	);531	pass_method!(532		nft_properties(533			collection_id: RmrkCollectionId,534			nft_id: RmrkNftId,535536			#[map(|keys| string_keys_to_bytes_keys(keys))]537			filter_keys: Option<Vec<String>>538		) -> Vec<PropertyInfo>,539		rmrk_api540	);541	pass_method!(nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<ResourceInfo>, rmrk_api);542	pass_method!(nft_resource_priorities(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<RmrkResourceId>, rmrk_api);543	pass_method!(base(base_id: RmrkBaseId) -> Option<BaseInfo>, rmrk_api);544	pass_method!(base_parts(base_id: RmrkBaseId) -> Vec<PartType>, rmrk_api);545	pass_method!(theme_names(base_id: RmrkBaseId) -> Vec<RmrkThemeName>, rmrk_api);546	pass_method!(547		theme(548			base_id: RmrkBaseId,549550			#[map(|n| n.into_bytes())]551			theme_name: String,552553			#[map(|keys| string_keys_to_bytes_keys(keys))]554			filter_keys: Option<Vec<String>>555		) -> Option<Theme>, rmrk_api);556}557558fn string_keys_to_bytes_keys(keys: Option<Vec<String>>) -> Option<Vec<Vec<u8>>> {559	keys.map(|keys| keys.into_iter().map(|key| key.into_bytes()).collect())560}