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

difftreelog

source

pallets/nft/src/eth/sponsoring.rs4.0 KiBsourcehistory
1//! Implements EVM sponsoring logic via OnChargeEVMTransaction23use crate::{Collection, Config, FungibleTransferBasket, NftTransferBasket};4use evm_coder::{Call, abi::AbiReader};5use frame_support::{6	storage::{StorageDoubleMap},7};8use pallet_common::eth::map_eth_to_id;9use sp_core::H160;10use sp_std::prelude::*;11use up_sponsorship::SponsorshipHandler;12use core::marker::PhantomData;13use core::convert::TryInto;14use nft_data_structs::{CollectionId, NFT_SPONSOR_TRANSFER_TIMEOUT, FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT};15use pallet_common::{16	CollectionById,17	account::{CrossAccountId, EvmBackwardsAddressMapping},18};1920use pallet_nonfungible::erc::{UniqueNFTCall, ERC721UniqueExtensionsCall, ERC721Call};21use pallet_fungible::erc::{UniqueFungibleCall, ERC20Call};2223struct AnyError;2425fn try_sponsor<T: Config>(26	caller: &H160,27	collection_id: CollectionId,28	collection: &Collection<T>,29	call: &[u8],30) -> Result<(), AnyError> {31	let (method_id, mut reader) = AbiReader::new_call(call).map_err(|_| AnyError)?;32	match &collection.mode {33		crate::CollectionMode::NFT => {34			let call: UniqueNFTCall = UniqueNFTCall::parse(method_id, &mut reader)35				.map_err(|_| AnyError)?36				.ok_or(AnyError)?;37			match call {38				UniqueNFTCall::ERC721UniqueExtensions(ERC721UniqueExtensionsCall::Transfer {39					token_id,40					..41				})42				| UniqueNFTCall::ERC721(ERC721Call::TransferFrom { token_id, .. }) => {43					let token_id: u32 = token_id.try_into().map_err(|_| AnyError)?;44					let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;45					let collection_limits = &collection.limits;46					let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {47						collection_limits.sponsor_transfer_timeout48					} else {49						NFT_SPONSOR_TRANSFER_TIMEOUT50					};5152					let mut sponsor = true;53					if <NftTransferBasket<T>>::contains_key(collection_id, token_id) {54						let last_tx_block = <NftTransferBasket<T>>::get(collection_id, token_id);55						let limit_time = last_tx_block + limit.into();56						if block_number <= limit_time {57							sponsor = false;58						}59					}60					if sponsor {61						<NftTransferBasket<T>>::insert(collection_id, token_id, block_number);62						return Ok(());63					}64				}65				_ => {}66			}67		}68		crate::CollectionMode::Fungible(_) => {69			let call: UniqueFungibleCall = UniqueFungibleCall::parse(method_id, &mut reader)70				.map_err(|_| AnyError)?71				.ok_or(AnyError)?;72			#[allow(clippy::single_match)]73			match call {74				UniqueFungibleCall::ERC20(ERC20Call::Transfer { .. }) => {75					let who = T::CrossAccountId::from_eth(*caller);76					let collection_limits = &collection.limits;77					let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {78						collection_limits.sponsor_transfer_timeout79					} else {80						FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT81					};8283					let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;84					let mut sponsored = true;85					if <FungibleTransferBasket<T>>::contains_key(collection_id, who.as_sub()) {86						let last_tx_block =87							<FungibleTransferBasket<T>>::get(collection_id, who.as_sub());88						let limit_time = last_tx_block + limit.into();89						if block_number <= limit_time {90							sponsored = false;91						}92					}93					if sponsored {94						<FungibleTransferBasket<T>>::insert(95							collection_id,96							who.as_sub(),97							block_number,98						);99						return Ok(());100					}101				}102				_ => {}103			}104		}105		_ => {}106	}107	Err(AnyError)108}109110pub struct NftEthSponsorshipHandler<T: Config>(PhantomData<*const T>);111impl<T: Config> SponsorshipHandler<H160, (H160, Vec<u8>)> for NftEthSponsorshipHandler<T> {112	fn get_sponsor(who: &H160, call: &(H160, Vec<u8>)) -> Option<H160> {113		if let Some(collection_id) = map_eth_to_id(&call.0) {114			if let Some(collection) = <CollectionById<T>>::get(collection_id) {115				if !collection.sponsorship.confirmed() {116					return None;117				}118				if try_sponsor(who, collection_id, &collection, &call.1).is_ok() {119					return collection120						.sponsorship121						.sponsor()122						.cloned()123						.map(T::EvmBackwardsAddressMapping::from_account_id);124				}125			}126		}127		None128	}129}