1234567891011121314151617#![doc = include_str!("../README.md")]18#![cfg_attr(not(feature = "std"), no_std)]19#![deny(missing_docs)]2021use core::marker::PhantomData;22use fp_evm::WithdrawReason;23use frame_support::traits::IsSubType;24pub use pallet::*;25use pallet_evm::{account::CrossAccountId, EnsureAddressOrigin};26use sp_core::{H160, U256};27use sp_runtime::{TransactionOutcome, DispatchError};28use up_sponsorship::SponsorshipHandler;2930#[frame_support::pallet]31pub mod pallet {32 use super::*;3334 use sp_std::vec::Vec;3536 37 pub struct CallContext {38 39 pub contract_address: H160,40 41 pub input: Vec<u8>,42 43 pub max_fee: U256,44 }4546 #[pallet::config]47 pub trait Config: frame_system::Config + pallet_evm::Config {48 49 type EvmSponsorshipHandler: SponsorshipHandler<Self::CrossAccountId, CallContext>;50 }5152 #[pallet::pallet]53 pub struct Pallet<T>(_);54}555657pub struct TransactionValidityHack<T: Config>(PhantomData<*const T>);58impl<T: Config> fp_evm::TransactionValidityHack<T::CrossAccountId> for TransactionValidityHack<T> {59 fn who_pays_fee(60 origin: H160,61 max_fee: U256,62 reason: &WithdrawReason,63 ) -> Option<T::CrossAccountId> {64 match reason {65 WithdrawReason::Call { target, input } => {66 let origin_sub = T::CrossAccountId::from_eth(origin);67 let call_context = CallContext {68 contract_address: *target,69 input: input.clone(),70 max_fee,71 };72 T::EvmSponsorshipHandler::get_sponsor(&origin_sub, &call_context)73 }74 _ => None,75 }76 }77}787980pub struct BridgeSponsorshipHandler<T>(PhantomData<T>);81impl<T, C> SponsorshipHandler<T::AccountId, C> for BridgeSponsorshipHandler<T>82where83 T: Config + pallet_evm::Config,84 C: IsSubType<pallet_evm::Call<T>>,85{86 fn get_sponsor(who: &T::AccountId, call: &C) -> Option<T::AccountId> {87 match call.is_sub_type()? {88 pallet_evm::Call::call {89 source,90 target,91 input,92 gas_limit,93 max_fee_per_gas,94 ..95 } => {96 let _ = T::CallOrigin::ensure_address_origin(97 source,98 <frame_system::RawOrigin<T::AccountId>>::Signed(who.clone()).into(),99 )100 .ok()?;101 let who = T::CrossAccountId::from_sub(who.clone());102 let max_fee = max_fee_per_gas.saturating_mul((*gas_limit).into());103 let call_context = CallContext {104 contract_address: *target,105 input: input.clone(),106 max_fee,107 };108 109 110 let sponsor = frame_support::storage::with_transaction(|| {111 TransactionOutcome::Rollback(Ok::<_, DispatchError>(112 T::EvmSponsorshipHandler::get_sponsor(&who, &call_context),113 ))114 })115 116 .ok()??;117 Some(sponsor.as_sub().clone())118 }119 _ => None,120 }121 }122}