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

difftreelog

source

pallets/nft/src/eth/sponsoring.rs3.8 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<T>>::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 =47						collection_limits.sponsor_transfer_timeout(NFT_SPONSOR_TRANSFER_TIMEOUT);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<T>>::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 = collection_limits75						.sponsor_transfer_timeout(FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT);7677					let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;78					let mut sponsored = true;79					if <FungibleTransferBasket<T>>::contains_key(collection_id, who.as_sub()) {80						let last_tx_block =81							<FungibleTransferBasket<T>>::get(collection_id, who.as_sub());82						let limit_time = last_tx_block + limit.into();83						if block_number <= limit_time {84							sponsored = false;85						}86					}87					if sponsored {88						<FungibleTransferBasket<T>>::insert(89							collection_id,90							who.as_sub(),91							block_number,92						);93						return Ok(());94					}95				}96				_ => {}97			}98		}99		_ => {}100	}101	Err(AnyError)102}103104pub struct NftEthSponsorshipHandler<T: Config>(PhantomData<*const T>);105impl<T: Config> SponsorshipHandler<H160, (H160, Vec<u8>)> for NftEthSponsorshipHandler<T> {106	fn get_sponsor(who: &H160, call: &(H160, Vec<u8>)) -> Option<H160> {107		if let Some(collection_id) = map_eth_to_id(&call.0) {108			if let Some(collection) = <CollectionById<T>>::get(collection_id) {109				if !collection.sponsorship.confirmed() {110					return None;111				}112				if try_sponsor(who, collection_id, &collection, &call.1).is_ok() {113					return collection114						.sponsorship115						.sponsor()116						.cloned()117						.map(T::EvmBackwardsAddressMapping::from_account_id);118				}119			}120		}121		None122	}123}