git.delta.rocks / unique-network / refs/commits / 278f1b9c8b83

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(39					ERC721UniqueExtensionsCall::TransferNft { token_id, .. },40				)41				| UniqueNFTCall::ERC721(ERC721Call::TransferFrom { token_id, .. }) => {42					let token_id: u32 = token_id.try_into().map_err(|_| AnyError)?;43					let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;44					let collection_limits = &collection.limits;45					let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {46						collection_limits.sponsor_transfer_timeout47					} else {48						NFT_SPONSOR_TRANSFER_TIMEOUT49					};5051					let mut sponsor = true;52					if <NftTransferBasket<T>>::contains_key(collection_id, token_id) {53						let last_tx_block = <NftTransferBasket<T>>::get(collection_id, token_id);54						let limit_time = last_tx_block + limit.into();55						if block_number <= limit_time {56							sponsor = false;57						}58					}59					if sponsor {60						<NftTransferBasket<T>>::insert(collection_id, token_id, block_number);61						return Ok(());62					}63				}64				_ => {}65			}66		}67		crate::CollectionMode::Fungible(_) => {68			let call: UniqueFungibleCall = UniqueFungibleCall::parse(method_id, &mut reader)69				.map_err(|_| AnyError)?70				.ok_or(AnyError)?;71			#[allow(clippy::single_match)]72			match call {73				UniqueFungibleCall::ERC20(ERC20Call::Transfer { .. }) => {74					let who = T::CrossAccountId::from_eth(*caller);75					let collection_limits = &collection.limits;76					let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {77						collection_limits.sponsor_transfer_timeout78					} else {79						FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT80					};8182					let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;83					let mut sponsored = true;84					if <FungibleTransferBasket<T>>::contains_key(collection_id, who.as_sub()) {85						let last_tx_block =86							<FungibleTransferBasket<T>>::get(collection_id, who.as_sub());87						let limit_time = last_tx_block + limit.into();88						if block_number <= limit_time {89							sponsored = false;90						}91					}92					if sponsored {93						<FungibleTransferBasket<T>>::insert(94							collection_id,95							who.as_sub(),96							block_number,97						);98						return Ok(());99					}100				}101				_ => {}102			}103		}104		_ => {}105	}106	Err(AnyError)107}108109pub struct NftEthSponsorshipHandler<T: Config>(PhantomData<*const T>);110impl<T: Config> SponsorshipHandler<H160, (H160, Vec<u8>)> for NftEthSponsorshipHandler<T> {111	fn get_sponsor(who: &H160, call: &(H160, Vec<u8>)) -> Option<H160> {112		if let Some(collection_id) = map_eth_to_id(&call.0) {113			if let Some(collection) = <CollectionById<T>>::get(collection_id) {114				if !collection.sponsorship.confirmed() {115					return None;116				}117				if try_sponsor(who, collection_id, &collection, &call.1).is_ok() {118					return collection119						.sponsorship120						.sponsor()121						.cloned()122						.map(T::EvmBackwardsAddressMapping::from_account_id);123				}124			}125		}126		None127	}128}