referrerpolicy=no-referrer-when-downgrade

pallet_revive/
lib.rs

1// This file is part of Substrate.
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#![doc = include_str!("../README.md")]
19#![allow(rustdoc::private_intra_doc_links)]
20#![cfg_attr(not(feature = "std"), no_std)]
21#![cfg_attr(feature = "runtime-benchmarks", recursion_limit = "1024")]
22
23extern crate alloc;
24
25mod access_list;
26mod address;
27mod benchmarking;
28#[cfg(any(feature = "runtime-benchmarks", test))]
29pub mod call_builder;
30mod debug;
31mod deposit_payment;
32mod exec;
33mod impl_fungibles;
34mod limits;
35mod metering;
36mod primitives;
37#[doc(hidden)]
38pub mod runtime_api;
39#[doc(hidden)]
40pub mod state_overrides;
41mod storage;
42#[cfg(test)]
43mod tests;
44mod transient_storage;
45mod vm;
46mod weightinfo_extension;
47
48pub mod evm;
49pub mod migrations;
50pub mod mock;
51pub mod precompiles;
52pub mod test_utils;
53pub mod tracing;
54pub mod weights;
55
56use crate::{
57	access_list::Warmth,
58	evm::{
59		CallTracer, CreateCallMode, ExecutionTracer, GenericTransaction, PrestateTracer,
60		StateOverrideSet, TYPE_EIP1559, TYPE_EIP7702, Tracer, TracerType,
61		block_hash::EthereumBlockBuilderIR, block_storage, fees::InfoT as FeeInfo,
62		runtime::SetWeightLimit,
63	},
64	exec::{AccountIdOf, ExecError, Stack as ExecStack},
65	sp_runtime::TransactionOutcome,
66	storage::{AccountType, DeletionQueueManager},
67	tracing::if_tracing,
68	vm::{CodeInfo, RuntimeCosts, StorageAccessKind, pvm::extract_code_and_data},
69	weightinfo_extension::OnFinalizeBlockParts,
70};
71use alloc::{boxed::Box, format, vec};
72use codec::{Codec, Decode, Encode, MaxEncodedLen};
73use environmental::*;
74use frame_support::{
75	BoundedVec,
76	dispatch::{
77		DispatchErrorWithPostInfo, DispatchResult, DispatchResultWithPostInfo, GetDispatchInfo,
78		Pays, PostDispatchInfo, RawOrigin,
79	},
80	ensure,
81	pallet_prelude::DispatchClass,
82	storage::with_transaction,
83	traits::{
84		ConstU32, ConstU64, DefensiveResult, EnsureOrigin, Get, IsSubType, IsType, OnUnbalanced,
85		OriginTrait,
86		fungible::{Balanced, Credit, Inspect, Mutate, MutateHold},
87		tokens::Balance,
88	},
89	weights::WeightMeter,
90};
91use frame_system::{
92	Pallet as System, ensure_signed,
93	pallet_prelude::{BlockNumberFor, OriginFor},
94};
95use pallet_revive_types::runtime_api::*;
96use scale_info::TypeInfo;
97use sp_runtime::{
98	AccountId32, DispatchError, FixedPointNumber, FixedU128, SaturatedConversion,
99	traits::{
100		BadOrigin, Bounded, Convert, Dispatchable, Saturating, UniqueSaturatedFrom,
101		UniqueSaturatedInto, Zero,
102	},
103};
104
105pub use crate::{
106	address::{AccountId32Mapper, AddressMapper, AutoMapper, TestAccountMapper, create1, create2},
107	debug::DebugSettings,
108	deposit_payment::{Deposit, PGasDeposit},
109	evm::{Address as EthAddress, Block as EthBlock, block_hash::ReceiptGasInfo},
110	exec::{
111		CallResources, DelegateInfo, Executable, Key, MomentOf, Origin as ExecOrigin,
112		ReentrancyProtection,
113	},
114	limits::TRANSIENT_STORAGE_BYTES as TRANSIENT_STORAGE_LIMIT,
115	metering::{
116		EthTxInfo, FrameMeter, ResourceMeter, Token as WeightToken, TransactionLimits,
117		TransactionMeter,
118	},
119	pallet::{genesis, *},
120	storage::{AccountInfo, ContractInfo},
121	transient_storage::{MeterEntry, StorageMeter as TransientStorageMeter, TransientStorage},
122	vm::{BytecodeType, ContractBlob},
123};
124pub use codec;
125use frame_support::traits::tokens::Precision;
126pub use frame_support::{self, dispatch::DispatchInfo, traits::Time, weights::Weight};
127pub use frame_system::{self, limits::BlockWeights};
128pub use primitives::*;
129pub use sp_core::{H160, H256, U256};
130pub use sp_crypto_hashing::keccak_256;
131pub use sp_runtime;
132pub use weights::WeightInfo;
133
134// Types re-export, needed to make it easier for runtimes to implement the pallet-revive runtime API
135pub extern crate pallet_revive_types;
136
137#[cfg(doc)]
138pub use crate::vm::pvm::SyscallDoc;
139
140pub type BalanceOf<T> = <T as Config>::Balance;
141pub type CreditOf<T> = Credit<<T as frame_system::Config>::AccountId, <T as Config>::Currency>;
142type TrieId = BoundedVec<u8, ConstU32<128>>;
143type ImmutableData = BoundedVec<u8, ConstU32<{ limits::IMMUTABLE_BYTES }>>;
144type CallOf<T> = <T as Config>::RuntimeCall;
145
146/// Used as a sentinel value when reading and writing contract memory.
147///
148/// It is usually used to signal `None` to a contract when only a primitive is allowed
149/// and we don't want to go through encoding a full Rust type. Using `u32::Max` is a safe
150/// sentinel because contracts are never allowed to use such a large amount of resources
151/// that this value makes sense for a memory location or length.
152const SENTINEL: u32 = u32::MAX;
153
154/// The target that is used for the log output emitted by this crate.
155///
156/// Hence you can use this target to selectively increase the log level for this crate.
157///
158/// Example: `RUST_LOG=runtime::revive=debug my_code --dev`
159const LOG_TARGET: &str = "runtime::revive";
160
161#[frame_support::pallet]
162pub mod pallet {
163	use super::*;
164	use frame_support::{pallet_prelude::*, traits::FindAuthor};
165	use frame_system::pallet_prelude::*;
166	use sp_core::U256;
167	use sp_runtime::Perbill;
168
169	/// The in-code storage version.
170	pub(crate) const STORAGE_VERSION: StorageVersion = StorageVersion::new(0);
171
172	#[pallet::pallet]
173	#[pallet::storage_version(STORAGE_VERSION)]
174	pub struct Pallet<T>(_);
175
176	#[pallet::config(with_default)]
177	pub trait Config: frame_system::Config {
178		/// The time implementation used to supply timestamps to contracts through `seal_now`.
179		type Time: Time<Moment: Into<U256>>;
180
181		/// The balance type of [`Self::Currency`].
182		///
183		/// Just added here to add additional trait bounds.
184		#[pallet::no_default]
185		type Balance: Balance
186			+ TryFrom<U256>
187			+ Into<U256>
188			+ Bounded
189			+ UniqueSaturatedInto<u64>
190			+ UniqueSaturatedFrom<u64>
191			+ UniqueSaturatedInto<u128>;
192
193		/// The fungible in which fees are paid and contract balances are held.
194		#[pallet::no_default]
195		type Currency: Inspect<Self::AccountId, Balance = Self::Balance>
196			+ Mutate<Self::AccountId>
197			+ MutateHold<Self::AccountId, Reason = Self::RuntimeHoldReason>
198			+ Balanced<Self::AccountId>;
199
200		/// Handler for burned native currency (e.g. gas rounding).
201		///
202		/// When EVM gas accounting rounds up the transaction cost, the small rounding
203		/// difference is withdrawn from the caller and forwarded to this handler.
204		/// Use this to redirect burned value to a treasury or DAP instead of silently
205		/// destroying it.
206		#[pallet::no_default_bounds]
207		type OnBurn: OnUnbalanced<CreditOf<Self>>;
208
209		/// The overarching event type.
210		#[pallet::no_default_bounds]
211		#[allow(deprecated)]
212		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
213
214		/// The overarching call type.
215		#[pallet::no_default_bounds]
216		type RuntimeCall: Parameter
217			+ Dispatchable<
218				RuntimeOrigin = OriginFor<Self>,
219				Info = DispatchInfo,
220				PostInfo = PostDispatchInfo,
221			> + IsType<<Self as frame_system::Config>::RuntimeCall>
222			+ From<Call<Self>>
223			+ IsSubType<Call<Self>>
224			+ GetDispatchInfo;
225
226		/// The overarching origin type.
227		#[pallet::no_default_bounds]
228		type RuntimeOrigin: IsType<OriginFor<Self>>
229			+ From<Origin<Self>>
230			+ Into<Result<Origin<Self>, OriginFor<Self>>>;
231
232		/// Overarching hold reason.
233		#[pallet::no_default_bounds]
234		type RuntimeHoldReason: From<HoldReason>;
235
236		/// Describes the weights of the dispatchables of this module and is also used to
237		/// construct a default cost schedule.
238		type WeightInfo: WeightInfo;
239
240		/// Type that allows the runtime authors to add new host functions for a contract to call.
241		///
242		/// Pass in a tuple of types that implement [`precompiles::Precompile`].
243		#[pallet::no_default_bounds]
244		#[allow(private_bounds)]
245		type Precompiles: precompiles::Precompiles<Self>;
246
247		/// Find the author of the current block.
248		type FindAuthor: FindAuthor<Self::AccountId>;
249
250		/// The amount of balance a caller has to pay for each byte of storage.
251		///
252		/// # Note
253		///
254		/// It is safe to change this value on a live chain as all refunds are pro rata.
255		#[pallet::constant]
256		#[pallet::no_default_bounds]
257		type DepositPerByte: Get<BalanceOf<Self>>;
258
259		/// The amount of balance a caller has to pay for each storage item.
260		///
261		/// # Note
262		///
263		/// It is safe to change this value on a live chain as all refunds are pro rata.
264		#[pallet::constant]
265		#[pallet::no_default_bounds]
266		type DepositPerItem: Get<BalanceOf<Self>>;
267
268		/// The amount of balance a caller has to pay for each child trie storage item.
269		///
270		/// Those are the items created by a contract. In Solidity each value is a single
271		/// storage item. This is why we need to set a lower value here than for the main
272		/// trie items. Otherwise the storage deposit is too high.
273		///
274		/// # Note
275		///
276		/// It is safe to change this value on a live chain as all refunds are pro rata.
277		#[pallet::constant]
278		#[pallet::no_default_bounds]
279		type DepositPerChildTrieItem: Get<BalanceOf<Self>>;
280
281		/// The percentage of the storage deposit that should be held for using a code hash.
282		/// Instantiating a contract, protects the code from being removed. In order to prevent
283		/// abuse these actions are protected with a percentage of the code deposit.
284		#[pallet::constant]
285		type CodeHashLockupDepositPercent: Get<Perbill>;
286
287		/// Use either valid type is [`address::AccountId32Mapper`] or [`address::H160Mapper`].
288		#[pallet::no_default]
289		type AddressMapper: AddressMapper<Self>;
290
291		/// Allow EVM bytecode to be uploaded and instantiated.
292		#[pallet::constant]
293		type AllowEVMBytecode: Get<bool>;
294
295		/// Origin allowed to upload code.
296		///
297		/// By default, it is safe to set this to `EnsureSigned`, allowing anyone to upload contract
298		/// code.
299		#[pallet::no_default_bounds]
300		type UploadOrigin: EnsureOrigin<OriginFor<Self>, Success = Self::AccountId>;
301
302		/// Origin allowed to instantiate code.
303		///
304		/// # Note
305		///
306		/// This is not enforced when a contract instantiates another contract. The
307		/// [`Self::UploadOrigin`] should make sure that no code is deployed that does unwanted
308		/// instantiations.
309		///
310		/// By default, it is safe to set this to `EnsureSigned`, allowing anyone to instantiate
311		/// contract code.
312		#[pallet::no_default_bounds]
313		type InstantiateOrigin: EnsureOrigin<OriginFor<Self>, Success = Self::AccountId>;
314
315		/// The amount of memory in bytes that parachain nodes a lot to the runtime.
316		///
317		/// This is used in [`Pallet::integrity_test`] to make sure that the runtime has enough
318		/// memory to support this pallet if set to the correct value.
319		type RuntimeMemory: Get<u32>;
320
321		/// The amount of memory in bytes that relay chain validators a lot to the PoV.
322		///
323		/// This is used in [`Pallet::integrity_test`] to make sure that the runtime has enough
324		/// memory to support this pallet if set to the correct value.
325		///
326		/// This value is usually higher than [`Self::RuntimeMemory`] to account for the fact
327		/// that validators have to hold all storage items in PvF memory.
328		type PVFMemory: Get<u32>;
329
330		/// The [EIP-155](https://eips.ethereum.org/EIPS/eip-155) chain ID.
331		///
332		/// This is a unique identifier assigned to each blockchain network,
333		/// preventing replay attacks.
334		#[pallet::constant]
335		type ChainId: Get<u64>;
336
337		/// The ratio between the decimal representation of the native token and the ETH token.
338		#[pallet::constant]
339		type NativeToEthRatio: Get<u32>;
340
341		/// Set to [`crate::evm::fees::Info`] for a production runtime.
342		///
343		/// For mock runtimes that do not need to interact with any eth compat functionality
344		/// the default value of `()` will suffice.
345		#[pallet::no_default_bounds]
346		type FeeInfo: FeeInfo<Self>;
347
348		/// Payment backend used to charge storage deposits.
349		/// The default `()` binding always uses the native currency.
350		#[pallet::no_default_bounds]
351		type Deposit: Deposit<Self>;
352
353		/// The fraction the maximum extrinsic weight `eth_transact` extrinsics are capped to.
354		///
355		/// This is not a security measure but a requirement due to how we map gas to `(Weight,
356		/// StorageDeposit)`. The mapping might derive a `Weight` that is too large to fit into an
357		/// extrinsic. In this case we cap it to the limit specified here.
358		///
359		/// `eth_transact` transactions that use more weight than specified will fail with an out of
360		/// gas error during execution. Larger fractions will allow more transactions to run.
361		/// Smaller values waste less block space: Choose as small as possible and as large as
362		/// necessary.
363		///
364		///  Default: `0.5`.
365		#[pallet::constant]
366		type MaxEthExtrinsicWeight: Get<FixedU128>;
367
368		/// Allows debug-mode configuration, such as enabling unlimited contract size.
369		#[pallet::constant]
370		type DebugEnabled: Get<bool>;
371
372		/// When enabled, accounts are automatically mapped on creation and unmapped on
373		/// kill via [`AutoMapper`]. This removes the need for explicit `map_account` calls.
374		///
375		/// Requires `frame_system::Config::OnNewAccount` and `OnKilledAccount` to be set
376		/// to [`AutoMapper`]. When enabled, the `map_account` and `unmap_account`
377		/// dispatchables are disabled.
378		#[pallet::constant]
379		type AutoMap: Get<bool>;
380
381		/// This determines the relative scale of our gas price and gas estimates.
382		///
383		/// By default, the gas price (in wei) is `FeeInfo::next_fee_multiplier()` multiplied by
384		/// `NativeToEthRatio`. `GasScale` allows to scale this value: the actual gas price is the
385		/// default gas price multiplied by `GasScale`.
386		///
387		/// As a consequence, gas cost (gas estimates and actual gas usage during transaction) is
388		/// scaled down by the same factor. Thus, the total transaction cost is not affected by
389		/// `GasScale` – apart from rounding differences: the transaction cost is always a multiple
390		/// of the gas price and is derived by rounded up, so that with higher `GasScales` this can
391		/// lead to higher gas cost as the rounding difference would be larger.
392		///
393		/// The main purpose of changing the `GasScale` is to tune the gas cost so that it is closer
394		/// to standard EVM gas cost and contracts will not run out of gas when tools or code
395		/// assume hard coded gas limits.
396		///
397		/// Requirement: `GasScale` must not be 0
398		#[pallet::constant]
399		#[pallet::no_default_bounds]
400		type GasScale: Get<u32>;
401	}
402
403	/// Container for different types that implement [`DefaultConfig`]` of this pallet.
404	pub mod config_preludes {
405		use super::*;
406		use frame_support::{
407			derive_impl,
408			traits::{ConstBool, ConstU32},
409		};
410		use frame_system::EnsureSigned;
411		use sp_core::parameter_types;
412
413		type Balance = u64;
414
415		pub const DOLLARS: Balance = 1_000_000_000_000;
416		pub const CENTS: Balance = DOLLARS / 100;
417		pub const MILLICENTS: Balance = CENTS / 1_000;
418
419		pub const fn deposit(items: u32, bytes: u32) -> Balance {
420			items as Balance * 20 * CENTS + (bytes as Balance) * MILLICENTS
421		}
422
423		parameter_types! {
424			pub const DepositPerItem: Balance = deposit(1, 0);
425			pub const DepositPerChildTrieItem: Balance = deposit(1, 0) / 100;
426			pub const DepositPerByte: Balance = deposit(0, 1);
427			pub const CodeHashLockupDepositPercent: Perbill = Perbill::from_percent(0);
428			pub const MaxEthExtrinsicWeight: FixedU128 = FixedU128::from_rational(9, 10);
429			pub const GasScale: u32 = 10u32;
430		}
431
432		/// A type providing default configurations for this pallet in testing environment.
433		pub struct TestDefaultConfig;
434
435		impl Time for TestDefaultConfig {
436			type Moment = u64;
437			fn now() -> Self::Moment {
438				0u64
439			}
440		}
441
442		impl<T: From<u64>> Convert<Weight, T> for TestDefaultConfig {
443			fn convert(w: Weight) -> T {
444				w.ref_time().into()
445			}
446		}
447
448		#[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)]
449		impl frame_system::DefaultConfig for TestDefaultConfig {}
450
451		#[frame_support::register_default_impl(TestDefaultConfig)]
452		impl DefaultConfig for TestDefaultConfig {
453			#[inject_runtime_type]
454			type RuntimeEvent = ();
455
456			#[inject_runtime_type]
457			type RuntimeHoldReason = ();
458
459			#[inject_runtime_type]
460			type RuntimeCall = ();
461
462			#[inject_runtime_type]
463			type RuntimeOrigin = ();
464
465			type Precompiles = ();
466			type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent;
467			type DepositPerByte = DepositPerByte;
468			type DepositPerItem = DepositPerItem;
469			type DepositPerChildTrieItem = DepositPerChildTrieItem;
470			type Time = Self;
471			type AllowEVMBytecode = ConstBool<true>;
472			type UploadOrigin = EnsureSigned<Self::AccountId>;
473			type InstantiateOrigin = EnsureSigned<Self::AccountId>;
474			type WeightInfo = ();
475			type RuntimeMemory = ConstU32<{ 128 * 1024 * 1024 }>;
476			type PVFMemory = ConstU32<{ 512 * 1024 * 1024 }>;
477			type ChainId = ConstU64<42>;
478			type NativeToEthRatio = ConstU32<1_000_000>;
479			type FindAuthor = ();
480			type FeeInfo = ();
481			type Deposit = ();
482			type MaxEthExtrinsicWeight = MaxEthExtrinsicWeight;
483			type DebugEnabled = ConstBool<false>;
484			type AutoMap = ConstBool<false>;
485			type GasScale = GasScale;
486			type OnBurn = ();
487		}
488	}
489
490	#[pallet::event]
491	pub enum Event<T: Config> {
492		/// A custom event emitted by the contract.
493		ContractEmitted {
494			/// The contract that emitted the event.
495			contract: H160,
496			/// Data supplied by the contract. Metadata generated during contract compilation
497			/// is needed to decode it.
498			data: Vec<u8>,
499			/// A list of topics used to index the event.
500			/// Number of topics is capped by [`limits::NUM_EVENT_TOPICS`].
501			topics: Vec<H256>,
502		},
503
504		/// Contract deployed by deployer at the specified address.
505		Instantiated { deployer: H160, contract: H160 },
506
507		/// Emitted when an Ethereum transaction reverts.
508		///
509		/// Ethereum transactions always complete successfully at the extrinsic level,
510		/// as even reverted calls must store their `ReceiptInfo`.
511		/// To distinguish reverted calls from successful ones, this event is emitted
512		/// for failed Ethereum transactions.
513		EthExtrinsicRevert { dispatch_error: DispatchError },
514	}
515
516	#[pallet::error]
517	#[repr(u8)]
518	pub enum Error<T> {
519		/// Invalid schedule supplied, e.g. with zero weight of a basic operation.
520		InvalidSchedule = 0x01,
521		/// Invalid combination of flags supplied to `seal_call` or `seal_delegate_call`.
522		InvalidCallFlags = 0x02,
523		/// The executed contract exhausted its gas limit.
524		OutOfGas = 0x03,
525		/// Performing the requested transfer failed. Probably because there isn't enough
526		/// free balance in the sender's account.
527		TransferFailed = 0x04,
528		/// Performing a call was denied because the calling depth reached the limit
529		/// of what is specified in the schedule.
530		MaxCallDepthReached = 0x05,
531		/// No contract was found at the specified address.
532		ContractNotFound = 0x06,
533		/// No code could be found at the supplied code hash.
534		CodeNotFound = 0x07,
535		/// No code info could be found at the supplied code hash.
536		CodeInfoNotFound = 0x08,
537		/// A buffer outside of sandbox memory was passed to a contract API function.
538		OutOfBounds = 0x09,
539		/// Input passed to a contract API function failed to decode as expected type.
540		DecodingFailed = 0x0A,
541		/// Contract trapped during execution.
542		ContractTrapped = 0x0B,
543		/// Event body or storage item exceeds [`limits::STORAGE_BYTES`].
544		ValueTooLarge = 0x0C,
545		/// Termination of a contract is not allowed while the contract is already
546		/// on the call stack. Can be triggered by `seal_terminate`.
547		TerminatedWhileReentrant = 0x0D,
548		/// `seal_call` forwarded this contracts input. It therefore is no longer available.
549		InputForwarded = 0x0E,
550		/// The amount of topics passed to `seal_deposit_events` exceeds the limit.
551		TooManyTopics = 0x0F,
552		/// A contract with the same AccountId already exists.
553		DuplicateContract = 0x12,
554		/// A contract self destructed in its constructor.
555		///
556		/// This can be triggered by a call to `seal_terminate`.
557		TerminatedInConstructor = 0x13,
558		/// A call tried to invoke a contract that is flagged as non-reentrant.
559		ReentranceDenied = 0x14,
560		/// A contract called into the runtime which then called back into this pallet.
561		ReenteredPallet = 0x15,
562		/// A contract attempted to invoke a state modifying API while being in read-only mode.
563		StateChangeDenied = 0x16,
564		/// Origin doesn't have enough balance to pay the required storage deposits.
565		StorageDepositNotEnoughFunds = 0x17,
566		/// More storage was created than allowed by the storage deposit limit.
567		StorageDepositLimitExhausted = 0x18,
568		/// Code removal was denied because the code is still in use by at least one contract.
569		CodeInUse = 0x19,
570		/// The contract ran to completion but decided to revert its storage changes.
571		/// Please note that this error is only returned from extrinsics. When called directly
572		/// or via RPC an `Ok` will be returned. In this case the caller needs to inspect the flags
573		/// to determine whether a reversion has taken place.
574		ContractReverted = 0x1A,
575		/// The contract failed to compile or is missing the correct entry points.
576		///
577		/// A more detailed error can be found on the node console if debug messages are enabled
578		/// by supplying `-lruntime::revive=debug`.
579		CodeRejected = 0x1B,
580		/// The code blob supplied is larger than [`limits::code::BLOB_BYTES`].
581		BlobTooLarge = 0x1C,
582		/// The contract declares too much memory (ro + rw + stack).
583		StaticMemoryTooLarge = 0x1D,
584		/// The program contains a basic block that is larger than allowed.
585		BasicBlockTooLarge = 0x1E,
586		/// The program contains an invalid instruction.
587		InvalidInstruction = 0x1F,
588		/// The contract has reached its maximum number of delegate dependencies.
589		MaxDelegateDependenciesReached = 0x20,
590		/// The dependency was not found in the contract's delegate dependencies.
591		DelegateDependencyNotFound = 0x21,
592		/// The contract already depends on the given delegate dependency.
593		DelegateDependencyAlreadyExists = 0x22,
594		/// Can not add a delegate dependency to the code hash of the contract itself.
595		CannotAddSelfAsDelegateDependency = 0x23,
596		/// Can not add more data to transient storage.
597		OutOfTransientStorage = 0x24,
598		/// The contract tried to call a syscall which does not exist (at its current api level).
599		InvalidSyscall = 0x25,
600		/// Invalid storage flags were passed to one of the storage syscalls.
601		InvalidStorageFlags = 0x26,
602		/// PolkaVM failed during code execution. Probably due to a malformed program.
603		ExecutionFailed = 0x27,
604		/// Failed to convert a U256 to a Balance.
605		BalanceConversionFailed = 0x28,
606		/// Immutable data can only be set during deploys and only be read during calls.
607		/// Additionally, it is only valid to set the data once and it must not be empty.
608		InvalidImmutableAccess = 0x2A,
609		/// An `AccountID32` account tried to interact with the pallet without having a mapping.
610		///
611		/// Call [`Pallet::map_account`] in order to create a mapping for the account.
612		AccountUnmapped = 0x2B,
613		/// Tried to map an account that is already mapped.
614		AccountAlreadyMapped = 0x2C,
615		/// The transaction used to dry-run a contract is invalid.
616		InvalidGenericTransaction = 0x2D,
617		/// The refcount of a code either over or underflowed.
618		RefcountOverOrUnderflow = 0x2E,
619		/// Unsupported precompile address.
620		UnsupportedPrecompileAddress = 0x2F,
621		/// The calldata exceeds [`limits::CALLDATA_BYTES`].
622		CallDataTooLarge = 0x30,
623		/// The return data exceeds [`limits::CALLDATA_BYTES`].
624		ReturnDataTooLarge = 0x31,
625		/// Invalid jump destination. Dynamic jumps points to invalid not jumpdest opcode.
626		InvalidJump = 0x32,
627		/// Attempting to pop a value from an empty stack.
628		StackUnderflow = 0x33,
629		/// Attempting to push a value onto a full stack.
630		StackOverflow = 0x34,
631		/// Too much deposit was drawn from the shared txfee and deposit credit.
632		///
633		/// This happens if the passed `gas` inside the ethereum transaction is too low.
634		TxFeeOverdraw = 0x35,
635		/// When calling an EVM constructor `data` has to be empty.
636		///
637		/// EVM constructors do not accept data. Their input data is part of the code blob itself.
638		EvmConstructorNonEmptyData = 0x36,
639		/// Tried to construct an EVM contract via code hash.
640		///
641		/// EVM contracts can only be instantiated via code upload as no initcode is
642		/// stored on-chain.
643		EvmConstructedFromHash = 0x37,
644		/// The contract does not have enough balance to refund the storage deposit.
645		///
646		/// This is a bug and should never happen. It means the accounting got out of sync.
647		StorageRefundNotEnoughFunds = 0x38,
648		/// This means there are locks on the contracts storage deposit that prevents refunding it.
649		///
650		/// This would be the case if the contract used its storage deposits for governance
651		/// or other pallets that allow creating locks over held balance.
652		StorageRefundLocked = 0x39,
653		/// Called a pre-compile that is not allowed to be delegate called.
654		///
655		/// Some pre-compile functions will trap the caller context if being delegate
656		/// called or if their caller was being delegate called.
657		PrecompileDelegateDenied = 0x40,
658		/// ECDSA public key recovery failed. Most probably wrong recovery id or signature.
659		EcdsaRecoveryFailed = 0x41,
660		/// Manual mapping is disabled when auto-mapping is enabled.
661		AutoMappingEnabled = 0x42,
662		/// A contract cannot be created at this address: it still has uncleared
663		/// [`NativeDepositOf`] entries from a previously terminated contract that the deletion
664		/// queue has not yet drained.
665		PendingDepositCleanup = 0x43,
666		/// `seal_terminate` was invoked on an EIP-7702 delegated EOA. Delegated accounts
667		/// cannot be torn down via the contract-termination path.
668		CannotTerminateDelegatedAccount = 0x44,
669		/// Benchmarking only error.
670		#[cfg(feature = "runtime-benchmarks")]
671		BenchmarkingError = 0xFF,
672	}
673
674	/// A reason for the pallet revive placing a hold on funds.
675	#[pallet::composite_enum]
676	pub enum HoldReason {
677		/// The Pallet has reserved it for storing code on-chain.
678		CodeUploadDepositReserve,
679		/// The Pallet has reserved it for storage deposit.
680		StorageDepositReserve,
681		/// Deposit for creating an address mapping in [`OriginalAccount`].
682		AddressMapping,
683	}
684
685	/// A reason for the pallet revive placing a freeze on PGAS funds.
686	#[pallet::composite_enum]
687	pub enum FreezeReason {
688		/// Pins the PGAS existential deposit minted into a contract account so it cannot be
689		/// transferred or burned by the contract while it is alive. Without this freeze, a
690		/// contract could call the PGAS ERC20 precompile with `Preservation::Expendable` and
691		/// drain its own ED.
692		PGasMinBalance,
693	}
694
695	#[derive(
696		PartialEq, Eq, Clone, MaxEncodedLen, Encode, Decode, DecodeWithMemTracking, TypeInfo, Debug,
697	)]
698	#[pallet::origin]
699	pub enum Origin<T: Config> {
700		EthTransaction(T::AccountId),
701	}
702
703	/// A mapping from a contract's code hash to its code.
704	/// The code's size is bounded by [`crate::limits::BLOB_BYTES`] for PVM and
705	/// [`revm::primitives::eip170::MAX_CODE_SIZE`] for EVM bytecode.
706	#[pallet::storage]
707	#[pallet::unbounded]
708	pub(crate) type PristineCode<T: Config> = StorageMap<_, Identity, H256, Vec<u8>>;
709
710	/// A mapping from a contract's code hash to its code info.
711	#[pallet::storage]
712	pub(crate) type CodeInfoOf<T: Config> = StorageMap<_, Identity, H256, CodeInfo<T>>;
713
714	/// The data associated to a contract or externally owned account.
715	#[pallet::storage]
716	pub(crate) type AccountInfoOf<T: Config> = StorageMap<_, Identity, H160, AccountInfo<T>>;
717
718	/// Native currency storage deposit contributed by a user into a contract.
719	///
720	/// Bounds how much native value the user can receive back from that contract's
721	/// storage deposit.
722	///
723	/// Keys: `(holder, contributor) -> amount`
724	/// - `holder`: account on which the deposit is held (a contract, or the pallet's own account
725	///   for code-upload deposits).
726	/// - `contributor`: user that funded the deposit. Receives the native portion on refund, capped
727	///   at this entry's `amount`.
728	#[pallet::storage]
729	pub(crate) type NativeDepositOf<T: Config> = StorageDoubleMap<
730		_,
731		Identity,
732		T::AccountId,
733		Identity,
734		T::AccountId,
735		BalanceOf<T>,
736		ValueQuery,
737	>;
738
739	/// The immutable data associated with a given account.
740	#[pallet::storage]
741	pub(crate) type ImmutableDataOf<T: Config> = StorageMap<_, Identity, H160, ImmutableData>;
742
743	/// Terminated contracts that await lazy cleanup.
744	///
745	/// Each entry pairs a child trie ID with the contract account so that `on_idle` can
746	/// drain both the child trie and any [`NativeDepositOf`] entries that named the contract
747	/// as `holder`. Both can be arbitrarily large, so cleanup runs lazily in `on_idle`.
748	#[pallet::storage]
749	pub(crate) type DeletionQueue<T: Config> =
750		StorageMap<_, Twox64Concat, u32, crate::storage::DeletionQueueItem<T>>;
751
752	/// A pair of monotonic counters used to track the latest contract marked for deletion
753	/// and the latest deleted contract in queue.
754	#[pallet::storage]
755	pub(crate) type DeletionQueueCounter<T: Config> =
756		StorageValue<_, DeletionQueueManager<T>, ValueQuery>;
757
758	/// Map a Ethereum address to its original `AccountId32`.
759	///
760	/// When deriving a `H160` from an `AccountId32` we use a hash function. In order to
761	/// reconstruct the original account we need to store the reverse mapping here.
762	/// Register your `AccountId32` using [`Pallet::map_account`] in order to
763	/// use it with this pallet.
764	#[pallet::storage]
765	pub(crate) type OriginalAccount<T: Config> = StorageMap<_, Identity, H160, AccountId32>;
766
767	/// The current Ethereum block that is stored in the `on_finalize` method.
768	///
769	/// # Note
770	///
771	/// This could be further optimized into the future to store only the minimum
772	/// information needed to reconstruct the Ethereum block at the RPC level.
773	///
774	/// Since the block is convenient to have around, and the extra details are capped
775	/// by a few hashes and the vector of transaction hashes, we store the block here.
776	#[pallet::storage]
777	#[pallet::unbounded]
778	pub(crate) type EthereumBlock<T> = StorageValue<_, EthBlock, ValueQuery>;
779
780	/// Mapping for block number and hashes.
781	///
782	/// The maximum number of elements stored is capped by the block hash count `BLOCK_HASH_COUNT`.
783	#[pallet::storage]
784	pub(crate) type BlockHash<T: Config> =
785		StorageMap<_, Identity, BlockNumberFor<T>, H256, ValueQuery>;
786
787	/// The details needed to reconstruct the receipt info offchain.
788	///
789	/// This contains valuable information about the gas used by the transaction.
790	///
791	/// NOTE: The item is unbound and should therefore never be read on chain.
792	/// It could otherwise inflate the PoV size of a block.
793	#[pallet::storage]
794	#[pallet::unbounded]
795	pub(crate) type ReceiptInfoData<T: Config> = StorageValue<_, Vec<ReceiptGasInfo>, ValueQuery>;
796
797	/// Incremental ethereum block builder.
798	#[pallet::storage]
799	#[pallet::unbounded]
800	pub(crate) type EthBlockBuilderIR<T: Config> =
801		StorageValue<_, EthereumBlockBuilderIR<T>, ValueQuery>;
802
803	/// The first transaction and receipt of the ethereum block.
804	///
805	/// These values are moved out of the `EthBlockBuilderIR` to avoid serializing and
806	/// deserializing them on every transaction. Instead, they are loaded when needed.
807	#[pallet::storage]
808	#[pallet::unbounded]
809	pub(crate) type EthBlockBuilderFirstValues<T: Config> =
810		StorageValue<_, Option<(Vec<u8>, Vec<u8>)>, ValueQuery>;
811
812	/// Debugging settings that can be configured when DebugEnabled config is true.
813	#[pallet::storage]
814	pub(crate) type DebugSettingsOf<T: Config> = StorageValue<_, DebugSettings, ValueQuery>;
815
816	pub mod genesis {
817		use super::*;
818		use crate::evm::Bytes32;
819
820		/// Genesis configuration for contract-specific data.
821		#[derive(Clone, PartialEq, Debug, Default, serde::Serialize, serde::Deserialize)]
822		pub struct ContractData {
823			/// Contract code.
824			pub code: crate::evm::Bytes,
825			/// Initial storage entries as 32-byte key/value pairs.
826			pub storage: alloc::collections::BTreeMap<Bytes32, Bytes32>,
827		}
828
829		/// Genesis configuration for a contract account.
830		#[derive(PartialEq, Default, Debug, Clone, serde::Serialize, serde::Deserialize)]
831		pub struct Account<T: Config> {
832			/// Contract address.
833			pub address: H160,
834			/// Contract balance.
835			#[serde(default)]
836			pub balance: U256,
837			/// Account nonce
838			#[serde(default)]
839			pub nonce: T::Nonce,
840			/// Contract-specific data (code and storage). None for EOAs.
841			#[serde(flatten, skip_serializing_if = "Option::is_none")]
842			pub contract_data: Option<ContractData>,
843		}
844	}
845
846	#[pallet::genesis_config]
847	#[derive(Debug, PartialEq, frame_support::DefaultNoBound)]
848	pub struct GenesisConfig<T: Config> {
849		/// List of native Substrate accounts (typically `AccountId32`) to be mapped at genesis
850		/// block, enabling them to interact with smart contracts.
851		#[serde(default, skip_serializing_if = "Vec::is_empty")]
852		pub mapped_accounts: Vec<T::AccountId>,
853
854		/// Account entries (both EOAs and contracts)
855		#[serde(default, skip_serializing_if = "Vec::is_empty")]
856		pub accounts: Vec<genesis::Account<T>>,
857
858		/// Optional debugging settings applied at genesis.
859		#[serde(default, skip_serializing_if = "Option::is_none")]
860		pub debug_settings: Option<DebugSettings>,
861	}
862
863	#[pallet::genesis_build]
864	impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
865		fn build(&self) {
866			use crate::{exec::Key, vm::ContractBlob};
867			use frame_support::traits::fungible::Mutate;
868
869			if !System::<T>::account_exists(&Pallet::<T>::account_id()) {
870				let _ = T::Currency::mint_into(
871					&Pallet::<T>::account_id(),
872					T::Currency::minimum_balance(),
873				);
874			}
875
876			for id in &self.mapped_accounts {
877				if let Err(err) = T::AddressMapper::map_no_deposit_unchecked(id) {
878					log::error!(target: LOG_TARGET, "Failed to map account {id:?}: {err:?}");
879				}
880			}
881
882			let owner = Pallet::<T>::account_id();
883
884			for genesis::Account { address, balance, nonce, contract_data } in &self.accounts {
885				let account_id = T::AddressMapper::to_account_id(address);
886
887				if !System::<T>::account_exists(&account_id) {
888					let _ = T::Currency::mint_into(&account_id, T::Currency::minimum_balance());
889				}
890
891				frame_system::Account::<T>::mutate(&account_id, |info| {
892					info.nonce = (*nonce).into();
893				});
894
895				match contract_data {
896					None => {
897						AccountInfoOf::<T>::insert(
898							address,
899							AccountInfo { account_type: AccountType::EOA, dust: 0 },
900						);
901					},
902					Some(genesis::ContractData { code, storage }) => {
903						let blob = if code.0.starts_with(&polkavm_common::program::BLOB_MAGIC) {
904							ContractBlob::<T>::from_pvm_code(code.0.clone(), owner.clone())
905								.inspect_err(|err| {
906									log::error!(target: LOG_TARGET, "Failed to create PVM ContractBlob for {address:?}: {err:?}");
907								})
908						} else {
909							ContractBlob::<T>::from_evm_runtime_code(code.0.clone(), account_id)
910								.inspect_err(|err| {
911									log::error!(target: LOG_TARGET, "Failed to create EVM ContractBlob for {address:?}: {err:?}");
912								})
913						};
914
915						let Ok(blob) = blob else {
916							continue;
917						};
918
919						let code_hash = *blob.code_hash();
920						let Ok(info) = <ContractInfo<T>>::new(&address, 0u32.into(), code_hash)
921							.inspect_err(|err| {
922								log::error!(target: LOG_TARGET, "Failed to create ContractInfo for {address:?}: {err:?}");
923							})
924						else {
925							continue;
926						};
927
928						AccountInfoOf::<T>::insert(
929							address,
930							AccountInfo { account_type: info.clone().into(), dust: 0 },
931						);
932
933						<PristineCode<T>>::insert(blob.code_hash(), code.0.clone());
934						<CodeInfoOf<T>>::insert(blob.code_hash(), blob.code_info().clone());
935						for (k, v) in storage {
936							let _ = info.write(&Key::from_fixed(k.0), Some(v.0.to_vec()), None, false).inspect_err(|err| {
937								log::error!(target: LOG_TARGET, "Failed to write genesis storage for {address:?} at key {k:?}: {err:?}");
938							});
939						}
940					},
941				}
942
943				let _ = Pallet::<T>::set_evm_balance(address, *balance).inspect_err(|err| {
944					log::error!(target: LOG_TARGET, "Failed to set EVM balance for {address:?}: {err:?}");
945				});
946			}
947
948			// Build genesis block
949			block_storage::on_finalize_build_eth_block::<T>(
950				// Make sure to use the block number from storage instead of the hardcoded 0.
951				// This enables testing tools like anvil to customise the genesis block number.
952				frame_system::Pallet::<T>::block_number(),
953			);
954
955			// Set debug settings.
956			if let Some(settings) = self.debug_settings.as_ref() {
957				settings.write_to_storage::<T>()
958			}
959		}
960	}
961
962	#[pallet::hooks]
963	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
964		fn on_idle(_block: BlockNumberFor<T>, limit: Weight) -> Weight {
965			let mut meter = WeightMeter::with_limit(limit);
966			ContractInfo::<T>::process_deletion_queue_batch(&mut meter);
967			meter.consumed()
968		}
969
970		fn on_initialize(_n: BlockNumberFor<T>) -> Weight {
971			// Kill related ethereum block storage items.
972			block_storage::on_initialize::<T>();
973
974			// Warm up the pallet account.
975			System::<T>::account_exists(&Pallet::<T>::account_id());
976			// Account for the fixed part of the costs incurred in `on_finalize`.
977			<T as Config>::WeightInfo::on_finalize_block_fixed()
978		}
979
980		fn on_finalize(block_number: BlockNumberFor<T>) {
981			// Build the ethereum block and place it in storage.
982			block_storage::on_finalize_build_eth_block::<T>(block_number);
983		}
984
985		fn integrity_test() {
986			assert!(T::ChainId::get() > 0, "ChainId must be greater than 0");
987
988			assert!(T::GasScale::get() > 0u32.into(), "GasScale must not be 0");
989
990			T::FeeInfo::integrity_test();
991
992			// The memory available in the block building runtime
993			let max_runtime_mem: u64 = T::RuntimeMemory::get().into();
994
995			// We only allow 50% of the runtime memory to be utilized by the contracts call
996			// stack, keeping the rest for other facilities, such as PoV, etc.
997			const TOTAL_MEMORY_DEVIDER: u64 = 2;
998
999			// Validators are configured to be able to use more memory than block builders. This is
1000			// because in addition to `max_runtime_mem` they need to hold additional data in
1001			// memory: PoV in multiple copies (1x encoded + 2x decoded) and all storage which
1002			// includes emitted events. The assumption is that storage/events size
1003			// can be a maximum of half of the validator runtime memory - max_runtime_mem.
1004			let max_block_weight = T::BlockWeights::get()
1005				.get(DispatchClass::Normal)
1006				.max_total
1007				.unwrap_or_else(|| T::BlockWeights::get().max_block);
1008			let max_key_size: u64 =
1009				Key::try_from_var(alloc::vec![0u8; limits::STORAGE_KEY_BYTES as usize])
1010					.expect("Key of maximal size shall be created")
1011					.hash()
1012					.len()
1013					.try_into()
1014					.unwrap();
1015
1016			let max_immutable_key_size: u64 = T::AccountId::max_encoded_len().try_into().unwrap();
1017			let max_immutable_size: u64 = max_block_weight
1018				.checked_div_per_component(&<RuntimeCosts as WeightToken<T>>::weight(
1019					&RuntimeCosts::SetImmutableData(limits::IMMUTABLE_BYTES),
1020				))
1021				.unwrap()
1022				.saturating_mul(
1023					u64::from(limits::IMMUTABLE_BYTES)
1024						.saturating_add(max_immutable_key_size)
1025						.into(),
1026				);
1027
1028			let max_pvf_mem: u64 = T::PVFMemory::get().into();
1029			let storage_size_limit = max_pvf_mem.saturating_sub(max_runtime_mem) / 2;
1030
1031			// We can use storage to store events using the available block ref_time with the
1032			// `deposit_event` host function. The overhead of stored events, which is around 100B,
1033			// is not taken into account to simplify calculations, as it does not change much.
1034			let max_events_size = max_block_weight
1035				.checked_div_per_component(
1036					&(<RuntimeCosts as WeightToken<T>>::weight(&RuntimeCosts::DepositEvent {
1037						num_topic: 0,
1038						len: limits::EVENT_BYTES,
1039					})
1040					.saturating_add(<RuntimeCosts as WeightToken<T>>::weight(
1041						&RuntimeCosts::HostFn,
1042					))),
1043				)
1044				.unwrap()
1045				.saturating_mul(limits::EVENT_BYTES.into());
1046
1047			assert!(
1048				max_events_size <= storage_size_limit,
1049				"Maximal events size {} exceeds the events limit {}",
1050				max_events_size,
1051				storage_size_limit
1052			);
1053
1054			// The incremental block builder uses 3 x maximum entry size for receipts and
1055			// for transactions. Transactions are bounded to `MAX_TRANSACTION_PAYLOAD_SIZE`.
1056			//
1057			// To determine the maximum size of the receipts, we know the following:
1058			// - (I) first receipt is stored into pallet storage and not given to the hasher until
1059			//   finalization.
1060			// - (II) the hasher will not consume more memory than the receipts we are giving it.
1061			// - (III) the hasher is capped by 3 x maximum entry for 3 or more transactions.
1062			//
1063			// # Case 1. One transaction with maximum receipts
1064			//
1065			// The worst case scenario for having one single transaction is for the transaction
1066			// to emit the maximum receipt size (ie `max_events_size`). In this case,
1067			// the maximum storage (and memory) consumed is bounded by `max_events_size` (II). The
1068			// receipt is stored in pallet storage, and loaded from storage in the
1069			// `on_finalize` hook (I).
1070			//
1071			// # Case 2. Two transactions
1072			//
1073			// The sum of the receipt size of both transactions cannot exceed `max_events_size`,
1074			// otherwise one transaction will be reverted. From (II), the bytes utilized
1075			// by the builder are capped to `max_events_size`.
1076			//
1077			// # Case 3. Three or more transactions
1078			//
1079			// Similar to the above case, the sum of all receipt size is bounded to
1080			// `max_events_size`. Therefore, the bytes are capped to `max_events_size`.
1081			//
1082			// On average, a transaction could emit `max_events_size / num_tx`. The would
1083			// consume `max_events_size / num_tx * 3` bytes, which is lower than
1084			// `max_events_size` for more than 3 transactions.
1085			//
1086			// In practice, the builder will consume even lower amounts considering
1087			// it is unlikely for a transaction to utilize all the weight of the block for events.
1088			let max_eth_block_builder_bytes =
1089				block_storage::block_builder_bytes_usage(max_events_size.try_into().unwrap());
1090
1091			log::debug!(
1092				target: LOG_TARGET,
1093				"Integrity check: max_eth_block_builder_bytes={} KB using max_events_size={} KB",
1094				max_eth_block_builder_bytes / 1024,
1095				max_events_size / 1024,
1096			);
1097
1098			// Check that the configured memory limits fit into runtime memory.
1099			//
1100			// Dynamic allocations are not available, yet. Hence they are not taken into
1101			// consideration here.
1102			let memory_left = i128::from(max_runtime_mem)
1103				.saturating_div(TOTAL_MEMORY_DEVIDER.into())
1104				.saturating_sub(limits::MEMORY_REQUIRED.into())
1105				.saturating_sub(max_eth_block_builder_bytes.into());
1106
1107			log::debug!(target: LOG_TARGET, "Integrity check: memory_left={} KB", memory_left / 1024);
1108
1109			assert!(
1110				memory_left >= 0,
1111				"Runtime does not have enough memory for current limits. Additional runtime memory required: {} KB",
1112				memory_left.saturating_mul(TOTAL_MEMORY_DEVIDER.into()).abs() / 1024
1113			);
1114
1115			// We can use storage to store items using the available block ref_time with the
1116			// `set_storage` host function. A revertible cold access is the worst case.
1117			let max_storage_size = max_block_weight
1118				.checked_div_per_component(
1119					&<RuntimeCosts as WeightToken<T>>::weight(&RuntimeCosts::SetStorage {
1120						new_bytes: limits::STORAGE_BYTES,
1121						old_bytes: 0,
1122						kind: StorageAccessKind::Persistent(Warmth::Cold { revertible: true }),
1123					})
1124					.saturating_mul(u64::from(limits::STORAGE_BYTES).saturating_add(max_key_size)),
1125				)
1126				.unwrap()
1127				.saturating_add(max_immutable_size.into())
1128				.saturating_add(max_eth_block_builder_bytes.into());
1129
1130			assert!(
1131				max_storage_size <= storage_size_limit,
1132				"Maximal storage size {} exceeds the storage limit {}",
1133				max_storage_size,
1134				storage_size_limit
1135			);
1136		}
1137	}
1138
1139	#[pallet::call]
1140	impl<T: Config> Pallet<T> {
1141		/// A raw EVM transaction, typically dispatched by an Ethereum JSON-RPC server.
1142		///
1143		/// # Parameters
1144		///
1145		/// * `payload`: The encoded [`crate::evm::TransactionSigned`].
1146		///
1147		/// # Note
1148		///
1149		/// This call cannot be dispatched directly; attempting to do so will result in a failed
1150		/// transaction. It serves as a wrapper for an Ethereum transaction. When submitted, the
1151		/// runtime converts it into a [`sp_runtime::generic::CheckedExtrinsic`] by recovering the
1152		/// signer and validating the transaction.
1153		#[allow(unused_variables)]
1154		#[pallet::call_index(0)]
1155		#[pallet::weight(Weight::MAX)]
1156		pub fn eth_transact(origin: OriginFor<T>, payload: Vec<u8>) -> DispatchResultWithPostInfo {
1157			Err(frame_system::Error::CallFiltered::<T>.into())
1158		}
1159
1160		/// Makes a call to an account, optionally transferring some balance.
1161		///
1162		/// # Parameters
1163		///
1164		/// * `dest`: Address of the contract to call.
1165		/// * `value`: The balance to transfer from the `origin` to `dest`.
1166		/// * `weight_limit`: The weight limit enforced when executing the constructor.
1167		/// * `storage_deposit_limit`: The maximum amount of balance that can be charged from the
1168		///   caller to pay for the storage consumed.
1169		/// * `data`: The input data to pass to the contract.
1170		///
1171		/// * If the account is a smart-contract account, the associated code will be
1172		/// executed and any value will be transferred.
1173		/// * If the account is a regular account, any value will be transferred.
1174		/// * If no account exists and the call value is not less than `existential_deposit`,
1175		/// a regular account will be created and any value will be transferred.
1176		#[pallet::call_index(1)]
1177		#[pallet::weight(<T as Config>::WeightInfo::call().saturating_add(*weight_limit))]
1178		pub fn call(
1179			origin: OriginFor<T>,
1180			dest: H160,
1181			#[pallet::compact] value: BalanceOf<T>,
1182			weight_limit: Weight,
1183			#[pallet::compact] storage_deposit_limit: BalanceOf<T>,
1184			data: Vec<u8>,
1185		) -> DispatchResultWithPostInfo {
1186			Self::ensure_non_contract_if_signed(&origin)?;
1187			let mut output = Self::bare_call(
1188				origin,
1189				dest,
1190				Pallet::<T>::convert_native_to_evm(value),
1191				TransactionLimits::WeightAndDeposit {
1192					weight_limit,
1193					deposit_limit: storage_deposit_limit,
1194				},
1195				data,
1196				&ExecConfig::new_substrate_tx(),
1197			);
1198
1199			if let Ok(return_value) = &output.result &&
1200				return_value.did_revert()
1201			{
1202				output.result = Err(<Error<T>>::ContractReverted.into());
1203			}
1204			dispatch_result(
1205				output.result,
1206				output.weight_consumed,
1207				<T as Config>::WeightInfo::call(),
1208			)
1209		}
1210
1211		/// Instantiates a contract from a previously deployed vm binary.
1212		///
1213		/// This function is identical to [`Self::instantiate_with_code`] but without the
1214		/// code deployment step. Instead, the `code_hash` of an on-chain deployed vm binary
1215		/// must be supplied.
1216		#[pallet::call_index(2)]
1217		#[pallet::weight(
1218			<T as Config>::WeightInfo::instantiate(data.len() as u32).saturating_add(*weight_limit)
1219		)]
1220		pub fn instantiate(
1221			origin: OriginFor<T>,
1222			#[pallet::compact] value: BalanceOf<T>,
1223			weight_limit: Weight,
1224			#[pallet::compact] storage_deposit_limit: BalanceOf<T>,
1225			code_hash: sp_core::H256,
1226			data: Vec<u8>,
1227			salt: Option<[u8; 32]>,
1228		) -> DispatchResultWithPostInfo {
1229			Self::ensure_non_contract_if_signed(&origin)?;
1230			let data_len = data.len() as u32;
1231			let mut output = Self::bare_instantiate(
1232				origin,
1233				Pallet::<T>::convert_native_to_evm(value),
1234				TransactionLimits::WeightAndDeposit {
1235					weight_limit,
1236					deposit_limit: storage_deposit_limit,
1237				},
1238				Code::Existing(code_hash),
1239				data,
1240				salt,
1241				&ExecConfig::new_substrate_tx(),
1242			);
1243			if let Ok(retval) = &output.result &&
1244				retval.result.did_revert()
1245			{
1246				output.result = Err(<Error<T>>::ContractReverted.into());
1247			}
1248			dispatch_result(
1249				output.result.map(|result| result.result),
1250				output.weight_consumed,
1251				<T as Config>::WeightInfo::instantiate(data_len),
1252			)
1253		}
1254
1255		/// Instantiates a new contract from the supplied `code` optionally transferring
1256		/// some balance.
1257		///
1258		/// This dispatchable has the same effect as calling [`Self::upload_code`] +
1259		/// [`Self::instantiate`]. Bundling them together provides efficiency gains. Please
1260		/// also check the documentation of [`Self::upload_code`].
1261		///
1262		/// # Parameters
1263		///
1264		/// * `value`: The balance to transfer from the `origin` to the newly created contract.
1265		/// * `weight_limit`: The weight limit enforced when executing the constructor.
1266		/// * `storage_deposit_limit`: The maximum amount of balance that can be charged/reserved
1267		///   from the caller to pay for the storage consumed.
1268		/// * `code`: The contract code to deploy in raw bytes.
1269		/// * `data`: The input data to pass to the contract constructor.
1270		/// * `salt`: Used for the address derivation. If `Some` is supplied then `CREATE2`
1271		/// 	semantics are used. If `None` then `CRATE1` is used.
1272		///
1273		///
1274		/// Instantiation is executed as follows:
1275		///
1276		/// - The supplied `code` is deployed, and a `code_hash` is created for that code.
1277		/// - If the `code_hash` already exists on the chain the underlying `code` will be shared.
1278		/// - The destination address is computed based on the sender, code_hash and the salt.
1279		/// - The smart-contract account is created at the computed address.
1280		/// - The `value` is transferred to the new account.
1281		/// - The `deploy` function is executed in the context of the newly-created account.
1282		#[pallet::call_index(3)]
1283		#[pallet::weight(
1284			<T as Config>::WeightInfo::instantiate_with_code(code.len() as u32, data.len() as u32)
1285			.saturating_add(*weight_limit)
1286		)]
1287		pub fn instantiate_with_code(
1288			origin: OriginFor<T>,
1289			#[pallet::compact] value: BalanceOf<T>,
1290			weight_limit: Weight,
1291			#[pallet::compact] storage_deposit_limit: BalanceOf<T>,
1292			code: Vec<u8>,
1293			data: Vec<u8>,
1294			salt: Option<[u8; 32]>,
1295		) -> DispatchResultWithPostInfo {
1296			Self::ensure_non_contract_if_signed(&origin)?;
1297			let code_len = code.len() as u32;
1298			let data_len = data.len() as u32;
1299			let mut output = Self::bare_instantiate(
1300				origin,
1301				Pallet::<T>::convert_native_to_evm(value),
1302				TransactionLimits::WeightAndDeposit {
1303					weight_limit,
1304					deposit_limit: storage_deposit_limit,
1305				},
1306				Code::Upload(code),
1307				data,
1308				salt,
1309				&ExecConfig::new_substrate_tx(),
1310			);
1311			if let Ok(retval) = &output.result &&
1312				retval.result.did_revert()
1313			{
1314				output.result = Err(<Error<T>>::ContractReverted.into());
1315			}
1316			dispatch_result(
1317				output.result.map(|result| result.result),
1318				output.weight_consumed,
1319				<T as Config>::WeightInfo::instantiate_with_code(code_len, data_len),
1320			)
1321		}
1322
1323		/// Same as [`Self::instantiate_with_code`], but intended to be dispatched **only**
1324		/// by an EVM transaction through the EVM compatibility layer.
1325		///
1326		/// # Parameters
1327		///
1328		/// * `value`: The balance to transfer from the `origin` to the newly created contract.
1329		/// * `weight_limit`: The gas limit used to derive the transaction weight for transaction
1330		///   payment
1331		/// * `eth_gas_limit`: The Ethereum gas limit governing the resource usage of the execution
1332		/// * `code`: The contract code to deploy in raw bytes.
1333		/// * `data`: The input data to pass to the contract constructor.
1334		/// * `transaction_encoded`: The RLP encoding of the signed Ethereum transaction,
1335		///   represented as [crate::evm::TransactionSigned], provided by the Ethereum wallet. This
1336		///   is used for building the Ethereum transaction root.
1337		/// * `effective_gas_price`: the price of a unit of gas
1338		/// * `encoded_len`: the byte code size of the `eth_transact` extrinsic
1339		///
1340		/// Calling this dispatchable ensures that the origin's nonce is bumped only once,
1341		/// via the `CheckNonce` transaction extension. In contrast, [`Self::instantiate_with_code`]
1342		/// also bumps the nonce after contract instantiation, since it may be invoked multiple
1343		/// times within a batch call transaction.
1344		#[pallet::call_index(10)]
1345		#[pallet::weight(
1346			<T as Config>::WeightInfo::eth_instantiate_with_code(code.len() as u32, data.len() as u32, Pallet::<T>::has_dust(*value).into())
1347			.saturating_add(*weight_limit)
1348			.saturating_add(T::WeightInfo::on_finalize_block_per_tx(transaction_encoded.len() as u32))
1349		)]
1350		pub fn eth_instantiate_with_code(
1351			origin: OriginFor<T>,
1352			value: U256,
1353			weight_limit: Weight,
1354			eth_gas_limit: U256,
1355			code: Vec<u8>,
1356			data: Vec<u8>,
1357			transaction_encoded: Vec<u8>,
1358			effective_gas_price: U256,
1359			encoded_len: u32,
1360		) -> DispatchResultWithPostInfo {
1361			let signer = Self::ensure_eth_signed(origin)?;
1362			let origin = OriginFor::<T>::signed(signer.clone());
1363			Self::ensure_non_contract_if_signed(&origin)?;
1364			let mut call = Call::<T>::eth_instantiate_with_code {
1365				value,
1366				weight_limit,
1367				eth_gas_limit,
1368				code: code.clone(),
1369				data: data.clone(),
1370				transaction_encoded: transaction_encoded.clone(),
1371				effective_gas_price,
1372				encoded_len,
1373			}
1374			.into();
1375			let info = T::FeeInfo::dispatch_info(&call);
1376			let base_info = T::FeeInfo::base_dispatch_info(&mut call);
1377			drop(call);
1378
1379			block_storage::with_ethereum_context::<T>(transaction_encoded, || {
1380				let extra_weight = base_info.total_weight();
1381				let output = Self::bare_instantiate(
1382					origin,
1383					value,
1384					TransactionLimits::EthereumGas {
1385						eth_gas_limit: eth_gas_limit.saturated_into(),
1386						weight_limit,
1387						eth_tx_info: EthTxInfo::new(encoded_len, extra_weight),
1388						authorization_deposit: Default::default(),
1389					},
1390					Code::Upload(code),
1391					data,
1392					None,
1393					&ExecConfig::new_eth_tx(effective_gas_price, encoded_len, extra_weight),
1394				);
1395
1396				block_storage::EthereumCallResult::new::<T>(
1397					signer,
1398					output.map_result(|r| r.result),
1399					base_info.call_weight,
1400					encoded_len,
1401					&info,
1402					effective_gas_price,
1403				)
1404			})
1405		}
1406
1407		/// Same as [`Self::call`], but intended to be dispatched **only**
1408		/// by an EVM transaction through the EVM compatibility layer.
1409		///
1410		/// # Parameters
1411		///
1412		/// * `dest`: The Ethereum address of the account to be called
1413		/// * `value`: The balance to transfer from the `origin` to the newly created contract.
1414		/// * `weight_limit`: The gas limit used to derive the transaction weight for transaction
1415		///   payment
1416		/// * `eth_gas_limit`: The Ethereum gas limit governing the resource usage of the execution
1417		/// * `data`: The input data to pass to the contract constructor.
1418		/// * `transaction_encoded`: The RLP encoding of the signed Ethereum transaction,
1419		///   represented as [crate::evm::TransactionSigned], provided by the Ethereum wallet. This
1420		///   is used for building the Ethereum transaction root.
1421		/// * `effective_gas_price`: the price of a unit of gas
1422		/// * `encoded_len`: the byte code size of the `eth_transact` extrinsic
1423		/// * `authorization_list`: EIP-7702 authorization tuples to process before execution
1424		#[pallet::call_index(11)]
1425		#[pallet::weight(
1426			T::WeightInfo::eth_call(Pallet::<T>::has_dust(*value).into())
1427			.saturating_add(*weight_limit)
1428			.saturating_add(T::WeightInfo::on_finalize_block_per_tx(transaction_encoded.len() as u32))
1429			.saturating_add(evm::eip7702::worst_case_authorization_weight::<T>(authorization_list.len() as u32))
1430		)]
1431		pub fn eth_call(
1432			origin: OriginFor<T>,
1433			dest: H160,
1434			value: U256,
1435			weight_limit: Weight,
1436			eth_gas_limit: U256,
1437			data: Vec<u8>,
1438			transaction_encoded: Vec<u8>,
1439			effective_gas_price: U256,
1440			encoded_len: u32,
1441			authorization_list: Vec<evm::AuthorizationListEntry>,
1442		) -> DispatchResultWithPostInfo {
1443			let signer = Self::ensure_eth_signed(origin)?;
1444			let origin = OriginFor::<T>::signed(signer.clone());
1445
1446			Self::ensure_non_contract_if_signed(&origin)?;
1447			let mut call = Call::<T>::eth_call {
1448				dest,
1449				value,
1450				weight_limit,
1451				eth_gas_limit,
1452				data: data.clone(),
1453				transaction_encoded: transaction_encoded.clone(),
1454				effective_gas_price,
1455				encoded_len,
1456				authorization_list: authorization_list.clone(),
1457			}
1458			.into();
1459			let info = T::FeeInfo::dispatch_info(&call);
1460			let base_info = T::FeeInfo::base_dispatch_info(&mut call);
1461			drop(call);
1462
1463			let exec_config =
1464				ExecConfig::new_eth_tx(effective_gas_price, encoded_len, base_info.total_weight());
1465			let auth_result = evm::eip7702::process_authorizations::<T>(
1466				&authorization_list,
1467				&signer,
1468				&exec_config,
1469			);
1470			let extra_weight = base_info.total_weight().saturating_sub(auth_result.weight_refund);
1471			let base_call_weight = base_info.call_weight.saturating_sub(auth_result.weight_refund);
1472
1473			block_storage::with_ethereum_context::<T>(transaction_encoded, || {
1474				let output = Self::bare_call(
1475					origin,
1476					dest,
1477					value,
1478					TransactionLimits::EthereumGas {
1479						eth_gas_limit: eth_gas_limit.saturated_into(),
1480						weight_limit,
1481						eth_tx_info: EthTxInfo::new(encoded_len, extra_weight),
1482						authorization_deposit: auth_result.deposit,
1483					},
1484					data,
1485					&ExecConfig::new_eth_tx(effective_gas_price, encoded_len, extra_weight),
1486				);
1487
1488				block_storage::EthereumCallResult::new::<T>(
1489					signer,
1490					output,
1491					base_call_weight,
1492					encoded_len,
1493					&info,
1494					effective_gas_price,
1495				)
1496			})
1497		}
1498
1499		/// Executes a Substrate runtime call from an Ethereum transaction.
1500		///
1501		/// This dispatchable is intended to be called **only** through the EVM compatibility
1502		/// layer. The provided call will be dispatched using `RawOrigin::Signed`.
1503		///
1504		/// # Parameters
1505		///
1506		/// * `origin`: Must be an [`Origin::EthTransaction`] origin.
1507		/// * `call`: The Substrate runtime call to execute.
1508		/// * `transaction_encoded`: The RLP encoding of the Ethereum transaction,
1509		#[pallet::call_index(12)]
1510		#[pallet::weight(
1511			T::WeightInfo::eth_substrate_call(transaction_encoded.len() as u32)
1512			.saturating_add(call.get_dispatch_info().call_weight)
1513			.saturating_add(T::WeightInfo::on_finalize_block_per_tx(transaction_encoded.len() as u32))
1514		)]
1515		pub fn eth_substrate_call(
1516			origin: OriginFor<T>,
1517			call: Box<<T as Config>::RuntimeCall>,
1518			transaction_encoded: Vec<u8>,
1519		) -> DispatchResultWithPostInfo {
1520			// Note that the inner dispatch uses `RawOrigin::Signed`, which cannot
1521			// re-enter `eth_substrate_call` (which requires `Origin::EthTransaction`).
1522			let signer = Self::ensure_eth_signed(origin)?;
1523			Self::ensure_non_contract_if_signed(&OriginFor::<T>::signed(signer.clone()))?;
1524			let tx_len = transaction_encoded.len() as u32;
1525			let weight_overhead = T::WeightInfo::eth_substrate_call(tx_len)
1526				.saturating_add(T::WeightInfo::on_finalize_block_per_tx(tx_len));
1527
1528			block_storage::with_ethereum_context::<T>(transaction_encoded, || {
1529				let call_weight = call.get_dispatch_info().call_weight;
1530				let mut call_result = call.dispatch(RawOrigin::Signed(signer).into());
1531
1532				// Add extrinsic_overhead to the actual weight in PostDispatchInfo
1533				match &mut call_result {
1534					Ok(post_info) | Err(DispatchErrorWithPostInfo { post_info, .. }) => {
1535						post_info.actual_weight = Some(
1536							post_info
1537								.actual_weight
1538								.unwrap_or_else(|| call_weight)
1539								.saturating_add(weight_overhead),
1540						);
1541					},
1542				}
1543
1544				// Return zero EVM gas (Substrate dispatch, not EVM contract call).
1545				// Actual weight is in `post_info.actual_weight`.
1546				block_storage::EthereumCallResult {
1547					receipt_gas_info: ReceiptGasInfo::default(),
1548					result: call_result,
1549				}
1550			})
1551		}
1552
1553		/// Upload new `code` without instantiating a contract from it.
1554		///
1555		/// If the code does not already exist a deposit is reserved from the caller
1556		/// The size of the reserve depends on the size of the supplied `code`.
1557		///
1558		/// # Note
1559		///
1560		/// Anyone can instantiate a contract from any uploaded code and thus prevent its removal.
1561		/// To avoid this situation a constructor could employ access control so that it can
1562		/// only be instantiated by permissioned entities. The same is true when uploading
1563		/// through [`Self::instantiate_with_code`].
1564		///
1565		/// If the refcount of the code reaches zero after terminating the last contract that
1566		/// references this code, the code will be removed automatically.
1567		#[pallet::call_index(4)]
1568		#[pallet::weight(<T as Config>::WeightInfo::upload_code(code.len() as u32))]
1569		pub fn upload_code(
1570			origin: OriginFor<T>,
1571			code: Vec<u8>,
1572			#[pallet::compact] storage_deposit_limit: BalanceOf<T>,
1573		) -> DispatchResult {
1574			Self::ensure_non_contract_if_signed(&origin)?;
1575			Self::bare_upload_code(origin, code, storage_deposit_limit).map(|_| ())
1576		}
1577
1578		/// Remove the code stored under `code_hash` and refund the deposit to its owner.
1579		///
1580		/// A code can only be removed by its original uploader (its owner) and only if it is
1581		/// not used by any contract.
1582		#[pallet::call_index(5)]
1583		#[pallet::weight(<T as Config>::WeightInfo::remove_code())]
1584		pub fn remove_code(
1585			origin: OriginFor<T>,
1586			code_hash: sp_core::H256,
1587		) -> DispatchResultWithPostInfo {
1588			let origin = ensure_signed(origin)?;
1589			<ContractBlob<T>>::remove(&origin, code_hash)?;
1590			// we waive the fee because removing unused code is beneficial
1591			Ok(Pays::No.into())
1592		}
1593
1594		/// Privileged function that changes the code of an existing contract.
1595		///
1596		/// This takes care of updating refcounts and all other necessary operations. Returns
1597		/// an error if either the `code_hash` or `dest` do not exist.
1598		///
1599		/// # Note
1600		///
1601		/// This does **not** change the address of the contract in question. This means
1602		/// that the contract address is no longer derived from its code hash after calling
1603		/// this dispatchable.
1604		#[pallet::call_index(6)]
1605		#[pallet::weight(<T as Config>::WeightInfo::set_code())]
1606		pub fn set_code(
1607			origin: OriginFor<T>,
1608			dest: H160,
1609			code_hash: sp_core::H256,
1610		) -> DispatchResult {
1611			ensure_root(origin)?;
1612			<AccountInfoOf<T>>::try_mutate(&dest, |account| {
1613				let Some(account) = account else {
1614					return Err(<Error<T>>::ContractNotFound.into());
1615				};
1616
1617				let AccountType::Contract(ref mut contract) = account.account_type else {
1618					return Err(<Error<T>>::ContractNotFound.into());
1619				};
1620
1621				<CodeInfo<T>>::increment_refcount(code_hash)?;
1622				let _ = <CodeInfo<T>>::decrement_refcount(contract.code_hash)?;
1623				contract.code_hash = code_hash;
1624
1625				Ok(())
1626			})
1627		}
1628
1629		/// Register the callers account id so that it can be used in contract interactions.
1630		///
1631		/// This will error if the origin is already mapped or is a eth native `Address20`. It will
1632		/// take a deposit that can be released by calling [`Self::unmap_account`].
1633		///
1634		/// Noop when [`Config::AutoMap`] is enabled, as accounts are automatically mapped
1635		/// on creation via [`AutoMapper`].
1636		#[pallet::call_index(7)]
1637		#[pallet::weight(<T as Config>::WeightInfo::map_account())]
1638		pub fn map_account(origin: OriginFor<T>) -> DispatchResult {
1639			#[cfg(not(feature = "runtime-benchmarks"))]
1640			if T::AutoMap::get() {
1641				return Ok(());
1642			}
1643
1644			Self::ensure_non_contract_if_signed(&origin)?;
1645			let origin = ensure_signed(origin)?;
1646			T::AddressMapper::map(&origin)
1647		}
1648
1649		/// Map many accounts and make the TX free if at least 90% were unmapped or held deposits.
1650		#[pallet::call_index(13)]
1651		#[pallet::weight(<T as Config>::WeightInfo::batch_map_accounts(accounts.len().saturated_into::<u32>()))]
1652		pub fn batch_map_accounts(
1653			origin: OriginFor<T>,
1654			accounts: Vec<T::AccountId>,
1655		) -> DispatchResultWithPostInfo {
1656			ensure_signed(origin.clone())?;
1657			Self::ensure_non_contract_if_signed(&origin)?;
1658
1659			let total: u32 = accounts.len().saturated_into();
1660			let mut mapped = 0;
1661
1662			for account_id in accounts
1663				.iter()
1664				// Eth-derived accounts are stateless mapped, nothing to do.
1665				.filter(|&a| !T::AddressMapper::is_eth_derived(a))
1666				// Skip non-existent accounts: otherwise any caller could permanently
1667				// insert mappings for arbitrary AccountIds at no cost.
1668				.filter(|&a| frame_system::Pallet::<T>::account_exists(a))
1669			{
1670				let mut useful = false;
1671
1672				match T::AddressMapper::map_no_deposit_unchecked(account_id) {
1673					Ok(()) => {
1674						useful = true;
1675					},
1676					Err(err) => log::debug!(
1677						target: LOG_TARGET,
1678						"Failed to map account {account_id:?}: {err:?}",
1679					),
1680				}
1681
1682				match T::Currency::release_all(
1683					&HoldReason::AddressMapping.into(),
1684					account_id,
1685					Precision::BestEffort,
1686				) {
1687					// `release_all` returns `Ok(0)` when there is no hold to release,
1688					// which is not useful work and must not earn a fee refund.
1689					Ok(released) if !released.is_zero() => {
1690						useful = true;
1691					},
1692					Ok(_) => {},
1693					Err(err) => log::debug!(
1694						target: LOG_TARGET,
1695						"Failed to release mapping deposit for {account_id:?}: {err:?}",
1696					),
1697				}
1698
1699				if useful {
1700					mapped = mapped.saturating_add(1);
1701				}
1702			}
1703
1704			// guard against 0 division below
1705			if total == 0 || mapped == 0 {
1706				return Ok(Pays::Yes.into());
1707			}
1708
1709			let proportion_mapped = Perbill::from_rational(mapped, total);
1710			if proportion_mapped >= Perbill::from_percent(90) {
1711				Ok(Pays::No.into())
1712			} else {
1713				Ok(Pays::Yes.into())
1714			}
1715		}
1716
1717		/// Unregister the callers account id in order to free the deposit.
1718		///
1719		/// There is no reason to ever call this function other than freeing up the deposit.
1720		/// This is only useful when the account should no longer be used.
1721		///
1722		/// Disabled when [`Config::AutoMap`] is enabled, as accounts are automatically unmapped
1723		/// on kill via [`AutoMapper`].
1724		#[pallet::call_index(8)]
1725		#[pallet::weight(<T as Config>::WeightInfo::unmap_account())]
1726		pub fn unmap_account(origin: OriginFor<T>) -> DispatchResult {
1727			#[cfg(not(feature = "runtime-benchmarks"))]
1728			ensure!(!T::AutoMap::get(), <Error<T>>::AutoMappingEnabled);
1729			let origin = ensure_signed(origin)?;
1730			T::AddressMapper::unmap(&origin)
1731		}
1732
1733		/// Dispatch an `call` with the origin set to the callers fallback address.
1734		///
1735		/// Every `AccountId32` can control its corresponding fallback account. The fallback account
1736		/// is the `AccountId20` with the last 12 bytes set to `0xEE`. This is essentially a
1737		/// recovery function in case an `AccountId20` was used without creating a mapping first.
1738		#[pallet::call_index(9)]
1739		#[pallet::weight({
1740			let dispatch_info = call.get_dispatch_info();
1741			(
1742				<T as Config>::WeightInfo::dispatch_as_fallback_account().saturating_add(dispatch_info.call_weight),
1743				dispatch_info.class
1744			)
1745		})]
1746		pub fn dispatch_as_fallback_account(
1747			mut origin: OriginFor<T>,
1748			call: Box<<T as Config>::RuntimeCall>,
1749		) -> DispatchResultWithPostInfo {
1750			Self::ensure_non_contract_if_signed(&origin)?;
1751			let account_id = origin.as_signer().ok_or(DispatchError::BadOrigin)?;
1752			let unmapped_account = T::AddressMapper::to_fallback_account_id(
1753				&T::AddressMapper::to_address(&account_id),
1754			);
1755			origin.set_caller_from(RawOrigin::Signed(unmapped_account));
1756			call.dispatch(origin)
1757		}
1758	}
1759}
1760
1761/// Create a dispatch result reflecting the amount of consumed weight.
1762fn dispatch_result<R>(
1763	result: Result<R, DispatchError>,
1764	weight_consumed: Weight,
1765	base_weight: Weight,
1766) -> DispatchResultWithPostInfo {
1767	let post_info = PostDispatchInfo {
1768		actual_weight: Some(weight_consumed.saturating_add(base_weight)),
1769		pays_fee: Default::default(),
1770	};
1771
1772	result
1773		.map(|_| post_info)
1774		.map_err(|e| DispatchErrorWithPostInfo { post_info, error: e })
1775}
1776
1777impl<T: Config> Pallet<T> {
1778	/// A generalized version of [`Self::call`].
1779	///
1780	/// Identical to [`Self::call`] but tailored towards being called by other code within the
1781	/// runtime as opposed to from an extrinsic. It returns more information and allows the
1782	/// enablement of features that are not suitable for an extrinsic (debugging, event
1783	/// collection).
1784	pub fn bare_call(
1785		origin: OriginFor<T>,
1786		dest: H160,
1787		evm_value: U256,
1788		transaction_limits: TransactionLimits<T>,
1789		data: Vec<u8>,
1790		exec_config: &ExecConfig<T>,
1791	) -> ContractResult<ExecReturnValue, BalanceOf<T>> {
1792		let mut transaction_meter = match TransactionMeter::new(transaction_limits) {
1793			Ok(transaction_meter) => transaction_meter,
1794			Err(error) => return ContractResult { result: Err(error), ..Default::default() },
1795		};
1796		let mut storage_deposit = Default::default();
1797
1798		let try_call = || {
1799			let origin = ExecOrigin::from_runtime_origin(origin)?;
1800			let result = ExecStack::<T, ContractBlob<T>>::run_call(
1801				origin.clone(),
1802				dest,
1803				&mut transaction_meter,
1804				evm_value,
1805				data,
1806				&exec_config,
1807			)?;
1808
1809			storage_deposit = transaction_meter
1810				.execute_postponed_deposits(&origin, &exec_config)
1811				.inspect_err(|err| {
1812				log::debug!(target: LOG_TARGET, "Failed to transfer deposit: {err:?}");
1813			})?;
1814
1815			Ok(result)
1816		};
1817		let result = Self::run_guarded(try_call);
1818
1819		log::trace!(target: LOG_TARGET, "Bare call ends: \
1820			result={result:?}, \
1821			weight_consumed={:?}, \
1822			weight_required={:?}, \
1823			storage_deposit={:?}, \
1824			gas_consumed={:?}, \
1825			max_storage_deposit={:?}",
1826			transaction_meter.weight_consumed(),
1827			transaction_meter.weight_required(),
1828			storage_deposit,
1829			transaction_meter.total_consumed_gas(),
1830			transaction_meter.deposit_required()
1831		);
1832
1833		ContractResult {
1834			result: result.map_err(|r| r.error),
1835			weight_consumed: transaction_meter.weight_consumed(),
1836			weight_required: transaction_meter.weight_required(),
1837			storage_deposit,
1838			gas_consumed: transaction_meter.total_consumed_gas(),
1839			max_storage_deposit: transaction_meter.deposit_required(),
1840		}
1841	}
1842
1843	/// Prepare a dry run for the given account.
1844	///
1845	///
1846	/// This function is public because it is called by the runtime API implementation
1847	/// (see `impl_runtime_apis_plus_revive`).
1848	pub fn prepare_dry_run(account: &T::AccountId) {
1849		// Bump the  nonce to simulate what would happen
1850		// `pre-dispatch` if the transaction was executed.
1851		frame_system::Pallet::<T>::inc_account_nonce(account);
1852
1853		// Map the account if it is not mapped already so we don't hit
1854		// `AccountUnmapped` from the origin when dry-running.
1855		if !T::AddressMapper::is_mapped(account) {
1856			let _ = T::AddressMapper::map_no_deposit_unchecked(account);
1857		}
1858	}
1859
1860	/// A generalized version of [`Self::instantiate`] or [`Self::instantiate_with_code`].
1861	///
1862	/// Identical to [`Self::instantiate`] or [`Self::instantiate_with_code`] but tailored towards
1863	/// being called by other code within the runtime as opposed to from an extrinsic. It returns
1864	/// more information to the caller useful to estimate the cost of the operation.
1865	pub fn bare_instantiate(
1866		origin: OriginFor<T>,
1867		evm_value: U256,
1868		transaction_limits: TransactionLimits<T>,
1869		code: Code,
1870		data: Vec<u8>,
1871		salt: Option<[u8; 32]>,
1872		exec_config: &ExecConfig<T>,
1873	) -> ContractResult<InstantiateReturnValue, BalanceOf<T>> {
1874		let mut transaction_meter = match TransactionMeter::new(transaction_limits) {
1875			Ok(transaction_meter) => transaction_meter,
1876			Err(error) => return ContractResult { result: Err(error), ..Default::default() },
1877		};
1878
1879		let mut storage_deposit = Default::default();
1880
1881		let try_instantiate = || {
1882			let instantiate_account = T::InstantiateOrigin::ensure_origin(origin.clone())?;
1883
1884			if_tracing(|t| t.instantiate_code(&code, salt.as_ref()));
1885			let executable = match code {
1886				Code::Upload(code) if code.starts_with(&polkavm_common::program::BLOB_MAGIC) => {
1887					let upload_account = T::UploadOrigin::ensure_origin(origin)?;
1888					let executable = Self::try_upload_code(
1889						upload_account,
1890						code,
1891						BytecodeType::Pvm,
1892						&mut transaction_meter,
1893						&exec_config,
1894					)?;
1895					executable
1896				},
1897				Code::Upload(code) => {
1898					if T::AllowEVMBytecode::get() {
1899						ensure!(data.is_empty(), <Error<T>>::EvmConstructorNonEmptyData);
1900						let origin = T::UploadOrigin::ensure_origin(origin)?;
1901						let executable = ContractBlob::from_evm_init_code(code, origin)?;
1902						executable
1903					} else {
1904						return Err(<Error<T>>::CodeRejected.into());
1905					}
1906				},
1907				Code::Existing(code_hash) => {
1908					let executable = ContractBlob::from_storage(code_hash, &mut transaction_meter)?;
1909					ensure!(executable.code_info().is_pvm(), <Error<T>>::EvmConstructedFromHash);
1910					executable
1911				},
1912			};
1913			let instantiate_origin = ExecOrigin::from_account_id(instantiate_account.clone());
1914			let result = ExecStack::<T, ContractBlob<T>>::run_instantiate(
1915				instantiate_account,
1916				executable,
1917				&mut transaction_meter,
1918				evm_value,
1919				data,
1920				salt.as_ref(),
1921				&exec_config,
1922			);
1923
1924			storage_deposit = transaction_meter
1925				.execute_postponed_deposits(&instantiate_origin, &exec_config)
1926				.inspect_err(|err| {
1927					log::debug!(target: LOG_TARGET, "Failed to transfer deposit: {err:?}");
1928				})?;
1929			result
1930		};
1931		let output = Self::run_guarded(try_instantiate);
1932
1933		log::trace!(target: LOG_TARGET, "Bare instantiate ends: weight_consumed={:?}\
1934			weight_required={:?} \
1935			storage_deposit={:?} \
1936			gas_consumed={:?} \
1937			max_storage_deposit={:?}",
1938			transaction_meter.weight_consumed(),
1939			transaction_meter.weight_required(),
1940			storage_deposit,
1941			transaction_meter.total_consumed_gas(),
1942			transaction_meter.deposit_required()
1943		);
1944
1945		ContractResult {
1946			result: output
1947				.map(|(addr, result)| InstantiateReturnValue { result, addr })
1948				.map_err(|e| e.error),
1949			weight_consumed: transaction_meter.weight_consumed(),
1950			weight_required: transaction_meter.weight_required(),
1951			storage_deposit,
1952			gas_consumed: transaction_meter.total_consumed_gas(),
1953			max_storage_deposit: transaction_meter.deposit_required(),
1954		}
1955	}
1956
1957	/// Estimates the amount of gas that a transactions requires.
1958	///
1959	/// This function estimates the gas of the transaction according to the same binary search
1960	/// algorithm that's implemented in Geth. It stops when with an acceptable error ratio of
1961	/// 1.5% so that the algorithm terminates early.
1962	///
1963	/// # Note
1964	///
1965	/// All calls to [`Self::dry_run_eth_transact`] need to happen inside of a [`with_transaction`]
1966	/// with state rollback to ensure that dry runs subsequent to the first one preserve the correct
1967	/// amount of storage deposits needed without any kind of caching from the previous dry runs.
1968	pub fn eth_estimate_gas(
1969		tx: GenericTransaction,
1970		timestamp_override: Option<MomentOf<T>>,
1971		state_overrides: Option<StateOverrideSet>,
1972	) -> Result<U256, EthTransactError>
1973	where
1974		T::Nonce: Into<U256> + TryFrom<U256>,
1975		CallOf<T>: SetWeightLimit,
1976	{
1977		log::debug!(target: LOG_TARGET, "eth_estimate_gas: {tx:?}");
1978
1979		let mut low = U256::zero();
1980		let mut high = Self::evm_block_gas_limit();
1981
1982		log::trace!(target: LOG_TARGET, "eth_estimate_gas starting with low={low}, high={high}");
1983
1984		// If the user has specified a gas limit then this is the limit we use as the high bound for
1985		// the binary search. Also, if the user didn't specify a gas limit then we need to skip the
1986		// balance checks.
1987		let perform_balance_checks = if let Some(gas_limit) = tx.gas {
1988			high = gas_limit;
1989			log::trace!(target: LOG_TARGET, "eth_estimate_gas high limited by the gas limit high={high}");
1990			true
1991		} else {
1992			false
1993		};
1994
1995		// Cap the high bound of the binary search based on the account's balance if it can be done.
1996		let fee_cap = tx.max_fee_per_gas.or(tx.gas_price);
1997		if let (Some(fee_cap), Some(from), true) = (fee_cap, tx.from, perform_balance_checks) {
1998			let mut available_balance = Self::evm_balance(&from);
1999			if let Some(value) = tx.value {
2000				available_balance = available_balance.checked_sub(value).ok_or_else(|| {
2001					EthTransactError::Message("insufficient funds for value transfer".into())
2002				})?;
2003			}
2004			if let Some(allowance) = available_balance.checked_div(fee_cap) {
2005				if high > allowance && allowance != U256::zero() {
2006					log::trace!(target: LOG_TARGET, "eth_estimate_gas high limited by the user's allowance high={high} allowance={allowance}");
2007					high = allowance
2008				}
2009			}
2010		}
2011
2012		// Run one gas probe in a rolled-back transaction. Overrides are passed along so that
2013		// `dry_run_eth_transact` applies them *after* `prepare_dry_run` bumps the nonce, keeping a
2014		// nonce override at the exact value it sets.
2015		let dry_run_at = |gas: U256| {
2016			let mut transaction = tx.clone();
2017			transaction.gas = Some(gas);
2018			with_transaction(|| {
2019				TransactionOutcome::Rollback(Ok::<_, DispatchError>(Self::dry_run_eth_transact(
2020					transaction,
2021					timestamp_override,
2022					perform_balance_checks,
2023					state_overrides.clone(),
2024				)))
2025			})
2026			.expect("Rollback shouldn't error out")
2027		};
2028
2029		// Classify against post-override state (a code override can make the destination a
2030		// contract) in a rolled-back probe, so the overrides don't leak into the dry runs.
2031		let is_simple_transfer = with_transaction(|| {
2032			let probe = state_overrides
2033				.clone()
2034				.map_or(Ok(()), state_overrides::apply_state_overrides::<T>)
2035				.map(|()| Self::is_simple_transfer(&tx));
2036			TransactionOutcome::Rollback(Ok::<_, DispatchError>(probe))
2037		})
2038		.expect("Rollback shouldn't error out")?;
2039
2040		if is_simple_transfer {
2041			let dry_run_result = dry_run_at(high)?;
2042			log::trace!(
2043				target: LOG_TARGET,
2044				"eth_estimate_gas short-circuited simple transfer to {:?} with eth_gas={}",
2045				tx.to,
2046				dry_run_result.eth_gas,
2047			);
2048			return Ok(dry_run_result.eth_gas);
2049		}
2050
2051		// Perform the first dry run with the gas limit of the binary search's high bound. If it
2052		// fails then we attempt again with the max extrinsic weight in gas which we do since some
2053		// transactions fail the dry run with the highest gas limit. If both of these fail then we
2054		// return early as it means that the transaction simply can't succeed.
2055		let dry_run_results = [high, Self::evm_max_extrinsic_weight_in_gas()]
2056			.map(|gas_limit| (gas_limit, dry_run_at(gas_limit)));
2057		let (gas_limit, first_dry_run_result) = match dry_run_results {
2058			[(gas_limit1, Ok(dry_run_result1)), (gas_limit2, Ok(dry_run_result2))] => {
2059				if dry_run_result2.eth_gas >= gas_limit2 {
2060					(gas_limit1, dry_run_result1)
2061				} else {
2062					(gas_limit2, dry_run_result2)
2063				}
2064			},
2065			[(gas_limit, Ok(dry_run_result)), (_, Err(_))] |
2066			[(_, Err(_)), (gas_limit, Ok(dry_run_result))] => (gas_limit, dry_run_result),
2067			[(_, Err(err)), (_, Err(..))] => return Err(err),
2068		};
2069		log::trace!(
2070			target: LOG_TARGET,
2071			"eth_estimate_gas first dry run succeeded with gas_limit={} consumed={}",
2072			gas_limit,
2073			first_dry_run_result.eth_gas
2074		);
2075		low = first_dry_run_result.eth_gas;
2076		high = gas_limit;
2077
2078		// TODO: each iteration re-runs `process_authorizations`, which re-recovers every
2079		// authority via `ecdsa_recover`. The recovered addresses are invariant across iterations
2080		// (they're a function of the signatures, not gas) — cache them once outside the loop and
2081		// thread them into `dry_run_eth_transact` to save N * iterations ECDSA recoveries.
2082		while low + U256::one() < high {
2083			log::trace!(target: LOG_TARGET, "eth_estimate_gas estimation iteration with low={low} high={high}");
2084			let error_ratio = high
2085				.checked_sub(low)
2086				.and_then(|value| value.checked_mul(U256::from(1000)))
2087				.and_then(|value| value.checked_div(high))
2088				.ok_or_else(|| {
2089					EthTransactError::Message(
2090						"failed to calculate error ratio in gas estimation".into(),
2091					)
2092				})?;
2093			if error_ratio <= U256::from(15) {
2094				log::trace!(
2095					target: LOG_TARGET,
2096					"eth_estimate_gas finished due to error ratio being less than 1.5% high={}",
2097					high
2098				);
2099				break;
2100			}
2101
2102			let mut midpoint = high
2103				.checked_sub(low)
2104				.and_then(|value| value.checked_div(U256::from(2)))
2105				.and_then(|value| value.checked_add(low))
2106				.ok_or_else(|| {
2107					EthTransactError::Message(
2108						"failed to calculate midpoint in gas estimation".into(),
2109					)
2110				})?;
2111
2112			if let Some(other_midpoint) = low.checked_mul(U256::from(2)) {
2113				if other_midpoint != U256::zero() {
2114					midpoint = midpoint.min(other_midpoint)
2115				}
2116			};
2117
2118			let dry_run_result = dry_run_at(midpoint);
2119			log::trace!(target: LOG_TARGET, "eth_estimate_gas dry run result with midpoint={midpoint} is dry_run_result={dry_run_result:?}");
2120			match dry_run_result {
2121				Ok(..) => {
2122					log::trace!(target: LOG_TARGET, "eth_estimate_gas dry run succeeded, new high={midpoint}");
2123					high = midpoint
2124				},
2125				Err(..) => {
2126					log::trace!(target: LOG_TARGET, "eth_estimate_gas dry run failed, new low={midpoint}");
2127					low = midpoint
2128				},
2129			}
2130		}
2131
2132		log::trace!(target: LOG_TARGET, "eth_estimate_gas completed. high={high}");
2133		Ok(high)
2134	}
2135
2136	/// Returns true when `tx` is a plain value transfer that executes no code at its destination.
2137	pub(crate) fn is_simple_transfer(tx: &GenericTransaction) -> bool {
2138		tx.to
2139			.map(|to| tx.has_simple_transfer_fields() && Self::address_runs_no_code(&to))
2140			.unwrap_or(false)
2141	}
2142
2143	/// Returns true when a value transfer can target `address` without triggering any code
2144	/// execution: it is neither the runtime pallets address, a precompile, a contract, nor an
2145	/// EIP-7702 delegated EOA (a transfer to one executes the delegate's code).
2146	fn address_runs_no_code(address: &H160) -> bool {
2147		*address != RUNTIME_PALLETS_ADDR &&
2148			!exec::is_precompile::<T, ContractBlob<T>>(address) &&
2149			!<AccountInfo<T>>::is_contract(address) &&
2150			!<AccountInfo<T>>::is_delegated(address)
2151	}
2152
2153	/// Return the pre-dispatch weight booked for the signed Ethereum transaction payload.
2154	///
2155	/// This matches the weight contribution that `frame_system::CheckWeight` would add for the
2156	/// transaction on an otherwise empty block:
2157	/// - the revive call's total dispatch weight, including extension weight,
2158	/// - the dispatch class base extrinsic weight,
2159	/// - and the extrinsic-length proof-size charge.
2160	pub fn eth_pre_dispatch_weight(transaction_encoded: Vec<u8>) -> Result<Weight, EthTransactError>
2161	where
2162		CallOf<T>: SetWeightLimit,
2163	{
2164		let signed_tx =
2165			crate::evm::TransactionSigned::decode(&transaction_encoded).map_err(|err| {
2166				EthTransactError::Message(format!("Failed to decode transaction: {err:?}"))
2167			})?;
2168		let signer_addr = signed_tx.recover_eth_address().map_err(|err| {
2169			EthTransactError::Message(format!("Failed to recover signer: {err:?}"))
2170		})?;
2171		let tx =
2172			GenericTransaction::from_signed(signed_tx, Self::evm_base_fee(), Some(signer_addr));
2173		let encoded_len = T::FeeInfo::encoded_len(
2174			crate::Call::<T>::eth_transact { payload: transaction_encoded.clone() }.into(),
2175		);
2176		let call_info = tx
2177			.into_call::<T>(CreateCallMode::ExtrinsicExecution(encoded_len, transaction_encoded))
2178			.map_err(|err| EthTransactError::Message(format!("Invalid call: {err:?}")))?;
2179		let info = T::FeeInfo::dispatch_info(&call_info.call);
2180
2181		Ok(frame_system::calculate_consumed_extrinsic_weight::<CallOf<T>>(
2182			&T::BlockWeights::get(),
2183			&info,
2184			call_info.encoded_len as usize,
2185		))
2186	}
2187
2188	/// Dry-run Ethereum calls.
2189	///
2190	/// # Parameters
2191	///
2192	/// - `tx`: The Ethereum transaction to simulate. Must carry a `from` address when its
2193	///   `authorization_list` is non-empty, since the authorization deposits are charged to it.
2194	/// - `timestamp_override`: An optional timestamp to report to the contract instead of the
2195	///   current one.
2196	/// - `perform_balance_checks`: Whether the origin's balance is checked to cover the fees and
2197	///   the transferred value.
2198	/// - `state_overrides`: Optional state overrides to apply before executing the call.
2199	pub fn dry_run_eth_transact(
2200		mut tx: GenericTransaction,
2201		timestamp_override: Option<MomentOf<T>>,
2202		perform_balance_checks: bool,
2203		state_overrides: Option<StateOverrideSet>,
2204	) -> Result<EthTransactInfo<BalanceOf<T>>, EthTransactError>
2205	where
2206		T::Nonce: Into<U256> + TryFrom<U256>,
2207		CallOf<T>: SetWeightLimit,
2208	{
2209		log::debug!(target: LOG_TARGET, "dry_run_eth_transact: {tx:?}");
2210
2211		// The authorization deposits are charged to `tx.from`. Defaulting a missing `from` to the
2212		// zero address would charge an unfunded account, so every authorization would be rolled
2213		// back post-validation and silently dropped from the estimate.
2214		if !tx.authorization_list.is_empty() && tx.from.is_none() {
2215			return Err(EthTransactError::Message(
2216				"a transaction with an authorization list requires a `from` address: \
2217				 the authorization deposits are charged to it"
2218					.into(),
2219			));
2220		}
2221
2222		let origin = T::AddressMapper::to_account_id(&tx.from.unwrap_or_default());
2223		Self::prepare_dry_run(&origin);
2224
2225		if let Some(overrides) = state_overrides {
2226			state_overrides::apply_state_overrides::<T>(overrides)?;
2227		}
2228
2229		let base_fee = Self::evm_base_fee();
2230		let effective_gas_price = tx.effective_gas_price(base_fee).unwrap_or(base_fee);
2231
2232		if effective_gas_price < base_fee {
2233			Err(EthTransactError::Message(format!(
2234				"Effective gas price {effective_gas_price:?} lower than base fee {base_fee:?}"
2235			)))?;
2236		}
2237
2238		if tx.nonce.is_none() {
2239			tx.nonce = Some(<System<T>>::account_nonce(&origin).into());
2240		}
2241		if tx.chain_id.is_none() {
2242			tx.chain_id = Some(T::ChainId::get().into());
2243		}
2244
2245		// tx.into_call expects tx.gas_price to be the effective gas price
2246		tx.gas_price = Some(effective_gas_price);
2247		// we don't support priority fee for now as the tipping system in pallet-transaction-payment
2248		// works differently and the total tip needs to be known pre dispatch
2249		tx.max_priority_fee_per_gas = Some(0.into());
2250		if tx.max_fee_per_gas.is_none() {
2251			tx.max_fee_per_gas = Some(effective_gas_price);
2252		}
2253
2254		let gas = tx.gas;
2255		if tx.gas.is_none() {
2256			tx.gas = Some(Self::evm_block_gas_limit());
2257		}
2258		if tx.r#type.is_none() {
2259			tx.r#type = Some(
2260				if tx.authorization_list.is_empty() { TYPE_EIP1559 } else { TYPE_EIP7702 }.into(),
2261			);
2262		}
2263
2264		// Store values before moving the tx
2265		let authorization_list = tx.authorization_list.clone();
2266		let value = tx.value.unwrap_or_default();
2267		let input = tx.input.clone().to_vec();
2268		let from = tx.from;
2269		let to = tx.to;
2270
2271		// we need to parse the weight from the transaction so that it is run
2272		// using the exact weight limit passed by the eth wallet
2273		let mut call_info = tx
2274			.into_call::<T>(CreateCallMode::DryRun)
2275			.map_err(|err| EthTransactError::Message(format!("Invalid call: {err:?}")))?;
2276
2277		// the dry-run might leave out certain fields
2278		// in those cases we skip the check that the caller has enough balance
2279		// to pay for the fees
2280		let base_info = T::FeeInfo::base_dispatch_info(&mut call_info.call);
2281		let mut base_weight = base_info.total_weight();
2282
2283		// emulate transaction behavior
2284		let fees = call_info.tx_fee.saturating_add(call_info.storage_deposit);
2285		if let Some(from) = &from {
2286			let fees = if gas.is_some() && perform_balance_checks { fees } else { Zero::zero() };
2287			let balance = Self::evm_balance(from);
2288			if balance < Pallet::<T>::convert_native_to_evm(fees).saturating_add(value) {
2289				return Err(EthTransactError::Message(format!(
2290					"insufficient funds for gas * price + value ({fees:?}): address {from:?} have {balance:?} (supplied gas {gas:?})",
2291				)));
2292			}
2293		}
2294
2295		// the deposit is done when the transaction is transformed from an `eth_transact`
2296		// we emulate this behavior for the dry-run here
2297		T::FeeInfo::deposit_txfee(T::Currency::issue(fees));
2298
2299		let extract_error = |err| {
2300			if err == Error::<T>::StorageDepositNotEnoughFunds.into() {
2301				Err(EthTransactError::Message(format!("Not enough gas supplied: {err:?}")))
2302			} else {
2303				Err(EthTransactError::Message(format!("failed to run contract: {err:?}")))
2304			}
2305		};
2306
2307		let exec_config =
2308			ExecConfig::new_eth_tx(effective_gas_price, call_info.encoded_len, base_weight);
2309		let auth_result =
2310			evm::eip7702::process_authorizations::<T>(&authorization_list, &origin, &exec_config);
2311		base_weight = base_weight.saturating_sub(auth_result.weight_refund);
2312		let actual_auth_deposit = auth_result.deposit;
2313		let worst_case_auth_deposit = Self::worst_case_delegation_deposit()
2314			.saturating_mul(authorization_list.len().saturated_into());
2315
2316		let exec_config =
2317			ExecConfig::new_eth_tx(effective_gas_price, call_info.encoded_len, base_weight)
2318				.with_dry_run(timestamp_override);
2319
2320		let transaction_limits = TransactionLimits::EthereumGas {
2321			eth_gas_limit: call_info.eth_gas_limit.saturated_into(),
2322			weight_limit: Self::evm_max_extrinsic_weight(),
2323			eth_tx_info: EthTxInfo::new(call_info.encoded_len, base_weight),
2324			authorization_deposit: actual_auth_deposit,
2325		};
2326
2327		// Dry run the call
2328		let mut dry_run = match to {
2329			// A contract call.
2330			Some(dest) => {
2331				if dest == RUNTIME_PALLETS_ADDR {
2332					let Ok(dispatch_call) = <CallOf<T>>::decode(&mut &input[..]) else {
2333						return Err(EthTransactError::Message(format!(
2334							"Failed to decode pallet-call {input:?}"
2335						)));
2336					};
2337
2338					if let Err(result) =
2339						dispatch_call.clone().dispatch(RawOrigin::Signed(origin).into())
2340					{
2341						return Err(EthTransactError::Message(format!(
2342							"Failed to dispatch call: {:?}",
2343							result.error,
2344						)));
2345					};
2346
2347					Default::default()
2348				} else {
2349					// Dry run the call.
2350					let result = crate::Pallet::<T>::bare_call(
2351						OriginFor::<T>::signed(origin),
2352						dest,
2353						value,
2354						transaction_limits,
2355						input.clone(),
2356						&exec_config,
2357					);
2358
2359					let data = match result.result {
2360						Ok(return_value) => {
2361							if return_value.did_revert() {
2362								return Err(EthTransactError::Data(return_value.data));
2363							}
2364							return_value.data
2365						},
2366						Err(err) => {
2367							log::debug!(target: LOG_TARGET, "Failed to execute call: {err:?}");
2368							return extract_error(err);
2369						},
2370					};
2371
2372					EthTransactInfo {
2373						weight_required: result.weight_required,
2374						storage_deposit: result.storage_deposit.charge_or_zero(),
2375						max_storage_deposit: result.max_storage_deposit.charge_or_zero(),
2376						data,
2377						eth_gas: Default::default(),
2378					}
2379				}
2380			},
2381			// A contract deployment
2382			None => {
2383				// Extract code and data from the input.
2384				let (code, data) = if input.starts_with(&polkavm_common::program::BLOB_MAGIC) {
2385					extract_code_and_data(&input).unwrap_or_else(|| (input, Default::default()))
2386				} else {
2387					(input, vec![])
2388				};
2389
2390				// Dry run the call.
2391				let result = crate::Pallet::<T>::bare_instantiate(
2392					OriginFor::<T>::signed(origin),
2393					value,
2394					transaction_limits,
2395					Code::Upload(code.clone()),
2396					data.clone(),
2397					None,
2398					&exec_config,
2399				);
2400
2401				let returned_data = match result.result {
2402					Ok(return_value) => {
2403						if return_value.result.did_revert() {
2404							return Err(EthTransactError::Data(return_value.result.data));
2405						}
2406						return_value.result.data
2407					},
2408					Err(err) => {
2409						log::debug!(target: LOG_TARGET, "Failed to instantiate: {err:?}");
2410						return extract_error(err);
2411					},
2412				};
2413
2414				EthTransactInfo {
2415					weight_required: result.weight_required,
2416					storage_deposit: result.storage_deposit.charge_or_zero(),
2417					max_storage_deposit: result.max_storage_deposit.charge_or_zero(),
2418					data: returned_data,
2419					eth_gas: Default::default(),
2420				}
2421			},
2422		};
2423
2424		// Ensure max_storage_deposit covers worst-case authorization cost for pool validation.
2425		// The meter already includes the actual auth deposit; this bumps it to worst case
2426		// so that the gas estimate produces a transaction that passes pool validation.
2427		dry_run.max_storage_deposit = dry_run.max_storage_deposit.max(worst_case_auth_deposit);
2428
2429		// replace the weight passed in the transaction with the dry_run result
2430		call_info.call.set_weight_limit(dry_run.weight_required);
2431
2432		// we notify the wallet that the tx would not fit
2433		let total_weight = T::FeeInfo::dispatch_info(&call_info.call).total_weight();
2434		let max_weight = Self::evm_max_extrinsic_weight();
2435		if total_weight.any_gt(max_weight) {
2436			log::debug!(target: LOG_TARGET, "Transaction weight estimate exceeds extrinsic maximum: \
2437				total_weight={total_weight:?} \
2438				max_weight={max_weight:?}",
2439			);
2440
2441			Err(EthTransactError::Message(format!(
2442				"\
2443				The transaction consumes more than the allowed weight. \
2444				needed={total_weight} \
2445				allowed={max_weight} \
2446				overweight_by={}\
2447				",
2448				total_weight.saturating_sub(max_weight),
2449			)))?;
2450		}
2451
2452		// not enough gas supplied to pay for both the tx fees and the storage deposit
2453		let transaction_fee = T::FeeInfo::tx_fee(call_info.encoded_len, &call_info.call);
2454		let available_fee = T::FeeInfo::remaining_txfee();
2455		if transaction_fee > available_fee {
2456			Err(EthTransactError::Message(format!(
2457				"Not enough gas supplied: Off by: {:?}",
2458				transaction_fee.saturating_sub(available_fee),
2459			)))?;
2460		}
2461
2462		let total_cost = transaction_fee.saturating_add(dry_run.max_storage_deposit);
2463		let total_cost_wei = Pallet::<T>::convert_native_to_evm(total_cost);
2464		let (mut eth_gas, rest) = total_cost_wei.div_mod(base_fee);
2465		if !rest.is_zero() {
2466			eth_gas = eth_gas.saturating_add(1_u32.into());
2467		}
2468
2469		log::debug!(target: LOG_TARGET, "\
2470			dry_run_eth_transact finished: \
2471			weight_limit={}, \
2472			total_weight={total_weight}, \
2473			max_weight={max_weight}, \
2474			weight_left={}, \
2475			eth_gas={eth_gas}, \
2476			encoded_len={}, \
2477			tx_fee={transaction_fee:?}, \
2478			storage_deposit={:?}, \
2479			max_storage_deposit={:?}\
2480			",
2481			dry_run.weight_required,
2482			max_weight.saturating_sub(total_weight),
2483			call_info.encoded_len,
2484			dry_run.storage_deposit,
2485			dry_run.max_storage_deposit,
2486
2487		);
2488		dry_run.eth_gas = eth_gas;
2489		Ok(dry_run)
2490	}
2491
2492	/// Get the balance with EVM decimals of the given `address`.
2493	///
2494	/// Returns the spendable balance excluding the existential deposit.
2495	pub fn evm_balance(address: &H160) -> U256 {
2496		let balance = AccountInfo::<T>::balance_of((*address).into());
2497		Self::convert_native_to_evm(balance)
2498	}
2499
2500	/// Get the current Ethereum block from storage.
2501	pub fn eth_block() -> EthBlock {
2502		EthereumBlock::<T>::get()
2503	}
2504
2505	/// Convert the Ethereum block number into the Ethereum block hash.
2506	///
2507	/// # Note
2508	///
2509	/// The Ethereum block number is identical to the Substrate block number.
2510	/// If the provided block number is outside of the pruning None is returned.
2511	pub fn eth_block_hash_from_number(number: U256) -> Option<H256> {
2512		let number = BlockNumberFor::<T>::try_from(number).ok()?;
2513		let hash = <BlockHash<T>>::get(number);
2514		if hash == H256::zero() { None } else { Some(hash) }
2515	}
2516
2517	/// The details needed to reconstruct the receipt information offchain.
2518	pub fn eth_receipt_data() -> Vec<ReceiptGasInfo> {
2519		ReceiptInfoData::<T>::get()
2520	}
2521
2522	/// Set the EVM balance of an account.
2523	///
2524	/// The account's total balance becomes the EVM value plus the existential deposit,
2525	/// consistent with `evm_balance` which returns the spendable balance excluding the existential
2526	/// deposit.
2527	pub fn set_evm_balance(address: &H160, evm_value: U256) -> Result<(), Error<T>> {
2528		let (balance, dust) = Self::new_balance_with_dust(evm_value)
2529			.map_err(|_| <Error<T>>::BalanceConversionFailed)?;
2530		let account_id = T::AddressMapper::to_account_id(&address);
2531		T::Currency::set_balance(&account_id, balance);
2532		AccountInfoOf::<T>::mutate(&address, |account| {
2533			if let Some(account) = account {
2534				account.dust = dust;
2535			} else {
2536				*account = Some(AccountInfo { dust, ..Default::default() });
2537			}
2538		});
2539
2540		Ok(())
2541	}
2542
2543	/// Construct native balance from EVM balance.
2544	///
2545	/// Adds the existential deposit and returns the native balance plus the dust.
2546	pub fn new_balance_with_dust(
2547		evm_value: U256,
2548	) -> Result<(BalanceOf<T>, u32), BalanceConversionError> {
2549		let ed = T::Currency::minimum_balance();
2550		let balance_with_dust = BalanceWithDust::<BalanceOf<T>>::from_value::<T>(evm_value)?;
2551		let (value, dust) = balance_with_dust.deconstruct();
2552
2553		Ok((ed.saturating_add(value), dust))
2554	}
2555
2556	/// Get the nonce for the given `address`.
2557	pub fn evm_nonce(address: &H160) -> u32
2558	where
2559		T::Nonce: Into<u32>,
2560	{
2561		let account = T::AddressMapper::to_account_id(&address);
2562		System::<T>::account_nonce(account).into()
2563	}
2564
2565	/// Get the block gas limit.
2566	pub fn evm_block_gas_limit() -> U256 {
2567		// We just return `u64::MAX` because the gas cost of a transaction can get very large when
2568		// the transaction executes many storage deposits (in theory a contract can behave like a
2569		// factory, procedurally create code and make contract creation calls to store that as
2570		// code). It is too brittle to estimate a maximally possible amount here.
2571		// On the other hand, the data type `u64` seems to be the "common denominator" as the
2572		// typical data type tools and Ethereum implementations use to represent gas amounts.
2573		u64::MAX.into()
2574	}
2575
2576	/// Returns the maximum value of gas that can be represented in weights.
2577	pub fn evm_max_extrinsic_weight_in_gas() -> U256 {
2578		let max_extrinsic_fee = T::FeeInfo::weight_to_fee(&Self::evm_max_extrinsic_weight());
2579		let gas_scale: BalanceOf<T> = T::GasScale::get().into();
2580		(max_extrinsic_fee / gas_scale).into()
2581	}
2582
2583	/// The maximum weight an `eth_transact` is allowed to consume.
2584	pub fn evm_max_extrinsic_weight() -> Weight {
2585		let factor = <T as Config>::MaxEthExtrinsicWeight::get();
2586		let max_weight = <T as frame_system::Config>::BlockWeights::get()
2587			.get(DispatchClass::Normal)
2588			.max_extrinsic
2589			.unwrap_or_else(|| <T as frame_system::Config>::BlockWeights::get().max_block);
2590		Weight::from_parts(
2591			factor.saturating_mul_int(max_weight.ref_time()),
2592			factor.saturating_mul_int(max_weight.proof_size()),
2593		)
2594	}
2595
2596	/// Get the base gas price.
2597	pub fn evm_base_fee() -> U256 {
2598		let gas_scale = <T as Config>::GasScale::get();
2599		let multiplier = T::FeeInfo::next_fee_multiplier();
2600		multiplier
2601			.saturating_mul_int::<u128>(T::NativeToEthRatio::get().into())
2602			.saturating_mul(gas_scale.saturated_into())
2603			.into()
2604	}
2605
2606	/// Build an EVM tracer from the given tracer type.
2607	pub fn evm_tracer(tracer_type: TracerType) -> Tracer<T>
2608	where
2609		T::Nonce: Into<u32>,
2610	{
2611		match tracer_type {
2612			TracerType::CallTracer(config) => CallTracer::new(config.unwrap_or_default()).into(),
2613			TracerType::PrestateTracer(config) => {
2614				PrestateTracer::new(config.unwrap_or_default()).into()
2615			},
2616			TracerType::ExecutionTracer(config) => {
2617				ExecutionTracer::new(config.unwrap_or_default()).into()
2618			},
2619		}
2620	}
2621
2622	/// A generalized version of [`Self::upload_code`].
2623	///
2624	/// It is identical to [`Self::upload_code`] and only differs in the information it returns.
2625	pub fn bare_upload_code(
2626		origin: OriginFor<T>,
2627		code: Vec<u8>,
2628		storage_deposit_limit: BalanceOf<T>,
2629	) -> CodeUploadResult<BalanceOf<T>> {
2630		let origin = T::UploadOrigin::ensure_origin(origin)?;
2631
2632		let bytecode_type = if code.starts_with(&polkavm_common::program::BLOB_MAGIC) {
2633			BytecodeType::Pvm
2634		} else {
2635			if !T::AllowEVMBytecode::get() {
2636				return Err(<Error<T>>::CodeRejected.into());
2637			}
2638			BytecodeType::Evm
2639		};
2640
2641		let mut meter = TransactionMeter::new(TransactionLimits::WeightAndDeposit {
2642			weight_limit: Default::default(),
2643			deposit_limit: storage_deposit_limit,
2644		})?;
2645
2646		let module = Self::try_upload_code(
2647			origin,
2648			code,
2649			bytecode_type,
2650			&mut meter,
2651			&ExecConfig::new_substrate_tx(),
2652		)?;
2653		Ok(CodeUploadReturnValue {
2654			code_hash: *module.code_hash(),
2655			deposit: meter.deposit_consumed().charge_or_zero(),
2656		})
2657	}
2658
2659	/// Query storage of a specified contract under a specified key.
2660	pub fn get_storage(address: H160, key: [u8; 32]) -> GetStorageResult {
2661		let contract_info =
2662			AccountInfo::<T>::load_contract(&address).ok_or(ContractAccessError::DoesntExist)?;
2663
2664		let maybe_value = contract_info.read(&Key::from_fixed(key));
2665		Ok(maybe_value)
2666	}
2667
2668	/// Get the immutable data of a specified contract.
2669	///
2670	/// Returns `None` if the contract does not exist or has no immutable data.
2671	pub fn get_immutables(address: H160) -> Option<ImmutableData> {
2672		let immutable_data = <ImmutableDataOf<T>>::get(address);
2673		immutable_data
2674	}
2675
2676	/// Sets immutable data of a contract
2677	///
2678	/// Returns an error if the contract does not exist.
2679	///
2680	/// # Warning
2681	///
2682	/// Does not collect any storage deposit. Not safe to be called by user controlled code.
2683	/// Immutables belong to deployed contracts only — do not target delegated EOAs.
2684	pub fn set_immutables(address: H160, data: ImmutableData) -> Result<(), ContractAccessError> {
2685		AccountInfo::<T>::load_contract(&address).ok_or(ContractAccessError::DoesntExist)?;
2686		<ImmutableDataOf<T>>::insert(address, data);
2687		Ok(())
2688	}
2689
2690	/// Query storage of a specified contract under a specified variable-sized key.
2691	pub fn get_storage_var_key(address: H160, key: Vec<u8>) -> GetStorageResult {
2692		let contract_info =
2693			AccountInfo::<T>::load_contract(&address).ok_or(ContractAccessError::DoesntExist)?;
2694
2695		let maybe_value = contract_info.read(
2696			&Key::try_from_var(key)
2697				.map_err(|_| ContractAccessError::KeyDecodingFailed)?
2698				.into(),
2699		);
2700		Ok(maybe_value)
2701	}
2702
2703	/// Convert a native balance to EVM balance.
2704	pub fn convert_native_to_evm(value: impl Into<BalanceWithDust<BalanceOf<T>>>) -> U256 {
2705		let (value, dust) = value.into().deconstruct();
2706		value
2707			.into()
2708			.saturating_mul(T::NativeToEthRatio::get().into())
2709			.saturating_add(dust.into())
2710	}
2711
2712	/// Set storage of a specified contract under a specified key.
2713	///
2714	/// If the `value` is `None`, the storage entry is deleted.
2715	///
2716	/// Returns an error if the contract does not exist or if the write operation fails.
2717	///
2718	/// # Warning
2719	///
2720	/// Does not collect any storage deposit. Not safe to be called by user controlled code.
2721	pub fn set_storage(address: H160, key: [u8; 32], value: Option<Vec<u8>>) -> SetStorageResult {
2722		let contract_info =
2723			AccountInfo::<T>::load_contract(&address).ok_or(ContractAccessError::DoesntExist)?;
2724
2725		contract_info
2726			.write(&Key::from_fixed(key), value, None, false)
2727			.map_err(ContractAccessError::StorageWriteFailed)
2728	}
2729
2730	/// Set the storage of a specified contract under a specified variable-sized key.
2731	///
2732	/// If the `value` is `None`, the storage entry is deleted.
2733	///
2734	/// Returns an error if the contract does not exist, if the key decoding fails,
2735	/// or if the write operation fails.
2736	///
2737	/// # Warning
2738	///
2739	/// Does not collect any storage deposit. Not safe to be called by user controlled code.
2740	pub fn set_storage_var_key(
2741		address: H160,
2742		key: Vec<u8>,
2743		value: Option<Vec<u8>>,
2744	) -> SetStorageResult {
2745		let contract_info =
2746			AccountInfo::<T>::load_contract(&address).ok_or(ContractAccessError::DoesntExist)?;
2747
2748		contract_info
2749			.write(
2750				&Key::try_from_var(key)
2751					.map_err(|_| ContractAccessError::KeyDecodingFailed)?
2752					.into(),
2753				value,
2754				None,
2755				false,
2756			)
2757			.map_err(ContractAccessError::StorageWriteFailed)
2758	}
2759
2760	/// Pallet account, used to hold funds for contracts upload deposit.
2761	pub fn account_id() -> T::AccountId {
2762		use frame_support::PalletId;
2763		use sp_runtime::traits::AccountIdConversion;
2764		PalletId(*b"py/reviv").into_account_truncating()
2765	}
2766
2767	/// The address of the validator that produced the current block.
2768	pub fn block_author() -> H160 {
2769		use frame_support::traits::FindAuthor;
2770
2771		let digest = <frame_system::Pallet<T>>::digest();
2772		let pre_runtime_digests = digest.logs.iter().filter_map(|d| d.as_pre_runtime());
2773
2774		T::FindAuthor::find_author(pre_runtime_digests)
2775			.map(|account_id| T::AddressMapper::to_address(&account_id))
2776			.unwrap_or_default()
2777	}
2778
2779	/// Returns the code at `address`.
2780	///
2781	/// This takes pre-compiles into account.
2782	/// For EIP-7702 delegated accounts, returns the delegation indicator (0xef0100 || target).
2783	pub fn code(address: &H160) -> Vec<u8> {
2784		use precompiles::{All, Precompiles};
2785		if let Some(code) = <All<T>>::code(address.as_fixed_bytes()) {
2786			return code.into();
2787		}
2788
2789		let Some(info) = <AccountInfoOf<T>>::get(address) else { return Vec::new() };
2790
2791		match info.account_type {
2792			AccountType::Contract(contract) => <PristineCode<T>>::get(contract.code_hash)
2793				.map(|code| code.into())
2794				.unwrap_or_default(),
2795			AccountType::DelegatedEOA { delegate_target: Some(target), .. } => {
2796				AccountInfo::<T>::delegation_indicator(&target).to_vec()
2797			},
2798			AccountType::EOA | AccountType::DelegatedEOA { .. } => Vec::new(),
2799		}
2800	}
2801
2802	/// Uploads new code and returns the Vm binary contract blob and deposit amount collected.
2803	pub fn try_upload_code(
2804		origin: T::AccountId,
2805		code: Vec<u8>,
2806		code_type: BytecodeType,
2807		meter: &mut TransactionMeter<T>,
2808		exec_config: &ExecConfig<T>,
2809	) -> Result<ContractBlob<T>, DispatchError> {
2810		let mut module = match code_type {
2811			BytecodeType::Pvm => ContractBlob::from_pvm_code(code, origin)?,
2812			BytecodeType::Evm => ContractBlob::from_evm_runtime_code(code, origin)?,
2813		};
2814		module.store_code(exec_config, meter)?;
2815		Ok(module)
2816	}
2817
2818	/// Run the supplied function `f` if no other instance of this pallet is on the stack.
2819	fn run_guarded<R, F: FnOnce() -> Result<R, ExecError>>(f: F) -> Result<R, ExecError> {
2820		executing_contract::using_once(&mut false, || {
2821			executing_contract::with(|f| {
2822				// Fail if already entered contract execution
2823				if *f {
2824					return Err(())
2825				}
2826				// We are entering contract execution
2827				*f = true;
2828				Ok(())
2829			})
2830				.expect("Returns `Ok` if called within `using_once`. It is syntactically obvious that this is the case; qed")
2831				.map_err(|_| <Error<T>>::ReenteredPallet.into())
2832				.map(|_| f())
2833				.and_then(|r| r)
2834		})
2835	}
2836
2837	/// Transfer a deposit from some account to another and place it on hold under `hold_reason`.
2838	///
2839	/// `from` is usually the transaction origin and `to` a contract or
2840	/// the pallets own account.
2841	fn charge_deposit(
2842		hold_reason: HoldReason,
2843		from: &T::AccountId,
2844		to: &T::AccountId,
2845		amount: BalanceOf<T>,
2846		exec_config: &ExecConfig<T>,
2847	) -> DispatchResult {
2848		if amount.is_zero() {
2849			return Ok(());
2850		}
2851
2852		T::Deposit::charge_and_hold(hold_reason, exec_config.funds(from), to, amount)
2853			.map_err(|_| Error::<T>::StorageDepositNotEnoughFunds)?;
2854		Ok(())
2855	}
2856
2857	/// Refund a deposit.
2858	///
2859	/// `dst` is usually the transaction origin and `from` a contract or
2860	/// the pallets own account.
2861	pub(crate) fn refund_deposit(
2862		hold_reason: HoldReason,
2863		from: &T::AccountId,
2864		dst: deposit_payment::Funds<T::AccountId>,
2865		amount: BalanceOf<T>,
2866	) -> Result<(), DispatchError> {
2867		if amount.is_zero() {
2868			return Ok(());
2869		}
2870
2871		let to = match &dst {
2872			deposit_payment::Funds::Balance(to) | deposit_payment::Funds::TxFee(to) => *to,
2873		};
2874		let result = T::Deposit::refund_on_hold(hold_reason, from, dst, amount);
2875
2876		result.defensive_map_err(|err| {
2877			let available = T::Deposit::total_on_hold(hold_reason, from);
2878			if available < amount {
2879				// The storage deposit accounting got out of sync with the balance: This would be a
2880				// straight up bug in this pallet.
2881				log::error!(
2882					target: LOG_TARGET,
2883					"Failed to refund storage deposit {amount:?} from contract {from:?} to origin {to:?}. Not enough deposit: {available:?}. This is a bug.",
2884				);
2885				Error::<T>::StorageRefundNotEnoughFunds.into()
2886			} else {
2887				// There are some locks preventing the refund. This could be the case if the
2888				// contract participates in government. The consequence is that if a contract votes
2889				// with its storage deposit it would no longer be possible to remove storage without first
2890				// reducing the lock.
2891				log::warn!(
2892					target: LOG_TARGET,
2893					"Failed to refund storage deposit {amount:?} from contract {from:?} to origin {to:?}: {err:?}. First remove locks (staking, governance) from the contracts account.",
2894				);
2895				Error::<T>::StorageRefundLocked.into()
2896			}
2897		})
2898	}
2899
2900	/// Returns true if the evm value carries dust.
2901	fn has_dust(value: U256) -> bool {
2902		value % U256::from(<T>::NativeToEthRatio::get()) != U256::zero()
2903	}
2904
2905	/// Returns true if the evm value carries balance.
2906	fn has_balance(value: U256) -> bool {
2907		value >= U256::from(<T>::NativeToEthRatio::get())
2908	}
2909
2910	/// Return the existential deposit of [`Config::Currency`].
2911	#[cfg(any(feature = "runtime-benchmarks", feature = "try-runtime", test))]
2912	fn min_balance() -> BalanceOf<T> {
2913		<T::Currency as Inspect<AccountIdOf<T>>>::minimum_balance()
2914	}
2915
2916	/// Worst-case storage deposit for a single EIP-7702 authorization.
2917	///
2918	/// Assumes a new account delegating to a contract with the maximum code size.
2919	pub(crate) fn worst_case_delegation_deposit() -> BalanceOf<T> {
2920		let ed = <T as Config>::Currency::minimum_balance();
2921		let contract_deposit = T::DepositPerByte::get()
2922			.saturating_mul((<ContractInfo<T>>::max_encoded_len() as u32).into())
2923			.saturating_add(T::DepositPerItem::get());
2924		let max_code_deposit = vm::calculate_code_deposit::<T>(limits::code::BLOB_BYTES);
2925		let code_lockup = T::CodeHashLockupDepositPercent::get().mul_ceil(max_code_deposit);
2926		ed.saturating_add(contract_deposit).saturating_add(code_lockup)
2927	}
2928
2929	/// Deposit a pallet revive event.
2930	///
2931	/// This method will be called by the EVM to deposit events emitted by the contract.
2932	/// Therefore all events must be contract emitted events.
2933	fn deposit_event(event: Event<T>) {
2934		<frame_system::Pallet<T>>::deposit_event(<T as Config>::RuntimeEvent::from(event))
2935	}
2936
2937	// Returns Ok with the account that signed the eth transaction.
2938	fn ensure_eth_signed(origin: OriginFor<T>) -> Result<AccountIdOf<T>, DispatchError> {
2939		match <T as Config>::RuntimeOrigin::from(origin).into() {
2940			Ok(Origin::EthTransaction(signer)) => Ok(signer),
2941			_ => Err(BadOrigin.into()),
2942		}
2943	}
2944
2945	/// Ensure that the origin is neither a pre-compile nor a contract.
2946	///
2947	/// This enforces EIP-3607.
2948	fn ensure_non_contract_if_signed(origin: &OriginFor<T>) -> DispatchResult {
2949		if DebugSettings::bypass_eip_3607::<T>() {
2950			return Ok(());
2951		}
2952		let Some(address) = origin
2953			.as_system_ref()
2954			.and_then(|o| o.as_signed())
2955			.map(<T::AddressMapper as AddressMapper<T>>::to_address)
2956		else {
2957			return Ok(());
2958		};
2959		if exec::is_precompile::<T, ContractBlob<T>>(&address) ||
2960			<AccountInfo<T>>::is_contract(&address)
2961		{
2962			log::debug!(
2963				target: crate::LOG_TARGET,
2964				"EIP-3607: reject tx as pre-compile or account exist at {address:?}",
2965			);
2966			Err(DispatchError::BadOrigin)
2967		} else {
2968			Ok(())
2969		}
2970	}
2971}
2972
2973/// The address used to call the runtime's pallets dispatchables
2974///
2975/// Note:
2976/// computed with PalletId(*b"py/paddr").into_account_truncating();
2977pub const RUNTIME_PALLETS_ADDR: H160 =
2978	H160(hex_literal::hex!("6d6f646c70792f70616464720000000000000000"));
2979
2980// Set up a global reference to the boolean flag used for the re-entrancy guard.
2981environmental!(executing_contract: bool);
2982
2983sp_api::decl_runtime_apis! {
2984	/// The API used to dry-run contract interactions.
2985	#[api_version(2)]
2986	pub trait ReviveApi<AccountId, Balance, Nonce, BlockNumber, Moment> where
2987		AccountId: Codec,
2988		Balance: Codec,
2989		Nonce: Codec,
2990		BlockNumber: Codec,
2991		Moment: Codec,
2992	{
2993		/// Returns the current ETH block.
2994		///
2995		/// This is one block behind the substrate block.
2996		#[deprecated(note = "Use the versioned equivalent `eth_block_versioned` if available on your runtime")]
2997		fn eth_block() -> BlockV1;
2998
2999		/// Returns the ETH block hash for the given block number.
3000		#[deprecated(note = "Use the versioned equivalent `eth_block_hash_versioned` if available on your runtime")]
3001		fn eth_block_hash(number: U256) -> Option<H256>;
3002
3003		/// The details needed to reconstruct the receipt information offchain.
3004		///
3005		/// # Note
3006		///
3007		/// Each entry corresponds to the appropriate Ethereum transaction in the current block.
3008		#[deprecated(note = "Use the versioned equivalent `eth_receipt_data_versioned` if available on your runtime")]
3009		fn eth_receipt_data() -> Vec<ReceiptGasInfoV1>;
3010
3011		/// Returns the block gas limit.
3012		#[deprecated(note = "Use the versioned equivalent `block_gas_limit_versioned` if available on your runtime")]
3013		fn block_gas_limit() -> U256;
3014
3015		/// Returns the block gas limit as calculated from the weights.
3016		#[deprecated(note = "Use the versioned equivalent `max_extrinsic_weight_in_gas_versioned` if available on your runtime")]
3017		fn max_extrinsic_weight_in_gas() -> U256;
3018
3019		/// Returns the free balance of the given `[H160]` address, using EVM decimals.
3020		#[deprecated(note = "Use the versioned equivalent `balance_versioned` if available on your runtime")]
3021		fn balance(address: H160) -> U256;
3022
3023		/// Returns the gas price.
3024		#[deprecated(note = "Use the versioned equivalent `gas_price_versioned` if available on your runtime")]
3025		fn gas_price() -> U256;
3026
3027		/// Returns the nonce of the given `[H160]` address.
3028		#[deprecated(note = "Use the versioned equivalent `nonce_versioned` if available on your runtime")]
3029		fn nonce(address: H160) -> Nonce;
3030
3031		/// Perform a call from a specified account to a given contract.
3032		///
3033		/// See [`crate::Pallet::bare_call`].
3034		#[deprecated(note = "Use the versioned equivalent `call_versioned` if available on your runtime")]
3035		fn call(
3036			origin: AccountId,
3037			dest: H160,
3038			value: Balance,
3039			gas_limit: Option<Weight>,
3040			storage_deposit_limit: Option<Balance>,
3041			input_data: Vec<u8>,
3042		) -> ContractResultV1<ExecReturnValueV1, Balance>;
3043
3044		/// Instantiate a new contract.
3045		///
3046		/// See `[crate::Pallet::bare_instantiate]`.
3047		#[deprecated(note = "Use the versioned equivalent `instantiate_versioned` if available on your runtime")]
3048		fn instantiate(
3049			origin: AccountId,
3050			value: Balance,
3051			gas_limit: Option<Weight>,
3052			storage_deposit_limit: Option<Balance>,
3053			code: CodeV1,
3054			data: Vec<u8>,
3055			salt: Option<[u8; 32]>,
3056		) -> ContractResultV1<InstantiateReturnValueV1, Balance>;
3057
3058
3059		/// Perform an Ethereum call.
3060		///
3061		/// See [`crate::Pallet::dry_run_eth_transact`]
3062		#[deprecated(note = "Use the versioned equivalent `eth_transact_versioned` if available on your runtime")]
3063		fn eth_transact(tx: GenericTransactionV1) -> Result<EthTransactInfoV1<Balance>, EthTransactError>;
3064
3065		/// Perform an Ethereum call.
3066		///
3067		/// See [`crate::Pallet::dry_run_eth_transact`]
3068		#[deprecated(note = "Use the versioned equivalent `eth_transact_versioned` if available on your runtime")]
3069		fn eth_transact_with_config(
3070			tx: GenericTransactionV1,
3071			config: DryRunConfigV1<Moment>,
3072		) -> Result<EthTransactInfoV1<Balance>, EthTransactError>;
3073
3074		/// Estimates the amount of gas that a transactions requires.
3075		///
3076		/// This function estimates the gas of the transaction according to the same binary search
3077		/// algorithm that's implemented in Geth. It stops when with an acceptable error ratio of
3078		/// 1.5% so that the algorithm terminates early.
3079		#[deprecated(note = "Use the versioned equivalent `eth_estimate_gas_versioned` if available on your runtime")]
3080		fn eth_estimate_gas(
3081			tx: GenericTransactionV1,
3082			config: DryRunConfigV1<Moment>
3083		) -> Result<U256, EthTransactError>;
3084
3085		/// Return the pre-dispatch weight booked for the signed Ethereum transaction payload.
3086		#[deprecated(note = "Use the versioned equivalent `eth_pre_dispatch_weight_versioned` if available on your runtime")]
3087		fn eth_pre_dispatch_weight(tx: Vec<u8>) -> Result<Weight, EthTransactError>;
3088
3089		/// Upload new code without instantiating a contract from it.
3090		///
3091		/// See [`crate::Pallet::bare_upload_code`].
3092		#[deprecated(note = "Use the versioned equivalent `upload_code_versioned` if available on your runtime")]
3093		fn upload_code(
3094			origin: AccountId,
3095			code: Vec<u8>,
3096			storage_deposit_limit: Option<Balance>,
3097		) -> Result<CodeUploadReturnValueV1<Balance>, DispatchError>;
3098
3099		/// Query a given storage key in a given contract.
3100		///
3101		/// Returns `Ok(Some(Vec<u8>))` if the storage value exists under the given key in the
3102		/// specified account and `Ok(None)` if it doesn't. If the account specified by the address
3103		/// doesn't exist, or doesn't have a contract then `Err` is returned.
3104		#[deprecated(note = "Use the versioned equivalent `get_storage_versioned` if available on your runtime")]
3105		fn get_storage(
3106			address: H160,
3107			key: [u8; 32],
3108		) -> GetStorageResult;
3109
3110		/// Query a given variable-sized storage key in a given contract.
3111		///
3112		/// Returns `Ok(Some(Vec<u8>))` if the storage value exists under the given key in the
3113		/// specified account and `Ok(None)` if it doesn't. If the account specified by the address
3114		/// doesn't exist, or doesn't have a contract then `Err` is returned.
3115		#[deprecated(note = "Use the versioned equivalent `get_storage_versioned` if available on your runtime")]
3116		fn get_storage_var_key(
3117			address: H160,
3118			key: Vec<u8>,
3119		) -> GetStorageResult;
3120
3121		/// Traces the execution of an entire block and returns call traces.
3122		///
3123		/// This is intended to be called through `state_call` to replay the block from the
3124		/// parent block.
3125		///
3126		/// See eth-rpc `debug_traceBlockByNumber` for usage.
3127		#[deprecated(note = "Use the versioned equivalent `trace_block_versioned` if available on your runtime")]
3128		fn trace_block(
3129			block: Block,
3130			config: TracerTypeV1
3131		) -> Vec<(u32, TraceV1)>;
3132
3133		/// Traces the execution of a specific transaction within a block.
3134		///
3135		/// This is intended to be called through `state_call` to replay the block from the
3136		/// parent hash up to the transaction.
3137		///
3138		/// See eth-rpc `debug_traceTransaction` for usage.
3139		#[deprecated(note = "Use the versioned equivalent `trace_tx_versioned` if available on your runtime")]
3140		fn trace_tx(
3141			block: Block,
3142			tx_index: u32,
3143			config: TracerTypeV1
3144		) -> Option<TraceV1>;
3145
3146		/// Dry run and return the trace of the given call.
3147		///
3148		/// See eth-rpc `debug_traceCall` for usage.
3149		#[deprecated(note = "Use the versioned equivalent `trace_call_versioned` if available on your runtime")]
3150		fn trace_call(tx: GenericTransactionV1, config: TracerTypeV1) -> Result<TraceV1, EthTransactError>;
3151
3152		/// Dry run and return the trace of the given call with additional configuration.
3153		///
3154		/// Like [`Self::trace_call`], but accepts a [`TracingConfigV1`] that can carry state
3155		/// overrides. The config must be the **last argument** for backwards compatibility.
3156		#[deprecated(note = "Use the versioned equivalent `trace_call_versioned` if available on your runtime")]
3157		fn trace_call_with_config(
3158			tx: GenericTransactionV1,
3159			tracer_type: TracerTypeV1,
3160			config: TracingConfigV1,
3161		) -> Result<TraceV1, EthTransactError>;
3162
3163		/// The address of the validator that produced the current block.
3164		#[deprecated(note = "Use the versioned equivalent `block_author_versioned` if available on your runtime")]
3165		fn block_author() -> H160;
3166
3167		/// Get the H160 address associated to this account id
3168		#[deprecated(note = "Use the versioned equivalent `address_versioned` if available on your runtime")]
3169		fn address(account_id: AccountId) -> H160;
3170
3171		/// Get the account id associated to this H160 address.
3172		#[deprecated(note = "Use the versioned equivalent `account_id_versioned` if available on your runtime")]
3173		fn account_id(address: H160) -> AccountId;
3174
3175		/// The address used to call the runtime's pallets dispatchables
3176		#[deprecated(note = "Use the versioned equivalent `runtime_pallets_address_versioned` if available on your runtime")]
3177		fn runtime_pallets_address() -> H160;
3178
3179		/// The code at the specified address taking pre-compiles into account.
3180		#[deprecated(note = "Use the versioned equivalent `code_versioned` if available on your runtime")]
3181		fn code(address: H160) -> Vec<u8>;
3182
3183		/// Construct the new balance and dust components of this EVM balance.
3184		#[deprecated(note = "Use the versioned equivalent `new_balance_with_dust_versioned` if available on your runtime")]
3185		fn new_balance_with_dust(balance: U256) -> Result<(Balance, u32), BalanceConversionError>;
3186
3187		/* Versioned Runtime APIs */
3188
3189		#[api_version(2)]
3190		fn version_declarations() -> ReviveRuntimeApiVersionDeclarations;
3191
3192		#[api_version(2)]
3193		fn eth_block_versioned(input: BlockVersionedInputPayload) -> BlockVersionedOutputPayload;
3194
3195		#[api_version(2)]
3196		fn eth_block_hash_versioned(input: BlockHashVersionedInputPayload) -> BlockHashVersionedOutputPayload;
3197
3198		#[api_version(2)]
3199		fn eth_receipt_data_versioned(input: ReceiptDataVersionedInputPayload) -> ReceiptDataVersionedOutputPayload;
3200
3201		#[api_version(2)]
3202		fn block_gas_limit_versioned(
3203			input: BlockGasLimitVersionedInputPayload
3204		) -> BlockGasLimitVersionedOutputPayload;
3205
3206		#[api_version(2)]
3207		fn max_extrinsic_weight_in_gas_versioned(
3208			input: MaxExtrinsicWeightInGasVersionedInputPayload
3209		) -> MaxExtrinsicWeightInGasVersionedOutputPayload;
3210
3211		#[api_version(2)]
3212		fn balance_versioned(input: BalanceVersionedInputPayload) -> BalanceVersionedOutputPayload;
3213
3214		#[api_version(2)]
3215		fn gas_price_versioned(input: GasPriceVersionedInputPayload) -> GasPriceVersionedOutputPayload;
3216
3217		#[api_version(2)]
3218		fn nonce_versioned(input: NonceVersionedInputPayload) -> NonceVersionedOutputPayload<Nonce>;
3219
3220		#[api_version(2)]
3221		fn call_versioned(
3222			input: CallVersionedInputPayload<AccountId, Balance>
3223		) -> CallVersionedOutputPayload<Balance>;
3224
3225		#[api_version(2)]
3226		fn instantiate_versioned(
3227			input: InstantiateVersionedInputPayload<AccountId, Balance>
3228		) -> InstantiateVersionedOutputPayload<Balance>;
3229
3230		#[api_version(2)]
3231		fn eth_transact_versioned(
3232			input: TransactVersionedInputPayload<Moment>
3233		) -> Result<TransactVersionedOutputPayload<Balance>, EthTransactError>;
3234
3235		#[api_version(2)]
3236		fn eth_estimate_gas_versioned(
3237			input: EstimateGasVersionedInputPayload<Moment>
3238		) -> Result<EstimateGasVersionedOutputPayload, EthTransactError>;
3239
3240		#[api_version(2)]
3241		fn eth_pre_dispatch_weight_versioned(
3242			input: PreDispatchWeightVersionedInputPayload
3243		) -> Result<PreDispatchWeightVersionedOutputPayload, EthTransactError>;
3244
3245		#[api_version(2)]
3246		fn upload_code_versioned(
3247			input: UploadCodeVersionedInputPayload<AccountId, Balance>
3248		) -> Result<UploadCodeVersionedOutputPayload<Balance>, DispatchError>;
3249
3250		#[api_version(2)]
3251		fn get_storage_versioned(
3252			input: GetStorageVersionedInputPayload
3253		) -> Result<GetStorageVersionedOutputPayload, ContractAccessError>;
3254
3255		#[api_version(2)]
3256		fn runtime_pallets_address_versioned(
3257			input: RuntimePalletsAddressVersionedInputPayload
3258		) -> RuntimePalletsAddressVersionedOutputPayload;
3259
3260		#[api_version(2)]
3261		fn code_versioned(input: CodeVersionedInputPayload) -> CodeVersionedOutputPayload;
3262
3263		#[api_version(2)]
3264		fn account_id_versioned(input: AccountIdVersionedInputPayload) -> AccountIdVersionedOutputPayload<AccountId>;
3265
3266		#[api_version(2)]
3267		fn new_balance_with_dust_versioned(
3268			input: NewBalanceWithDustVersionedInputPayload
3269		) -> Result<NewBalanceWithDustVersionedOutputPayload<Balance>, BalanceConversionError>;
3270
3271		#[api_version(2)]
3272		fn block_author_versioned(input: BlockAuthorVersionedInputPayload) -> BlockAuthorVersionedOutputPayload;
3273
3274		#[api_version(2)]
3275		fn address_versioned(input: AddressVersionedInputPayload<AccountId>) -> AddressVersionedOutputPayload;
3276
3277		#[api_version(2)]
3278		fn trace_block_versioned(input: TraceBlockVersionedInputPayload<Block>) -> TraceBlockVersionedOutputPayload;
3279
3280		#[api_version(2)]
3281		fn trace_tx_versioned(input: TraceTxVersionedInputPayload<Block>) -> TraceTxVersionedOutputPayload;
3282
3283		#[api_version(2)]
3284		fn trace_call_versioned(
3285			input: TraceCallVersionedInputPayload
3286		) -> Result<TraceCallVersionedOutputPayload, EthTransactError>;
3287	}
3288}
3289
3290/// This macro wraps substrate's `impl_runtime_apis!` and implements `pallet_revive` runtime APIs
3291/// and other required traits.
3292///
3293/// # Note
3294///
3295/// This also implements [`SetWeightLimit`] for the runtime call.
3296///
3297/// # Parameters
3298/// - `$Runtime`: The runtime type to implement the APIs for.
3299/// - `$Revive`: The name under which revive is declared in `construct_runtime`.
3300/// - `$Executive`: The Executive type of the runtime.
3301/// - `$EthExtra`: Type for additional Ethereum runtime extension.
3302/// - `$($rest:tt)*`: Remaining input to be forwarded to the underlying `impl_runtime_apis!`.
3303#[macro_export]
3304macro_rules! impl_runtime_apis_plus_revive_traits {
3305	($Runtime: ty, $Revive: ident, $Executive: ty, $EthExtra: ty, $($rest:tt)*) => {
3306
3307		type __ReviveMacroMoment = $crate::MomentOf<$Runtime>;
3308
3309		impl $crate::evm::runtime::SetWeightLimit for RuntimeCall {
3310			fn set_weight_limit(&mut self, new_weight_limit: Weight) -> Weight {
3311				use $crate::pallet::Call as ReviveCall;
3312				match self {
3313					Self::$Revive(
3314						ReviveCall::eth_call{ weight_limit, .. } |
3315						ReviveCall::eth_instantiate_with_code{ weight_limit, .. }
3316					) => {
3317						let old = *weight_limit;
3318						*weight_limit = new_weight_limit;
3319						old
3320					},
3321					_ => Weight::default(),
3322				}
3323			}
3324		}
3325
3326		impl_runtime_apis! {
3327			$($rest)*
3328
3329			#[api_version(2)]
3330			impl pallet_revive::ReviveApi<Block, AccountId, Balance, Nonce, BlockNumber, __ReviveMacroMoment> for $Runtime
3331			{
3332				fn eth_block() -> $crate::pallet_revive_types::runtime_api::BlockV1 {
3333					use $crate::pallet_revive_types::runtime_api::*;
3334
3335					let input = BlockVersionedInputPayload::from(BlockInputPayloadV1);
3336					let output = Self::eth_block_versioned(input);
3337					BlockOutputPayloadV1::try_from(output)
3338						.expect("v1 input must produce v1 output; qed")
3339						.block
3340				}
3341
3342				fn eth_block_hash(number: $crate::U256) -> Option<$crate::H256> {
3343					use $crate::pallet_revive_types::runtime_api::*;
3344
3345					let input = BlockHashVersionedInputPayload::from(BlockHashInputPayloadV1 {
3346						block_number: number
3347					});
3348					let output = Self::eth_block_hash_versioned(input);
3349					BlockHashOutputPayloadV1::try_from(output)
3350						.expect("v1 input must produce v1 output; qed")
3351						.block_hash
3352				}
3353
3354				fn eth_receipt_data() -> Vec<$crate::pallet_revive_types::runtime_api::ReceiptGasInfoV1> {
3355					use $crate::pallet_revive_types::runtime_api::*;
3356
3357					let input = ReceiptDataVersionedInputPayload::from(ReceiptDataInputPayloadV1);
3358					let output = Self::eth_receipt_data_versioned(input);
3359					ReceiptDataOutputPayloadV1::try_from(output)
3360						.expect("v1 input must produce v1 output; qed")
3361						.receipt_data
3362				}
3363
3364				fn balance(address: $crate::H160) -> $crate::U256 {
3365					use $crate::pallet_revive_types::runtime_api::*;
3366
3367					let input = BalanceVersionedInputPayload::from(BalanceInputPayloadV1 { address });
3368					let output = Self::balance_versioned(input);
3369					BalanceOutputPayloadV1::try_from(output)
3370						.expect("v1 input must produce v1 output; qed")
3371						.balance
3372				}
3373
3374				fn block_author() -> $crate::H160 {
3375					use $crate::pallet_revive_types::runtime_api::*;
3376
3377					let input = BlockAuthorVersionedInputPayload::from(BlockAuthorInputPayloadV1);
3378					let output = Self::block_author_versioned(input);
3379					BlockAuthorOutputPayloadV1::try_from(output)
3380						.expect("v1 input must produce v1 output; qed")
3381						.block_author
3382				}
3383
3384				fn block_gas_limit() -> $crate::U256 {
3385					use $crate::pallet_revive_types::runtime_api::*;
3386
3387					let input = BlockGasLimitVersionedInputPayload::from(BlockGasLimitInputPayloadV1);
3388					let output = Self::block_gas_limit_versioned(input);
3389					BlockGasLimitOutputPayloadV1::try_from(output)
3390						.expect("v1 input must produce v1 output; qed")
3391						.block_gas_limit
3392				}
3393
3394				fn max_extrinsic_weight_in_gas() -> $crate::U256 {
3395					use $crate::pallet_revive_types::runtime_api::*;
3396
3397					let input = MaxExtrinsicWeightInGasVersionedInputPayload::from(
3398						MaxExtrinsicWeightInGasInputPayloadV1
3399					);
3400					let output = Self::max_extrinsic_weight_in_gas_versioned(input);
3401					MaxExtrinsicWeightInGasOutputPayloadV1::try_from(output)
3402						.expect("v1 input must produce v1 output; qed")
3403						.max_extrinsic_weight_in_gas
3404				}
3405
3406				fn gas_price() -> $crate::U256 {
3407					use $crate::pallet_revive_types::runtime_api::*;
3408
3409					let input = GasPriceVersionedInputPayload::from(GasPriceInputPayloadV1);
3410					let output = Self::gas_price_versioned(input);
3411					GasPriceOutputPayloadV1::try_from(output)
3412						.expect("v1 input must produce v1 output; qed")
3413						.gas_price
3414				}
3415
3416				fn nonce(address: $crate::H160) -> Nonce {
3417					use $crate::pallet_revive_types::runtime_api::*;
3418
3419					let input = NonceVersionedInputPayload::from(NonceInputPayloadV1 { address });
3420					let output = Self::nonce_versioned(input);
3421					NonceOutputPayloadV1::try_from(output)
3422						.expect("v1 input must produce v1 output; qed")
3423						.nonce
3424				}
3425
3426				fn address(account_id: AccountId) -> $crate::H160 {
3427					use $crate::pallet_revive_types::runtime_api::*;
3428
3429					let input = AddressVersionedInputPayload::from(AddressInputPayloadV1 { account_id });
3430					let output = Self::address_versioned(input);
3431					AddressOutputPayloadV1::try_from(output)
3432						.expect("v1 input must produce v1 output; qed")
3433						.address
3434				}
3435
3436				fn eth_transact(
3437					tx: $crate::pallet_revive_types::runtime_api::GenericTransactionV1,
3438				) -> Result<
3439					$crate::pallet_revive_types::runtime_api::EthTransactInfoV1<Balance>,
3440					$crate::EthTransactError
3441				> {
3442					use $crate::pallet_revive_types::runtime_api::*;
3443
3444					let input = TransactVersionedInputPayload::from(TransactInputPayloadV1 {
3445						tx,
3446						timestamp_override: None,
3447						perform_balance_checks: true,
3448						state_overrides: None
3449					});
3450					let output = Self::eth_transact_versioned(input)?;
3451					Ok(TransactOutputPayloadV1::try_from(output)
3452						.expect("v1 input must produce v1 output; qed")
3453						.transact_info)
3454				}
3455
3456				fn eth_transact_with_config(
3457					tx: $crate::pallet_revive_types::runtime_api::GenericTransactionV1,
3458					config: $crate::pallet_revive_types::runtime_api::DryRunConfigV1<__ReviveMacroMoment>,
3459				) -> Result<
3460					$crate::pallet_revive_types::runtime_api::EthTransactInfoV1<Balance>,
3461					$crate::EthTransactError
3462				> {
3463					use $crate::pallet_revive_types::runtime_api::*;
3464
3465					let DryRunConfigV1 { timestamp_override, perform_balance_checks, state_overrides } =
3466						config;
3467
3468					let input = TransactVersionedInputPayload::from(TransactInputPayloadV1 {
3469						tx,
3470						timestamp_override,
3471						perform_balance_checks: perform_balance_checks.unwrap_or(false),
3472						state_overrides
3473					});
3474					let output = Self::eth_transact_versioned(input)?;
3475					Ok(TransactOutputPayloadV1::try_from(output)
3476						.expect("v1 input must produce v1 output; qed")
3477						.transact_info)
3478				}
3479
3480				fn eth_estimate_gas(
3481					tx: $crate::pallet_revive_types::runtime_api::GenericTransactionV1,
3482					config: $crate::pallet_revive_types::runtime_api::DryRunConfigV1<__ReviveMacroMoment>,
3483				) -> Result<$crate::U256, $crate::EthTransactError>  {
3484					use $crate::pallet_revive_types::runtime_api::*;
3485
3486					let DryRunConfigV1 { timestamp_override, perform_balance_checks: _, state_overrides } =
3487						config;
3488
3489					let input = EstimateGasVersionedInputPayload::from(EstimateGasInputPayloadV1 {
3490						tx,
3491						timestamp_override,
3492						state_overrides
3493					});
3494					let output = Self::eth_estimate_gas_versioned(input)?;
3495					Ok(EstimateGasOutputPayloadV1::try_from(output)
3496						.expect("v1 input must produce v1 output; qed")
3497						.gas_estimate)
3498				}
3499
3500				fn eth_pre_dispatch_weight(
3501					tx: Vec<u8>,
3502				) -> Result<$crate::Weight, $crate::EthTransactError> {
3503					use $crate::pallet_revive_types::runtime_api::*;
3504
3505					let input = PreDispatchWeightVersionedInputPayload::from(
3506						PreDispatchWeightInputPayloadV1 { tx }
3507					);
3508					let output = Self::eth_pre_dispatch_weight_versioned(input)?;
3509					Ok(PreDispatchWeightOutputPayloadV1::try_from(output)
3510						.expect("v1 input must produce v1 output; qed")
3511						.weight)
3512				}
3513
3514				fn call(
3515					origin: AccountId,
3516					dest: $crate::H160,
3517					value: Balance,
3518					weight_limit: Option<$crate::Weight>,
3519					storage_deposit_limit: Option<Balance>,
3520					input_data: Vec<u8>,
3521				) -> $crate::pallet_revive_types::runtime_api::ContractResultV1<
3522					$crate::pallet_revive_types::runtime_api::ExecReturnValueV1,
3523					Balance
3524				> {
3525					use $crate::pallet_revive_types::runtime_api::*;
3526
3527					let input = CallVersionedInputPayload::from(CallInputPayloadV1 {
3528						origin,
3529						dest,
3530						value,
3531						gas_limit: weight_limit,
3532						storage_deposit_limit,
3533						input_data
3534					});
3535					let output = Self::call_versioned(input);
3536					CallOutputPayloadV1::try_from(output)
3537						.expect("v1 input must produce v1 output; qed")
3538						.contract_result
3539				}
3540
3541				fn instantiate(
3542					origin: AccountId,
3543					value: Balance,
3544					weight_limit: Option<$crate::Weight>,
3545					storage_deposit_limit: Option<Balance>,
3546					code: $crate::pallet_revive_types::runtime_api::CodeV1,
3547					data: Vec<u8>,
3548					salt: Option<[u8; 32]>,
3549				) -> $crate::pallet_revive_types::runtime_api::ContractResultV1<
3550					$crate::pallet_revive_types::runtime_api::InstantiateReturnValueV1,
3551					Balance
3552				> {
3553					use $crate::pallet_revive_types::runtime_api::*;
3554
3555					let input = InstantiateVersionedInputPayload::from(InstantiateInputPayloadV1 {
3556						origin,
3557						value,
3558						gas_limit: weight_limit,
3559						storage_deposit_limit,
3560						code,
3561						data,
3562						salt
3563					});
3564					let output = Self::instantiate_versioned(input);
3565					InstantiateOutputPayloadV1::try_from(output)
3566						.expect("v1 input must produce v1 output; qed")
3567						.contract_result
3568				}
3569
3570				fn upload_code(
3571					origin: AccountId,
3572					code: Vec<u8>,
3573					storage_deposit_limit: Option<Balance>,
3574				) -> Result<$crate::pallet_revive_types::runtime_api::CodeUploadReturnValueV1<Balance>, $crate::sp_runtime::DispatchError> {
3575					use $crate::pallet_revive_types::runtime_api::*;
3576
3577					let input = UploadCodeVersionedInputPayload::from(UploadCodeInputPayloadV1 {
3578						origin,
3579						code,
3580						storage_deposit_limit
3581					});
3582					let output = Self::upload_code_versioned(input)?;
3583					Ok(UploadCodeOutputPayloadV1::try_from(output)
3584						.expect("v1 input must produce v1 output; qed")
3585						.code_upload_return_value)
3586				}
3587
3588				fn get_storage_var_key(
3589					address: $crate::H160,
3590					key: Vec<u8>,
3591				) -> $crate::GetStorageResult {
3592					use $crate::pallet_revive_types::runtime_api::*;
3593
3594					let input = GetStorageVersionedInputPayload::from(GetStorageInputPayloadV1 {
3595						address,
3596						key: StorageKeyV1::Variable(key)
3597					});
3598					let output = Self::get_storage_versioned(input)?;
3599					Ok(GetStorageOutputPayloadV1::try_from(output)
3600						.expect("v1 input must produce v1 output; qed")
3601						.storage)
3602				}
3603
3604				fn get_storage(address: $crate::H160, key: [u8; 32]) -> $crate::GetStorageResult {
3605					use $crate::pallet_revive_types::runtime_api::*;
3606
3607					let input = GetStorageVersionedInputPayload::from(GetStorageInputPayloadV1 {
3608						address,
3609						key: StorageKeyV1::Fixed(key)
3610					});
3611					let output = Self::get_storage_versioned(input)?;
3612					Ok(GetStorageOutputPayloadV1::try_from(output)
3613						.expect("v1 input must produce v1 output; qed")
3614						.storage)
3615				}
3616
3617				fn trace_block(
3618					block: Block,
3619					tracer_type: $crate::pallet_revive_types::runtime_api::TracerTypeV1,
3620				) -> Vec<(u32, $crate::pallet_revive_types::runtime_api::TraceV1)> {
3621					use $crate::pallet_revive_types::runtime_api::*;
3622
3623					let input = TraceBlockVersionedInputPayload::from(TraceBlockInputPayloadV1 {
3624						block,
3625						config: tracer_type
3626					});
3627					let output = Self::trace_block_versioned(input);
3628					TraceBlockOutputPayloadV1::try_from(output)
3629						.expect("v1 input must produce v1 output; qed")
3630						.traces
3631				}
3632
3633				fn trace_tx(
3634					block: Block,
3635					tx_index: u32,
3636					tracer_type: $crate::pallet_revive_types::runtime_api::TracerTypeV1,
3637				) -> Option<$crate::pallet_revive_types::runtime_api::TraceV1> {
3638					use $crate::pallet_revive_types::runtime_api::*;
3639
3640					let input = TraceTxVersionedInputPayload::from(TraceTxInputPayloadV1 {
3641						block,
3642						tx_index,
3643						config: tracer_type
3644					});
3645					let output = Self::trace_tx_versioned(input);
3646					TraceTxOutputPayloadV1::try_from(output)
3647						.expect("v1 input must produce v1 output; qed")
3648						.trace
3649				}
3650
3651				fn trace_call(
3652					tx: $crate::pallet_revive_types::runtime_api::GenericTransactionV1,
3653					tracer_type: $crate::pallet_revive_types::runtime_api::TracerTypeV1,
3654				) -> Result<$crate::pallet_revive_types::runtime_api::TraceV1, $crate::EthTransactError> {
3655					use $crate::pallet_revive_types::runtime_api::*;
3656
3657					let input = TraceCallVersionedInputPayload::from(TraceCallInputPayloadV1 {
3658						tx,
3659						config: tracer_type,
3660						state_overrides: None
3661					});
3662					let output = Self::trace_call_versioned(input)?;
3663					Ok(TraceCallOutputPayloadV1::try_from(output)
3664						.expect("v1 input must produce v1 output; qed")
3665						.trace)
3666				}
3667
3668				fn trace_call_with_config(
3669					tx: $crate::pallet_revive_types::runtime_api::GenericTransactionV1,
3670					tracer_type: $crate::pallet_revive_types::runtime_api::TracerTypeV1,
3671					config: $crate::pallet_revive_types::runtime_api::TracingConfigV1,
3672				) -> Result<$crate::pallet_revive_types::runtime_api::TraceV1, $crate::EthTransactError> {
3673					use $crate::pallet_revive_types::runtime_api::*;
3674
3675					let TracingConfigV1 { state_overrides } = config;
3676
3677					let input = TraceCallVersionedInputPayload::from(TraceCallInputPayloadV1 {
3678						tx,
3679						config: tracer_type,
3680						state_overrides
3681					});
3682					let output = Self::trace_call_versioned(input)?;
3683					Ok(TraceCallOutputPayloadV1::try_from(output)
3684						.expect("v1 input must produce v1 output; qed")
3685						.trace)
3686				}
3687
3688				fn runtime_pallets_address() -> $crate::H160 {
3689					use $crate::pallet_revive_types::runtime_api::*;
3690
3691					let input = RuntimePalletsAddressVersionedInputPayload::from(
3692						RuntimePalletsAddressInputPayloadV1
3693					);
3694					let output = Self::runtime_pallets_address_versioned(input);
3695					RuntimePalletsAddressOutputPayloadV1::try_from(output)
3696						.expect("v1 input must produce v1 output; qed")
3697						.runtime_pallets_address
3698				}
3699
3700				fn code(address: $crate::H160) -> Vec<u8> {
3701					use $crate::pallet_revive_types::runtime_api::*;
3702
3703					let input = CodeVersionedInputPayload::from(CodeInputPayloadV1 { address });
3704					let output = Self::code_versioned(input);
3705					CodeOutputPayloadV1::try_from(output)
3706						.expect("v1 input must produce v1 output; qed")
3707						.code
3708				}
3709
3710				fn account_id(address: $crate::H160) -> AccountId {
3711					use $crate::pallet_revive_types::runtime_api::*;
3712
3713					let input = AccountIdVersionedInputPayload::from(AccountIdInputPayloadV1 { address });
3714					let output = Self::account_id_versioned(input);
3715					AccountIdOutputPayloadV1::try_from(output)
3716						.expect("v1 input must produce v1 output; qed")
3717						.account_id
3718				}
3719
3720				fn new_balance_with_dust(balance: $crate::U256) -> Result<(Balance, u32), $crate::BalanceConversionError> {
3721					use $crate::pallet_revive_types::runtime_api::*;
3722
3723					let input = NewBalanceWithDustVersionedInputPayload::from(
3724						NewBalanceWithDustInputPayloadV1 { balance }
3725					);
3726					let output = Self::new_balance_with_dust_versioned(input)?;
3727					let output = NewBalanceWithDustOutputPayloadV1::try_from(output)
3728						.expect("v1 input must produce v1 output; qed");
3729					Ok((output.new_balance, output.dust))
3730				}
3731
3732				/* Versioned Runtime APIs */
3733
3734				fn version_declarations()
3735					-> $crate::pallet_revive_types::runtime_api::ReviveRuntimeApiVersionDeclarations
3736				{
3737					use $crate::pallet_revive_types::runtime_api::*;
3738
3739					ReviveRuntimeApiVersionDeclarations::new()
3740						.insert("eth_block_versioned", 1)
3741						.insert("eth_block_hash_versioned", 1)
3742						.insert("eth_receipt_data_versioned", 1)
3743						.insert("block_gas_limit_versioned", 1)
3744						.insert("max_extrinsic_weight_in_gas_versioned", 1)
3745						.insert("balance_versioned", 1)
3746						.insert("gas_price_versioned", 1)
3747						.insert("nonce_versioned", 1)
3748						.insert("call_versioned", 1)
3749						.insert("instantiate_versioned", 1)
3750						.insert("eth_transact_versioned", 1)
3751						.insert("eth_estimate_gas_versioned", 1)
3752						.insert("eth_pre_dispatch_weight_versioned", 1)
3753						.insert("upload_code_versioned", 1)
3754						.insert("get_storage_versioned", 1)
3755						.insert("runtime_pallets_address_versioned", 1)
3756						.insert("code_versioned", 1)
3757						.insert("account_id_versioned", 1)
3758						.insert("new_balance_with_dust_versioned", 1)
3759						.insert("block_author_versioned", 1)
3760						.insert("address_versioned", 1)
3761						.insert("trace_block_versioned", 2)
3762						.insert("trace_tx_versioned", 2)
3763						.insert("trace_call_versioned", 2)
3764				}
3765
3766				fn eth_block_versioned(
3767					input: $crate::pallet_revive_types::runtime_api::BlockVersionedInputPayload
3768				) -> $crate::pallet_revive_types::runtime_api::BlockVersionedOutputPayload {
3769					use $crate::pallet_revive_types::runtime_api::*;
3770					use $crate::runtime_api::*;
3771					use alloc::boxed::Box;
3772
3773					let (_input, output_wrapper): (
3774						_,
3775						Box<dyn Fn(BlockOutputPayload) -> BlockVersionedOutputPayload>,
3776					) = match input {
3777						BlockVersionedInputPayload::V1(payload) => (
3778							BlockInputPayload::from(payload),
3779							Box::new(|output| BlockVersionedOutputPayload::V1(output.into())),
3780						),
3781					};
3782
3783					let output = BlockOutputPayload { block: $crate::Pallet::<Self>::eth_block() };
3784					output_wrapper(output)
3785				}
3786
3787				fn eth_block_hash_versioned(
3788					input: $crate::pallet_revive_types::runtime_api::BlockHashVersionedInputPayload
3789				) -> $crate::pallet_revive_types::runtime_api::BlockHashVersionedOutputPayload {
3790					use $crate::pallet_revive_types::runtime_api::*;
3791					use $crate::runtime_api::*;
3792					use alloc::boxed::Box;
3793
3794					let (input, output_wrapper): (
3795						_,
3796						Box<dyn Fn(BlockHashOutputPayload) -> BlockHashVersionedOutputPayload>,
3797					) = match input {
3798						BlockHashVersionedInputPayload::V1(payload) => (
3799							BlockHashInputPayload::from(payload),
3800							Box::new(|output| BlockHashVersionedOutputPayload::V1(output.into())),
3801						),
3802					};
3803
3804					let output = BlockHashOutputPayload {
3805						block_hash: $crate::Pallet::<Self>::eth_block_hash_from_number(input.block_number)
3806					};
3807					output_wrapper(output)
3808				}
3809
3810				fn eth_receipt_data_versioned(
3811					input: $crate::pallet_revive_types::runtime_api::ReceiptDataVersionedInputPayload
3812				) -> $crate::pallet_revive_types::runtime_api::ReceiptDataVersionedOutputPayload {
3813					use $crate::pallet_revive_types::runtime_api::*;
3814					use $crate::runtime_api::*;
3815					use alloc::boxed::Box;
3816
3817					let (_input, output_wrapper): (
3818						_,
3819						Box<dyn Fn(ReceiptDataOutputPayload) -> ReceiptDataVersionedOutputPayload>,
3820					) = match input {
3821						ReceiptDataVersionedInputPayload::V1(payload) => (
3822							ReceiptDataInputPayload::from(payload),
3823							Box::new(|output| ReceiptDataVersionedOutputPayload::V1(output.into())),
3824						),
3825					};
3826
3827					let output = ReceiptDataOutputPayload {
3828						receipt_data: $crate::Pallet::<Self>::eth_receipt_data()
3829					};
3830					output_wrapper(output)
3831				}
3832
3833				fn block_gas_limit_versioned(
3834					input: $crate::pallet_revive_types::runtime_api::BlockGasLimitVersionedInputPayload
3835				) -> $crate::pallet_revive_types::runtime_api::BlockGasLimitVersionedOutputPayload {
3836					use $crate::pallet_revive_types::runtime_api::*;
3837					use $crate::runtime_api::*;
3838					use alloc::boxed::Box;
3839
3840					let (_input, output_wrapper): (
3841						_,
3842						Box<dyn Fn(BlockGasLimitOutputPayload) -> BlockGasLimitVersionedOutputPayload>,
3843					) = match input {
3844						BlockGasLimitVersionedInputPayload::V1(payload) => (
3845							BlockGasLimitInputPayload::from(payload),
3846							Box::new(|output| BlockGasLimitVersionedOutputPayload::V1(output.into())),
3847						),
3848					};
3849
3850					let output = BlockGasLimitOutputPayload {
3851						block_gas_limit: $crate::Pallet::<Self>::evm_block_gas_limit()
3852					};
3853					output_wrapper(output)
3854				}
3855
3856				fn max_extrinsic_weight_in_gas_versioned(
3857					input: $crate::pallet_revive_types::runtime_api::MaxExtrinsicWeightInGasVersionedInputPayload
3858				) -> $crate::pallet_revive_types::runtime_api::MaxExtrinsicWeightInGasVersionedOutputPayload {
3859					use $crate::pallet_revive_types::runtime_api::*;
3860					use $crate::runtime_api::*;
3861					use alloc::boxed::Box;
3862
3863					let (_input, output_wrapper): (
3864						_,
3865						Box<dyn Fn(MaxExtrinsicWeightInGasOutputPayload) -> MaxExtrinsicWeightInGasVersionedOutputPayload>,
3866					) = match input {
3867						MaxExtrinsicWeightInGasVersionedInputPayload::V1(payload) => (
3868							MaxExtrinsicWeightInGasInputPayload::from(payload),
3869							Box::new(|output| MaxExtrinsicWeightInGasVersionedOutputPayload::V1(output.into())),
3870						),
3871					};
3872
3873					let output = MaxExtrinsicWeightInGasOutputPayload {
3874						max_extrinsic_weight_in_gas: $crate::Pallet::<Self>::evm_max_extrinsic_weight_in_gas()
3875					};
3876					output_wrapper(output)
3877				}
3878
3879				fn balance_versioned(
3880					input: $crate::pallet_revive_types::runtime_api::BalanceVersionedInputPayload
3881				) -> $crate::pallet_revive_types::runtime_api::BalanceVersionedOutputPayload {
3882					use $crate::pallet_revive_types::runtime_api::*;
3883					use $crate::runtime_api::*;
3884					use alloc::boxed::Box;
3885
3886					let (input, output_wrapper): (
3887						_,
3888						Box<dyn Fn(BalanceOutputPayload) -> BalanceVersionedOutputPayload>,
3889					) = match input {
3890						BalanceVersionedInputPayload::V1(payload) => (
3891							BalanceInputPayload::from(payload),
3892							Box::new(|output| BalanceVersionedOutputPayload::V1(output.into())),
3893						),
3894					};
3895
3896					let output = BalanceOutputPayload {
3897						balance: $crate::Pallet::<Self>::evm_balance(&input.address)
3898					};
3899					output_wrapper(output)
3900				}
3901
3902				fn gas_price_versioned(
3903					input: $crate::pallet_revive_types::runtime_api::GasPriceVersionedInputPayload
3904				) -> $crate::pallet_revive_types::runtime_api::GasPriceVersionedOutputPayload {
3905					use $crate::pallet_revive_types::runtime_api::*;
3906					use $crate::runtime_api::*;
3907					use alloc::boxed::Box;
3908
3909					let (_input, output_wrapper): (
3910						_,
3911						Box<dyn Fn(GasPriceOutputPayload) -> GasPriceVersionedOutputPayload>,
3912					) = match input {
3913						GasPriceVersionedInputPayload::V1(payload) => (
3914							GasPriceInputPayload::from(payload),
3915							Box::new(|output| GasPriceVersionedOutputPayload::V1(output.into())),
3916						),
3917					};
3918
3919					let output = GasPriceOutputPayload {
3920						gas_price: $crate::Pallet::<Self>::evm_base_fee()
3921					};
3922					output_wrapper(output)
3923				}
3924
3925				fn nonce_versioned(
3926					input: $crate::pallet_revive_types::runtime_api::NonceVersionedInputPayload
3927				) -> $crate::pallet_revive_types::runtime_api::NonceVersionedOutputPayload<Nonce> {
3928					use $crate::pallet_revive_types::runtime_api::*;
3929					use $crate::runtime_api::*;
3930					use $crate::AddressMapper;
3931					use alloc::boxed::Box;
3932
3933					let (input, output_wrapper): (
3934						_,
3935						Box<dyn Fn(NonceOutputPayload<Nonce>) -> NonceVersionedOutputPayload<Nonce>>,
3936					) = match input {
3937						NonceVersionedInputPayload::V1(payload) => (
3938							NonceInputPayload::from(payload),
3939							Box::new(|output| NonceVersionedOutputPayload::V1(output.into())),
3940						),
3941					};
3942
3943					let account = <Self as $crate::Config>::AddressMapper::to_account_id(&input.address);
3944					let output = NonceOutputPayload {
3945						nonce: $crate::frame_system::Pallet::<Self>::account_nonce(account)
3946					};
3947					output_wrapper(output)
3948				}
3949
3950				fn call_versioned(
3951					input: $crate::pallet_revive_types::runtime_api::CallVersionedInputPayload<AccountId, Balance>
3952				) -> $crate::pallet_revive_types::runtime_api::CallVersionedOutputPayload<Balance> {
3953					use $crate::pallet_revive_types::runtime_api::*;
3954					use $crate::runtime_api::*;
3955					use $crate::frame_support::traits::Get;
3956					use alloc::boxed::Box;
3957
3958					let (input, output_wrapper): (
3959						_,
3960						Box<dyn Fn(CallOutputPayload<Balance>) -> CallVersionedOutputPayload<Balance>>,
3961					) = match input {
3962						CallVersionedInputPayload::V1(payload) => (
3963							CallInputPayload::from(payload),
3964							Box::new(|output| CallVersionedOutputPayload::V1(output.into())),
3965						),
3966					};
3967
3968					let blockweights: $crate::BlockWeights =
3969						<Self as $crate::frame_system::Config>::BlockWeights::get();
3970
3971					$crate::Pallet::<Self>::prepare_dry_run(&input.origin);
3972					let contract_result = $crate::Pallet::<Self>::bare_call(
3973						<Self as $crate::frame_system::Config>::RuntimeOrigin::signed(input.origin),
3974						input.dest,
3975						$crate::Pallet::<Self>::convert_native_to_evm(input.value),
3976						$crate::TransactionLimits::WeightAndDeposit {
3977							weight_limit: input.gas_limit.unwrap_or(blockweights.max_block),
3978							deposit_limit: input.storage_deposit_limit.unwrap_or(u128::MAX),
3979						},
3980						input.input_data,
3981						&$crate::ExecConfig::new_substrate_tx().with_dry_run(None),
3982					);
3983
3984					let output = CallOutputPayload { contract_result };
3985					output_wrapper(output)
3986				}
3987
3988				fn instantiate_versioned(
3989					input: $crate::pallet_revive_types::runtime_api::InstantiateVersionedInputPayload<AccountId, Balance>
3990				) -> $crate::pallet_revive_types::runtime_api::InstantiateVersionedOutputPayload<Balance> {
3991					use $crate::pallet_revive_types::runtime_api::*;
3992					use $crate::runtime_api::*;
3993					use $crate::frame_support::traits::Get;
3994					use alloc::boxed::Box;
3995
3996					let (input, output_wrapper): (
3997						_,
3998						Box<dyn Fn(InstantiateOutputPayload<Balance>) -> InstantiateVersionedOutputPayload<Balance>>,
3999					) = match input {
4000						InstantiateVersionedInputPayload::V1(payload) => (
4001							InstantiateInputPayload::from(payload),
4002							Box::new(|output| InstantiateVersionedOutputPayload::V1(output.into())),
4003						),
4004					};
4005
4006					let blockweights: $crate::BlockWeights =
4007						<Self as $crate::frame_system::Config>::BlockWeights::get();
4008
4009					$crate::Pallet::<Self>::prepare_dry_run(&input.origin);
4010					let contract_result = $crate::Pallet::<Self>::bare_instantiate(
4011						<Self as $crate::frame_system::Config>::RuntimeOrigin::signed(input.origin),
4012						$crate::Pallet::<Self>::convert_native_to_evm(input.value),
4013						$crate::TransactionLimits::WeightAndDeposit {
4014							weight_limit: input.gas_limit.unwrap_or(blockweights.max_block),
4015							deposit_limit: input.storage_deposit_limit.unwrap_or(u128::MAX),
4016						},
4017						input.code,
4018						input.data,
4019						input.salt,
4020						&$crate::ExecConfig::new_substrate_tx().with_dry_run(None),
4021					);
4022
4023					let output = InstantiateOutputPayload { contract_result };
4024					output_wrapper(output)
4025				}
4026
4027				fn eth_transact_versioned(
4028					input: $crate::pallet_revive_types::runtime_api::TransactVersionedInputPayload<__ReviveMacroMoment>
4029				) -> Result<
4030					$crate::pallet_revive_types::runtime_api::TransactVersionedOutputPayload<Balance>,
4031					$crate::EthTransactError
4032				> {
4033					use $crate::pallet_revive_types::runtime_api::*;
4034					use $crate::runtime_api::*;
4035					use $crate::{
4036						codec::Encode, evm::runtime::EthExtra, frame_support::traits::Get,
4037						sp_runtime::traits::TransactionExtension,
4038						sp_runtime::traits::Block as BlockT
4039					};
4040					use alloc::boxed::Box;
4041
4042					let (input, output_wrapper): (
4043						_,
4044						Box<dyn Fn(TransactOutputPayload<Balance>) -> TransactVersionedOutputPayload<Balance>>,
4045					) = match input {
4046						TransactVersionedInputPayload::V1(payload) => (
4047							TransactInputPayload::from(payload),
4048							Box::new(|output| TransactVersionedOutputPayload::V1(output.into())),
4049						),
4050					};
4051
4052					let transact_info = $crate::Pallet::<Self>::dry_run_eth_transact(
4053						input.tx,
4054						input.timestamp_override,
4055						input.perform_balance_checks,
4056						input.state_overrides,
4057					)?;
4058					let output = TransactOutputPayload { transact_info };
4059					Ok(output_wrapper(output))
4060				}
4061
4062				fn eth_estimate_gas_versioned(
4063					input: $crate::pallet_revive_types::runtime_api::EstimateGasVersionedInputPayload<__ReviveMacroMoment>
4064				) -> Result<
4065					$crate::pallet_revive_types::runtime_api::EstimateGasVersionedOutputPayload,
4066					$crate::EthTransactError
4067				> {
4068					use $crate::pallet_revive_types::runtime_api::*;
4069					use $crate::runtime_api::*;
4070					use $crate::{
4071						codec::Encode, evm::runtime::EthExtra, frame_support::traits::Get,
4072						sp_runtime::traits::TransactionExtension,
4073						sp_runtime::traits::Block as BlockT
4074					};
4075					use alloc::boxed::Box;
4076
4077					let (input, output_wrapper): (
4078						_,
4079						Box<dyn Fn(EstimateGasOutputPayload) -> EstimateGasVersionedOutputPayload>,
4080					) = match input {
4081						EstimateGasVersionedInputPayload::V1(payload) => (
4082							EstimateGasInputPayload::from(payload),
4083							Box::new(|output| EstimateGasVersionedOutputPayload::V1(output.into())),
4084						),
4085					};
4086
4087					let gas_estimate = $crate::Pallet::<Self>::eth_estimate_gas(
4088						input.tx,
4089						input.timestamp_override,
4090						input.state_overrides,
4091					)?;
4092					let output = EstimateGasOutputPayload { gas_estimate };
4093					Ok(output_wrapper(output))
4094				}
4095
4096				fn eth_pre_dispatch_weight_versioned(
4097					input: $crate::pallet_revive_types::runtime_api::PreDispatchWeightVersionedInputPayload
4098				) -> Result<
4099					$crate::pallet_revive_types::runtime_api::PreDispatchWeightVersionedOutputPayload,
4100					$crate::EthTransactError
4101				> {
4102					use $crate::pallet_revive_types::runtime_api::*;
4103					use $crate::runtime_api::*;
4104					use alloc::boxed::Box;
4105
4106					let (input, output_wrapper): (
4107						_,
4108						Box<dyn Fn(PreDispatchWeightOutputPayload) -> PreDispatchWeightVersionedOutputPayload>,
4109					) = match input {
4110						PreDispatchWeightVersionedInputPayload::V1(payload) => (
4111							PreDispatchWeightInputPayload::from(payload),
4112							Box::new(|output| PreDispatchWeightVersionedOutputPayload::V1(output.into())),
4113						),
4114					};
4115
4116					let output = PreDispatchWeightOutputPayload {
4117						weight: $crate::Pallet::<Self>::eth_pre_dispatch_weight(input.tx)?
4118					};
4119					Ok(output_wrapper(output))
4120				}
4121
4122				fn upload_code_versioned(
4123					input: $crate::pallet_revive_types::runtime_api::UploadCodeVersionedInputPayload<AccountId, Balance>
4124				) -> Result<
4125					$crate::pallet_revive_types::runtime_api::UploadCodeVersionedOutputPayload<Balance>,
4126					$crate::sp_runtime::DispatchError
4127				> {
4128					use $crate::pallet_revive_types::runtime_api::*;
4129					use $crate::runtime_api::*;
4130					use alloc::boxed::Box;
4131
4132					let (input, output_wrapper): (
4133						_,
4134						Box<dyn Fn(UploadCodeOutputPayload<Balance>) -> UploadCodeVersionedOutputPayload<Balance>>,
4135					) = match input {
4136						UploadCodeVersionedInputPayload::V1(payload) => (
4137							UploadCodeInputPayload::from(payload),
4138							Box::new(|output| UploadCodeVersionedOutputPayload::V1(output.into())),
4139						),
4140					};
4141
4142					let origin =
4143						<Self as $crate::frame_system::Config>::RuntimeOrigin::signed(input.origin);
4144					let code_upload_return_value = $crate::Pallet::<Self>::bare_upload_code(
4145						origin,
4146						input.code,
4147						input.storage_deposit_limit.unwrap_or(u128::MAX),
4148					)?;
4149					let output = UploadCodeOutputPayload { code_upload_return_value };
4150					Ok(output_wrapper(output))
4151				}
4152
4153				fn get_storage_versioned(
4154					input: $crate::pallet_revive_types::runtime_api::GetStorageVersionedInputPayload
4155				) -> Result<
4156					$crate::pallet_revive_types::runtime_api::GetStorageVersionedOutputPayload,
4157					$crate::ContractAccessError
4158				> {
4159					use $crate::pallet_revive_types::runtime_api::*;
4160					use $crate::runtime_api::*;
4161					use alloc::boxed::Box;
4162
4163					let (input, output_wrapper): (
4164						_,
4165						Box<dyn Fn(GetStorageOutputPayload) -> GetStorageVersionedOutputPayload>,
4166					) = match input {
4167						GetStorageVersionedInputPayload::V1(payload) => (
4168							GetStorageInputPayload::from(payload),
4169							Box::new(|output| GetStorageVersionedOutputPayload::V1(output.into())),
4170						),
4171					};
4172
4173					let storage = match input.key {
4174						StorageKey::Fixed(key) => $crate::Pallet::<Self>::get_storage(input.address, key)?,
4175						StorageKey::Variable(key) => $crate::Pallet::<Self>::get_storage_var_key(input.address, key)?,
4176					};
4177					let output = GetStorageOutputPayload { storage };
4178					Ok(output_wrapper(output))
4179				}
4180
4181				fn runtime_pallets_address_versioned(
4182					input: $crate::pallet_revive_types::runtime_api::RuntimePalletsAddressVersionedInputPayload
4183				) -> $crate::pallet_revive_types::runtime_api::RuntimePalletsAddressVersionedOutputPayload {
4184					use $crate::pallet_revive_types::runtime_api::*;
4185					use $crate::runtime_api::*;
4186					use alloc::boxed::Box;
4187
4188					let (_input, output_wrapper): (
4189						_,
4190						Box<dyn Fn(RuntimePalletsAddressOutputPayload) -> RuntimePalletsAddressVersionedOutputPayload>,
4191					) = match input {
4192						RuntimePalletsAddressVersionedInputPayload::V1(payload) => (
4193							RuntimePalletsAddressInputPayload::from(payload),
4194							Box::new(|output| RuntimePalletsAddressVersionedOutputPayload::V1(output.into())),
4195						),
4196					};
4197
4198					let output = RuntimePalletsAddressOutputPayload {
4199						runtime_pallets_address: $crate::RUNTIME_PALLETS_ADDR
4200					};
4201					output_wrapper(output)
4202				}
4203
4204				fn code_versioned(
4205					input: $crate::pallet_revive_types::runtime_api::CodeVersionedInputPayload
4206				) -> $crate::pallet_revive_types::runtime_api::CodeVersionedOutputPayload {
4207					use $crate::pallet_revive_types::runtime_api::*;
4208					use $crate::runtime_api::*;
4209					use alloc::boxed::Box;
4210
4211					let (input, output_wrapper): (
4212						_,
4213						Box<dyn Fn(CodeOutputPayload) -> CodeVersionedOutputPayload>,
4214					) = match input {
4215						CodeVersionedInputPayload::V1(payload) => (
4216							CodeInputPayload::from(payload),
4217							Box::new(|output| CodeVersionedOutputPayload::V1(output.into())),
4218						),
4219					};
4220
4221					let output = CodeOutputPayload {
4222						code: $crate::Pallet::<Self>::code(&input.address)
4223					};
4224					output_wrapper(output)
4225				}
4226
4227				fn account_id_versioned(
4228					input: $crate::pallet_revive_types::runtime_api::AccountIdVersionedInputPayload
4229				) -> $crate::pallet_revive_types::runtime_api::AccountIdVersionedOutputPayload<AccountId> {
4230					use $crate::pallet_revive_types::runtime_api::*;
4231					use $crate::runtime_api::*;
4232					use $crate::AddressMapper;
4233					use alloc::boxed::Box;
4234
4235					let (input, output_wrapper): (
4236						_,
4237						Box<dyn Fn(AccountIdOutputPayload<AccountId>) -> AccountIdVersionedOutputPayload<AccountId>>,
4238					) = match input {
4239						AccountIdVersionedInputPayload::V1(payload) => (
4240							AccountIdInputPayload::from(payload),
4241							Box::new(|output| AccountIdVersionedOutputPayload::V1(output.into())),
4242						),
4243					};
4244
4245					let output = AccountIdOutputPayload {
4246						account_id: <Self as $crate::Config>::AddressMapper::to_account_id(&input.address)
4247					};
4248					output_wrapper(output)
4249				}
4250
4251				fn new_balance_with_dust_versioned(
4252					input: $crate::pallet_revive_types::runtime_api::NewBalanceWithDustVersionedInputPayload
4253				) -> Result<
4254					$crate::pallet_revive_types::runtime_api::NewBalanceWithDustVersionedOutputPayload<Balance>,
4255					$crate::BalanceConversionError
4256				> {
4257					use $crate::pallet_revive_types::runtime_api::*;
4258					use $crate::runtime_api::*;
4259					use alloc::boxed::Box;
4260
4261					let (input, output_wrapper): (
4262						_,
4263						Box<
4264							dyn Fn(NewBalanceWithDustOutputPayload<Balance>) -> NewBalanceWithDustVersionedOutputPayload<Balance>,
4265						>,
4266					) = match input {
4267						NewBalanceWithDustVersionedInputPayload::V1(payload) => (
4268							NewBalanceWithDustInputPayload::from(payload),
4269							Box::new(|output| NewBalanceWithDustVersionedOutputPayload::V1(output.into())),
4270						),
4271					};
4272
4273					let (new_balance, dust) = $crate::Pallet::<Self>::new_balance_with_dust(input.balance)?;
4274					let output = NewBalanceWithDustOutputPayload { new_balance, dust };
4275					Ok(output_wrapper(output))
4276				}
4277
4278				fn block_author_versioned(
4279					input: $crate::pallet_revive_types::runtime_api::BlockAuthorVersionedInputPayload
4280				) -> $crate::pallet_revive_types::runtime_api::BlockAuthorVersionedOutputPayload {
4281					use $crate::pallet_revive_types::runtime_api::*;
4282					use $crate::runtime_api::*;
4283					use alloc::boxed::Box;
4284
4285					let (_input, output_wrapper): (
4286						_,
4287						Box<dyn Fn(BlockAuthorOutputPayload) -> BlockAuthorVersionedOutputPayload>,
4288					) = match input {
4289						BlockAuthorVersionedInputPayload::V1(payload) => (
4290							BlockAuthorInputPayload::from(payload),
4291							Box::new(|output| BlockAuthorVersionedOutputPayload::V1(output.into())),
4292						),
4293					};
4294
4295					let output = BlockAuthorOutputPayload {
4296						block_author: $crate::Pallet::<Self>::block_author()
4297					};
4298					output_wrapper(output)
4299				}
4300
4301				fn address_versioned(
4302					input: $crate::pallet_revive_types::runtime_api::AddressVersionedInputPayload<AccountId>
4303				) -> $crate::pallet_revive_types::runtime_api::AddressVersionedOutputPayload {
4304					use $crate::pallet_revive_types::runtime_api::*;
4305					use $crate::runtime_api::*;
4306					use $crate::AddressMapper;
4307					use alloc::boxed::Box;
4308
4309					let (input, output_wrapper): (
4310						_,
4311						Box<dyn Fn(AddressOutputPayload) -> AddressVersionedOutputPayload>,
4312					) = match input {
4313						AddressVersionedInputPayload::V1(payload) => (
4314							AddressInputPayload::from(payload),
4315							Box::new(|output| AddressVersionedOutputPayload::V1(output.into())),
4316						),
4317					};
4318
4319					let output = AddressOutputPayload {
4320						address: <Self as $crate::Config>::AddressMapper::to_address(&input.account_id)
4321					};
4322					output_wrapper(output)
4323				}
4324
4325				fn trace_block_versioned(
4326					input: $crate::pallet_revive_types::runtime_api::TraceBlockVersionedInputPayload<Block>
4327				) -> $crate::pallet_revive_types::runtime_api::TraceBlockVersionedOutputPayload {
4328					use $crate::{
4329						sp_runtime::traits::Block,
4330						tracing::trace,
4331						evm::TraceEntry,
4332						runtime_api::*,
4333						pallet_revive_types::runtime_api::*
4334					};
4335					use alloc::boxed::Box;
4336
4337					let (input, output_wrapper): (_, Box<dyn Fn(TraceBlockOutputPayload) -> TraceBlockVersionedOutputPayload>) = match input {
4338						TraceBlockVersionedInputPayload::V1(payload) => (
4339							TraceBlockInputPayload::from(payload),
4340							Box::new(|output| TraceBlockVersionedOutputPayload::V1(output.into()))
4341						),
4342						TraceBlockVersionedInputPayload::V2(payload) => (
4343							TraceBlockInputPayload::from(payload),
4344							Box::new(|output| TraceBlockVersionedOutputPayload::V2(output.into()))
4345						),
4346					};
4347
4348					if matches!(input.config, $crate::evm::TracerType::ExecutionTracer(_)) &&
4349						!$crate::DebugSettings::is_execution_tracing_enabled::<Runtime>()
4350					{
4351						return output_wrapper(Default::default())
4352					}
4353
4354					// Faithful proof-size accounting needs a PoV recorder registered for this call
4355					// (e.g. the node's `state_callRecorded` RPC); without one the block tail may hit
4356					// `ExhaustsResources`. V1 drops such traces; V2 reports them as `NotTraced`.
4357					let mut entries = vec![];
4358					let (header, extrinsics) = input.block.deconstruct();
4359					<$Executive>::initialize_block(&header);
4360					for (index, ext) in extrinsics.into_iter().enumerate() {
4361						let mut tracer = $crate::Pallet::<Self>::evm_tracer(input.config.clone());
4362						let t = tracer.as_tracing();
4363						let result = trace(t, || <$Executive>::apply_extrinsic(ext));
4364
4365						if let Some(tx_trace) = tracer.collect_trace() {
4366							entries.push((index as u32, TraceEntry::Traced(tx_trace)));
4367						} else if let Some(entry) = TraceEntry::for_untraced(&result) {
4368							entries.push((index as u32, entry));
4369						}
4370					}
4371
4372					let output = TraceBlockOutputPayload { entries };
4373					output_wrapper(output)
4374				}
4375
4376				fn trace_tx_versioned(
4377					input: $crate::pallet_revive_types::runtime_api::TraceTxVersionedInputPayload<Block>
4378				) -> $crate::pallet_revive_types::runtime_api::TraceTxVersionedOutputPayload {
4379					use $crate::pallet_revive_types::runtime_api::*;
4380					use $crate::runtime_api::*;
4381					use $crate::{evm::TraceEntry, sp_runtime::traits::Block, tracing::trace};
4382					use alloc::boxed::Box;
4383
4384					let (input, output_wrapper): (
4385						_,
4386						Box<dyn Fn(TraceTxOutputPayload) -> TraceTxVersionedOutputPayload>,
4387					) = match input {
4388						TraceTxVersionedInputPayload::V1(payload) => (
4389							TraceTxInputPayload::from(payload),
4390							Box::new(|output| TraceTxVersionedOutputPayload::V1(output.into())),
4391						),
4392						TraceTxVersionedInputPayload::V2(payload) => (
4393							TraceTxInputPayload::from(payload),
4394							Box::new(|output| TraceTxVersionedOutputPayload::V2(output.into())),
4395						),
4396					};
4397
4398					if matches!(&input.config, $crate::evm::TracerType::ExecutionTracer(_)) &&
4399						!$crate::DebugSettings::is_execution_tracing_enabled::<Runtime>()
4400					{
4401						return output_wrapper(TraceTxOutputPayload { entry: None })
4402					}
4403
4404					// Faithful proof-size accounting needs a PoV recorder registered for this call
4405					// (e.g. the node's `state_callRecorded` RPC); without one the block tail may hit
4406					// `ExhaustsResources`. V1 drops such traces; V2 reports them as `NotTraced`.
4407					let mut tracer = $crate::Pallet::<Self>::evm_tracer(input.config);
4408					let (header, extrinsics) = input.block.deconstruct();
4409
4410					<$Executive>::initialize_block(&header);
4411					let mut entry = None;
4412					for (index, ext) in extrinsics.into_iter().enumerate() {
4413						if index as u32 == input.tx_index {
4414							let t = tracer.as_tracing();
4415							let result = trace(t, || <$Executive>::apply_extrinsic(ext));
4416							entry = match tracer.collect_trace() {
4417								Some(tx_trace) => Some(TraceEntry::Traced(tx_trace)),
4418								None => TraceEntry::for_untraced(&result),
4419							};
4420							break;
4421						} else {
4422							let _ = <$Executive>::apply_extrinsic(ext);
4423						}
4424					}
4425
4426					let output = TraceTxOutputPayload { entry };
4427					output_wrapper(output)
4428				}
4429
4430				fn trace_call_versioned(
4431					input: $crate::pallet_revive_types::runtime_api::TraceCallVersionedInputPayload
4432				) -> Result<
4433					$crate::pallet_revive_types::runtime_api::TraceCallVersionedOutputPayload,
4434					$crate::EthTransactError
4435				> {
4436					use $crate::pallet_revive_types::runtime_api::*;
4437					use $crate::runtime_api::*;
4438					use $crate::tracing::trace;
4439					use alloc::boxed::Box;
4440
4441					let (input, output_wrapper): (
4442						_,
4443						Box<dyn Fn(TraceCallOutputPayload) -> TraceCallVersionedOutputPayload>,
4444					) = match input {
4445						TraceCallVersionedInputPayload::V1(payload) => (
4446							TraceCallInputPayload::from(payload),
4447							Box::new(|output| TraceCallVersionedOutputPayload::V1(output.into())),
4448						),
4449						TraceCallVersionedInputPayload::V2(payload) => (
4450							TraceCallInputPayload::from(payload),
4451							Box::new(|output| TraceCallVersionedOutputPayload::V2(output.into())),
4452						),
4453					};
4454
4455					if let Some(overrides) = input.state_overrides {
4456						$crate::state_overrides::apply_state_overrides::<Runtime>(overrides)?;
4457					}
4458
4459					if matches!(input.config, $crate::evm::TracerType::ExecutionTracer(_)) &&
4460						!$crate::DebugSettings::is_execution_tracing_enabled::<Runtime>()
4461					{
4462						return Err($crate::EthTransactError::Message("Execution Tracing is disabled".into()))
4463					}
4464
4465					let mut tracer = $crate::Pallet::<Self>::evm_tracer(input.config.clone());
4466					let t = tracer.as_tracing();
4467
4468					t.watch_address(&input.tx.from.unwrap_or_default());
4469					t.watch_address(&$crate::Pallet::<Self>::block_author());
4470					let result = trace(t, || {
4471						$crate::Pallet::<Self>::dry_run_eth_transact(input.tx, None, true, None)
4472					});
4473
4474					let trace = if let Some(trace) = tracer.collect_trace() {
4475						Ok(trace)
4476					} else if let Err(err) = result {
4477						Err(err)
4478					} else {
4479						Ok($crate::Pallet::<Self>::evm_tracer(input.config).empty_trace())
4480					}?;
4481
4482					let output = TraceCallOutputPayload { trace };
4483					Ok(output_wrapper(output))
4484				}
4485			}
4486		}
4487	};
4488}