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