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