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