pallet_evm/
lib.rs

1// This file is part of Frontier.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! # EVM Pallet
19//!
20//! The EVM pallet allows unmodified EVM code to be executed in a Substrate-based blockchain.
21//! - [`evm::Config`]
22//!
23//! ## EVM Engine
24//!
25//! The EVM pallet uses [`SputnikVM`](https://github.com/rust-blockchain/evm) as the underlying EVM engine.
26//! The engine is overhauled so that it's [`modular`](https://github.com/corepaper/evm).
27//!
28//! ## Execution Lifecycle
29//!
30//! There are a separate set of accounts managed by the EVM pallet. Substrate based accounts can call the EVM Pallet
31//! to deposit or withdraw balance from the Substrate base-currency into a different balance managed and used by
32//! the EVM pallet. Once a user has populated their balance, they can create and call smart contracts using this pallet.
33//!
34//! There's one-to-one mapping from Substrate accounts and EVM external accounts that is defined by a conversion function.
35//!
36//! ## EVM Pallet vs Ethereum Network
37//!
38//! The EVM pallet should be able to produce nearly identical results compared to the Ethereum mainnet,
39//! including gas cost and balance changes.
40//!
41//! Observable differences include:
42//!
43//! - The available length of block hashes may not be 256 depending on the configuration of the System pallet
44//!   in the Substrate runtime.
45//! - Difficulty and coinbase, which do not make sense in this pallet and is currently hard coded to zero.
46//!
47//! We currently do not aim to make unobservable behaviors, such as state root, to be the same. We also don't aim to follow
48//! the exact same transaction / receipt format. However, given one Ethereum transaction and one Substrate account's
49//! private key, one should be able to convert any Ethereum transaction into a transaction compatible with this pallet.
50//!
51//! The gas configurations are configurable. Right now, a pre-defined London hard fork configuration option is provided.
52
53// Ensure we're `no_std` when compiling for Wasm.
54#![cfg_attr(not(feature = "std"), no_std)]
55#![warn(unused_crate_dependencies)]
56#![allow(clippy::too_many_arguments)]
57#![allow(clippy::useless_conversion)]
58
59extern crate alloc;
60
61#[cfg(feature = "runtime-benchmarks")]
62pub mod benchmarking;
63
64#[cfg(test)]
65mod mock;
66pub mod runner;
67#[cfg(test)]
68mod tests;
69pub mod weights;
70
71use alloc::{borrow::Cow, collections::btree_map::BTreeMap, vec::Vec};
72use core::cmp::min;
73use ethereum::AuthorizationList;
74pub use evm::{
75	Config as EvmConfig, Context, ExitError, ExitFatal, ExitReason, ExitRevert, ExitSucceed,
76};
77use hash_db::Hasher;
78use impl_trait_for_tuples::impl_for_tuples;
79use scale_codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
80use scale_info::TypeInfo;
81// Substrate
82use frame_support::{
83	dispatch::{DispatchResultWithPostInfo, Pays, PostDispatchInfo},
84	storage::KeyPrefixIterator,
85	traits::{
86		fungible::{Balanced, Credit, Debt},
87		tokens::{
88			currency::Currency,
89			fungible::Inspect,
90			imbalance::{Imbalance, OnUnbalanced, SignedImbalance},
91			ExistenceRequirement, Fortitude, Precision, Preservation, WithdrawReasons,
92		},
93		FindAuthor, Get, Time,
94	},
95	weights::Weight,
96};
97use frame_system::RawOrigin;
98use sp_core::{H160, H256, U256};
99use sp_runtime::{
100	traits::{BadOrigin, NumberFor, Saturating, UniqueSaturatedInto, Zero},
101	AccountId32, DispatchErrorWithPostInfo,
102};
103// Frontier
104use fp_account::AccountId20;
105use fp_evm::GenesisAccount;
106pub use fp_evm::{
107	Account, AccountProvider, CallInfo, CreateInfo, ExecutionInfoV2 as ExecutionInfo,
108	FeeCalculator, IsPrecompileResult, LinearCostPrecompile, Log, Precompile, PrecompileFailure,
109	PrecompileHandle, PrecompileOutput, PrecompileResult, PrecompileSet,
110	TransactionValidationError, Vicinity, EVM_CONFIG,
111};
112
113pub use self::{
114	pallet::*,
115	runner::{Runner, RunnerError},
116	weights::WeightInfo,
117};
118
119#[frame_support::pallet]
120pub mod pallet {
121	use super::*;
122	use frame_support::pallet_prelude::*;
123	use frame_system::pallet_prelude::*;
124
125	#[pallet::pallet]
126	#[pallet::without_storage_info]
127	pub struct Pallet<T>(PhantomData<T>);
128
129	#[pallet::config(with_default)]
130	pub trait Config: frame_system::Config {
131		/// Account info provider.
132		#[pallet::no_default]
133		type AccountProvider: AccountProvider;
134
135		/// Calculator for current gas price.
136		type FeeCalculator: FeeCalculator;
137
138		/// Maps Ethereum gas to Substrate weight.
139		type GasWeightMapping: GasWeightMapping;
140
141		/// Weight corresponding to a gas unit.
142		type WeightPerGas: Get<Weight>;
143
144		/// Block number to block hash.
145		#[pallet::no_default]
146		type BlockHashMapping: BlockHashMapping;
147
148		/// Allow the origin to call on behalf of given address.
149		#[pallet::no_default_bounds]
150		type CallOrigin: EnsureAddressOrigin<Self::RuntimeOrigin>;
151
152		/// Allow the source address to deploy contracts directly via CREATE calls.
153		#[pallet::no_default_bounds]
154		type CreateOriginFilter: EnsureCreateOrigin<Self>;
155
156		/// Allow the source address to deploy contracts via CALL(CREATE) calls.
157		#[pallet::no_default_bounds]
158		type CreateInnerOriginFilter: EnsureCreateOrigin<Self>;
159
160		/// Allow the origin to withdraw on behalf of given address.
161		#[pallet::no_default_bounds]
162		type WithdrawOrigin: EnsureAddressOrigin<Self::RuntimeOrigin, Success = AccountIdOf<Self>>;
163
164		/// Mapping from address to account id.
165		#[pallet::no_default_bounds]
166		type AddressMapping: AddressMapping<AccountIdOf<Self>>;
167
168		/// Currency type for withdraw and balance storage.
169		#[pallet::no_default]
170		type Currency: Currency<AccountIdOf<Self>> + Inspect<AccountIdOf<Self>>;
171
172		/// Precompiles associated with this EVM engine.
173		type PrecompilesType: PrecompileSet;
174		type PrecompilesValue: Get<Self::PrecompilesType>;
175
176		/// Chain ID of EVM.
177		type ChainId: Get<u64>;
178		/// The block gas limit. Can be a simple constant, or an adjustment algorithm in another pallet.
179		type BlockGasLimit: Get<U256>;
180
181		/// Optional maximum gas limit for a single transaction.
182		///
183		/// Set to `None` to rely only on the block gas limit and weight/proof-size constraints.
184		type TransactionGasLimit: Get<Option<U256>>;
185
186		/// EVM execution runner.
187		#[pallet::no_default]
188		type Runner: Runner<Self>;
189
190		/// To handle fee deduction for EVM transactions. An example is this pallet being used by `pallet_ethereum`
191		/// where the chain implementing `pallet_ethereum` should be able to configure what happens to the fees
192		/// Similar to `OnChargeTransaction` of `pallet_transaction_payment`
193		#[pallet::no_default_bounds]
194		type OnChargeTransaction: OnChargeEVMTransaction<Self>;
195
196		/// Called on create calls, used to record owner
197		#[pallet::no_default_bounds]
198		type OnCreate: OnCreate<Self>;
199
200		/// Find author for the current block.
201		type FindAuthor: FindAuthor<H160>;
202
203		/// Gas limit Pov size ratio.
204		type GasLimitPovSizeRatio: Get<u64>;
205
206		/// Gas limit storage growth ratio.
207		type GasLimitStorageGrowthRatio: Get<u64>;
208
209		/// Get the timestamp for the current block.
210		#[pallet::no_default]
211		type Timestamp: Time;
212
213		/// Weight information for extrinsics in this pallet.
214		type WeightInfo: WeightInfo;
215
216		/// EVM config used in the module.
217		fn config() -> &'static EvmConfig {
218			&EVM_CONFIG
219		}
220	}
221
222	pub mod config_preludes {
223		use super::*;
224		use core::str::FromStr;
225		use frame_support::{derive_impl, parameter_types, ConsensusEngineId};
226		use sp_runtime::traits::BlakeTwo256;
227
228		pub struct TestDefaultConfig;
229
230		#[derive_impl(
231			frame_system::config_preludes::SolochainDefaultConfig,
232			no_aggregated_types
233		)]
234		impl frame_system::DefaultConfig for TestDefaultConfig {}
235
236		const BLOCK_GAS_LIMIT: u64 = 150_000_000;
237		const MAX_POV_SIZE: u64 = 5 * 1024 * 1024;
238		/// The maximum storage growth per block in bytes.
239		const MAX_STORAGE_GROWTH: u64 = 400 * 1024;
240
241		parameter_types! {
242			pub BlockGasLimit: U256 = U256::from(BLOCK_GAS_LIMIT);
243			pub TransactionGasLimit: Option<U256> = Some(fp_evm::MAX_TRANSACTION_GAS_LIMIT);
244			pub const ChainId: u64 = 42;
245			pub const GasLimitPovSizeRatio: u64 = BLOCK_GAS_LIMIT.saturating_div(MAX_POV_SIZE);
246			pub const GasLimitStorageGrowthRatio: u64 = BLOCK_GAS_LIMIT.saturating_div(MAX_STORAGE_GROWTH);
247			pub WeightPerGas: Weight = Weight::from_parts(20_000, 0);
248		}
249
250		#[register_default_impl(TestDefaultConfig)]
251		impl DefaultConfig for TestDefaultConfig {
252			type CallOrigin = EnsureAddressRoot<Self::AccountId>;
253			type WithdrawOrigin = EnsureAddressNever<Self::AccountId>;
254			type AddressMapping = HashedAddressMapping<BlakeTwo256>;
255			type FeeCalculator = FixedGasPrice;
256			type GasWeightMapping = FixedGasWeightMapping<Self>;
257			type WeightPerGas = WeightPerGas;
258			type PrecompilesType = ();
259			type PrecompilesValue = ();
260			type ChainId = ChainId;
261			type BlockGasLimit = BlockGasLimit;
262			type TransactionGasLimit = TransactionGasLimit;
263			type OnChargeTransaction = ();
264			type OnCreate = ();
265			type FindAuthor = FindAuthorTruncated;
266			type GasLimitPovSizeRatio = GasLimitPovSizeRatio;
267			type GasLimitStorageGrowthRatio = GasLimitStorageGrowthRatio;
268			type CreateOriginFilter = ();
269			type CreateInnerOriginFilter = ();
270			type WeightInfo = ();
271		}
272
273		impl FixedGasWeightMappingAssociatedTypes for TestDefaultConfig {
274			type WeightPerGas = <Self as DefaultConfig>::WeightPerGas;
275			type BlockWeights = <Self as frame_system::DefaultConfig>::BlockWeights;
276			type GasLimitPovSizeRatio = <Self as DefaultConfig>::GasLimitPovSizeRatio;
277		}
278
279		pub struct FixedGasPrice;
280		impl FeeCalculator for FixedGasPrice {
281			fn min_gas_price() -> (U256, Weight) {
282				(1.into(), Weight::zero())
283			}
284		}
285
286		pub struct FindAuthorTruncated;
287		impl FindAuthor<H160> for FindAuthorTruncated {
288			fn find_author<'a, I>(_digests: I) -> Option<H160>
289			where
290				I: 'a + IntoIterator<Item = (ConsensusEngineId, &'a [u8])>,
291			{
292				Some(H160::from_str("1234500000000000000000000000000000000000").unwrap())
293			}
294		}
295	}
296
297	#[pallet::call]
298	impl<T: Config> Pallet<T> {
299		/// Withdraw balance from EVM into currency/balances pallet.
300		#[pallet::call_index(0)]
301		#[pallet::weight(<T as pallet::Config>::WeightInfo::withdraw())]
302		pub fn withdraw(
303			origin: OriginFor<T>,
304			address: H160,
305			value: BalanceOf<T>,
306		) -> DispatchResult {
307			let destination = T::WithdrawOrigin::ensure_address_origin(&address, origin)?;
308			let address_account_id = T::AddressMapping::into_account_id(address);
309
310			T::Currency::transfer(
311				&address_account_id,
312				&destination,
313				value,
314				ExistenceRequirement::AllowDeath,
315			)?;
316
317			Ok(())
318		}
319
320		/// Issue an EVM call operation. This is similar to a message call transaction in Ethereum.
321		#[pallet::call_index(1)]
322		#[pallet::weight({
323			let without_base_extrinsic_weight = true;
324			T::GasWeightMapping::gas_to_weight(*gas_limit, without_base_extrinsic_weight)
325		})]
326		pub fn call(
327			origin: OriginFor<T>,
328			source: H160,
329			target: H160,
330			input: Vec<u8>,
331			value: U256,
332			gas_limit: u64,
333			max_fee_per_gas: U256,
334			max_priority_fee_per_gas: Option<U256>,
335			nonce: Option<U256>,
336			access_list: Vec<(H160, Vec<H256>)>,
337			authorization_list: AuthorizationList,
338		) -> DispatchResultWithPostInfo {
339			T::CallOrigin::ensure_address_origin(&source, origin)?;
340
341			let is_transactional = true;
342			let validate = true;
343			let info = match T::Runner::call(
344				source,
345				target,
346				input,
347				value,
348				gas_limit,
349				Some(max_fee_per_gas),
350				max_priority_fee_per_gas,
351				nonce,
352				access_list,
353				authorization_list,
354				is_transactional,
355				validate,
356				None,
357				None,
358				None,
359				T::config(),
360			) {
361				Ok(info) => info,
362				Err(e) => {
363					return Err(DispatchErrorWithPostInfo {
364						post_info: PostDispatchInfo {
365							actual_weight: Some(e.weight),
366							pays_fee: Pays::Yes,
367						},
368						error: e.error.into(),
369					})
370				}
371			};
372
373			match info.exit_reason {
374				ExitReason::Succeed(_) => {
375					Pallet::<T>::deposit_event(Event::<T>::Executed { address: target });
376				}
377				_ => {
378					Pallet::<T>::deposit_event(Event::<T>::ExecutedFailed { address: target });
379				}
380			};
381
382			Ok(PostDispatchInfo {
383				actual_weight: {
384					let mut gas_to_weight = T::GasWeightMapping::gas_to_weight(
385						info.used_gas.standard.unique_saturated_into(),
386						true,
387					);
388					if let Some(weight_info) = info.weight_info {
389						if let Some(proof_size_usage) = weight_info.proof_size_usage {
390							*gas_to_weight.proof_size_mut() = proof_size_usage;
391						}
392					}
393					Some(gas_to_weight)
394				},
395				pays_fee: Pays::No,
396			})
397		}
398
399		/// Issue an EVM create operation. This is similar to a contract creation transaction in
400		/// Ethereum.
401		#[pallet::call_index(2)]
402		#[pallet::weight({
403			let without_base_extrinsic_weight = true;
404			T::GasWeightMapping::gas_to_weight(*gas_limit, without_base_extrinsic_weight)
405		})]
406		pub fn create(
407			origin: OriginFor<T>,
408			source: H160,
409			init: Vec<u8>,
410			value: U256,
411			gas_limit: u64,
412			max_fee_per_gas: U256,
413			max_priority_fee_per_gas: Option<U256>,
414			nonce: Option<U256>,
415			access_list: Vec<(H160, Vec<H256>)>,
416			authorization_list: AuthorizationList,
417		) -> DispatchResultWithPostInfo {
418			T::CallOrigin::ensure_address_origin(&source, origin)?;
419
420			let is_transactional = true;
421			let validate = true;
422			let info = match T::Runner::create(
423				source,
424				init,
425				value,
426				gas_limit,
427				Some(max_fee_per_gas),
428				max_priority_fee_per_gas,
429				nonce,
430				access_list,
431				authorization_list,
432				is_transactional,
433				validate,
434				None,
435				None,
436				T::config(),
437			) {
438				Ok(info) => info,
439				Err(e) => {
440					return Err(DispatchErrorWithPostInfo {
441						post_info: PostDispatchInfo {
442							actual_weight: Some(e.weight),
443							pays_fee: Pays::Yes,
444						},
445						error: e.error.into(),
446					})
447				}
448			};
449
450			match info {
451				CreateInfo {
452					exit_reason: ExitReason::Succeed(_),
453					value: create_address,
454					..
455				} => {
456					Pallet::<T>::deposit_event(Event::<T>::Created {
457						address: create_address,
458					});
459				}
460				CreateInfo {
461					exit_reason: _,
462					value: create_address,
463					..
464				} => {
465					Pallet::<T>::deposit_event(Event::<T>::CreatedFailed {
466						address: create_address,
467					});
468				}
469			}
470
471			Ok(PostDispatchInfo {
472				actual_weight: {
473					let mut gas_to_weight = T::GasWeightMapping::gas_to_weight(
474						info.used_gas.standard.unique_saturated_into(),
475						true,
476					);
477					if let Some(weight_info) = info.weight_info {
478						if let Some(proof_size_usage) = weight_info.proof_size_usage {
479							*gas_to_weight.proof_size_mut() = proof_size_usage;
480						}
481					}
482					Some(gas_to_weight)
483				},
484				pays_fee: Pays::No,
485			})
486		}
487
488		/// Issue an EVM create2 operation.
489		#[pallet::call_index(3)]
490		#[pallet::weight({
491			let without_base_extrinsic_weight = true;
492			T::GasWeightMapping::gas_to_weight(*gas_limit, without_base_extrinsic_weight)
493		})]
494		pub fn create2(
495			origin: OriginFor<T>,
496			source: H160,
497			init: Vec<u8>,
498			salt: H256,
499			value: U256,
500			gas_limit: u64,
501			max_fee_per_gas: U256,
502			max_priority_fee_per_gas: Option<U256>,
503			nonce: Option<U256>,
504			access_list: Vec<(H160, Vec<H256>)>,
505			authorization_list: AuthorizationList,
506		) -> DispatchResultWithPostInfo {
507			T::CallOrigin::ensure_address_origin(&source, origin)?;
508
509			let is_transactional = true;
510			let validate = true;
511			let info = match T::Runner::create2(
512				source,
513				init,
514				salt,
515				value,
516				gas_limit,
517				Some(max_fee_per_gas),
518				max_priority_fee_per_gas,
519				nonce,
520				access_list,
521				authorization_list,
522				is_transactional,
523				validate,
524				None,
525				None,
526				T::config(),
527			) {
528				Ok(info) => info,
529				Err(e) => {
530					return Err(DispatchErrorWithPostInfo {
531						post_info: PostDispatchInfo {
532							actual_weight: Some(e.weight),
533							pays_fee: Pays::Yes,
534						},
535						error: e.error.into(),
536					})
537				}
538			};
539
540			match info {
541				CreateInfo {
542					exit_reason: ExitReason::Succeed(_),
543					value: create_address,
544					..
545				} => {
546					Pallet::<T>::deposit_event(Event::<T>::Created {
547						address: create_address,
548					});
549				}
550				CreateInfo {
551					exit_reason: _,
552					value: create_address,
553					..
554				} => {
555					Pallet::<T>::deposit_event(Event::<T>::CreatedFailed {
556						address: create_address,
557					});
558				}
559			}
560
561			Ok(PostDispatchInfo {
562				actual_weight: {
563					let mut gas_to_weight = T::GasWeightMapping::gas_to_weight(
564						info.used_gas.standard.unique_saturated_into(),
565						true,
566					);
567					if let Some(weight_info) = info.weight_info {
568						if let Some(proof_size_usage) = weight_info.proof_size_usage {
569							*gas_to_weight.proof_size_mut() = proof_size_usage;
570						}
571					}
572					Some(gas_to_weight)
573				},
574				pays_fee: Pays::No,
575			})
576		}
577	}
578
579	#[pallet::event]
580	#[pallet::generate_deposit(pub(super) fn deposit_event)]
581	pub enum Event<T: Config> {
582		/// Ethereum events from contracts.
583		Log { log: Log },
584		/// A contract has been created at given address.
585		Created { address: H160 },
586		/// A contract was attempted to be created, but the execution failed.
587		CreatedFailed { address: H160 },
588		/// A contract has been executed successfully with states applied.
589		Executed { address: H160 },
590		/// A contract has been executed with errors. States are reverted with only gas fees applied.
591		ExecutedFailed { address: H160 },
592	}
593
594	#[pallet::error]
595	pub enum Error<T> {
596		/// Not enough balance to perform action
597		BalanceLow,
598		/// Calculating total fee overflowed
599		FeeOverflow,
600		/// Calculating total payment overflowed
601		PaymentOverflow,
602		/// Withdraw fee failed
603		WithdrawFailed,
604		/// Gas price is too low.
605		GasPriceTooLow,
606		/// Nonce is invalid
607		InvalidNonce,
608		/// Gas limit is too low.
609		GasLimitTooLow,
610		/// Gas limit exceeds block gas limit.
611		GasLimitExceedsBlockLimit,
612		/// The chain id is invalid.
613		InvalidChainId,
614		/// the signature is invalid.
615		InvalidSignature,
616		/// EVM reentrancy
617		Reentrancy,
618		/// EIP-3607,
619		TransactionMustComeFromEOA,
620		/// Undefined error.
621		Undefined,
622		/// Address not allowed to deploy contracts either via CREATE or CALL(CREATE).
623		CreateOriginNotAllowed,
624		/// EIP-7825: Transaction gas limit exceeds protocol cap (2^24).
625		TransactionGasLimitExceedsCap,
626	}
627
628	impl<T> From<TransactionValidationError> for Error<T> {
629		fn from(validation_error: TransactionValidationError) -> Self {
630			match validation_error {
631				TransactionValidationError::GasLimitTooLow => Error::<T>::GasLimitTooLow,
632				TransactionValidationError::GasLimitExceedsBlockLimit => {
633					Error::<T>::GasLimitExceedsBlockLimit
634				}
635				TransactionValidationError::BalanceTooLow => Error::<T>::BalanceLow,
636				TransactionValidationError::TxNonceTooLow => Error::<T>::InvalidNonce,
637				TransactionValidationError::TxNonceTooHigh => Error::<T>::InvalidNonce,
638				TransactionValidationError::GasPriceTooLow => Error::<T>::GasPriceTooLow,
639				TransactionValidationError::PriorityFeeTooHigh => Error::<T>::GasPriceTooLow,
640				TransactionValidationError::InvalidFeeInput => Error::<T>::GasPriceTooLow,
641				TransactionValidationError::InvalidChainId => Error::<T>::InvalidChainId,
642				TransactionValidationError::InvalidSignature => Error::<T>::InvalidSignature,
643				TransactionValidationError::EmptyAuthorizationList => Error::<T>::Undefined,
644				TransactionValidationError::AuthorizationListTooLarge => Error::<T>::Undefined,
645				TransactionValidationError::TransactionGasLimitExceedsCap => {
646					Error::<T>::TransactionGasLimitExceedsCap
647				}
648				TransactionValidationError::UnknownError => Error::<T>::Undefined,
649			}
650		}
651	}
652
653	#[pallet::genesis_config]
654	#[derive(frame_support::DefaultNoBound)]
655	pub struct GenesisConfig<T> {
656		pub accounts: BTreeMap<H160, GenesisAccount>,
657		#[serde(skip)]
658		pub _marker: PhantomData<T>,
659	}
660
661	#[pallet::genesis_build]
662	impl<T: Config> BuildGenesisConfig for GenesisConfig<T>
663	where
664		U256: UniqueSaturatedInto<BalanceOf<T>>,
665	{
666		fn build(&self) {
667			const MAX_ACCOUNT_NONCE: usize = 100;
668
669			for (address, account) in &self.accounts {
670				let account_id = T::AddressMapping::into_account_id(*address);
671
672				// ASSUME: in one single EVM transaction, the nonce will not increase more than
673				// `u128::max_value()`.
674				for _ in 0..min(
675					MAX_ACCOUNT_NONCE,
676					UniqueSaturatedInto::<usize>::unique_saturated_into(account.nonce),
677				) {
678					T::AccountProvider::inc_account_nonce(&account_id);
679				}
680
681				let _ = T::Currency::deposit_creating(
682					&account_id,
683					account.balance.unique_saturated_into(),
684				);
685
686				let _ = Pallet::<T>::create_account(*address, account.code.clone(), None);
687
688				for (index, value) in &account.storage {
689					<AccountStorages<T>>::insert(address, index, value);
690				}
691			}
692		}
693	}
694
695	#[pallet::storage]
696	pub type AccountCodes<T: Config> = StorageMap<_, Blake2_128Concat, H160, Vec<u8>, ValueQuery>;
697
698	#[pallet::storage]
699	pub type AccountCodesMetadata<T: Config> =
700		StorageMap<_, Blake2_128Concat, H160, CodeMetadata, OptionQuery>;
701
702	#[pallet::storage]
703	pub type AccountStorages<T: Config> =
704		StorageDoubleMap<_, Blake2_128Concat, H160, Blake2_128Concat, H256, H256, ValueQuery>;
705}
706
707/// Utility alias for easy access to the [`AccountProvider::AccountId`] type from a given config.
708pub type AccountIdOf<T> = <<T as Config>::AccountProvider as AccountProvider>::AccountId;
709
710/// Type alias for currency balance.
711pub type BalanceOf<T> = <<T as Config>::Currency as Currency<AccountIdOf<T>>>::Balance;
712
713/// Type alias for negative imbalance during fees
714type NegativeImbalanceOf<C, T> = <C as Currency<AccountIdOf<T>>>::NegativeImbalance;
715
716#[derive(
717	Debug,
718	Clone,
719	Copy,
720	Eq,
721	PartialEq,
722	Encode,
723	Decode,
724	DecodeWithMemTracking,
725	TypeInfo,
726	MaxEncodedLen
727)]
728pub struct CodeMetadata {
729	pub size: u64,
730	pub hash: H256,
731}
732
733impl CodeMetadata {
734	pub fn from_code(code: &[u8]) -> Self {
735		let size = code.len() as u64;
736		let hash = H256::from(sp_io::hashing::keccak_256(code));
737
738		Self { size, hash }
739	}
740}
741
742pub trait EnsureAddressOrigin<OuterOrigin> {
743	/// Success return type.
744	type Success;
745
746	/// Perform the origin check.
747	fn ensure_address_origin(
748		address: &H160,
749		origin: OuterOrigin,
750	) -> Result<Self::Success, BadOrigin> {
751		Self::try_address_origin(address, origin).map_err(|_| BadOrigin)
752	}
753
754	/// Try with origin.
755	fn try_address_origin(
756		address: &H160,
757		origin: OuterOrigin,
758	) -> Result<Self::Success, OuterOrigin>;
759}
760
761/// Ensure that the EVM address is the same as the Substrate address. This only works if the account
762/// ID is `H160`.
763pub struct EnsureAddressSame;
764
765impl<OuterOrigin> EnsureAddressOrigin<OuterOrigin> for EnsureAddressSame
766where
767	OuterOrigin: Into<Result<RawOrigin<H160>, OuterOrigin>> + From<RawOrigin<H160>>,
768{
769	type Success = H160;
770
771	fn try_address_origin(address: &H160, origin: OuterOrigin) -> Result<H160, OuterOrigin> {
772		origin.into().and_then(|o| match o {
773			RawOrigin::Signed(who) if &who == address => Ok(who),
774			r => Err(OuterOrigin::from(r)),
775		})
776	}
777}
778
779/// Ensure that the origin is root.
780pub struct EnsureAddressRoot<AccountId>(core::marker::PhantomData<AccountId>);
781
782impl<OuterOrigin, AccountId> EnsureAddressOrigin<OuterOrigin> for EnsureAddressRoot<AccountId>
783where
784	OuterOrigin: Into<Result<RawOrigin<AccountId>, OuterOrigin>> + From<RawOrigin<AccountId>>,
785{
786	type Success = ();
787
788	fn try_address_origin(_address: &H160, origin: OuterOrigin) -> Result<(), OuterOrigin> {
789		origin.into().and_then(|o| match o {
790			RawOrigin::Root => Ok(()),
791			r => Err(OuterOrigin::from(r)),
792		})
793	}
794}
795
796/// Ensure that the origin never happens.
797pub struct EnsureAddressNever<AccountId>(core::marker::PhantomData<AccountId>);
798
799impl<OuterOrigin, AccountId> EnsureAddressOrigin<OuterOrigin> for EnsureAddressNever<AccountId> {
800	type Success = AccountId;
801
802	fn try_address_origin(_address: &H160, origin: OuterOrigin) -> Result<AccountId, OuterOrigin> {
803		Err(origin)
804	}
805}
806
807/// Ensure that the address is truncated hash of the origin. Only works if the account id is
808/// `AccountId32`.
809pub struct EnsureAddressTruncated;
810
811impl<OuterOrigin> EnsureAddressOrigin<OuterOrigin> for EnsureAddressTruncated
812where
813	OuterOrigin: Into<Result<RawOrigin<AccountId32>, OuterOrigin>> + From<RawOrigin<AccountId32>>,
814{
815	type Success = AccountId32;
816
817	fn try_address_origin(address: &H160, origin: OuterOrigin) -> Result<AccountId32, OuterOrigin> {
818		origin.into().and_then(|o| match o {
819			RawOrigin::Signed(who) if AsRef::<[u8; 32]>::as_ref(&who)[0..20] == address[0..20] => {
820				Ok(who)
821			}
822			r => Err(OuterOrigin::from(r)),
823		})
824	}
825}
826
827/// Ensure that the address is AccountId20.
828pub struct EnsureAccountId20;
829
830impl<OuterOrigin> EnsureAddressOrigin<OuterOrigin> for EnsureAccountId20
831where
832	OuterOrigin: Into<Result<RawOrigin<AccountId20>, OuterOrigin>> + From<RawOrigin<AccountId20>>,
833{
834	type Success = AccountId20;
835
836	fn try_address_origin(address: &H160, origin: OuterOrigin) -> Result<AccountId20, OuterOrigin> {
837		let acc: AccountId20 = AccountId20::from(*address);
838		origin.into().and_then(|o| match o {
839			RawOrigin::Signed(who) if who == acc => Ok(who),
840			r => Err(OuterOrigin::from(r)),
841		})
842	}
843}
844
845pub trait EnsureCreateOrigin<T> {
846	fn check_create_origin(address: &H160) -> Result<(), Error<T>>;
847}
848
849pub struct EnsureAllowedCreateAddress<AddressGetter>(core::marker::PhantomData<AddressGetter>);
850
851impl<AddressGetter, T: Config> EnsureCreateOrigin<T> for EnsureAllowedCreateAddress<AddressGetter>
852where
853	AddressGetter: Get<Vec<H160>>,
854{
855	fn check_create_origin(address: &H160) -> Result<(), Error<T>> {
856		if !AddressGetter::get().contains(address) {
857			return Err(Error::<T>::CreateOriginNotAllowed);
858		}
859		Ok(())
860	}
861}
862
863impl<T> EnsureCreateOrigin<T> for () {
864	fn check_create_origin(_address: &H160) -> Result<(), Error<T>> {
865		Ok(())
866	}
867}
868
869/// Trait to be implemented for evm address mapping.
870pub trait AddressMapping<A> {
871	fn into_account_id(address: H160) -> A;
872}
873
874/// Identity address mapping.
875pub struct IdentityAddressMapping;
876
877impl<T: From<H160>> AddressMapping<T> for IdentityAddressMapping {
878	fn into_account_id(address: H160) -> T {
879		address.into()
880	}
881}
882
883/// Hashed address mapping.
884pub struct HashedAddressMapping<H>(core::marker::PhantomData<H>);
885
886impl<H: Hasher<Out = H256>> AddressMapping<AccountId32> for HashedAddressMapping<H> {
887	fn into_account_id(address: H160) -> AccountId32 {
888		let mut data = [0u8; 24];
889		data[0..4].copy_from_slice(b"evm:");
890		data[4..24].copy_from_slice(&address[..]);
891		let hash = H::hash(&data);
892
893		AccountId32::from(Into::<[u8; 32]>::into(hash))
894	}
895}
896
897/// A trait for getting a block hash by number.
898pub trait BlockHashMapping {
899	fn block_hash(number: u32) -> H256;
900}
901
902/// Returns the Substrate block hash by number.
903pub struct SubstrateBlockHashMapping<T>(core::marker::PhantomData<T>);
904impl<T: Config> BlockHashMapping for SubstrateBlockHashMapping<T> {
905	fn block_hash(number: u32) -> H256 {
906		let number = <NumberFor<T::Block>>::from(number);
907		H256::from_slice(frame_system::Pallet::<T>::block_hash(number).as_ref())
908	}
909}
910
911/// A mapping function that converts Ethereum gas to Substrate weight
912pub trait GasWeightMapping {
913	fn gas_to_weight(gas: u64, without_base_weight: bool) -> Weight;
914	fn weight_to_gas(weight: Weight) -> u64;
915}
916
917pub trait FixedGasWeightMappingAssociatedTypes {
918	type WeightPerGas: Get<Weight>;
919	type BlockWeights: Get<frame_system::limits::BlockWeights>;
920	type GasLimitPovSizeRatio: Get<u64>;
921}
922
923impl<T: Config> FixedGasWeightMappingAssociatedTypes for T {
924	type WeightPerGas = T::WeightPerGas;
925	type BlockWeights = T::BlockWeights;
926	type GasLimitPovSizeRatio = T::GasLimitPovSizeRatio;
927}
928
929pub struct FixedGasWeightMapping<T>(core::marker::PhantomData<T>);
930impl<T> GasWeightMapping for FixedGasWeightMapping<T>
931where
932	T: FixedGasWeightMappingAssociatedTypes,
933{
934	fn gas_to_weight(gas: u64, without_base_weight: bool) -> Weight {
935		let mut weight = T::WeightPerGas::get().saturating_mul(gas);
936		if without_base_weight {
937			weight = weight.saturating_sub(
938				T::BlockWeights::get()
939					.get(frame_support::dispatch::DispatchClass::Normal)
940					.base_extrinsic,
941			);
942		}
943		// Apply a gas to proof size ratio based on BlockGasLimit
944		let ratio = T::GasLimitPovSizeRatio::get();
945		if ratio > 0 {
946			let proof_size = gas.saturating_div(ratio);
947			*weight.proof_size_mut() = proof_size;
948		}
949
950		weight
951	}
952	fn weight_to_gas(weight: Weight) -> u64 {
953		weight.div(T::WeightPerGas::get().ref_time()).ref_time()
954	}
955}
956
957impl<T: Config> Pallet<T> {
958	/// Check whether an account is empty.
959	pub fn is_account_empty(address: &H160) -> bool {
960		let (account, _) = Self::account_basic(address);
961		let code_len = <AccountCodes<T>>::decode_len(address).unwrap_or(0);
962
963		account.nonce == U256::zero() && account.balance == U256::zero() && code_len == 0
964	}
965
966	pub fn iter_account_storages(address: &H160) -> KeyPrefixIterator<H256> {
967		<AccountStorages<T>>::iter_key_prefix(address)
968	}
969
970	/// Remove an account if its empty.
971	pub fn remove_account_if_empty(address: &H160) {
972		if Self::is_account_empty(address) {
973			Self::remove_account(address);
974		}
975	}
976
977	/// Remove an account.
978	pub fn remove_account(address: &H160) {
979		let account_id = T::AddressMapping::into_account_id(*address);
980		T::AccountProvider::remove_account(&account_id);
981
982		<AccountCodes<T>>::remove(address);
983		<AccountCodesMetadata<T>>::remove(address);
984		let _ = <AccountStorages<T>>::clear_prefix(address, u32::MAX, None);
985	}
986
987	/// Remove an account's code if present.
988	pub fn remove_account_code(address: &H160) {
989		<AccountCodes<T>>::remove(address);
990		<AccountCodesMetadata<T>>::remove(address);
991	}
992
993	/// Create an account.
994	pub fn create_account(
995		address: H160,
996		code: Vec<u8>,
997		caller: Option<H160>,
998	) -> Result<(), ExitError> {
999		if let Some(caller_address) = caller {
1000			T::CreateInnerOriginFilter::check_create_origin(&caller_address).map_err(|e| {
1001				let error: &'static str = e.into();
1002				ExitError::Other(Cow::Borrowed(error))
1003			})?;
1004		}
1005
1006		if code.is_empty() {
1007			return Ok(());
1008		}
1009
1010		if !<AccountCodes<T>>::contains_key(address) {
1011			let account_id = T::AddressMapping::into_account_id(address);
1012			T::AccountProvider::create_account(&account_id);
1013		}
1014
1015		// Update metadata.
1016		let meta = CodeMetadata::from_code(&code);
1017		<AccountCodesMetadata<T>>::insert(address, meta);
1018
1019		<AccountCodes<T>>::insert(address, code);
1020		Ok(())
1021	}
1022
1023	/// Get the account metadata (hash and size) from storage if it exists,
1024	/// or compute it from code and store it if it doesn't exist.
1025	pub fn account_code_metadata(address: H160) -> CodeMetadata {
1026		if let Some(meta) = <AccountCodesMetadata<T>>::get(address) {
1027			return meta;
1028		}
1029
1030		let code = <AccountCodes<T>>::get(address);
1031
1032		// If code is empty we return precomputed hash for empty code.
1033		// We don't store it as this address could get code deployed in the future.
1034		if code.is_empty() {
1035			const EMPTY_CODE_HASH: [u8; 32] = hex_literal::hex!(
1036				"c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
1037			);
1038			return CodeMetadata {
1039				size: 0,
1040				hash: EMPTY_CODE_HASH.into(),
1041			};
1042		}
1043
1044		let meta = CodeMetadata::from_code(&code);
1045
1046		<AccountCodesMetadata<T>>::insert(address, meta);
1047		meta
1048	}
1049
1050	/// Get the account basic in EVM format.
1051	pub fn account_basic(address: &H160) -> (Account, frame_support::weights::Weight) {
1052		let account_id = T::AddressMapping::into_account_id(*address);
1053		let nonce = T::AccountProvider::account_nonce(&account_id);
1054		let balance =
1055			T::Currency::reducible_balance(&account_id, Preservation::Preserve, Fortitude::Polite);
1056
1057		(
1058			Account {
1059				nonce: U256::from(UniqueSaturatedInto::<u128>::unique_saturated_into(nonce)),
1060				balance: U256::from(UniqueSaturatedInto::<u128>::unique_saturated_into(balance)),
1061			},
1062			T::DbWeight::get().reads(2),
1063		)
1064	}
1065
1066	/// Get the author using the FindAuthor trait.
1067	pub fn find_author() -> H160 {
1068		let digest = <frame_system::Pallet<T>>::digest();
1069		let pre_runtime_digests = digest.logs.iter().filter_map(|d| d.as_pre_runtime());
1070
1071		T::FindAuthor::find_author(pre_runtime_digests).unwrap_or_default()
1072	}
1073}
1074
1075/// Handle withdrawing, refunding and depositing of transaction fees.
1076/// Similar to `OnChargeTransaction` of `pallet_transaction_payment`
1077pub trait OnChargeEVMTransaction<T: Config> {
1078	type LiquidityInfo: Default;
1079
1080	/// Before the transaction is executed the payment of the transaction fees
1081	/// need to be secured.
1082	fn withdraw_fee(who: &H160, fee: U256) -> Result<Self::LiquidityInfo, Error<T>>;
1083
1084	/// After the transaction was executed the actual fee can be calculated.
1085	/// This function should refund any overpaid fees and optionally deposit
1086	/// the corrected amount, and handles the base fee rationing using the provided
1087	/// `OnUnbalanced` implementation.
1088	/// Returns the `NegativeImbalance` - if any - produced by the priority fee.
1089	fn correct_and_deposit_fee(
1090		who: &H160,
1091		corrected_fee: U256,
1092		base_fee: U256,
1093		already_withdrawn: Self::LiquidityInfo,
1094	) -> Self::LiquidityInfo;
1095
1096	/// Introduced in EIP1559 to handle the priority tip.
1097	fn pay_priority_fee(tip: Self::LiquidityInfo);
1098}
1099
1100/// Implements the transaction payment for a pallet implementing the `Currency`
1101/// trait (eg. the pallet_balances) using an unbalance handler (implementing
1102/// `OnUnbalanced`).
1103/// Similar to `CurrencyAdapter` of `pallet_transaction_payment`
1104pub struct EVMCurrencyAdapter<C, OU>(core::marker::PhantomData<(C, OU)>);
1105
1106impl<T, C, OU> OnChargeEVMTransaction<T> for EVMCurrencyAdapter<C, OU>
1107where
1108	T: Config,
1109	C: Currency<AccountIdOf<T>>,
1110	C::PositiveImbalance:
1111		Imbalance<<C as Currency<AccountIdOf<T>>>::Balance, Opposite = C::NegativeImbalance>,
1112	C::NegativeImbalance:
1113		Imbalance<<C as Currency<AccountIdOf<T>>>::Balance, Opposite = C::PositiveImbalance>,
1114	OU: OnUnbalanced<NegativeImbalanceOf<C, T>>,
1115	U256: UniqueSaturatedInto<<C as Currency<AccountIdOf<T>>>::Balance>,
1116{
1117	// Kept type as Option to satisfy bound of Default
1118	type LiquidityInfo = Option<NegativeImbalanceOf<C, T>>;
1119
1120	fn withdraw_fee(who: &H160, fee: U256) -> Result<Self::LiquidityInfo, Error<T>> {
1121		if fee.is_zero() {
1122			return Ok(None);
1123		}
1124		let account_id = T::AddressMapping::into_account_id(*who);
1125		let imbalance = C::withdraw(
1126			&account_id,
1127			fee.unique_saturated_into(),
1128			WithdrawReasons::FEE,
1129			ExistenceRequirement::AllowDeath,
1130		)
1131		.map_err(|_| Error::<T>::BalanceLow)?;
1132		Ok(Some(imbalance))
1133	}
1134
1135	fn correct_and_deposit_fee(
1136		who: &H160,
1137		corrected_fee: U256,
1138		base_fee: U256,
1139		already_withdrawn: Self::LiquidityInfo,
1140	) -> Self::LiquidityInfo {
1141		if let Some(paid) = already_withdrawn {
1142			let account_id = T::AddressMapping::into_account_id(*who);
1143
1144			// Calculate how much refund we should return
1145			let refund_amount = paid
1146				.peek()
1147				.saturating_sub(corrected_fee.unique_saturated_into());
1148			// refund to the account that paid the fees. If this fails, the
1149			// account might have dropped below the existential balance. In
1150			// that case we don't refund anything.
1151			let refund_imbalance = C::deposit_into_existing(&account_id, refund_amount)
1152				.unwrap_or_else(|_| C::PositiveImbalance::zero());
1153
1154			// Make sure this works with 0 ExistentialDeposit
1155			// https://github.com/paritytech/substrate/issues/10117
1156			// If we tried to refund something, the account still empty and the ED is set to 0,
1157			// we call `make_free_balance_be` with the refunded amount.
1158			let refund_imbalance = if C::minimum_balance().is_zero()
1159				&& refund_amount > C::Balance::zero()
1160				&& C::total_balance(&account_id).is_zero()
1161			{
1162				// Known bug: Substrate tried to refund to a zeroed AccountData, but
1163				// interpreted the account to not exist.
1164				match C::make_free_balance_be(&account_id, refund_amount) {
1165					SignedImbalance::Positive(p) => p,
1166					_ => C::PositiveImbalance::zero(),
1167				}
1168			} else {
1169				refund_imbalance
1170			};
1171
1172			// merge the imbalance caused by paying the fees and refunding parts of it again.
1173			let adjusted_paid = paid
1174				.offset(refund_imbalance)
1175				.same()
1176				.unwrap_or_else(|_| C::NegativeImbalance::zero());
1177
1178			let (base_fee, tip) = adjusted_paid.split(base_fee.unique_saturated_into());
1179			// Handle base fee. Can be either burned, rationed, etc ...
1180			OU::on_unbalanced(base_fee);
1181			return Some(tip);
1182		}
1183		None
1184	}
1185
1186	fn pay_priority_fee(tip: Self::LiquidityInfo) {
1187		// Default Ethereum behaviour: issue the tip to the block author.
1188		if let Some(tip) = tip {
1189			let account_id = T::AddressMapping::into_account_id(<Pallet<T>>::find_author());
1190			let _ = C::deposit_into_existing(&account_id, tip.peek());
1191		}
1192	}
1193}
1194/// Implements transaction payment for a pallet implementing the [`fungible`]
1195/// trait (eg. pallet_balances) using an unbalance handler (implementing
1196/// [`OnUnbalanced`]).
1197///
1198/// Equivalent of `EVMCurrencyAdapter` but for fungible traits. Similar to `FungibleAdapter` of
1199/// `pallet_transaction_payment`
1200pub struct EVMFungibleAdapter<F, OU>(core::marker::PhantomData<(F, OU)>);
1201
1202impl<T, F, OU> OnChargeEVMTransaction<T> for EVMFungibleAdapter<F, OU>
1203where
1204	T: Config,
1205	F: Balanced<AccountIdOf<T>>,
1206	OU: OnUnbalanced<Credit<AccountIdOf<T>, F>>,
1207	U256: UniqueSaturatedInto<<F as Inspect<AccountIdOf<T>>>::Balance>,
1208{
1209	// Kept type as Option to satisfy bound of Default
1210	type LiquidityInfo = Option<Credit<AccountIdOf<T>, F>>;
1211
1212	fn withdraw_fee(who: &H160, fee: U256) -> Result<Self::LiquidityInfo, Error<T>> {
1213		if fee.is_zero() {
1214			return Ok(None);
1215		}
1216		let account_id = T::AddressMapping::into_account_id(*who);
1217		let imbalance = F::withdraw(
1218			&account_id,
1219			fee.unique_saturated_into(),
1220			Precision::Exact,
1221			Preservation::Preserve,
1222			Fortitude::Polite,
1223		)
1224		.map_err(|_| Error::<T>::BalanceLow)?;
1225		Ok(Some(imbalance))
1226	}
1227
1228	fn correct_and_deposit_fee(
1229		who: &H160,
1230		corrected_fee: U256,
1231		base_fee: U256,
1232		already_withdrawn: Self::LiquidityInfo,
1233	) -> Self::LiquidityInfo {
1234		if let Some(paid) = already_withdrawn {
1235			let account_id = T::AddressMapping::into_account_id(*who);
1236
1237			// Calculate how much refund we should return
1238			let refund_amount = paid
1239				.peek()
1240				.saturating_sub(corrected_fee.unique_saturated_into());
1241			// refund to the account that paid the fees.
1242			let refund_imbalance = F::deposit(&account_id, refund_amount, Precision::BestEffort)
1243				.unwrap_or_else(|_| Debt::<AccountIdOf<T>, F>::zero());
1244
1245			// merge the imbalance caused by paying the fees and refunding parts of it again.
1246			let adjusted_paid = paid
1247				.offset(refund_imbalance)
1248				.same()
1249				.unwrap_or_else(|_| Credit::<AccountIdOf<T>, F>::zero());
1250
1251			let (base_fee, tip) = adjusted_paid.split(base_fee.unique_saturated_into());
1252			// Handle base fee. Can be either burned, rationed, etc ...
1253			OU::on_unbalanced(base_fee);
1254			return Some(tip);
1255		}
1256		None
1257	}
1258
1259	fn pay_priority_fee(tip: Self::LiquidityInfo) {
1260		// Default Ethereum behaviour: issue the tip to the block author.
1261		if let Some(tip) = tip {
1262			let account_id = T::AddressMapping::into_account_id(<Pallet<T>>::find_author());
1263			let _ = F::deposit(&account_id, tip.peek(), Precision::BestEffort);
1264		}
1265	}
1266}
1267
1268/// Implementation for () does not specify what to do with imbalance
1269impl<T> OnChargeEVMTransaction<T> for ()
1270where
1271	T: Config,
1272	T::Currency: Balanced<AccountIdOf<T>>,
1273	U256: UniqueSaturatedInto<<<T as Config>::Currency as Inspect<AccountIdOf<T>>>::Balance>,
1274{
1275	// Kept type as Option to satisfy bound of Default
1276	type LiquidityInfo = Option<Credit<AccountIdOf<T>, T::Currency>>;
1277
1278	fn withdraw_fee(who: &H160, fee: U256) -> Result<Self::LiquidityInfo, Error<T>> {
1279		EVMFungibleAdapter::<T::Currency, ()>::withdraw_fee(who, fee)
1280	}
1281
1282	fn correct_and_deposit_fee(
1283		who: &H160,
1284		corrected_fee: U256,
1285		base_fee: U256,
1286		already_withdrawn: Self::LiquidityInfo,
1287	) -> Self::LiquidityInfo {
1288		<EVMFungibleAdapter<T::Currency, ()> as OnChargeEVMTransaction<T>>::correct_and_deposit_fee(
1289			who,
1290			corrected_fee,
1291			base_fee,
1292			already_withdrawn,
1293		)
1294	}
1295
1296	fn pay_priority_fee(tip: Self::LiquidityInfo) {
1297		<EVMFungibleAdapter<T::Currency, ()> as OnChargeEVMTransaction<T>>::pay_priority_fee(tip);
1298	}
1299}
1300
1301pub trait OnCreate<T> {
1302	fn on_create(owner: H160, contract: H160);
1303}
1304
1305impl<T> OnCreate<T> for () {
1306	fn on_create(_owner: H160, _contract: H160) {}
1307}
1308
1309#[impl_for_tuples(1, 12)]
1310impl<T> OnCreate<T> for Tuple {
1311	fn on_create(owner: H160, contract: H160) {
1312		for_tuples!(#(
1313			Tuple::on_create(owner, contract);
1314		)*)
1315	}
1316}
1317
1318/// EVM account provider based on the [`frame_system`] accounts.
1319///
1320/// Uses standard Substrate accounts system to hold EVM accounts.
1321pub struct FrameSystemAccountProvider<T>(core::marker::PhantomData<T>);
1322
1323impl<T: frame_system::Config> AccountProvider for FrameSystemAccountProvider<T> {
1324	type AccountId = T::AccountId;
1325	type Nonce = T::Nonce;
1326
1327	fn account_nonce(who: &Self::AccountId) -> Self::Nonce {
1328		frame_system::Pallet::<T>::account_nonce(who)
1329	}
1330
1331	fn inc_account_nonce(who: &Self::AccountId) {
1332		frame_system::Pallet::<T>::inc_account_nonce(who)
1333	}
1334
1335	fn create_account(who: &Self::AccountId) {
1336		let _ = frame_system::Pallet::<T>::inc_sufficients(who);
1337	}
1338
1339	fn remove_account(who: &Self::AccountId) {
1340		let _ = frame_system::Pallet::<T>::dec_sufficients(who);
1341	}
1342}