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

difftreelog

source

client/rpc/src/lib.rs18.7 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: CrossAccountId, at: Option<BlockHash>) -> Result<u128>;251252	///Returns the total amount of staked tokens per block when staked.253	#[method(name = "unique_totalStakedPerBlock")]254	fn total_staked_per_block(255		&self,256		staker: CrossAccountId,257		at: Option<BlockHash>,258	) -> Result<Vec<(BlockNumber, u128)>>;259260	/// Return the total amount locked by staking tokens.261	#[method(name = "unique_totalStakingLocked")]262	fn total_staking_locked(&self, staker: CrossAccountId, at: Option<BlockHash>) -> Result<u128>;263}264265mod rmrk_unique_rpc {266	use super::*;267268	#[rpc(server)]269	#[async_trait]270	pub trait RmrkApi<271		BlockHash,272		AccountId,273		CollectionInfo,274		NftInfo,275		ResourceInfo,276		PropertyInfo,277		BaseInfo,278		PartType,279		Theme,280	>281	{282		/// Get the latest created collection ID.283		#[method(name = "rmrk_lastCollectionIdx")]284		fn last_collection_idx(&self, at: Option<BlockHash>) -> Result<RmrkCollectionId>;285286		/// Get collection info by ID.287		#[method(name = "rmrk_collectionById")]288		fn collection_by_id(289			&self,290			id: RmrkCollectionId,291			at: Option<BlockHash>,292		) -> Result<Option<CollectionInfo>>;293294		/// Get NFT info by collection and NFT IDs.295		#[method(name = "rmrk_nftById")]296		fn nft_by_id(297			&self,298			collection_id: RmrkCollectionId,299			nft_id: RmrkNftId,300			at: Option<BlockHash>,301		) -> Result<Option<NftInfo>>;302303		/// Get tokens owned by an account in a collection.304		#[method(name = "rmrk_accountTokens")]305		fn account_tokens(306			&self,307			account_id: AccountId,308			collection_id: RmrkCollectionId,309			at: Option<BlockHash>,310		) -> Result<Vec<RmrkNftId>>;311312		/// Get tokens nested in an NFT - its direct children (not the children's children).313		#[method(name = "rmrk_nftChildren")]314		fn nft_children(315			&self,316			collection_id: RmrkCollectionId,317			nft_id: RmrkNftId,318			at: Option<BlockHash>,319		) -> Result<Vec<RmrkNftChild>>;320321		/// Get collection properties, created by the user - not the proxy-specific properties.322		#[method(name = "rmrk_collectionProperties")]323		fn collection_properties(324			&self,325			collection_id: RmrkCollectionId,326			filter_keys: Option<Vec<String>>,327			at: Option<BlockHash>,328		) -> Result<Vec<PropertyInfo>>;329330		/// Get NFT properties, created by the user - not the proxy-specific properties.331		#[method(name = "rmrk_nftProperties")]332		fn nft_properties(333			&self,334			collection_id: RmrkCollectionId,335			nft_id: RmrkNftId,336			filter_keys: Option<Vec<String>>,337			at: Option<BlockHash>,338		) -> Result<Vec<PropertyInfo>>;339340		/// Get data of resources of an NFT.341		#[method(name = "rmrk_nftResources")]342		fn nft_resources(343			&self,344			collection_id: RmrkCollectionId,345			nft_id: RmrkNftId,346			at: Option<BlockHash>,347		) -> Result<Vec<ResourceInfo>>;348349		/// Get the priority of a resource in an NFT.350		#[method(name = "rmrk_nftResourcePriority")]351		fn nft_resource_priority(352			&self,353			collection_id: RmrkCollectionId,354			nft_id: RmrkNftId,355			resource_id: RmrkResourceId,356			at: Option<BlockHash>,357		) -> Result<Option<u32>>;358359		/// Get base info by its ID.360		#[method(name = "rmrk_base")]361		fn base(&self, base_id: RmrkBaseId, at: Option<BlockHash>) -> Result<Option<BaseInfo>>;362363		/// Get all parts of a base.364		#[method(name = "rmrk_baseParts")]365		fn base_parts(&self, base_id: RmrkBaseId, at: Option<BlockHash>) -> Result<Vec<PartType>>;366367		/// Get the theme names belonging to a base.368		#[method(name = "rmrk_themeNames")]369		fn theme_names(370			&self,371			base_id: RmrkBaseId,372			at: Option<BlockHash>,373		) -> Result<Vec<RmrkThemeName>>;374375		/// Get theme info, including properties, optionally limited to the provided keys.376		#[method(name = "rmrk_themes")]377		fn theme(378			&self,379			base_id: RmrkBaseId,380			theme_name: String,381			filter_keys: Option<Vec<String>>,382			at: Option<BlockHash>,383		) -> Result<Option<Theme>>;384	}385}386387pub struct Unique<C, P> {388	client: Arc<C>,389	_marker: std::marker::PhantomData<P>,390}391392impl<C, P> Unique<C, P> {393	pub fn new(client: Arc<C>) -> Self {394		Self {395			client,396			_marker: Default::default(),397		}398	}399}400401pub struct Rmrk<C, P> {402	client: Arc<C>,403	_marker: std::marker::PhantomData<P>,404}405406impl<C, P> Rmrk<C, P> {407	pub fn new(client: Arc<C>) -> Self {408		Self {409			client,410			_marker: Default::default(),411		}412	}413}414415macro_rules! pass_method {416	(417		$method_name:ident(418			$($(#[map(|$map_arg:ident| $map:expr)])? $name:ident: $ty:ty),* $(,)?419		) -> $result:ty $(=> $mapper:expr)?,420		//$runtime_name:ident $(<$($lt: tt),+>)*421		$runtime_api_macro:ident422		$(; changed_in $ver:expr, $changed_method_name:ident ($($changed_name:expr), * $(,)?) => $fixer:expr)*423	) => {424		fn $method_name(425			&self,426			$(427				$name: $ty,428			)*429			at: Option<<Block as BlockT>::Hash>,430		) -> Result<$result> {431			let api = self.client.runtime_api();432			let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash));433			let _api_version = if let Ok(Some(api_version)) =434				api.api_version::<$runtime_api_macro!()>(&at)435			{436				api_version437			} else {438				// unreachable for our runtime439				return Err(anyhow!("api is not available").into())440			};441442			let result = $(if _api_version < $ver {443				api.$changed_method_name(&at, $($changed_name),*).map(|r| r.map($fixer))444			} else)*445			{ api.$method_name(&at, $($((|$map_arg: $ty| $map))? ($name)),*) };446447			Ok(result448				.map_err(|e| anyhow!("unable to query: {e}"))?449				.map_err(|e| anyhow!("runtime error: {e:?}"))$(.map($mapper))??)450		}451	};452}453454macro_rules! unique_api {455	() => {456		dyn UniqueRuntimeApi<Block, BlockNumber, CrossAccountId, AccountId>457	};458}459460macro_rules! rmrk_api {461	() => {462		dyn RmrkRuntimeApi<Block, AccountId, CollectionInfo, NftInfo, ResourceInfo, PropertyInfo, BaseInfo, PartType, Theme>463	};464}465466#[allow(deprecated)]467impl<C, Block, BlockNumber, CrossAccountId, AccountId>468	UniqueApiServer<<Block as BlockT>::Hash, BlockNumber, CrossAccountId, AccountId>469	for Unique<C, Block>470where471	Block: BlockT,472	BlockNumber: Decode + Member + AtLeast32BitUnsigned,473	AccountId: Decode,474	C: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,475	C::Api: UniqueRuntimeApi<Block, BlockNumber, CrossAccountId, AccountId>,476	CrossAccountId: pallet_evm::account::CrossAccountId<AccountId>,477{478	pass_method!(479		account_tokens(collection: CollectionId, account: CrossAccountId) -> Vec<TokenId>, unique_api480	);481	pass_method!(482		collection_tokens(collection: CollectionId) -> Vec<TokenId>, unique_api483	);484	pass_method!(485		token_exists(collection: CollectionId, token: TokenId) -> bool, unique_api486	);487	pass_method!(488		token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>, unique_api489	);490	pass_method!(491		topmost_token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>, unique_api492	);493	pass_method!(token_children(collection: CollectionId, token: TokenId) -> Vec<TokenChild>, unique_api);494	pass_method!(total_supply(collection: CollectionId) -> u32, unique_api);495	pass_method!(account_balance(collection: CollectionId, account: CrossAccountId) -> u32, unique_api);496	pass_method!(balance(collection: CollectionId, account: CrossAccountId, token: TokenId) -> String => |v| v.to_string(), unique_api);497	pass_method!(498		allowance(collection: CollectionId, sender: CrossAccountId, spender: CrossAccountId, token: TokenId) -> String => |v| v.to_string(),499		unique_api500	);501502	pass_method!(collection_properties(503		collection: CollectionId,504505		#[map(|keys| string_keys_to_bytes_keys(keys))]506		keys: Option<Vec<String>>507	) -> Vec<Property>, unique_api);508509	pass_method!(token_properties(510		collection: CollectionId,511		token_id: TokenId,512513		#[map(|keys| string_keys_to_bytes_keys(keys))]514		keys: Option<Vec<String>>515	) -> Vec<Property>, unique_api);516517	pass_method!(property_permissions(518		collection: CollectionId,519520		#[map(|keys| string_keys_to_bytes_keys(keys))]521		keys: Option<Vec<String>>522	) -> Vec<PropertyKeyPermission>, unique_api);523524	pass_method!(token_data(525		collection: CollectionId,526		token_id: TokenId,527528		#[map(|keys| string_keys_to_bytes_keys(keys))]529		keys: Option<Vec<String>>,530	) -> TokenData<CrossAccountId>, unique_api);531532	pass_method!(adminlist(collection: CollectionId) -> Vec<CrossAccountId>, unique_api);533	pass_method!(allowlist(collection: CollectionId) -> Vec<CrossAccountId>, unique_api);534	pass_method!(allowed(collection: CollectionId, user: CrossAccountId) -> bool, unique_api);535	pass_method!(last_token_id(collection: CollectionId) -> TokenId, unique_api);536	pass_method!(collection_by_id(collection: CollectionId) -> Option<RpcCollection<AccountId>>, unique_api);537	pass_method!(collection_stats() -> CollectionStats, unique_api);538	pass_method!(next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Option<u64>, unique_api);539	pass_method!(effective_collection_limits(collection_id: CollectionId) -> Option<CollectionLimits>, unique_api);540	pass_method!(total_pieces(collection_id: CollectionId, token_id: TokenId) -> Option<String> => |o| o.map(|number| number.to_string()) , unique_api);541	pass_method!(token_owners(collection: CollectionId, token: TokenId) -> Vec<CrossAccountId>, unique_api);542	pass_method!(total_staked(staker: CrossAccountId) -> u128, unique_api);543	pass_method!(total_staked_per_block(staker: CrossAccountId) -> Vec<(BlockNumber, u128)>, unique_api);544	pass_method!(total_staking_locked(staker: CrossAccountId) -> u128, unique_api);545}546547#[allow(deprecated)]548impl<549		C,550		Block,551		AccountId,552		CollectionInfo,553		NftInfo,554		ResourceInfo,555		PropertyInfo,556		BaseInfo,557		PartType,558		Theme,559	>560	rmrk_unique_rpc::RmrkApiServer<561		<Block as BlockT>::Hash,562		AccountId,563		CollectionInfo,564		NftInfo,565		ResourceInfo,566		PropertyInfo,567		BaseInfo,568		PartType,569		Theme,570	> for Rmrk<C, Block>571where572	C: Send + Sync + 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,573	C::Api: RmrkRuntimeApi<574		Block,575		AccountId,576		CollectionInfo,577		NftInfo,578		ResourceInfo,579		PropertyInfo,580		BaseInfo,581		PartType,582		Theme,583	>,584	AccountId: Decode + Encode,585	CollectionInfo: Decode,586	NftInfo: Decode,587	ResourceInfo: Decode,588	PropertyInfo: Decode,589	BaseInfo: Decode,590	PartType: Decode,591	Theme: Decode,592	Block: BlockT,593{594	pass_method!(last_collection_idx() -> RmrkCollectionId, rmrk_api);595	pass_method!(collection_by_id(id: RmrkCollectionId) -> Option<CollectionInfo>, rmrk_api);596	pass_method!(nft_by_id(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Option<NftInfo>, rmrk_api);597	pass_method!(account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Vec<RmrkNftId>, rmrk_api);598	pass_method!(nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<RmrkNftChild>, rmrk_api);599	pass_method!(600		collection_properties(601			collection_id: RmrkCollectionId,602603			#[map(|keys| string_keys_to_bytes_keys(keys))]604			filter_keys: Option<Vec<String>>605		) -> Vec<PropertyInfo>,606		rmrk_api607	);608	pass_method!(609		nft_properties(610			collection_id: RmrkCollectionId,611			nft_id: RmrkNftId,612613			#[map(|keys| string_keys_to_bytes_keys(keys))]614			filter_keys: Option<Vec<String>>615		) -> Vec<PropertyInfo>,616		rmrk_api617	);618	pass_method!(nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<ResourceInfo>, rmrk_api);619	pass_method!(nft_resource_priority(collection_id: RmrkCollectionId, nft_id: RmrkNftId, resource_id: RmrkResourceId) -> Option<u32>, rmrk_api);620	pass_method!(base(base_id: RmrkBaseId) -> Option<BaseInfo>, rmrk_api);621	pass_method!(base_parts(base_id: RmrkBaseId) -> Vec<PartType>, rmrk_api);622	pass_method!(theme_names(base_id: RmrkBaseId) -> Vec<RmrkThemeName>, rmrk_api);623	pass_method!(624		theme(625			base_id: RmrkBaseId,626627			#[map(|n| n.into_bytes())]628			theme_name: String,629630			#[map(|keys| string_keys_to_bytes_keys(keys))]631			filter_keys: Option<Vec<String>>632		) -> Option<Theme>, rmrk_api);633}634635fn string_keys_to_bytes_keys(keys: Option<Vec<String>>) -> Option<Vec<Vec<u8>>> {636	keys.map(|keys| keys.into_iter().map(|key| key.into_bytes()).collect())637}