git.delta.rocks / unique-network / refs/commits / aa2eb2fbd54b

difftreelog

source

client/rpc/src/lib.rs15.0 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,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,34	RmrkResourceId,35};3637pub use rmrk_unique_rpc::RmrkApi;3839#[rpc]40pub trait UniqueApi<BlockHash, CrossAccountId, AccountId> {41	#[rpc(name = "unique_accountTokens")]42	fn account_tokens(43		&self,44		collection: CollectionId,45		account: CrossAccountId,46		at: Option<BlockHash>,47	) -> Result<Vec<TokenId>>;48	#[rpc(name = "unique_collectionTokens")]49	fn collection_tokens(50		&self,51		collection: CollectionId,52		at: Option<BlockHash>,53	) -> Result<Vec<TokenId>>;54	#[rpc(name = "unique_tokenExists")]55	fn token_exists(56		&self,57		collection: CollectionId,58		token: TokenId,59		at: Option<BlockHash>,60	) -> Result<bool>;6162	#[rpc(name = "unique_tokenOwner")]63	fn token_owner(64		&self,65		collection: CollectionId,66		token: TokenId,67		at: Option<BlockHash>,68	) -> Result<Option<CrossAccountId>>;69	#[rpc(name = "unique_topmostTokenOwner")]70	fn topmost_token_owner(71		&self,72		collection: CollectionId,73		token: TokenId,74		at: Option<BlockHash>,75	) -> Result<Option<CrossAccountId>>;7677	#[rpc(name = "unique_collectionProperties")]78	fn collection_properties(79		&self,80		collection: CollectionId,81		keys: Option<Vec<String>>,82		at: Option<BlockHash>,83	) -> Result<Vec<Property>>;8485	#[rpc(name = "unique_tokenProperties")]86	fn token_properties(87		&self,88		collection: CollectionId,89		token_id: TokenId,90		keys: Option<Vec<String>>,91		at: Option<BlockHash>,92	) -> Result<Vec<Property>>;9394	#[rpc(name = "unique_propertyPermissions")]95	fn property_permissions(96		&self,97		collection: CollectionId,98		keys: Option<Vec<String>>,99		at: Option<BlockHash>,100	) -> Result<Vec<PropertyKeyPermission>>;101102	#[rpc(name = "unique_tokenData")]103	fn token_data(104		&self,105		collection: CollectionId,106		token_id: TokenId,107		keys: Option<Vec<String>>,108		at: Option<BlockHash>,109	) -> Result<TokenData<CrossAccountId>>;110111	#[rpc(name = "unique_totalSupply")]112	fn total_supply(&self, collection: CollectionId, at: Option<BlockHash>) -> Result<u32>;113	#[rpc(name = "unique_accountBalance")]114	fn account_balance(115		&self,116		collection: CollectionId,117		account: CrossAccountId,118		at: Option<BlockHash>,119	) -> Result<u32>;120	#[rpc(name = "unique_balance")]121	fn balance(122		&self,123		collection: CollectionId,124		account: CrossAccountId,125		token: TokenId,126		at: Option<BlockHash>,127	) -> Result<String>;128	#[rpc(name = "unique_allowance")]129	fn allowance(130		&self,131		collection: CollectionId,132		sender: CrossAccountId,133		spender: CrossAccountId,134		token: TokenId,135		at: Option<BlockHash>,136	) -> Result<String>;137138	#[rpc(name = "unique_adminlist")]139	fn adminlist(140		&self,141		collection: CollectionId,142		at: Option<BlockHash>,143	) -> Result<Vec<CrossAccountId>>;144	#[rpc(name = "unique_allowlist")]145	fn allowlist(146		&self,147		collection: CollectionId,148		at: Option<BlockHash>,149	) -> Result<Vec<CrossAccountId>>;150	#[rpc(name = "unique_allowed")]151	fn allowed(152		&self,153		collection: CollectionId,154		user: CrossAccountId,155		at: Option<BlockHash>,156	) -> Result<bool>;157	#[rpc(name = "unique_lastTokenId")]158	fn last_token_id(&self, collection: CollectionId, at: Option<BlockHash>) -> Result<TokenId>;159	#[rpc(name = "unique_collectionById")]160	fn collection_by_id(161		&self,162		collection: CollectionId,163		at: Option<BlockHash>,164	) -> Result<Option<RpcCollection<AccountId>>>;165	#[rpc(name = "unique_collectionStats")]166	fn collection_stats(&self, at: Option<BlockHash>) -> Result<CollectionStats>;167168	#[rpc(name = "unique_nextSponsored")]169	fn next_sponsored(170		&self,171		collection: CollectionId,172		account: CrossAccountId,173		token: TokenId,174		at: Option<BlockHash>,175	) -> Result<Option<u64>>;176	#[rpc(name = "unique_effectiveCollectionLimits")]177	fn effective_collection_limits(178		&self,179		collection_id: CollectionId,180		at: Option<BlockHash>,181	) -> Result<Option<CollectionLimits>>;182}183184mod rmrk_unique_rpc {185	use super::*;186187	#[rpc(server)]188	pub trait RmrkApi<189		BlockHash,190		AccountId,191		CollectionInfo,192		NftInfo,193		ResourceInfo,194		PropertyInfo,195		BaseInfo,196		PartType,197		Theme,198	>199	{200		#[rpc(name = "rmrk_lastCollectionIdx")]201		/// Get the latest created collection id202		fn last_collection_idx(&self, at: Option<BlockHash>) -> Result<RmrkCollectionId>;203204		#[rpc(name = "rmrk_collectionById")]205		/// Get collection by id206		fn collection_by_id(207			&self,208			id: RmrkCollectionId,209			at: Option<BlockHash>,210		) -> Result<Option<CollectionInfo>>;211212		#[rpc(name = "rmrk_nftById")]213		/// Get NFT by collection id and NFT id214		fn nft_by_id(215			&self,216			collection_id: RmrkCollectionId,217			nft_id: RmrkNftId,218			at: Option<BlockHash>,219		) -> Result<Option<NftInfo>>;220221		#[rpc(name = "rmrk_accountTokens")]222		/// Get tokens owned by an account in a collection223		fn account_tokens(224			&self,225			account_id: AccountId,226			collection_id: RmrkCollectionId,227			at: Option<BlockHash>,228		) -> Result<Vec<RmrkNftId>>;229230		#[rpc(name = "rmrk_nftChildren")]231		/// Get NFT children232		fn nft_children(233			&self,234			collection_id: RmrkCollectionId,235			nft_id: RmrkNftId,236			at: Option<BlockHash>,237		) -> Result<Vec<RmrkNftChild>>;238239		#[rpc(name = "rmrk_collectionProperties")]240		/// Get collection properties241		fn collection_properties(242			&self,243			collection_id: RmrkCollectionId,244			filter_keys: Option<Vec<String>>,245			at: Option<BlockHash>,246		) -> Result<Vec<PropertyInfo>>;247248		#[rpc(name = "rmrk_nftProperties")]249		/// Get NFT properties250		fn nft_properties(251			&self,252			collection_id: RmrkCollectionId,253			nft_id: RmrkNftId,254			filter_keys: Option<Vec<String>>,255			at: Option<BlockHash>,256		) -> Result<Vec<PropertyInfo>>;257258		#[rpc(name = "rmrk_nftResources")]259		/// Get NFT resources260		fn nft_resources(261			&self,262			collection_id: RmrkCollectionId,263			nft_id: RmrkNftId,264			at: Option<BlockHash>,265		) -> Result<Vec<ResourceInfo>>;266267		#[rpc(name = "rmrk_nftResourcePriorities")]268		/// Get NFT resource priorities269		fn nft_resource_priorities(270			&self,271			collection_id: RmrkCollectionId,272			nft_id: RmrkNftId,273			at: Option<BlockHash>,274		) -> Result<Vec<RmrkResourceId>>;275276		#[rpc(name = "rmrk_base")]277		/// Get base info278		fn base(&self, base_id: RmrkBaseId, at: Option<BlockHash>) -> Result<Option<BaseInfo>>;279280		#[rpc(name = "rmrk_baseParts")]281		/// Get all Base's parts282		fn base_parts(&self, base_id: RmrkBaseId, at: Option<BlockHash>) -> Result<Vec<PartType>>;283284		#[rpc(name = "rmrk_themeNames")]285		fn theme_names(286			&self,287			base_id: RmrkBaseId,288			at: Option<BlockHash>,289		) -> Result<Vec<RmrkThemeName>>;290291		#[rpc(name = "rmrk_themes")]292		fn theme(293			&self,294			base_id: RmrkBaseId,295			theme_name: String,296			filter_keys: Option<Vec<String>>,297			at: Option<BlockHash>,298		) -> Result<Option<Theme>>;299	}300}301302pub struct Unique<C, P> {303	client: Arc<C>,304	_marker: std::marker::PhantomData<P>,305}306307impl<C, P> Unique<C, P> {308	pub fn new(client: Arc<C>) -> Self {309		Self {310			client,311			_marker: Default::default(),312		}313	}314}315316pub enum Error {317	RuntimeError,318}319320impl From<Error> for i64 {321	fn from(e: Error) -> i64 {322		match e {323			Error::RuntimeError => 1,324		}325	}326}327328macro_rules! pass_method {329	(330		$method_name:ident(331			$($(#[map(|$map_arg:ident| $map:expr)])? $name:ident: $ty:ty),* $(,)?332		) -> $result:ty $(=> $mapper:expr)?,333		//$runtime_name:ident $(<$($lt: tt),+>)*334		$runtime_api_macro:ident335		$(; changed_in $ver:expr, $changed_method_name:ident ($($changed_name:expr), * $(,)?) => $fixer:expr)*336	) => {337		fn $method_name(338			&self,339			$(340				$name: $ty,341			)*342			at: Option<<Block as BlockT>::Hash>,343		) -> Result<$result> {344			let api = self.client.runtime_api();345			let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash));346			let _api_version = if let Ok(Some(api_version)) =347				api.api_version::<$runtime_api_macro!()>(&at)348			{349				api_version350			} else {351				// unreachable for our runtime352				return Err(RpcError {353					code: ErrorCode::InvalidParams,354					message: "Api is not available".into(),355					data: None,356				})357			};358359			let result = $(if _api_version < $ver {360				api.$changed_method_name(&at, $($changed_name),*).map(|r| r.map($fixer))361			} else)*362			{ api.$method_name(&at, $($((|$map_arg: $ty| $map))? ($name)),*) };363364			let result = result.map_err(|e| RpcError {365				code: ErrorCode::ServerError(Error::RuntimeError.into()),366				message: "Unable to query".into(),367				data: Some(format!("{:?}", e).into()),368			})?;369			result.map_err(|e| RpcError {370				code: ErrorCode::InvalidParams,371				message: "Runtime returned error".into(),372				data: Some(format!("{:?}", e).into()),373			})$(.map($mapper))?374		}375	};376}377378macro_rules! unique_api {379	() => {380		dyn UniqueRuntimeApi<Block, CrossAccountId, AccountId>381	};382}383384macro_rules! rmrk_api {385	() => {386		dyn RmrkRuntimeApi<Block, AccountId, CollectionInfo, NftInfo, ResourceInfo, PropertyInfo, BaseInfo, PartType, Theme>387	};388}389390#[allow(deprecated)]391impl<C, Block, CrossAccountId, AccountId>392	UniqueApi<<Block as BlockT>::Hash, CrossAccountId, AccountId> for Unique<C, Block>393where394	Block: BlockT,395	AccountId: Decode,396	C: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,397	C::Api: UniqueRuntimeApi<Block, CrossAccountId, AccountId>,398	CrossAccountId: pallet_evm::account::CrossAccountId<AccountId>,399{400	pass_method!(401		account_tokens(collection: CollectionId, account: CrossAccountId) -> Vec<TokenId>, unique_api402	);403	pass_method!(404		collection_tokens(collection: CollectionId) -> Vec<TokenId>, unique_api405	);406	pass_method!(407		token_exists(collection: CollectionId, token: TokenId) -> bool, unique_api408	);409	pass_method!(410		token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>, unique_api411	);412	pass_method!(413		topmost_token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>, unique_api414	);415	pass_method!(total_supply(collection: CollectionId) -> u32, unique_api);416	pass_method!(account_balance(collection: CollectionId, account: CrossAccountId) -> u32, unique_api);417	pass_method!(balance(collection: CollectionId, account: CrossAccountId, token: TokenId) -> String => |v| v.to_string(), unique_api);418	pass_method!(419		allowance(collection: CollectionId, sender: CrossAccountId, spender: CrossAccountId, token: TokenId) -> String => |v| v.to_string(),420		unique_api421	);422423	pass_method!(collection_properties(424		collection: CollectionId,425426		#[map(|keys| string_keys_to_bytes_keys(keys))]427		keys: Option<Vec<String>>428	) -> Vec<Property>, unique_api);429430	pass_method!(token_properties(431		collection: CollectionId,432		token_id: TokenId,433434		#[map(|keys| string_keys_to_bytes_keys(keys))]435		keys: Option<Vec<String>>436	) -> Vec<Property>, unique_api);437438	pass_method!(property_permissions(439		collection: CollectionId,440441		#[map(|keys| string_keys_to_bytes_keys(keys))]442		keys: Option<Vec<String>>443	) -> Vec<PropertyKeyPermission>, unique_api);444445	pass_method!(token_data(446		collection: CollectionId,447		token_id: TokenId,448449		#[map(|keys| string_keys_to_bytes_keys(keys))]450		keys: Option<Vec<String>>,451	) -> TokenData<CrossAccountId>, unique_api);452453	pass_method!(adminlist(collection: CollectionId) -> Vec<CrossAccountId>, unique_api);454	pass_method!(allowlist(collection: CollectionId) -> Vec<CrossAccountId>, unique_api);455	pass_method!(allowed(collection: CollectionId, user: CrossAccountId) -> bool, unique_api);456	pass_method!(last_token_id(collection: CollectionId) -> TokenId, unique_api);457	pass_method!(collection_by_id(collection: CollectionId) -> Option<RpcCollection<AccountId>>, unique_api);458	pass_method!(collection_stats() -> CollectionStats, unique_api);459	pass_method!(next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Option<u64>, unique_api);460	pass_method!(effective_collection_limits(collection_id: CollectionId) -> Option<CollectionLimits>, unique_api);461}462463#[allow(deprecated)]464impl<465		C,466		Block,467		AccountId,468		CollectionInfo,469		NftInfo,470		ResourceInfo,471		PropertyInfo,472		BaseInfo,473		PartType,474		Theme,475	>476	rmrk_unique_rpc::RmrkApi<477		<Block as BlockT>::Hash,478		AccountId,479		CollectionInfo,480		NftInfo,481		ResourceInfo,482		PropertyInfo,483		BaseInfo,484		PartType,485		Theme,486	> for Unique<C, Block>487where488	C: Send + Sync + 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,489	C::Api: RmrkRuntimeApi<490		Block,491		AccountId,492		CollectionInfo,493		NftInfo,494		ResourceInfo,495		PropertyInfo,496		BaseInfo,497		PartType,498		Theme,499	>,500	AccountId: Decode + Encode,501	CollectionInfo: Decode,502	NftInfo: Decode,503	ResourceInfo: Decode,504	PropertyInfo: Decode,505	BaseInfo: Decode,506	PartType: Decode,507	Theme: Decode,508	Block: BlockT,509{510	pass_method!(last_collection_idx() -> RmrkCollectionId, rmrk_api);511	pass_method!(collection_by_id(id: RmrkCollectionId) -> Option<CollectionInfo>, rmrk_api);512	pass_method!(nft_by_id(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Option<NftInfo>, rmrk_api);513	pass_method!(account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Vec<RmrkNftId>, rmrk_api);514	pass_method!(nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<RmrkNftChild>, rmrk_api);515	pass_method!(516		collection_properties(517			collection_id: RmrkCollectionId,518519			#[map(|keys| string_keys_to_bytes_keys(keys))]520			filter_keys: Option<Vec<String>>521		) -> Vec<PropertyInfo>,522		rmrk_api523	);524	pass_method!(525		nft_properties(526			collection_id: RmrkCollectionId,527			nft_id: RmrkNftId,528529			#[map(|keys| string_keys_to_bytes_keys(keys))]530			filter_keys: Option<Vec<String>>531		) -> Vec<PropertyInfo>,532		rmrk_api533	);534	pass_method!(nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<ResourceInfo>, rmrk_api);535	pass_method!(nft_resource_priorities(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<RmrkResourceId>, rmrk_api);536	pass_method!(base(base_id: RmrkBaseId) -> Option<BaseInfo>, rmrk_api);537	pass_method!(base_parts(base_id: RmrkBaseId) -> Vec<PartType>, rmrk_api);538	pass_method!(theme_names(base_id: RmrkBaseId) -> Vec<RmrkThemeName>, rmrk_api);539	pass_method!(540		theme(541			base_id: RmrkBaseId,542543			#[map(|n| n.into_bytes())]544			theme_name: String,545546			#[map(|keys| string_keys_to_bytes_keys(keys))]547			filter_keys: Option<Vec<String>>548		) -> Option<Theme>, rmrk_api);549}550551fn string_keys_to_bytes_keys(keys: Option<Vec<String>>) -> Option<Vec<Vec<u8>>> {552	keys.map(|keys| keys.into_iter().map(|key| key.into_bytes()).collect())553}