git.delta.rocks / unique-network / refs/commits / 448eded3df3f

difftreelog

source

pallets/nft/src/eth/sponsoring.rs3.9 KiBsourcehistory
1//! Implements EVM sponsoring logic via OnChargeEVMTransaction23use crate::{4	ChainLimit, Collection, CollectionById, Config, FungibleTransferBasket, NftTransferBasket,5	eth::{account::EvmBackwardsAddressMapping, map_eth_to_id},6};7use evm_coder::{Call, abi::AbiReader};8use frame_support::{9	storage::{StorageMap, StorageDoubleMap, StorageValue},10};11use sp_core::H160;12use sp_std::prelude::*;13use up_sponsorship::SponsorshipHandler;14use super::{15	account::CrossAccountId,16	erc::{UniqueFungibleCall, UniqueNFTCall, ERC721Call, ERC20Call, ERC721UniqueExtensionsCall},17};18use core::convert::TryInto;19use core::marker::PhantomData;2021struct AnyError;2223fn try_sponsor<T: Config>(24	caller: &H160,25	collection_id: u32,26	collection: &Collection<T>,27	call: &[u8],28) -> Result<(), AnyError> {29	let (method_id, mut reader) = AbiReader::new_call(call).map_err(|_| AnyError)?;30	match &collection.mode {31		crate::CollectionMode::NFT => {32			let call: UniqueNFTCall = UniqueNFTCall::parse(method_id, &mut reader)33				.map_err(|_| AnyError)?34				.ok_or(AnyError)?;35			match call {36				UniqueNFTCall::ERC721UniqueExtensions(37					ERC721UniqueExtensionsCall::TransferNft { token_id, .. },38				)39				| UniqueNFTCall::ERC721(ERC721Call::TransferFrom { token_id, .. }) => {40					let token_id: u32 = token_id.try_into().map_err(|_| AnyError)?;41					let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;42					let collection_limits = &collection.limits;43					let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {44						collection_limits.sponsor_transfer_timeout45					} else {46						ChainLimit::get().nft_sponsor_transfer_timeout47					};4849					let mut sponsor = true;50					if <NftTransferBasket<T>>::contains_key(collection_id, token_id) {51						let last_tx_block = <NftTransferBasket<T>>::get(collection_id, token_id);52						let limit_time = last_tx_block + limit.into();53						if block_number <= limit_time {54							sponsor = false;55						}56					}57					if sponsor {58						<NftTransferBasket<T>>::insert(collection_id, token_id, block_number);59						return Ok(());60					}61				}62				_ => {}63			}64		}65		crate::CollectionMode::Fungible(_) => {66			let call: UniqueFungibleCall = UniqueFungibleCall::parse(method_id, &mut reader)67				.map_err(|_| AnyError)?68				.ok_or(AnyError)?;69			#[allow(clippy::single_match)]70			match call {71				UniqueFungibleCall::ERC20(ERC20Call::Transfer { .. }) => {72					let who = T::CrossAccountId::from_eth(*caller);73					let collection_limits = &collection.limits;74					let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {75						collection_limits.sponsor_transfer_timeout76					} else {77						ChainLimit::get().fungible_sponsor_transfer_timeout78					};7980					let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;81					let mut sponsored = true;82					if <FungibleTransferBasket<T>>::contains_key(collection_id, who.as_sub()) {83						let last_tx_block =84							<FungibleTransferBasket<T>>::get(collection_id, who.as_sub());85						let limit_time = last_tx_block + limit.into();86						if block_number <= limit_time {87							sponsored = false;88						}89					}90					if sponsored {91						<FungibleTransferBasket<T>>::insert(92							collection_id,93							who.as_sub(),94							block_number,95						);96						return Ok(());97					}98				}99				_ => {}100			}101		}102		_ => {}103	}104	Err(AnyError)105}106107pub struct NftEthSponsorshipHandler<T: Config>(PhantomData<*const T>);108impl<T: Config> SponsorshipHandler<H160, (H160, Vec<u8>)> for NftEthSponsorshipHandler<T> {109	fn get_sponsor(who: &H160, call: &(H160, Vec<u8>)) -> Option<H160> {110		if let Some(collection_id) = map_eth_to_id(&call.0) {111			if let Some(collection) = <CollectionById<T>>::get(collection_id) {112				if !collection.sponsorship.confirmed() {113					return None;114				}115				if try_sponsor(who, collection_id, &collection, &call.1).is_ok() {116					return collection117						.sponsorship118						.sponsor()119						.cloned()120						.map(T::EvmBackwardsAddressMapping::from_account_id);121				}122			}123		}124		None125	}126}