git.delta.rocks / unique-network / refs/commits / 6c48590c156a

difftreelog

source

client/rpc/src/lib.rs17.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 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 account.46	#[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 within a collection.55	#[method(name = "unique_collectionTokens")]56	fn collection_tokens(57		&self,58		collection: CollectionId,59		at: Option<BlockHash>,60	) -> Result<Vec<TokenId>>;6162	/// Check if the token exists.63	#[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 the token owner.72	#[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	/// Returns 10 tokens owners in no particular order.81	#[method(name = "unique_tokenOwners")]82	fn token_owners(83		&self,84		collection: CollectionId,85		token: TokenId,86		at: Option<BlockHash>,87	) -> Result<Vec<CrossAccountId>>;8889	/// Get the topmost token owner in the hierarchy of a possibly nested token.90	#[method(name = "unique_topmostTokenOwner")]91	fn topmost_token_owner(92		&self,93		collection: CollectionId,94		token: TokenId,95		at: Option<BlockHash>,96	) -> Result<Option<CrossAccountId>>;9798	/// Get tokens nested directly into the token.99	#[method(name = "unique_tokenChildren")]100	fn token_children(101		&self,102		collection: CollectionId,103		token: TokenId,104		at: Option<BlockHash>,105	) -> Result<Vec<TokenChild>>;106107	/// Get collection properties, optionally limited to the provided keys.108	#[method(name = "unique_collectionProperties")]109	fn collection_properties(110		&self,111		collection: CollectionId,112		keys: Option<Vec<String>>,113		at: Option<BlockHash>,114	) -> Result<Vec<Property>>;115116	/// Get token properties, optionally limited to the provided keys.117	#[method(name = "unique_tokenProperties")]118	fn token_properties(119		&self,120		collection: CollectionId,121		token_id: TokenId,122		keys: Option<Vec<String>>,123		at: Option<BlockHash>,124	) -> Result<Vec<Property>>;125126	/// Get property permissions, optionally limited to the provided keys.127	#[method(name = "unique_propertyPermissions")]128	fn property_permissions(129		&self,130		collection: CollectionId,131		keys: Option<Vec<String>>,132		at: Option<BlockHash>,133	) -> Result<Vec<PropertyKeyPermission>>;134135	/// Get token data, including properties, optionally limited to the provided keys, and total pieces for an RFT.136	#[method(name = "unique_tokenData")]137	fn token_data(138		&self,139		collection: CollectionId,140		token_id: TokenId,141		keys: Option<Vec<String>>,142		at: Option<BlockHash>,143	) -> Result<TokenData<CrossAccountId>>;144145	/// Get the amount of distinctive tokens present in a collection.146	#[method(name = "unique_totalSupply")]147	fn total_supply(&self, collection: CollectionId, at: Option<BlockHash>) -> Result<u32>;148149	/// Get the amount of any user tokens owned by an account.150	#[method(name = "unique_accountBalance")]151	fn account_balance(152		&self,153		collection: CollectionId,154		account: CrossAccountId,155		at: Option<BlockHash>,156	) -> Result<u32>;157158	/// Get the amount of a specific token owned by an account.159	#[method(name = "unique_balance")]160	fn balance(161		&self,162		collection: CollectionId,163		account: CrossAccountId,164		token: TokenId,165		at: Option<BlockHash>,166	) -> Result<String>;167168	/// Get the amount of currently possible sponsored transactions on a token for the fee to be taken off a sponsor.169	#[method(name = "unique_allowance")]170	fn allowance(171		&self,172		collection: CollectionId,173		sender: CrossAccountId,174		spender: CrossAccountId,175		token: TokenId,176		at: Option<BlockHash>,177	) -> Result<String>;178179	/// Get the list of admin accounts of a collection.180	#[method(name = "unique_adminlist")]181	fn adminlist(182		&self,183		collection: CollectionId,184		at: Option<BlockHash>,185	) -> Result<Vec<CrossAccountId>>;186187	/// Get the list of accounts allowed to operate within a collection.188	#[method(name = "unique_allowlist")]189	fn allowlist(190		&self,191		collection: CollectionId,192		at: Option<BlockHash>,193	) -> Result<Vec<CrossAccountId>>;194195	/// Check if a user is allowed to operate within a collection.196	#[method(name = "unique_allowed")]197	fn allowed(198		&self,199		collection: CollectionId,200		user: CrossAccountId,201		at: Option<BlockHash>,202	) -> Result<bool>;203204	/// Get the last token ID created in a collection.205	#[method(name = "unique_lastTokenId")]206	fn last_token_id(&self, collection: CollectionId, at: Option<BlockHash>) -> Result<TokenId>;207208	/// Get collection info by the specified ID.209	#[method(name = "unique_collectionById")]210	fn collection_by_id(211		&self,212		collection: CollectionId,213		at: Option<BlockHash>,214	) -> Result<Option<RpcCollection<AccountId>>>;215216	/// Get chain stats about collections.217	#[method(name = "unique_collectionStats")]218	fn collection_stats(&self, at: Option<BlockHash>) -> Result<CollectionStats>;219220	/// Get the number of blocks until sponsoring a transaction is available.221	#[method(name = "unique_nextSponsored")]222	fn next_sponsored(223		&self,224		collection: CollectionId,225		account: CrossAccountId,226		token: TokenId,227		at: Option<BlockHash>,228	) -> Result<Option<u64>>;229230	/// Get effective collection limits. If not explicitly set, get the chain defaults.231	#[method(name = "unique_effectiveCollectionLimits")]232	fn effective_collection_limits(233		&self,234		collection_id: CollectionId,235		at: Option<BlockHash>,236	) -> Result<Option<CollectionLimits>>;237238	/// Get the total amount of pieces of an RFT.239	#[method(name = "unique_totalPieces")]240	fn total_pieces(241		&self,242		collection_id: CollectionId,243		token_id: TokenId,244		at: Option<BlockHash>,245	) -> Result<Option<String>>;246}247248mod rmrk_unique_rpc {249	use super::*;250251	#[rpc(server)]252	#[async_trait]253	pub trait RmrkApi<254		BlockHash,255		AccountId,256		CollectionInfo,257		NftInfo,258		ResourceInfo,259		PropertyInfo,260		BaseInfo,261		PartType,262		Theme,263	>264	{265		/// Get the latest created collection ID.266		#[method(name = "rmrk_lastCollectionIdx")]267		fn last_collection_idx(&self, at: Option<BlockHash>) -> Result<RmrkCollectionId>;268269		/// Get collection info by ID.270		#[method(name = "rmrk_collectionById")]271		fn collection_by_id(272			&self,273			id: RmrkCollectionId,274			at: Option<BlockHash>,275		) -> Result<Option<CollectionInfo>>;276277		/// Get NFT info by collection and NFT IDs.278		#[method(name = "rmrk_nftById")]279		fn nft_by_id(280			&self,281			collection_id: RmrkCollectionId,282			nft_id: RmrkNftId,283			at: Option<BlockHash>,284		) -> Result<Option<NftInfo>>;285286		/// Get tokens owned by an account in a collection.287		#[method(name = "rmrk_accountTokens")]288		fn account_tokens(289			&self,290			account_id: AccountId,291			collection_id: RmrkCollectionId,292			at: Option<BlockHash>,293		) -> Result<Vec<RmrkNftId>>;294295		/// Get tokens nested in an NFT - its direct children (not the children's children).296		#[method(name = "rmrk_nftChildren")]297		fn nft_children(298			&self,299			collection_id: RmrkCollectionId,300			nft_id: RmrkNftId,301			at: Option<BlockHash>,302		) -> Result<Vec<RmrkNftChild>>;303304		/// Get collection properties, created by the user - not the proxy-specific properties.305		#[method(name = "rmrk_collectionProperties")]306		fn collection_properties(307			&self,308			collection_id: RmrkCollectionId,309			filter_keys: Option<Vec<String>>,310			at: Option<BlockHash>,311		) -> Result<Vec<PropertyInfo>>;312313		/// Get NFT properties, created by the user - not the proxy-specific properties.314		#[method(name = "rmrk_nftProperties")]315		fn nft_properties(316			&self,317			collection_id: RmrkCollectionId,318			nft_id: RmrkNftId,319			filter_keys: Option<Vec<String>>,320			at: Option<BlockHash>,321		) -> Result<Vec<PropertyInfo>>;322323		/// Get data of resources of an NFT.324		#[method(name = "rmrk_nftResources")]325		fn nft_resources(326			&self,327			collection_id: RmrkCollectionId,328			nft_id: RmrkNftId,329			at: Option<BlockHash>,330		) -> Result<Vec<ResourceInfo>>;331332		/// Get the priority of a resource in an NFT.333		#[method(name = "rmrk_nftResourcePriority")]334		fn nft_resource_priority(335			&self,336			collection_id: RmrkCollectionId,337			nft_id: RmrkNftId,338			resource_id: RmrkResourceId,339			at: Option<BlockHash>,340		) -> Result<Option<u32>>;341342		/// Get base info by its ID.343		#[method(name = "rmrk_base")]344		fn base(&self, base_id: RmrkBaseId, at: Option<BlockHash>) -> Result<Option<BaseInfo>>;345346		/// Get all parts of a base.347		#[method(name = "rmrk_baseParts")]348		fn base_parts(&self, base_id: RmrkBaseId, at: Option<BlockHash>) -> Result<Vec<PartType>>;349350		/// Get the theme names belonging to a base.351		#[method(name = "rmrk_themeNames")]352		fn theme_names(353			&self,354			base_id: RmrkBaseId,355			at: Option<BlockHash>,356		) -> Result<Vec<RmrkThemeName>>;357358		/// Get theme info, including properties, optionally limited to the provided keys.359		#[method(name = "rmrk_themes")]360		fn theme(361			&self,362			base_id: RmrkBaseId,363			theme_name: String,364			filter_keys: Option<Vec<String>>,365			at: Option<BlockHash>,366		) -> Result<Option<Theme>>;367	}368}369370pub struct Unique<C, P> {371	client: Arc<C>,372	_marker: std::marker::PhantomData<P>,373}374375impl<C, P> Unique<C, P> {376	pub fn new(client: Arc<C>) -> Self {377		Self {378			client,379			_marker: Default::default(),380		}381	}382}383384pub struct Rmrk<C, P> {385	client: Arc<C>,386	_marker: std::marker::PhantomData<P>,387}388389impl<C, P> Rmrk<C, P> {390	pub fn new(client: Arc<C>) -> Self {391		Self {392			client,393			_marker: Default::default(),394		}395	}396}397398macro_rules! pass_method {399	(400		$method_name:ident(401			$($(#[map(|$map_arg:ident| $map:expr)])? $name:ident: $ty:ty),* $(,)?402		) -> $result:ty $(=> $mapper:expr)?,403		//$runtime_name:ident $(<$($lt: tt),+>)*404		$runtime_api_macro:ident405		$(; changed_in $ver:expr, $changed_method_name:ident ($($changed_name:expr), * $(,)?) => $fixer:expr)*406	) => {407		fn $method_name(408			&self,409			$(410				$name: $ty,411			)*412			at: Option<<Block as BlockT>::Hash>,413		) -> Result<$result> {414			let api = self.client.runtime_api();415			let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash));416			let _api_version = if let Ok(Some(api_version)) =417				api.api_version::<$runtime_api_macro!()>(&at)418			{419				api_version420			} else {421				// unreachable for our runtime422				return Err(anyhow!("api is not available").into())423			};424425			let result = $(if _api_version < $ver {426				api.$changed_method_name(&at, $($changed_name),*).map(|r| r.map($fixer))427			} else)*428			{ api.$method_name(&at, $($((|$map_arg: $ty| $map))? ($name)),*) };429430			Ok(result431				.map_err(|e| anyhow!("unable to query: {e}"))?432				.map_err(|e| anyhow!("runtime error: {e:?}"))$(.map($mapper))??)433		}434	};435}436437macro_rules! unique_api {438	() => {439		dyn UniqueRuntimeApi<Block, CrossAccountId, AccountId>440	};441}442443macro_rules! rmrk_api {444	() => {445		dyn RmrkRuntimeApi<Block, AccountId, CollectionInfo, NftInfo, ResourceInfo, PropertyInfo, BaseInfo, PartType, Theme>446	};447}448449#[allow(deprecated)]450impl<C, Block, CrossAccountId, AccountId>451	UniqueApiServer<<Block as BlockT>::Hash, CrossAccountId, AccountId> for Unique<C, Block>452where453	Block: BlockT,454	AccountId: Decode,455	C: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,456	C::Api: UniqueRuntimeApi<Block, CrossAccountId, AccountId>,457	CrossAccountId: pallet_evm::account::CrossAccountId<AccountId>,458{459	pass_method!(460		account_tokens(collection: CollectionId, account: CrossAccountId) -> Vec<TokenId>, unique_api461	);462	pass_method!(463		collection_tokens(collection: CollectionId) -> Vec<TokenId>, unique_api464	);465	pass_method!(466		token_exists(collection: CollectionId, token: TokenId) -> bool, unique_api467	);468	pass_method!(469		token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>, unique_api470	);471	pass_method!(472		topmost_token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>, unique_api473	);474	pass_method!(token_children(collection: CollectionId, token: TokenId) -> Vec<TokenChild>, unique_api);475	pass_method!(total_supply(collection: CollectionId) -> u32, unique_api);476	pass_method!(account_balance(collection: CollectionId, account: CrossAccountId) -> u32, unique_api);477	pass_method!(balance(collection: CollectionId, account: CrossAccountId, token: TokenId) -> String => |v| v.to_string(), unique_api);478	pass_method!(479		allowance(collection: CollectionId, sender: CrossAccountId, spender: CrossAccountId, token: TokenId) -> String => |v| v.to_string(),480		unique_api481	);482483	pass_method!(collection_properties(484		collection: CollectionId,485486		#[map(|keys| string_keys_to_bytes_keys(keys))]487		keys: Option<Vec<String>>488	) -> Vec<Property>, unique_api);489490	pass_method!(token_properties(491		collection: CollectionId,492		token_id: TokenId,493494		#[map(|keys| string_keys_to_bytes_keys(keys))]495		keys: Option<Vec<String>>496	) -> Vec<Property>, unique_api);497498	pass_method!(property_permissions(499		collection: CollectionId,500501		#[map(|keys| string_keys_to_bytes_keys(keys))]502		keys: Option<Vec<String>>503	) -> Vec<PropertyKeyPermission>, unique_api);504505	pass_method!(token_data(506		collection: CollectionId,507		token_id: TokenId,508509		#[map(|keys| string_keys_to_bytes_keys(keys))]510		keys: Option<Vec<String>>,511	) -> TokenData<CrossAccountId>, unique_api);512513	pass_method!(adminlist(collection: CollectionId) -> Vec<CrossAccountId>, unique_api);514	pass_method!(allowlist(collection: CollectionId) -> Vec<CrossAccountId>, unique_api);515	pass_method!(allowed(collection: CollectionId, user: CrossAccountId) -> bool, unique_api);516	pass_method!(last_token_id(collection: CollectionId) -> TokenId, unique_api);517	pass_method!(collection_by_id(collection: CollectionId) -> Option<RpcCollection<AccountId>>, unique_api);518	pass_method!(collection_stats() -> CollectionStats, unique_api);519	pass_method!(next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Option<u64>, unique_api);520	pass_method!(effective_collection_limits(collection_id: CollectionId) -> Option<CollectionLimits>, unique_api);521	pass_method!(total_pieces(collection_id: CollectionId, token_id: TokenId) -> Option<String> => |o| o.map(|number| number.to_string()) , unique_api);522	pass_method!(token_owners(collection: CollectionId, token: TokenId) -> Vec<CrossAccountId>, unique_api);523}524525#[allow(deprecated)]526impl<527		C,528		Block,529		AccountId,530		CollectionInfo,531		NftInfo,532		ResourceInfo,533		PropertyInfo,534		BaseInfo,535		PartType,536		Theme,537	>538	rmrk_unique_rpc::RmrkApiServer<539		<Block as BlockT>::Hash,540		AccountId,541		CollectionInfo,542		NftInfo,543		ResourceInfo,544		PropertyInfo,545		BaseInfo,546		PartType,547		Theme,548	> for Rmrk<C, Block>549where550	C: Send + Sync + 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,551	C::Api: RmrkRuntimeApi<552		Block,553		AccountId,554		CollectionInfo,555		NftInfo,556		ResourceInfo,557		PropertyInfo,558		BaseInfo,559		PartType,560		Theme,561	>,562	AccountId: Decode + Encode,563	CollectionInfo: Decode,564	NftInfo: Decode,565	ResourceInfo: Decode,566	PropertyInfo: Decode,567	BaseInfo: Decode,568	PartType: Decode,569	Theme: Decode,570	Block: BlockT,571{572	pass_method!(last_collection_idx() -> RmrkCollectionId, rmrk_api);573	pass_method!(collection_by_id(id: RmrkCollectionId) -> Option<CollectionInfo>, rmrk_api);574	pass_method!(nft_by_id(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Option<NftInfo>, rmrk_api);575	pass_method!(account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Vec<RmrkNftId>, rmrk_api);576	pass_method!(nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<RmrkNftChild>, rmrk_api);577	pass_method!(578		collection_properties(579			collection_id: RmrkCollectionId,580581			#[map(|keys| string_keys_to_bytes_keys(keys))]582			filter_keys: Option<Vec<String>>583		) -> Vec<PropertyInfo>,584		rmrk_api585	);586	pass_method!(587		nft_properties(588			collection_id: RmrkCollectionId,589			nft_id: RmrkNftId,590591			#[map(|keys| string_keys_to_bytes_keys(keys))]592			filter_keys: Option<Vec<String>>593		) -> Vec<PropertyInfo>,594		rmrk_api595	);596	pass_method!(nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<ResourceInfo>, rmrk_api);597	pass_method!(nft_resource_priority(collection_id: RmrkCollectionId, nft_id: RmrkNftId, resource_id: RmrkResourceId) -> Option<u32>, rmrk_api);598	pass_method!(base(base_id: RmrkBaseId) -> Option<BaseInfo>, rmrk_api);599	pass_method!(base_parts(base_id: RmrkBaseId) -> Vec<PartType>, rmrk_api);600	pass_method!(theme_names(base_id: RmrkBaseId) -> Vec<RmrkThemeName>, rmrk_api);601	pass_method!(602		theme(603			base_id: RmrkBaseId,604605			#[map(|n| n.into_bytes())]606			theme_name: String,607608			#[map(|keys| string_keys_to_bytes_keys(keys))]609			filter_keys: Option<Vec<String>>610		) -> Option<Theme>, rmrk_api);611}612613fn string_keys_to_bytes_keys(keys: Option<Vec<String>>) -> Option<Vec<Vec<u8>>> {614	keys.map(|keys| keys.into_iter().map(|key| key.into_bytes()).collect())615}