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