git.delta.rocks / unique-network / refs/commits / 4d07c60d3d95

difftreelog

source

client/rpc/src/lib.rs19.2 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>;265266	/// Return the total amount locked by staking tokens.267	#[method(name = "unique_pendingUnstake")]268	fn pending_unstake(269		&self,270		staker: Option<CrossAccountId>,271		at: Option<BlockHash>,272	) -> Result<String>;273}274275mod rmrk_unique_rpc {276	use super::*;277278	#[rpc(server)]279	#[async_trait]280	pub trait RmrkApi<281		BlockHash,282		AccountId,283		CollectionInfo,284		NftInfo,285		ResourceInfo,286		PropertyInfo,287		BaseInfo,288		PartType,289		Theme,290	>291	{292		/// Get the latest created collection ID.293		#[method(name = "rmrk_lastCollectionIdx")]294		fn last_collection_idx(&self, at: Option<BlockHash>) -> Result<RmrkCollectionId>;295296		/// Get collection info by ID.297		#[method(name = "rmrk_collectionById")]298		fn collection_by_id(299			&self,300			id: RmrkCollectionId,301			at: Option<BlockHash>,302		) -> Result<Option<CollectionInfo>>;303304		/// Get NFT info by collection and NFT IDs.305		#[method(name = "rmrk_nftById")]306		fn nft_by_id(307			&self,308			collection_id: RmrkCollectionId,309			nft_id: RmrkNftId,310			at: Option<BlockHash>,311		) -> Result<Option<NftInfo>>;312313		/// Get tokens owned by an account in a collection.314		#[method(name = "rmrk_accountTokens")]315		fn account_tokens(316			&self,317			account_id: AccountId,318			collection_id: RmrkCollectionId,319			at: Option<BlockHash>,320		) -> Result<Vec<RmrkNftId>>;321322		/// Get tokens nested in an NFT - its direct children (not the children's children).323		#[method(name = "rmrk_nftChildren")]324		fn nft_children(325			&self,326			collection_id: RmrkCollectionId,327			nft_id: RmrkNftId,328			at: Option<BlockHash>,329		) -> Result<Vec<RmrkNftChild>>;330331		/// Get collection properties, created by the user - not the proxy-specific properties.332		#[method(name = "rmrk_collectionProperties")]333		fn collection_properties(334			&self,335			collection_id: RmrkCollectionId,336			filter_keys: Option<Vec<String>>,337			at: Option<BlockHash>,338		) -> Result<Vec<PropertyInfo>>;339340		/// Get NFT properties, created by the user - not the proxy-specific properties.341		#[method(name = "rmrk_nftProperties")]342		fn nft_properties(343			&self,344			collection_id: RmrkCollectionId,345			nft_id: RmrkNftId,346			filter_keys: Option<Vec<String>>,347			at: Option<BlockHash>,348		) -> Result<Vec<PropertyInfo>>;349350		/// Get data of resources of an NFT.351		#[method(name = "rmrk_nftResources")]352		fn nft_resources(353			&self,354			collection_id: RmrkCollectionId,355			nft_id: RmrkNftId,356			at: Option<BlockHash>,357		) -> Result<Vec<ResourceInfo>>;358359		/// Get the priority of a resource in an NFT.360		#[method(name = "rmrk_nftResourcePriority")]361		fn nft_resource_priority(362			&self,363			collection_id: RmrkCollectionId,364			nft_id: RmrkNftId,365			resource_id: RmrkResourceId,366			at: Option<BlockHash>,367		) -> Result<Option<u32>>;368369		/// Get base info by its ID.370		#[method(name = "rmrk_base")]371		fn base(&self, base_id: RmrkBaseId, at: Option<BlockHash>) -> Result<Option<BaseInfo>>;372373		/// Get all parts of a base.374		#[method(name = "rmrk_baseParts")]375		fn base_parts(&self, base_id: RmrkBaseId, at: Option<BlockHash>) -> Result<Vec<PartType>>;376377		/// Get the theme names belonging to a base.378		#[method(name = "rmrk_themeNames")]379		fn theme_names(380			&self,381			base_id: RmrkBaseId,382			at: Option<BlockHash>,383		) -> Result<Vec<RmrkThemeName>>;384385		/// Get theme info, including properties, optionally limited to the provided keys.386		#[method(name = "rmrk_themes")]387		fn theme(388			&self,389			base_id: RmrkBaseId,390			theme_name: String,391			filter_keys: Option<Vec<String>>,392			at: Option<BlockHash>,393		) -> Result<Option<Theme>>;394	}395}396397pub struct Unique<C, P> {398	client: Arc<C>,399	_marker: std::marker::PhantomData<P>,400}401402impl<C, P> Unique<C, P> {403	pub fn new(client: Arc<C>) -> Self {404		Self {405			client,406			_marker: Default::default(),407		}408	}409}410411pub struct Rmrk<C, P> {412	client: Arc<C>,413	_marker: std::marker::PhantomData<P>,414}415416impl<C, P> Rmrk<C, P> {417	pub fn new(client: Arc<C>) -> Self {418		Self {419			client,420			_marker: Default::default(),421		}422	}423}424425macro_rules! pass_method {426	(427		$method_name:ident(428			$($(#[map(|$map_arg:ident| $map:expr)])? $name:ident: $ty:ty),* $(,)?429		) -> $result:ty $(=> $mapper:expr)?,430		//$runtime_name:ident $(<$($lt: tt),+>)*431		$runtime_api_macro:ident432		$(; changed_in $ver:expr, $changed_method_name:ident ($($changed_name:expr), * $(,)?) => $fixer:expr)*433	) => {434		fn $method_name(435			&self,436			$(437				$name: $ty,438			)*439			at: Option<<Block as BlockT>::Hash>,440		) -> Result<$result> {441			let api = self.client.runtime_api();442			let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash));443			let _api_version = if let Ok(Some(api_version)) =444				api.api_version::<$runtime_api_macro!()>(&at)445			{446				api_version447			} else {448				// unreachable for our runtime449				return Err(anyhow!("api is not available").into())450			};451452			let result = $(if _api_version < $ver {453				api.$changed_method_name(&at, $($changed_name),*).map(|r| r.map($fixer))454			} else)*455			{ api.$method_name(&at, $($((|$map_arg: $ty| $map))? ($name)),*) };456457			Ok(result458				.map_err(|e| anyhow!("unable to query: {e}"))?459				.map_err(|e| anyhow!("runtime error: {e:?}"))$(.map($mapper))??)460		}461	};462}463464macro_rules! unique_api {465	() => {466		dyn UniqueRuntimeApi<Block, BlockNumber, CrossAccountId, AccountId>467	};468}469470macro_rules! rmrk_api {471	() => {472		dyn RmrkRuntimeApi<Block, AccountId, CollectionInfo, NftInfo, ResourceInfo, PropertyInfo, BaseInfo, PartType, Theme>473	};474}475476#[allow(deprecated)]477impl<C, Block, BlockNumber, CrossAccountId, AccountId>478	UniqueApiServer<<Block as BlockT>::Hash, BlockNumber, CrossAccountId, AccountId>479	for Unique<C, Block>480where481	Block: BlockT,482	BlockNumber: Decode + Member + AtLeast32BitUnsigned,483	AccountId: Decode,484	C: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,485	C::Api: UniqueRuntimeApi<Block, BlockNumber, CrossAccountId, AccountId>,486	CrossAccountId: pallet_evm::account::CrossAccountId<AccountId>,487{488	pass_method!(489		account_tokens(collection: CollectionId, account: CrossAccountId) -> Vec<TokenId>, unique_api490	);491	pass_method!(492		collection_tokens(collection: CollectionId) -> Vec<TokenId>, unique_api493	);494	pass_method!(495		token_exists(collection: CollectionId, token: TokenId) -> bool, unique_api496	);497	pass_method!(498		token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>, unique_api499	);500	pass_method!(501		topmost_token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>, unique_api502	);503	pass_method!(token_children(collection: CollectionId, token: TokenId) -> Vec<TokenChild>, unique_api);504	pass_method!(total_supply(collection: CollectionId) -> u32, unique_api);505	pass_method!(account_balance(collection: CollectionId, account: CrossAccountId) -> u32, unique_api);506	pass_method!(balance(collection: CollectionId, account: CrossAccountId, token: TokenId) -> String => |v| v.to_string(), unique_api);507	pass_method!(508		allowance(collection: CollectionId, sender: CrossAccountId, spender: CrossAccountId, token: TokenId) -> String => |v| v.to_string(),509		unique_api510	);511512	pass_method!(collection_properties(513		collection: CollectionId,514515		#[map(|keys| string_keys_to_bytes_keys(keys))]516		keys: Option<Vec<String>>517	) -> Vec<Property>, unique_api);518519	pass_method!(token_properties(520		collection: CollectionId,521		token_id: TokenId,522523		#[map(|keys| string_keys_to_bytes_keys(keys))]524		keys: Option<Vec<String>>525	) -> Vec<Property>, unique_api);526527	pass_method!(property_permissions(528		collection: CollectionId,529530		#[map(|keys| string_keys_to_bytes_keys(keys))]531		keys: Option<Vec<String>>532	) -> Vec<PropertyKeyPermission>, unique_api);533534	pass_method!(token_data(535		collection: CollectionId,536		token_id: TokenId,537538		#[map(|keys| string_keys_to_bytes_keys(keys))]539		keys: Option<Vec<String>>,540	) -> TokenData<CrossAccountId>, unique_api);541542	pass_method!(adminlist(collection: CollectionId) -> Vec<CrossAccountId>, unique_api);543	pass_method!(allowlist(collection: CollectionId) -> Vec<CrossAccountId>, unique_api);544	pass_method!(allowed(collection: CollectionId, user: CrossAccountId) -> bool, unique_api);545	pass_method!(last_token_id(collection: CollectionId) -> TokenId, unique_api);546	pass_method!(collection_by_id(collection: CollectionId) -> Option<RpcCollection<AccountId>>, unique_api);547	pass_method!(collection_stats() -> CollectionStats, unique_api);548	pass_method!(next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Option<u64>, unique_api);549	pass_method!(effective_collection_limits(collection_id: CollectionId) -> Option<CollectionLimits>, unique_api);550	pass_method!(total_pieces(collection_id: CollectionId, token_id: TokenId) -> Option<String> => |o| o.map(|number| number.to_string()) , unique_api);551	pass_method!(token_owners(collection: CollectionId, token: TokenId) -> Vec<CrossAccountId>, unique_api);552	pass_method!(total_staked(staker: Option<CrossAccountId>) -> String => |v| v.to_string(), unique_api);553	pass_method!(total_staked_per_block(staker: CrossAccountId) -> Vec<(BlockNumber, String)> =>554		|v| v555		.into_iter()556		.map(|(b, a)| (b, a.to_string()))557		.collect::<Vec<_>>(), unique_api);558	pass_method!(total_staking_locked(staker: CrossAccountId) -> String => |v| v.to_string(), unique_api);559	pass_method!(pending_unstake(staker: Option<CrossAccountId>) -> String => |v| v.to_string(), unique_api);560}561562#[allow(deprecated)]563impl<564		C,565		Block,566		AccountId,567		CollectionInfo,568		NftInfo,569		ResourceInfo,570		PropertyInfo,571		BaseInfo,572		PartType,573		Theme,574	>575	rmrk_unique_rpc::RmrkApiServer<576		<Block as BlockT>::Hash,577		AccountId,578		CollectionInfo,579		NftInfo,580		ResourceInfo,581		PropertyInfo,582		BaseInfo,583		PartType,584		Theme,585	> for Rmrk<C, Block>586where587	C: Send + Sync + 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,588	C::Api: RmrkRuntimeApi<589		Block,590		AccountId,591		CollectionInfo,592		NftInfo,593		ResourceInfo,594		PropertyInfo,595		BaseInfo,596		PartType,597		Theme,598	>,599	AccountId: Decode + Encode,600	CollectionInfo: Decode,601	NftInfo: Decode,602	ResourceInfo: Decode,603	PropertyInfo: Decode,604	BaseInfo: Decode,605	PartType: Decode,606	Theme: Decode,607	Block: BlockT,608{609	pass_method!(last_collection_idx() -> RmrkCollectionId, rmrk_api);610	pass_method!(collection_by_id(id: RmrkCollectionId) -> Option<CollectionInfo>, rmrk_api);611	pass_method!(nft_by_id(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Option<NftInfo>, rmrk_api);612	pass_method!(account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Vec<RmrkNftId>, rmrk_api);613	pass_method!(nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<RmrkNftChild>, rmrk_api);614	pass_method!(615		collection_properties(616			collection_id: RmrkCollectionId,617618			#[map(|keys| string_keys_to_bytes_keys(keys))]619			filter_keys: Option<Vec<String>>620		) -> Vec<PropertyInfo>,621		rmrk_api622	);623	pass_method!(624		nft_properties(625			collection_id: RmrkCollectionId,626			nft_id: RmrkNftId,627628			#[map(|keys| string_keys_to_bytes_keys(keys))]629			filter_keys: Option<Vec<String>>630		) -> Vec<PropertyInfo>,631		rmrk_api632	);633	pass_method!(nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<ResourceInfo>, rmrk_api);634	pass_method!(nft_resource_priority(collection_id: RmrkCollectionId, nft_id: RmrkNftId, resource_id: RmrkResourceId) -> Option<u32>, rmrk_api);635	pass_method!(base(base_id: RmrkBaseId) -> Option<BaseInfo>, rmrk_api);636	pass_method!(base_parts(base_id: RmrkBaseId) -> Vec<PartType>, rmrk_api);637	pass_method!(theme_names(base_id: RmrkBaseId) -> Vec<RmrkThemeName>, rmrk_api);638	pass_method!(639		theme(640			base_id: RmrkBaseId,641642			#[map(|n| n.into_bytes())]643			theme_name: String,644645			#[map(|keys| string_keys_to_bytes_keys(keys))]646			filter_keys: Option<Vec<String>>647		) -> Option<Theme>, rmrk_api);648}649650fn string_keys_to_bytes_keys(keys: Option<Vec<String>>) -> Option<Vec<Vec<u8>>> {651	keys.map(|keys| keys.into_iter().map(|key| key.into_bytes()).collect())652}