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

difftreelog

source

client/rpc/src/lib.rs16.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/>.1617use std::sync::Arc;1819use codec::{Decode, Encode};20use jsonrpc_core::{Error as RpcError, ErrorCode, Result};21use jsonrpc_derive::rpc;22use up_data_structs::{23	RpcCollection, CollectionId, CollectionStats, CollectionLimits, TokenId, Property,24	PropertyKeyPermission, TokenData,25};26use sp_api::{BlockId, BlockT, ProvideRuntimeApi, ApiExt};27use sp_blockchain::HeaderBackend;28use up_rpc::UniqueApi as UniqueRuntimeApi;2930// RMRK31use rmrk_rpc::RmrkApi as RmrkRuntimeApi;32use rmrk_traits::{33	primitives::{34		CollectionId as RmrkCollectionId,35		NftId as RmrkNftId,36		BaseId as RmrkBaseId,37		//ResourceId as RmrkResourceId,38	},39	NftChild as RmrkNftChild,40};41pub use unique_runtime_common::types::{RmrkThemeName, RmrkPropertyKey, RmrkResourceId};4243pub use rmrk::RmrkApi;4445#[rpc]46pub trait UniqueApi<BlockHash, CrossAccountId, AccountId> {47	#[rpc(name = "unique_accountTokens")]48	fn account_tokens(49		&self,50		collection: CollectionId,51		account: CrossAccountId,52		at: Option<BlockHash>,53	) -> Result<Vec<TokenId>>;54	#[rpc(name = "unique_collectionTokens")]55	fn collection_tokens(56		&self,57		collection: CollectionId,58		at: Option<BlockHash>,59	) -> Result<Vec<TokenId>>;60	#[rpc(name = "unique_tokenExists")]61	fn token_exists(62		&self,63		collection: CollectionId,64		token: TokenId,65		at: Option<BlockHash>,66	) -> Result<bool>;6768	#[rpc(name = "unique_tokenOwner")]69	fn token_owner(70		&self,71		collection: CollectionId,72		token: TokenId,73		at: Option<BlockHash>,74	) -> Result<Option<CrossAccountId>>;75	#[rpc(name = "unique_topmostTokenOwner")]76	fn topmost_token_owner(77		&self,78		collection: CollectionId,79		token: TokenId,80		at: Option<BlockHash>,81	) -> Result<Option<CrossAccountId>>;82	#[rpc(name = "unique_constMetadata")]83	fn const_metadata(84		&self,85		collection: CollectionId,86		token: TokenId,87		at: Option<BlockHash>,88	) -> Result<Vec<u8>>;89	#[rpc(name = "unique_variableMetadata")]90	fn variable_metadata(91		&self,92		collection: CollectionId,93		token: TokenId,94		at: Option<BlockHash>,95	) -> Result<Vec<u8>>;9697	#[rpc(name = "unique_collectionProperties")]98	fn collection_properties(99		&self,100		collection: CollectionId,101		keys: Vec<String>,102		at: Option<BlockHash>,103	) -> Result<Vec<Property>>;104105	#[rpc(name = "unique_tokenProperties")]106	fn token_properties(107		&self,108		collection: CollectionId,109		token_id: TokenId,110		properties: Vec<String>,111		at: Option<BlockHash>,112	) -> Result<Vec<Property>>;113114	#[rpc(name = "unique_propertyPermissions")]115	fn property_permissions(116		&self,117		collection: CollectionId,118		keys: Vec<String>,119		at: Option<BlockHash>,120	) -> Result<Vec<PropertyKeyPermission>>;121122	#[rpc(name = "unique_tokenData")]123	fn token_data(124		&self,125		collection: CollectionId,126		token_id: TokenId,127		keys: Vec<String>,128		at: Option<BlockHash>,129	) -> Result<TokenData<CrossAccountId>>;130131	#[rpc(name = "unique_totalSupply")]132	fn total_supply(&self, collection: CollectionId, at: Option<BlockHash>) -> Result<u32>;133	#[rpc(name = "unique_accountBalance")]134	fn account_balance(135		&self,136		collection: CollectionId,137		account: CrossAccountId,138		at: Option<BlockHash>,139	) -> Result<u32>;140	#[rpc(name = "unique_balance")]141	fn balance(142		&self,143		collection: CollectionId,144		account: CrossAccountId,145		token: TokenId,146		at: Option<BlockHash>,147	) -> Result<String>;148	#[rpc(name = "unique_allowance")]149	fn allowance(150		&self,151		collection: CollectionId,152		sender: CrossAccountId,153		spender: CrossAccountId,154		token: TokenId,155		at: Option<BlockHash>,156	) -> Result<String>;157158	#[rpc(name = "unique_adminlist")]159	fn adminlist(160		&self,161		collection: CollectionId,162		at: Option<BlockHash>,163	) -> Result<Vec<CrossAccountId>>;164	#[rpc(name = "unique_allowlist")]165	fn allowlist(166		&self,167		collection: CollectionId,168		at: Option<BlockHash>,169	) -> Result<Vec<CrossAccountId>>;170	#[rpc(name = "unique_allowed")]171	fn allowed(172		&self,173		collection: CollectionId,174		user: CrossAccountId,175		at: Option<BlockHash>,176	) -> Result<bool>;177	#[rpc(name = "unique_lastTokenId")]178	fn last_token_id(&self, collection: CollectionId, at: Option<BlockHash>) -> Result<TokenId>;179	#[rpc(name = "unique_collectionById")]180	fn collection_by_id(181		&self,182		collection: CollectionId,183		at: Option<BlockHash>,184	) -> Result<Option<RpcCollection<AccountId>>>;185	#[rpc(name = "unique_collectionStats")]186	fn collection_stats(&self, at: Option<BlockHash>) -> Result<CollectionStats>;187188	#[rpc(name = "unique_nextSponsored")]189	fn next_sponsored(190		&self,191		collection: CollectionId,192		account: CrossAccountId,193		token: TokenId,194		at: Option<BlockHash>,195	) -> Result<Option<u64>>;196	#[rpc(name = "unique_effectiveCollectionLimits")]197	fn effective_collection_limits(198		&self,199		collection_id: CollectionId,200		at: Option<BlockHash>,201	) -> Result<Option<CollectionLimits>>;202}203204mod rmrk {205	use super::*;206207	#[rpc]208	pub trait RmrkApi<209		BlockHash,210		AccountId,211		CollectionInfo,212		NftInfo,213		ResourceInfo,214		PropertyInfo,215		BaseInfo,216		PartType,217		Theme,218	>219	{220		#[rpc(name = "rmrk_lastCollectionIdx")]221		/// Get the latest created collection id222		fn last_collection_idx(&self, at: Option<BlockHash>) -> Result<RmrkCollectionId>;223224		#[rpc(name = "rmrk_collectionById")]225		/// Get collection by id226		fn collection_by_id(227			&self,228			id: RmrkCollectionId,229			at: Option<BlockHash>,230		) -> Result<Option<CollectionInfo>>;231232		#[rpc(name = "rmrk_nftById")]233		/// Get NFT by collection id and NFT id234		fn nft_by_id(235			&self,236			collection_id: RmrkCollectionId,237			nft_id: RmrkNftId,238			at: Option<BlockHash>,239		) -> Result<Option<NftInfo>>;240241		#[rpc(name = "rmrk_accountTokens")]242		/// Get tokens owned by an account in a collection243		fn account_tokens(244			&self,245			account_id: AccountId,246			collection_id: RmrkCollectionId,247			at: Option<BlockHash>,248		) -> Result<Vec<RmrkNftId>>;249250		#[rpc(name = "rmrk_nftChildren")]251		/// Get NFT children252		fn nft_children(253			&self,254			collection_id: RmrkCollectionId,255			nft_id: RmrkNftId,256			at: Option<BlockHash>,257		) -> Result<Vec<RmrkNftChild>>;258259		#[rpc(name = "rmrk_collectionProperties")]260		/// Get collection properties261		fn collection_properties(262			&self,263			collection_id: RmrkCollectionId,264			filter_keys: Option<Vec<RmrkPropertyKey>>, //String265			at: Option<BlockHash>,266		) -> Result<Vec<PropertyInfo>>;267268		#[rpc(name = "rmrk_nftProperties")]269		/// Get NFT properties270		fn nft_properties(271			&self,272			collection_id: RmrkCollectionId,273			nft_id: RmrkNftId,274			filter_keys: Option<Vec<RmrkPropertyKey>>,275			at: Option<BlockHash>,276		) -> Result<Vec<PropertyInfo>>;277278		#[rpc(name = "rmrk_nftResources")]279		/// Get NFT resources280		fn nft_resources(281			&self,282			collection_id: RmrkCollectionId,283			nft_id: RmrkNftId,284			at: Option<BlockHash>,285		) -> Result<Vec<ResourceInfo>>;286287		#[rpc(name = "rmrk_nftResourcePriorities")]288		/// Get NFT resource priorities289		fn nft_resource_priorities(290			&self,291			collection_id: RmrkCollectionId,292			nft_id: RmrkNftId,293			at: Option<BlockHash>,294		) -> Result<Vec<RmrkResourceId>>;295296		#[rpc(name = "rmrk_base")]297		/// Get base info298		fn base(&self, base_id: RmrkBaseId, at: Option<BlockHash>) -> Result<Option<BaseInfo>>;299300		#[rpc(name = "rmrk_baseParts")]301		/// Get all Base's parts302		fn base_parts(&self, base_id: RmrkBaseId, at: Option<BlockHash>) -> Result<Vec<PartType>>;303304		#[rpc(name = "rmrk_themeNames")]305		fn theme_names(306			&self,307			base_id: RmrkBaseId,308			at: Option<BlockHash>,309		) -> Result<Vec<RmrkThemeName>>;310311		#[rpc(name = "rmrk_themes")]312		fn theme(313			&self,314			base_id: RmrkBaseId,315			theme_name: RmrkThemeName, // String316			filter_keys: Option<Vec<RmrkPropertyKey>>,317			at: Option<BlockHash>,318		) -> Result<Option<Theme>>;319	}320}321322// todo clone, derivative323pub struct Unique<C, P> {324	client: Arc<C>,325	_marker: std::marker::PhantomData<P>,326}327328impl<C, P> Unique<C, P> {329	pub fn new(client: Arc<C>) -> Self {330		Self {331			client,332			_marker: Default::default(),333		}334	}335}336337pub enum Error {338	RuntimeError,339}340341impl From<Error> for i64 {342	fn from(e: Error) -> i64 {343		match e {344			Error::RuntimeError => 1,345		}346	}347}348349macro_rules! pass_method {350	(351		$method_name:ident(352			$($(#[map(|$map_arg:ident| $map:expr)])? $name:ident: $ty:ty),* $(,)?353		) -> $result:ty $(=> $mapper:expr)?,354		//$runtime_name:ident $(<$($lt: tt),+>)*355		$runtime_api_macro:ident356		$(; changed_in $ver:expr, $changed_method_name:ident ($($changed_name:expr), * $(,)?) => $fixer:expr)*357	) => {358		fn $method_name(359			&self,360			$(361				$name: $ty,362			)*363			at: Option<<Block as BlockT>::Hash>,364		) -> Result<$result> {365			let api = self.client.runtime_api();366			let at = BlockId::hash(at.unwrap_or_else(|| self.client.info().best_hash));367			let _api_version = if let Ok(Some(api_version)) =368				api.api_version::<$runtime_api_macro!()>(&at)//<dyn $runtime_name $(<$($lt),+>)?>(&at)369			{370				api_version371			} else {372				// unreachable for our runtime373				return Err(RpcError {374					code: ErrorCode::InvalidParams,375					message: "Api is not available".into(),376					data: None,377				})378			};379380			let result = $(if _api_version < $ver {381				api.$changed_method_name(&at, $($changed_name),*).map(|r| r.map($fixer))382			} else)*383			{ api.$method_name(&at, $($((|$map_arg: $ty| $map))? ($name)),*) };384385			let result = result.map_err(|e| RpcError {386				code: ErrorCode::ServerError(Error::RuntimeError.into()),387				message: "Unable to query".into(),388				data: Some(format!("{:?}", e).into()),389			})?;390			result.map_err(|e| RpcError {391				code: ErrorCode::InvalidParams,392				message: "Runtime returned error".into(),393				data: Some(format!("{:?}", e).into()),394			})$(.map($mapper))?395		}396	};397}398399macro_rules! unique_api {400	() => {401		dyn UniqueRuntimeApi<Block, CrossAccountId, AccountId>402	};403}404405macro_rules! rmrk_api {406	() => {407		dyn RmrkRuntimeApi<Block, AccountId, CollectionInfo, NftInfo, ResourceInfo, PropertyInfo, BaseInfo, PartType, Theme>408	};409}410411#[allow(deprecated)]412impl<C, Block, CrossAccountId, AccountId>413	UniqueApi<<Block as BlockT>::Hash, CrossAccountId, AccountId> for Unique<C, Block>414where415	Block: BlockT,416	AccountId: Decode,417	C: 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,418	C::Api: UniqueRuntimeApi<Block, CrossAccountId, AccountId>, // todo unique_api!() possible?419	CrossAccountId: pallet_evm::account::CrossAccountId<AccountId>,420{421	pass_method!(422		account_tokens(collection: CollectionId, account: CrossAccountId) -> Vec<TokenId>, unique_api423	);424	pass_method!(425		collection_tokens(collection: CollectionId) -> Vec<TokenId>, unique_api426	);427	pass_method!(428		token_exists(collection: CollectionId, token: TokenId) -> bool, unique_api429	);430	pass_method!(431		token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>, unique_api432	);433	pass_method!(434		topmost_token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>, unique_api435	);436	/*pass_method!(437		token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>,438		UniqueRuntimeApi<Block, CrossAccountId, AccountId>;439		changed_in 2, token_owner_before_version_2(collection, token) => |u| Some(u)440	);*/441	pass_method!(442		const_metadata(collection: CollectionId, token: TokenId) -> Vec<u8>, unique_api443	);444	pass_method!(445		variable_metadata(collection: CollectionId, token: TokenId) -> Vec<u8>,446		unique_api447	);448	pass_method!(total_supply(collection: CollectionId) -> u32, unique_api);449	pass_method!(account_balance(collection: CollectionId, account: CrossAccountId) -> u32, unique_api);450	pass_method!(balance(collection: CollectionId, account: CrossAccountId, token: TokenId) -> String => |v| v.to_string(), unique_api);451	pass_method!(452		allowance(collection: CollectionId, sender: CrossAccountId, spender: CrossAccountId, token: TokenId) -> String => |v| v.to_string(),453		unique_api454	);455	pass_method!(topmost_token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>, unique_api);456	pass_method!(const_metadata(collection: CollectionId, token: TokenId) -> Vec<u8>, unique_api);457	pass_method!(variable_metadata(collection: CollectionId, token: TokenId) -> Vec<u8>, unique_api);458459	pass_method!(collection_properties(460		collection: CollectionId,461462		#[map(|keys| string_keys_to_bytes_keys(keys))]463		keys: Vec<String>464	) -> Vec<Property>, unique_api);465466	pass_method!(token_properties(467		collection: CollectionId,468		token_id: TokenId,469470		#[map(|keys| string_keys_to_bytes_keys(keys))]471		properties: Vec<String>472	) -> Vec<Property>, unique_api);473474	pass_method!(property_permissions(475		collection: CollectionId,476477		#[map(|keys| string_keys_to_bytes_keys(keys))]478		keys: Vec<String>479	) -> Vec<PropertyKeyPermission>, unique_api);480481	pass_method!(token_data(482		collection: CollectionId,483		token_id: TokenId,484485		#[map(|keys| string_keys_to_bytes_keys(keys))]486		keys: Vec<String>,487	) -> TokenData<CrossAccountId>, unique_api);488489	pass_method!(total_supply(collection: CollectionId) -> u32, unique_api);490	pass_method!(account_balance(collection: CollectionId, account: CrossAccountId) -> u32, unique_api);491	pass_method!(balance(collection: CollectionId, account: CrossAccountId, token: TokenId) -> String => |v| v.to_string(), unique_api);492	pass_method!(493		allowance(collection: CollectionId, sender: CrossAccountId, spender: CrossAccountId, token: TokenId) -> String => |v| v.to_string(), 494		unique_api495	); // todo format496497	pass_method!(adminlist(collection: CollectionId) -> Vec<CrossAccountId>, unique_api);498	pass_method!(allowlist(collection: CollectionId) -> Vec<CrossAccountId>, unique_api);499	pass_method!(allowed(collection: CollectionId, user: CrossAccountId) -> bool, unique_api);500	pass_method!(last_token_id(collection: CollectionId) -> TokenId, unique_api);501	pass_method!(collection_by_id(collection: CollectionId) -> Option<RpcCollection<AccountId>>, unique_api);502	pass_method!(collection_stats() -> CollectionStats, unique_api);503	pass_method!(next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Option<u64>, unique_api);504	pass_method!(effective_collection_limits(collection_id: CollectionId) -> Option<CollectionLimits>, unique_api);505}506507#[allow(deprecated)]508impl<509		C,510		Block,511		AccountId,512		CollectionInfo,513		NftInfo,514		ResourceInfo,515		PropertyInfo,516		BaseInfo,517		PartType,518		Theme,519	>520	rmrk::RmrkApi<521		<Block as BlockT>::Hash,522		AccountId,523		CollectionInfo,524		NftInfo,525		ResourceInfo,526		PropertyInfo,527		BaseInfo,528		PartType,529		Theme,530	> for Unique<C, Block>531where532	C: Send + Sync + 'static + ProvideRuntimeApi<Block> + HeaderBackend<Block>,533	C::Api: RmrkRuntimeApi<534		Block,535		AccountId,536		CollectionInfo,537		NftInfo,538		ResourceInfo,539		PropertyInfo,540		BaseInfo,541		PartType,542		Theme,543	>,544	AccountId: Decode + Encode,545	CollectionInfo: Decode,546	NftInfo: Decode,547	ResourceInfo: Decode,548	PropertyInfo: Decode,549	BaseInfo: Decode,550	PartType: Decode,551	Theme: Decode,552	Block: BlockT,553{554	pass_method!(last_collection_idx() -> RmrkCollectionId, rmrk_api);555	pass_method!(collection_by_id(id: RmrkCollectionId) -> Option<CollectionInfo>, rmrk_api);556	pass_method!(nft_by_id(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Option<NftInfo>, rmrk_api);557	pass_method!(account_tokens(account_id: AccountId, collection_id: RmrkCollectionId) -> Vec<RmrkNftId>, rmrk_api);558	pass_method!(nft_children(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<RmrkNftChild>, rmrk_api);559	pass_method!(560		collection_properties(collection_id: RmrkCollectionId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Vec<PropertyInfo>,561		rmrk_api562	);563	pass_method!(564		nft_properties(collection_id: RmrkCollectionId, nft_id: RmrkNftId, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Vec<PropertyInfo>,565		rmrk_api566	);567	pass_method!(nft_resources(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<ResourceInfo>, rmrk_api);568	pass_method!(nft_resource_priorities(collection_id: RmrkCollectionId, nft_id: RmrkNftId) -> Vec<RmrkResourceId>, rmrk_api);569	pass_method!(base(base_id: RmrkBaseId) -> Option<BaseInfo>, rmrk_api);570	pass_method!(base_parts(base_id: RmrkBaseId) -> Vec<PartType>, rmrk_api);571	pass_method!(theme_names(base_id: RmrkBaseId) -> Vec<RmrkThemeName>, rmrk_api);572	/*fn theme(573		&self,574		base_id: RmrkBaseId,575		theme_name: String,576		filter_keys: Option<Vec<String>>,577		at: Option<<Block as BlockT>::Hash>578	) -> Result<Option<Theme>> {todo!()}*/579	pass_method!(theme(base_id: RmrkBaseId, theme_name: RmrkThemeName, filter_keys: Option<Vec<RmrkPropertyKey>>) -> Option<Theme>, rmrk_api);580}581582fn string_keys_to_bytes_keys(keys: Vec<String>) -> Vec<Vec<u8>> {583	keys.into_iter().map(|key| key.into_bytes()).collect()584}