difftreelog
feat use new ethereum sponsoring interface
in: master
2 files changed
pallets/evm-transaction-payment/src/lib.rsdiffbeforeafterboth60 pub struct Pallet<T>(_);60 pub struct Pallet<T>(_);61}61}626263/// Implements [`fp_evm::TransactionValidityHack`], which provides sponsor address to pallet-evm64pub struct TransactionValidityHack<T: Config>(PhantomData<*const T>);65impl<T: Config> fp_evm::TransactionValidityHack<T::CrossAccountId> for TransactionValidityHack<T> {63fn who_pays_fee<T: Config>(66 fn who_pays_fee(67 origin: H160,64 origin: H160,68 max_fee: U256,65 max_fee: U256,69 reason: &WithdrawReason,66 reason: &WithdrawReason,70 ) -> Option<T::CrossAccountId> {67) -> Option<T::CrossAccountId> {71 match reason {68 match reason {72 WithdrawReason::Call { target, input } => {69 WithdrawReason::Call { target, input, .. } => {73 let origin_sub = T::CrossAccountId::from_eth(origin);70 let origin_sub = T::CrossAccountId::from_eth(origin);74 let call_context = CallContext {71 let call_context = CallContext {75 contract_address: *target,72 contract_address: *target,81 _ => None,78 _ => None,82 }79 }83 }80}84}818582fn 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}86/// Implements sponsoring for evm calls performed from pallet-evm (via api.tx.ethereum.transact/api.tx.evm.call)119/// Implements sponsoring for evm calls performed from pallet-evm (via api.tx.ethereum.transact/api.tx.evm.call)87pub struct BridgeSponsorshipHandler<T>(PhantomData<T>);120pub struct BridgeSponsorshipHandler<T>(PhantomData<T>);88impl<T, C> SponsorshipHandler<T::AccountId, C> for BridgeSponsorshipHandler<T>121impl<T, C> SponsorshipHandler<T::AccountId, C> for BridgeSponsorshipHandler<T>128 }161 }129}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}130295runtime/common/config/ethereum.rsdiffbeforeafterboth89 type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate<Self>;89 type OnCreate = pallet_evm_contract_helpers::HelpersOnCreate<Self>;90 type ChainId = ChainId;90 type ChainId = ChainId;91 type Runner = pallet_evm::runner::stack::Runner<Self>;91 type Runner = pallet_evm::runner::stack::Runner<Self>;92 type OnChargeTransaction = pallet_evm::EVMCurrencyAdapter<Balances, DealWithFees>;92 type OnChargeTransaction =93 type TransactionValidityHack = pallet_evm_transaction_payment::TransactionValidityHack<Self>;93 pallet_evm_transaction_payment::WrappedEVMCurrencyAdapter<Balances, DealWithFees>;94 type FindAuthor = EthereumFindAuthor<Aura>;94 type FindAuthor = EthereumFindAuthor<Aura>;95 type Timestamp = crate::Timestamp;95 type Timestamp = crate::Timestamp;96 type WeightInfo = pallet_evm::weights::SubstrateWeight<Self>;96 type WeightInfo = pallet_evm::weights::SubstrateWeight<Self>;97 type GasLimitPovSizeRatio = ProofSizePerGas;97 type GasLimitPovSizeRatio = ProofSizePerGas;98 type OnCheckEvmTransaction = pallet_evm_transaction_payment::TransactionValidity<Self>;98}99}99100100impl pallet_evm_migration::Config for Runtime {101impl pallet_evm_migration::Config for Runtime {