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

difftreelog

source

pallets/nft-transaction-payment/src/lib.rs11.4 KiBsourcehistory
1//2// This file is subject to the terms and conditions defined in3// file 'LICENSE', which is part of this source code package.4//56#![cfg_attr(not(feature = "std"), no_std)]78#[cfg(feature = "std")]9pub use std::*;1011#[cfg(feature = "std")]12pub use serde::*;1314#[cfg(feature = "runtime-benchmarks")]15mod benchmarking;1617#[cfg(test)]18mod tests;1920use frame_support::{21	decl_error, decl_module, decl_storage,22	traits::{23		IsSubType, 24	},25	weights::{26		DispatchInfo27	}28};29use sp_runtime::traits::StaticLookup;30use sp_runtime::{31	traits::{ 32		Hash, Dispatchable,33	},34	transaction_validity::{35        InvalidTransaction, TransactionValidityError,36    },37};38use pallet_contracts::chain_extension::UncheckedFrom;39use sp_std::prelude::*;40use nft_data_structs::{41	CreateItemData,42	CollectionId, CollectionMode, TokenId43};4445type CodeHash<T> = <T as frame_system::Config>::Hash;4647	pub trait Config: frame_system::Config + pallet_contracts::Config + pallet_transaction_payment::Config + pallet_nft::Config {48	}4950	// Error for non-fungible-token module.51	52	decl_error! {53		/// Error for non-fungible-token module.54		pub enum Error for Module<T: Config> {55		/// No available class ID56		NoAvailableClassId,57		/// No available token ID58		NoAvailableTokenId,59		/// Token(ClassId, TokenId) not found60		TokenNotFound,61		/// Class not found62		CollectionNotFound,63		/// The operator is not the owner of the token and has no permission64		NoPermission,65		/// Arithmetic calculation overflow66		NumOverflow,67		/// Can not destroy class68		/// Total issuance is not 069		CannotDestroyClass,70	}71}7273	decl_storage! {74		trait Store for Module<T: Config> as NftTransactionPayment{7576	}77}7879decl_module! {8081	pub struct Module<T: Config> for enum Call 82    where 83		origin: T::Origin,84    {85	}86}8788impl<T: Config> Module<T> 89{9091	pub fn check_error(92		who: &T::AccountId,93		call: &T::Call94	) -> Result<bool, TransactionValidityError> where 95		T::Call: Dispatchable<Info=DispatchInfo>,96		T::Call: IsSubType<pallet_nft::Call<T>>, 97		T::Call: IsSubType<pallet_contracts::Call<T>>,98		T::AccountId: AsRef<[u8]>,99		T::AccountId: UncheckedFrom<T::Hash>100		{101102			match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {103				Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {104	105					let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());106	107					let owned_contract = pallet_nft::ContractOwner::<T>::get(called_contract.clone()).as_ref() == Some(who);108					let white_list_enabled = pallet_nft::ContractWhiteListEnabled::<T>::contains_key(called_contract.clone());109					  110					if !owned_contract && white_list_enabled {111						if !pallet_nft::ContractWhiteList::<T>::contains_key(called_contract.clone(), who) {112							return Err(InvalidTransaction::Call.into());113						}114					}115					Ok(true)116				},117				_ => { Ok(true) },118			}119		}120121	pub fn withdraw_type(122		who: &T::AccountId,123		call: &T::Call124	) -> Option<T::AccountId> where 125		T::Call: Dispatchable<Info=DispatchInfo>,126		T::Call: IsSubType<pallet_nft::Call<T>>, 127		T::Call: IsSubType<pallet_contracts::Call<T>>,128		T::AccountId: AsRef<[u8]>,129		T::AccountId: UncheckedFrom<T::Hash>130		{131132        let mut sponsor: Option<T::AccountId> = match IsSubType::<pallet_nft::Call<T>>::is_sub_type(call)  {133            Some(pallet_nft::Call::create_item(collection_id, _owner, _properties)) => {134135                Self::withdraw_create_item(who, collection_id, &_properties)136            },137            Some(pallet_nft::Call::transfer(_new_owner, collection_id, item_id, _value)) => {138139                Self::withdraw_transfer(who, collection_id, item_id)140            },141            Some(pallet_nft::Call::set_variable_meta_data(collection_id, item_id, data)) => {142143                Self::withdraw_set_variable_meta_data(collection_id, item_id, &data)144			},145			_ => None,146        };147148        sponsor = sponsor.or_else(|| match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {149            Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {150151                Self::withdraw_contract_call(who, dest)152            },153            Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, _data, salt)) => {154155                Self::withdraw_contract_instantiate(&who, code_hash, salt)156            },157            Some(pallet_contracts::Call::instantiate_with_code(_endowment, _gas_limit, _code, _data, _salt))  => {158159                Self::withdraw_contract_instantiate(&who, &T::Hashing::hash(&_code), _salt)160			},161			_ => None,162        });163164		sponsor165	}166167168169	pub fn withdraw_create_item(170		who: &T::AccountId,171		collection_id: &CollectionId,172		_properties: &CreateItemData,173	) -> Option<T::AccountId> {174	175		let collection = pallet_nft::CollectionById::<T>::get(collection_id)?;176177		// sponsor timeout178		let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;179180		let limit = collection.limits.sponsor_transfer_timeout;181		if pallet_nft::CreateItemBasket::<T>::contains_key((collection_id, &who)) {182			let last_tx_block = pallet_nft::CreateItemBasket::<T>::get((collection_id, &who));183			let limit_time = last_tx_block + limit.into();184			if block_number <= limit_time {185				return None;186			}187		}188		pallet_nft::CreateItemBasket::<T>::insert((collection_id, who.clone()), block_number);189190		// check free create limit191		if collection.limits.sponsored_data_size >= (_properties.len() as u32) {192			collection.sponsorship.sponsor()193				.cloned()194		} else {195			None196		}197	}198199	pub fn withdraw_transfer(200		who: &T::AccountId,201		collection_id: &CollectionId,202		item_id: &TokenId,203	) -> Option<T::AccountId> {204205		let collection = pallet_nft::CollectionById::<T>::get(collection_id)?;206		let limits = pallet_nft::ChainLimit::get();207208		let mut sponsor_transfer = false;209		if collection.sponsorship.confirmed() {210211			let collection_limits = collection.limits.clone();212			let collection_mode = collection.mode.clone();213214			// sponsor timeout215			let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;216			sponsor_transfer = match collection_mode {217				CollectionMode::NFT => {218219					// get correct limit220					let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {221						collection_limits.sponsor_transfer_timeout222					} else {223						limits.nft_sponsor_transfer_timeout224					};225226					let mut sponsored = true;227					if pallet_nft::NftTransferBasket::<T>::contains_key(collection_id, item_id) {228						let last_tx_block = pallet_nft::NftTransferBasket::<T>::get(collection_id, item_id);229						let limit_time = last_tx_block + limit.into();230						if block_number <= limit_time {231							sponsored = false;232						}233					}234					if sponsored {235						pallet_nft::NftTransferBasket::<T>::insert(collection_id, item_id, block_number);236					}237238					sponsored239				}240				CollectionMode::Fungible(_) => {241242					// get correct limit243					let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {244						collection_limits.sponsor_transfer_timeout245					} else {246						limits.fungible_sponsor_transfer_timeout247					};248249					let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;250					let mut sponsored = true;251					if pallet_nft::FungibleTransferBasket::<T>::contains_key(collection_id, who) {252						let last_tx_block = pallet_nft::FungibleTransferBasket::<T>::get(collection_id, who);253						let limit_time = last_tx_block + limit.into();254						if block_number <= limit_time {255							sponsored = false;256						}257					}258					if sponsored {259						pallet_nft::FungibleTransferBasket::<T>::insert(collection_id, who, block_number);260					}261262					sponsored263				}264				CollectionMode::ReFungible => {265266					// get correct limit267					let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {268						collection_limits.sponsor_transfer_timeout269					} else {270						limits.refungible_sponsor_transfer_timeout271					};272273					let mut sponsored = true;274					if pallet_nft::ReFungibleTransferBasket::<T>::contains_key(collection_id, item_id) {275						let last_tx_block = pallet_nft::ReFungibleTransferBasket::<T>::get(collection_id, item_id);276						let limit_time = last_tx_block + limit.into();277						if block_number <= limit_time {278							sponsored = false;279						}280					}281					if sponsored {282						pallet_nft::ReFungibleTransferBasket::<T>::insert(collection_id, item_id, block_number);283					}284285					sponsored286				}287				_ => {288					false289				},290			};291		}292293		if !sponsor_transfer {294			None295		} else {296			collection.sponsorship.sponsor()297				.cloned()298		}299	}300	301	pub fn withdraw_set_variable_meta_data(302		collection_id: &CollectionId,303		item_id: &TokenId,304		data: &Vec<u8>,305	) -> Option<T::AccountId> {306307		let mut sponsor_metadata_changes = false;308309		let collection = pallet_nft::CollectionById::<T>::get(collection_id)?;310311		if312			collection.sponsorship.confirmed() &&313			// Can't sponsor fungible collection, this tx will be rejected314			// as invalid315			!matches!(collection.mode, CollectionMode::Fungible(_)) &&316			data.len() <= collection.limits.sponsored_data_size as usize317		{318			if let Some(rate_limit) = collection.limits.sponsored_data_rate_limit {319				let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;320321				if pallet_nft::VariableMetaDataBasket::<T>::get(collection_id, item_id)322					.map(|last_block| block_number - last_block > rate_limit)323					.unwrap_or(true) 324				{325					sponsor_metadata_changes = true;326					pallet_nft::VariableMetaDataBasket::<T>::insert(collection_id, item_id, block_number);327				}328			}329		}330331		if !sponsor_metadata_changes {332			None333		} else {334			collection.sponsorship.sponsor().cloned()335		}336337	}338339	pub fn withdraw_contract_call(340		who: &T::AccountId,341		dest: &<T::Lookup as StaticLookup>::Source342	) -> Option<T::AccountId> {343344		let called_contract: T::AccountId = T::Lookup::lookup((dest).clone()).unwrap_or(T::AccountId::default());345346		let owned_contract = pallet_nft::ContractOwner::<T>::get(called_contract.clone()).as_ref() == Some(who);347		let white_list_enabled = pallet_nft::ContractWhiteListEnabled::<T>::contains_key(called_contract.clone());348		  349		// ???350		if !owned_contract && white_list_enabled {351		 	if !pallet_nft::ContractWhiteList::<T>::contains_key(called_contract.clone(), who) {352				return Some(who.clone())353		 		// return Err(InvalidTransaction::Call.into());354		 	}355		}356357		let mut sponsor_transfer = false;358		if pallet_nft::ContractSponsoringRateLimit::<T>::contains_key(called_contract.clone()) {359			let last_tx_block = pallet_nft::ContractSponsorBasket::<T>::get((&called_contract, &who));360			let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;361			let rate_limit = pallet_nft::ContractSponsoringRateLimit::<T>::get(&called_contract);362			let limit_time = last_tx_block + rate_limit;363364			if block_number >= limit_time {365				pallet_nft::ContractSponsorBasket::<T>::insert((called_contract.clone(), who.clone()), block_number);366				sponsor_transfer = true;367			}368		} else {369			sponsor_transfer = false;370		}371	   372		if sponsor_transfer {373			if pallet_nft::ContractSelfSponsoring::<T>::contains_key(called_contract.clone()) {374				if pallet_nft::ContractSelfSponsoring::<T>::get(called_contract.clone()) {375					return Some(called_contract);376				}377			}378		}379380		None381	}382383	pub fn withdraw_contract_instantiate(384		who: &T::AccountId,385		code_hash: &CodeHash<T>,386		salt: &[u8],387	) -> Option<T::AccountId> where388	T::AccountId: AsRef<[u8]>,389	T::AccountId: UncheckedFrom<T::Hash>390	{391392		let new_contract_address = <pallet_contracts::Pallet<T>>::contract_address(393			&who,394			code_hash,395			salt,396		);397		pallet_nft::ContractOwner::<T>::insert(new_contract_address.clone(), who.clone());398399		None400	}401}