git.delta.rocks / unique-network / refs/commits / 982476ef99fe

difftreelog

source

client/rpc/src/lib.rs19.6 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<String>>;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	/// Returns 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>;265266	/// Returns the total amount of tokens pending withdrawal from staking.267	#[method(name = "unique_pendingUnstake")]268	fn pending_unstake(269		&self,270		staker: Option<CrossAccountId>,271		at: Option<BlockHash>,272	) -> Result<String>;273	/// Returns the total amount of tokens pending withdrawal from staking per block.274	#[method(name = "unique_pendingUnstakePerBlock")]275	fn pending_unstake_per_block(276		&self,277		staker: CrossAccountId,278		at: Option<BlockHash>,279	) -> Result<Vec<(BlockNumber, String)>>;280}281282mod rmrk_unique_rpc {283	use super::*;284285	#[rpc(server)]286	#[async_trait]287	pub trait RmrkApi<288		BlockHash,289		AccountId,290		CollectionInfo,291		NftInfo,292		ResourceInfo,293		PropertyInfo,294		BaseInfo,295		PartType,296		Theme,297	>298	{299		/// Get the latest created collection ID.300		#[method(name = "rmrk_lastCollectionIdx")]301		fn last_collection_idx(&self, at: Option<BlockHash>) -> Result<RmrkCollectionId>;302303		/// Get collection info by ID.304		#[method(name = "rmrk_collectionById")]305		fn collection_by_id(306			&self,307			id: RmrkCollectionId,308			at: Option<BlockHash>,309		) -> Result<Option<CollectionInfo>>;310311		/// Get NFT info by collection and NFT IDs.312		#[method(name = "rmrk_nftById")]313		fn nft_by_id(314			&self,315			collection_id: RmrkCollectionId,316			nft_id: RmrkNftId,317			at: Option<BlockHash>,318		) -> Result<Option<NftInfo>>;319320		/// Get tokens owned by an account in a collection.321		#[method(name = "rmrk_accountTokens")]322		fn account_tokens(323			&self,324			account_id: AccountId,325			collection_id: RmrkCollectionId,326			at: Option<BlockHash>,327		) -> Result<Vec<RmrkNftId>>;328329		/// Get tokens nested in an NFT - its direct children (not the children's children).330		#[method(name = "rmrk_nftChildren")]331		fn nft_children(332			&self,333			collection_id: RmrkCollectionId,334			nft_id: RmrkNftId,335			at: Option<BlockHash>,336		) -> Result<Vec<RmrkNftChild>>;337338		/// Get collection properties, created by the user - not the proxy-specific properties.339		#[method(name = "rmrk_collectionProperties")]340		fn collection_properties(341			&self,342			collection_id: RmrkCollectionId,343			filter_keys: Option<Vec<String>>,344			at: Option<BlockHash>,345		) -> Result<Vec<PropertyInfo>>;346347		/// Get NFT properties, created by the user - not the proxy-specific properties.348		#[method(name = "rmrk_nftProperties")]349		fn nft_properties(350			&self,351			collection_id: RmrkCollectionId,352			nft_id: RmrkNftId,353			filter_keys: Option<Vec<String>>,354			at: Option<BlockHash>,355		) -> Result<Vec<PropertyInfo>>;356357		/// Get data of resources of an NFT.358		#[method(name = "rmrk_nftResources")]359		fn nft_resources(360			&self,361			collection_id: RmrkCollectionId,362			nft_id: RmrkNftId,363			at: Option<BlockHash>,364		) -> Result<Vec<ResourceInfo>>;365366		/// Get the priority of a resource in an NFT.367		#[method(name = "rmrk_nftResourcePriority")]368		fn nft_resource_priority(369			&self,370			collection_id: RmrkCollectionId,371			nft_id: RmrkNftId,372			resource_id: RmrkResourceId,373			at: Option<BlockHash>,374		) -> Result<Option<u32>>;375376		/// Get base info by its ID.377		#[method(name = "rmrk_base")]378		fn base(&self, base_id: RmrkBaseId, at: Option<BlockHash>) -> Result<Option<BaseInfo>>;379380		/// Get all parts of a base.381		#[method(name = "rmrk_baseParts")]382		fn base_parts(&self, base_id: RmrkBaseId, at: Option<BlockHash>) -> Result<Vec<PartType>>;383384		/// Get the theme names belonging to a base.385		#[method(name = "rmrk_themeNames")]386		fn theme_names(387			&self,388			base_id: RmrkBaseId,389			at: Option<BlockHash>,390		) -> Result<Vec<RmrkThemeName>>;391392		/// Get theme info, including properties, optionally limited to the provided keys.393		#[method(name = "rmrk_themes")]394		fn theme(395			&self,396			base_id: RmrkBaseId,397			theme_name: String,398			filter_keys: Option<Vec<String>>,399			at: Option<BlockHash>,400		) -> Result<Option<Theme>>;401	}402}403404pub struct Unique<C, P> {405	client: Arc<C>,406	_marker: std::marker::PhantomData<P>,407}408409impl<C, P> Unique<C, P> {410	pub fn new(client: Arc<C>) -> Self {411		Self {412			client,413			_marker: Default::default(),414		}415	}416}417418pub struct Rmrk<C, P> {419	client: Arc<C>,420	_marker: std::marker::PhantomData<P>,421}422423impl<C, P> Rmrk<C, P> {424	pub fn new(client: Arc<C>) -> Self {425		Self {426			client,427			_marker: Default::default(),428		}429	}430}431432macro_rules! pass_method {433	(434		$method_name:ident(435			$($(#[map(|$map_arg:ident| $map:expr)])? $name:ident: $ty:ty),* $(,)?436		) -> $result:ty $(=> $mapper:expr)?,437		//$runtime_name:ident $(<$($lt: tt),+>)*438		$runtime_api_macro:ident439		$(; changed_in $ver:expr, $changed_method_name:ident ($($changed_name:expr), * $(,)?) => $fixer:expr)*440	) => {441		fn $method_name(442			&self,443			$(444				$name: $ty,445			)*446			at: Option<<Block as BlockT>::Hash>,447		) -> Result<$result> {448			let api = self.client.runtime_api();449			let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash));450			let _api_version = if let Ok(Some(api_version)) =451				api.api_version::<$runtime_api_macro!()>(&at)452			{453				api_version454			} else {455				// unreachable for our runtime456				return Err(anyhow!("api is not available").into())457			};458459			let result = $(if _api_version < $ver {460				api.$changed_method_name(&at, $($changed_name),*).map(|r| r.map($fixer))461			} else)*462			{ api.$method_name(&at, $($((|$map_arg: $ty| $map))? ($name)),*) };463464			Ok(result465				.map_err(|e| anyhow!("unable to query: {e}"))?466				.map_err(|e| anyhow!("runtime error: {e:?}"))$(.map($mapper))??)467		}468	};469}470471macro_rules! unique_api {472	() => {473		dyn UniqueRuntimeApi<Block, BlockNumber, CrossAccountId, AccountId>474	};475}476477macro_rules! rmrk_api {478	() => {479		dyn RmrkRuntimeApi<Block, AccountId, CollectionInfo, NftInfo, ResourceInfo, PropertyInfo, BaseInfo, PartType, Theme>480	};481}482483#[allow(deprecated)]484impl<C, Block, BlockNumber, CrossAccountId, AccountId>485	UniqueApiServer<<Block as BlockT>::Hash, BlockNumber, CrossAccountId, AccountId>486	for Unique<C, Block>487where488	Block: BlockT,489	BlockNumber: Decode + Member + AtLeast32BitUnsigned,490	AccountId: Decode,491	C: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,492	C::Api: UniqueRuntimeApi<Block, BlockNumber, CrossAccountId, AccountId>,493	CrossAccountId: pallet_evm::account::CrossAccountId<AccountId>,494{495	pass_method!(496		account_tokens(collection: CollectionId, account: CrossAccountId) -> Vec<TokenId>, unique_api497	);498	pass_method!(499		collection_tokens(collection: CollectionId) -> Vec<TokenId>, unique_api500	);501	pass_method!(502		token_exists(collection: CollectionId, token: TokenId) -> bool, unique_api503	);504	pass_method!(505		token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>, unique_api506	);507	pass_method!(508		topmost_token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>, unique_api509	);510	pass_method!(token_children(collection: CollectionId, token: TokenId) -> Vec<TokenChild>, unique_api);511	pass_method!(total_supply(collection: CollectionId) -> u32, unique_api);512	pass_method!(account_balance(collection: CollectionId, account: CrossAccountId) -> u32, unique_api);513	pass_method!(balance(collection: CollectionId, account: CrossAccountId, token: TokenId) -> String => |v| v.to_string(), unique_api);514	pass_method!(515		allowance(collection: CollectionId, sender: CrossAccountId, spender: CrossAccountId, token: TokenId) -> String => |v| v.to_string(),516		unique_api517	);518519	pass_method!(collection_properties(520		collection: CollectionId,521522		#[map(|keys| string_keys_to_bytes_keys(keys))]523		keys: Option<Vec<String>>524	) -> Vec<Property>, unique_api);525526	pass_method!(token_properties(527		collection: CollectionId,528		token_id: TokenId,529530		#[map(|keys| string_keys_to_bytes_keys(keys))]531		keys: Option<Vec<String>>532	) -> Vec<Property>, unique_api);533534	pass_method!(property_permissions(535		collection: CollectionId,536537		#[map(|keys| string_keys_to_bytes_keys(keys))]538		keys: Option<Vec<String>>539	) -> Vec<PropertyKeyPermission>, unique_api);540541	pass_method!(token_data(542		collection: CollectionId,543		token_id: TokenId,544545		#[map(|keys| string_keys_to_bytes_keys(keys))]546		keys: Option<Vec<String>>,547	) -> TokenData<CrossAccountId>, unique_api);548549	pass_method!(adminlist(collection: CollectionId) -> Vec<CrossAccountId>, unique_api);550	pass_method!(allowlist(collection: CollectionId) -> Vec<CrossAccountId>, unique_api);551	pass_method!(allowed(collection: CollectionId, user: CrossAccountId) -> bool, unique_api);552	pass_method!(last_token_id(collection: CollectionId) -> TokenId, unique_api);553	pass_method!(collection_by_id(collection: CollectionId) -> Option<RpcCollection<AccountId>>, unique_api);554	pass_method!(collection_stats() -> CollectionStats, unique_api);555	pass_method!(next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Option<u64>, unique_api);556	pass_method!(effective_collection_limits(collection_id: CollectionId) -> Option<CollectionLimits>, unique_api);557	pass_method!(total_pieces(collection_id: CollectionId, token_id: TokenId) -> Option<String> => |o| o.map(|number| number.to_string()) , unique_api);558	pass_method!(token_owners(collection: CollectionId, token: TokenId) -> Vec<CrossAccountId>, unique_api);559	pass_method!(total_staked(staker: Option<CrossAccountId>) -> String => |v| v.to_string(), unique_api);560	pass_method!(total_staked_per_block(staker: CrossAccountId) -> Vec<(BlockNumber, String)> =>561		|v| v562		.into_iter()563		.map(|(b, a)| (b, a.to_string()))564		.collect::<Vec<_>>(), unique_api);565	pass_method!(total_staking_locked(staker: CrossAccountId) -> String => |v| v.to_string(), unique_api);566	pass_method!(pending_unstake(staker: Option<CrossAccountId>) -> String => |v| v.to_string(), unique_api);567	pass_method!(pending_unstake_per_block(staker: CrossAccountId) -> Vec<(BlockNumber, String)> =>568		|v| v569		.into_iter()570		.map(|(b, a)| (b, a.to_string()))571		.collect::<Vec<_>>(), unique_api);572}573574#[allow(deprecated)]575impl<576		C,577		Block,578		AccountId,579		CollectionInfo,580		NftInfo,581		ResourceInfo,582		PropertyInfo,583		BaseInfo,584		PartType,585		Theme,586	>587	rmrk_unique_rpc::RmrkApiServer<588		<Block as BlockT>::Hash,589		AccountId,590		CollectionInfo,591		NftInfo,592		ResourceInfo,593		PropertyInfo,594		BaseInfo,595		PartType,596		Theme,597	> for Rmrk<C, Block>598where599	C: Send + Sync + 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,600	C::Api: RmrkRuntimeApi<601		Block,602		AccountId,603		CollectionInfo,604		NftInfo,605		ResourceInfo,606		PropertyInfo,607		BaseInfo,608		PartType,609		Theme,610	>,611	AccountId: Decode + Encode,612	CollectionInfo: Decode,613	NftInfo: Decode,614	ResourceInfo: Decode,615	PropertyInfo: Decode,616	BaseInfo: Decode,617	PartType: Decode,618	Theme: Decode,619	Block: BlockT,620{621	pass_method!(last_collection_idx() -> RmrkCollectionId, rmrk_api);622	pass_method!(collection_by_id(id: RmrkCollectionId) -> Option<CollectionInfo>, rmrk_api);623	pass_method!(nft_by_id(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Option<NftInfo>, rmrk_api);624	pass_method!(account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Vec<RmrkNftId>, rmrk_api);625	pass_method!(nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<RmrkNftChild>, rmrk_api);626	pass_method!(627		collection_properties(628			collection_id: RmrkCollectionId,629630			#[map(|keys| string_keys_to_bytes_keys(keys))]631			filter_keys: Option<Vec<String>>632		) -> Vec<PropertyInfo>,633		rmrk_api634	);635	pass_method!(636		nft_properties(637			collection_id: RmrkCollectionId,638			nft_id: RmrkNftId,639640			#[map(|keys| string_keys_to_bytes_keys(keys))]641			filter_keys: Option<Vec<String>>642		) -> Vec<PropertyInfo>,643		rmrk_api644	);645	pass_method!(nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<ResourceInfo>, rmrk_api);646	pass_method!(nft_resource_priority(collection_id: RmrkCollectionId, nft_id: RmrkNftId, resource_id: RmrkResourceId) -> Option<u32>, rmrk_api);647	pass_method!(base(base_id: RmrkBaseId) -> Option<BaseInfo>, rmrk_api);648	pass_method!(base_parts(base_id: RmrkBaseId) -> Vec<PartType>, rmrk_api);649	pass_method!(theme_names(base_id: RmrkBaseId) -> Vec<RmrkThemeName>, rmrk_api);650	pass_method!(651		theme(652			base_id: RmrkBaseId,653654			#[map(|n| n.into_bytes())]655			theme_name: String,656657			#[map(|keys| string_keys_to_bytes_keys(keys))]658			filter_keys: Option<Vec<String>>659		) -> Option<Theme>, rmrk_api);660}661662fn string_keys_to_bytes_keys(keys: Option<Vec<String>>) -> Option<Vec<Vec<u8>>> {663	keys.map(|keys| keys.into_iter().map(|key| key.into_bytes()).collect())664}