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