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

difftreelog

source

client/rpc/src/lib.rs16.4 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/>.1617// Original License18use std::sync::Arc;1920use codec::{Decode, Encode};21use jsonrpsee::{22	core::{RpcResult as Result},23	proc_macros::rpc,24};25use anyhow::anyhow;26use up_data_structs::{27	RpcCollection, CollectionId, CollectionStats, CollectionLimits, TokenId, Property,28	PropertyKeyPermission, TokenData, TokenChild,29};30use sp_api::{BlockId, BlockT, ProvideRuntimeApi, ApiExt};31use sp_blockchain::HeaderBackend;32use up_rpc::UniqueApi as UniqueRuntimeApi;3334// RMRK35use rmrk_rpc::RmrkApi as RmrkRuntimeApi;36use up_data_structs::{37	RmrkCollectionId, RmrkNftId, RmrkBaseId, RmrkNftChild, RmrkThemeName, RmrkResourceId,38};3940pub use rmrk_unique_rpc::RmrkApiServer;4142#[rpc(server)]43#[async_trait]44pub trait UniqueApi<BlockHash, CrossAccountId, AccountId> {45	/// Get tokens owned by account46	#[method(name = "unique_accountTokens")]47	fn account_tokens(48		&self,49		collection: CollectionId,50		account: CrossAccountId,51		at: Option<BlockHash>,52	) -> Result<Vec<TokenId>>;5354	/// Get tokens contained in collection55	#[method(name = "unique_collectionTokens")]56	fn collection_tokens(57		&self,58		collection: CollectionId,59		at: Option<BlockHash>,60	) -> Result<Vec<TokenId>>;6162	/// Check if token exists63	#[method(name = "unique_tokenExists")]64	fn token_exists(65		&self,66		collection: CollectionId,67		token: TokenId,68		at: Option<BlockHash>,69	) -> Result<bool>;7071	/// Get token owner72	#[method(name = "unique_tokenOwner")]73	fn token_owner(74		&self,75		collection: CollectionId,76		token: TokenId,77		at: Option<BlockHash>,78	) -> Result<Option<CrossAccountId>>;7980	/// Get token owner, in case of nested token - find the parent recursively81	#[method(name = "unique_topmostTokenOwner")]82	fn topmost_token_owner(83		&self,84		collection: CollectionId,85		token: TokenId,86		at: Option<BlockHash>,87	) -> Result<Option<CrossAccountId>>;8889	/// Get tokens nested directly into the token90	#[method(name = "unique_tokenChildren")]91	fn token_children(92		&self,93		collection: CollectionId,94		token: TokenId,95		at: Option<BlockHash>,96	) -> Result<Vec<TokenChild>>;9798	/// Get collection properties99	#[method(name = "unique_collectionProperties")]100	fn collection_properties(101		&self,102		collection: CollectionId,103		keys: Option<Vec<String>>,104		at: Option<BlockHash>,105	) -> Result<Vec<Property>>;106107	/// Get token properties108	#[method(name = "unique_tokenProperties")]109	fn token_properties(110		&self,111		collection: CollectionId,112		token_id: TokenId,113		keys: Option<Vec<String>>,114		at: Option<BlockHash>,115	) -> Result<Vec<Property>>;116117	/// Get property permissions118	#[method(name = "unique_propertyPermissions")]119	fn property_permissions(120		&self,121		collection: CollectionId,122		keys: Option<Vec<String>>,123		at: Option<BlockHash>,124	) -> Result<Vec<PropertyKeyPermission>>;125126	/// Get token data127	#[method(name = "unique_tokenData")]128	fn token_data(129		&self,130		collection: CollectionId,131		token_id: TokenId,132		keys: Option<Vec<String>>,133		at: Option<BlockHash>,134	) -> Result<TokenData<CrossAccountId>>;135136	/// Get amount of unique collection tokens137	#[method(name = "unique_totalSupply")]138	fn total_supply(&self, collection: CollectionId, at: Option<BlockHash>) -> Result<u32>;139140	/// Get owned amount of any user tokens141	#[method(name = "unique_accountBalance")]142	fn account_balance(143		&self,144		collection: CollectionId,145		account: CrossAccountId,146		at: Option<BlockHash>,147	) -> Result<u32>;148149	/// Get owned amount of specific account token150	#[method(name = "unique_balance")]151	fn balance(152		&self,153		collection: CollectionId,154		account: CrossAccountId,155		token: TokenId,156		at: Option<BlockHash>,157	) -> Result<String>;158159	/// Get allowed amount160	#[method(name = "unique_allowance")]161	fn allowance(162		&self,163		collection: CollectionId,164		sender: CrossAccountId,165		spender: CrossAccountId,166		token: TokenId,167		at: Option<BlockHash>,168	) -> Result<String>;169170	/// Get admin list171	#[method(name = "unique_adminlist")]172	fn adminlist(173		&self,174		collection: CollectionId,175		at: Option<BlockHash>,176	) -> Result<Vec<CrossAccountId>>;177178	/// Get allowlist179	#[method(name = "unique_allowlist")]180	fn allowlist(181		&self,182		collection: CollectionId,183		at: Option<BlockHash>,184	) -> Result<Vec<CrossAccountId>>;185186	/// Check if user is allowed to use collection187	#[method(name = "unique_allowed")]188	fn allowed(189		&self,190		collection: CollectionId,191		user: CrossAccountId,192		at: Option<BlockHash>,193	) -> Result<bool>;194195	/// Get last token ID created in a collection196	#[method(name = "unique_lastTokenId")]197	fn last_token_id(&self, collection: CollectionId, at: Option<BlockHash>) -> Result<TokenId>;198199	/// Get collection by specified ID200	#[method(name = "unique_collectionById")]201	fn collection_by_id(202		&self,203		collection: CollectionId,204		at: Option<BlockHash>,205	) -> Result<Option<RpcCollection<AccountId>>>;206207	/// Get collection stats208	#[method(name = "unique_collectionStats")]209	fn collection_stats(&self, at: Option<BlockHash>) -> Result<CollectionStats>;210211	/// Get number of blocks when sponsored transaction is available212	#[method(name = "unique_nextSponsored")]213	fn next_sponsored(214		&self,215		collection: CollectionId,216		account: CrossAccountId,217		token: TokenId,218		at: Option<BlockHash>,219	) -> Result<Option<u64>>;220221	/// Get effective collection limits222	#[method(name = "unique_effectiveCollectionLimits")]223	fn effective_collection_limits(224		&self,225		collection_id: CollectionId,226		at: Option<BlockHash>,227	) -> Result<Option<CollectionLimits>>;228229	/// Get total pieces of token230	#[method(name = "unique_totalPieces")]231	fn total_pieces(232		&self,233		collection_id: CollectionId,234		token_id: TokenId,235		at: Option<BlockHash>,236	) -> Result<Option<u128>>;237}238239mod rmrk_unique_rpc {240	use super::*;241242	#[rpc(server)]243	#[async_trait]244	pub trait RmrkApi<245		BlockHash,246		AccountId,247		CollectionInfo,248		NftInfo,249		ResourceInfo,250		PropertyInfo,251		BaseInfo,252		PartType,253		Theme,254	>255	{256		#[method(name = "rmrk_lastCollectionIdx")]257		/// Get the latest created collection id258		fn last_collection_idx(&self, at: Option<BlockHash>) -> Result<RmrkCollectionId>;259260		#[method(name = "rmrk_collectionById")]261		/// Get collection by id262		fn collection_by_id(263			&self,264			id: RmrkCollectionId,265			at: Option<BlockHash>,266		) -> Result<Option<CollectionInfo>>;267268		#[method(name = "rmrk_nftById")]269		/// Get NFT by collection id and NFT id270		fn nft_by_id(271			&self,272			collection_id: RmrkCollectionId,273			nft_id: RmrkNftId,274			at: Option<BlockHash>,275		) -> Result<Option<NftInfo>>;276277		#[method(name = "rmrk_accountTokens")]278		/// Get tokens owned by an account in a collection279		fn account_tokens(280			&self,281			account_id: AccountId,282			collection_id: RmrkCollectionId,283			at: Option<BlockHash>,284		) -> Result<Vec<RmrkNftId>>;285286		#[method(name = "rmrk_nftChildren")]287		/// Get NFT children288		fn nft_children(289			&self,290			collection_id: RmrkCollectionId,291			nft_id: RmrkNftId,292			at: Option<BlockHash>,293		) -> Result<Vec<RmrkNftChild>>;294295		#[method(name = "rmrk_collectionProperties")]296		/// Get collection properties297		fn collection_properties(298			&self,299			collection_id: RmrkCollectionId,300			filter_keys: Option<Vec<String>>,301			at: Option<BlockHash>,302		) -> Result<Vec<PropertyInfo>>;303304		#[method(name = "rmrk_nftProperties")]305		/// Get NFT properties306		fn nft_properties(307			&self,308			collection_id: RmrkCollectionId,309			nft_id: RmrkNftId,310			filter_keys: Option<Vec<String>>,311			at: Option<BlockHash>,312		) -> Result<Vec<PropertyInfo>>;313314		#[method(name = "rmrk_nftResources")]315		/// Get NFT resources316		fn nft_resources(317			&self,318			collection_id: RmrkCollectionId,319			nft_id: RmrkNftId,320			at: Option<BlockHash>,321		) -> Result<Vec<ResourceInfo>>;322323		#[method(name = "rmrk_nftResourcePriority")]324		/// Get NFT resource priority325		fn nft_resource_priority(326			&self,327			collection_id: RmrkCollectionId,328			nft_id: RmrkNftId,329			resource_id: RmrkResourceId,330			at: Option<BlockHash>,331		) -> Result<Option<u32>>;332333		#[method(name = "rmrk_base")]334		/// Get base info335		fn base(&self, base_id: RmrkBaseId, at: Option<BlockHash>) -> Result<Option<BaseInfo>>;336337		#[method(name = "rmrk_baseParts")]338		/// Get all Base's parts339		fn base_parts(&self, base_id: RmrkBaseId, at: Option<BlockHash>) -> Result<Vec<PartType>>;340341		#[method(name = "rmrk_themeNames")]342		/// Get Base's theme names343		fn theme_names(344			&self,345			base_id: RmrkBaseId,346			at: Option<BlockHash>,347		) -> Result<Vec<RmrkThemeName>>;348349		#[method(name = "rmrk_themes")]350		/// Get Theme info -- name, properties, and inherit flag351		fn theme(352			&self,353			base_id: RmrkBaseId,354			theme_name: String,355			filter_keys: Option<Vec<String>>,356			at: Option<BlockHash>,357		) -> Result<Option<Theme>>;358	}359}360361pub struct Unique<C, P> {362	client: Arc<C>,363	_marker: std::marker::PhantomData<P>,364}365366impl<C, P> Unique<C, P> {367	pub fn new(client: Arc<C>) -> Self {368		Self {369			client,370			_marker: Default::default(),371		}372	}373}374375pub struct Rmrk<C, P> {376	client: Arc<C>,377	_marker: std::marker::PhantomData<P>,378}379380impl<C, P> Rmrk<C, P> {381	pub fn new(client: Arc<C>) -> Self {382		Self {383			client,384			_marker: Default::default(),385		}386	}387}388389macro_rules! pass_method {390	(391		$method_name:ident(392			$($(#[map(|$map_arg:ident| $map:expr)])? $name:ident: $ty:ty),* $(,)?393		) -> $result:ty $(=> $mapper:expr)?,394		//$runtime_name:ident $(<$($lt: tt),+>)*395		$runtime_api_macro:ident396		$(; changed_in $ver:expr, $changed_method_name:ident ($($changed_name:expr), * $(,)?) => $fixer:expr)*397	) => {398		fn $method_name(399			&self,400			$(401				$name: $ty,402			)*403			at: Option<<Block as BlockT>::Hash>,404		) -> Result<$result> {405			let api = self.client.runtime_api();406			let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash));407			let _api_version = if let Ok(Some(api_version)) =408				api.api_version::<$runtime_api_macro!()>(&at)409			{410				api_version411			} else {412				// unreachable for our runtime413				return Err(anyhow!("api is not available").into())414			};415416			let result = $(if _api_version < $ver {417				api.$changed_method_name(&at, $($changed_name),*).map(|r| r.map($fixer))418			} else)*419			{ api.$method_name(&at, $($((|$map_arg: $ty| $map))? ($name)),*) };420421			Ok(result422				.map_err(|e| anyhow!("unable to query: {e}"))?423				.map_err(|e| anyhow!("runtime error: {e:?}"))$(.map($mapper))??)424		}425	};426}427428macro_rules! unique_api {429	() => {430		dyn UniqueRuntimeApi<Block, CrossAccountId, AccountId>431	};432}433434macro_rules! rmrk_api {435	() => {436		dyn RmrkRuntimeApi<Block, AccountId, CollectionInfo, NftInfo, ResourceInfo, PropertyInfo, BaseInfo, PartType, Theme>437	};438}439440#[allow(deprecated)]441impl<C, Block, CrossAccountId, AccountId>442	UniqueApiServer<<Block as BlockT>::Hash, CrossAccountId, AccountId> for Unique<C, Block>443where444	Block: BlockT,445	AccountId: Decode,446	C: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,447	C::Api: UniqueRuntimeApi<Block, CrossAccountId, AccountId>,448	CrossAccountId: pallet_evm::account::CrossAccountId<AccountId>,449{450	pass_method!(451		account_tokens(collection: CollectionId, account: CrossAccountId) -> Vec<TokenId>, unique_api452	);453	pass_method!(454		collection_tokens(collection: CollectionId) -> Vec<TokenId>, unique_api455	);456	pass_method!(457		token_exists(collection: CollectionId, token: TokenId) -> bool, unique_api458	);459	pass_method!(460		token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>, unique_api461	);462	pass_method!(463		topmost_token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>, unique_api464	);465	pass_method!(token_children(collection: CollectionId, token: TokenId) -> Vec<TokenChild>, unique_api);466	pass_method!(total_supply(collection: CollectionId) -> u32, unique_api);467	pass_method!(account_balance(collection: CollectionId, account: CrossAccountId) -> u32, unique_api);468	pass_method!(balance(collection: CollectionId, account: CrossAccountId, token: TokenId) -> String => |v| v.to_string(), unique_api);469	pass_method!(470		allowance(collection: CollectionId, sender: CrossAccountId, spender: CrossAccountId, token: TokenId) -> String => |v| v.to_string(),471		unique_api472	);473474	pass_method!(collection_properties(475		collection: CollectionId,476477		#[map(|keys| string_keys_to_bytes_keys(keys))]478		keys: Option<Vec<String>>479	) -> Vec<Property>, unique_api);480481	pass_method!(token_properties(482		collection: CollectionId,483		token_id: TokenId,484485		#[map(|keys| string_keys_to_bytes_keys(keys))]486		keys: Option<Vec<String>>487	) -> Vec<Property>, unique_api);488489	pass_method!(property_permissions(490		collection: CollectionId,491492		#[map(|keys| string_keys_to_bytes_keys(keys))]493		keys: Option<Vec<String>>494	) -> Vec<PropertyKeyPermission>, unique_api);495496	pass_method!(token_data(497		collection: CollectionId,498		token_id: TokenId,499500		#[map(|keys| string_keys_to_bytes_keys(keys))]501		keys: Option<Vec<String>>,502	) -> TokenData<CrossAccountId>, unique_api);503504	pass_method!(adminlist(collection: CollectionId) -> Vec<CrossAccountId>, unique_api);505	pass_method!(allowlist(collection: CollectionId) -> Vec<CrossAccountId>, unique_api);506	pass_method!(allowed(collection: CollectionId, user: CrossAccountId) -> bool, unique_api);507	pass_method!(last_token_id(collection: CollectionId) -> TokenId, unique_api);508	pass_method!(collection_by_id(collection: CollectionId) -> Option<RpcCollection<AccountId>>, unique_api);509	pass_method!(collection_stats() -> CollectionStats, unique_api);510	pass_method!(next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Option<u64>, unique_api);511	pass_method!(effective_collection_limits(collection_id: CollectionId) -> Option<CollectionLimits>, unique_api);512	pass_method!(total_pieces(collection_id: CollectionId, token_id: TokenId) -> Option<u128>, unique_api);513}514515#[allow(deprecated)]516impl<517		C,518		Block,519		AccountId,520		CollectionInfo,521		NftInfo,522		ResourceInfo,523		PropertyInfo,524		BaseInfo,525		PartType,526		Theme,527	>528	rmrk_unique_rpc::RmrkApiServer<529		<Block as BlockT>::Hash,530		AccountId,531		CollectionInfo,532		NftInfo,533		ResourceInfo,534		PropertyInfo,535		BaseInfo,536		PartType,537		Theme,538	> for Rmrk<C, Block>539where540	C: Send + Sync + 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,541	C::Api: RmrkRuntimeApi<542		Block,543		AccountId,544		CollectionInfo,545		NftInfo,546		ResourceInfo,547		PropertyInfo,548		BaseInfo,549		PartType,550		Theme,551	>,552	AccountId: Decode + Encode,553	CollectionInfo: Decode,554	NftInfo: Decode,555	ResourceInfo: Decode,556	PropertyInfo: Decode,557	BaseInfo: Decode,558	PartType: Decode,559	Theme: Decode,560	Block: BlockT,561{562	pass_method!(last_collection_idx() -> RmrkCollectionId, rmrk_api);563	pass_method!(collection_by_id(id: RmrkCollectionId) -> Option<CollectionInfo>, rmrk_api);564	pass_method!(nft_by_id(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Option<NftInfo>, rmrk_api);565	pass_method!(account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Vec<RmrkNftId>, rmrk_api);566	pass_method!(nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<RmrkNftChild>, rmrk_api);567	pass_method!(568		collection_properties(569			collection_id: RmrkCollectionId,570571			#[map(|keys| string_keys_to_bytes_keys(keys))]572			filter_keys: Option<Vec<String>>573		) -> Vec<PropertyInfo>,574		rmrk_api575	);576	pass_method!(577		nft_properties(578			collection_id: RmrkCollectionId,579			nft_id: RmrkNftId,580581			#[map(|keys| string_keys_to_bytes_keys(keys))]582			filter_keys: Option<Vec<String>>583		) -> Vec<PropertyInfo>,584		rmrk_api585	);586	pass_method!(nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<ResourceInfo>, rmrk_api);587	pass_method!(nft_resource_priority(collection_id: RmrkCollectionId, nft_id: RmrkNftId, resource_id: RmrkResourceId) -> Option<u32>, rmrk_api);588	pass_method!(base(base_id: RmrkBaseId) -> Option<BaseInfo>, rmrk_api);589	pass_method!(base_parts(base_id: RmrkBaseId) -> Vec<PartType>, rmrk_api);590	pass_method!(theme_names(base_id: RmrkBaseId) -> Vec<RmrkThemeName>, rmrk_api);591	pass_method!(592		theme(593			base_id: RmrkBaseId,594595			#[map(|n| n.into_bytes())]596			theme_name: String,597598			#[map(|keys| string_keys_to_bytes_keys(keys))]599			filter_keys: Option<Vec<String>>600		) -> Option<Theme>, rmrk_api);601}602603fn string_keys_to_bytes_keys(keys: Option<Vec<String>>) -> Option<Vec<Vec<u8>>> {604	keys.map(|keys| keys.into_iter().map(|key| key.into_bytes()).collect())605}