diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index d186507dab179..f0e3613914f64 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -239,6 +239,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = (); + type XcmEventEmitter = (); type AssetTransactor = (); type OriginConverter = BridgeHubLocationXcmOriginAsRoot; type IsReserve = (); diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs index 0c6ff5e4bfddc..0c0ed1e7b28c3 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/xcm_config.rs @@ -360,6 +360,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; type AssetTransactor = AssetTransactors; type OriginConverter = XcmOriginToTransactDispatchOrigin; // Asset Hub trusts only particular, pre-configured bridged locations from a different consensus diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs index 1ea2ce5136abd..a686039bb4913 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/xcm_config.rs @@ -380,6 +380,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; type AssetTransactor = AssetTransactors; type OriginConverter = XcmOriginToTransactDispatchOrigin; // Asset Hub trusts only particular, pre-configured bridged locations from a different consensus diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs index b37945317f6cf..ddb8edcc624ea 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs @@ -178,6 +178,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; type AssetTransactor = FungibleTransactor; type OriginConverter = XcmOriginToTransactDispatchOrigin; // BridgeHub does not recognize a reserve location for any asset. Users must teleport Native diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs index befb63ef97098..dbd9c1e7e9ae8 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs @@ -175,6 +175,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; type AssetTransactor = FungibleTransactor; type OriginConverter = XcmOriginToTransactDispatchOrigin; // BridgeHub does not recognize a reserve location for any asset. Users must teleport Native diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs index c5ab21fe8f904..1d47e14871c32 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs @@ -194,6 +194,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; type AssetTransactor = FungibleTransactor; type OriginConverter = XcmOriginToTransactDispatchOrigin; // Collectives does not recognize a reserve location for any asset. Users must teleport WND diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs index 532ad4ff4ce00..f9880c108c3a5 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs @@ -178,6 +178,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; type AssetTransactor = FungibleTransactor; type OriginConverter = XcmOriginToTransactDispatchOrigin; type IsReserve = NativeAsset; diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs index 33ad172962a15..552904b328ebe 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs @@ -187,6 +187,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; type AssetTransactor = AssetTransactors; type OriginConverter = XcmOriginToTransactDispatchOrigin; // Coretime chain does not recognize a reserve location for any asset. Users must teleport ROC diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs index 8a4879a1506ee..5b8207c91f0c6 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs @@ -201,6 +201,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; type AssetTransactor = AssetTransactors; type OriginConverter = XcmOriginToTransactDispatchOrigin; // Coretime chain does not recognize a reserve location for any asset. Users must teleport ROC diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs index b67c32495d67c..8f90d07fc6ee3 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/xcm_config.rs @@ -65,6 +65,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = (); // sending XCM not supported + type XcmEventEmitter = (); type AssetTransactor = (); // balances not supported type OriginConverter = XcmOriginToTransactDispatchOrigin; type IsReserve = (); // balances not supported diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs index 724d87587c6c5..97b3fb7747ac4 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs @@ -191,6 +191,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; type AssetTransactor = FungibleTransactor; type OriginConverter = XcmOriginToTransactDispatchOrigin; // People chain does not recognize a reserve location for any asset. Users must teleport ROC diff --git a/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs index 7eaa43c05b208..7f343a2207193 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs @@ -205,6 +205,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; type AssetTransactor = FungibleTransactor; type OriginConverter = XcmOriginToTransactDispatchOrigin; // People does not recognize a reserve location for any asset. Users must teleport WND diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index 10481d5d2ebc4..a0af55e443ccf 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -364,6 +364,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; // How to withdraw and deposit an asset. type AssetTransactor = AssetTransactors; type OriginConverter = XcmOriginToTransactDispatchOrigin; diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index 89cd17d5450ac..d52fb122df64b 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -472,6 +472,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; // How to withdraw and deposit an asset. type AssetTransactor = AssetTransactors; type OriginConverter = XcmOriginToTransactDispatchOrigin; diff --git a/polkadot/runtime/rococo/src/xcm_config.rs b/polkadot/runtime/rococo/src/xcm_config.rs index 10c3f6c0cbfcf..af486db12f426 100644 --- a/polkadot/runtime/rococo/src/xcm_config.rs +++ b/polkadot/runtime/rococo/src/xcm_config.rs @@ -191,6 +191,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = XcmPallet; type AssetTransactor = LocalAssetTransactor; type OriginConverter = LocalOriginConverter; type IsReserve = (); diff --git a/polkadot/runtime/test-runtime/src/xcm_config.rs b/polkadot/runtime/test-runtime/src/xcm_config.rs index b424b9a3ee55b..304c1d52e9ef5 100644 --- a/polkadot/runtime/test-runtime/src/xcm_config.rs +++ b/polkadot/runtime/test-runtime/src/xcm_config.rs @@ -130,6 +130,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = super::RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = super::Xcm; type AssetTransactor = DummyAssetTransactor; type OriginConverter = OriginConverter; type IsReserve = (); diff --git a/polkadot/runtime/westend/src/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs index 4235edf82b24d..fbd15d429d2ec 100644 --- a/polkadot/runtime/westend/src/xcm_config.rs +++ b/polkadot/runtime/westend/src/xcm_config.rs @@ -193,6 +193,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = XcmPallet; type AssetTransactor = LocalAssetTransactor; type OriginConverter = LocalOriginConverter; type IsReserve = (); diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs index 0180354458ce4..11e6219f835c5 100644 --- a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs +++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs @@ -114,6 +114,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = (); + type XcmEventEmitter = (); type AssetTransactor = asset_transactor::AssetTransactor; type OriginConverter = (); // The declaration of which Locations are reserves for which Assets. diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs index 06b00c39e8a04..af7f1aeca3ef2 100644 --- a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs +++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs @@ -87,6 +87,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = (); + type XcmEventEmitter = (); type AssetTransactor = asset_transactor::AssetTransactor; type OriginConverter = (); // We don't need to recognize anyone as a reserve diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs index c0dfa91afc786..9e06550b6b724 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/fungible/mock.rs @@ -94,6 +94,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = EnsureDecodableXcm; + type XcmEventEmitter = (); type AssetTransactor = AssetTransactor; type OriginConverter = (); type IsReserve = TrustedReserves; diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs index f51d34092616b..1eeafaa7f5e97 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/mock.rs @@ -83,6 +83,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = EnsureDecodableXcm; + type XcmEventEmitter = (); type AssetTransactor = NoAssetTransactor; type OriginConverter = AlwaysSignedByDefault; type IsReserve = AllAssetLocationsPass; diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 6360298b21c36..a934e2262466e 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -61,7 +61,7 @@ use xcm_builder::{ use xcm_executor::{ traits::{ AssetTransferError, CheckSuspension, ClaimAssets, ConvertLocation, ConvertOrigin, - DropAssets, MatchesFungible, OnResponse, Properties, QueryHandler, QueryResponseStatus, + DropAssets, EventEmitter, MatchesFungible, OnResponse, Properties, QueryHandler, QueryResponseStatus, RecordXcm, TransactAsset, TransferType, VersionChangeNotifier, WeightBounds, XcmAssetTransfers, }, @@ -402,6 +402,31 @@ pub mod pallet { } } + impl EventEmitter for Pallet { + fn emit_sent_event( + origin: Location, + destination: Location, + message_id: XcmHash, + ) { + Self::deposit_event(Event::Sent { origin, destination, message: Xcm::default(), message_id }); + } + + fn emit_sent_failure_event( + origin: Location, + destination: Location, + error: SendError, + ) { + Self::deposit_event(Event::SentFailed { origin, destination, error }); + } + + fn emit_process_failure_event( + origin: Location, + error: XcmError, + ) { + Self::deposit_event(Event::ProcessXcmError { origin, error }); + } + } + #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { @@ -409,6 +434,10 @@ pub mod pallet { Attempted { outcome: xcm::latest::Outcome }, /// A XCM message was sent. Sent { origin: Location, destination: Location, message: Xcm<()>, message_id: XcmHash }, + /// A XCM message failed to be sent. + SentFailed { origin: Location, destination: Location, error: SendError }, + /// Process XCM message failed. + ProcessXcmError { origin: Location, error: XcmError }, /// Query response received which does not match a registered query. This may be because a /// matching query was never registered, it may be because it is a duplicate response, or /// because the query timed out. diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index 8d0476b0e70d7..77b762cdcb2c6 100644 --- a/polkadot/xcm/pallet-xcm/src/mock.rs +++ b/polkadot/xcm/pallet-xcm/src/mock.rs @@ -480,6 +480,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = XcmPallet; type AssetTransactor = AssetTransactors; type OriginConverter = LocalOriginConverter; type IsReserve = (Case, Case, Case); diff --git a/polkadot/xcm/pallet-xcm/src/tests/mod.rs b/polkadot/xcm/pallet-xcm/src/tests/mod.rs index 350530f7711f8..a0648eeec0281 100644 --- a/polkadot/xcm/pallet-xcm/src/tests/mod.rs +++ b/polkadot/xcm/pallet-xcm/src/tests/mod.rs @@ -1456,3 +1456,55 @@ fn record_xcm_works() { assert_eq!(RecordedXcm::::get(), Some(message.into())); }); } + +#[test] +fn execute_initiate_transfer_and_check_sent_event() { + let balances = vec![(ALICE, INITIAL_BALANCE)]; + new_test_ext_with_balances(balances).execute_with(|| { + let dest: Location = Location::new(1, [Junction::AccountId32 { network: None, id: BOB.into() }]); + let assets: Asset = (Parent, SEND_AMOUNT).into(); + + let message = Xcm(vec![ + InitiateReserveWithdraw { + assets: Wild(All), + reserve: Parent.into(), + xcm: Xcm(vec![ + BuyExecution { fees: assets.clone(), weight_limit: Unlimited }, + DepositAsset { assets: All.into(), beneficiary: dest.clone() }, + ]), + }, + ]); + + assert_ok!(XcmPallet::execute( + RuntimeOrigin::signed(ALICE), + Box::new(VersionedXcm::from(message.clone())), + BaseXcmWeight::get() * 3, + )); + + let sender: Location = AccountId32 { network: None, id: ALICE.into() }.into(); + let expected_message = Xcm(vec![ + WithdrawAsset(Assets::new()), + ClearOrigin, + BuyExecution { fees: assets.clone(), weight_limit: Unlimited }, + DepositAsset { assets: All.into(), beneficiary: dest.clone() }, + ]); + let id = fake_message_hash(&expected_message); + + assert_eq!( + last_events(2), + vec![ + RuntimeEvent::XcmPallet(crate::Event::Sent { + origin: sender, + destination: Parent.into(), + message: expected_message, + message_id: id, + }), + RuntimeEvent::XcmPallet(crate::Event::Attempted { + outcome: Outcome::Complete { + used: Weight::from_parts(1000, 1000) + } + }) + ] + ); + }); +} diff --git a/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/mock.rs b/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/mock.rs index e6fe8e45c2651..171b87fd7254d 100644 --- a/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/mock.rs +++ b/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/mock.rs @@ -218,6 +218,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = (); + type XcmEventEmitter = (); type AssetTransactor = FungibleTransactor; type OriginConverter = (); type IsReserve = (); diff --git a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs index 6ebf6476f7e57..c48380eea3c79 100644 --- a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs @@ -203,6 +203,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = TestMessageSender; + type XcmEventEmitter = XcmPallet; type AssetTransactor = LocalAssetsTransactor; type OriginConverter = OriginConverter; type IsReserve = (); diff --git a/polkadot/xcm/xcm-builder/tests/mock/mod.rs b/polkadot/xcm/xcm-builder/tests/mock/mod.rs index 0468b0a5410c4..007273352e991 100644 --- a/polkadot/xcm/xcm-builder/tests/mock/mod.rs +++ b/polkadot/xcm/xcm-builder/tests/mock/mod.rs @@ -168,6 +168,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = TestXcmRouter; + type XcmEventEmitter = XcmPallet; type AssetTransactor = LocalAssetTransactor; type OriginConverter = LocalOriginConverter; type IsReserve = (); diff --git a/polkadot/xcm/xcm-executor/src/config.rs b/polkadot/xcm/xcm-executor/src/config.rs index 5bcbbd3466e8e..c0cc30c6b19d4 100644 --- a/polkadot/xcm/xcm-executor/src/config.rs +++ b/polkadot/xcm/xcm-executor/src/config.rs @@ -15,7 +15,7 @@ // along with Polkadot. If not, see . use crate::traits::{ - AssetExchange, AssetLock, CallDispatcher, ClaimAssets, ConvertOrigin, DropAssets, ExportXcm, + AssetExchange, AssetLock, CallDispatcher, ClaimAssets, ConvertOrigin, DropAssets, EventEmitter, ExportXcm, FeeManager, HandleHrmpChannelAccepted, HandleHrmpChannelClosing, HandleHrmpNewChannelOpenRequest, OnResponse, ProcessTransaction, RecordXcm, ShouldExecute, TransactAsset, VersionChangeNotifier, WeightBounds, WeightTrader, @@ -39,6 +39,9 @@ pub trait Config { /// the executor. type XcmSender: SendXcm; + /// How to emit XCM events. + type XcmEventEmitter: EventEmitter; + /// How to withdraw and deposit an asset. type AssetTransactor: TransactAsset; diff --git a/polkadot/xcm/xcm-executor/src/lib.rs b/polkadot/xcm/xcm-executor/src/lib.rs index d0f18aea1ab31..63e2c7c799326 100644 --- a/polkadot/xcm/xcm-executor/src/lib.rs +++ b/polkadot/xcm/xcm-executor/src/lib.rs @@ -34,7 +34,7 @@ use xcm::latest::{prelude::*, AssetTransferFilter}; pub mod traits; use traits::{ validate_export, AssetExchange, AssetLock, CallDispatcher, ClaimAssets, ConvertOrigin, - DropAssets, Enact, ExportXcm, FeeManager, FeeReason, HandleHrmpChannelAccepted, + DropAssets, Enact, ExportXcm, EventEmitter, FeeManager, FeeReason, HandleHrmpChannelAccepted, HandleHrmpChannelClosing, HandleHrmpNewChannelOpenRequest, OnResponse, ProcessTransaction, Properties, ShouldExecute, TransactAsset, VersionChangeNotifier, WeightBounds, WeightTrader, XcmAssetTransfers, @@ -427,9 +427,27 @@ impl XcmExecutor { reason = ?reason, "Sending msg", ); - let (ticket, fee) = validate_send::(dest, msg)?; + let (ticket, fee) = validate_send::(dest.clone(), msg)?; self.take_fee(fee, reason)?; - Config::XcmSender::deliver(ticket).map_err(Into::into) + match Config::XcmSender::deliver(ticket) { + Ok(message_id) => { + Config::XcmEventEmitter::emit_sent_event( + self.original_origin.clone(), + dest, + message_id.clone(), + ); + Ok(message_id) + }, + Err(e) => { + tracing::error!(target: "xcm::send", ?e, "XCM failed to deliver with error"); + Config::XcmEventEmitter::emit_sent_failure_event( + self.original_origin.clone(), + dest, + e.clone(), + ); + Err(e.into()) + }, + } } /// Remove the registered error handler and return it. Do not refund its weight. @@ -813,6 +831,7 @@ impl XcmExecutor { self.process_instruction(instr) }); if let Err(e) = inst_res { + Config::XcmEventEmitter::emit_process_failure_event(self.original_origin.clone(), e.clone()); tracing::trace!(target: "xcm::execute", "!!! ERROR: {:?}", e); *r = Err(ExecutorError { index: i as u32, diff --git a/polkadot/xcm/xcm-executor/src/traits/event_emitter.rs b/polkadot/xcm/xcm-executor/src/traits/event_emitter.rs new file mode 100644 index 0000000000000..473020f2c399f --- /dev/null +++ b/polkadot/xcm/xcm-executor/src/traits/event_emitter.rs @@ -0,0 +1,55 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +use xcm::latest::prelude::*; + +/// Defines the event emitter for the XCM executor. +pub trait EventEmitter { + fn emit_sent_event( + origin: Location, + destination: Location, + message_id: XcmHash, + ); + + fn emit_sent_failure_event( + origin: Location, + destination: Location, + error: SendError, + ); + fn emit_process_failure_event( + origin: Location, + error: XcmError + ); +} + +impl EventEmitter for () { + fn emit_sent_event( + _origin: Location, + _destination: Location, + _message_id: XcmHash, + ) {} + + fn emit_sent_failure_event( + _origin: Location, + _destination: Location, + _error: SendError, + ) {} + + fn emit_process_failure_event( + _origin: Location, + _error: XcmError + ) {} +} \ No newline at end of file diff --git a/polkadot/xcm/xcm-executor/src/traits/mod.rs b/polkadot/xcm/xcm-executor/src/traits/mod.rs index feb2922bcdffc..f4f56c625e3de 100644 --- a/polkadot/xcm/xcm-executor/src/traits/mod.rs +++ b/polkadot/xcm/xcm-executor/src/traits/mod.rs @@ -51,6 +51,9 @@ pub use hrmp::{ }; mod record_xcm; mod weight; +mod event_emitter; +pub use event_emitter::EventEmitter; + pub use record_xcm::RecordXcm; #[deprecated = "Use `sp_runtime::traits::` instead"] pub use sp_runtime::traits::{Identity, TryConvertInto as JustTry}; @@ -59,7 +62,7 @@ pub use weight::{WeightBounds, WeightTrader}; pub mod prelude { pub use super::{ export_xcm, validate_export, AssetExchange, AssetLock, ClaimAssets, ConvertOrigin, - DropAssets, Enact, Error, ExportXcm, FeeManager, FeeReason, LockError, MatchesFungible, + DropAssets, Enact, Error, EventEmitter, ExportXcm, FeeManager, FeeReason, LockError, MatchesFungible, MatchesFungibles, MatchesNonFungible, MatchesNonFungibles, OnResponse, ProcessTransaction, ShouldExecute, TransactAsset, VersionChangeNotifier, WeightBounds, WeightTrader, WithOriginFilter, diff --git a/polkadot/xcm/xcm-runtime-apis/tests/mock.rs b/polkadot/xcm/xcm-runtime-apis/tests/mock.rs index 56a77094f1774..3e7d380456af8 100644 --- a/polkadot/xcm/xcm-runtime-apis/tests/mock.rs +++ b/polkadot/xcm/xcm-runtime-apis/tests/mock.rs @@ -283,6 +283,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = XcmPallet; type AssetTransactor = AssetTransactors; type OriginConverter = (); type IsReserve = RelayTokenToAssetHub; diff --git a/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/mod.rs b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/mod.rs index a6b55d1bd9be0..8278d645cb504 100644 --- a/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/mod.rs +++ b/polkadot/xcm/xcm-simulator/example/src/parachain/xcm_config/mod.rs @@ -34,6 +34,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; type AssetTransactor = asset_transactor::AssetTransactor; type OriginConverter = origin_converter::OriginConverter; type IsReserve = reserve::TrustedReserves; diff --git a/substrate/frame/contracts/mock-network/src/parachain.rs b/substrate/frame/contracts/mock-network/src/parachain.rs index 6edbfb0e7e86a..b17dbb5640b31 100644 --- a/substrate/frame/contracts/mock-network/src/parachain.rs +++ b/substrate/frame/contracts/mock-network/src/parachain.rs @@ -254,6 +254,7 @@ pub struct XcmConfig; impl Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; type AssetTransactor = AssetTransactors; type OriginConverter = XcmOriginToCallOrigin; type IsReserve = (NativeAsset, TrustedReserves); diff --git a/substrate/frame/contracts/mock-network/src/relay_chain.rs b/substrate/frame/contracts/mock-network/src/relay_chain.rs index 5fed061f80b45..acaf955ea7217 100644 --- a/substrate/frame/contracts/mock-network/src/relay_chain.rs +++ b/substrate/frame/contracts/mock-network/src/relay_chain.rs @@ -155,6 +155,7 @@ pub struct XcmConfig; impl Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = XcmPallet; type AssetTransactor = AssetTransactors; type OriginConverter = LocalOriginConverter; type IsReserve = (); diff --git a/substrate/frame/revive/mock-network/src/parachain.rs b/substrate/frame/revive/mock-network/src/parachain.rs index 26a8fdcada27e..f8f5d3fd8009a 100644 --- a/substrate/frame/revive/mock-network/src/parachain.rs +++ b/substrate/frame/revive/mock-network/src/parachain.rs @@ -254,6 +254,7 @@ pub struct XcmConfig; impl Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; type AssetTransactor = AssetTransactors; type OriginConverter = XcmOriginToCallOrigin; type IsReserve = (NativeAsset, TrustedReserves); diff --git a/substrate/frame/revive/mock-network/src/relay_chain.rs b/substrate/frame/revive/mock-network/src/relay_chain.rs index 5fed061f80b45..acaf955ea7217 100644 --- a/substrate/frame/revive/mock-network/src/relay_chain.rs +++ b/substrate/frame/revive/mock-network/src/relay_chain.rs @@ -155,6 +155,7 @@ pub struct XcmConfig; impl Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = XcmPallet; type AssetTransactor = AssetTransactors; type OriginConverter = LocalOriginConverter; type IsReserve = (); diff --git a/templates/parachain/runtime/src/configs/xcm_config.rs b/templates/parachain/runtime/src/configs/xcm_config.rs index 3da3b711f4ff3..090a6043c2dc8 100644 --- a/templates/parachain/runtime/src/configs/xcm_config.rs +++ b/templates/parachain/runtime/src/configs/xcm_config.rs @@ -119,6 +119,7 @@ pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; type XcmSender = XcmRouter; + type XcmEventEmitter = PolkadotXcm; // How to withdraw and deposit an asset. type AssetTransactor = LocalAssetTransactor; type OriginConverter = XcmOriginToTransactDispatchOrigin;