moonbeam_runtime_common/
impl_xcm_evm_runner.rs

1// Copyright 2019-2025 PureStake Inc.
2// This file is part of Moonbeam.
3
4// Moonbeam is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Moonbeam is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Moonbeam.  If not, see <http://www.gnu.org/licenses/>.
16
17#[macro_export]
18macro_rules! impl_evm_runner_precompile_or_eth_xcm {
19	{} => {
20		use ethereum::AuthorizationList;
21		use fp_evm::{CallInfo, CallOrCreateInfo, Context, Transfer};
22		use frame_support::dispatch::CallableCallFor;
23		use pallet_evm::{Runner, RunnerError};
24		use precompile_utils::{prelude::*, evm::handle::with_precompile_handle};
25		use sp_core::U256;
26		use sp_runtime::DispatchError;
27		use sp_std::vec::Vec;
28		use xcm_primitives::{EthereumXcmTransaction, EthereumXcmTransactionV3};
29
30		pub struct EvmRunnerPrecompileOrEthXcm<CallDispatcher, Runtime>(
31			core::marker::PhantomData<(CallDispatcher, Runtime)>,
32		);
33
34		impl<CallDispatcher, Runtime> Runner<Runtime>
35			for EvmRunnerPrecompileOrEthXcm<CallDispatcher, Runtime>
36		where
37			CallDispatcher: xcm_executor::traits::CallDispatcher<RuntimeCall>,
38			Runtime: pallet_evm::Config + pallet_ethereum_xcm::Config,
39			Runtime::RuntimeOrigin: From<pallet_ethereum_xcm::RawOrigin>,
40		{
41			type Error = DispatchError;
42
43			fn call(
44				source: H160,
45				target: H160,
46				input: Vec<u8>,
47				value: U256,
48				gas_limit: u64,
49				_max_fee_per_gas: Option<U256>,
50				_max_priority_fee_per_gas: Option<U256>,
51				_nonce: Option<U256>,
52				access_list: Vec<(H160, Vec<H256>)>,
53				authorization_list: AuthorizationList,
54				_is_transactional: bool,
55				_validate: bool,
56				_weight_limit: Option<Weight>,
57				_transaction_len: Option<u64>,
58				_config: &fp_evm::Config,
59			) -> Result<CallInfo, RunnerError<Self::Error>> {
60				// The `with_precompile_handle` function will execute the closure (and return the
61				// result in a Some) if and only if there is an available EVM context. Otherwise,
62				// it will return None.
63				if let Some((exit_reason, value)) = with_precompile_handle(|precompile_handle| {
64					let transfer = if value.is_zero() {
65						None
66					} else {
67						Some(Transfer {
68							source,
69							target,
70							value,
71						})
72					};
73
74					precompile_handle.call(
75						target,
76						transfer,
77						input.clone(),
78						Some(gas_limit),
79						false,
80						&Context {
81							address: target,
82							caller: source,
83							apparent_value: value,
84						},
85					)
86				}) {
87					Ok(CallInfo {
88						exit_reason,
89						value,
90						used_gas: fp_evm::UsedGas {
91							standard: U256::default(),
92							effective: U256::default(),
93						},
94						logs: Default::default(),
95						weight_info: None,
96					})
97				} else {
98					let xcm_transaction = EthereumXcmTransaction::V3(EthereumXcmTransactionV3 {
99						gas_limit: gas_limit.into(),
100						action: pallet_ethereum_xcm::TransactionAction::Call(target),
101						value,
102						input: input.try_into().map_err(|_| RunnerError {
103							error: DispatchError::Exhausted,
104							weight: Default::default(),
105						})?,
106						access_list: Some(access_list),
107						authorization_list: Some(authorization_list),
108					});
109
110					let mut execution_info: Option<CallOrCreateInfo> = None;
111					pallet_ethereum::catch_exec_info(&mut execution_info, || {
112						CallDispatcher::dispatch(
113							RuntimeCall::EthereumXcm(pallet_ethereum_xcm::Call::transact { xcm_transaction }),
114							RawOrigin::Signed(source.into()).into(),
115						)
116						.map_err(|DispatchErrorWithPostInfo { error, .. }| RunnerError {
117							error,
118							weight: Default::default(),
119						})
120					})?;
121
122					if let Some(CallOrCreateInfo::Call(call_info))= execution_info {
123						Ok(call_info)
124					} else {
125						// `execution_info` must have been filled in
126						Err(RunnerError {
127							error: DispatchError::Unavailable,
128							weight: Default::default(),
129						})
130					}
131				}
132			}
133
134			fn create(
135				_source: H160,
136				_init: Vec<u8>,
137				_value: U256,
138				_gas_limit: u64,
139				_max_fee_per_gas: Option<U256>,
140				_max_priority_fee_per_gas: Option<U256>,
141				_nonce: Option<U256>,
142				_access_list: Vec<(H160, Vec<H256>)>,
143				_authorization_list: AuthorizationList,
144				_is_transactional: bool,
145				_validate: bool,
146				_weight_limit: Option<Weight>,
147				_transaction_len: Option<u64>,
148				_config: &fp_evm::Config,
149			) -> Result<fp_evm::CreateInfo, RunnerError<Self::Error>> {
150				unimplemented!()
151			}
152
153			fn create2(
154				_source: H160,
155				_init: Vec<u8>,
156				_salt: H256,
157				_value: U256,
158				_gas_limit: u64,
159				_max_fee_per_gas: Option<U256>,
160				_max_priority_fee_per_gas: Option<U256>,
161				_nonce: Option<U256>,
162				_access_list: Vec<(H160, Vec<H256>)>,
163				_authorization_list: AuthorizationList,
164				_is_transactional: bool,
165				_validate: bool,
166				_weight_limit: Option<Weight>,
167				_transaction_len: Option<u64>,
168				_config: &fp_evm::Config,
169			) -> Result<fp_evm::CreateInfo, RunnerError<Self::Error>> {
170				unimplemented!()
171			}
172
173			fn create_force_address(
174				source: H160,
175				init: Vec<u8>,
176				value: U256,
177				gas_limit: u64,
178				max_fee_per_gas: Option<U256>,
179				max_priority_fee_per_gas: Option<U256>,
180				nonce: Option<U256>,
181				access_list: Vec<(H160, Vec<H256>)>,
182				authorization_list: AuthorizationList,
183				is_transactional: bool,
184				validate: bool,
185				weight_limit: Option<Weight>,
186				transaction_len: Option<u64>,
187				config: &fp_evm::Config,
188				force_address: H160,
189			) -> Result<fp_evm::CreateInfo, RunnerError<Self::Error>> {
190				let xcm_transaction = EthereumXcmTransaction::V3(EthereumXcmTransactionV3 {
191					gas_limit: gas_limit.into(),
192					action: pallet_ethereum_xcm::TransactionAction::Create,
193					value,
194					input: init.try_into().map_err(|_| RunnerError {
195						error: DispatchError::Exhausted,
196						weight: Default::default(),
197					})?,
198					access_list: Some(access_list),
199					authorization_list: Some(authorization_list),
200				});
201
202				let mut execution_info: Option<CallOrCreateInfo> = None;
203				pallet_ethereum::catch_exec_info(&mut execution_info, || {
204					CallDispatcher::dispatch(
205						RuntimeCall::EthereumXcm(pallet_ethereum_xcm::Call::force_transact_as {
206							transact_as: source,
207							xcm_transaction,
208							force_create_address: Some(force_address),
209						}),
210						RawOrigin::Root.into(),
211					)
212					.map_err(|DispatchErrorWithPostInfo { error, .. }| RunnerError {
213						error,
214						weight: Default::default(),
215					})
216				})?;
217
218				if let Some(CallOrCreateInfo::Create(create_info))= execution_info {
219					Ok(create_info)
220				} else {
221					// `execution_info` must have been filled in
222					Err(RunnerError {
223						error: DispatchError::Unavailable,
224						weight: Default::default(),
225					})
226				}
227			}
228
229			fn validate(
230				_source: H160,
231				_target: Option<H160>,
232				_input: Vec<u8>,
233				_value: U256,
234				_gas_limit: u64,
235				_max_fee_per_gas: Option<U256>,
236				_max_priority_fee_per_gas: Option<U256>,
237				_nonce: Option<U256>,
238				_access_list: Vec<(H160, Vec<H256>)>,
239				_authorization_list: Vec<(U256, H160, U256, Option<H160>)>,
240				_is_transactional: bool,
241				_weight_limit: Option<Weight>,
242				_transaction_len: Option<u64>,
243				_evm_config: &fp_evm::Config,
244			) -> Result<(), RunnerError<Self::Error>> {
245				unimplemented!()
246			}
247		}
248
249	}
250}