git.delta.rocks / unique-network / refs/commits / 549eb4c11dfd

difftreelog

source

pallets/nft/src/eth/sponsoring.rs4.0 KiBsourcehistory
1//! Implements EVM sponsoring logic via OnChargeEVMTransaction23use crate::{4	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},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;20use nft_data_structs::{NFT_SPONSOR_TRANSFER_TIMEOUT, FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT};2122struct AnyError;2324fn try_sponsor<T: Config>(25	caller: &H160,26	collection_id: u32,27	collection: &Collection<T>,28	call: &[u8],29) -> Result<(), AnyError> {30	let (method_id, mut reader) = AbiReader::new_call(call).map_err(|_| AnyError)?;31	match &collection.mode {32		crate::CollectionMode::NFT => {33			let call: UniqueNFTCall = UniqueNFTCall::parse(method_id, &mut reader)34				.map_err(|_| AnyError)?35				.ok_or(AnyError)?;36			match call {37				UniqueNFTCall::ERC721UniqueExtensions(38					ERC721UniqueExtensionsCall::TransferNft { token_id, .. },39				)40				| UniqueNFTCall::ERC721(ERC721Call::TransferFrom { token_id, .. }) => {41					let token_id: u32 = token_id.try_into().map_err(|_| AnyError)?;42					let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;43					let collection_limits = &collection.limits;44					let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {45						collection_limits.sponsor_transfer_timeout46					} else {47						NFT_SPONSOR_TRANSFER_TIMEOUT48					};4950					let mut sponsor = true;51					if <NftTransferBasket<T>>::contains_key(collection_id, token_id) {52						let last_tx_block = <NftTransferBasket<T>>::get(collection_id, token_id);53						let limit_time = last_tx_block + limit.into();54						if block_number <= limit_time {55							sponsor = false;56						}57					}58					if sponsor {59						<NftTransferBasket<T>>::insert(collection_id, token_id, block_number);60						return Ok(());61					}62				}63				_ => {}64			}65		}66		crate::CollectionMode::Fungible(_) => {67			let call: UniqueFungibleCall = UniqueFungibleCall::parse(method_id, &mut reader)68				.map_err(|_| AnyError)?69				.ok_or(AnyError)?;70			#[allow(clippy::single_match)]71			match call {72				UniqueFungibleCall::ERC20(ERC20Call::Transfer { .. }) => {73					let who = T::CrossAccountId::from_eth(*caller);74					let collection_limits = &collection.limits;75					let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {76						collection_limits.sponsor_transfer_timeout77					} else {78						FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT79					};8081					let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;82					let mut sponsored = true;83					if <FungibleTransferBasket<T>>::contains_key(collection_id, who.as_sub()) {84						let last_tx_block =85							<FungibleTransferBasket<T>>::get(collection_id, who.as_sub());86						let limit_time = last_tx_block + limit.into();87						if block_number <= limit_time {88							sponsored = false;89						}90					}91					if sponsored {92						<FungibleTransferBasket<T>>::insert(93							collection_id,94							who.as_sub(),95							block_number,96						);97						return Ok(());98					}99				}100				_ => {}101			}102		}103		_ => {}104	}105	Err(AnyError)106}107108pub struct NftEthSponsorshipHandler<T: Config>(PhantomData<*const T>);109impl<T: Config> SponsorshipHandler<H160, (H160, Vec<u8>)> for NftEthSponsorshipHandler<T> {110	fn get_sponsor(who: &H160, call: &(H160, Vec<u8>)) -> Option<H160> {111		if let Some(collection_id) = map_eth_to_id(&call.0) {112			if let Some(collection) = <CollectionById<T>>::get(collection_id) {113				if !collection.sponsorship.confirmed() {114					return None;115				}116				if try_sponsor(who, collection_id, &collection, &call.1).is_ok() {117					return collection118						.sponsorship119						.sponsor()120						.cloned()121						.map(T::EvmBackwardsAddressMapping::from_account_id);122				}123			}124		}125		None126	}127}