diff --git a/Cargo.lock b/Cargo.lock
index f8c62061fb23d..32e6b0d150cb4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -12740,6 +12740,7 @@ dependencies = [
"sp-tracing 16.0.0",
"staging-xcm",
"staging-xcm-builder",
+ "staging-xcm-executor",
"substrate-bn",
"subxt-signer 0.38.0",
]
@@ -12797,6 +12798,7 @@ dependencies = [
name = "pallet-revive-mock-network"
version = "0.1.0"
dependencies = [
+ "alloy-core",
"frame-support",
"frame-system",
"pallet-assets",
diff --git a/substrate/frame/revive/Cargo.toml b/substrate/frame/revive/Cargo.toml
index 7c88a0a5c41db..5474888c11fb2 100644
--- a/substrate/frame/revive/Cargo.toml
+++ b/substrate/frame/revive/Cargo.toml
@@ -36,7 +36,10 @@ rand = { workspace = true, optional = true }
rand_pcg = { workspace = true, optional = true }
rlp = { workspace = true }
scale-info = { features = ["derive"], workspace = true }
-serde = { features = ["alloc", "derive"], workspace = true, default-features = false }
+serde = { features = [
+ "alloc",
+ "derive",
+], workspace = true, default-features = false }
# Polkadot SDK Dependencies
bn = { workspace = true }
@@ -56,9 +59,12 @@ sp-consensus-slots = { workspace = true, optional = true }
sp-core = { workspace = true }
sp-io = { workspace = true }
sp-runtime = { workspace = true }
-subxt-signer = { workspace = true, optional = true, features = ["unstable-eth"] }
+subxt-signer = { workspace = true, optional = true, features = [
+ "unstable-eth",
+] }
xcm = { workspace = true }
xcm-builder = { workspace = true }
+xcm-executor = { workspace = true }
[dev-dependencies]
array-bytes = { workspace = true, default-features = true }
@@ -77,6 +83,7 @@ pallet-utility = { workspace = true, default-features = true }
sp-keystore = { workspace = true, default-features = true }
sp-tracing = { workspace = true, default-features = true }
xcm-builder = { workspace = true, default-features = true }
+xcm-executor = { workspace = true }
[features]
default = ["std"]
@@ -118,6 +125,7 @@ std = [
"sp-runtime/std",
"subxt-signer",
"xcm-builder/std",
+ "xcm-executor/std",
"xcm/std",
]
runtime-benchmarks = [
diff --git a/substrate/frame/revive/mock-network/Cargo.toml b/substrate/frame/revive/mock-network/Cargo.toml
index becce626e7298..833fa2f77385b 100644
--- a/substrate/frame/revive/mock-network/Cargo.toml
+++ b/substrate/frame/revive/mock-network/Cargo.toml
@@ -35,6 +35,7 @@ xcm = { workspace = true }
xcm-builder = { workspace = true, default-features = true }
xcm-executor = { workspace = true }
xcm-simulator = { workspace = true, default-features = true }
+alloy-core = { workspace = true, features = ["sol-types"] }
[dev-dependencies]
pallet-revive-fixtures = { workspace = true }
@@ -42,6 +43,7 @@ pallet-revive-fixtures = { workspace = true }
[features]
default = ["std"]
std = [
+ "alloy-core/std",
"codec/std",
"frame-support/std",
"frame-system/std",
diff --git a/substrate/frame/revive/mock-network/src/parachain/contracts_config.rs b/substrate/frame/revive/mock-network/src/parachain/contracts_config.rs
index c2ddb8fb750fe..d0ec1b98bcdf1 100644
--- a/substrate/frame/revive/mock-network/src/parachain/contracts_config.rs
+++ b/substrate/frame/revive/mock-network/src/parachain/contracts_config.rs
@@ -15,8 +15,15 @@
// along with Substrate. If not, see .
use super::{Balances, Runtime, RuntimeCall, RuntimeEvent};
-use crate::parachain::RuntimeHoldReason;
+use crate::parachain::{parameter_types, MaxInstructions, RuntimeHoldReason};
use frame_support::derive_impl;
+use pallet_revive::precompiles::XcmPrecompile;
+use xcm::latest::Weight;
+use xcm_builder::FixedWeightBounds;
+
+parameter_types! {
+ pub const BaseXcmWeight: xcm::latest::Weight = Weight::from_parts(100_000_000, 2_000);
+}
#[derive_impl(pallet_revive::config_preludes::TestDefaultConfig)]
impl pallet_revive::Config for Runtime {
@@ -24,4 +31,6 @@ impl pallet_revive::Config for Runtime {
type Currency = Balances;
type Time = super::Timestamp;
type Xcm = pallet_xcm::Pallet;
+ type Precompiles = (XcmPrecompile,);
+ type XcmWeigher = FixedWeightBounds;
}
diff --git a/substrate/frame/revive/mock-network/src/tests.rs b/substrate/frame/revive/mock-network/src/tests.rs
index 34f797c2b530f..a78c87983e3bd 100644
--- a/substrate/frame/revive/mock-network/src/tests.rs
+++ b/substrate/frame/revive/mock-network/src/tests.rs
@@ -19,21 +19,22 @@ use crate::{
parachain, parachain_account_sovereign_account_id, primitives::CENTS, relay_chain, MockNet,
ParaA, ParachainBalances, Relay, ALICE, BOB, INITIAL_BALANCE,
};
+use alloy_core::sol_types::{SolInterface, SolValue};
use codec::{Decode, Encode};
use frame_support::traits::{fungibles::Mutate, Currency};
use frame_system::RawOrigin;
use pallet_revive::{
test_utils::{self, builder::*},
- Code, DepositLimit,
+ Code, DepositLimit, ExecReturnValue, IXcm,
};
use pallet_revive_fixtures::compile_module;
-use pallet_revive_uapi::ReturnErrorCode;
+use pallet_revive_uapi::{ReturnErrorCode, ReturnFlags};
use sp_core::H160;
use xcm::{v4::prelude::*, VersionedLocation, VersionedXcm};
use xcm_simulator::TestExt;
macro_rules! assert_return_code {
- ( $x:expr , $y:expr $(,)? ) => {{
+ ($x:expr, $y:expr $(,)?) => {{
assert_eq!(u32::from_le_bytes($x.data[..].try_into().unwrap()), $y as u32);
}};
}
@@ -61,6 +62,7 @@ fn instantiate_test_contract(name: &str) -> Contract {
parachain::Balances::make_free_balance_be(&contract.account_id, INITIAL_BALANCE);
parachain::Assets::mint_into(0u32.into(), &contract.account_id, INITIAL_BALANCE).unwrap();
});
+
Relay::execute_with(|| {
let sovereign_account =
parachain_account_sovereign_account_id(1u32, contract.account_id.clone());
@@ -70,6 +72,14 @@ fn instantiate_test_contract(name: &str) -> Contract {
contract
}
+fn to_fixed_non_zero(precompile_id: u16) -> H160 {
+ let mut address = [0u8; 20];
+ address[16] = (precompile_id >> 8) as u8;
+ address[17] = (precompile_id & 0xFF) as u8;
+
+ H160::from(address)
+}
+
#[test]
fn test_xcm_execute() {
MockNet::reset();
@@ -148,7 +158,6 @@ fn test_xcm_execute_reentrant_call() {
value: 0u128,
});
- // The XCM used to transfer funds to Bob.
let message: Xcm = Xcm::builder_unsafe()
.transact(OriginKind::Native, 1_000_000_000, transact_call.encode())
.expect_transact_status(MaybeErrorCode::Success)
@@ -202,3 +211,271 @@ fn test_xcm_send() {
assert_eq!(INITIAL_BALANCE + amount - fee, relay_chain::Balances::free_balance(ALICE));
});
}
+
+#[test]
+fn test_xcm_execute_reentrant_call_via_precompile() {
+ MockNet::reset();
+
+ ParaA::execute_with(|| {
+ let initial_bob_balance = ParachainBalances::free_balance(BOB);
+
+ let transact_call = parachain::RuntimeCall::Contracts(pallet_revive::Call::call {
+ dest: to_fixed_non_zero(10),
+ gas_limit: 1_000_000.into(),
+ storage_deposit_limit: test_utils::deposit_limit::(),
+ data: vec![],
+ value: 0u128,
+ });
+
+ let message: Xcm = Xcm::builder_unsafe()
+ .transact(OriginKind::Native, 1_000_000_000, transact_call.encode())
+ .expect_transact_status(MaybeErrorCode::Success)
+ .build();
+
+ let weight_params =
+ IXcm::weighMessageCall { message: VersionedXcm::V4(message.clone()).encode().into() };
+ let weight_call = IXcm::IXcmCalls::weighMessage(weight_params);
+ let xcm_weight_results =
+ bare_call(to_fixed_non_zero(10)).data(weight_call.abi_encode()).build();
+
+ let weight_result = match xcm_weight_results.result {
+ Ok(value) => value,
+ Err(_) => ExecReturnValue { flags: ReturnFlags::REVERT, data: Vec::new() },
+ };
+
+ let weight: IXcm::Weight =
+ IXcm::Weight::abi_decode(&weight_result.data[..], true).expect("Failed to weight");
+
+ let xcm_execute_params =
+ IXcm::xcmExecuteCall { message: VersionedXcm::V4(message).encode().into(), weight };
+
+ let call = IXcm::IXcmCalls::xcmExecute(xcm_execute_params);
+ let encoded_call = call.abi_encode();
+ let results = bare_call(to_fixed_non_zero(10)).data(encoded_call).build();
+ let result = match results.result {
+ Ok(value) => value,
+ Err(_) => ExecReturnValue { flags: ReturnFlags::REVERT, data: Vec::new() },
+ };
+
+ let final_bob_balance = ParachainBalances::free_balance(BOB);
+
+ assert_eq!(
+ result.flags,
+ ReturnFlags::REVERT,
+ "Expected transaction to revert due to reentrant call"
+ );
+ assert_eq!(final_bob_balance, initial_bob_balance, "Bob's balance should remain unchanged");
+ });
+}
+
+#[test]
+fn test_xcm_execute_incomplete_call_via_precompile() {
+ MockNet::reset();
+ let amount = 10 * CENTS;
+
+ ParaA::execute_with(|| {
+ let initial_bob_balance = ParachainBalances::free_balance(BOB);
+ let initial_alice_balance = ParachainBalances::free_balance(ALICE);
+
+ let assets: Asset = (Here, amount).into();
+ let beneficiary = AccountId32 { network: None, id: BOB.clone().into() };
+
+ let message: Xcm<()> = Xcm::builder_unsafe()
+ .withdraw_asset(assets.clone())
+ // This will fail as the contract does not have enough balance to complete both
+ // withdrawals.
+ .withdraw_asset((Here, INITIAL_BALANCE))
+ .buy_execution(assets.clone(), Unlimited)
+ .deposit_asset(assets, beneficiary)
+ .build();
+
+ // First, calculate the weight of the XCM message
+ let weight_params =
+ IXcm::weighMessageCall { message: VersionedXcm::V4(message.clone()).encode().into() };
+ let weight_call = IXcm::IXcmCalls::weighMessage(weight_params);
+ let xcm_weight_results =
+ bare_call(to_fixed_non_zero(10)).data(weight_call.abi_encode()).build();
+
+ let weight_result = match xcm_weight_results.result {
+ Ok(value) => value,
+ Err(_) => ExecReturnValue { flags: ReturnFlags::REVERT, data: Vec::new() },
+ };
+
+ let weight: IXcm::Weight =
+ IXcm::Weight::abi_decode(&weight_result.data[..], true).expect("Failed to weight");
+
+ let xcm_execute_params =
+ IXcm::xcmExecuteCall { message: VersionedXcm::V4(message).encode().into(), weight };
+
+ let call = IXcm::IXcmCalls::xcmExecute(xcm_execute_params);
+ let encoded_call = call.abi_encode();
+ bare_call(to_fixed_non_zero(10)).data(encoded_call).build();
+
+ let final_bob_balance = ParachainBalances::free_balance(BOB);
+ let final_alice_balance = ParachainBalances::free_balance(ALICE);
+
+ assert_eq!(final_bob_balance, initial_bob_balance, "Bob's balance should remain unchanged");
+ assert_eq!(
+ final_alice_balance, initial_alice_balance,
+ "Alice's balance should remain unchanged"
+ );
+ });
+}
+
+#[test]
+fn test_xcm_execute_precompile() {
+ MockNet::reset();
+ let amount: u128 = 10 * CENTS;
+
+ ParaA::execute_with(|| {
+ let initial_alice_balance = ParachainBalances::free_balance(ALICE);
+ let initial_bob_balance = ParachainBalances::free_balance(BOB);
+
+ let assets: Asset = (Here, amount).into();
+ let beneficiary = AccountId32 { network: None, id: BOB.clone().into() };
+
+ let message: Xcm<()> = Xcm::builder_unsafe()
+ .withdraw_asset(assets.clone())
+ .deposit_asset(assets, beneficiary)
+ .build();
+
+ let weight_params =
+ IXcm::weighMessageCall { message: VersionedXcm::V4(message.clone()).encode().into() };
+ let weight_call = IXcm::IXcmCalls::weighMessage(weight_params);
+ let xcm_weight_results =
+ bare_call(to_fixed_non_zero(10)).data(weight_call.abi_encode()).build();
+
+ let weight_result = match xcm_weight_results.result {
+ Ok(value) => value,
+ Err(_) => ExecReturnValue { flags: ReturnFlags::REVERT, data: Vec::new() },
+ };
+
+ let weight: IXcm::Weight =
+ IXcm::Weight::abi_decode(&weight_result.data[..], true).expect("Failed to weight");
+
+ let xcm_execute_params =
+ IXcm::xcmExecuteCall { message: VersionedXcm::V4(message).encode().into(), weight };
+
+ let call = IXcm::IXcmCalls::xcmExecute(xcm_execute_params);
+ let encoded_call = call.abi_encode();
+
+ bare_call(to_fixed_non_zero(10)).data(encoded_call).build();
+
+ let final_alice_balance = ParachainBalances::free_balance(ALICE);
+ let final_bob_balance = ParachainBalances::free_balance(BOB);
+
+ assert_eq!(
+ final_bob_balance,
+ initial_bob_balance + amount,
+ "Bob's balance should increase by the specified amount"
+ );
+ assert_eq!(
+ final_alice_balance,
+ initial_alice_balance - amount,
+ "Alice's balance should decrease by the specified amount"
+ );
+ });
+}
+
+#[test]
+fn test_xcm_send_precompile() {
+ MockNet::reset();
+ let amount = 1_000 * CENTS;
+ let fee: u128 = parachain::estimate_message_fee(4);
+
+ let sovereign_account_id = ParaA::execute_with(|| {
+ let sovereign_account_id = parachain_account_sovereign_account_id(1, ALICE.clone());
+ let initial_sovereign_balance =
+ Relay::execute_with(|| relay_chain::Balances::free_balance(&sovereign_account_id));
+
+ let initial_alice_relay_balance =
+ Relay::execute_with(|| relay_chain::Balances::free_balance(ALICE));
+
+ let dest = VersionedLocation::V4(Parent.into());
+ let assets: Asset = (Here, amount).into();
+ let beneficiary = AccountId32 { network: None, id: ALICE.clone().into() };
+
+ let message: Xcm<()> = Xcm::builder()
+ .withdraw_asset(assets.clone())
+ .buy_execution((Here, fee), Unlimited)
+ .deposit_asset(assets, beneficiary)
+ .build();
+
+ let xcm_send_params = IXcm::xcmSendCall {
+ destination: dest.encode().into(),
+ message: VersionedXcm::V4(message).encode().into(),
+ };
+
+ let call = IXcm::IXcmCalls::xcmSend(xcm_send_params);
+ let encoded_call = call.abi_encode();
+ let results = bare_call(to_fixed_non_zero(10)).data(encoded_call).build();
+ let result = results.result.expect("Transaction should succeed");
+ let mut data = &result.data[..];
+ XcmHash::decode(&mut data).expect("Failed to decode xcm_send message_id");
+
+ (sovereign_account_id, initial_sovereign_balance, initial_alice_relay_balance)
+ });
+
+ Relay::execute_with(|| {
+ let (sovereign_account_id, initial_sovereign_balance, initial_alice_relay_balance) =
+ sovereign_account_id;
+
+ let final_sovereign_balance = relay_chain::Balances::free_balance(&sovereign_account_id);
+ assert_eq!(
+ final_sovereign_balance,
+ initial_sovereign_balance - amount,
+ "Sovereign account balance should decrease by the amount sent"
+ );
+
+ let final_alice_balance = relay_chain::Balances::free_balance(ALICE);
+ assert_eq!(
+ final_alice_balance,
+ initial_alice_relay_balance + amount - fee,
+ "Alice's balance should increase by amount minus fee"
+ );
+ });
+}
+
+#[test]
+fn test_xcm_send_precompile_via_fixture() {
+ MockNet::reset();
+ let amount = 1_000 * CENTS;
+ let fee: u128 = parachain::estimate_message_fee(4);
+ let Contract { addr, .. } = instantiate_test_contract("call_and_return");
+
+ ParaA::execute_with(|| {
+ let dest = VersionedLocation::V4(Parent.into());
+ let assets: Asset = (Here, amount).into();
+ let beneficiary = AccountId32 { network: None, id: ALICE.clone().into() };
+
+ let message: Xcm<()> = Xcm::builder()
+ .withdraw_asset(assets.clone())
+ .buy_execution((Here, fee), Unlimited)
+ .deposit_asset(assets, beneficiary)
+ .build();
+
+ let xcm_send_params = IXcm::xcmSendCall {
+ destination: dest.encode().into(),
+ message: VersionedXcm::V4(message).encode().into(),
+ };
+
+ let call = IXcm::IXcmCalls::xcmSend(xcm_send_params);
+ let encoded_call = call.abi_encode();
+ let result = bare_call(addr)
+ .data(
+ (to_fixed_non_zero(10), 5000u64)
+ .encode()
+ .into_iter()
+ .chain(encoded_call)
+ .collect::>(),
+ )
+ .build_and_unwrap_result();
+
+ let mut data = &result.data[..];
+ XcmHash::decode(&mut data).expect("Failed to decode xcm_send message_id");
+ });
+
+ Relay::execute_with(|| {
+ assert_eq!(INITIAL_BALANCE + amount - fee, relay_chain::Balances::free_balance(ALICE));
+ });
+}
diff --git a/substrate/frame/revive/src/lib.rs b/substrate/frame/revive/src/lib.rs
index 3ffb88c6b8a87..c6a11c707d5ea 100644
--- a/substrate/frame/revive/src/lib.rs
+++ b/substrate/frame/revive/src/lib.rs
@@ -41,6 +41,7 @@ pub mod precompiles;
pub mod test_utils;
pub mod tracing;
pub mod weights;
+pub use precompiles::{IXcm, XcmPrecompile};
use crate::{
evm::{
@@ -267,6 +268,12 @@ pub mod pallet {
BlockNumberFor,
>;
+ /// The weigher used to calculate XCM execution costs
+ #[pallet::no_default_bounds]
+ type XcmWeigher: xcm_executor::traits::WeightBounds<
+ ::RuntimeCall,
+ >;
+
/// The amount of memory in bytes that parachain nodes a lot to the runtime.
///
/// This is used in [`Pallet::integrity_test`] to make sure that the runtime has enough
@@ -355,6 +362,7 @@ pub mod pallet {
type RuntimeCall = ();
type CallFilter = ();
type Precompiles = ();
+ type XcmWeigher = ();
type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent;
type DepositPerByte = DepositPerByte;
type DepositPerItem = DepositPerItem;
diff --git a/substrate/frame/revive/src/precompiles.rs b/substrate/frame/revive/src/precompiles.rs
index c12527cee6646..d23986fd45f3f 100644
--- a/substrate/frame/revive/src/precompiles.rs
+++ b/substrate/frame/revive/src/precompiles.rs
@@ -25,7 +25,9 @@
//!
//! Use `alloy` through our re-export in this module to implement Eth ABI.
-mod builtin;
+pub mod builtin;
+mod xcm;
+pub use xcm::{IXcm, XcmPrecompile};
mod tests;
diff --git a/substrate/frame/revive/src/precompiles/xcm.rs b/substrate/frame/revive/src/precompiles/xcm.rs
new file mode 100644
index 0000000000000..7e09eacb29c99
--- /dev/null
+++ b/substrate/frame/revive/src/precompiles/xcm.rs
@@ -0,0 +1,169 @@
+// This file is part of Substrate.
+
+// Copyright (C) Parity Technologies (UK) Ltd.
+// SPDX-License-Identifier: Apache-2.0
+
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use crate::{
+ precompiles::{AddressMatcher, Error, Ext, ExtWithInfo, Precompile},
+ Config, Origin, RuntimeCosts,
+};
+use alloc::vec::Vec;
+use alloy_core::{sol, sol_types::SolValue};
+use codec::{DecodeAll, Encode};
+use core::{marker::PhantomData, num::NonZero};
+use log::error;
+use sp_runtime::Weight;
+use xcm_builder::{ExecuteController, SendController, SendControllerWeightInfo};
+use xcm_executor::traits::WeightBounds;
+pub use IXcm::IXcmCalls;
+
+pub struct XcmPrecompile(PhantomData);
+
+sol! {
+ /// @title Defines all functions that can be used to interact with XCM
+ /// @author Tiago Bandeira
+ /// @dev Parameters MUST use SCALE codec serialisation
+ interface IXcm {
+ struct Weight {
+ uint64 refTime;
+ uint64 proofSize;
+ }
+
+ /// @notice Execute an XCM message locally with the caller's origin
+ /// @param message The XCM message to send
+ /// @param weight The maximum amount of weight to be used to execute the message
+ function xcmExecute(bytes calldata message, Weight calldata weight) external;
+
+ /// @notice Send an XCM message to a destination chain
+ /// @param destination The destination location, encoded according to the XCM format
+ /// @param message The XCM message to send
+ function xcmSend(bytes calldata destination, bytes calldata message) external;
+
+ /// @notice Given a message estimate the weight cost
+ /// @param message The XCM message to send
+ /// @returns weight estimated for sending the message
+ function weighMessage(bytes calldata message) external view returns(Weight weight);
+ }
+}
+
+impl Precompile for XcmPrecompile {
+ type T = T;
+ const MATCHER: AddressMatcher = AddressMatcher::Fixed(NonZero::new(10).unwrap());
+ const HAS_CONTRACT_INFO: bool = false;
+ type Interface = IXcm::IXcmCalls;
+
+ fn call(
+ _address: &[u8; 20],
+ input: &Self::Interface,
+ env: &mut impl Ext,
+ ) -> Result, Error> {
+ let origin = env.caller();
+ let frame_origin = match origin {
+ Origin::Root => frame_system::RawOrigin::Root.into(),
+ Origin::Signed(account_id) =>
+ frame_system::RawOrigin::Signed(account_id.clone()).into(),
+ };
+
+ match input {
+ IXcmCalls::xcmSend(IXcm::xcmSendCall { destination, message }) => {
+ let final_destination = xcm::VersionedLocation::decode_all(&mut &destination[..])
+ .map_err(|e| {
+ error!("XCM send failed: Invalid destination format. Error: {e:?}");
+ Error::Revert("Invalid destination format".into())
+ })?;
+
+ let final_message = xcm::VersionedXcm::<()>::decode_all(&mut &message[..])
+ .map_err(|e| {
+ error!("XCM send failed: Invalid message format. Error: {e:?}");
+ Error::Revert("Invalid message format".into())
+ })?;
+
+ let weight = <::Xcm as SendController<_>>::WeightInfo::send();
+ env.gas_meter_mut().charge(RuntimeCosts::CallRuntime(weight))?;
+
+ <::Xcm>::send(
+ frame_origin,
+ final_destination.into(),
+ final_message.into(),
+ )
+ .map(|message_id| message_id.encode())
+ .map_err(|e| {
+ error!(
+ "XCM send failed: destination or message format may be incompatible. \
+ Error: {e:?}"
+ );
+ Error::Revert(
+ "XCM send failed: destination or message format may be incompatible".into(),
+ )
+ })
+ },
+ IXcmCalls::xcmExecute(IXcm::xcmExecuteCall { message, weight }) => {
+ let final_message =
+ xcm::VersionedXcm::decode_all(&mut &message[..]).map_err(|e| {
+ error!("XCM execute failed: Invalid message format. Error: {e:?}");
+ Error::Revert("Invalid message format".into())
+ })?;
+
+ let weight = Weight::from_parts(weight.refTime, weight.proofSize);
+ env.gas_meter_mut().charge(RuntimeCosts::CallXcmExecute(weight.clone()))?;
+
+ <::Xcm>::execute(frame_origin, final_message.into(), weight)
+ .map(|results| results.encode())
+ .map_err(|e| {
+ error!(
+ "XCM execute failed: message may be invalid or execution \
+ constraints not satisfied. Error: {e:?}"
+ );
+ Error::Revert(
+ "XCM execute failed: message may be invalid or execution \
+ constraints not satisfied"
+ .into(),
+ )
+ })
+ },
+ IXcmCalls::weighMessage(IXcm::weighMessageCall { message }) => {
+ let converted_message =
+ xcm::VersionedXcm::decode_all(&mut &message[..]).map_err(|error| {
+ error!("XCM weighMessage: Invalid message format. Error: {error:?}");
+ Error::Revert("XCM weighMessage: Invalid message format".into())
+ })?;
+
+ let mut final_message = converted_message.try_into().map_err(|e| {
+ error!("XCM weighMessage: Conversion to Xcm failed with Error: {e:?}");
+ Error::Revert("XCM weighMessage: Conversion to Xcm failed".into())
+ })?;
+
+ let weight =
+ <::XcmWeigher>::weight(&mut final_message).map_err(|e| {
+ error!("XCM weighMessage: Failed to calculate weight. Error: {e:?}");
+ Error::Revert("XCM weighMessage: Failed to calculate weight".into())
+ })?;
+
+ let final_weight =
+ IXcm::Weight { proofSize: weight.proof_size(), refTime: weight.ref_time() };
+
+ Ok(final_weight.abi_encode())
+ },
+ }
+ }
+
+ fn call_with_info(
+ _address: &[u8; 20],
+ _input: &Self::Interface,
+ _env: &mut impl ExtWithInfo,
+ ) -> Result, Error> {
+ Err(Error::Revert("call_with_info not implemented for XcmPrecompile".into()))
+ }
+}