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

difftreelog

source

client/rpc/src/lib.rs18.8 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 sp_runtime::traits::{AtLeast32BitUnsigned, Member};27use up_data_structs::{28	RpcCollection, CollectionId, CollectionStats, CollectionLimits, TokenId, Property,29	PropertyKeyPermission, TokenData, TokenChild,30};31use sp_api::{BlockId, BlockT, ProvideRuntimeApi, ApiExt};32use sp_blockchain::HeaderBackend;33use up_rpc::UniqueApi as UniqueRuntimeApi;3435// RMRK36use rmrk_rpc::RmrkApi as RmrkRuntimeApi;37use up_data_structs::{38	RmrkCollectionId, RmrkNftId, RmrkBaseId, RmrkNftChild, RmrkThemeName, RmrkResourceId,39};4041pub use rmrk_unique_rpc::RmrkApiServer;4243#[rpc(server)]44#[async_trait]45pub trait UniqueApi<BlockHash, BlockNumber, CrossAccountId, AccountId> {46	/// Get tokens owned by account.47	#[method(name = "unique_accountTokens")]48	fn account_tokens(49		&self,50		collection: CollectionId,51		account: CrossAccountId,52		at: Option<BlockHash>,53	) -> Result<Vec<TokenId>>;5455	/// Get tokens contained within a collection.56	#[method(name = "unique_collectionTokens")]57	fn collection_tokens(58		&self,59		collection: CollectionId,60		at: Option<BlockHash>,61	) -> Result<Vec<TokenId>>;6263	/// Check if the token exists.64	#[method(name = "unique_tokenExists")]65	fn token_exists(66		&self,67		collection: CollectionId,68		token: TokenId,69		at: Option<BlockHash>,70	) -> Result<bool>;7172	/// Get the token owner.73	#[method(name = "unique_tokenOwner")]74	fn token_owner(75		&self,76		collection: CollectionId,77		token: TokenId,78		at: Option<BlockHash>,79	) -> Result<Option<CrossAccountId>>;8081	/// Returns 10 tokens owners in no particular order.82	#[method(name = "unique_tokenOwners")]83	fn token_owners(84		&self,85		collection: CollectionId,86		token: TokenId,87		at: Option<BlockHash>,88	) -> Result<Vec<CrossAccountId>>;8990	/// Get the topmost token owner in the hierarchy of a possibly nested token.91	#[method(name = "unique_topmostTokenOwner")]92	fn topmost_token_owner(93		&self,94		collection: CollectionId,95		token: TokenId,96		at: Option<BlockHash>,97	) -> Result<Option<CrossAccountId>>;9899	/// Get tokens nested directly into the token.100	#[method(name = "unique_tokenChildren")]101	fn token_children(102		&self,103		collection: CollectionId,104		token: TokenId,105		at: Option<BlockHash>,106	) -> Result<Vec<TokenChild>>;107108	/// Get collection properties, optionally limited to the provided keys.109	#[method(name = "unique_collectionProperties")]110	fn collection_properties(111		&self,112		collection: CollectionId,113		keys: Option<Vec<String>>,114		at: Option<BlockHash>,115	) -> Result<Vec<Property>>;116117	/// Get token properties, optionally limited to the provided keys.118	#[method(name = "unique_tokenProperties")]119	fn token_properties(120		&self,121		collection: CollectionId,122		token_id: TokenId,123		keys: Option<Vec<String>>,124		at: Option<BlockHash>,125	) -> Result<Vec<Property>>;126127	/// Get property permissions, optionally limited to the provided keys.128	#[method(name = "unique_propertyPermissions")]129	fn property_permissions(130		&self,131		collection: CollectionId,132		keys: Option<Vec<String>>,133		at: Option<BlockHash>,134	) -> Result<Vec<PropertyKeyPermission>>;135136	/// Get token data, including properties, optionally limited to the provided keys, and total pieces for an RFT.137	#[method(name = "unique_tokenData")]138	fn token_data(139		&self,140		collection: CollectionId,141		token_id: TokenId,142		keys: Option<Vec<String>>,143		at: Option<BlockHash>,144	) -> Result<TokenData<CrossAccountId>>;145146	/// Get the amount of distinctive tokens present in a collection.147	#[method(name = "unique_totalSupply")]148	fn total_supply(&self, collection: CollectionId, at: Option<BlockHash>) -> Result<u32>;149150	/// Get the amount of any user tokens owned by an account.151	#[method(name = "unique_accountBalance")]152	fn account_balance(153		&self,154		collection: CollectionId,155		account: CrossAccountId,156		at: Option<BlockHash>,157	) -> Result<u32>;158159	/// Get the amount of a specific token owned by an account.160	#[method(name = "unique_balance")]161	fn balance(162		&self,163		collection: CollectionId,164		account: CrossAccountId,165		token: TokenId,166		at: Option<BlockHash>,167	) -> Result<String>;168169	/// Get the amount of currently possible sponsored transactions on a token for the fee to be taken off a sponsor.170	#[method(name = "unique_allowance")]171	fn allowance(172		&self,173		collection: CollectionId,174		sender: CrossAccountId,175		spender: CrossAccountId,176		token: TokenId,177		at: Option<BlockHash>,178	) -> Result<String>;179180	/// Get the list of admin accounts of a collection.181	#[method(name = "unique_adminlist")]182	fn adminlist(183		&self,184		collection: CollectionId,185		at: Option<BlockHash>,186	) -> Result<Vec<CrossAccountId>>;187188	/// Get the list of accounts allowed to operate within a collection.189	#[method(name = "unique_allowlist")]190	fn allowlist(191		&self,192		collection: CollectionId,193		at: Option<BlockHash>,194	) -> Result<Vec<CrossAccountId>>;195196	/// Check if a user is allowed to operate within a collection.197	#[method(name = "unique_allowed")]198	fn allowed(199		&self,200		collection: CollectionId,201		user: CrossAccountId,202		at: Option<BlockHash>,203	) -> Result<bool>;204205	/// Get the last token ID created in a collection.206	#[method(name = "unique_lastTokenId")]207	fn last_token_id(&self, collection: CollectionId, at: Option<BlockHash>) -> Result<TokenId>;208209	/// Get collection info by the specified ID.210	#[method(name = "unique_collectionById")]211	fn collection_by_id(212		&self,213		collection: CollectionId,214		at: Option<BlockHash>,215	) -> Result<Option<RpcCollection<AccountId>>>;216217	/// Get chain stats about collections.218	#[method(name = "unique_collectionStats")]219	fn collection_stats(&self, at: Option<BlockHash>) -> Result<CollectionStats>;220221	/// Get the number of blocks until sponsoring a transaction is available.222	#[method(name = "unique_nextSponsored")]223	fn next_sponsored(224		&self,225		collection: CollectionId,226		account: CrossAccountId,227		token: TokenId,228		at: Option<BlockHash>,229	) -> Result<Option<u64>>;230231	/// Get effective collection limits. If not explicitly set, get the chain defaults.232	#[method(name = "unique_effectiveCollectionLimits")]233	fn effective_collection_limits(234		&self,235		collection_id: CollectionId,236		at: Option<BlockHash>,237	) -> Result<Option<CollectionLimits>>;238239	/// Get the total amount of pieces of an RFT.240	#[method(name = "unique_totalPieces")]241	fn total_pieces(242		&self,243		collection_id: CollectionId,244		token_id: TokenId,245		at: Option<BlockHash>,246	) -> Result<Option<u128>>;247248	/// Returns the total amount of staked tokens.249	#[method(name = "unique_totalStaked")]250	fn total_staked(&self, staker: Option<CrossAccountId>, at: Option<BlockHash>)251		-> Result<String>;252253	///Returns the total amount of staked tokens per block when staked.254	#[method(name = "unique_totalStakedPerBlock")]255	fn total_staked_per_block(256		&self,257		staker: CrossAccountId,258		at: Option<BlockHash>,259	) -> Result<Vec<(BlockNumber, String)>>;260261	/// Return the total amount locked by staking tokens.262	#[method(name = "unique_totalStakingLocked")]263	fn total_staking_locked(&self, staker: CrossAccountId, at: Option<BlockHash>)264		-> Result<String>;265}266267mod rmrk_unique_rpc {268	use super::*;269270	#[rpc(server)]271	#[async_trait]272	pub trait RmrkApi<273		BlockHash,274		AccountId,275		CollectionInfo,276		NftInfo,277		ResourceInfo,278		PropertyInfo,279		BaseInfo,280		PartType,281		Theme,282	>283	{284		/// Get the latest created collection ID.285		#[method(name = "rmrk_lastCollectionIdx")]286		fn last_collection_idx(&self, at: Option<BlockHash>) -> Result<RmrkCollectionId>;287288		/// Get collection info by ID.289		#[method(name = "rmrk_collectionById")]290		fn collection_by_id(291			&self,292			id: RmrkCollectionId,293			at: Option<BlockHash>,294		) -> Result<Option<CollectionInfo>>;295296		/// Get NFT info by collection and NFT IDs.297		#[method(name = "rmrk_nftById")]298		fn nft_by_id(299			&self,300			collection_id: RmrkCollectionId,301			nft_id: RmrkNftId,302			at: Option<BlockHash>,303		) -> Result<Option<NftInfo>>;304305		/// Get tokens owned by an account in a collection.306		#[method(name = "rmrk_accountTokens")]307		fn account_tokens(308			&self,309			account_id: AccountId,310			collection_id: RmrkCollectionId,311			at: Option<BlockHash>,312		) -> Result<Vec<RmrkNftId>>;313314		/// Get tokens nested in an NFT - its direct children (not the children's children).315		#[method(name = "rmrk_nftChildren")]316		fn nft_children(317			&self,318			collection_id: RmrkCollectionId,319			nft_id: RmrkNftId,320			at: Option<BlockHash>,321		) -> Result<Vec<RmrkNftChild>>;322323		/// Get collection properties, created by the user - not the proxy-specific properties.324		#[method(name = "rmrk_collectionProperties")]325		fn collection_properties(326			&self,327			collection_id: RmrkCollectionId,328			filter_keys: Option<Vec<String>>,329			at: Option<BlockHash>,330		) -> Result<Vec<PropertyInfo>>;331332		/// Get NFT properties, created by the user - not the proxy-specific properties.333		#[method(name = "rmrk_nftProperties")]334		fn nft_properties(335			&self,336			collection_id: RmrkCollectionId,337			nft_id: RmrkNftId,338			filter_keys: Option<Vec<String>>,339			at: Option<BlockHash>,340		) -> Result<Vec<PropertyInfo>>;341342		/// Get data of resources of an NFT.343		#[method(name = "rmrk_nftResources")]344		fn nft_resources(345			&self,346			collection_id: RmrkCollectionId,347			nft_id: RmrkNftId,348			at: Option<BlockHash>,349		) -> Result<Vec<ResourceInfo>>;350351		/// Get the priority of a resource in an NFT.352		#[method(name = "rmrk_nftResourcePriority")]353		fn nft_resource_priority(354			&self,355			collection_id: RmrkCollectionId,356			nft_id: RmrkNftId,357			resource_id: RmrkResourceId,358			at: Option<BlockHash>,359		) -> Result<Option<u32>>;360361		/// Get base info by its ID.362		#[method(name = "rmrk_base")]363		fn base(&self, base_id: RmrkBaseId, at: Option<BlockHash>) -> Result<Option<BaseInfo>>;364365		/// Get all parts of a base.366		#[method(name = "rmrk_baseParts")]367		fn base_parts(&self, base_id: RmrkBaseId, at: Option<BlockHash>) -> Result<Vec<PartType>>;368369		/// Get the theme names belonging to a base.370		#[method(name = "rmrk_themeNames")]371		fn theme_names(372			&self,373			base_id: RmrkBaseId,374			at: Option<BlockHash>,375		) -> Result<Vec<RmrkThemeName>>;376377		/// Get theme info, including properties, optionally limited to the provided keys.378		#[method(name = "rmrk_themes")]379		fn theme(380			&self,381			base_id: RmrkBaseId,382			theme_name: String,383			filter_keys: Option<Vec<String>>,384			at: Option<BlockHash>,385		) -> Result<Option<Theme>>;386	}387}388389pub struct Unique<C, P> {390	client: Arc<C>,391	_marker: std::marker::PhantomData<P>,392}393394impl<C, P> Unique<C, P> {395	pub fn new(client: Arc<C>) -> Self {396		Self {397			client,398			_marker: Default::default(),399		}400	}401}402403pub struct Rmrk<C, P> {404	client: Arc<C>,405	_marker: std::marker::PhantomData<P>,406}407408impl<C, P> Rmrk<C, P> {409	pub fn new(client: Arc<C>) -> Self {410		Self {411			client,412			_marker: Default::default(),413		}414	}415}416417macro_rules! pass_method {418	(419		$method_name:ident(420			$($(#[map(|$map_arg:ident| $map:expr)])? $name:ident: $ty:ty),* $(,)?421		) -> $result:ty $(=> $mapper:expr)?,422		//$runtime_name:ident $(<$($lt: tt),+>)*423		$runtime_api_macro:ident424		$(; changed_in $ver:expr, $changed_method_name:ident ($($changed_name:expr), * $(,)?) => $fixer:expr)*425	) => {426		fn $method_name(427			&self,428			$(429				$name: $ty,430			)*431			at: Option<<Block as BlockT>::Hash>,432		) -> Result<$result> {433			let api = self.client.runtime_api();434			let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash));435			let _api_version = if let Ok(Some(api_version)) =436				api.api_version::<$runtime_api_macro!()>(&at)437			{438				api_version439			} else {440				// unreachable for our runtime441				return Err(anyhow!("api is not available").into())442			};443444			let result = $(if _api_version < $ver {445				api.$changed_method_name(&at, $($changed_name),*).map(|r| r.map($fixer))446			} else)*447			{ api.$method_name(&at, $($((|$map_arg: $ty| $map))? ($name)),*) };448449			Ok(result450				.map_err(|e| anyhow!("unable to query: {e}"))?451				.map_err(|e| anyhow!("runtime error: {e:?}"))$(.map($mapper))??)452		}453	};454}455456macro_rules! unique_api {457	() => {458		dyn UniqueRuntimeApi<Block, BlockNumber, CrossAccountId, AccountId>459	};460}461462macro_rules! rmrk_api {463	() => {464		dyn RmrkRuntimeApi<Block, AccountId, CollectionInfo, NftInfo, ResourceInfo, PropertyInfo, BaseInfo, PartType, Theme>465	};466}467468#[allow(deprecated)]469impl<C, Block, BlockNumber, CrossAccountId, AccountId>470	UniqueApiServer<<Block as BlockT>::Hash, BlockNumber, CrossAccountId, AccountId>471	for Unique<C, Block>472where473	Block: BlockT,474	BlockNumber: Decode + Member + AtLeast32BitUnsigned,475	AccountId: Decode,476	C: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,477	C::Api: UniqueRuntimeApi<Block, BlockNumber, CrossAccountId, AccountId>,478	CrossAccountId: pallet_evm::account::CrossAccountId<AccountId>,479{480	pass_method!(481		account_tokens(collection: CollectionId, account: CrossAccountId) -> Vec<TokenId>, unique_api482	);483	pass_method!(484		collection_tokens(collection: CollectionId) -> Vec<TokenId>, unique_api485	);486	pass_method!(487		token_exists(collection: CollectionId, token: TokenId) -> bool, unique_api488	);489	pass_method!(490		token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>, unique_api491	);492	pass_method!(493		topmost_token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>, unique_api494	);495	pass_method!(token_children(collection: CollectionId, token: TokenId) -> Vec<TokenChild>, unique_api);496	pass_method!(total_supply(collection: CollectionId) -> u32, unique_api);497	pass_method!(account_balance(collection: CollectionId, account: CrossAccountId) -> u32, unique_api);498	pass_method!(balance(collection: CollectionId, account: CrossAccountId, token: TokenId) -> String => |v| v.to_string(), unique_api);499	pass_method!(500		allowance(collection: CollectionId, sender: CrossAccountId, spender: CrossAccountId, token: TokenId) -> String => |v| v.to_string(),501		unique_api502	);503504	pass_method!(collection_properties(505		collection: CollectionId,506507		#[map(|keys| string_keys_to_bytes_keys(keys))]508		keys: Option<Vec<String>>509	) -> Vec<Property>, unique_api);510511	pass_method!(token_properties(512		collection: CollectionId,513		token_id: TokenId,514515		#[map(|keys| string_keys_to_bytes_keys(keys))]516		keys: Option<Vec<String>>517	) -> Vec<Property>, unique_api);518519	pass_method!(property_permissions(520		collection: CollectionId,521522		#[map(|keys| string_keys_to_bytes_keys(keys))]523		keys: Option<Vec<String>>524	) -> Vec<PropertyKeyPermission>, unique_api);525526	pass_method!(token_data(527		collection: CollectionId,528		token_id: TokenId,529530		#[map(|keys| string_keys_to_bytes_keys(keys))]531		keys: Option<Vec<String>>,532	) -> TokenData<CrossAccountId>, unique_api);533534	pass_method!(adminlist(collection: CollectionId) -> Vec<CrossAccountId>, unique_api);535	pass_method!(allowlist(collection: CollectionId) -> Vec<CrossAccountId>, unique_api);536	pass_method!(allowed(collection: CollectionId, user: CrossAccountId) -> bool, unique_api);537	pass_method!(last_token_id(collection: CollectionId) -> TokenId, unique_api);538	pass_method!(collection_by_id(collection: CollectionId) -> Option<RpcCollection<AccountId>>, unique_api);539	pass_method!(collection_stats() -> CollectionStats, unique_api);540	pass_method!(next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Option<u64>, unique_api);541	pass_method!(effective_collection_limits(collection_id: CollectionId) -> Option<CollectionLimits>, unique_api);542	pass_method!(total_pieces(collection_id: CollectionId, token_id: TokenId) -> Option<String> => |o| o.map(|number| number.to_string()) , unique_api);543	pass_method!(token_owners(collection: CollectionId, token: TokenId) -> Vec<CrossAccountId>, unique_api);544	pass_method!(total_staked(staker: Option<CrossAccountId>) -> String => |v| v.to_string(), unique_api);545	pass_method!(total_staked_per_block(staker: CrossAccountId) -> Vec<(BlockNumber, String)> =>546		|v| v547		.into_iter()548		.map(|(b, a)| (b, a.to_string()))549		.collect::<Vec<_>>(), unique_api);550	pass_method!(total_staking_locked(staker: CrossAccountId) -> String => |v| v.to_string(), unique_api);551}552553#[allow(deprecated)]554impl<555		C,556		Block,557		AccountId,558		CollectionInfo,559		NftInfo,560		ResourceInfo,561		PropertyInfo,562		BaseInfo,563		PartType,564		Theme,565	>566	rmrk_unique_rpc::RmrkApiServer<567		<Block as BlockT>::Hash,568		AccountId,569		CollectionInfo,570		NftInfo,571		ResourceInfo,572		PropertyInfo,573		BaseInfo,574		PartType,575		Theme,576	> for Rmrk<C, Block>577where578	C: Send + Sync + 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,579	C::Api: RmrkRuntimeApi<580		Block,581		AccountId,582		CollectionInfo,583		NftInfo,584		ResourceInfo,585		PropertyInfo,586		BaseInfo,587		PartType,588		Theme,589	>,590	AccountId: Decode + Encode,591	CollectionInfo: Decode,592	NftInfo: Decode,593	ResourceInfo: Decode,594	PropertyInfo: Decode,595	BaseInfo: Decode,596	PartType: Decode,597	Theme: Decode,598	Block: BlockT,599{600	pass_method!(last_collection_idx() -> RmrkCollectionId, rmrk_api);601	pass_method!(collection_by_id(id: RmrkCollectionId) -> Option<CollectionInfo>, rmrk_api);602	pass_method!(nft_by_id(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Option<NftInfo>, rmrk_api);603	pass_method!(account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Vec<RmrkNftId>, rmrk_api);604	pass_method!(nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<RmrkNftChild>, rmrk_api);605	pass_method!(606		collection_properties(607			collection_id: RmrkCollectionId,608609			#[map(|keys| string_keys_to_bytes_keys(keys))]610			filter_keys: Option<Vec<String>>611		) -> Vec<PropertyInfo>,612		rmrk_api613	);614	pass_method!(615		nft_properties(616			collection_id: RmrkCollectionId,617			nft_id: RmrkNftId,618619			#[map(|keys| string_keys_to_bytes_keys(keys))]620			filter_keys: Option<Vec<String>>621		) -> Vec<PropertyInfo>,622		rmrk_api623	);624	pass_method!(nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<ResourceInfo>, rmrk_api);625	pass_method!(nft_resource_priority(collection_id: RmrkCollectionId, nft_id: RmrkNftId, resource_id: RmrkResourceId) -> Option<u32>, rmrk_api);626	pass_method!(base(base_id: RmrkBaseId) -> Option<BaseInfo>, rmrk_api);627	pass_method!(base_parts(base_id: RmrkBaseId) -> Vec<PartType>, rmrk_api);628	pass_method!(theme_names(base_id: RmrkBaseId) -> Vec<RmrkThemeName>, rmrk_api);629	pass_method!(630		theme(631			base_id: RmrkBaseId,632633			#[map(|n| n.into_bytes())]634			theme_name: String,635636			#[map(|keys| string_keys_to_bytes_keys(keys))]637			filter_keys: Option<Vec<String>>638		) -> Option<Theme>, rmrk_api);639}640641fn string_keys_to_bytes_keys(keys: Option<Vec<String>>) -> Option<Vec<Vec<u8>>> {642	keys.map(|keys| keys.into_iter().map(|key| key.into_bytes()).collect())643}