From 4a3d8395a0e4d714f59e4ec2dbcc3160a0671e37 Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Thu, 18 Nov 2021 13:48:07 +0000 Subject: [PATCH] feat: sponsor evm transactions coming from substrate --- --- a/pallets/evm-transaction-payment/src/lib.rs +++ b/pallets/evm-transaction-payment/src/lib.rs @@ -1,100 +1,140 @@ #![cfg_attr(not(feature = "std"), no_std)] +use core::marker::PhantomData; +use fp_evm::WithdrawReason; +use frame_support::traits::{Currency, IsSubType}; pub use pallet::*; +use pallet_evm::{EVMCurrencyAdapter, EnsureAddressOrigin}; +use sp_core::{H160, U256}; +use sp_runtime::TransactionOutcome; +use up_sponsorship::SponsorshipHandler; use up_evm_mapping::EvmBackwardsAddressMapping; +use pallet_evm::AddressMapping; #[frame_support::pallet] pub mod pallet { - use core::marker::PhantomData; + use super::*; + use frame_support::traits::Currency; - use pallet_evm::EVMCurrencyAdapter; - use fp_evm::WithdrawReason; - use sp_core::{H160, U256}; - use sp_runtime::TransactionOutcome; - use up_sponsorship::SponsorshipHandler; use sp_std::vec::Vec; - type NegativeImbalanceOf = - ::AccountId>>::NegativeImbalance; - #[pallet::config] pub trait Config: frame_system::Config { - type SponsorshipHandler: SponsorshipHandler)>; + type EvmSponsorshipHandler: SponsorshipHandler)>; type Currency: Currency; type EvmBackwardsAddressMapping: EvmBackwardsAddressMapping; + type EvmAddressMapping: AddressMapping; } #[pallet::pallet] #[pallet::generate_store(pub(super) trait Store)] pub struct Pallet(_); +} - pub struct ChargeEvmLiquidityInfo - where - T: Config, - T: pallet_evm::Config, - { - who: H160, - negative_imbalance: NegativeImbalanceOf<::Currency, T>, +type NegativeImbalanceOf = + ::AccountId>>::NegativeImbalance; + +pub struct ChargeEvmLiquidityInfo +where + T: Config, + T: pallet_evm::Config, +{ + who: H160, + negative_imbalance: NegativeImbalanceOf<::Currency, T>, +} + +pub struct TransactionValidityHack(PhantomData<*const T>); +impl fp_evm::TransactionValidityHack for TransactionValidityHack { + fn who_pays_fee(origin: H160, reason: &WithdrawReason) -> Option { + match reason { + WithdrawReason::Call { target, input } => { + // This method is only used for checking, we shouldn't touch storage in it + frame_support::storage::with_transaction(|| { + TransactionOutcome::Rollback(T::EvmSponsorshipHandler::get_sponsor( + &origin, + &(*target, input.clone()), + )) + }) + } + _ => None, + } } +} +pub struct OnChargeTransaction(PhantomData<*const T>); +impl pallet_evm::OnChargeEVMTransaction for OnChargeTransaction +where + T: Config, + T: pallet_evm::Config, +{ + type LiquidityInfo = Option>; - pub struct TransactionValidityHack(PhantomData<*const T>); - impl fp_evm::TransactionValidityHack for TransactionValidityHack { - fn who_pays_fee(origin: H160, reason: &WithdrawReason) -> Option { - match reason { - WithdrawReason::Call { target, input } => { - // This method is only used for checking, we shouldn't touch storage in it - frame_support::storage::with_transaction(|| { - TransactionOutcome::Rollback(T::SponsorshipHandler::get_sponsor( - &origin, - &(*target, input.clone()), - )) - }) - } - _ => None, - } + fn withdraw_fee( + who: &H160, + reason: WithdrawReason, + fee: U256, + ) -> core::result::Result> { + let mut who_pays_fee = *who; + if let WithdrawReason::Call { target, input } = &reason { + who_pays_fee = T::EvmSponsorshipHandler::get_sponsor(who, &(*target, input.clone())) + .unwrap_or(who_pays_fee); } + let negative_imbalance = EVMCurrencyAdapter::<::Currency, ()>::withdraw_fee( + &who_pays_fee, + reason, + fee, + )?; + Ok(negative_imbalance.map(|i| ChargeEvmLiquidityInfo { + who: who_pays_fee, + negative_imbalance: i, + })) } - pub struct OnChargeTransaction(PhantomData<*const T>); - impl pallet_evm::OnChargeEVMTransaction for OnChargeTransaction - where - T: Config, - T: pallet_evm::Config, - { - type LiquidityInfo = Option>; + fn correct_and_deposit_fee( + who: &H160, + corrected_fee: U256, + already_withdrawn: Self::LiquidityInfo, + ) { + ::Currency, ()> as pallet_evm::OnChargeEVMTransaction>::correct_and_deposit_fee( + &already_withdrawn.as_ref().map(|e| e.who).unwrap_or(*who), + corrected_fee, + already_withdrawn.map(|e| e.negative_imbalance), + ) + } +} - fn withdraw_fee( - who: &H160, - reason: WithdrawReason, - fee: U256, - ) -> core::result::Result> { - let mut who_pays_fee = *who; - if let WithdrawReason::Call { target, input } = &reason { - who_pays_fee = T::SponsorshipHandler::get_sponsor(who, &(*target, input.clone())) - .unwrap_or(who_pays_fee); +/// Implements sponsoring for evm calls performed from pallet-evm (via api.tx.ethereum.transact/api.tx.evm.call) +pub struct BridgeSponsorshipHandler(PhantomData); +impl SponsorshipHandler for BridgeSponsorshipHandler +where + T: Config + pallet_evm::Config, + C: IsSubType>, +{ + fn get_sponsor(who: &T::AccountId, call: &C) -> Option { + match call.is_sub_type()? { + pallet_evm::Call::call { + source, + target, + input, + .. + } => { + let _ = T::CallOrigin::ensure_address_origin( + source, + >::Signed(who.clone()).into(), + ) + .ok()?; + let who = T::EvmBackwardsAddressMapping::from_account_id(who.clone()); + // Effects from EvmSponsorshipHandler are applied in OnChargeEvmTransaction by pallet_evm::runner + // TODO: Should we implement simulation mode (test, but do not apply effects) in `up-sponsorship`? + let sponsor = frame_support::storage::with_transaction(|| { + TransactionOutcome::Rollback(T::EvmSponsorshipHandler::get_sponsor( + &who, + &(target.clone(), input.clone()), + )) + })?; + let sponsor = T::EvmAddressMapping::into_account_id(sponsor); + Some(sponsor) } - let negative_imbalance = - EVMCurrencyAdapter::<::Currency, ()>::withdraw_fee( - &who_pays_fee, - reason, - fee, - )?; - Ok(negative_imbalance.map(|i| ChargeEvmLiquidityInfo { - who: who_pays_fee, - negative_imbalance: i, - })) - } - - fn correct_and_deposit_fee( - who: &H160, - corrected_fee: U256, - already_withdrawn: Self::LiquidityInfo, - ) { - ::Currency, ()> as pallet_evm::OnChargeEVMTransaction>::correct_and_deposit_fee( - &already_withdrawn.as_ref().map(|e| e.who).unwrap_or(*who), - corrected_fee, - already_withdrawn.map(|e| e.negative_imbalance), - ) + _ => None, } } } --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -777,20 +777,14 @@ pub const MaxScheduledPerBlock: u32 = 50; } -pub struct Sponsoring; -impl SponsoringResolve for Sponsoring { - fn resolve(who: &AccountId, call: &Call) -> Option - where - Call: Dispatchable, - AccountId: AsRef<[u8]>, - { - pallet_nft_transaction_payment::Module::::withdraw_type(who, call) - } -} - +type EvmSponsorshipHandler = ( + pallet_nft::NftEthSponsorshipHandler, + pallet_evm_contract_helpers::HelpersContractSponsoring, +); type SponsorshipHandler = ( pallet_nft::NftSponsorshipHandler, //pallet_contract_helpers::ContractSponsorshipHandler, + pallet_evm_transaction_payment::BridgeSponsorshipHandler, ); impl pallet_unq_scheduler::Config for Runtime { @@ -806,16 +800,14 @@ } impl pallet_evm_transaction_payment::Config for Runtime { - type SponsorshipHandler = ( - pallet_nft::NftEthSponsorshipHandler, - pallet_evm_contract_helpers::HelpersContractSponsoring, - ); + type EvmSponsorshipHandler = EvmSponsorshipHandler; type Currency = Balances; + type EvmAddressMapping = HashedAddressMapping; type EvmBackwardsAddressMapping = up_evm_mapping::MapBackwardsAddressTruncated; } impl pallet_nft_charge_transaction::Config for Runtime { - type SponsorshipHandler = pallet_nft::NftSponsorshipHandler; + type SponsorshipHandler = SponsorshipHandler; } // impl pallet_contract_helpers::Config for Runtime { -- gitstuff