git.delta.rocks / unique-network / refs/commits / 3b5acf80d0a1

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, 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>>;7576	#[rpc(name = "unique_collectionProperties")]77	fn collection_properties(78		&self,79		collection: CollectionId,80		keys: Option<Vec<String>>,81		at: Option<BlockHash>,82	) -> Result<Vec<Property>>;8384	#[rpc(name = "unique_tokenProperties")]85	fn token_properties(86		&self,87		collection: CollectionId,88		token_id: TokenId,89		keys: Option<Vec<String>>,90		at: Option<BlockHash>,91	) -> Result<Vec<Property>>;9293	#[rpc(name = "unique_propertyPermissions")]94	fn property_permissions(95		&self,96		collection: CollectionId,97		keys: Option<Vec<String>>,98		at: Option<BlockHash>,99	) -> Result<Vec<PropertyKeyPermission>>;100101	#[rpc(name = "unique_tokenData")]102	fn token_data(103		&self,104		collection: CollectionId,105		token_id: TokenId,106		keys: Option<Vec<String>>,107		at: Option<BlockHash>,108	) -> Result<TokenData<CrossAccountId>>;109110	#[rpc(name = "unique_totalSupply")]111	fn total_supply(&self, collection: CollectionId, at: Option<BlockHash>) -> Result<u32>;112	#[rpc(name = "unique_accountBalance")]113	fn account_balance(114		&self,115		collection: CollectionId,116		account: CrossAccountId,117		at: Option<BlockHash>,118	) -> Result<u32>;119	#[rpc(name = "unique_balance")]120	fn balance(121		&self,122		collection: CollectionId,123		account: CrossAccountId,124		token: TokenId,125		at: Option<BlockHash>,126	) -> Result<String>;127	#[rpc(name = "unique_allowance")]128	fn allowance(129		&self,130		collection: CollectionId,131		sender: CrossAccountId,132		spender: CrossAccountId,133		token: TokenId,134		at: Option<BlockHash>,135	) -> Result<String>;136137	#[rpc(name = "unique_adminlist")]138	fn adminlist(139		&self,140		collection: CollectionId,141		at: Option<BlockHash>,142	) -> Result<Vec<CrossAccountId>>;143	#[rpc(name = "unique_allowlist")]144	fn allowlist(145		&self,146		collection: CollectionId,147		at: Option<BlockHash>,148	) -> Result<Vec<CrossAccountId>>;149	#[rpc(name = "unique_allowed")]150	fn allowed(151		&self,152		collection: CollectionId,153		user: CrossAccountId,154		at: Option<BlockHash>,155	) -> Result<bool>;156	#[rpc(name = "unique_lastTokenId")]157	fn last_token_id(&self, collection: CollectionId, at: Option<BlockHash>) -> Result<TokenId>;158	#[rpc(name = "unique_collectionById")]159	fn collection_by_id(160		&self,161		collection: CollectionId,162		at: Option<BlockHash>,163	) -> Result<Option<RpcCollection<AccountId>>>;164	#[rpc(name = "unique_collectionStats")]165	fn collection_stats(&self, at: Option<BlockHash>) -> Result<CollectionStats>;166167	#[rpc(name = "unique_nextSponsored")]168	fn next_sponsored(169		&self,170		collection: CollectionId,171		account: CrossAccountId,172		token: TokenId,173		at: Option<BlockHash>,174	) -> Result<Option<u64>>;175	#[rpc(name = "unique_effectiveCollectionLimits")]176	fn effective_collection_limits(177		&self,178		collection_id: CollectionId,179		at: Option<BlockHash>,180	) -> Result<Option<CollectionLimits>>;181}182183mod rmrk_unique_rpc {184	use super::*;185186	#[rpc(server)]187	pub trait RmrkApi<188		BlockHash,189		AccountId,190		CollectionInfo,191		NftInfo,192		ResourceInfo,193		PropertyInfo,194		BaseInfo,195		PartType,196		Theme,197	>198	{199		#[rpc(name = "rmrk_lastCollectionIdx")]200		/// Get the latest created collection id201		fn last_collection_idx(&self, at: Option<BlockHash>) -> Result<RmrkCollectionId>;202203		#[rpc(name = "rmrk_collectionById")]204		/// Get collection by id205		fn collection_by_id(206			&self,207			id: RmrkCollectionId,208			at: Option<BlockHash>,209		) -> Result<Option<CollectionInfo>>;210211		#[rpc(name = "rmrk_nftById")]212		/// Get NFT by collection id and NFT id213		fn nft_by_id(214			&self,215			collection_id: RmrkCollectionId,216			nft_id: RmrkNftId,217			at: Option<BlockHash>,218		) -> Result<Option<NftInfo>>;219220		#[rpc(name = "rmrk_accountTokens")]221		/// Get tokens owned by an account in a collection222		fn account_tokens(223			&self,224			account_id: AccountId,225			collection_id: RmrkCollectionId,226			at: Option<BlockHash>,227		) -> Result<Vec<RmrkNftId>>;228229		#[rpc(name = "rmrk_nftChildren")]230		/// Get NFT children231		fn nft_children(232			&self,233			collection_id: RmrkCollectionId,234			nft_id: RmrkNftId,235			at: Option<BlockHash>,236		) -> Result<Vec<RmrkNftChild>>;237238		#[rpc(name = "rmrk_collectionProperties")]239		/// Get collection properties240		fn collection_properties(241			&self,242			collection_id: RmrkCollectionId,243			filter_keys: Option<Vec<String>>,244			at: Option<BlockHash>,245		) -> Result<Vec<PropertyInfo>>;246247		#[rpc(name = "rmrk_nftProperties")]248		/// Get NFT properties249		fn nft_properties(250			&self,251			collection_id: RmrkCollectionId,252			nft_id: RmrkNftId,253			filter_keys: Option<Vec<String>>,254			at: Option<BlockHash>,255		) -> Result<Vec<PropertyInfo>>;256257		#[rpc(name = "rmrk_nftResources")]258		/// Get NFT resources259		fn nft_resources(260			&self,261			collection_id: RmrkCollectionId,262			nft_id: RmrkNftId,263			at: Option<BlockHash>,264		) -> Result<Vec<ResourceInfo>>;265266		#[rpc(name = "rmrk_nftResourcePriorities")]267		/// Get NFT resource priorities268		fn nft_resource_priorities(269			&self,270			collection_id: RmrkCollectionId,271			nft_id: RmrkNftId,272			at: Option<BlockHash>,273		) -> Result<Vec<RmrkResourceId>>;274275		#[rpc(name = "rmrk_base")]276		/// Get base info277		fn base(&self, base_id: RmrkBaseId, at: Option<BlockHash>) -> Result<Option<BaseInfo>>;278279		#[rpc(name = "rmrk_baseParts")]280		/// Get all Base's parts281		fn base_parts(&self, base_id: RmrkBaseId, at: Option<BlockHash>) -> Result<Vec<PartType>>;282283		#[rpc(name = "rmrk_themeNames")]284		fn theme_names(285			&self,286			base_id: RmrkBaseId,287			at: Option<BlockHash>,288		) -> Result<Vec<RmrkThemeName>>;289290		#[rpc(name = "rmrk_themes")]291		fn theme(292			&self,293			base_id: RmrkBaseId,294			theme_name: String,295			filter_keys: Option<Vec<String>>,296			at: Option<BlockHash>,297		) -> Result<Option<Theme>>;298	}299}300301pub struct Unique<C, P> {302	client: Arc<C>,303	_marker: std::marker::PhantomData<P>,304}305306impl<C, P> Unique<C, P> {307	pub fn new(client: Arc<C>) -> Self {308		Self {309			client,310			_marker: Default::default(),311		}312	}313}314315pub enum Error {316	RuntimeError,317}318319impl From<Error> for i64 {320	fn from(e: Error) -> i64 {321		match e {322			Error::RuntimeError => 1,323		}324	}325}326327macro_rules! pass_method {328	(329		$method_name:ident(330			$($(#[map(|$map_arg:ident| $map:expr)])? $name:ident: $ty:ty),* $(,)?331		) -> $result:ty $(=> $mapper:expr)?,332		//$runtime_name:ident $(<$($lt: tt),+>)*333		$runtime_api_macro:ident334		$(; changed_in $ver:expr, $changed_method_name:ident ($($changed_name:expr), * $(,)?) => $fixer:expr)*335	) => {336		fn $method_name(337			&self,338			$(339				$name: $ty,340			)*341			at: Option<<Block as BlockT>::Hash>,342		) -> Result<$result> {343			let api = self.client.runtime_api();344			let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash));345			let _api_version = if let Ok(Some(api_version)) =346				api.api_version::<$runtime_api_macro!()>(&at)347			{348				api_version349			} else {350				// unreachable for our runtime351				return Err(RpcError {352					code: ErrorCode::InvalidParams,353					message: "Api is not available".into(),354					data: None,355				})356			};357358			let result = $(if _api_version < $ver {359				api.$changed_method_name(&at, $($changed_name),*).map(|r| r.map($fixer))360			} else)*361			{ api.$method_name(&at, $($((|$map_arg: $ty| $map))? ($name)),*) };362363			let result = result.map_err(|e| RpcError {364				code: ErrorCode::ServerError(Error::RuntimeError.into()),365				message: "Unable to query".into(),366				data: Some(format!("{:?}", e).into()),367			})?;368			result.map_err(|e| RpcError {369				code: ErrorCode::InvalidParams,370				message: "Runtime returned error".into(),371				data: Some(format!("{:?}", e).into()),372			})$(.map($mapper))?373		}374	};375}376377macro_rules! unique_api {378	() => {379		dyn UniqueRuntimeApi<Block, CrossAccountId, AccountId>380	};381}382383macro_rules! rmrk_api {384	() => {385		dyn RmrkRuntimeApi<Block, AccountId, CollectionInfo, NftInfo, ResourceInfo, PropertyInfo, BaseInfo, PartType, Theme>386	};387}388389#[allow(deprecated)]390impl<C, Block, CrossAccountId, AccountId>391	UniqueApi<<Block as BlockT>::Hash, CrossAccountId, AccountId> for Unique<C, Block>392where393	Block: BlockT,394	AccountId: Decode,395	C: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,396	C::Api: UniqueRuntimeApi<Block, CrossAccountId, AccountId>,397	CrossAccountId: pallet_evm::account::CrossAccountId<AccountId>,398{399	pass_method!(400		account_tokens(collection: CollectionId, account: CrossAccountId) -> Vec<TokenId>, unique_api401	);402	pass_method!(403		collection_tokens(collection: CollectionId) -> Vec<TokenId>, unique_api404	);405	pass_method!(406		token_exists(collection: CollectionId, token: TokenId) -> bool, unique_api407	);408	pass_method!(409		token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>, unique_api410	);411	pass_method!(412		topmost_token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>, unique_api413	);414	pass_method!(total_supply(collection: CollectionId) -> u32, unique_api);415	pass_method!(account_balance(collection: CollectionId, account: CrossAccountId) -> u32, unique_api);416	pass_method!(balance(collection: CollectionId, account: CrossAccountId, token: TokenId) -> String => |v| v.to_string(), unique_api);417	pass_method!(418		allowance(collection: CollectionId, sender: CrossAccountId, spender: CrossAccountId, token: TokenId) -> String => |v| v.to_string(),419		unique_api420	);421422	pass_method!(collection_properties(423		collection: CollectionId,424425		#[map(|keys| string_keys_to_bytes_keys(keys))]426		keys: Option<Vec<String>>427	) -> Vec<Property>, unique_api);428429	pass_method!(token_properties(430		collection: CollectionId,431		token_id: TokenId,432433		#[map(|keys| string_keys_to_bytes_keys(keys))]434		keys: Option<Vec<String>>435	) -> Vec<Property>, unique_api);436437	pass_method!(property_permissions(438		collection: CollectionId,439440		#[map(|keys| string_keys_to_bytes_keys(keys))]441		keys: Option<Vec<String>>442	) -> Vec<PropertyKeyPermission>, unique_api);443444	pass_method!(token_data(445		collection: CollectionId,446		token_id: TokenId,447448		#[map(|keys| string_keys_to_bytes_keys(keys))]449		keys: Option<Vec<String>>,450	) -> TokenData<CrossAccountId>, unique_api);451452	pass_method!(adminlist(collection: CollectionId) -> Vec<CrossAccountId>, unique_api);453	pass_method!(allowlist(collection: CollectionId) -> Vec<CrossAccountId>, unique_api);454	pass_method!(allowed(collection: CollectionId, user: CrossAccountId) -> bool, unique_api);455	pass_method!(last_token_id(collection: CollectionId) -> TokenId, unique_api);456	pass_method!(collection_by_id(collection: CollectionId) -> Option<RpcCollection<AccountId>>, unique_api);457	pass_method!(collection_stats() -> CollectionStats, unique_api);458	pass_method!(next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Option<u64>, unique_api);459	pass_method!(effective_collection_limits(collection_id: CollectionId) -> Option<CollectionLimits>, unique_api);460}461462#[allow(deprecated)]463impl<464		C,465		Block,466		AccountId,467		CollectionInfo,468		NftInfo,469		ResourceInfo,470		PropertyInfo,471		BaseInfo,472		PartType,473		Theme,474	>475	rmrk_unique_rpc::RmrkApi<476		<Block as BlockT>::Hash,477		AccountId,478		CollectionInfo,479		NftInfo,480		ResourceInfo,481		PropertyInfo,482		BaseInfo,483		PartType,484		Theme,485	> for Unique<C, Block>486where487	C: Send + Sync + 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,488	C::Api: RmrkRuntimeApi<489		Block,490		AccountId,491		CollectionInfo,492		NftInfo,493		ResourceInfo,494		PropertyInfo,495		BaseInfo,496		PartType,497		Theme,498	>,499	AccountId: Decode + Encode,500	CollectionInfo: Decode,501	NftInfo: Decode,502	ResourceInfo: Decode,503	PropertyInfo: Decode,504	BaseInfo: Decode,505	PartType: Decode,506	Theme: Decode,507	Block: BlockT,508{509	pass_method!(last_collection_idx() -> RmrkCollectionId, rmrk_api);510	pass_method!(collection_by_id(id: RmrkCollectionId) -> Option<CollectionInfo>, rmrk_api);511	pass_method!(nft_by_id(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Option<NftInfo>, rmrk_api);512	pass_method!(account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Vec<RmrkNftId>, rmrk_api);513	pass_method!(nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<RmrkNftChild>, rmrk_api);514	pass_method!(515		collection_properties(516			collection_id: RmrkCollectionId,517518			#[map(|keys| string_keys_to_bytes_keys(keys))]519			filter_keys: Option<Vec<String>>520		) -> Vec<PropertyInfo>,521		rmrk_api522	);523	pass_method!(524		nft_properties(525			collection_id: RmrkCollectionId,526			nft_id: RmrkNftId,527528			#[map(|keys| string_keys_to_bytes_keys(keys))]529			filter_keys: Option<Vec<String>>530		) -> Vec<PropertyInfo>,531		rmrk_api532	);533	pass_method!(nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<ResourceInfo>, rmrk_api);534	pass_method!(nft_resource_priorities(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<RmrkResourceId>, rmrk_api);535	pass_method!(base(base_id: RmrkBaseId) -> Option<BaseInfo>, rmrk_api);536	pass_method!(base_parts(base_id: RmrkBaseId) -> Vec<PartType>, rmrk_api);537	pass_method!(theme_names(base_id: RmrkBaseId) -> Vec<RmrkThemeName>, rmrk_api);538	pass_method!(539		theme(540			base_id: RmrkBaseId,541542			#[map(|n| n.into_bytes())]543			theme_name: String,544545			#[map(|keys| string_keys_to_bytes_keys(keys))]546			filter_keys: Option<Vec<String>>547		) -> Option<Theme>, rmrk_api);548}549550fn string_keys_to_bytes_keys(keys: Option<Vec<String>>) -> Option<Vec<Vec<u8>>> {551	keys.map(|keys| keys.into_iter().map(|key| key.into_bytes()).collect())552}