git.delta.rocks / unique-network / refs/commits / 13e91d34e4ba

difftreelog

fix(`evm-transaction-payment`) clippy

PraetorP2023-10-04parent: #f9563fa.patch.diff
in: master

1 file changed

modifiedpallets/evm-transaction-payment/src/lib.rsdiffbeforeafterboth
before · pallets/evm-transaction-payment/src/lib.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617#![doc = include_str!("../README.md")]18#![cfg_attr(not(feature = "std"), no_std)]19#![deny(missing_docs)]2021use core::marker::PhantomData;2223use fp_evm::{CheckEvmTransaction, FeeCalculator, TransactionValidationError, WithdrawReason};24use frame_support::{25	storage::with_transaction,26	traits::{Currency, Imbalance, IsSubType, OnUnbalanced},27};28pub use pallet::*;29use pallet_evm::{30	account::CrossAccountId, EnsureAddressOrigin, NegativeImbalanceOf, OnChargeEVMTransaction,31	OnCheckEvmTransaction,32};33use sp_core::{H160, U256};34use sp_runtime::{traits::UniqueSaturatedInto, DispatchError, TransactionOutcome};35use up_sponsorship::SponsorshipHandler;3637#[frame_support::pallet]38pub mod pallet {39	use sp_std::vec::Vec;4041	use super::*;4243	/// Contains call data44	pub struct CallContext {45		/// Contract address46		pub contract_address: H160,47		/// Transaction data48		pub input: Vec<u8>,49		/// Max fee for transaction - gasLimit * gasPrice50		pub max_fee: U256,51	}5253	#[pallet::config]54	pub trait Config: frame_system::Config + pallet_evm::Config {55		/// Loosly-coupled handlers for evm call sponsoring56		type EvmSponsorshipHandler: SponsorshipHandler<Self::CrossAccountId, CallContext>;57	}5859	#[pallet::pallet]60	pub struct Pallet<T>(_);61}6263fn who_pays_fee<T: Config>(64	origin: H160,65	max_fee: U256,66	reason: &WithdrawReason,67) -> Option<T::CrossAccountId> {68	match reason {69		WithdrawReason::Call { target, input, .. } => {70			let origin_sub = T::CrossAccountId::from_eth(origin);71			let call_context = CallContext {72				contract_address: *target,73				input: input.clone(),74				max_fee,75			};76			T::EvmSponsorshipHandler::get_sponsor(&origin_sub, &call_context)77		}78		_ => None,79	}80}8182fn get_sponsor<T: Config>(83	source: H160,84	max_fee_per_gas: Option<U256>,85	gas_limit: u64,86	reason: &WithdrawReason,87	is_transactional: bool,88	is_check: bool,89) -> Option<T::CrossAccountId> {90	let accept_gas_fee = |gas_fee| {91		let (base_fee, _) = T::FeeCalculator::min_gas_price();92		base_fee <= gas_fee && gas_fee <= base_fee * 21 / 1093	};94	let (max_fee_per_gas, may_sponsor) = match (max_fee_per_gas, is_transactional) {95		(Some(max_fee_per_gas), _) => (max_fee_per_gas, accept_gas_fee(max_fee_per_gas)),96		// Gas price check is skipped for non-transactional calls that don't97		// define a `max_fee_per_gas` input.98		(None, false) => (Default::default(), true),99		_ => return None,100	};101102	let max_fee = max_fee_per_gas.saturating_mul(gas_limit.into());103104	// #[cfg(feature = "debug-logging")]105	// log::trace!(target: "sponsoring", "checking who will pay fee for {:?} {:?}", source, reason);106	with_transaction(|| {107		let result = may_sponsor108			.then(|| who_pays_fee::<T>(source, max_fee, reason))109			.flatten();110		if is_check {111			TransactionOutcome::Rollback(Ok::<_, DispatchError>(result))112		} else {113			TransactionOutcome::Commit(Ok(result))114		}115	})116	.ok()117	.flatten()118}119/// Implements sponsoring for evm calls performed from pallet-evm (via api.tx.ethereum.transact/api.tx.evm.call)120pub struct BridgeSponsorshipHandler<T>(PhantomData<T>);121impl<T, C> SponsorshipHandler<T::AccountId, C> for BridgeSponsorshipHandler<T>122where123	T: Config + pallet_evm::Config,124	C: IsSubType<pallet_evm::Call<T>>,125{126	fn get_sponsor(who: &T::AccountId, call: &C) -> Option<T::AccountId> {127		match call.is_sub_type()? {128			pallet_evm::Call::call {129				source,130				target,131				input,132				gas_limit,133				max_fee_per_gas,134				..135			} => {136				let _ = T::CallOrigin::ensure_address_origin(137					source,138					<frame_system::RawOrigin<T::AccountId>>::Signed(who.clone()).into(),139				)140				.ok()?;141				let who = T::CrossAccountId::from_sub(who.clone());142				let max_fee = max_fee_per_gas.saturating_mul((*gas_limit).into());143				let call_context = CallContext {144					contract_address: *target,145					input: input.clone(),146					max_fee,147				};148				// Effects from EvmSponsorshipHandler are applied by pallet_evm::runner149				// TODO: Should we implement simulation mode (test, but do not apply effects) in `up-sponsorship`?150				let sponsor = frame_support::storage::with_transaction(|| {151					TransactionOutcome::Rollback(Ok::<_, DispatchError>(152						T::EvmSponsorshipHandler::get_sponsor(&who, &call_context),153					))154				})155				// FIXME: it may fail with DispatchError in case of depth limit156				.ok()??;157				Some(sponsor.as_sub().clone())158			}159			_ => None,160		}161	}162}163164/// Set transaction sponsor if available and enough balance.165pub struct TransactionValidity<T>(PhantomData<T>);166impl<T: Config> OnCheckEvmTransaction<T> for TransactionValidity<T> {167	fn on_check_evm_transaction(168		v: &mut CheckEvmTransaction,169		origin: &T::CrossAccountId,170	) -> Result<(), TransactionValidationError> {171		let who = &v.who;172		let max_fee_per_gas = Some(v.transaction_fee_input()?.0);173		let gas_limit = v.transaction.gas_limit.low_u64();174		let reason = if let Some(to) = v.transaction.to {175			WithdrawReason::Call {176				target: to,177				input: v.transaction.input.clone(),178				max_fee_per_gas,179				gas_limit,180				is_transactional: v.config.is_transactional,181				is_check: true,182			}183		} else {184			WithdrawReason::Create185		};186		let sponsor = get_sponsor::<T>(187			*origin.as_eth(),188			max_fee_per_gas,189			gas_limit,190			&reason,191			v.config.is_transactional,192			true,193		)194		.as_ref()195		.map(pallet_evm::Pallet::<T>::account_basic_by_id)196		.map(|v| v.0);197		let fee = max_fee_per_gas198			.unwrap()199			.saturating_mul(v.transaction.gas_limit);200		if let Some(sponsor) = sponsor.as_ref() {201			if who.balance < v.transaction.value || sponsor.balance < fee {202				return Err(TransactionValidationError::BalanceTooLow.into());203			}204		} else {205			let total_payment = v.transaction.value.saturating_add(fee);206			if who.balance < total_payment {207				return Err(TransactionValidationError::BalanceTooLow.into());208			}209		}210211		let who = sponsor.unwrap_or_else(|| v.who.clone());212		v.who.balance = who.balance;213		Ok(())214	}215}216217/// Implements the transaction payment for a pallet implementing the `Currency`218/// trait (eg. the pallet_balances) using an unbalance handler (implementing219/// `OnUnbalanced`).220/// Similar to `CurrencyAdapter` of `pallet_transaction_payment`221pub struct WrappedEVMCurrencyAdapter<C, OU>(sp_std::marker::PhantomData<(C, OU)>);222impl<T, C, OU> OnChargeEVMTransaction<T> for WrappedEVMCurrencyAdapter<C, OU>223where224	T: Config,225	C: Currency<<T as frame_system::Config>::AccountId>,226	C::PositiveImbalance: Imbalance<227		<C as Currency<<T as frame_system::Config>::AccountId>>::Balance,228		Opposite = C::NegativeImbalance,229	>,230	C::NegativeImbalance: Imbalance<231		<C as Currency<<T as frame_system::Config>::AccountId>>::Balance,232		Opposite = C::PositiveImbalance,233	>,234	OU: OnUnbalanced<NegativeImbalanceOf<C, T>>,235	U256: UniqueSaturatedInto<<C as Currency<<T as frame_system::Config>::AccountId>>::Balance>,236{237	// Kept type as Option to satisfy bound of Default238	type LiquidityInfo = (Option<NegativeImbalanceOf<C, T>>, Option<T::CrossAccountId>);239240	fn withdraw_fee(241		who: &T::CrossAccountId,242		reason: WithdrawReason,243		fee: U256,244	) -> Result<Self::LiquidityInfo, pallet_evm::Error<T>> {245		let sponsor = match reason {246			WithdrawReason::Call {247				max_fee_per_gas,248				gas_limit,249				is_transactional,250				is_check,251				..252			} => get_sponsor::<T>(253				*who.as_eth(),254				max_fee_per_gas,255				gas_limit,256				&reason,257				is_transactional,258				is_check,259			),260			_ => None,261		};262263		let who = sponsor.as_ref().unwrap_or(who);264		<pallet_evm::EVMCurrencyAdapter<C, OU> as OnChargeEVMTransaction<T>>::withdraw_fee(265			who, reason, fee,266		)267		.map(|li| (li, sponsor))268	}269270	fn correct_and_deposit_fee(271		who: &T::CrossAccountId,272		corrected_fee: U256,273		base_fee: U256,274		already_withdrawn: Self::LiquidityInfo,275	) -> Self::LiquidityInfo {276		let (already_withdrawn, sponsor) = already_withdrawn;277		let who = sponsor.as_ref().unwrap_or(who);278		(279			<pallet_evm::EVMCurrencyAdapter<C, OU> as OnChargeEVMTransaction<T>>::correct_and_deposit_fee(280				who,281				corrected_fee,282				base_fee,283				already_withdrawn,284			),285			None286		)287	}288289	fn pay_priority_fee(tip: Self::LiquidityInfo) {290		<pallet_evm::EVMCurrencyAdapter<C, OU> as OnChargeEVMTransaction<T>>::pay_priority_fee(291			tip.0,292		)293	}294}