diff --git a/bridges/README.md b/bridges/README.md
index ac3e49b94c6a6b9f8912d441d6e002b14fcd66c2..3d3b177bbaae62c4d6d7ccc99ba5629a91983dae 100644
--- a/bridges/README.md
+++ b/bridges/README.md
@@ -10,6 +10,11 @@ Substrate chains.
 
 🚧 The bridges are currently under construction - a hardhat is recommended beyond this point 🚧
 
+**IMPORTANT**: this documentation is outdated and it is mostly related to the previous version of our
+bridge. Right there's an ongoing work to make our bridge work with XCM messages. Old bridge is still
+available at [encoded-calls-messaging](https://github.com/paritytech/parity-bridges-common/releases/tag/encoded-calls-messaging)
+tag.
+
 ## Contents
 
 - [Installation](#installation)
diff --git a/bridges/bin/millau/runtime/Cargo.toml b/bridges/bin/millau/runtime/Cargo.toml
index 7fd2db7eee6712b623e8e0d8d560fee72a5cb9f1..80d961388831ab877de986200007f3cec802d235 100644
--- a/bridges/bin/millau/runtime/Cargo.toml
+++ b/bridges/bin/millau/runtime/Cargo.toml
@@ -17,17 +17,14 @@ serde = { version = "1.0", optional = true, features = ["derive"] }
 # Bridge dependencies
 
 bp-header-chain = { path = "../../../primitives/header-chain", default-features = false }
-bp-message-dispatch = { path = "../../../primitives/message-dispatch", default-features = false }
 bp-messages = { path = "../../../primitives/messages", default-features = false }
 bp-millau = { path = "../../../primitives/chain-millau", default-features = false }
 bp-rialto = { path = "../../../primitives/chain-rialto", default-features = false }
 bp-runtime = { path = "../../../primitives/runtime", default-features = false }
 bp-westend = { path = "../../../primitives/chain-westend", default-features = false }
 bridge-runtime-common = { path = "../../runtime-common", default-features = false }
-pallet-bridge-dispatch = { path = "../../../modules/dispatch", default-features = false }
 pallet-bridge-grandpa = { path = "../../../modules/grandpa", default-features = false }
 pallet-bridge-messages = { path = "../../../modules/messages", default-features = false }
-pallet-bridge-token-swap = { path = "../../../modules/token-swap", default-features = false }
 pallet-shift-session-manager = { path = "../../../modules/shift-session-manager", default-features = false }
 
 # Substrate Dependencies
@@ -77,7 +74,6 @@ default = ["std"]
 std = [
 	"beefy-primitives/std",
 	"bp-header-chain/std",
-	"bp-message-dispatch/std",
 	"bp-messages/std",
 	"bp-millau/std",
 	"bp-rialto/std",
@@ -93,10 +89,8 @@ std = [
 	"pallet-balances/std",
 	"pallet-beefy/std",
 	"pallet-beefy-mmr/std",
-	"pallet-bridge-dispatch/std",
 	"pallet-bridge-grandpa/std",
 	"pallet-bridge-messages/std",
-	"pallet-bridge-token-swap/std",
 	"pallet-grandpa/std",
 	"pallet-mmr/std",
 	"pallet-randomness-collective-flip/std",
@@ -129,6 +123,5 @@ runtime-benchmarks = [
 	"frame-system/runtime-benchmarks",
 	"libsecp256k1",
 	"pallet-bridge-messages/runtime-benchmarks",
-	"pallet-bridge-token-swap/runtime-benchmarks",
 	"sp-runtime/runtime-benchmarks",
 ]
diff --git a/bridges/bin/millau/runtime/src/lib.rs b/bridges/bin/millau/runtime/src/lib.rs
index 99bb8ae33c11a8487bc6652aedfae24ded50ec90..4d44f34b624b3bd06c1eddc33246e9c5f733bcc4 100644
--- a/bridges/bin/millau/runtime/src/lib.rs
+++ b/bridges/bin/millau/runtime/src/lib.rs
@@ -50,7 +50,7 @@ use sp_runtime::{
 	create_runtime_str, generic, impl_opaque_keys,
 	traits::{Block as BlockT, IdentityLookup, Keccak256, NumberFor, OpaqueKeys},
 	transaction_validity::{TransactionSource, TransactionValidity},
-	ApplyExtrinsicResult, FixedPointNumber, FixedU128, MultiSignature, MultiSigner, Perquintill,
+	ApplyExtrinsicResult, FixedPointNumber, FixedU128, Perquintill,
 };
 use sp_std::prelude::*;
 #[cfg(feature = "std")]
@@ -225,18 +225,6 @@ impl pallet_beefy::Config for Runtime {
 	type BeefyId = BeefyId;
 }
 
-impl pallet_bridge_dispatch::Config for Runtime {
-	type Event = Event;
-	type BridgeMessageId = (bp_messages::LaneId, bp_messages::MessageNonce);
-	type Call = Call;
-	type CallFilter = frame_support::traits::Everything;
-	type EncodedCall = crate::rialto_messages::FromRialtoEncodedCall;
-	type SourceChainAccountId = bp_rialto::AccountId;
-	type TargetChainAccountPublic = MultiSigner;
-	type TargetChainSignature = MultiSignature;
-	type AccountIdConverter = bp_millau::AccountIdConverter;
-}
-
 impl pallet_grandpa::Config for Runtime {
 	type Event = Event;
 	type Call = Call;
@@ -471,38 +459,13 @@ impl pallet_bridge_messages::Config<WithRialtoMessagesInstance> for Runtime {
 			GetDeliveryConfirmationTransactionFee,
 		>;
 	type OnMessageAccepted = ();
-	type OnDeliveryConfirmed =
-		pallet_bridge_token_swap::Pallet<Runtime, WithRialtoTokenSwapInstance>;
+	type OnDeliveryConfirmed = ();
 
 	type SourceHeaderChain = crate::rialto_messages::Rialto;
 	type MessageDispatch = crate::rialto_messages::FromRialtoMessageDispatch;
 	type BridgedChainId = RialtoChainId;
 }
 
-parameter_types! {
-	pub const TokenSwapMessagesLane: bp_messages::LaneId = *b"swap";
-}
-
-/// Instance of the with-Rialto token swap pallet.
-pub type WithRialtoTokenSwapInstance = ();
-
-impl pallet_bridge_token_swap::Config<WithRialtoTokenSwapInstance> for Runtime {
-	type Event = Event;
-	type WeightInfo = ();
-
-	type BridgedChainId = RialtoChainId;
-	type OutboundMessageLaneId = TokenSwapMessagesLane;
-	#[cfg(not(feature = "runtime-benchmarks"))]
-	type MessagesBridge = pallet_bridge_messages::Pallet<Runtime, WithRialtoMessagesInstance>;
-	#[cfg(feature = "runtime-benchmarks")]
-	type MessagesBridge = bp_messages::source_chain::NoopMessagesBridge;
-	type ThisCurrency = pallet_balances::Pallet<Runtime>;
-	type FromSwapToThisAccountIdConverter = bp_rialto::AccountIdConverter;
-
-	type BridgedChain = bp_rialto::Rialto;
-	type FromBridgedToThisAccountIdConverter = bp_millau::AccountIdConverter;
-}
-
 construct_runtime!(
 	pub enum Runtime where
 		Block = Block,
@@ -532,9 +495,7 @@ construct_runtime!(
 
 		// Rialto bridge modules.
 		BridgeRialtoGrandpa: pallet_bridge_grandpa::{Pallet, Call, Storage},
-		BridgeDispatch: pallet_bridge_dispatch::{Pallet, Event<T>},
 		BridgeRialtoMessages: pallet_bridge_messages::{Pallet, Call, Storage, Event<T>, Config<T>},
-		BridgeRialtoTokenSwap: pallet_bridge_token_swap::{Pallet, Call, Storage, Event<T>, Origin<T>},
 
 		// Westend bridge modules.
 		BridgeWestendGrandpa: pallet_bridge_grandpa::<Instance1>::{Pallet, Call, Config<T>, Storage},
@@ -806,7 +767,6 @@ impl_runtime_apis! {
 
 			let mut list = Vec::<BenchmarkList>::new();
 
-			list_benchmark!(list, extra, pallet_bridge_token_swap, BridgeRialtoTokenSwap);
 			list_benchmark!(list, extra, pallet_bridge_messages, MessagesBench::<Runtime, WithRialtoMessagesInstance>);
 			list_benchmark!(list, extra, pallet_bridge_grandpa, BridgeRialtoGrandpa);
 
@@ -878,8 +838,6 @@ impl_runtime_apis! {
 				) -> (rialto_messages::FromRialtoMessagesProof, Weight) {
 					prepare_message_proof::<Runtime, (), (), WithRialtoMessageBridge, bp_rialto::Header, bp_rialto::Hasher>(
 						params,
-						&VERSION,
-						Balance::MAX / 100,
 					)
 				}
 
@@ -891,33 +849,11 @@ impl_runtime_apis! {
 					)
 				}
 
-				fn is_message_dispatched(nonce: bp_messages::MessageNonce) -> bool {
-					frame_system::Pallet::<Runtime>::events()
-						.into_iter()
-						.map(|event_record| event_record.event)
-						.any(|event| matches!(
-							event,
-							Event::BridgeDispatch(pallet_bridge_dispatch::Event::<Runtime, _>::MessageDispatched(
-								_, ([0, 0, 0, 0], nonce_from_event), _,
-							)) if nonce_from_event == nonce
-						))
+				fn is_message_dispatched(_nonce: bp_messages::MessageNonce) -> bool {
+					true
 				}
 			}
 
-			use pallet_bridge_token_swap::benchmarking::Config as TokenSwapConfig;
-
-			impl TokenSwapConfig<WithRialtoTokenSwapInstance> for Runtime {
-				fn initialize_environment() {
-					let relayers_fund_account = pallet_bridge_messages::relayer_fund_account_id::<
-						bp_millau::AccountId,
-						bp_millau::AccountIdConverter,
-					>();
-					pallet_balances::Pallet::<Runtime>::make_free_balance_be(
-						&relayers_fund_account,
-						Balance::MAX / 100,
-					);
-				}
-			}
 
 			add_benchmark!(
 				params,
@@ -926,37 +862,12 @@ impl_runtime_apis! {
 				MessagesBench::<Runtime, WithRialtoMessagesInstance>
 			);
 			add_benchmark!(params, batches, pallet_bridge_grandpa, BridgeRialtoGrandpa);
-			add_benchmark!(params, batches, pallet_bridge_token_swap, BridgeRialtoTokenSwap);
 
 			Ok(batches)
 		}
 	}
 }
 
-/// Rialto account ownership digest from Millau.
-///
-/// The byte vector returned by this function should be signed with a Rialto account private key.
-/// This way, the owner of `millau_account_id` on Millau proves that the Rialto account private key
-/// is also under his control.
-pub fn millau_to_rialto_account_ownership_digest<Call, AccountId, SpecVersion>(
-	rialto_call: &Call,
-	millau_account_id: AccountId,
-	rialto_spec_version: SpecVersion,
-) -> sp_std::vec::Vec<u8>
-where
-	Call: codec::Encode,
-	AccountId: codec::Encode,
-	SpecVersion: codec::Encode,
-{
-	pallet_bridge_dispatch::account_ownership_digest(
-		rialto_call,
-		millau_account_id,
-		rialto_spec_version,
-		bp_runtime::MILLAU_CHAIN_ID,
-		bp_runtime::RIALTO_CHAIN_ID,
-	)
-}
-
 #[cfg(test)]
 mod tests {
 	use super::*;
diff --git a/bridges/bin/millau/runtime/src/rialto_messages.rs b/bridges/bin/millau/runtime/src/rialto_messages.rs
index d925d805dd04b4444861fbebc534ba6d7b57ca8a..9b2c62375714807c8c9e7c6f49df0c70005e3760 100644
--- a/bridges/bin/millau/runtime/src/rialto_messages.rs
+++ b/bridges/bin/millau/runtime/src/rialto_messages.rs
@@ -33,7 +33,7 @@ use frame_support::{
 };
 use scale_info::TypeInfo;
 use sp_runtime::{traits::Saturating, FixedPointNumber, FixedU128};
-use sp_std::{convert::TryFrom, ops::RangeInclusive};
+use sp_std::convert::TryFrom;
 
 /// Initial value of `RialtoToMillauConversionRate` parameter.
 pub const INITIAL_RIALTO_TO_MILLAU_CONVERSION_RATE: FixedU128 =
@@ -49,19 +49,14 @@ parameter_types! {
 }
 
 /// Message payload for Millau -> Rialto messages.
-pub type ToRialtoMessagePayload =
-	messages::source::FromThisChainMessagePayload<WithRialtoMessageBridge>;
+pub type ToRialtoMessagePayload = messages::source::FromThisChainMessagePayload;
 
 /// Message verifier for Millau -> Rialto messages.
 pub type ToRialtoMessageVerifier =
 	messages::source::FromThisChainMessageVerifier<WithRialtoMessageBridge>;
 
 /// Message payload for Rialto -> Millau messages.
-pub type FromRialtoMessagePayload =
-	messages::target::FromBridgedChainMessagePayload<WithRialtoMessageBridge>;
-
-/// Encoded Millau Call as it comes from Rialto.
-pub type FromRialtoEncodedCall = messages::target::FromBridgedChainEncodedMessageCall<crate::Call>;
+pub type FromRialtoMessagePayload = messages::target::FromBridgedChainMessagePayload;
 
 /// Messages proof for Rialto -> Millau messages.
 pub type FromRialtoMessagesProof = messages::target::FromBridgedChainMessagesProof<bp_rialto::Hash>;
@@ -120,19 +115,7 @@ impl messages::ThisChainWithMessages for Millau {
 	type Call = crate::Call;
 
 	fn is_message_accepted(send_origin: &Self::Origin, lane: &LaneId) -> bool {
-		// lanes 0x00000000 && 0x00000001 are accepting any paid messages, while
-		// `TokenSwapMessageLane` only accepts messages from token swap pallet
-		let token_swap_dedicated_lane = crate::TokenSwapMessagesLane::get();
-		match *lane {
-			[0, 0, 0, 0] | [0, 0, 0, 1] => send_origin.linked_account().is_some(),
-			_ if *lane == token_swap_dedicated_lane => matches!(
-				send_origin.caller,
-				crate::OriginCaller::BridgeRialtoTokenSwap(
-					pallet_bridge_token_swap::RawOrigin::TokenSwap { .. }
-				)
-			),
-			_ => false,
-		}
+		(*lane == [0, 0, 0, 0] || *lane == [0, 0, 0, 1]) && send_origin.linked_account().is_some()
 	}
 
 	fn maximal_pending_messages_at_outbound_lane() -> MessageNonce {
@@ -189,19 +172,8 @@ impl messages::BridgedChainWithMessages for Rialto {
 		bp_rialto::Rialto::max_extrinsic_size()
 	}
 
-	fn message_weight_limits(_message_payload: &[u8]) -> RangeInclusive<Weight> {
-		// we don't want to relay too large messages + keep reserve for future upgrades
-		let upper_limit = messages::target::maximal_incoming_message_dispatch_weight(
-			bp_rialto::Rialto::max_extrinsic_weight(),
-		);
-
-		// we're charging for payload bytes in `WithRialtoMessageBridge::transaction_payment`
-		// function
-		//
-		// this bridge may be used to deliver all kind of messages, so we're not making any
-		// assumptions about minimal dispatch weight here
-
-		0..=upper_limit
+	fn verify_dispatch_weight(_message_payload: &[u8]) -> bool {
+		true
 	}
 
 	fn estimate_delivery_transaction(
@@ -296,12 +268,6 @@ impl SenderOrigin<crate::AccountId> for crate::Origin {
 			crate::OriginCaller::system(frame_system::RawOrigin::Root) |
 			crate::OriginCaller::system(frame_system::RawOrigin::None) =>
 				crate::RootAccountForPayments::get(),
-			crate::OriginCaller::BridgeRialtoTokenSwap(
-				pallet_bridge_token_swap::RawOrigin::TokenSwap {
-					ref swap_account_at_this_chain,
-					..
-				},
-			) => Some(swap_account_at_this_chain.clone()),
 			_ => None,
 		}
 	}
diff --git a/bridges/bin/rialto/runtime/Cargo.toml b/bridges/bin/rialto/runtime/Cargo.toml
index 99ab1f9a6915db42c6363d82873d280c18836483..ccfa65090e6d102faa945dfb51ba85a44cd2a604 100644
--- a/bridges/bin/rialto/runtime/Cargo.toml
+++ b/bridges/bin/rialto/runtime/Cargo.toml
@@ -18,13 +18,11 @@ serde = { version = "1.0", optional = true, features = ["derive"] }
 # Bridge dependencies
 
 bp-header-chain = { path = "../../../primitives/header-chain", default-features = false }
-bp-message-dispatch = { path = "../../../primitives/message-dispatch", default-features = false }
 bp-messages = { path = "../../../primitives/messages", default-features = false }
 bp-millau = { path = "../../../primitives/chain-millau", default-features = false }
 bp-rialto = { path = "../../../primitives/chain-rialto", default-features = false }
 bp-runtime = { path = "../../../primitives/runtime", default-features = false }
 bridge-runtime-common = { path = "../../runtime-common", default-features = false }
-pallet-bridge-dispatch = { path = "../../../modules/dispatch", default-features = false }
 pallet-bridge-grandpa = { path = "../../../modules/grandpa", default-features = false }
 pallet-bridge-messages = { path = "../../../modules/messages", default-features = false }
 pallet-shift-session-manager = { path = "../../../modules/shift-session-manager", default-features = false }
@@ -85,7 +83,6 @@ default = ["std"]
 std = [
 	"beefy-primitives/std",
 	"bp-header-chain/std",
-	"bp-message-dispatch/std",
 	"bp-messages/std",
 	"bp-millau/std",
 	"bp-rialto/std",
@@ -103,7 +100,6 @@ std = [
 	"pallet-balances/std",
 	"pallet-beefy/std",
 	"pallet-beefy-mmr/std",
-	"pallet-bridge-dispatch/std",
 	"pallet-bridge-grandpa/std",
 	"pallet-bridge-messages/std",
 	"pallet-grandpa/std",
diff --git a/bridges/bin/rialto/runtime/src/lib.rs b/bridges/bin/rialto/runtime/src/lib.rs
index 2334d45f340e7fad0ef7e92ec37c209f5dc052bb..4d2602a20a60806441f6095e22840afb5e5ceb14 100644
--- a/bridges/bin/rialto/runtime/src/lib.rs
+++ b/bridges/bin/rialto/runtime/src/lib.rs
@@ -51,7 +51,7 @@ use sp_runtime::{
 	create_runtime_str, generic, impl_opaque_keys,
 	traits::{AccountIdLookup, Block as BlockT, Keccak256, NumberFor, OpaqueKeys},
 	transaction_validity::{TransactionSource, TransactionValidity},
-	ApplyExtrinsicResult, FixedPointNumber, FixedU128, MultiSignature, MultiSigner, Perquintill,
+	ApplyExtrinsicResult, FixedPointNumber, FixedU128, Perquintill,
 };
 use sp_std::{collections::btree_map::BTreeMap, prelude::*};
 #[cfg(feature = "std")]
@@ -251,18 +251,6 @@ impl pallet_beefy::Config for Runtime {
 	type BeefyId = BeefyId;
 }
 
-impl pallet_bridge_dispatch::Config for Runtime {
-	type Event = Event;
-	type BridgeMessageId = (bp_messages::LaneId, bp_messages::MessageNonce);
-	type Call = Call;
-	type CallFilter = frame_support::traits::Everything;
-	type EncodedCall = crate::millau_messages::FromMillauEncodedCall;
-	type SourceChainAccountId = bp_millau::AccountId;
-	type TargetChainAccountPublic = MultiSigner;
-	type TargetChainSignature = MultiSignature;
-	type AccountIdConverter = bp_rialto::AccountIdConverter;
-}
-
 impl pallet_grandpa::Config for Runtime {
 	type Event = Event;
 	type Call = Call;
@@ -505,7 +493,6 @@ construct_runtime!(
 
 		// Millau bridge modules.
 		BridgeMillauGrandpa: pallet_bridge_grandpa::{Pallet, Call, Storage},
-		BridgeDispatch: pallet_bridge_dispatch::{Pallet, Event<T>},
 		BridgeMillauMessages: pallet_bridge_messages::{Pallet, Call, Storage, Event<T>, Config<T>},
 
 		// Parachain modules.
@@ -920,30 +907,6 @@ impl_runtime_apis! {
 	}
 }
 
-/// Millau account ownership digest from Rialto.
-///
-/// The byte vector returned by this function should be signed with a Millau account private key.
-/// This way, the owner of `rialto_account_id` on Rialto proves that the 'millau' account private
-/// key is also under his control.
-pub fn rialto_to_millau_account_ownership_digest<Call, AccountId, SpecVersion>(
-	millau_call: &Call,
-	rialto_account_id: AccountId,
-	millau_spec_version: SpecVersion,
-) -> sp_std::vec::Vec<u8>
-where
-	Call: codec::Encode,
-	AccountId: codec::Encode,
-	SpecVersion: codec::Encode,
-{
-	pallet_bridge_dispatch::account_ownership_digest(
-		millau_call,
-		rialto_account_id,
-		millau_spec_version,
-		bp_runtime::RIALTO_CHAIN_ID,
-		bp_runtime::MILLAU_CHAIN_ID,
-	)
-}
-
 #[cfg(test)]
 mod tests {
 	use super::*;
diff --git a/bridges/bin/rialto/runtime/src/millau_messages.rs b/bridges/bin/rialto/runtime/src/millau_messages.rs
index 44348383f1d52e897c52fca2ffea8a6362010aa2..8088ee56ac7543fc5c8e3e971264ca03dc6ffc51 100644
--- a/bridges/bin/rialto/runtime/src/millau_messages.rs
+++ b/bridges/bin/rialto/runtime/src/millau_messages.rs
@@ -33,7 +33,7 @@ use frame_support::{
 };
 use scale_info::TypeInfo;
 use sp_runtime::{traits::Saturating, FixedPointNumber, FixedU128};
-use sp_std::{convert::TryFrom, ops::RangeInclusive};
+use sp_std::convert::TryFrom;
 
 /// Initial value of `MillauToRialtoConversionRate` parameter.
 pub const INITIAL_MILLAU_TO_RIALTO_CONVERSION_RATE: FixedU128 =
@@ -49,19 +49,14 @@ parameter_types! {
 }
 
 /// Message payload for Rialto -> Millau messages.
-pub type ToMillauMessagePayload =
-	messages::source::FromThisChainMessagePayload<WithMillauMessageBridge>;
+pub type ToMillauMessagePayload = messages::source::FromThisChainMessagePayload;
 
 /// Message verifier for Rialto -> Millau messages.
 pub type ToMillauMessageVerifier =
 	messages::source::FromThisChainMessageVerifier<WithMillauMessageBridge>;
 
 /// Message payload for Millau -> Rialto messages.
-pub type FromMillauMessagePayload =
-	messages::target::FromBridgedChainMessagePayload<WithMillauMessageBridge>;
-
-/// Encoded Rialto Call as it comes from Millau.
-pub type FromMillauEncodedCall = messages::target::FromBridgedChainEncodedMessageCall<crate::Call>;
+pub type FromMillauMessagePayload = messages::target::FromBridgedChainMessagePayload;
 
 /// Call-dispatch based message dispatch for Millau -> Rialto messages.
 pub type FromMillauMessageDispatch = messages::target::FromBridgedChainMessageDispatch<
@@ -177,19 +172,8 @@ impl messages::BridgedChainWithMessages for Millau {
 		bp_millau::Millau::max_extrinsic_size()
 	}
 
-	fn message_weight_limits(_message_payload: &[u8]) -> RangeInclusive<Weight> {
-		// we don't want to relay too large messages + keep reserve for future upgrades
-		let upper_limit = messages::target::maximal_incoming_message_dispatch_weight(
-			bp_millau::Millau::max_extrinsic_weight(),
-		);
-
-		// we're charging for payload bytes in `WithMillauMessageBridge::transaction_payment`
-		// function
-		//
-		// this bridge may be used to deliver all kind of messages, so we're not making any
-		// assumptions about minimal dispatch weight here
-
-		0..=upper_limit
+	fn verify_dispatch_weight(_message_payload: &[u8]) -> bool {
+		true
 	}
 
 	fn estimate_delivery_transaction(
@@ -308,100 +292,15 @@ impl MessagesParameter for RialtoToMillauMessagesParameter {
 #[cfg(test)]
 mod tests {
 	use super::*;
-	use crate::{
-		AccountId, Call, DbWeight, ExistentialDeposit, MillauGrandpaInstance, Runtime, SystemCall,
-		SystemConfig, WithMillauMessagesInstance, VERSION,
-	};
-	use bp_message_dispatch::CallOrigin;
-	use bp_messages::{
-		target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch},
-		MessageKey,
-	};
-	use bp_runtime::{derive_account_id, messages::DispatchFeePayment, Chain, SourceAccount};
+	use crate::{DbWeight, MillauGrandpaInstance, Runtime, WithMillauMessagesInstance};
+	use bp_runtime::Chain;
 	use bridge_runtime_common::{
 		assert_complete_bridge_types,
 		integrity::{
 			assert_complete_bridge_constants, AssertBridgeMessagesPalletConstants,
 			AssertBridgePalletNames, AssertChainConstants, AssertCompleteBridgeConstants,
 		},
-		messages::target::{FromBridgedChainEncodedMessageCall, FromBridgedChainMessagePayload},
 	};
-	use frame_support::{
-		traits::Currency,
-		weights::{GetDispatchInfo, WeightToFeePolynomial},
-	};
-	use sp_runtime::traits::Convert;
-
-	#[test]
-	fn transfer_happens_when_dispatch_fee_is_paid_at_target_chain() {
-		// this test actually belongs to the `bridge-runtime-common` crate, but there we have no
-		// mock runtime. Making another one there just for this test, given that both crates
-		// live n single repo is an overkill
-		let mut ext: sp_io::TestExternalities =
-			SystemConfig::default().build_storage::<Runtime>().unwrap().into();
-		ext.execute_with(|| {
-			let bridge = MILLAU_CHAIN_ID;
-			let call: Call = SystemCall::set_heap_pages { pages: 64 }.into();
-			let dispatch_weight = call.get_dispatch_info().weight;
-			let dispatch_fee = <Runtime as pallet_transaction_payment::Config>::WeightToFee::calc(
-				&dispatch_weight,
-			);
-			assert!(dispatch_fee > 0);
-
-			// create relayer account with minimal balance
-			let relayer_account: AccountId = [1u8; 32].into();
-			let initial_amount = ExistentialDeposit::get();
-			let _ = <pallet_balances::Pallet<Runtime> as Currency<AccountId>>::deposit_creating(
-				&relayer_account,
-				initial_amount,
-			);
-
-			// create dispatch account with minimal balance + dispatch fee
-			let dispatch_account = derive_account_id::<
-				<Runtime as pallet_bridge_dispatch::Config>::SourceChainAccountId,
-			>(bridge, SourceAccount::Root);
-			let dispatch_account =
-				<Runtime as pallet_bridge_dispatch::Config>::AccountIdConverter::convert(
-					dispatch_account,
-				);
-			let _ = <pallet_balances::Pallet<Runtime> as Currency<AccountId>>::deposit_creating(
-				&dispatch_account,
-				initial_amount + dispatch_fee,
-			);
-
-			// dispatch message with intention to pay dispatch fee at the target chain
-			FromMillauMessageDispatch::dispatch(
-				&relayer_account,
-				DispatchMessage {
-					key: MessageKey { lane_id: Default::default(), nonce: 0 },
-					data: DispatchMessageData {
-						payload: Ok(FromBridgedChainMessagePayload::<WithMillauMessageBridge> {
-							spec_version: VERSION.spec_version,
-							weight: dispatch_weight,
-							origin: CallOrigin::SourceRoot,
-							dispatch_fee_payment: DispatchFeePayment::AtTargetChain,
-							call: FromBridgedChainEncodedMessageCall::new(call.encode()),
-						}),
-						fee: 1,
-					},
-				},
-			);
-
-			// ensure that fee has been transferred from dispatch to relayer account
-			assert_eq!(
-				<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::free_balance(
-					&relayer_account
-				),
-				initial_amount + dispatch_fee,
-			);
-			assert_eq!(
-				<pallet_balances::Pallet<Runtime> as Currency<AccountId>>::free_balance(
-					&dispatch_account
-				),
-				initial_amount,
-			);
-		});
-	}
 
 	#[test]
 	fn ensure_rialto_message_lane_weights_are_correct() {
@@ -490,69 +389,4 @@ mod tests {
 			.0,
 		);
 	}
-
-	#[test]
-	#[ignore]
-	fn no_stack_overflow_when_decoding_nested_call_during_dispatch() {
-		// this test is normally ignored, because it only makes sense to run it in release mode
-
-		let mut ext: sp_io::TestExternalities =
-			SystemConfig::default().build_storage::<Runtime>().unwrap().into();
-		ext.execute_with(|| {
-			let bridge = MILLAU_CHAIN_ID;
-
-			let mut call: Call = SystemCall::set_heap_pages { pages: 64 }.into();
-
-			for _i in 0..3000 {
-				call = Call::Sudo(pallet_sudo::Call::sudo { call: Box::new(call) });
-			}
-
-			let dispatch_weight = 500;
-			let dispatch_fee = <Runtime as pallet_transaction_payment::Config>::WeightToFee::calc(
-				&dispatch_weight,
-			);
-			assert!(dispatch_fee > 0);
-
-			// create relayer account with minimal balance
-			let relayer_account: AccountId = [1u8; 32].into();
-			let initial_amount = ExistentialDeposit::get();
-			let _ = <pallet_balances::Pallet<Runtime> as Currency<AccountId>>::deposit_creating(
-				&relayer_account,
-				initial_amount,
-			);
-
-			// create dispatch account with minimal balance + dispatch fee
-			let dispatch_account = derive_account_id::<
-				<Runtime as pallet_bridge_dispatch::Config>::SourceChainAccountId,
-			>(bridge, SourceAccount::Root);
-			let dispatch_account =
-				<Runtime as pallet_bridge_dispatch::Config>::AccountIdConverter::convert(
-					dispatch_account,
-				);
-			let _ = <pallet_balances::Pallet<Runtime> as Currency<AccountId>>::deposit_creating(
-				&dispatch_account,
-				initial_amount + dispatch_fee,
-			);
-
-			// dispatch message with intention to pay dispatch fee at the target chain
-			//
-			// this is where the stack overflow has happened before the fix has been applied
-			FromMillauMessageDispatch::dispatch(
-				&relayer_account,
-				DispatchMessage {
-					key: MessageKey { lane_id: Default::default(), nonce: 0 },
-					data: DispatchMessageData {
-						payload: Ok(FromBridgedChainMessagePayload::<WithMillauMessageBridge> {
-							spec_version: VERSION.spec_version,
-							weight: dispatch_weight,
-							origin: CallOrigin::SourceRoot,
-							dispatch_fee_payment: DispatchFeePayment::AtTargetChain,
-							call: FromBridgedChainEncodedMessageCall::new(call.encode()),
-						}),
-						fee: 1,
-					},
-				},
-			);
-		});
-	}
 }
diff --git a/bridges/bin/runtime-common/Cargo.toml b/bridges/bin/runtime-common/Cargo.toml
index 6ca7de5ac43dd4301dcdb0f001c9b0d1ea459b4f..7e8609071f86c23463cd0c3ec60afb3a6d0d96da 100644
--- a/bridges/bin/runtime-common/Cargo.toml
+++ b/bridges/bin/runtime-common/Cargo.toml
@@ -9,17 +9,15 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
 codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] }
-ed25519-dalek = { version = "1.0", default-features = false, optional = true }
 hash-db = { version = "0.15.2", default-features = false }
+log = { version = "0.4.14", default-features = false }
 scale-info = { version = "2.1.1", default-features = false, features = ["derive"] }
 static_assertions = { version = "1.1", optional = true }
 
 # Bridge dependencies
 
-bp-message-dispatch = { path = "../../primitives/message-dispatch", default-features = false }
 bp-messages = { path = "../../primitives/messages", default-features = false }
 bp-runtime = { path = "../../primitives/runtime", default-features = false }
-pallet-bridge-dispatch = { path = "../../modules/dispatch", default-features = false }
 pallet-bridge-grandpa = { path = "../../modules/grandpa", default-features = false }
 pallet-bridge-messages = { path = "../../modules/messages", default-features = false }
 
@@ -40,14 +38,13 @@ sp-version = { git = "https://github.com/paritytech/substrate", branch = "master
 [features]
 default = ["std"]
 std = [
-	"bp-message-dispatch/std",
 	"bp-messages/std",
 	"bp-runtime/std",
 	"codec/std",
 	"frame-support/std",
 	"frame-system/std",
 	"hash-db/std",
-	"pallet-bridge-dispatch/std",
+	"log/std",
 	"pallet-bridge-grandpa/std",
 	"pallet-bridge-messages/std",
 	"pallet-transaction-payment/std",
@@ -60,7 +57,6 @@ std = [
 	"sp-trie/std",
 ]
 runtime-benchmarks = [
-	"ed25519-dalek/u64_backend",
 	"pallet-balances",
 	"pallet-bridge-grandpa/runtime-benchmarks",
 	"pallet-bridge-messages/runtime-benchmarks",
diff --git a/bridges/bin/runtime-common/README.md b/bridges/bin/runtime-common/README.md
deleted file mode 100644
index 5f2298cd787d3f0dd0e35eecc28ba877b83a80c9..0000000000000000000000000000000000000000
--- a/bridges/bin/runtime-common/README.md
+++ /dev/null
@@ -1,181 +0,0 @@
-# Helpers for Messages Module Integration
-
-The [`messages`](./src/messages.rs) module of this crate contains a bunch of helpers for integrating
-messages module into your runtime. Basic prerequisites of these helpers are:
-- we're going to bridge Substrate-based chain with another Substrate-based chain;
-- both chains have [messages module](../../modules/messages/README.md), Substrate bridge
-  module and the [call dispatch module](../../modules/dispatch/README.md);
-- all message lanes are identical and may be used to transfer the same messages;
-- the messages sent over the bridge are dispatched using
-  [call dispatch module](../../modules/dispatch/README.md);
-- the messages are `bp_message_dispatch::MessagePayload` structures, where `call` field is
-  encoded `Call` of the target chain. This means that the `Call` is opaque to the
-  [messages module](../../modules/messages/README.md) instance at the source chain.
-  It is pre-encoded by the message submitter;
-- all proofs in the [messages module](../../modules/messages/README.md) transactions are
-  based on the storage proofs from the bridged chain: storage proof of the outbound message (value
-  from the `pallet_bridge_messages::Store::MessagePayload` map), storage proof of the outbound lane
-  state (value from the `pallet_bridge_messages::Store::OutboundLanes` map) and storage proof of the
-  inbound lane state (value from the `pallet_bridge_messages::Store::InboundLanes` map);
-- storage proofs are built at the finalized headers of the corresponding chain. So all message lane
-  transactions with proofs are verifying storage proofs against finalized chain headers from
-  Substrate bridge module.
-
-**IMPORTANT NOTE**: after reading this document, you may refer to our test runtimes
-([rialto_messages.rs](../millau/runtime/src/rialto_messages.rs) and/or
-[millau_messages.rs](../rialto/runtime/src/millau_messages.rs)) to see how to use these helpers.
-
-## Contents
-- [`MessageBridge` Trait](#messagebridge-trait)
-- [`ChainWithMessages` Trait ](#ChainWithMessages-trait)
-- [Helpers for the Source Chain](#helpers-for-the-source-chain)
-- [Helpers for the Target Chain](#helpers-for-the-target-chain)
-
-## `MessageBridge` Trait
-
-The essence of your integration will be a struct that implements a `MessageBridge` trait. It has
-single method (`MessageBridge::bridged_balance_to_this_balance`), used to convert from bridged chain
-tokens into this chain tokens. The bridge also requires two associated types to be specified -
-`ThisChain` and `BridgedChain`.
-
-Worth to say that if you're going to use hardcoded constant (conversion rate) in the
-`MessageBridge::bridged_balance_to_this_balance` method (or in any other method of
-`ThisChainWithMessages` or `BridgedChainWithMessages` traits), then you should take a
-look at the
-[messages parameters functionality](../../modules/messages/README.md#Non-Essential-Functionality).
-They allow pallet owner to update constants more frequently than runtime upgrade happens.
-
-## `ChainWithMessages` Trait
-
-The trait is quite simple and can easily be implemented - you just need to specify types used at the
-corresponding chain. There is single exception, though (it may be changed in the future):
-
-- `ChainWithMessages::MessagesInstance`: this is used to compute runtime storage keys. There
-  may be several instances of messages pallet, included in the Runtime. Every instance stores
-  messages and these messages stored under different keys. When we are verifying storage proofs from
-  the bridged chain, we should know which instance we're talking to. This is fine, but there's
-  significant inconvenience with that - this chain runtime must have the same messages pallet
-  instance. This does not necessarily mean that we should use the same instance on both chains -
-  this instance may be used to bridge with another chain/instance, or may not be used at all.
-
-## `ThisChainWithMessages` Trait
-
-This trait represents this chain from bridge point of view. Let's review every method of this trait:
-
-- `ThisChainWithMessages::is_message_accepted`: is used to check whether given lane accepts
-  messages. The send-message origin is passed to the function, so you may e.g. verify that only
-  given pallet is able to send messages over selected lane. **IMPORTANT**: if you assume that the
-  message must be paid by the sender, you must ensure that the sender origin has linked the account
-  for paying message delivery and dispatch fee.
-
-- `ThisChainWithMessages::maximal_pending_messages_at_outbound_lane`: you should return maximal
-  number of pending (undelivered) messages from this function. Returning small values would require
-  relayers to operate faster and could make message sending logic more complicated. On the other
-  hand, returning large values could lead to chain state growth.
-
-- `ThisChainWithMessages::estimate_delivery_confirmation_transaction`: you'll need to return
-  estimated size and dispatch weight of the delivery confirmation transaction (that happens on
-  this chain) from this function.
-
-- `ThisChainWithMessages::transaction_payment`: you'll need to return fee that the submitter
-  must pay for given transaction on this chain. Normally, you would use transaction payment pallet
-  for this. However, if your chain has non-zero fee multiplier set, this would mean that the
-  payment will be computed using current value of this multiplier. But since this transaction
-  will be submitted in the future, you may want to choose other value instead. Otherwise,
-  non-altruistic relayer may choose not to submit this transaction until number of transactions
-  will decrease.
-
-## `BridgedChainWithMessages` Trait
-
-This trait represents this chain from bridge point of view. Let's review every method of this trait:
-
-- `BridgedChainWithMessages::maximal_extrinsic_size`: you will need to return the maximal
-  extrinsic size of the target chain from this function.
-
-- `MessageBridge::message_weight_limits`: you'll need to return a range of
-  dispatch weights that the outbound message may take at the target chain. Please keep in mind that
-  our helpers assume that the message is an encoded call of the target chain. But we never decode
-  this call at the source chain. So you can't simply get dispatch weight from pre-dispatch
-  information. Instead there are two options to prepare this range: if you know which calls are to
-  be sent over your bridge, then you may just return weight ranges for these particular calls.
-  Otherwise, if you're going to accept all kinds of calls, you may just return range `[0; maximal
-  incoming message dispatch weight]`. If you choose the latter, then you shall remember that the
-  delivery transaction itself has some weight, so you can't accept messages with weight equal to
-  maximal weight of extrinsic at the target chain. In our test chains, we reject all messages that
-  have declared dispatch weight larger than 50% of the maximal bridged extrinsic weight.
-
-- `MessageBridge::estimate_delivery_transaction`: you will need to return estimated dispatch weight and
-  size of the delivery transaction that delivers a given message to the target chain. The transaction
-  weight must or must not include the weight of pay-dispatch-fee operation, depending on the value
-  of `include_pay_dispatch_fee_cost` argument.
-
-- `MessageBridge::transaction_payment`: you'll need to return fee that the submitter
-  must pay for given transaction on bridged chain. The best case is when you have the same conversion
-  formula on both chains - then you may just reuse the `ThisChainWithMessages::transaction_payment`
-  implementation. Otherwise, you'll need to hardcode this formula into your runtime.
-
-## Helpers for the Source Chain
-
-The helpers for the Source Chain reside in the `source` submodule of the
-[`messages`](./src/messages.rs) module. The structs are: `FromThisChainMessagePayload`,
-`FromBridgedChainMessagesDeliveryProof`, `FromThisChainMessageVerifier`. And the helper functions
-are: `maximal_message_size`, `verify_chain_message`, `verify_messages_delivery_proof` and
-`estimate_message_dispatch_and_delivery_fee`.
-
-`FromThisChainMessagePayload` is a message that the sender sends through our bridge. It is the
-`bp_message_dispatch::MessagePayload`, where `call` field is encoded target chain call. So
-at this chain we don't see internals of this call - we just know its size.
-
-`FromThisChainMessageVerifier` is an implementation of `bp_messages::LaneMessageVerifier`. It
-has following checks in its `verify_message` method:
-
-1. it'll verify that the used outbound lane is enabled in our runtime;
-
-1. it'll reject messages if there are too many undelivered outbound messages at this lane. The
-   sender need to wait while relayers will do their work before sending the message again;
-
-1. it'll reject a message if it has the wrong dispatch origin declared. Like if the submitter is not
-   the root of this chain, but it tries to dispatch the message at the target chain using
-   `bp_message_dispatch::CallOrigin::SourceRoot` origin. Or he has provided wrong signature
-   in the `bp_message_dispatch::CallOrigin::TargetAccount` origin;
-
-1. it'll reject a message if the delivery and dispatch fee that the submitter wants to pay is lesser
-   than the fee that is computed using the `estimate_message_dispatch_and_delivery_fee` function.
-
-`estimate_message_dispatch_and_delivery_fee` returns a minimal fee that the submitter needs to pay
-for sending a given message. The fee includes: payment for the delivery transaction at the target
-chain, payment for delivery confirmation transaction on this chain, payment for `Call` dispatch at
-the target chain and relayer interest.
-
-`FromBridgedChainMessagesDeliveryProof` holds the lane identifier and the storage proof of this
-inbound lane state at the bridged chain. This also holds the hash of the target chain header, that
-was used to generate this storage proof. The proof is verified by the
-`verify_messages_delivery_proof`, which simply checks that the target chain header is finalized
-(using Substrate bridge module) and then reads the inbound lane state from the proof.
-
-`verify_chain_message` function checks that the message may be delivered to the bridged chain. There
-are two main checks:
-
-1. that the message size is less than or equal to the `2/3` of maximal extrinsic size at the target
-   chain. We leave `1/3` for signed extras and for the storage proof overhead;
-
-1. that the message dispatch weight is less than or equal to the `1/2` of maximal normal extrinsic
-   weight at the target chain. We leave `1/2` for the delivery transaction overhead.
-
-## Helpers for the Target Chain
-
-The helpers for the target chain reside in the `target` submodule of the
-[`messages`](./src/messages.rs) module. The structs are: `FromBridgedChainMessagePayload`,
-`FromBridgedChainMessagesProof`, `FromBridgedChainMessagesProof`. And the helper functions are:
-`maximal_incoming_message_dispatch_weight`, `maximal_incoming_message_size` and
-`verify_messages_proof`.
-
-`FromBridgedChainMessagePayload` corresponds to the `FromThisChainMessagePayload` at the bridged
-chain. We expect that messages with this payload are stored in the `OutboundMessages` storage map of
-the [messages module](../../modules/messages/README.md). This map is used to build
-`FromBridgedChainMessagesProof`. The proof holds the lane id, range of message nonces included in
-the proof, storage proof of `OutboundMessages` entries and the hash of bridged chain header that has
-been used to build the proof. Additionally, there's storage proof may contain the proof of outbound
-lane state. It may be required to prune `relayers` entries at this chain (see
-[messages module documentation](../../modules/messages/README.md#What-about-other-Constants-in-the-Messages-Module-Configuration-Trait)
-for details). This proof is verified by the `verify_messages_proof` function.
diff --git a/bridges/bin/runtime-common/src/integrity.rs b/bridges/bin/runtime-common/src/integrity.rs
index ab517566a0fe6e882802b1cb0b77bd1f5d4503bd..603f385f29ed53d69f9a50626b73beade48856aa 100644
--- a/bridges/bin/runtime-common/src/integrity.rs
+++ b/bridges/bin/runtime-common/src/integrity.rs
@@ -120,10 +120,10 @@ macro_rules! assert_bridge_messages_pallet_types(
 			use pallet_bridge_messages::Config as MessagesConfig;
 			use static_assertions::assert_type_eq_all;
 
-			assert_type_eq_all!(<$r as MessagesConfig<$i>>::OutboundPayload, FromThisChainMessagePayload<$bridge>);
+			assert_type_eq_all!(<$r as MessagesConfig<$i>>::OutboundPayload, FromThisChainMessagePayload);
 			assert_type_eq_all!(<$r as MessagesConfig<$i>>::OutboundMessageFee, BalanceOf<ThisChain<$bridge>>);
 
-			assert_type_eq_all!(<$r as MessagesConfig<$i>>::InboundPayload, FromBridgedChainMessagePayload<$bridge>);
+			assert_type_eq_all!(<$r as MessagesConfig<$i>>::InboundPayload, FromBridgedChainMessagePayload);
 			assert_type_eq_all!(<$r as MessagesConfig<$i>>::InboundMessageFee, BalanceOf<BridgedChain<$bridge>>);
 			assert_type_eq_all!(<$r as MessagesConfig<$i>>::InboundRelayer, AccountIdOf<BridgedChain<$bridge>>);
 
diff --git a/bridges/bin/runtime-common/src/messages.rs b/bridges/bin/runtime-common/src/messages.rs
index 6bcaae4d36577fba79f5a8acc4292a24d7af1cc7..f7eb0b2975d6bb964e1a9001737512fb676d159a 100644
--- a/bridges/bin/runtime-common/src/messages.rs
+++ b/bridges/bin/runtime-common/src/messages.rs
@@ -20,32 +20,21 @@
 //! pallet is used to dispatch incoming messages. Message identified by a tuple
 //! of to elements - message lane id and message nonce.
 
-use bp_message_dispatch::MessageDispatch as _;
 use bp_messages::{
 	source_chain::LaneMessageVerifier,
 	target_chain::{DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages},
 	InboundLaneData, LaneId, Message, MessageData, MessageKey, MessageNonce, OutboundLaneData,
 };
-use bp_runtime::{
-	messages::{DispatchFeePayment, MessageDispatchResult},
-	ChainId, Size, StorageProofChecker,
-};
-use codec::{Decode, DecodeLimit, Encode};
-use frame_support::{
-	traits::{Currency, ExistenceRequirement},
-	weights::{Weight, WeightToFeePolynomial},
-	RuntimeDebug,
-};
+use bp_runtime::{messages::MessageDispatchResult, ChainId, Size, StorageProofChecker};
+use codec::{Decode, Encode};
+use frame_support::{traits::Currency, weights::Weight, RuntimeDebug};
 use hash_db::Hasher;
 use scale_info::TypeInfo;
 use sp_runtime::{
-	traits::{AtLeast32BitUnsigned, CheckedAdd, CheckedDiv, CheckedMul, Saturating, Zero},
+	traits::{AtLeast32BitUnsigned, CheckedAdd, CheckedDiv, CheckedMul, Saturating},
 	FixedPointNumber, FixedPointOperand, FixedU128,
 };
-use sp_std::{
-	cmp::PartialOrd, convert::TryFrom, fmt::Debug, marker::PhantomData, ops::RangeInclusive,
-	vec::Vec,
-};
+use sp_std::{cmp::PartialOrd, convert::TryFrom, fmt::Debug, marker::PhantomData, vec::Vec};
 use sp_trie::StorageProof;
 
 /// Bidirectional message bridge.
@@ -136,16 +125,9 @@ pub trait BridgedChainWithMessages: ChainWithMessages {
 	/// Maximal extrinsic size at Bridged chain.
 	fn maximal_extrinsic_size() -> u32;
 
-	/// Returns feasible weights range for given message payload at the Bridged chain.
-	///
-	/// If message is being sent with the weight that is out of this range, then it
-	/// should be rejected.
-	///
-	/// Weights returned from this function shall not include transaction overhead
-	/// (like weight of signature and signed extensions verification), because they're
-	/// already accounted by the `weight_of_delivery_transaction`. So this function should
-	/// return pure call dispatch weights range.
-	fn message_weight_limits(message_payload: &[u8]) -> RangeInclusive<Self::Weight>;
+	/// Returns `true` if message dispatch weight is withing expected limits. `false` means
+	/// that the message is too heavy to be sent over the bridge and shall be rejected.
+	fn verify_dispatch_weight(message_payload: &[u8]) -> bool;
 
 	/// Estimate size and weight of single message delivery transaction at the Bridged chain.
 	fn estimate_delivery_transaction(
@@ -218,12 +200,7 @@ pub mod source {
 	pub type BridgedChainOpaqueCall = Vec<u8>;
 
 	/// Message payload for This -> Bridged chain messages.
-	pub type FromThisChainMessagePayload<B> = bp_message_dispatch::MessagePayload<
-		AccountIdOf<ThisChain<B>>,
-		SignerOf<BridgedChain<B>>,
-		SignatureOf<BridgedChain<B>>,
-		BridgedChainOpaqueCall,
-	>;
+	pub type FromThisChainMessagePayload = Vec<u8>;
 
 	/// Messages delivery proof from bridged chain:
 	///
@@ -260,7 +237,6 @@ pub mod source {
 	/// This verifier assumes following:
 	///
 	/// - all message lanes are equivalent, so all checks are the same;
-	/// - messages are being dispatched using `pallet-bridge-dispatch` pallet on the target chain.
 	///
 	/// Following checks are made:
 	///
@@ -288,7 +264,7 @@ pub mod source {
 		LaneMessageVerifier<
 			OriginOf<ThisChain<B>>,
 			AccountIdOf<ThisChain<B>>,
-			FromThisChainMessagePayload<B>,
+			FromThisChainMessagePayload,
 			BalanceOf<ThisChain<B>>,
 		> for FromThisChainMessageVerifier<B>
 	where
@@ -305,7 +281,7 @@ pub mod source {
 			delivery_and_dispatch_fee: &BalanceOf<ThisChain<B>>,
 			lane: &LaneId,
 			lane_outbound_data: &OutboundLaneData,
-			payload: &FromThisChainMessagePayload<B>,
+			payload: &FromThisChainMessagePayload,
 		) -> Result<(), Self::Error> {
 			// reject message if lane is blocked
 			if !ThisChain::<B>::is_message_accepted(submitter, lane) {
@@ -321,24 +297,6 @@ pub mod source {
 				return Err(TOO_MANY_PENDING_MESSAGES)
 			}
 
-			// Do the dispatch-specific check. We assume that the target chain uses
-			// `Dispatch`, so we verify the message accordingly.
-			let raw_origin_or_err: Result<
-				frame_system::RawOrigin<AccountIdOf<ThisChain<B>>>,
-				OriginOf<ThisChain<B>>,
-			> = submitter.clone().into();
-			if let Ok(raw_origin) = raw_origin_or_err {
-				pallet_bridge_dispatch::verify_message_origin(&raw_origin, payload)
-					.map(drop)
-					.map_err(|_| BAD_ORIGIN)?;
-			} else {
-				// so what it means that we've failed to convert origin to the
-				// `frame_system::RawOrigin`? now it means that the custom pallet origin has
-				// been used to send the message. Do we need to verify it? The answer is no,
-				// because pallet may craft any origin (e.g. root) && we can't verify whether it
-				// is valid, or not.
-			};
-
 			let minimal_fee_in_this_tokens = estimate_message_dispatch_and_delivery_fee::<B>(
 				payload,
 				B::RELAYER_FEE_PERCENT,
@@ -365,10 +323,9 @@ pub mod source {
 	/// may be 'mined' by the target chain. But the lane may have its own checks (e.g. fee
 	/// check) that would reject message (see `FromThisChainMessageVerifier`).
 	pub fn verify_chain_message<B: MessageBridge>(
-		payload: &FromThisChainMessagePayload<B>,
+		payload: &FromThisChainMessagePayload,
 	) -> Result<(), &'static str> {
-		let weight_limits = BridgedChain::<B>::message_weight_limits(&payload.call);
-		if !weight_limits.contains(&payload.weight.into()) {
+		if !BridgedChain::<B>::verify_dispatch_weight(payload) {
 			return Err("Incorrect message weight declared")
 		}
 
@@ -382,7 +339,7 @@ pub mod source {
 		// is enormously large, it should be several dozens/hundreds of bytes. The delivery
 		// transaction also contains signatures and signed extensions. Because of this, we reserve
 		// 1/3 of the the maximal extrinsic weight for this data.
-		if payload.call.len() > maximal_message_size::<B>() as usize {
+		if payload.len() > maximal_message_size::<B>() as usize {
 			return Err("The message is too large to be sent over the lane")
 		}
 
@@ -395,7 +352,7 @@ pub mod source {
 	/// The fee is paid in This chain Balance, but we use Bridged chain balance to avoid additional
 	/// conversions. Returns `None` if overflow has happened.
 	pub fn estimate_message_dispatch_and_delivery_fee<B: MessageBridge>(
-		payload: &FromThisChainMessagePayload<B>,
+		payload: &FromThisChainMessagePayload,
 		relayer_fee_percent: u32,
 		bridged_to_this_conversion_rate: Option<FixedU128>,
 	) -> Result<BalanceOf<ThisChain<B>>, &'static str> {
@@ -403,13 +360,8 @@ pub mod source {
 		//
 		// if we're going to pay dispatch fee at the target chain, then we don't include weight
 		// of the message dispatch in the delivery transaction cost
-		let pay_dispatch_fee_at_target_chain =
-			payload.dispatch_fee_payment == DispatchFeePayment::AtTargetChain;
-		let delivery_transaction = BridgedChain::<B>::estimate_delivery_transaction(
-			&payload.encode(),
-			pay_dispatch_fee_at_target_chain,
-			if pay_dispatch_fee_at_target_chain { 0.into() } else { payload.weight.into() },
-		);
+		let delivery_transaction =
+			BridgedChain::<B>::estimate_delivery_transaction(&payload.encode(), true, 0.into());
 		let delivery_transaction_fee = BridgedChain::<B>::transaction_payment(delivery_transaction);
 
 		// the fee (in This tokens) of all transactions that are made on This chain
@@ -477,20 +429,8 @@ pub mod source {
 pub mod target {
 	use super::*;
 
-	/// Call origin for Bridged -> This chain messages.
-	pub type FromBridgedChainMessageCallOrigin<B> = bp_message_dispatch::CallOrigin<
-		AccountIdOf<BridgedChain<B>>,
-		SignerOf<ThisChain<B>>,
-		SignatureOf<ThisChain<B>>,
-	>;
-
 	/// Decoded Bridged -> This message payload.
-	pub type FromBridgedChainMessagePayload<B> = bp_message_dispatch::MessagePayload<
-		AccountIdOf<BridgedChain<B>>,
-		SignerOf<ThisChain<B>>,
-		SignatureOf<ThisChain<B>>,
-		FromBridgedChainEncodedMessageCall<CallOf<ThisChain<B>>>,
-	>;
+	pub type FromBridgedChainMessagePayload = Vec<u8>;
 
 	/// Messages proof from bridged chain:
 	///
@@ -522,35 +462,6 @@ pub mod target {
 		}
 	}
 
-	/// Encoded Call of This chain as it is transferred over bridge.
-	///
-	/// Our Call is opaque (`Vec<u8>`) for Bridged chain. So it is encoded, prefixed with
-	/// vector length. Custom decode implementation here is exactly to deal with this.
-	#[derive(Decode, Encode, RuntimeDebug, PartialEq)]
-	pub struct FromBridgedChainEncodedMessageCall<DecodedCall> {
-		encoded_call: Vec<u8>,
-		_marker: PhantomData<DecodedCall>,
-	}
-
-	impl<DecodedCall> FromBridgedChainEncodedMessageCall<DecodedCall> {
-		/// Create encoded call.
-		pub fn new(encoded_call: Vec<u8>) -> Self {
-			FromBridgedChainEncodedMessageCall { encoded_call, _marker: PhantomData::default() }
-		}
-	}
-
-	impl<DecodedCall: Decode> From<FromBridgedChainEncodedMessageCall<DecodedCall>>
-		for Result<DecodedCall, ()>
-	{
-		fn from(encoded_call: FromBridgedChainEncodedMessageCall<DecodedCall>) -> Self {
-			DecodedCall::decode_with_depth_limit(
-				sp_api::MAX_EXTRINSIC_DEPTH,
-				&mut &encoded_call.encoded_call[..],
-			)
-			.map_err(drop)
-		}
-	}
-
 	/// Dispatching Bridged -> This chain messages.
 	#[derive(RuntimeDebug, Clone, Copy)]
 	pub struct FromBridgedChainMessageDispatch<B, ThisRuntime, ThisCurrency, ThisDispatchInstance> {
@@ -563,60 +474,33 @@ pub mod target {
 	where
 		BalanceOf<ThisChain<B>>: Saturating + FixedPointOperand,
 		ThisDispatchInstance: 'static,
-		ThisRuntime: pallet_bridge_dispatch::Config<
-				ThisDispatchInstance,
-				BridgeMessageId = (LaneId, MessageNonce),
-			> + pallet_transaction_payment::Config,
+		ThisRuntime: pallet_transaction_payment::Config,
 		<ThisRuntime as pallet_transaction_payment::Config>::OnChargeTransaction:
 			pallet_transaction_payment::OnChargeTransaction<
 				ThisRuntime,
 				Balance = BalanceOf<ThisChain<B>>,
 			>,
 		ThisCurrency: Currency<AccountIdOf<ThisChain<B>>, Balance = BalanceOf<ThisChain<B>>>,
-		pallet_bridge_dispatch::Pallet<ThisRuntime, ThisDispatchInstance>:
-			bp_message_dispatch::MessageDispatch<
-				AccountIdOf<ThisChain<B>>,
-				(LaneId, MessageNonce),
-				Message = FromBridgedChainMessagePayload<B>,
-			>,
 	{
-		type DispatchPayload = FromBridgedChainMessagePayload<B>;
+		type DispatchPayload = FromBridgedChainMessagePayload;
 
 		fn dispatch_weight(
-			message: &DispatchMessage<Self::DispatchPayload, BalanceOf<BridgedChain<B>>>,
+			_message: &DispatchMessage<Self::DispatchPayload, BalanceOf<BridgedChain<B>>>,
 		) -> frame_support::weights::Weight {
-			message.data.payload.as_ref().map(|payload| payload.weight).unwrap_or(0)
+			0
 		}
 
 		fn dispatch(
-			relayer_account: &AccountIdOf<ThisChain<B>>,
+			_relayer_account: &AccountIdOf<ThisChain<B>>,
 			message: DispatchMessage<Self::DispatchPayload, BalanceOf<BridgedChain<B>>>,
 		) -> MessageDispatchResult {
 			let message_id = (message.key.lane_id, message.key.nonce);
-			pallet_bridge_dispatch::Pallet::<ThisRuntime, ThisDispatchInstance>::dispatch(
-				B::BRIDGED_CHAIN_ID,
-				B::THIS_CHAIN_ID,
-				message_id,
-				message.data.payload.map_err(drop),
-				|dispatch_origin, dispatch_weight| {
-					let unadjusted_weight_fee = ThisRuntime::WeightToFee::calc(&dispatch_weight);
-					let fee_multiplier =
-						pallet_transaction_payment::Pallet::<ThisRuntime>::next_fee_multiplier();
-					let adjusted_weight_fee =
-						fee_multiplier.saturating_mul_int(unadjusted_weight_fee);
-					if !adjusted_weight_fee.is_zero() {
-						ThisCurrency::transfer(
-							dispatch_origin,
-							relayer_account,
-							adjusted_weight_fee,
-							ExistenceRequirement::AllowDeath,
-						)
-						.map_err(drop)
-					} else {
-						Ok(())
-					}
-				},
-			)
+			log::trace!(target: "runtime::bridge-dispatch", "Incoming message {:?}: {:?}", message_id, message.data.payload);
+			MessageDispatchResult {
+				dispatch_result: true,
+				unspent_weight: 0,
+				dispatch_fee_paid_during_dispatch: false,
+			}
 		}
 	}
 
@@ -813,7 +697,8 @@ mod tests {
 	const THIS_CHAIN_WEIGHT_TO_BALANCE_RATE: Weight = 2;
 	const BRIDGED_CHAIN_WEIGHT_TO_BALANCE_RATE: Weight = 4;
 	const BRIDGED_CHAIN_TO_THIS_CHAIN_BALANCE_RATE: u32 = 6;
-	const BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT: Weight = 2048;
+	const BRIDGED_CHAIN_MIN_EXTRINSIC_WEIGHT: usize = 5;
+	const BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT: usize = 2048;
 	const BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE: u32 = 1024;
 
 	/// Bridge that is deployed on ThisChain and allows sending/receiving messages to/from
@@ -1016,7 +901,7 @@ mod tests {
 			unreachable!()
 		}
 
-		fn message_weight_limits(_message_payload: &[u8]) -> RangeInclusive<Self::Weight> {
+		fn verify_dispatch_weight(_message_payload: &[u8]) -> bool {
 			unreachable!()
 		}
 
@@ -1074,10 +959,9 @@ mod tests {
 			BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE
 		}
 
-		fn message_weight_limits(message_payload: &[u8]) -> RangeInclusive<Self::Weight> {
-			let begin =
-				std::cmp::min(BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT, message_payload.len() as Weight);
-			begin..=BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT
+		fn verify_dispatch_weight(message_payload: &[u8]) -> bool {
+			message_payload.len() >= BRIDGED_CHAIN_MIN_EXTRINSIC_WEIGHT &&
+				message_payload.len() <= BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT
 		}
 
 		fn estimate_delivery_transaction(
@@ -1102,57 +986,16 @@ mod tests {
 		OutboundLaneData::default()
 	}
 
-	#[test]
-	fn message_from_bridged_chain_is_decoded() {
-		// the message is encoded on the bridged chain
-		let message_on_bridged_chain =
-			source::FromThisChainMessagePayload::<OnBridgedChainBridge> {
-				spec_version: 1,
-				weight: 100,
-				origin: bp_message_dispatch::CallOrigin::SourceRoot,
-				dispatch_fee_payment: DispatchFeePayment::AtTargetChain,
-				call: ThisChainCall::Transfer.encode(),
-			}
-			.encode();
-
-		// and sent to this chain where it is decoded
-		let message_on_this_chain =
-			target::FromBridgedChainMessagePayload::<OnThisChainBridge>::decode(
-				&mut &message_on_bridged_chain[..],
-			)
-			.unwrap();
-		assert_eq!(
-			message_on_this_chain,
-			target::FromBridgedChainMessagePayload::<OnThisChainBridge> {
-				spec_version: 1,
-				weight: 100,
-				origin: bp_message_dispatch::CallOrigin::SourceRoot,
-				dispatch_fee_payment: DispatchFeePayment::AtTargetChain,
-				call: target::FromBridgedChainEncodedMessageCall::<ThisChainCall>::new(
-					ThisChainCall::Transfer.encode(),
-				),
-			}
-		);
-		assert_eq!(Ok(ThisChainCall::Transfer), message_on_this_chain.call.into());
-	}
-
 	const TEST_LANE_ID: &LaneId = b"test";
 	const MAXIMAL_PENDING_MESSAGES_AT_TEST_LANE: MessageNonce = 32;
 
-	fn regular_outbound_message_payload() -> source::FromThisChainMessagePayload<OnThisChainBridge>
-	{
-		source::FromThisChainMessagePayload::<OnThisChainBridge> {
-			spec_version: 1,
-			weight: 100,
-			origin: bp_message_dispatch::CallOrigin::SourceRoot,
-			dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
-			call: vec![42],
-		}
+	fn regular_outbound_message_payload() -> source::FromThisChainMessagePayload {
+		vec![42]
 	}
 
 	#[test]
 	fn message_fee_is_checked_by_verifier() {
-		const EXPECTED_MINIMAL_FEE: u32 = 5500;
+		const EXPECTED_MINIMAL_FEE: u32 = 2860;
 
 		// payload of the This -> Bridged chain message
 		let payload = regular_outbound_message_payload();
@@ -1167,25 +1010,6 @@ mod tests {
 			Ok(ThisChainBalance(EXPECTED_MINIMAL_FEE)),
 		);
 
-		// let's check if estimation is less than hardcoded, if dispatch is paid at target chain
-		let mut payload_with_pay_on_target = regular_outbound_message_payload();
-		payload_with_pay_on_target.dispatch_fee_payment = DispatchFeePayment::AtTargetChain;
-		let fee_at_source =
-			source::estimate_message_dispatch_and_delivery_fee::<OnThisChainBridge>(
-				&payload_with_pay_on_target,
-				OnThisChainBridge::RELAYER_FEE_PERCENT,
-				None,
-			)
-			.expect(
-				"estimate_message_dispatch_and_delivery_fee failed for pay-at-target-chain message",
-			);
-		assert!(
-			fee_at_source < EXPECTED_MINIMAL_FEE.into(),
-			"Computed fee {:?} without prepaid dispatch must be less than the fee with prepaid dispatch {}",
-			fee_at_source,
-			EXPECTED_MINIMAL_FEE,
-		);
-
 		// and now check that the verifier checks the fee
 		assert_eq!(
 			source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
@@ -1207,80 +1031,6 @@ mod tests {
 		.is_ok(),);
 	}
 
-	#[test]
-	fn should_disallow_root_calls_from_regular_accounts() {
-		// payload of the This -> Bridged chain message
-		let payload = source::FromThisChainMessagePayload::<OnThisChainBridge> {
-			spec_version: 1,
-			weight: 100,
-			origin: bp_message_dispatch::CallOrigin::SourceRoot,
-			dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
-			call: vec![42],
-		};
-
-		// and now check that the verifier checks the fee
-		assert_eq!(
-			source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
-				&ThisChainOrigin(Ok(frame_system::RawOrigin::Signed(ThisChainAccountId(0)))),
-				&ThisChainBalance(1_000_000),
-				TEST_LANE_ID,
-				&test_lane_outbound_data(),
-				&payload,
-			),
-			Err(source::BAD_ORIGIN)
-		);
-		assert_eq!(
-			source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
-				&ThisChainOrigin(Ok(frame_system::RawOrigin::None)),
-				&ThisChainBalance(1_000_000),
-				TEST_LANE_ID,
-				&test_lane_outbound_data(),
-				&payload,
-			),
-			Err(source::BAD_ORIGIN)
-		);
-		assert!(source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
-			&ThisChainOrigin(Ok(frame_system::RawOrigin::Root)),
-			&ThisChainBalance(1_000_000),
-			TEST_LANE_ID,
-			&test_lane_outbound_data(),
-			&payload,
-		)
-		.is_ok(),);
-	}
-
-	#[test]
-	fn should_verify_source_and_target_origin_matching() {
-		// payload of the This -> Bridged chain message
-		let payload = source::FromThisChainMessagePayload::<OnThisChainBridge> {
-			spec_version: 1,
-			weight: 100,
-			origin: bp_message_dispatch::CallOrigin::SourceAccount(ThisChainAccountId(1)),
-			dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
-			call: vec![42],
-		};
-
-		// and now check that the verifier checks the fee
-		assert_eq!(
-			source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
-				&ThisChainOrigin(Ok(frame_system::RawOrigin::Signed(ThisChainAccountId(0)))),
-				&ThisChainBalance(1_000_000),
-				TEST_LANE_ID,
-				&test_lane_outbound_data(),
-				&payload,
-			),
-			Err(source::BAD_ORIGIN)
-		);
-		assert!(source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
-			&ThisChainOrigin(Ok(frame_system::RawOrigin::Signed(ThisChainAccountId(1)))),
-			&ThisChainBalance(1_000_000),
-			TEST_LANE_ID,
-			&test_lane_outbound_data(),
-			&payload,
-		)
-		.is_ok(),);
-	}
-
 	#[test]
 	fn message_is_rejected_when_sent_using_disabled_lane() {
 		assert_eq!(
@@ -1315,58 +1065,42 @@ mod tests {
 
 	#[test]
 	fn verify_chain_message_rejects_message_with_too_small_declared_weight() {
-		assert!(source::verify_chain_message::<OnThisChainBridge>(
-			&source::FromThisChainMessagePayload::<OnThisChainBridge> {
-				spec_version: 1,
-				weight: 5,
-				origin: bp_message_dispatch::CallOrigin::SourceRoot,
-				dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
-				call: vec![1, 2, 3, 4, 5, 6],
-			},
-		)
+		assert!(source::verify_chain_message::<OnThisChainBridge>(&vec![
+			42;
+			BRIDGED_CHAIN_MIN_EXTRINSIC_WEIGHT -
+				1
+		])
 		.is_err());
 	}
 
 	#[test]
 	fn verify_chain_message_rejects_message_with_too_large_declared_weight() {
-		assert!(source::verify_chain_message::<OnThisChainBridge>(
-			&source::FromThisChainMessagePayload::<OnThisChainBridge> {
-				spec_version: 1,
-				weight: BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT + 1,
-				origin: bp_message_dispatch::CallOrigin::SourceRoot,
-				dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
-				call: vec![1, 2, 3, 4, 5, 6],
-			},
-		)
+		assert!(source::verify_chain_message::<OnThisChainBridge>(&vec![
+			42;
+			BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT -
+				1
+		])
 		.is_err());
 	}
 
 	#[test]
 	fn verify_chain_message_rejects_message_too_large_message() {
-		assert!(source::verify_chain_message::<OnThisChainBridge>(
-			&source::FromThisChainMessagePayload::<OnThisChainBridge> {
-				spec_version: 1,
-				weight: BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT,
-				origin: bp_message_dispatch::CallOrigin::SourceRoot,
-				dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
-				call: vec![0; source::maximal_message_size::<OnThisChainBridge>() as usize + 1],
-			},
-		)
+		assert!(source::verify_chain_message::<OnThisChainBridge>(&vec![
+			0;
+			source::maximal_message_size::<OnThisChainBridge>()
+				as usize + 1
+		],)
 		.is_err());
 	}
 
 	#[test]
 	fn verify_chain_message_accepts_maximal_message() {
 		assert_eq!(
-			source::verify_chain_message::<OnThisChainBridge>(
-				&source::FromThisChainMessagePayload::<OnThisChainBridge> {
-					spec_version: 1,
-					weight: BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT,
-					origin: bp_message_dispatch::CallOrigin::SourceRoot,
-					dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
-					call: vec![0; source::maximal_message_size::<OnThisChainBridge>() as _],
-				},
-			),
+			source::verify_chain_message::<OnThisChainBridge>(&vec![
+				0;
+				source::maximal_message_size::<OnThisChainBridge>()
+					as _
+			],),
 			Ok(()),
 		);
 	}
diff --git a/bridges/bin/runtime-common/src/messages_api.rs b/bridges/bin/runtime-common/src/messages_api.rs
index b09a88e62795982c64ffc99a07debff08e9eb24c..274d2ec2e00f8c3e575527dfb2fcee888579e0ac 100644
--- a/bridges/bin/runtime-common/src/messages_api.rs
+++ b/bridges/bin/runtime-common/src/messages_api.rs
@@ -16,10 +16,9 @@
 
 //! Helpers for implementing various message-related runtime API mthods.
 
-use crate::messages::{source::FromThisChainMessagePayload, MessageBridge};
+use crate::messages::MessageBridge;
 
 use bp_messages::{LaneId, MessageDetails, MessageNonce};
-use codec::Decode;
 use sp_std::vec::Vec;
 
 /// Implementation of the `To*OutboundLaneApi::message_details`.
@@ -37,14 +36,12 @@ where
 		.filter_map(|nonce| {
 			let message_data =
 				pallet_bridge_messages::Pallet::<Runtime, MessagesPalletInstance>::outbound_message_data(lane, nonce)?;
-			let decoded_payload =
-				FromThisChainMessagePayload::<BridgeConfig>::decode(&mut &message_data.payload[..]).ok()?;
 			Some(MessageDetails {
 				nonce,
-				dispatch_weight: decoded_payload.weight,
+				dispatch_weight: 0,
 				size: message_data.payload.len() as _,
 				delivery_and_dispatch_fee: message_data.fee,
-				dispatch_fee_payment: decoded_payload.dispatch_fee_payment,
+				dispatch_fee_payment: bp_runtime::messages::DispatchFeePayment::AtTargetChain,
 			})
 		})
 		.collect()
diff --git a/bridges/bin/runtime-common/src/messages_benchmarking.rs b/bridges/bin/runtime-common/src/messages_benchmarking.rs
index 7c9f50e8ea0cea1370c8acadf8d182c1953c1f1f..f789bee9f7b148ec0e5e07c2f9fba6095585146d 100644
--- a/bridges/bin/runtime-common/src/messages_benchmarking.rs
+++ b/bridges/bin/runtime-common/src/messages_benchmarking.rs
@@ -27,13 +27,8 @@ use crate::messages::{
 };
 
 use bp_messages::{storage_keys, MessageData, MessageKey, MessagePayload};
-use bp_runtime::{messages::DispatchFeePayment, ChainId};
 use codec::Encode;
-use ed25519_dalek::{PublicKey, SecretKey, Signer, KEYPAIR_LENGTH, SECRET_KEY_LENGTH};
-use frame_support::{
-	traits::Currency,
-	weights::{GetDispatchInfo, Weight},
-};
+use frame_support::weights::{GetDispatchInfo, Weight};
 use pallet_bridge_messages::benchmarking::{
 	MessageDeliveryProofParams, MessageParams, MessageProofParams, ProofSize,
 };
@@ -41,49 +36,16 @@ use sp_core::Hasher;
 use sp_runtime::traits::{Header, IdentifyAccount, MaybeSerializeDeserialize, Zero};
 use sp_std::{fmt::Debug, prelude::*};
 use sp_trie::{record_all_keys, trie_types::TrieDBMutV1, LayoutV1, MemoryDB, Recorder, TrieMut};
-use sp_version::RuntimeVersion;
-
-/// Return this chain account, used to dispatch message.
-pub fn dispatch_account<B>() -> AccountIdOf<ThisChain<B>>
-where
-	B: MessageBridge,
-	SignerOf<ThisChain<B>>:
-		From<sp_core::ed25519::Public> + IdentifyAccount<AccountId = AccountIdOf<ThisChain<B>>>,
-{
-	let this_raw_public = PublicKey::from(&dispatch_account_secret());
-	let this_public: SignerOf<ThisChain<B>> =
-		sp_core::ed25519::Public::from_raw(this_raw_public.to_bytes()).into();
-	this_public.into_account()
-}
-
-/// Return public key of this chain account, used to dispatch message.
-pub fn dispatch_account_secret() -> SecretKey {
-	// key from the repo example (https://docs.rs/ed25519-dalek/1.0.1/ed25519_dalek/struct.SecretKey.html)
-	SecretKey::from_bytes(&[
-		157, 097, 177, 157, 239, 253, 090, 096, 186, 132, 074, 244, 146, 236, 044, 196, 068, 073,
-		197, 105, 123, 050, 105, 025, 112, 059, 172, 003, 028, 174, 127, 096,
-	])
-	.expect("harcoded key is valid")
-}
 
 /// Prepare outbound message for the `send_message` call.
 pub fn prepare_outbound_message<B>(
 	params: MessageParams<AccountIdOf<ThisChain<B>>>,
-) -> FromThisChainMessagePayload<B>
+) -> FromThisChainMessagePayload
 where
 	B: MessageBridge,
 	BalanceOf<ThisChain<B>>: From<u64>,
 {
-	let message_payload = vec![0; params.size as usize];
-	let dispatch_origin = bp_message_dispatch::CallOrigin::SourceAccount(params.sender_account);
-
-	FromThisChainMessagePayload::<B> {
-		spec_version: 0,
-		weight: params.size as _,
-		origin: dispatch_origin,
-		call: message_payload,
-		dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
-	}
+	vec![0; params.size as usize]
 }
 
 /// Prepare proof of messages for the `receive_messages_proof` call.
@@ -92,8 +54,6 @@ where
 /// proof.
 pub fn prepare_message_proof<R, BI, FI, B, BH, BHH>(
 	params: MessageProofParams,
-	version: &RuntimeVersion,
-	endow_amount: BalanceOf<ThisChain<B>>,
 ) -> (FromBridgedChainMessagesProof<HashOf<BridgedChain<B>>>, Weight)
 where
 	R: frame_system::Config<AccountId = AccountIdOf<ThisChain<B>>>
@@ -115,51 +75,10 @@ where
 		+ From<sp_core::ed25519::Public>
 		+ IdentifyAccount<AccountId = AccountIdOf<ThisChain<B>>>,
 {
-	// we'll be dispatching the same call at This chain
-	let remark = match params.size {
+	let message_payload = match params.size {
 		ProofSize::Minimal(ref size) => vec![0u8; *size as _],
 		_ => vec![],
 	};
-	let call: CallOf<ThisChain<B>> = frame_system::Call::remark { remark }.into();
-	let call_weight = call.get_dispatch_info().weight;
-
-	// message payload needs to be signed, because we use `TargetAccount` call origin
-	// (which is 'heaviest' to verify)
-	let bridged_account_id: AccountIdOf<BridgedChain<B>> = [0u8; 32].into();
-	let (this_raw_public, this_raw_signature) = ed25519_sign(
-		&call,
-		&bridged_account_id,
-		version.spec_version,
-		B::BRIDGED_CHAIN_ID,
-		B::THIS_CHAIN_ID,
-	);
-	let this_public: SignerOf<ThisChain<B>> =
-		sp_core::ed25519::Public::from_raw(this_raw_public).into();
-	let this_signature: SignatureOf<ThisChain<B>> =
-		sp_core::ed25519::Signature::from_raw(this_raw_signature).into();
-
-	// if dispatch fee is paid at this chain, endow relayer account
-	if params.dispatch_fee_payment == DispatchFeePayment::AtTargetChain {
-		assert_eq!(this_public.clone().into_account(), dispatch_account::<B>());
-		pallet_balances::Pallet::<R, BI>::make_free_balance_be(
-			&this_public.clone().into_account(),
-			endow_amount,
-		);
-	}
-
-	// prepare message payload that is stored in the Bridged chain storage
-	let message_payload = bp_message_dispatch::MessagePayload {
-		spec_version: version.spec_version,
-		weight: call_weight,
-		origin: bp_message_dispatch::CallOrigin::<
-			AccountIdOf<BridgedChain<B>>,
-			SignerOf<ThisChain<B>>,
-			SignatureOf<ThisChain<B>>,
-		>::TargetAccount(bridged_account_id, this_public, this_signature),
-		dispatch_fee_payment: params.dispatch_fee_payment.clone(),
-		call: call.encode(),
-	}
-	.encode();
 
 	// finally - prepare storage proof and update environment
 	let (state_root, storage_proof) =
@@ -174,11 +93,7 @@ where
 			nonces_start: *params.message_nonces.start(),
 			nonces_end: *params.message_nonces.end(),
 		},
-		call_weight
-			.checked_mul(
-				params.message_nonces.end().saturating_sub(*params.message_nonces.start()) + 1,
-			)
-			.expect("too many messages requested by benchmark"),
+		0,
 	)
 }
 
@@ -312,40 +227,6 @@ where
 	bridged_header_hash
 }
 
-/// Generate ed25519 signature to be used in
-/// `pallet_brdige_call_dispatch::CallOrigin::TargetAccount`.
-///
-/// Returns public key of the signer and the signature itself.
-fn ed25519_sign(
-	target_call: &impl Encode,
-	source_account_id: &impl Encode,
-	target_spec_version: u32,
-	source_chain_id: ChainId,
-	target_chain_id: ChainId,
-) -> ([u8; 32], [u8; 64]) {
-	let target_secret = dispatch_account_secret();
-	let target_public: PublicKey = (&target_secret).into();
-
-	let mut target_pair_bytes = [0u8; KEYPAIR_LENGTH];
-	target_pair_bytes[..SECRET_KEY_LENGTH].copy_from_slice(&target_secret.to_bytes());
-	target_pair_bytes[SECRET_KEY_LENGTH..].copy_from_slice(&target_public.to_bytes());
-	let target_pair =
-		ed25519_dalek::Keypair::from_bytes(&target_pair_bytes).expect("hardcoded pair is valid");
-
-	let signature_message = pallet_bridge_dispatch::account_ownership_digest(
-		target_call,
-		source_account_id,
-		target_spec_version,
-		source_chain_id,
-		target_chain_id,
-	);
-	let target_origin_signature = target_pair
-		.try_sign(&signature_message)
-		.expect("Ed25519 try_sign should not fail in benchmarks");
-
-	(target_public.to_bytes(), target_origin_signature.to_bytes())
-}
-
 /// Populate trie with dummy keys+values until trie has at least given size.
 fn grow_trie<H: Hasher>(mut root: H::Out, mdb: &mut MemoryDB<H>, trie_size: ProofSize) -> H::Out {
 	let (iterations, leaf_size, minimal_trie_size) = match trie_size {
diff --git a/bridges/modules/dispatch/Cargo.toml b/bridges/modules/dispatch/Cargo.toml
deleted file mode 100644
index c2e8c74da828dad9b87c53809028c124c8d8ddd0..0000000000000000000000000000000000000000
--- a/bridges/modules/dispatch/Cargo.toml
+++ /dev/null
@@ -1,42 +0,0 @@
-[package]
-name = "pallet-bridge-dispatch"
-description = "A Substrate Runtime module that dispatches a bridge message, treating it simply as encoded Call"
-version = "0.1.0"
-authors = ["Parity Technologies <admin@parity.io>"]
-edition = "2021"
-license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
-
-[dependencies]
-codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false }
-log = { version = "0.4.14", default-features = false }
-scale-info = { version = "2.1.1", default-features = false, features = ["derive"] }
-
-# Bridge dependencies
-
-bp-message-dispatch = { path = "../../primitives/message-dispatch", default-features = false }
-bp-runtime = { path = "../../primitives/runtime", default-features = false }
-
-# Substrate Dependencies
-
-frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
-frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
-sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
-sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
-sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
-
-[dev-dependencies]
-sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" }
-
-[features]
-default = ["std"]
-std = [
-	"bp-message-dispatch/std",
-	"bp-runtime/std",
-	"frame-support/std",
-	"frame-system/std",
-	"log/std",
-	"scale-info/std",
-	"sp-core/std",
-	"sp-runtime/std",
-	"sp-std/std",
-]
diff --git a/bridges/modules/dispatch/README.md b/bridges/modules/dispatch/README.md
deleted file mode 100644
index 068ff1167f7d8fa618cf9aaecd62ade78264b48f..0000000000000000000000000000000000000000
--- a/bridges/modules/dispatch/README.md
+++ /dev/null
@@ -1,63 +0,0 @@
-# Call Dispatch Module
-
-The call dispatch module has a single internal (only callable by other runtime modules) entry point
-for dispatching encoded calls (`pallet_bridge_dispatch::Module::dispatch`). Every dispatch
-(successful or not) emits a corresponding module event. The module doesn't have any call-related
-requirements - they may come from the bridged chain over some message lane, or they may be crafted
-locally. But in this document we'll mostly talk about this module in the context of bridges.
-
-Every message that is being dispatched has three main characteristics:
-- `bridge` is the 4-bytes identifier of the bridge where this message comes from. This may be the
-  identifier of the bridged chain (like `b"rlto"` for messages coming from `Rialto`), or the
-  identifier of the bridge itself (`b"rimi"` for `Rialto` <-> `Millau` bridge);
-- `id` is the unique id of the message within the given bridge. For messages coming from the
-  [messages module](../messages/README.md), it may worth to use a tuple
-  `(LaneId, MessageNonce)` to identify a message;
-- `message` is the `bp_message_dispatch::MessagePayload` structure. The `call` field is set
-  to the (potentially) encoded `Call` of this chain.
-
-The easiest way to understand what is happening when a `Call` is being dispatched, is to look at the
-module events set:
-
-- `MessageRejected` event is emitted if a message has been rejected even before it has reached the
-  module. Dispatch then is called just to reflect the fact that message has been received, but we
-  have failed to pre-process it (e.g. because we have failed to decode `MessagePayload` structure
-  from the proof);
-- `MessageVersionSpecMismatch` event is emitted if current runtime specification version differs
-  from the version that has been used to encode the `Call`. The message payload has the
-  `spec_version`, that is filled by the message submitter. If this value differs from the current
-  runtime version, dispatch mechanism rejects to dispatch the message. Without this check, we may
-  decode the wrong `Call` for example if method arguments were changed;
-- `MessageCallDecodeFailed` event is emitted if we have failed to decode `Call` from the payload.
-  This may happen if the submitter has provided incorrect value in the `call` field, or if source
-  chain storage has been corrupted. The `Call` is decoded after `spec_version` check, so we'll never
-  try to decode `Call` from other runtime version;
-- `MessageSignatureMismatch` event is emitted if submitter has chose to dispatch message using
-  specified this chain account (`bp_message_dispatch::CallOrigin::TargetAccount` origin),
-  but he has failed to prove that he owns the private key for this account;
-- `MessageCallRejected` event is emitted if the module has been deployed with some call filter and
-  this filter has rejected the `Call`. In your bridge you may choose to reject all messages except
-  e.g. balance transfer calls;
-- `MessageWeightMismatch` event is emitted if the message submitter has specified invalid `Call`
-  dispatch weight in the `weight` field of the message payload. The value of this field is compared
-  to the pre-dispatch weight of the decoded `Call`. If it is less than the actual pre-dispatch
-  weight, the dispatch is rejected. Keep in mind, that even if post-dispatch weight will be less
-  than specified, the submitter still have to declare (and pay for) the maximal possible weight
-  (that is the pre-dispatch weight);
-- `MessageDispatchPaymentFailed` event is emitted if the message submitter has selected to pay
-  dispatch fee at the target chain, but has failed to do that;
-- `MessageDispatched` event is emitted if the message has passed all checks and we have actually
-  dispatched it. The dispatch may still fail, though - that's why we are including the dispatch
-  result in the event payload.
-
-When we talk about module in context of bridges, these events are helping in following cases:
-
-1. when the message submitter has access to the state of both chains and wants to monitor what has
-   happened with his message. Then he could use the message id (that he gets from the
-   [messages module events](../messages/README.md#General-Information)) to filter events of
-   call dispatch module at the target chain and actually see what has happened with his message;
-
-1. when the message submitter only has access to the source chain state (for example, when sender is
-   the runtime module at the source chain). In this case, your bridge may have additional mechanism
-   to deliver dispatch proofs (which are storage proof of module events) back to the source chain,
-   thus allowing the submitter to see what has happened with his messages.
diff --git a/bridges/modules/dispatch/src/lib.rs b/bridges/modules/dispatch/src/lib.rs
deleted file mode 100644
index 1e030b733205931e1fbba515241cd6c1ccfda74f..0000000000000000000000000000000000000000
--- a/bridges/modules/dispatch/src/lib.rs
+++ /dev/null
@@ -1,1084 +0,0 @@
-// Copyright 2019-2021 Parity Technologies (UK) Ltd.
-// This file is part of Parity Bridges Common.
-
-// Parity Bridges Common 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.
-
-// Parity Bridges Common 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 Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
-
-//! Runtime module which takes care of dispatching messages received over the bridge.
-//!
-//! The messages are interpreted directly as runtime `Call`. We attempt to decode
-//! them and then dispatch as usual. To prevent compatibility issues, the Calls have
-//! to include a `spec_version`. This will be checked before dispatch. In the case of
-//! a successful dispatch an event is emitted.
-
-#![cfg_attr(not(feature = "std"), no_std)]
-// Generated by `decl_event!`
-#![allow(clippy::unused_unit)]
-
-use bp_message_dispatch::{CallOrigin, MessageDispatch, MessagePayload, SpecVersion};
-use bp_runtime::{
-	derive_account_id,
-	messages::{DispatchFeePayment, MessageDispatchResult},
-	ChainId, SourceAccount,
-};
-use codec::Encode;
-use frame_support::{
-	dispatch::Dispatchable,
-	ensure,
-	traits::{Contains, Get},
-	weights::{extract_actual_weight, GetDispatchInfo},
-};
-use frame_system::RawOrigin;
-use sp_runtime::traits::{BadOrigin, Convert, IdentifyAccount, MaybeDisplay, Verify};
-use sp_std::{fmt::Debug, prelude::*};
-
-pub use pallet::*;
-
-#[frame_support::pallet]
-pub mod pallet {
-	use super::*;
-	use frame_support::pallet_prelude::*;
-	use frame_system::pallet_prelude::*;
-
-	#[pallet::config]
-	pub trait Config<I: 'static = ()>: frame_system::Config {
-		/// The overarching event type.
-		type Event: From<Event<Self, I>> + IsType<<Self as frame_system::Config>::Event>;
-		/// Id of the message. Whenever message is passed to the dispatch module, it emits
-		/// event with this id + dispatch result. Could be e.g. (LaneId, MessageNonce) if
-		/// it comes from the messages module.
-		type BridgeMessageId: Parameter;
-		/// Type of account ID on source chain.
-		type SourceChainAccountId: Parameter
-			+ Member
-			+ MaybeSerializeDeserialize
-			+ Debug
-			+ MaybeDisplay
-			+ Ord;
-		/// Type of account public key on target chain.
-		type TargetChainAccountPublic: Parameter + IdentifyAccount<AccountId = Self::AccountId>;
-		/// Type of signature that may prove that the message has been signed by
-		/// owner of `TargetChainAccountPublic`.
-		type TargetChainSignature: Parameter + Verify<Signer = Self::TargetChainAccountPublic>;
-		/// The overarching dispatch call type.
-		type Call: Parameter
-			+ GetDispatchInfo
-			+ Dispatchable<
-				Origin = <Self as frame_system::Config>::Origin,
-				PostInfo = frame_support::dispatch::PostDispatchInfo,
-			>;
-		/// Pre-dispatch filter for incoming calls.
-		///
-		/// The pallet will filter all incoming calls right before they're dispatched. If this
-		/// filter rejects the call, special event (`Event::MessageCallRejected`) is emitted.
-		type CallFilter: Contains<<Self as Config<I>>::Call>;
-		/// The type that is used to wrap the `Self::Call` when it is moved over bridge.
-		///
-		/// The idea behind this is to avoid `Call` conversion/decoding until we'll be sure
-		/// that all other stuff (like `spec_version`) is ok. If we would try to decode
-		/// `Call` which has been encoded using previous `spec_version`, then we might end
-		/// up with decoding error, instead of `MessageVersionSpecMismatch`.
-		type EncodedCall: Decode + Encode + Into<Result<<Self as Config<I>>::Call, ()>>;
-		/// A type which can be turned into an AccountId from a 256-bit hash.
-		///
-		/// Used when deriving target chain AccountIds from source chain AccountIds.
-		type AccountIdConverter: sp_runtime::traits::Convert<sp_core::hash::H256, Self::AccountId>;
-	}
-
-	type BridgeMessageIdOf<T, I> = <T as Config<I>>::BridgeMessageId;
-
-	#[pallet::pallet]
-	#[pallet::generate_store(pub(super) trait Store)]
-	pub struct Pallet<T, I = ()>(PhantomData<(T, I)>);
-
-	#[pallet::hooks]
-	impl<T: Config<I>, I: 'static> Hooks<BlockNumberFor<T>> for Pallet<T, I> {}
-
-	#[pallet::call]
-	impl<T: Config<I>, I: 'static> Pallet<T, I> {}
-
-	#[pallet::event]
-	#[pallet::generate_deposit(pub(super) fn deposit_event)]
-	pub enum Event<T: Config<I>, I: 'static = ()> {
-		/// Message has been rejected before reaching dispatch.
-		MessageRejected(ChainId, BridgeMessageIdOf<T, I>),
-		/// Message has been rejected by dispatcher because of spec version mismatch.
-		/// Last two arguments are: expected and passed spec version.
-		MessageVersionSpecMismatch(ChainId, BridgeMessageIdOf<T, I>, SpecVersion, SpecVersion),
-		/// Message has been rejected by dispatcher because of weight mismatch.
-		/// Last two arguments are: expected and passed call weight.
-		MessageWeightMismatch(ChainId, BridgeMessageIdOf<T, I>, Weight, Weight),
-		/// Message signature mismatch.
-		MessageSignatureMismatch(ChainId, BridgeMessageIdOf<T, I>),
-		/// We have failed to decode Call from the message.
-		MessageCallDecodeFailed(ChainId, BridgeMessageIdOf<T, I>),
-		/// The call from the message has been rejected by the call filter.
-		MessageCallRejected(ChainId, BridgeMessageIdOf<T, I>),
-		/// The origin account has failed to pay fee for dispatching the message.
-		MessageDispatchPaymentFailed(
-			ChainId,
-			BridgeMessageIdOf<T, I>,
-			<T as frame_system::Config>::AccountId,
-			Weight,
-		),
-		/// Message has been dispatched with given result.
-		MessageDispatched(ChainId, BridgeMessageIdOf<T, I>, DispatchResult),
-		/// Phantom member, never used. Needed to handle multiple pallet instances.
-		_Dummy(PhantomData<I>),
-	}
-}
-
-impl<T: Config<I>, I: 'static> MessageDispatch<T::AccountId, T::BridgeMessageId> for Pallet<T, I> {
-	type Message = MessagePayload<
-		T::SourceChainAccountId,
-		T::TargetChainAccountPublic,
-		T::TargetChainSignature,
-		T::EncodedCall,
-	>;
-
-	fn dispatch_weight(message: &Self::Message) -> bp_message_dispatch::Weight {
-		message.weight
-	}
-
-	fn dispatch<P: FnOnce(&T::AccountId, bp_message_dispatch::Weight) -> Result<(), ()>>(
-		source_chain: ChainId,
-		target_chain: ChainId,
-		id: T::BridgeMessageId,
-		message: Result<Self::Message, ()>,
-		pay_dispatch_fee: P,
-	) -> MessageDispatchResult {
-		// emit special even if message has been rejected by external component
-		let message = match message {
-			Ok(message) => message,
-			Err(_) => {
-				log::trace!(
-					target: "runtime::bridge-dispatch",
-					"Message {:?}/{:?}: rejected before actual dispatch",
-					source_chain,
-					id,
-				);
-				Self::deposit_event(Event::MessageRejected(source_chain, id));
-				return MessageDispatchResult {
-					dispatch_result: false,
-					unspent_weight: 0,
-					dispatch_fee_paid_during_dispatch: false,
-				}
-			},
-		};
-
-		// verify spec version
-		// (we want it to be the same, because otherwise we may decode Call improperly)
-		let mut dispatch_result = MessageDispatchResult {
-			dispatch_result: false,
-			unspent_weight: message.weight,
-			dispatch_fee_paid_during_dispatch: false,
-		};
-		let expected_version = <T as frame_system::Config>::Version::get().spec_version;
-		if message.spec_version != expected_version {
-			log::trace!(
-				"Message {:?}/{:?}: spec_version mismatch. Expected {:?}, got {:?}",
-				source_chain,
-				id,
-				expected_version,
-				message.spec_version,
-			);
-			Self::deposit_event(Event::MessageVersionSpecMismatch(
-				source_chain,
-				id,
-				expected_version,
-				message.spec_version,
-			));
-			return dispatch_result
-		}
-
-		// now that we have spec version checked, let's decode the call
-		let call = match message.call.into() {
-			Ok(call) => call,
-			Err(_) => {
-				log::trace!(
-					target: "runtime::bridge-dispatch",
-					"Failed to decode Call from message {:?}/{:?}",
-					source_chain,
-					id,
-				);
-				Self::deposit_event(Event::MessageCallDecodeFailed(source_chain, id));
-				return dispatch_result
-			},
-		};
-
-		// prepare dispatch origin
-		let origin_account = match message.origin {
-			CallOrigin::SourceRoot => {
-				let hex_id =
-					derive_account_id::<T::SourceChainAccountId>(source_chain, SourceAccount::Root);
-				let target_id = T::AccountIdConverter::convert(hex_id);
-				log::trace!(target: "runtime::bridge-dispatch", "Root Account: {:?}", &target_id);
-				target_id
-			},
-			CallOrigin::TargetAccount(source_account_id, target_public, target_signature) => {
-				let digest = account_ownership_digest(
-					&call,
-					source_account_id,
-					message.spec_version,
-					source_chain,
-					target_chain,
-				);
-
-				let target_account = target_public.into_account();
-				if !target_signature.verify(&digest[..], &target_account) {
-					log::trace!(
-						target: "runtime::bridge-dispatch",
-						"Message {:?}/{:?}: origin proof is invalid. Expected account: {:?} from signature: {:?}",
-						source_chain,
-						id,
-						target_account,
-						target_signature,
-					);
-					Self::deposit_event(Event::MessageSignatureMismatch(source_chain, id));
-					return dispatch_result
-				}
-
-				log::trace!(target: "runtime::bridge-dispatch", "Target Account: {:?}", &target_account);
-				target_account
-			},
-			CallOrigin::SourceAccount(source_account_id) => {
-				let hex_id =
-					derive_account_id(source_chain, SourceAccount::Account(source_account_id));
-				let target_id = T::AccountIdConverter::convert(hex_id);
-				log::trace!(target: "runtime::bridge-dispatch", "Source Account: {:?}", &target_id);
-				target_id
-			},
-		};
-
-		// filter the call
-		if !T::CallFilter::contains(&call) {
-			log::trace!(
-				target: "runtime::bridge-dispatch",
-				"Message {:?}/{:?}: the call ({:?}) is rejected by filter",
-				source_chain,
-				id,
-				call,
-			);
-			Self::deposit_event(Event::MessageCallRejected(source_chain, id));
-			return dispatch_result
-		}
-
-		// verify weight
-		// (we want passed weight to be at least equal to pre-dispatch weight of the call
-		// because otherwise Calls may be dispatched at lower price)
-		let dispatch_info = call.get_dispatch_info();
-		let expected_weight = dispatch_info.weight;
-		if message.weight < expected_weight {
-			log::trace!(
-				target: "runtime::bridge-dispatch",
-				"Message {:?}/{:?}: passed weight is too low. Expected at least {:?}, got {:?}",
-				source_chain,
-				id,
-				expected_weight,
-				message.weight,
-			);
-			Self::deposit_event(Event::MessageWeightMismatch(
-				source_chain,
-				id,
-				expected_weight,
-				message.weight,
-			));
-			return dispatch_result
-		}
-
-		// pay dispatch fee right before dispatch
-		let pay_dispatch_fee_at_target_chain =
-			message.dispatch_fee_payment == DispatchFeePayment::AtTargetChain;
-		if pay_dispatch_fee_at_target_chain &&
-			pay_dispatch_fee(&origin_account, message.weight).is_err()
-		{
-			log::trace!(
-				target: "runtime::bridge-dispatch",
-				"Failed to pay dispatch fee for dispatching message {:?}/{:?} with weight {}",
-				source_chain,
-				id,
-				message.weight,
-			);
-			Self::deposit_event(Event::MessageDispatchPaymentFailed(
-				source_chain,
-				id,
-				origin_account,
-				message.weight,
-			));
-			return dispatch_result
-		}
-		dispatch_result.dispatch_fee_paid_during_dispatch = pay_dispatch_fee_at_target_chain;
-
-		// finally dispatch message
-		let origin = RawOrigin::Signed(origin_account).into();
-
-		log::trace!(target: "runtime::bridge-dispatch", "Message being dispatched is: {:.4096?}", &call);
-		let result = call.dispatch(origin);
-		let actual_call_weight = extract_actual_weight(&result, &dispatch_info);
-		dispatch_result.dispatch_result = result.is_ok();
-		dispatch_result.unspent_weight = message.weight.saturating_sub(actual_call_weight);
-
-		log::trace!(
-			target: "runtime::bridge-dispatch",
-			"Message {:?}/{:?} has been dispatched. Weight: {} of {}. Result: {:?}. Call dispatch result: {:?}",
-			source_chain,
-			id,
-			actual_call_weight,
-			message.weight,
-			dispatch_result,
-			result,
-		);
-
-		Self::deposit_event(Event::MessageDispatched(
-			source_chain,
-			id,
-			result.map(drop).map_err(|e| e.error),
-		));
-
-		dispatch_result
-	}
-}
-
-/// Check if the message is allowed to be dispatched on the target chain given the sender's origin
-/// on the source chain.
-///
-/// For example, if a message is sent from a "regular" account on the source chain it will not be
-/// allowed to be dispatched as Root on the target chain. This is a useful check to do on the source
-/// chain _before_ sending a message whose dispatch will be rejected on the target chain.
-pub fn verify_message_origin<
-	SourceChainAccountId,
-	TargetChainAccountPublic,
-	TargetChainSignature,
-	Call,
->(
-	sender_origin: &RawOrigin<SourceChainAccountId>,
-	message: &MessagePayload<
-		SourceChainAccountId,
-		TargetChainAccountPublic,
-		TargetChainSignature,
-		Call,
-	>,
-) -> Result<Option<SourceChainAccountId>, BadOrigin>
-where
-	SourceChainAccountId: PartialEq + Clone,
-{
-	match message.origin {
-		CallOrigin::SourceRoot => {
-			ensure!(sender_origin == &RawOrigin::Root, BadOrigin);
-			Ok(None)
-		},
-		CallOrigin::TargetAccount(ref source_account_id, _, _) => {
-			ensure!(sender_origin == &RawOrigin::Signed(source_account_id.clone()), BadOrigin);
-			Ok(Some(source_account_id.clone()))
-		},
-		CallOrigin::SourceAccount(ref source_account_id) => {
-			ensure!(
-				sender_origin == &RawOrigin::Signed(source_account_id.clone()) ||
-					sender_origin == &RawOrigin::Root,
-				BadOrigin
-			);
-			Ok(Some(source_account_id.clone()))
-		},
-	}
-}
-
-/// Target account ownership digest from the source chain.
-///
-/// The byte vector returned by this function will be signed with a target chain account
-/// private key. This way, the owner of `source_account_id` on the source chain proves that
-/// the target chain account private key is also under his control.
-pub fn account_ownership_digest<Call, AccountId, SpecVersion>(
-	call: &Call,
-	source_account_id: AccountId,
-	target_spec_version: SpecVersion,
-	source_chain_id: ChainId,
-	target_chain_id: ChainId,
-) -> Vec<u8>
-where
-	Call: Encode,
-	AccountId: Encode,
-	SpecVersion: Encode,
-{
-	let mut proof = Vec::new();
-	call.encode_to(&mut proof);
-	source_account_id.encode_to(&mut proof);
-	target_spec_version.encode_to(&mut proof);
-	source_chain_id.encode_to(&mut proof);
-	target_chain_id.encode_to(&mut proof);
-
-	proof
-}
-
-#[cfg(test)]
-mod tests {
-	// From construct_runtime macro
-	#![allow(clippy::from_over_into)]
-
-	use super::*;
-	use codec::Decode;
-	use frame_support::{parameter_types, weights::Weight};
-	use frame_system::{EventRecord, Phase};
-	use scale_info::TypeInfo;
-	use sp_core::H256;
-	use sp_runtime::{
-		testing::Header,
-		traits::{BlakeTwo256, IdentityLookup},
-		Perbill,
-	};
-
-	type AccountId = u64;
-	type BridgeMessageId = [u8; 4];
-
-	const SOURCE_CHAIN_ID: ChainId = *b"srce";
-	const TARGET_CHAIN_ID: ChainId = *b"trgt";
-
-	#[derive(Debug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo)]
-	pub struct TestAccountPublic(AccountId);
-
-	impl IdentifyAccount for TestAccountPublic {
-		type AccountId = AccountId;
-
-		fn into_account(self) -> AccountId {
-			self.0
-		}
-	}
-
-	#[derive(Debug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo)]
-	pub struct TestSignature(AccountId);
-
-	impl Verify for TestSignature {
-		type Signer = TestAccountPublic;
-
-		fn verify<L: sp_runtime::traits::Lazy<[u8]>>(&self, _msg: L, signer: &AccountId) -> bool {
-			self.0 == *signer
-		}
-	}
-
-	pub struct AccountIdConverter;
-
-	impl sp_runtime::traits::Convert<H256, AccountId> for AccountIdConverter {
-		fn convert(hash: H256) -> AccountId {
-			hash.to_low_u64_ne()
-		}
-	}
-
-	type Block = frame_system::mocking::MockBlock<TestRuntime>;
-	type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<TestRuntime>;
-
-	use crate as call_dispatch;
-
-	frame_support::construct_runtime! {
-		pub enum TestRuntime where
-			Block = Block,
-			NodeBlock = Block,
-			UncheckedExtrinsic = UncheckedExtrinsic,
-		{
-			System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
-			Dispatch: call_dispatch::{Pallet, Call, Event<T>},
-		}
-	}
-
-	parameter_types! {
-		pub const BlockHashCount: u64 = 250;
-		pub const MaximumBlockWeight: Weight = 1024;
-		pub const MaximumBlockLength: u32 = 2 * 1024;
-		pub const AvailableBlockRatio: Perbill = Perbill::one();
-	}
-
-	impl frame_system::Config for TestRuntime {
-		type Origin = Origin;
-		type Index = u64;
-		type Call = Call;
-		type BlockNumber = u64;
-		type Hash = H256;
-		type Hashing = BlakeTwo256;
-		type AccountId = AccountId;
-		type Lookup = IdentityLookup<Self::AccountId>;
-		type Header = Header;
-		type Event = Event;
-		type BlockHashCount = BlockHashCount;
-		type Version = ();
-		type PalletInfo = PalletInfo;
-		type AccountData = ();
-		type OnNewAccount = ();
-		type OnKilledAccount = ();
-		type BaseCallFilter = frame_support::traits::Everything;
-		type SystemWeightInfo = ();
-		type BlockWeights = ();
-		type BlockLength = ();
-		type DbWeight = ();
-		type SS58Prefix = ();
-		type OnSetCode = ();
-		type MaxConsumers = frame_support::traits::ConstU32<16>;
-	}
-
-	impl Config for TestRuntime {
-		type Event = Event;
-		type BridgeMessageId = BridgeMessageId;
-		type SourceChainAccountId = AccountId;
-		type TargetChainAccountPublic = TestAccountPublic;
-		type TargetChainSignature = TestSignature;
-		type Call = Call;
-		type CallFilter = TestCallFilter;
-		type EncodedCall = EncodedCall;
-		type AccountIdConverter = AccountIdConverter;
-	}
-
-	#[derive(Decode, Encode)]
-	pub struct EncodedCall(Vec<u8>);
-
-	impl From<EncodedCall> for Result<Call, ()> {
-		fn from(call: EncodedCall) -> Result<Call, ()> {
-			Call::decode(&mut &call.0[..]).map_err(drop)
-		}
-	}
-
-	pub struct TestCallFilter;
-
-	impl Contains<Call> for TestCallFilter {
-		fn contains(call: &Call) -> bool {
-			!matches!(*call, Call::System(frame_system::Call::fill_block { .. }))
-		}
-	}
-
-	const TEST_SPEC_VERSION: SpecVersion = 0;
-	const TEST_WEIGHT: Weight = 1_000_000_000;
-
-	fn new_test_ext() -> sp_io::TestExternalities {
-		let t = frame_system::GenesisConfig::default().build_storage::<TestRuntime>().unwrap();
-		sp_io::TestExternalities::new(t)
-	}
-
-	fn prepare_message(
-		origin: CallOrigin<AccountId, TestAccountPublic, TestSignature>,
-		call: Call,
-	) -> <Pallet<TestRuntime> as MessageDispatch<
-		AccountId,
-		<TestRuntime as Config>::BridgeMessageId,
-	>>::Message {
-		MessagePayload {
-			spec_version: TEST_SPEC_VERSION,
-			weight: TEST_WEIGHT,
-			origin,
-			dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
-			call: EncodedCall(call.encode()),
-		}
-	}
-
-	fn prepare_root_message(
-		call: Call,
-	) -> <Pallet<TestRuntime> as MessageDispatch<
-		AccountId,
-		<TestRuntime as Config>::BridgeMessageId,
-	>>::Message {
-		prepare_message(CallOrigin::SourceRoot, call)
-	}
-
-	fn prepare_target_message(
-		call: Call,
-	) -> <Pallet<TestRuntime> as MessageDispatch<
-		AccountId,
-		<TestRuntime as Config>::BridgeMessageId,
-	>>::Message {
-		let origin = CallOrigin::TargetAccount(1, TestAccountPublic(1), TestSignature(1));
-		prepare_message(origin, call)
-	}
-
-	fn prepare_source_message(
-		call: Call,
-	) -> <Pallet<TestRuntime> as MessageDispatch<
-		AccountId,
-		<TestRuntime as Config>::BridgeMessageId,
-	>>::Message {
-		let origin = CallOrigin::SourceAccount(1);
-		prepare_message(origin, call)
-	}
-
-	#[test]
-	fn should_fail_on_spec_version_mismatch() {
-		new_test_ext().execute_with(|| {
-			let id = [0; 4];
-
-			const BAD_SPEC_VERSION: SpecVersion = 99;
-			let mut message = prepare_root_message(Call::System(frame_system::Call::remark {
-				remark: vec![1, 2, 3],
-			}));
-			let weight = message.weight;
-			message.spec_version = BAD_SPEC_VERSION;
-
-			System::set_block_number(1);
-			let result = Dispatch::dispatch(
-				SOURCE_CHAIN_ID,
-				TARGET_CHAIN_ID,
-				id,
-				Ok(message),
-				|_, _| unreachable!(),
-			);
-			assert_eq!(result.unspent_weight, weight);
-			assert!(!result.dispatch_result);
-
-			assert_eq!(
-				System::events(),
-				vec![EventRecord {
-					phase: Phase::Initialization,
-					event: Event::Dispatch(
-						call_dispatch::Event::<TestRuntime>::MessageVersionSpecMismatch(
-							SOURCE_CHAIN_ID,
-							id,
-							TEST_SPEC_VERSION,
-							BAD_SPEC_VERSION
-						)
-					),
-					topics: vec![],
-				}],
-			);
-		});
-	}
-
-	#[test]
-	fn should_fail_on_weight_mismatch() {
-		new_test_ext().execute_with(|| {
-			let id = [0; 4];
-			let call = Call::System(frame_system::Call::set_heap_pages { pages: 42 });
-			let call_weight = call.get_dispatch_info().weight;
-			let mut message = prepare_root_message(call);
-			message.weight = 7;
-			assert!(call_weight > 7, "needed for test to actually trigger a weight mismatch");
-
-			System::set_block_number(1);
-			let result = Dispatch::dispatch(
-				SOURCE_CHAIN_ID,
-				TARGET_CHAIN_ID,
-				id,
-				Ok(message),
-				|_, _| unreachable!(),
-			);
-			assert_eq!(result.unspent_weight, 7);
-			assert!(!result.dispatch_result);
-
-			assert_eq!(
-				System::events(),
-				vec![EventRecord {
-					phase: Phase::Initialization,
-					event: Event::Dispatch(
-						call_dispatch::Event::<TestRuntime>::MessageWeightMismatch(
-							SOURCE_CHAIN_ID,
-							id,
-							call_weight,
-							7,
-						)
-					),
-					topics: vec![],
-				}],
-			);
-		});
-	}
-
-	#[test]
-	fn should_fail_on_signature_mismatch() {
-		new_test_ext().execute_with(|| {
-			let id = [0; 4];
-
-			let call_origin = CallOrigin::TargetAccount(1, TestAccountPublic(1), TestSignature(99));
-			let message = prepare_message(
-				call_origin,
-				Call::System(frame_system::Call::remark { remark: vec![1, 2, 3] }),
-			);
-			let weight = message.weight;
-
-			System::set_block_number(1);
-			let result = Dispatch::dispatch(
-				SOURCE_CHAIN_ID,
-				TARGET_CHAIN_ID,
-				id,
-				Ok(message),
-				|_, _| unreachable!(),
-			);
-			assert_eq!(result.unspent_weight, weight);
-			assert!(!result.dispatch_result);
-
-			assert_eq!(
-				System::events(),
-				vec![EventRecord {
-					phase: Phase::Initialization,
-					event: Event::Dispatch(
-						call_dispatch::Event::<TestRuntime>::MessageSignatureMismatch(
-							SOURCE_CHAIN_ID,
-							id
-						)
-					),
-					topics: vec![],
-				}],
-			);
-		});
-	}
-
-	#[test]
-	fn should_emit_event_for_rejected_messages() {
-		new_test_ext().execute_with(|| {
-			let id = [0; 4];
-
-			System::set_block_number(1);
-			Dispatch::dispatch(
-				SOURCE_CHAIN_ID,
-				TARGET_CHAIN_ID,
-				id,
-				Err(()),
-				|_, _| unreachable!(),
-			);
-
-			assert_eq!(
-				System::events(),
-				vec![EventRecord {
-					phase: Phase::Initialization,
-					event: Event::Dispatch(call_dispatch::Event::<TestRuntime>::MessageRejected(
-						SOURCE_CHAIN_ID,
-						id
-					)),
-					topics: vec![],
-				}],
-			);
-		});
-	}
-
-	#[test]
-	fn should_fail_on_call_decode() {
-		new_test_ext().execute_with(|| {
-			let id = [0; 4];
-
-			let mut message = prepare_root_message(Call::System(frame_system::Call::remark {
-				remark: vec![1, 2, 3],
-			}));
-			let weight = message.weight;
-			message.call.0 = vec![];
-
-			System::set_block_number(1);
-			let result = Dispatch::dispatch(
-				SOURCE_CHAIN_ID,
-				TARGET_CHAIN_ID,
-				id,
-				Ok(message),
-				|_, _| unreachable!(),
-			);
-			assert_eq!(result.unspent_weight, weight);
-			assert!(!result.dispatch_result);
-
-			assert_eq!(
-				System::events(),
-				vec![EventRecord {
-					phase: Phase::Initialization,
-					event: Event::Dispatch(
-						call_dispatch::Event::<TestRuntime>::MessageCallDecodeFailed(
-							SOURCE_CHAIN_ID,
-							id
-						)
-					),
-					topics: vec![],
-				}],
-			);
-		});
-	}
-
-	#[test]
-	fn should_emit_event_for_rejected_calls() {
-		new_test_ext().execute_with(|| {
-			let id = [0; 4];
-
-			let call =
-				Call::System(frame_system::Call::fill_block { ratio: Perbill::from_percent(75) });
-			let weight = call.get_dispatch_info().weight;
-			let mut message = prepare_root_message(call);
-			message.weight = weight;
-
-			System::set_block_number(1);
-			let result = Dispatch::dispatch(
-				SOURCE_CHAIN_ID,
-				TARGET_CHAIN_ID,
-				id,
-				Ok(message),
-				|_, _| unreachable!(),
-			);
-			assert_eq!(result.unspent_weight, weight);
-			assert!(!result.dispatch_result);
-
-			assert_eq!(
-				System::events(),
-				vec![EventRecord {
-					phase: Phase::Initialization,
-					event: Event::Dispatch(
-						call_dispatch::Event::<TestRuntime>::MessageCallRejected(
-							SOURCE_CHAIN_ID,
-							id
-						)
-					),
-					topics: vec![],
-				}],
-			);
-		});
-	}
-
-	#[test]
-	fn should_emit_event_for_unpaid_calls() {
-		new_test_ext().execute_with(|| {
-			let id = [0; 4];
-
-			let mut message = prepare_root_message(Call::System(frame_system::Call::remark {
-				remark: vec![1, 2, 3],
-			}));
-			let weight = message.weight;
-			message.dispatch_fee_payment = DispatchFeePayment::AtTargetChain;
-
-			System::set_block_number(1);
-			let result =
-				Dispatch::dispatch(SOURCE_CHAIN_ID, TARGET_CHAIN_ID, id, Ok(message), |_, _| {
-					Err(())
-				});
-			assert_eq!(result.unspent_weight, weight);
-			assert!(!result.dispatch_result);
-
-			assert_eq!(
-				System::events(),
-				vec![EventRecord {
-					phase: Phase::Initialization,
-					event: Event::Dispatch(
-						call_dispatch::Event::<TestRuntime>::MessageDispatchPaymentFailed(
-							SOURCE_CHAIN_ID,
-							id,
-							AccountIdConverter::convert(derive_account_id::<AccountId>(
-								SOURCE_CHAIN_ID,
-								SourceAccount::Root
-							)),
-							TEST_WEIGHT,
-						)
-					),
-					topics: vec![],
-				}],
-			);
-		});
-	}
-
-	#[test]
-	fn should_dispatch_calls_paid_at_target_chain() {
-		new_test_ext().execute_with(|| {
-			let id = [0; 4];
-
-			let mut message = prepare_root_message(Call::System(frame_system::Call::remark {
-				remark: vec![1, 2, 3],
-			}));
-			message.dispatch_fee_payment = DispatchFeePayment::AtTargetChain;
-
-			System::set_block_number(1);
-			let result = Dispatch::dispatch(
-				SOURCE_CHAIN_ID,
-				TARGET_CHAIN_ID,
-				id,
-				Ok(message),
-				|_, _| Ok(()),
-			);
-			assert!(result.dispatch_fee_paid_during_dispatch);
-			assert!(result.dispatch_result);
-
-			assert_eq!(
-				System::events(),
-				vec![EventRecord {
-					phase: Phase::Initialization,
-					event: Event::Dispatch(call_dispatch::Event::<TestRuntime>::MessageDispatched(
-						SOURCE_CHAIN_ID,
-						id,
-						Ok(())
-					)),
-					topics: vec![],
-				}],
-			);
-		});
-	}
-
-	#[test]
-	fn should_return_dispatch_failed_flag_if_dispatch_happened_but_failed() {
-		new_test_ext().execute_with(|| {
-			let id = [0; 4];
-
-			let call = Call::System(frame_system::Call::set_heap_pages { pages: 1 });
-			let message = prepare_target_message(call);
-
-			System::set_block_number(1);
-			let result = Dispatch::dispatch(
-				SOURCE_CHAIN_ID,
-				TARGET_CHAIN_ID,
-				id,
-				Ok(message),
-				|_, _| unreachable!(),
-			);
-			assert!(!result.dispatch_fee_paid_during_dispatch);
-			assert!(!result.dispatch_result);
-
-			assert_eq!(
-				System::events(),
-				vec![EventRecord {
-					phase: Phase::Initialization,
-					event: Event::Dispatch(call_dispatch::Event::<TestRuntime>::MessageDispatched(
-						SOURCE_CHAIN_ID,
-						id,
-						Err(sp_runtime::DispatchError::BadOrigin)
-					)),
-					topics: vec![],
-				}],
-			);
-		})
-	}
-
-	#[test]
-	fn should_dispatch_bridge_message_from_root_origin() {
-		new_test_ext().execute_with(|| {
-			let id = [0; 4];
-			let message = prepare_root_message(Call::System(frame_system::Call::remark {
-				remark: vec![1, 2, 3],
-			}));
-
-			System::set_block_number(1);
-			let result = Dispatch::dispatch(
-				SOURCE_CHAIN_ID,
-				TARGET_CHAIN_ID,
-				id,
-				Ok(message),
-				|_, _| unreachable!(),
-			);
-			assert!(!result.dispatch_fee_paid_during_dispatch);
-			assert!(result.dispatch_result);
-
-			assert_eq!(
-				System::events(),
-				vec![EventRecord {
-					phase: Phase::Initialization,
-					event: Event::Dispatch(call_dispatch::Event::<TestRuntime>::MessageDispatched(
-						SOURCE_CHAIN_ID,
-						id,
-						Ok(())
-					)),
-					topics: vec![],
-				}],
-			);
-		});
-	}
-
-	#[test]
-	fn should_dispatch_bridge_message_from_target_origin() {
-		new_test_ext().execute_with(|| {
-			let id = [0; 4];
-
-			let call = Call::System(frame_system::Call::remark { remark: vec![] });
-			let message = prepare_target_message(call);
-
-			System::set_block_number(1);
-			let result = Dispatch::dispatch(
-				SOURCE_CHAIN_ID,
-				TARGET_CHAIN_ID,
-				id,
-				Ok(message),
-				|_, _| unreachable!(),
-			);
-			assert!(!result.dispatch_fee_paid_during_dispatch);
-			assert!(result.dispatch_result);
-
-			assert_eq!(
-				System::events(),
-				vec![EventRecord {
-					phase: Phase::Initialization,
-					event: Event::Dispatch(call_dispatch::Event::<TestRuntime>::MessageDispatched(
-						SOURCE_CHAIN_ID,
-						id,
-						Ok(())
-					)),
-					topics: vec![],
-				}],
-			);
-		})
-	}
-
-	#[test]
-	fn should_dispatch_bridge_message_from_source_origin() {
-		new_test_ext().execute_with(|| {
-			let id = [0; 4];
-
-			let call = Call::System(frame_system::Call::remark { remark: vec![] });
-			let message = prepare_source_message(call);
-
-			System::set_block_number(1);
-			let result = Dispatch::dispatch(
-				SOURCE_CHAIN_ID,
-				TARGET_CHAIN_ID,
-				id,
-				Ok(message),
-				|_, _| unreachable!(),
-			);
-			assert!(!result.dispatch_fee_paid_during_dispatch);
-			assert!(result.dispatch_result);
-
-			assert_eq!(
-				System::events(),
-				vec![EventRecord {
-					phase: Phase::Initialization,
-					event: Event::Dispatch(call_dispatch::Event::<TestRuntime>::MessageDispatched(
-						SOURCE_CHAIN_ID,
-						id,
-						Ok(())
-					)),
-					topics: vec![],
-				}],
-			);
-		})
-	}
-
-	#[test]
-	fn origin_is_checked_when_verifying_sending_message_using_source_root_account() {
-		let call = Call::System(frame_system::Call::remark { remark: vec![] });
-		let message = prepare_root_message(call);
-
-		// When message is sent by Root, CallOrigin::SourceRoot is allowed
-		assert!(matches!(verify_message_origin(&RawOrigin::Root, &message), Ok(None)));
-
-		// when message is sent by some real account, CallOrigin::SourceRoot is not allowed
-		assert!(matches!(verify_message_origin(&RawOrigin::Signed(1), &message), Err(BadOrigin)));
-	}
-
-	#[test]
-	fn origin_is_checked_when_verifying_sending_message_using_target_account() {
-		let call = Call::System(frame_system::Call::remark { remark: vec![] });
-		let message = prepare_target_message(call);
-
-		// When message is sent by Root, CallOrigin::TargetAccount is not allowed
-		assert!(matches!(verify_message_origin(&RawOrigin::Root, &message), Err(BadOrigin)));
-
-		// When message is sent by some other account, it is rejected
-		assert!(matches!(verify_message_origin(&RawOrigin::Signed(2), &message), Err(BadOrigin)));
-
-		// When message is sent by a real account, it is allowed to have origin
-		// CallOrigin::TargetAccount
-		assert!(matches!(verify_message_origin(&RawOrigin::Signed(1), &message), Ok(Some(1))));
-	}
-
-	#[test]
-	fn origin_is_checked_when_verifying_sending_message_using_source_account() {
-		let call = Call::System(frame_system::Call::remark { remark: vec![] });
-		let message = prepare_source_message(call);
-
-		// Sending a message from the expected origin account works
-		assert!(matches!(verify_message_origin(&RawOrigin::Signed(1), &message), Ok(Some(1))));
-
-		// If we send a message from a different account, it is rejected
-		assert!(matches!(verify_message_origin(&RawOrigin::Signed(2), &message), Err(BadOrigin)));
-
-		// The Root account is allowed to assume any expected origin account
-		assert!(matches!(verify_message_origin(&RawOrigin::Root, &message), Ok(Some(1))));
-	}
-}
diff --git a/bridges/modules/messages/Cargo.toml b/bridges/modules/messages/Cargo.toml
index eaacf2aeb45f116b3c20dd2d44f07740ff5a75f1..47d41dba176046d75cf7da2e7f2791d4d545b823 100644
--- a/bridges/modules/messages/Cargo.toml
+++ b/bridges/modules/messages/Cargo.toml
@@ -16,7 +16,6 @@ serde = { version = "1.0.101", optional = true, features = ["derive"] }
 
 # Bridge dependencies
 
-bp-message-dispatch = { path = "../../primitives/message-dispatch", default-features = false }
 bp-messages = { path = "../../primitives/messages", default-features = false }
 bp-runtime = { path = "../../primitives/runtime", default-features = false }
 
@@ -36,7 +35,6 @@ pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "m
 [features]
 default = ["std"]
 std = [
-	"bp-message-dispatch/std",
 	"bp-messages/std",
 	"bp-runtime/std",
 	"codec/std",
diff --git a/bridges/modules/token-swap/Cargo.toml b/bridges/modules/token-swap/Cargo.toml
deleted file mode 100644
index d3a60d3472902967cf8adef713090b84d4db30f6..0000000000000000000000000000000000000000
--- a/bridges/modules/token-swap/Cargo.toml
+++ /dev/null
@@ -1,59 +0,0 @@
-[package]
-name = "pallet-bridge-token-swap"
-description = "An Substrate pallet that allows parties on different chains (bridged using messages pallet) to swap their tokens"
-version = "0.1.0"
-authors = ["Parity Technologies <admin@parity.io>"]
-edition = "2021"
-license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
-
-[dependencies]
-codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false }
-log = { version = "0.4.14", default-features = false }
-scale-info = { version = "2.1.1", default-features = false, features = ["derive"] }
-serde = { version = "1.0", optional = true }
-
-# Bridge dependencies
-
-bp-message-dispatch = { path = "../../primitives/message-dispatch", default-features = false }
-bp-messages = { path = "../../primitives/messages", default-features = false }
-bp-runtime = { path = "../../primitives/runtime", default-features = false }
-bp-token-swap = { path = "../../primitives/token-swap", default-features = false }
-pallet-bridge-dispatch = { path = "../dispatch", default-features = false }
-pallet-bridge-messages = { path = "../messages", default-features = false }
-
-# Substrate Dependencies
-
-frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true }
-frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
-frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
-sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
-sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
-sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
-sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
-
-[dev-dependencies]
-pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" }
-
-[features]
-default = ["std"]
-std = [
-	"codec/std",
-	"bp-message-dispatch/std",
-	"bp-messages/std",
-	"bp-runtime/std",
-	"bp-token-swap/std",
-	"frame-support/std",
-	"frame-system/std",
-	"log/std",
-	"pallet-bridge-dispatch/std",
-	"pallet-bridge-messages/std",
-	"scale-info/std",
-	"serde",
-	"sp-core/std",
-	"sp-io/std",
-	"sp-runtime/std",
-	"sp-std/std",
-]
-runtime-benchmarks = [
-	"frame-benchmarking/runtime-benchmarks",
-]
diff --git a/bridges/modules/token-swap/src/benchmarking.rs b/bridges/modules/token-swap/src/benchmarking.rs
deleted file mode 100644
index 878cb20993a9d1c081c1c053de7a05f00b402a69..0000000000000000000000000000000000000000
--- a/bridges/modules/token-swap/src/benchmarking.rs
+++ /dev/null
@@ -1,198 +0,0 @@
-// Copyright 2019-2021 Parity Technologies (UK) Ltd.
-// This file is part of Parity Bridges Common.
-
-// Parity Bridges Common 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.
-
-// Parity Bridges Common 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 Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
-
-//! Token-swap pallet benchmarking.
-
-use crate::{
-	swap_account_id, target_account_at_this_chain, BridgedAccountIdOf, BridgedAccountPublicOf,
-	BridgedAccountSignatureOf, BridgedBalanceOf, Call, Origin, Pallet, ThisChainBalance,
-	TokenSwapCreationOf, TokenSwapOf,
-};
-
-use bp_token_swap::{TokenSwap, TokenSwapCreation, TokenSwapState, TokenSwapType};
-use codec::{Decode, Encode};
-use frame_benchmarking::{account, benchmarks_instance_pallet};
-use frame_support::{traits::Currency, Parameter};
-use frame_system::RawOrigin;
-use sp_core::H256;
-use sp_io::hashing::blake2_256;
-use sp_runtime::traits::{Bounded, TrailingZeroInput};
-use sp_std::{boxed::Box, vec::Vec};
-
-const SEED: u32 = 0;
-
-/// Trait that must be implemented by runtime.
-pub trait Config<I: 'static>: crate::Config<I> {
-	/// Initialize environment for token swap.
-	fn initialize_environment();
-}
-
-benchmarks_instance_pallet! {
-	where_clause {
-		where
-			Origin<T, I>: Into<T::Origin>,
-			BridgedAccountPublicOf<T, I>: Decode + Parameter,
-			BridgedAccountSignatureOf<T, I>: Decode,
-	}
-
-	//
-	// Benchmarks that are used directly by the runtime.
-	//
-
-	// Benchmark `create_swap` extrinsic.
-	//
-	// This benchmark assumes that message is **NOT** actually sent. Instead we're using `send_message_weight`
-	// from the `WeightInfoExt` trait.
-	//
-	// There aren't any factors that affect `create_swap` performance, so everything
-	// is straightforward here.
-	create_swap {
-		T::initialize_environment();
-
-		let sender = funded_account::<T, I>("source_account_at_this_chain", 0);
-		let swap: TokenSwapOf<T, I> = test_swap::<T, I>(sender.clone(), true);
-		let swap_creation: TokenSwapCreationOf<T, I> = test_swap_creation::<T, I>();
-	}: create_swap(
-		RawOrigin::Signed(sender.clone()),
-		swap,
-		Box::new(swap_creation)
-	)
-	verify {
-		assert!(crate::PendingSwaps::<T, I>::contains_key(test_swap_hash::<T, I>(sender, true)));
-	}
-
-	// Benchmark `claim_swap` extrinsic with the worst possible conditions:
-	//
-	// * swap is locked until some block, so current block number is read.
-	claim_swap {
-		T::initialize_environment();
-
-		let sender: T::AccountId = account("source_account_at_this_chain", 0, SEED);
-		crate::PendingSwaps::<T, I>::insert(
-			test_swap_hash::<T, I>(sender.clone(), false),
-			TokenSwapState::Confirmed,
-		);
-
-		let swap: TokenSwapOf<T, I> = test_swap::<T, I>(sender.clone(), false);
-		let claimer = target_account_at_this_chain::<T, I>(&swap);
-		let token_swap_account = swap_account_id::<T, I>(&swap);
-		T::ThisCurrency::make_free_balance_be(&token_swap_account, ThisChainBalance::<T, I>::max_value());
-	}: claim_swap(RawOrigin::Signed(claimer), swap)
-	verify {
-		assert!(!crate::PendingSwaps::<T, I>::contains_key(test_swap_hash::<T, I>(sender, false)));
-	}
-
-	// Benchmark `cancel_swap` extrinsic with the worst possible conditions:
-	//
-	// * swap is locked until some block, so current block number is read.
-	cancel_swap {
-		T::initialize_environment();
-
-		let sender: T::AccountId = account("source_account_at_this_chain", 0, SEED);
-		crate::PendingSwaps::<T, I>::insert(
-			test_swap_hash::<T, I>(sender.clone(), false),
-			TokenSwapState::Failed,
-		);
-
-		let swap: TokenSwapOf<T, I> = test_swap::<T, I>(sender.clone(), false);
-		let token_swap_account = swap_account_id::<T, I>(&swap);
-		T::ThisCurrency::make_free_balance_be(&token_swap_account, ThisChainBalance::<T, I>::max_value());
-
-	}: cancel_swap(RawOrigin::Signed(sender.clone()), swap)
-	verify {
-		assert!(!crate::PendingSwaps::<T, I>::contains_key(test_swap_hash::<T, I>(sender, false)));
-	}
-}
-
-/// Returns test token swap.
-fn test_swap<T: Config<I>, I: 'static>(sender: T::AccountId, is_create: bool) -> TokenSwapOf<T, I> {
-	TokenSwap {
-		swap_type: TokenSwapType::LockClaimUntilBlock(
-			if is_create { 10u32.into() } else { 0u32.into() },
-			0.into(),
-		),
-		source_balance_at_this_chain: source_balance_to_swap::<T, I>(),
-		source_account_at_this_chain: sender,
-		target_balance_at_bridged_chain: target_balance_to_swap::<T, I>(),
-		target_account_at_bridged_chain: target_account_at_bridged_chain::<T, I>(),
-	}
-}
-
-/// Returns test token swap hash.
-fn test_swap_hash<T: Config<I>, I: 'static>(sender: T::AccountId, is_create: bool) -> H256 {
-	test_swap::<T, I>(sender, is_create).using_encoded(blake2_256).into()
-}
-
-/// Returns test token swap creation params.
-fn test_swap_creation<T: Config<I>, I: 'static>() -> TokenSwapCreationOf<T, I>
-where
-	BridgedAccountPublicOf<T, I>: Decode,
-	BridgedAccountSignatureOf<T, I>: Decode,
-{
-	TokenSwapCreation {
-		target_public_at_bridged_chain: target_public_at_bridged_chain::<T, I>(),
-		swap_delivery_and_dispatch_fee: swap_delivery_and_dispatch_fee::<T, I>(),
-		bridged_chain_spec_version: 0,
-		bridged_currency_transfer: Vec::new(),
-		bridged_currency_transfer_weight: 0,
-		bridged_currency_transfer_signature: bridged_currency_transfer_signature::<T, I>(),
-	}
-}
-
-/// Account that has some balance.
-fn funded_account<T: Config<I>, I: 'static>(name: &'static str, index: u32) -> T::AccountId {
-	let account: T::AccountId = account(name, index, SEED);
-	T::ThisCurrency::make_free_balance_be(&account, ThisChainBalance::<T, I>::max_value());
-	account
-}
-
-/// Currency transfer message fee.
-fn swap_delivery_and_dispatch_fee<T: Config<I>, I: 'static>() -> ThisChainBalance<T, I> {
-	ThisChainBalance::<T, I>::max_value() / 4u32.into()
-}
-
-/// Balance at the source chain that we're going to swap.
-fn source_balance_to_swap<T: Config<I>, I: 'static>() -> ThisChainBalance<T, I> {
-	ThisChainBalance::<T, I>::max_value() / 2u32.into()
-}
-
-/// Balance at the target chain that we're going to swap.
-fn target_balance_to_swap<T: Config<I>, I: 'static>() -> BridgedBalanceOf<T, I> {
-	BridgedBalanceOf::<T, I>::max_value() / 2u32.into()
-}
-
-/// Public key of `target_account_at_bridged_chain`.
-fn target_public_at_bridged_chain<T: Config<I>, I: 'static>() -> BridgedAccountPublicOf<T, I>
-where
-	BridgedAccountPublicOf<T, I>: Decode,
-{
-	BridgedAccountPublicOf::<T, I>::decode(&mut TrailingZeroInput::zeroes())
-		.expect("failed to decode `BridgedAccountPublicOf` from zeroes")
-}
-
-/// Signature of `target_account_at_bridged_chain` over message.
-fn bridged_currency_transfer_signature<T: Config<I>, I: 'static>() -> BridgedAccountSignatureOf<T, I>
-where
-	BridgedAccountSignatureOf<T, I>: Decode,
-{
-	BridgedAccountSignatureOf::<T, I>::decode(&mut TrailingZeroInput::zeroes())
-		.expect("failed to decode `BridgedAccountSignatureOf` from zeroes")
-}
-
-/// Account at the bridged chain that is participating in the swap.
-fn target_account_at_bridged_chain<T: Config<I>, I: 'static>() -> BridgedAccountIdOf<T, I> {
-	account("target_account_at_bridged_chain", 0, SEED)
-}
diff --git a/bridges/modules/token-swap/src/lib.rs b/bridges/modules/token-swap/src/lib.rs
deleted file mode 100644
index 81059ee1fd5fa91b1984fd7962312bc83c5ea7c1..0000000000000000000000000000000000000000
--- a/bridges/modules/token-swap/src/lib.rs
+++ /dev/null
@@ -1,1195 +0,0 @@
-// Copyright 2019-2021 Parity Technologies (UK) Ltd.
-// This file is part of Parity Bridges Common.
-
-// Parity Bridges Common 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.
-
-// Parity Bridges Common 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 Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
-
-//! Runtime module that allows token swap between two parties acting on different chains.
-//!
-//! The swap is made using message lanes between This (where `pallet-bridge-token-swap` pallet
-//! is deployed) and some other Bridged chain. No other assumptions about the Bridged chain are
-//! made, so we don't need it to have an instance of the `pallet-bridge-token-swap` pallet deployed.
-//!
-//! There are four accounts participating in the swap:
-//!
-//! 1) account of This chain that has signed the `create_swap` transaction and has balance on This
-//! chain. We'll be referring to this account as `source_account_at_this_chain`;
-//!
-//! 2) account of the Bridged chain that is sending the `claim_swap` message from the Bridged to
-//! This chain. This account has balance on Bridged chain and is willing to swap these tokens to
-//! This chain tokens of the `source_account_at_this_chain`. We'll be referring to this account
-//! as `target_account_at_bridged_chain`;
-//!
-//! 3) account of the Bridged chain that is indirectly controlled by the
-//! `source_account_at_this_chain`. We'll be referring this account as
-//! `source_account_at_bridged_chain`;
-//!
-//! 4) account of This chain that is indirectly controlled by the `target_account_at_bridged_chain`.
-//! We'll be referring this account as `target_account_at_this_chain`.
-//!
-//! So the tokens swap is an intention of `source_account_at_this_chain` to swap his
-//! `source_balance_at_this_chain` tokens to the `target_balance_at_bridged_chain` tokens owned by
-//! `target_account_at_bridged_chain`. The swap process goes as follows:
-//!
-//! 1) the `source_account_at_this_chain` account submits the `create_swap` transaction on This
-//! chain;
-//!
-//! 2) the tokens transfer message that would transfer `target_balance_at_bridged_chain`
-//! tokens from the `target_account_at_bridged_chain` to the `source_account_at_bridged_chain`,
-//! is sent over the bridge;
-//!
-//! 3) when transfer message is delivered and dispatched, the pallet receives notification;
-//!
-//! 4) if message has been successfully dispatched, the `target_account_at_bridged_chain` sends the
-//! message that would transfer `source_balance_at_this_chain` tokens to his
-//! `target_account_at_this_chain` account;
-//!
-//! 5) if message dispatch has failed, the `source_account_at_this_chain` may submit the
-//! `cancel_swap` transaction and return his `source_balance_at_this_chain` back to his account.
-//!
-//! While swap is pending, the `source_balance_at_this_chain` tokens are owned by the special
-//! temporary `swap_account_at_this_chain` account. It is destroyed upon swap completion.
-
-#![cfg_attr(not(feature = "std"), no_std)]
-
-use bp_messages::{
-	source_chain::{MessagesBridge, OnDeliveryConfirmed},
-	DeliveredMessages, LaneId, MessageNonce,
-};
-use bp_runtime::{messages::DispatchFeePayment, ChainId};
-use bp_token_swap::{
-	RawBridgedTransferCall, TokenSwap, TokenSwapCreation, TokenSwapState, TokenSwapType,
-};
-use codec::{Decode, Encode};
-use frame_support::{
-	fail,
-	traits::{Currency, ExistenceRequirement},
-	weights::PostDispatchInfo,
-	RuntimeDebug,
-};
-use scale_info::TypeInfo;
-use sp_core::H256;
-use sp_io::hashing::blake2_256;
-use sp_runtime::traits::{Convert, Saturating};
-use sp_std::{boxed::Box, marker::PhantomData};
-use weights::WeightInfo;
-
-pub use weights_ext::WeightInfoExt;
-
-#[cfg(test)]
-mod mock;
-
-#[cfg(feature = "runtime-benchmarks")]
-pub mod benchmarking;
-
-pub mod weights;
-pub mod weights_ext;
-
-pub use pallet::*;
-
-/// Name of the `PendingSwaps` storage map.
-pub const PENDING_SWAPS_MAP_NAME: &str = "PendingSwaps";
-
-/// Origin for the token swap pallet.
-#[derive(PartialEq, Eq, Clone, RuntimeDebug, Encode, Decode, TypeInfo)]
-pub enum RawOrigin<AccountId, I> {
-	/// The call is originated by the token swap account.
-	TokenSwap {
-		/// Id of the account that has started the swap.
-		source_account_at_this_chain: AccountId,
-		/// Id of the account that holds the funds during this swap. The message fee is paid from
-		/// this account funds.
-		swap_account_at_this_chain: AccountId,
-	},
-	/// Dummy to manage the fact we have instancing.
-	_Phantom(PhantomData<I>),
-}
-
-// comes from #[pallet::event]
-#[allow(clippy::unused_unit)]
-#[frame_support::pallet]
-pub mod pallet {
-	use super::*;
-	use frame_support::pallet_prelude::*;
-	use frame_system::pallet_prelude::*;
-
-	#[pallet::config]
-	pub trait Config<I: 'static = ()>: frame_system::Config {
-		/// The overarching event type.
-		type Event: From<Event<Self, I>> + IsType<<Self as frame_system::Config>::Event>;
-		/// Benchmarks results from runtime we're plugged into.
-		type WeightInfo: WeightInfoExt;
-
-		/// Id of the bridge with the Bridged chain.
-		type BridgedChainId: Get<ChainId>;
-		/// The identifier of outbound message lane on This chain used to send token transfer
-		/// messages to the Bridged chain.
-		///
-		/// It is highly recommended to use dedicated lane for every instance of token swap
-		/// pallet. Messages delivery confirmation callback is implemented in the way that
-		/// for every confirmed message, there is (at least) a storage read. Which mean,
-		/// that if pallet will see unrelated confirmations, it'll just burn storage-read
-		/// weight, achieving nothing.
-		type OutboundMessageLaneId: Get<LaneId>;
-		/// Messages bridge with Bridged chain.
-		type MessagesBridge: MessagesBridge<
-			Self::Origin,
-			Self::AccountId,
-			<Self::ThisCurrency as Currency<Self::AccountId>>::Balance,
-			MessagePayloadOf<Self, I>,
-		>;
-
-		/// This chain Currency used in the tokens swap.
-		type ThisCurrency: Currency<Self::AccountId>;
-		/// Converter from raw hash (derived from swap) to This chain account.
-		type FromSwapToThisAccountIdConverter: Convert<H256, Self::AccountId>;
-
-		/// The chain we're bridged to.
-		type BridgedChain: bp_runtime::Chain;
-		/// Converter from raw hash (derived from Bridged chain account) to This chain account.
-		type FromBridgedToThisAccountIdConverter: Convert<H256, Self::AccountId>;
-	}
-
-	/// Tokens balance at This chain.
-	pub type ThisChainBalance<T, I> = <<T as Config<I>>::ThisCurrency as Currency<
-		<T as frame_system::Config>::AccountId,
-	>>::Balance;
-
-	/// Type of the Bridged chain.
-	pub type BridgedChainOf<T, I> = <T as Config<I>>::BridgedChain;
-	/// Tokens balance type at the Bridged chain.
-	pub type BridgedBalanceOf<T, I> = bp_runtime::BalanceOf<BridgedChainOf<T, I>>;
-	/// Account identifier type at the Bridged chain.
-	pub type BridgedAccountIdOf<T, I> = bp_runtime::AccountIdOf<BridgedChainOf<T, I>>;
-	/// Account public key type at the Bridged chain.
-	pub type BridgedAccountPublicOf<T, I> = bp_runtime::AccountPublicOf<BridgedChainOf<T, I>>;
-	/// Account signature type at the Bridged chain.
-	pub type BridgedAccountSignatureOf<T, I> = bp_runtime::SignatureOf<BridgedChainOf<T, I>>;
-
-	/// Bridge message payload used by the pallet.
-	pub type MessagePayloadOf<T, I> = bp_message_dispatch::MessagePayload<
-		<T as frame_system::Config>::AccountId,
-		BridgedAccountPublicOf<T, I>,
-		BridgedAccountSignatureOf<T, I>,
-		RawBridgedTransferCall,
-	>;
-	/// Type of `TokenSwap` used by the pallet.
-	pub type TokenSwapOf<T, I> = TokenSwap<
-		BlockNumberFor<T>,
-		ThisChainBalance<T, I>,
-		<T as frame_system::Config>::AccountId,
-		BridgedBalanceOf<T, I>,
-		BridgedAccountIdOf<T, I>,
-	>;
-	/// Type of `TokenSwapCreation` used by the pallet.
-	pub type TokenSwapCreationOf<T, I> = TokenSwapCreation<
-		BridgedAccountPublicOf<T, I>,
-		ThisChainBalance<T, I>,
-		BridgedAccountSignatureOf<T, I>,
-	>;
-
-	#[pallet::pallet]
-	#[pallet::generate_store(pub(super) trait Store)]
-	#[pallet::without_storage_info]
-	pub struct Pallet<T, I = ()>(PhantomData<(T, I)>);
-
-	#[pallet::hooks]
-	impl<T: Config<I>, I: 'static> Hooks<BlockNumberFor<T>> for Pallet<T, I> {}
-
-	#[pallet::call]
-	impl<T: Config<I>, I: 'static> Pallet<T, I>
-	where
-		BridgedAccountPublicOf<T, I>: Parameter,
-		Origin<T, I>: Into<T::Origin>,
-	{
-		/// Start token swap procedure.
-		///
-		/// The dispatch origin for this call must be exactly the
-		/// `swap.source_account_at_this_chain` account.
-		///
-		/// Method arguments are:
-		///
-		/// - `swap` - token swap intention;
-		/// - `swap_creation_params` - additional parameters required to start tokens swap.
-		///
-		/// The `source_account_at_this_chain` MUST have enough balance to cover both token swap and
-		/// message transfer. Message fee may be estimated using corresponding `OutboundLaneApi` of
-		/// This runtime.
-		///
-		/// **WARNING**: the submitter of this transaction is responsible for verifying:
-		///
-		/// 1) that the `swap_creation_params.bridged_currency_transfer` represents a valid token
-		/// transfer call that transfers `swap.target_balance_at_bridged_chain` to his
-		/// `swap.source_account_at_bridged_chain` account;
-		///
-		/// 2) that either the `swap.source_account_at_bridged_chain` already exists, or the
-		/// `swap.target_balance_at_bridged_chain` is above existential deposit of the Bridged
-		/// chain;
-		///
-		/// 3) the `swap_creation_params.target_public_at_bridged_chain` matches the
-		/// `swap.target_account_at_bridged_chain`;
-		///
-		/// 4) the `bridged_currency_transfer_signature` is valid and generated by the owner of
-		/// the `swap_creation_params.target_public_at_bridged_chain` account (read more
-		/// about [`CallOrigin::TargetAccount`]).
-		///
-		/// Violating rule#1 will lead to losing your `source_balance_at_this_chain` tokens.
-		/// Violating other rules will lead to losing message fees for this and other transactions +
-		/// losing fees for message transfer.
-		#[allow(clippy::boxed_local)]
-		#[pallet::weight(
-			T::WeightInfo::create_swap()
-				.saturating_add(T::WeightInfo::send_message_weight(
-					&&swap_creation_params.bridged_currency_transfer[..],
-					T::DbWeight::get(),
-				))
-			)]
-		pub fn create_swap(
-			origin: OriginFor<T>,
-			swap: TokenSwapOf<T, I>,
-			swap_creation_params: Box<TokenSwapCreationOf<T, I>>,
-		) -> DispatchResultWithPostInfo {
-			let TokenSwapCreation {
-				target_public_at_bridged_chain,
-				swap_delivery_and_dispatch_fee,
-				bridged_chain_spec_version,
-				bridged_currency_transfer,
-				bridged_currency_transfer_weight,
-				bridged_currency_transfer_signature,
-			} = *swap_creation_params;
-
-			// ensure that the `origin` is the same account that is mentioned in the `swap`
-			// intention
-			let origin_account = ensure_signed(origin)?;
-			ensure!(
-				origin_account == swap.source_account_at_this_chain,
-				Error::<T, I>::MismatchedSwapSourceOrigin,
-			);
-
-			// remember weight components
-			let base_weight = T::WeightInfo::create_swap();
-
-			// we can't exchange less than existential deposit (the temporary `swap_account` account
-			// won't be created then)
-			//
-			// the same can also happen with the `swap.bridged_balance`, but we can't check it
-			// here (without additional knowledge of the Bridged chain). So it is the `origin`
-			// responsibility to check that the swap is valid.
-			ensure!(
-				swap.source_balance_at_this_chain >= T::ThisCurrency::minimum_balance(),
-				Error::<T, I>::TooLowBalanceOnThisChain,
-			);
-
-			// if the swap is replay-protected, then we need to ensure that we have not yet passed
-			// the specified block yet
-			match swap.swap_type {
-				TokenSwapType::TemporaryTargetAccountAtBridgedChain => (),
-				TokenSwapType::LockClaimUntilBlock(block_number, _) => ensure!(
-					block_number >= frame_system::Pallet::<T>::block_number(),
-					Error::<T, I>::SwapPeriodIsFinished,
-				),
-			}
-
-			let swap_account = swap_account_id::<T, I>(&swap);
-			let actual_send_message_weight = frame_support::storage::with_transaction(
-				|| -> sp_runtime::TransactionOutcome<Result<_, sp_runtime::DispatchError>> {
-					// funds are transferred from This account to the temporary Swap account
-					let transfer_result = T::ThisCurrency::transfer(
-						&swap.source_account_at_this_chain,
-						&swap_account,
-						// saturating_add is ok, or we have the chain where single holder owns all
-						// tokens
-						swap.source_balance_at_this_chain
-							.saturating_add(swap_delivery_and_dispatch_fee),
-						// if we'll allow account to die, then he'll be unable to `cancel_claim`
-						// if something won't work
-						ExistenceRequirement::KeepAlive,
-					);
-					if let Err(err) = transfer_result {
-						log::error!(
-							target: "runtime::bridge-token-swap",
-							"Failed to transfer This chain tokens for the swap {:?} to Swap account ({:?}): {:?}",
-							swap,
-							swap_account,
-							err,
-						);
-
-						return sp_runtime::TransactionOutcome::Rollback(Err(
-							Error::<T, I>::FailedToTransferToSwapAccount.into(),
-						))
-					}
-
-					// the transfer message is sent over the bridge. The message is supposed to be a
-					// `Currency::transfer` call on the bridged chain, but no checks are made - it
-					// is the transaction submitter to ensure it is valid.
-					let send_message_result = T::MessagesBridge::send_message(
-						RawOrigin::TokenSwap {
-							source_account_at_this_chain: swap.source_account_at_this_chain.clone(),
-							swap_account_at_this_chain: swap_account.clone(),
-						}
-						.into(),
-						T::OutboundMessageLaneId::get(),
-						bp_message_dispatch::MessagePayload {
-							spec_version: bridged_chain_spec_version,
-							weight: bridged_currency_transfer_weight,
-							origin: bp_message_dispatch::CallOrigin::TargetAccount(
-								swap_account,
-								target_public_at_bridged_chain,
-								bridged_currency_transfer_signature,
-							),
-							dispatch_fee_payment: DispatchFeePayment::AtTargetChain,
-							call: bridged_currency_transfer,
-						},
-						swap_delivery_and_dispatch_fee,
-					);
-					let sent_message = match send_message_result {
-						Ok(sent_message) => sent_message,
-						Err(err) => {
-							log::error!(
-								target: "runtime::bridge-token-swap",
-								"Failed to send token transfer message for swap {:?} to the Bridged chain: {:?}",
-								swap,
-								err,
-							);
-
-							return sp_runtime::TransactionOutcome::Rollback(Err(
-								Error::<T, I>::FailedToSendTransferMessage.into(),
-							))
-						},
-					};
-
-					// remember that we have started the swap
-					let swap_hash = swap.using_encoded(blake2_256).into();
-					let insert_swap_result =
-						PendingSwaps::<T, I>::try_mutate(swap_hash, |maybe_state| {
-							if maybe_state.is_some() {
-								return Err(())
-							}
-
-							*maybe_state = Some(TokenSwapState::Started);
-							Ok(())
-						});
-					if insert_swap_result.is_err() {
-						log::error!(
-							target: "runtime::bridge-token-swap",
-							"Failed to start token swap {:?}: the swap is already started",
-							swap,
-						);
-
-						return sp_runtime::TransactionOutcome::Rollback(Err(
-							Error::<T, I>::SwapAlreadyStarted.into(),
-						))
-					}
-
-					log::trace!(
-						target: "runtime::bridge-token-swap",
-						"The swap {:?} (hash {:?}) has been started",
-						swap,
-						swap_hash,
-					);
-
-					// remember that we're waiting for the transfer message delivery confirmation
-					PendingMessages::<T, I>::insert(sent_message.nonce, swap_hash);
-
-					// finally - emit the event
-					Self::deposit_event(Event::SwapStarted(swap_hash, sent_message.nonce));
-
-					sp_runtime::TransactionOutcome::Commit(Ok(sent_message.weight))
-				},
-			)?;
-
-			Ok(PostDispatchInfo {
-				actual_weight: Some(base_weight.saturating_add(actual_send_message_weight)),
-				pays_fee: Pays::Yes,
-			})
-		}
-
-		/// Claim previously reserved `source_balance_at_this_chain` by
-		/// `target_account_at_this_chain`.
-		///
-		/// **WARNING**: the correct way to call this function is to call it over the messages
-		/// bridge with dispatch origin set to
-		/// `pallet_bridge_dispatch::CallOrigin::SourceAccount(target_account_at_bridged_chain)`.
-		///
-		/// This should be called only when successful transfer confirmation has been received.
-		#[pallet::weight(T::WeightInfo::claim_swap())]
-		pub fn claim_swap(
-			origin: OriginFor<T>,
-			swap: TokenSwapOf<T, I>,
-		) -> DispatchResultWithPostInfo {
-			// ensure that the `origin` is controlled by the `swap.target_account_at_bridged_chain`
-			let origin_account = ensure_signed(origin)?;
-			let target_account_at_this_chain = target_account_at_this_chain::<T, I>(&swap);
-			ensure!(origin_account == target_account_at_this_chain, Error::<T, I>::InvalidClaimant,);
-
-			// ensure that the swap is confirmed
-			let swap_hash = swap.using_encoded(blake2_256).into();
-			let swap_state = PendingSwaps::<T, I>::get(swap_hash);
-			match swap_state {
-				Some(TokenSwapState::Started) => fail!(Error::<T, I>::SwapIsPending),
-				Some(TokenSwapState::Confirmed) => {
-					let is_claim_allowed = match swap.swap_type {
-						TokenSwapType::TemporaryTargetAccountAtBridgedChain => true,
-						TokenSwapType::LockClaimUntilBlock(block_number, _) =>
-							block_number < frame_system::Pallet::<T>::block_number(),
-					};
-
-					ensure!(is_claim_allowed, Error::<T, I>::SwapIsTemporaryLocked);
-				},
-				Some(TokenSwapState::Failed) => fail!(Error::<T, I>::SwapIsFailed),
-				None => fail!(Error::<T, I>::SwapIsInactive),
-			}
-
-			complete_claim::<T, I>(swap, swap_hash, origin_account, Event::SwapClaimed(swap_hash))
-		}
-
-		/// Return previously reserved `source_balance_at_this_chain` back to the
-		/// `source_account_at_this_chain`.
-		///
-		/// This should be called only when transfer has failed at Bridged chain and we have
-		/// received notification about that.
-		#[pallet::weight(T::WeightInfo::cancel_swap())]
-		pub fn cancel_swap(
-			origin: OriginFor<T>,
-			swap: TokenSwapOf<T, I>,
-		) -> DispatchResultWithPostInfo {
-			// ensure that the `origin` is the same account that is mentioned in the `swap`
-			// intention
-			let origin_account = ensure_signed(origin)?;
-			ensure!(
-				origin_account == swap.source_account_at_this_chain,
-				Error::<T, I>::MismatchedSwapSourceOrigin,
-			);
-
-			// ensure that the swap has failed
-			let swap_hash = swap.using_encoded(blake2_256).into();
-			let swap_state = PendingSwaps::<T, I>::get(swap_hash);
-			match swap_state {
-				Some(TokenSwapState::Started) => fail!(Error::<T, I>::SwapIsPending),
-				Some(TokenSwapState::Confirmed) => fail!(Error::<T, I>::SwapIsConfirmed),
-				Some(TokenSwapState::Failed) => {
-					// we allow canceling swap even before lock period is over - the
-					// `source_account_at_this_chain` has already paid for nothing and it is up to
-					// him to decide whether he want to try again
-				},
-				None => fail!(Error::<T, I>::SwapIsInactive),
-			}
-
-			complete_claim::<T, I>(swap, swap_hash, origin_account, Event::SwapCanceled(swap_hash))
-		}
-	}
-
-	#[pallet::event]
-	#[pallet::generate_deposit(pub(super) fn deposit_event)]
-	pub enum Event<T: Config<I>, I: 'static = ()> {
-		/// Tokens swap has been started and message has been sent to the bridged message.
-		///
-		/// The payload is the swap hash and the transfer message nonce.
-		SwapStarted(H256, MessageNonce),
-		/// Token swap has been claimed.
-		SwapClaimed(H256),
-		/// Token swap has been canceled.
-		SwapCanceled(H256),
-	}
-
-	#[pallet::error]
-	pub enum Error<T, I = ()> {
-		/// The account that has submitted the `start_claim` doesn't match the
-		/// `TokenSwap::source_account_at_this_chain`.
-		MismatchedSwapSourceOrigin,
-		/// The swap balance in This chain tokens is below existential deposit and can't be made.
-		TooLowBalanceOnThisChain,
-		/// Transfer from This chain account to temporary Swap account has failed.
-		FailedToTransferToSwapAccount,
-		/// Transfer from the temporary Swap account to the derived account of Bridged account has
-		/// failed.
-		FailedToTransferFromSwapAccount,
-		/// The message to transfer tokens on Target chain can't be sent.
-		FailedToSendTransferMessage,
-		/// The same swap is already started.
-		SwapAlreadyStarted,
-		/// Swap outcome is not yet received.
-		SwapIsPending,
-		/// Someone is trying to claim swap that has failed.
-		SwapIsFailed,
-		/// Claiming swap is not allowed.
-		///
-		/// Now the only possible case when you may get this error, is when you're trying to claim
-		/// swap with `TokenSwapType::LockClaimUntilBlock` before lock period is over.
-		SwapIsTemporaryLocked,
-		/// Swap period is finished and you can not restart it.
-		///
-		/// Now the only possible case when you may get this error, is when you're trying to start
-		/// swap with `TokenSwapType::LockClaimUntilBlock` after lock period is over.
-		SwapPeriodIsFinished,
-		/// Someone is trying to cancel swap that has been confirmed.
-		SwapIsConfirmed,
-		/// Someone is trying to claim/cancel swap that is either not started or already
-		/// claimed/canceled.
-		SwapIsInactive,
-		/// The swap claimant is invalid.
-		InvalidClaimant,
-	}
-
-	/// Origin for the token swap pallet.
-	#[pallet::origin]
-	pub type Origin<T, I = ()> = RawOrigin<<T as frame_system::Config>::AccountId, I>;
-
-	/// Pending token swaps states.
-	#[pallet::storage]
-	pub type PendingSwaps<T: Config<I>, I: 'static = ()> =
-		StorageMap<_, Identity, H256, TokenSwapState>;
-
-	/// Pending transfer messages.
-	#[pallet::storage]
-	pub type PendingMessages<T: Config<I>, I: 'static = ()> =
-		StorageMap<_, Identity, MessageNonce, H256>;
-
-	impl<T: Config<I>, I: 'static> OnDeliveryConfirmed for Pallet<T, I> {
-		fn on_messages_delivered(lane: &LaneId, delivered_messages: &DeliveredMessages) -> Weight {
-			// we're only interested in our lane messages
-			if *lane != T::OutboundMessageLaneId::get() {
-				return 0
-			}
-
-			// so now we're dealing with our lane messages. Ideally we'll have dedicated lane
-			// and every message from `delivered_messages` is actually our transfer message.
-			// But it may be some shared lane (which is not recommended).
-			let mut reads = 0;
-			let mut writes = 0;
-			for message_nonce in delivered_messages.begin..=delivered_messages.end {
-				reads += 1;
-				if let Some(swap_hash) = PendingMessages::<T, I>::take(message_nonce) {
-					writes += 1;
-
-					let token_swap_state =
-						if delivered_messages.message_dispatch_result(message_nonce) {
-							TokenSwapState::Confirmed
-						} else {
-							TokenSwapState::Failed
-						};
-
-					log::trace!(
-						target: "runtime::bridge-token-swap",
-						"The dispatch of swap {:?} has been completed with {:?} status",
-						swap_hash,
-						token_swap_state,
-					);
-
-					PendingSwaps::<T, I>::insert(swap_hash, token_swap_state);
-				}
-			}
-
-			<T as frame_system::Config>::DbWeight::get().reads_writes(reads, writes)
-		}
-	}
-
-	/// Returns temporary account id used to lock funds during swap on This chain.
-	pub(crate) fn swap_account_id<T: Config<I>, I: 'static>(
-		swap: &TokenSwapOf<T, I>,
-	) -> T::AccountId {
-		T::FromSwapToThisAccountIdConverter::convert(swap.using_encoded(blake2_256).into())
-	}
-
-	/// Expected target account representation on This chain (aka `target_account_at_this_chain`).
-	pub(crate) fn target_account_at_this_chain<T: Config<I>, I: 'static>(
-		swap: &TokenSwapOf<T, I>,
-	) -> T::AccountId {
-		T::FromBridgedToThisAccountIdConverter::convert(bp_runtime::derive_account_id(
-			T::BridgedChainId::get(),
-			bp_runtime::SourceAccount::Account(swap.target_account_at_bridged_chain.clone()),
-		))
-	}
-
-	/// Complete claim with given outcome.
-	pub(crate) fn complete_claim<T: Config<I>, I: 'static>(
-		swap: TokenSwapOf<T, I>,
-		swap_hash: H256,
-		destination_account: T::AccountId,
-		event: Event<T, I>,
-	) -> DispatchResultWithPostInfo {
-		let swap_account = swap_account_id::<T, I>(&swap);
-		frame_support::storage::with_transaction(
-			|| -> sp_runtime::TransactionOutcome<Result<_, sp_runtime::DispatchError>> {
-				// funds are transferred from the temporary Swap account to the destination account
-				let transfer_result = T::ThisCurrency::transfer(
-					&swap_account,
-					&destination_account,
-					swap.source_balance_at_this_chain,
-					ExistenceRequirement::AllowDeath,
-				);
-				if let Err(err) = transfer_result {
-					log::error!(
-						target: "runtime::bridge-token-swap",
-						"Failed to transfer This chain tokens for the swap {:?} from the Swap account {:?} to {:?}: {:?}",
-						swap,
-						swap_account,
-						destination_account,
-						err,
-					);
-
-					return sp_runtime::TransactionOutcome::Rollback(Err(
-						Error::<T, I>::FailedToTransferFromSwapAccount.into(),
-					))
-				}
-
-				log::trace!(
-					target: "runtime::bridge-token-swap",
-					"The swap {:?} (hash {:?}) has been completed with {} status",
-					swap,
-					swap_hash,
-					match event {
-						Event::SwapClaimed(_) => "claimed",
-						Event::SwapCanceled(_) => "canceled",
-						_ => "<unknown>",
-					},
-				);
-
-				// forget about swap
-				PendingSwaps::<T, I>::remove(swap_hash);
-
-				// finally - emit the event
-				Pallet::<T, I>::deposit_event(event);
-
-				sp_runtime::TransactionOutcome::Commit(Ok(Ok(().into())))
-			},
-		)?
-	}
-}
-
-#[cfg(test)]
-mod tests {
-	use super::*;
-	use crate::mock::*;
-	use frame_support::{assert_noop, assert_ok, storage::generator::StorageMap};
-
-	const CAN_START_BLOCK_NUMBER: u64 = 10;
-	const CAN_CLAIM_BLOCK_NUMBER: u64 = CAN_START_BLOCK_NUMBER + 1;
-
-	const BRIDGED_CHAIN_ACCOUNT: BridgedAccountId = 3;
-	const BRIDGED_CHAIN_SPEC_VERSION: u32 = 4;
-	const BRIDGED_CHAIN_CALL_WEIGHT: Balance = 5;
-
-	fn bridged_chain_account_public() -> BridgedAccountPublic {
-		1.into()
-	}
-
-	fn bridged_chain_account_signature() -> BridgedAccountSignature {
-		sp_runtime::testing::TestSignature(2, Vec::new())
-	}
-
-	fn test_swap() -> TokenSwapOf<TestRuntime, ()> {
-		bp_token_swap::TokenSwap {
-			swap_type: TokenSwapType::LockClaimUntilBlock(CAN_START_BLOCK_NUMBER, 0.into()),
-			source_balance_at_this_chain: 100,
-			source_account_at_this_chain: THIS_CHAIN_ACCOUNT,
-			target_balance_at_bridged_chain: 200,
-			target_account_at_bridged_chain: BRIDGED_CHAIN_ACCOUNT,
-		}
-	}
-
-	fn test_swap_creation() -> TokenSwapCreationOf<TestRuntime, ()> {
-		TokenSwapCreation {
-			target_public_at_bridged_chain: bridged_chain_account_public(),
-			swap_delivery_and_dispatch_fee: SWAP_DELIVERY_AND_DISPATCH_FEE,
-			bridged_chain_spec_version: BRIDGED_CHAIN_SPEC_VERSION,
-			bridged_currency_transfer: test_transfer(),
-			bridged_currency_transfer_weight: BRIDGED_CHAIN_CALL_WEIGHT,
-			bridged_currency_transfer_signature: bridged_chain_account_signature(),
-		}
-	}
-
-	fn test_swap_hash() -> H256 {
-		test_swap().using_encoded(blake2_256).into()
-	}
-
-	fn test_transfer() -> RawBridgedTransferCall {
-		vec![OK_TRANSFER_CALL]
-	}
-
-	fn start_test_swap() {
-		assert_ok!(Pallet::<TestRuntime>::create_swap(
-			mock::Origin::signed(THIS_CHAIN_ACCOUNT),
-			test_swap(),
-			Box::new(TokenSwapCreation {
-				target_public_at_bridged_chain: bridged_chain_account_public(),
-				swap_delivery_and_dispatch_fee: SWAP_DELIVERY_AND_DISPATCH_FEE,
-				bridged_chain_spec_version: BRIDGED_CHAIN_SPEC_VERSION,
-				bridged_currency_transfer: test_transfer(),
-				bridged_currency_transfer_weight: BRIDGED_CHAIN_CALL_WEIGHT,
-				bridged_currency_transfer_signature: bridged_chain_account_signature(),
-			}),
-		));
-	}
-
-	fn receive_test_swap_confirmation(success: bool) {
-		Pallet::<TestRuntime, ()>::on_messages_delivered(
-			&OutboundMessageLaneId::get(),
-			&DeliveredMessages::new(MESSAGE_NONCE, success),
-		);
-	}
-
-	#[test]
-	fn create_swap_fails_if_origin_is_incorrect() {
-		run_test(|| {
-			assert_noop!(
-				Pallet::<TestRuntime>::create_swap(
-					mock::Origin::signed(THIS_CHAIN_ACCOUNT + 1),
-					test_swap(),
-					Box::new(test_swap_creation()),
-				),
-				Error::<TestRuntime, ()>::MismatchedSwapSourceOrigin
-			);
-		});
-	}
-
-	#[test]
-	fn create_swap_fails_if_this_chain_balance_is_below_existential_deposit() {
-		run_test(|| {
-			let mut swap = test_swap();
-			swap.source_balance_at_this_chain = ExistentialDeposit::get() - 1;
-			assert_noop!(
-				Pallet::<TestRuntime>::create_swap(
-					mock::Origin::signed(THIS_CHAIN_ACCOUNT),
-					swap,
-					Box::new(test_swap_creation()),
-				),
-				Error::<TestRuntime, ()>::TooLowBalanceOnThisChain
-			);
-		});
-	}
-
-	#[test]
-	fn create_swap_fails_if_currency_transfer_to_swap_account_fails() {
-		run_test(|| {
-			let mut swap = test_swap();
-			swap.source_balance_at_this_chain = THIS_CHAIN_ACCOUNT_BALANCE + 1;
-			assert_noop!(
-				Pallet::<TestRuntime>::create_swap(
-					mock::Origin::signed(THIS_CHAIN_ACCOUNT),
-					swap,
-					Box::new(test_swap_creation()),
-				),
-				Error::<TestRuntime, ()>::FailedToTransferToSwapAccount
-			);
-		});
-	}
-
-	#[test]
-	fn create_swap_fails_if_send_message_fails() {
-		run_test(|| {
-			let mut transfer = test_transfer();
-			transfer[0] = BAD_TRANSFER_CALL;
-			let mut swap_creation = test_swap_creation();
-			swap_creation.bridged_currency_transfer = transfer;
-			assert_noop!(
-				Pallet::<TestRuntime>::create_swap(
-					mock::Origin::signed(THIS_CHAIN_ACCOUNT),
-					test_swap(),
-					Box::new(swap_creation),
-				),
-				Error::<TestRuntime, ()>::FailedToSendTransferMessage
-			);
-		});
-	}
-
-	#[test]
-	fn create_swap_fails_if_swap_is_active() {
-		run_test(|| {
-			assert_ok!(Pallet::<TestRuntime>::create_swap(
-				mock::Origin::signed(THIS_CHAIN_ACCOUNT),
-				test_swap(),
-				Box::new(test_swap_creation()),
-			));
-
-			assert_noop!(
-				Pallet::<TestRuntime>::create_swap(
-					mock::Origin::signed(THIS_CHAIN_ACCOUNT),
-					test_swap(),
-					Box::new(test_swap_creation()),
-				),
-				Error::<TestRuntime, ()>::SwapAlreadyStarted
-			);
-		});
-	}
-
-	#[test]
-	fn create_swap_fails_if_trying_to_start_swap_after_lock_period_is_finished() {
-		run_test(|| {
-			frame_system::Pallet::<TestRuntime>::set_block_number(CAN_START_BLOCK_NUMBER + 1);
-			assert_noop!(
-				Pallet::<TestRuntime>::create_swap(
-					mock::Origin::signed(THIS_CHAIN_ACCOUNT),
-					test_swap(),
-					Box::new(test_swap_creation()),
-				),
-				Error::<TestRuntime, ()>::SwapPeriodIsFinished
-			);
-		});
-	}
-
-	#[test]
-	fn create_swap_succeeds_if_trying_to_start_swap_at_lock_period_end() {
-		run_test(|| {
-			frame_system::Pallet::<TestRuntime>::set_block_number(CAN_START_BLOCK_NUMBER);
-			assert_ok!(Pallet::<TestRuntime>::create_swap(
-				mock::Origin::signed(THIS_CHAIN_ACCOUNT),
-				test_swap(),
-				Box::new(test_swap_creation()),
-			));
-		});
-	}
-
-	#[test]
-	fn create_swap_succeeds() {
-		run_test(|| {
-			frame_system::Pallet::<TestRuntime>::set_block_number(1);
-			frame_system::Pallet::<TestRuntime>::reset_events();
-
-			assert_ok!(Pallet::<TestRuntime>::create_swap(
-				mock::Origin::signed(THIS_CHAIN_ACCOUNT),
-				test_swap(),
-				Box::new(test_swap_creation()),
-			));
-
-			let swap_hash = test_swap_hash();
-			assert_eq!(PendingSwaps::<TestRuntime>::get(swap_hash), Some(TokenSwapState::Started));
-			assert_eq!(PendingMessages::<TestRuntime>::get(MESSAGE_NONCE), Some(swap_hash));
-			assert_eq!(
-				pallet_balances::Pallet::<TestRuntime>::free_balance(&swap_account_id::<
-					TestRuntime,
-					(),
-				>(&test_swap())),
-				test_swap().source_balance_at_this_chain + SWAP_DELIVERY_AND_DISPATCH_FEE,
-			);
-			assert!(
-				frame_system::Pallet::<TestRuntime>::events().iter().any(|e| e.event ==
-					crate::mock::Event::TokenSwap(crate::Event::SwapStarted(
-						swap_hash,
-						MESSAGE_NONCE,
-					))),
-				"Missing SwapStarted event: {:?}",
-				frame_system::Pallet::<TestRuntime>::events(),
-			);
-		});
-	}
-
-	#[test]
-	fn claim_swap_fails_if_origin_is_incorrect() {
-		run_test(|| {
-			assert_noop!(
-				Pallet::<TestRuntime>::claim_swap(
-					mock::Origin::signed(
-						1 + target_account_at_this_chain::<TestRuntime, ()>(&test_swap())
-					),
-					test_swap(),
-				),
-				Error::<TestRuntime, ()>::InvalidClaimant
-			);
-		});
-	}
-
-	#[test]
-	fn claim_swap_fails_if_swap_is_pending() {
-		run_test(|| {
-			PendingSwaps::<TestRuntime, ()>::insert(test_swap_hash(), TokenSwapState::Started);
-
-			assert_noop!(
-				Pallet::<TestRuntime>::claim_swap(
-					mock::Origin::signed(target_account_at_this_chain::<TestRuntime, ()>(
-						&test_swap()
-					)),
-					test_swap(),
-				),
-				Error::<TestRuntime, ()>::SwapIsPending
-			);
-		});
-	}
-
-	#[test]
-	fn claim_swap_fails_if_swap_is_failed() {
-		run_test(|| {
-			PendingSwaps::<TestRuntime, ()>::insert(test_swap_hash(), TokenSwapState::Failed);
-
-			assert_noop!(
-				Pallet::<TestRuntime>::claim_swap(
-					mock::Origin::signed(target_account_at_this_chain::<TestRuntime, ()>(
-						&test_swap()
-					)),
-					test_swap(),
-				),
-				Error::<TestRuntime, ()>::SwapIsFailed
-			);
-		});
-	}
-
-	#[test]
-	fn claim_swap_fails_if_swap_is_inactive() {
-		run_test(|| {
-			assert_noop!(
-				Pallet::<TestRuntime>::claim_swap(
-					mock::Origin::signed(target_account_at_this_chain::<TestRuntime, ()>(
-						&test_swap()
-					)),
-					test_swap(),
-				),
-				Error::<TestRuntime, ()>::SwapIsInactive
-			);
-		});
-	}
-
-	#[test]
-	fn claim_swap_fails_if_currency_transfer_from_swap_account_fails() {
-		run_test(|| {
-			frame_system::Pallet::<TestRuntime>::set_block_number(CAN_CLAIM_BLOCK_NUMBER);
-			PendingSwaps::<TestRuntime, ()>::insert(test_swap_hash(), TokenSwapState::Confirmed);
-
-			assert_noop!(
-				Pallet::<TestRuntime>::claim_swap(
-					mock::Origin::signed(target_account_at_this_chain::<TestRuntime, ()>(
-						&test_swap()
-					)),
-					test_swap(),
-				),
-				Error::<TestRuntime, ()>::FailedToTransferFromSwapAccount
-			);
-		});
-	}
-
-	#[test]
-	fn claim_swap_fails_before_lock_period_is_completed() {
-		run_test(|| {
-			start_test_swap();
-			receive_test_swap_confirmation(true);
-
-			frame_system::Pallet::<TestRuntime>::set_block_number(CAN_CLAIM_BLOCK_NUMBER - 1);
-
-			assert_noop!(
-				Pallet::<TestRuntime>::claim_swap(
-					mock::Origin::signed(target_account_at_this_chain::<TestRuntime, ()>(
-						&test_swap()
-					)),
-					test_swap(),
-				),
-				Error::<TestRuntime, ()>::SwapIsTemporaryLocked
-			);
-		});
-	}
-
-	#[test]
-	fn claim_swap_succeeds() {
-		run_test(|| {
-			start_test_swap();
-			receive_test_swap_confirmation(true);
-
-			frame_system::Pallet::<TestRuntime>::set_block_number(CAN_CLAIM_BLOCK_NUMBER);
-			frame_system::Pallet::<TestRuntime>::reset_events();
-
-			assert_ok!(Pallet::<TestRuntime>::claim_swap(
-				mock::Origin::signed(target_account_at_this_chain::<TestRuntime, ()>(&test_swap())),
-				test_swap(),
-			));
-
-			let swap_hash = test_swap_hash();
-			assert_eq!(PendingSwaps::<TestRuntime>::get(swap_hash), None);
-			assert_eq!(
-				pallet_balances::Pallet::<TestRuntime>::free_balance(&swap_account_id::<
-					TestRuntime,
-					(),
-				>(&test_swap())),
-				0,
-			);
-			assert_eq!(
-				pallet_balances::Pallet::<TestRuntime>::free_balance(
-					&target_account_at_this_chain::<TestRuntime, ()>(&test_swap()),
-				),
-				test_swap().source_balance_at_this_chain,
-			);
-			assert!(
-				frame_system::Pallet::<TestRuntime>::events().iter().any(|e| e.event ==
-					crate::mock::Event::TokenSwap(crate::Event::SwapClaimed(swap_hash,))),
-				"Missing SwapClaimed event: {:?}",
-				frame_system::Pallet::<TestRuntime>::events(),
-			);
-		});
-	}
-
-	#[test]
-	fn cancel_swap_fails_if_origin_is_incorrect() {
-		run_test(|| {
-			start_test_swap();
-			receive_test_swap_confirmation(false);
-
-			assert_noop!(
-				Pallet::<TestRuntime>::cancel_swap(
-					mock::Origin::signed(THIS_CHAIN_ACCOUNT + 1),
-					test_swap()
-				),
-				Error::<TestRuntime, ()>::MismatchedSwapSourceOrigin
-			);
-		});
-	}
-
-	#[test]
-	fn cancel_swap_fails_if_swap_is_pending() {
-		run_test(|| {
-			start_test_swap();
-
-			assert_noop!(
-				Pallet::<TestRuntime>::cancel_swap(
-					mock::Origin::signed(THIS_CHAIN_ACCOUNT),
-					test_swap()
-				),
-				Error::<TestRuntime, ()>::SwapIsPending
-			);
-		});
-	}
-
-	#[test]
-	fn cancel_swap_fails_if_swap_is_confirmed() {
-		run_test(|| {
-			start_test_swap();
-			receive_test_swap_confirmation(true);
-
-			assert_noop!(
-				Pallet::<TestRuntime>::cancel_swap(
-					mock::Origin::signed(THIS_CHAIN_ACCOUNT),
-					test_swap()
-				),
-				Error::<TestRuntime, ()>::SwapIsConfirmed
-			);
-		});
-	}
-
-	#[test]
-	fn cancel_swap_fails_if_swap_is_inactive() {
-		run_test(|| {
-			assert_noop!(
-				Pallet::<TestRuntime>::cancel_swap(
-					mock::Origin::signed(THIS_CHAIN_ACCOUNT),
-					test_swap()
-				),
-				Error::<TestRuntime, ()>::SwapIsInactive
-			);
-		});
-	}
-
-	#[test]
-	fn cancel_swap_fails_if_currency_transfer_from_swap_account_fails() {
-		run_test(|| {
-			start_test_swap();
-			receive_test_swap_confirmation(false);
-			let _ = pallet_balances::Pallet::<TestRuntime>::slash(
-				&swap_account_id::<TestRuntime, ()>(&test_swap()),
-				test_swap().source_balance_at_this_chain,
-			);
-
-			assert_noop!(
-				Pallet::<TestRuntime>::cancel_swap(
-					mock::Origin::signed(THIS_CHAIN_ACCOUNT),
-					test_swap()
-				),
-				Error::<TestRuntime, ()>::FailedToTransferFromSwapAccount
-			);
-		});
-	}
-
-	#[test]
-	fn cancel_swap_succeeds() {
-		run_test(|| {
-			start_test_swap();
-			receive_test_swap_confirmation(false);
-
-			frame_system::Pallet::<TestRuntime>::set_block_number(1);
-			frame_system::Pallet::<TestRuntime>::reset_events();
-
-			assert_ok!(Pallet::<TestRuntime>::cancel_swap(
-				mock::Origin::signed(THIS_CHAIN_ACCOUNT),
-				test_swap()
-			));
-
-			let swap_hash = test_swap_hash();
-			assert_eq!(PendingSwaps::<TestRuntime>::get(swap_hash), None);
-			assert_eq!(
-				pallet_balances::Pallet::<TestRuntime>::free_balance(&swap_account_id::<
-					TestRuntime,
-					(),
-				>(&test_swap())),
-				0,
-			);
-			assert_eq!(
-				pallet_balances::Pallet::<TestRuntime>::free_balance(&THIS_CHAIN_ACCOUNT),
-				THIS_CHAIN_ACCOUNT_BALANCE - SWAP_DELIVERY_AND_DISPATCH_FEE,
-			);
-			assert!(
-				frame_system::Pallet::<TestRuntime>::events().iter().any(|e| e.event ==
-					crate::mock::Event::TokenSwap(crate::Event::SwapCanceled(swap_hash,))),
-				"Missing SwapCanceled event: {:?}",
-				frame_system::Pallet::<TestRuntime>::events(),
-			);
-		});
-	}
-
-	#[test]
-	fn messages_delivery_confirmations_are_accepted() {
-		run_test(|| {
-			start_test_swap();
-			assert_eq!(
-				PendingMessages::<TestRuntime, ()>::get(MESSAGE_NONCE),
-				Some(test_swap_hash())
-			);
-			assert_eq!(
-				PendingSwaps::<TestRuntime, ()>::get(test_swap_hash()),
-				Some(TokenSwapState::Started)
-			);
-
-			// when unrelated messages are delivered
-			let mut messages = DeliveredMessages::new(MESSAGE_NONCE - 2, true);
-			messages.note_dispatched_message(false);
-			Pallet::<TestRuntime, ()>::on_messages_delivered(
-				&OutboundMessageLaneId::get(),
-				&messages,
-			);
-			assert_eq!(
-				PendingMessages::<TestRuntime, ()>::get(MESSAGE_NONCE),
-				Some(test_swap_hash())
-			);
-			assert_eq!(
-				PendingSwaps::<TestRuntime, ()>::get(test_swap_hash()),
-				Some(TokenSwapState::Started)
-			);
-
-			// when message we're interested in is accompanied by a bunch of other messages
-			let mut messages = DeliveredMessages::new(MESSAGE_NONCE - 1, false);
-			messages.note_dispatched_message(true);
-			messages.note_dispatched_message(false);
-			Pallet::<TestRuntime, ()>::on_messages_delivered(
-				&OutboundMessageLaneId::get(),
-				&messages,
-			);
-			assert_eq!(PendingMessages::<TestRuntime, ()>::get(MESSAGE_NONCE), None);
-			assert_eq!(
-				PendingSwaps::<TestRuntime, ()>::get(test_swap_hash()),
-				Some(TokenSwapState::Confirmed)
-			);
-		});
-	}
-
-	#[test]
-	fn storage_keys_computed_properly() {
-		assert_eq!(
-			PendingSwaps::<TestRuntime>::storage_map_final_key(test_swap_hash()),
-			bp_token_swap::storage_keys::pending_swaps_key("TokenSwap", test_swap_hash()).0,
-		);
-	}
-}
diff --git a/bridges/modules/token-swap/src/mock.rs b/bridges/modules/token-swap/src/mock.rs
deleted file mode 100644
index ece7b16acc9101253d2017dc61e5d75c76a69638..0000000000000000000000000000000000000000
--- a/bridges/modules/token-swap/src/mock.rs
+++ /dev/null
@@ -1,200 +0,0 @@
-// Copyright 2019-2021 Parity Technologies (UK) Ltd.
-// This file is part of Parity Bridges Common.
-
-// Parity Bridges Common 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.
-
-// Parity Bridges Common 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 Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
-
-use crate as pallet_bridge_token_swap;
-use crate::MessagePayloadOf;
-
-use bp_messages::{
-	source_chain::{MessagesBridge, SendMessageArtifacts},
-	LaneId, MessageNonce,
-};
-use bp_runtime::ChainId;
-use frame_support::weights::Weight;
-use sp_core::H256;
-use sp_runtime::{
-	testing::Header as SubstrateHeader,
-	traits::{BlakeTwo256, IdentityLookup},
-	Perbill,
-};
-
-pub type AccountId = u64;
-pub type Balance = u64;
-pub type Block = frame_system::mocking::MockBlock<TestRuntime>;
-pub type BridgedAccountId = u64;
-pub type BridgedAccountPublic = sp_runtime::testing::UintAuthorityId;
-pub type BridgedAccountSignature = sp_runtime::testing::TestSignature;
-pub type BridgedBalance = u64;
-pub type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<TestRuntime>;
-
-pub const OK_TRANSFER_CALL: u8 = 1;
-pub const BAD_TRANSFER_CALL: u8 = 2;
-pub const MESSAGE_NONCE: MessageNonce = 3;
-
-pub const THIS_CHAIN_ACCOUNT: AccountId = 1;
-pub const THIS_CHAIN_ACCOUNT_BALANCE: Balance = 100_000;
-
-pub const SWAP_DELIVERY_AND_DISPATCH_FEE: Balance = 1;
-
-frame_support::construct_runtime! {
-	pub enum TestRuntime where
-		Block = Block,
-		NodeBlock = Block,
-		UncheckedExtrinsic = UncheckedExtrinsic,
-	{
-		System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
-		Balances: pallet_balances::{Pallet, Call, Event<T>},
-		TokenSwap: pallet_bridge_token_swap::{Pallet, Call, Event<T>, Origin<T>},
-	}
-}
-
-frame_support::parameter_types! {
-	pub const BlockHashCount: u64 = 250;
-	pub const MaximumBlockWeight: Weight = 1024;
-	pub const MaximumBlockLength: u32 = 2 * 1024;
-	pub const AvailableBlockRatio: Perbill = Perbill::one();
-}
-
-impl frame_system::Config for TestRuntime {
-	type Origin = Origin;
-	type Index = u64;
-	type Call = Call;
-	type BlockNumber = u64;
-	type Hash = H256;
-	type Hashing = BlakeTwo256;
-	type AccountId = AccountId;
-	type Lookup = IdentityLookup<Self::AccountId>;
-	type Header = SubstrateHeader;
-	type Event = Event;
-	type BlockHashCount = BlockHashCount;
-	type Version = ();
-	type PalletInfo = PalletInfo;
-	type AccountData = pallet_balances::AccountData<Balance>;
-	type OnNewAccount = ();
-	type OnKilledAccount = ();
-	type BaseCallFilter = frame_support::traits::Everything;
-	type SystemWeightInfo = ();
-	type BlockWeights = ();
-	type BlockLength = ();
-	type DbWeight = ();
-	type SS58Prefix = ();
-	type OnSetCode = ();
-	type MaxConsumers = frame_support::traits::ConstU32<16>;
-}
-
-frame_support::parameter_types! {
-	pub const ExistentialDeposit: u64 = 10;
-	pub const MaxReserves: u32 = 50;
-}
-
-impl pallet_balances::Config for TestRuntime {
-	type MaxLocks = ();
-	type Balance = Balance;
-	type DustRemoval = ();
-	type Event = Event;
-	type ExistentialDeposit = ExistentialDeposit;
-	type AccountStore = frame_system::Pallet<TestRuntime>;
-	type WeightInfo = ();
-	type MaxReserves = MaxReserves;
-	type ReserveIdentifier = [u8; 8];
-}
-
-frame_support::parameter_types! {
-	pub const BridgedChainId: ChainId = *b"inst";
-	pub const OutboundMessageLaneId: LaneId = *b"lane";
-}
-
-impl pallet_bridge_token_swap::Config for TestRuntime {
-	type Event = Event;
-	type WeightInfo = ();
-
-	type BridgedChainId = BridgedChainId;
-	type OutboundMessageLaneId = OutboundMessageLaneId;
-	type MessagesBridge = TestMessagesBridge;
-
-	type ThisCurrency = pallet_balances::Pallet<TestRuntime>;
-	type FromSwapToThisAccountIdConverter = TestAccountConverter;
-
-	type BridgedChain = BridgedChain;
-	type FromBridgedToThisAccountIdConverter = TestAccountConverter;
-}
-
-pub struct BridgedChain;
-
-impl bp_runtime::Chain for BridgedChain {
-	type BlockNumber = u64;
-	type Hash = H256;
-	type Hasher = BlakeTwo256;
-	type Header = sp_runtime::generic::Header<u64, BlakeTwo256>;
-
-	type AccountId = BridgedAccountId;
-	type Balance = BridgedBalance;
-	type Index = u64;
-	type Signature = BridgedAccountSignature;
-
-	fn max_extrinsic_size() -> u32 {
-		unreachable!()
-	}
-	fn max_extrinsic_weight() -> Weight {
-		unreachable!()
-	}
-}
-
-pub struct TestMessagesBridge;
-
-impl MessagesBridge<Origin, AccountId, Balance, MessagePayloadOf<TestRuntime, ()>>
-	for TestMessagesBridge
-{
-	type Error = ();
-
-	fn send_message(
-		sender: Origin,
-		lane: LaneId,
-		message: MessagePayloadOf<TestRuntime, ()>,
-		delivery_and_dispatch_fee: Balance,
-	) -> Result<SendMessageArtifacts, Self::Error> {
-		assert_eq!(lane, OutboundMessageLaneId::get());
-		assert_eq!(delivery_and_dispatch_fee, SWAP_DELIVERY_AND_DISPATCH_FEE);
-		match sender.caller {
-			OriginCaller::TokenSwap(_) => (),
-			_ => panic!("unexpected origin"),
-		}
-		match message.call[0] {
-			OK_TRANSFER_CALL => Ok(SendMessageArtifacts { nonce: MESSAGE_NONCE, weight: 0 }),
-			BAD_TRANSFER_CALL => Err(()),
-			_ => unreachable!(),
-		}
-	}
-}
-
-pub struct TestAccountConverter;
-
-impl sp_runtime::traits::Convert<H256, AccountId> for TestAccountConverter {
-	fn convert(hash: H256) -> AccountId {
-		hash.to_low_u64_ne()
-	}
-}
-
-/// Run pallet test.
-pub fn run_test<T>(test: impl FnOnce() -> T) -> T {
-	let mut t = frame_system::GenesisConfig::default().build_storage::<TestRuntime>().unwrap();
-	pallet_balances::GenesisConfig::<TestRuntime> {
-		balances: vec![(THIS_CHAIN_ACCOUNT, THIS_CHAIN_ACCOUNT_BALANCE)],
-	}
-	.assimilate_storage(&mut t)
-	.unwrap();
-	let mut ext = sp_io::TestExternalities::new(t);
-	ext.execute_with(test)
-}
diff --git a/bridges/modules/token-swap/src/weights.rs b/bridges/modules/token-swap/src/weights.rs
deleted file mode 100644
index 51c5d99de9c5cc92dc9159f0736c445ce85663cb..0000000000000000000000000000000000000000
--- a/bridges/modules/token-swap/src/weights.rs
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2019-2021 Parity Technologies (UK) Ltd.
-// This file is part of Parity Bridges Common.
-
-// Parity Bridges Common 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.
-
-// Parity Bridges Common 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 Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
-
-//! Autogenerated weights for `pallet_bridge_token_swap`
-//!
-//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2021-12-28, STEPS: 50, REPEAT: 20
-//! LOW RANGE: [], HIGH RANGE: []
-//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled
-//! CHAIN: Some("dev"), DB CACHE: 128
-
-// Executed Command:
-// target/release/millau-bridge-node
-// benchmark
-// --chain=dev
-// --steps=50
-// --repeat=20
-// --pallet=pallet_bridge_token_swap
-// --extrinsic=*
-// --execution=wasm
-// --wasm-execution=Compiled
-// --heap-pages=4096
-// --output=./modules/token-swap/src/weights.rs
-// --template=./.maintain/millau-weight-template.hbs
-
-#![allow(clippy::all)]
-#![allow(unused_parens)]
-#![allow(unused_imports)]
-
-use frame_support::{
-	traits::Get,
-	weights::{constants::RocksDbWeight, Weight},
-};
-use sp_std::marker::PhantomData;
-
-/// Weight functions needed for `pallet_bridge_token_swap`.
-pub trait WeightInfo {
-	fn create_swap() -> Weight;
-	fn claim_swap() -> Weight;
-	fn cancel_swap() -> Weight;
-}
-
-/// Weights for `pallet_bridge_token_swap` using the Millau node and recommended hardware.
-pub struct MillauWeight<T>(PhantomData<T>);
-impl<T: frame_system::Config> WeightInfo for MillauWeight<T> {
-	fn create_swap() -> Weight {
-		(90_368_000 as Weight)
-			.saturating_add(T::DbWeight::get().reads(3 as Weight))
-			.saturating_add(T::DbWeight::get().writes(4 as Weight))
-	}
-	fn claim_swap() -> Weight {
-		(88_397_000 as Weight)
-			.saturating_add(T::DbWeight::get().reads(3 as Weight))
-			.saturating_add(T::DbWeight::get().writes(3 as Weight))
-	}
-	fn cancel_swap() -> Weight {
-		(91_253_000 as Weight)
-			.saturating_add(T::DbWeight::get().reads(3 as Weight))
-			.saturating_add(T::DbWeight::get().writes(3 as Weight))
-	}
-}
-
-// For backwards compatibility and tests
-impl WeightInfo for () {
-	fn create_swap() -> Weight {
-		(90_368_000 as Weight)
-			.saturating_add(RocksDbWeight::get().reads(3 as Weight))
-			.saturating_add(RocksDbWeight::get().writes(4 as Weight))
-	}
-	fn claim_swap() -> Weight {
-		(88_397_000 as Weight)
-			.saturating_add(RocksDbWeight::get().reads(3 as Weight))
-			.saturating_add(RocksDbWeight::get().writes(3 as Weight))
-	}
-	fn cancel_swap() -> Weight {
-		(91_253_000 as Weight)
-			.saturating_add(RocksDbWeight::get().reads(3 as Weight))
-			.saturating_add(RocksDbWeight::get().writes(3 as Weight))
-	}
-}
diff --git a/bridges/modules/token-swap/src/weights_ext.rs b/bridges/modules/token-swap/src/weights_ext.rs
deleted file mode 100644
index 2d27c76cbe68564660b5b547ed2eb8aa2a882c7c..0000000000000000000000000000000000000000
--- a/bridges/modules/token-swap/src/weights_ext.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2019-2021 Parity Technologies (UK) Ltd.
-// This file is part of Parity Bridges Common.
-
-// Parity Bridges Common 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.
-
-// Parity Bridges Common 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 Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
-
-//! Weight-related utilities.
-
-use crate::weights::WeightInfo;
-
-use bp_runtime::Size;
-use frame_support::weights::{RuntimeDbWeight, Weight};
-
-/// Extended weight info.
-pub trait WeightInfoExt: WeightInfo {
-	// Functions that are directly mapped to extrinsics weights.
-
-	/// Weight of message send extrinsic.
-	fn send_message_weight(message: &impl Size, db_weight: RuntimeDbWeight) -> Weight;
-}
-
-impl WeightInfoExt for () {
-	fn send_message_weight(message: &impl Size, db_weight: RuntimeDbWeight) -> Weight {
-		<() as pallet_bridge_messages::WeightInfoExt>::send_message_weight(message, db_weight)
-	}
-}
-
-impl<T: frame_system::Config> WeightInfoExt for crate::weights::MillauWeight<T> {
-	fn send_message_weight(message: &impl Size, db_weight: RuntimeDbWeight) -> Weight {
-		<() as pallet_bridge_messages::WeightInfoExt>::send_message_weight(message, db_weight)
-	}
-}
diff --git a/bridges/primitives/chain-millau/src/lib.rs b/bridges/primitives/chain-millau/src/lib.rs
index ff8d53859535b46a55a05743a69a1c78f600bfe6..281ea471a2cfcb097653cbf7ebd58049876897ad 100644
--- a/bridges/primitives/chain-millau/src/lib.rs
+++ b/bridges/primitives/chain-millau/src/lib.rs
@@ -269,9 +269,6 @@ pub const WITH_MILLAU_MESSAGES_PALLET_NAME: &str = "BridgeMillauMessages";
 /// Name of the Rialto->Millau (actually DOT->KSM) conversion rate stored in the Millau runtime.
 pub const RIALTO_TO_MILLAU_CONVERSION_RATE_PARAMETER_NAME: &str = "RialtoToMillauConversionRate";
 
-/// Name of the With-Rialto token swap pallet instance in the Millau runtime.
-pub const WITH_RIALTO_TOKEN_SWAP_PALLET_NAME: &str = "BridgeRialtoTokenSwap";
-
 /// Name of the `MillauFinalityApi::best_finalized` runtime method.
 pub const BEST_FINALIZED_MILLAU_HEADER_METHOD: &str = "MillauFinalityApi_best_finalized";
 
diff --git a/bridges/primitives/message-dispatch/Cargo.toml b/bridges/primitives/message-dispatch/Cargo.toml
deleted file mode 100644
index 02b0912894daf56393017fa649e4665cbd7098ae..0000000000000000000000000000000000000000
--- a/bridges/primitives/message-dispatch/Cargo.toml
+++ /dev/null
@@ -1,27 +0,0 @@
-[package]
-name = "bp-message-dispatch"
-description = "Primitives of bridge messages dispatch modules."
-version = "0.1.0"
-authors = ["Parity Technologies <admin@parity.io>"]
-edition = "2021"
-license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
-
-[dependencies]
-bp-runtime = { path = "../runtime", default-features = false }
-codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false }
-scale-info = { version = "2.1.1", default-features = false, features = ["derive"] }
-
-# Substrate Dependencies
-
-frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
-sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
-
-[features]
-default = ["std"]
-std = [
-	"bp-runtime/std",
-	"codec/std",
-	"frame-support/std",
-	"scale-info/std",
-	"sp-std/std",
-]
diff --git a/bridges/primitives/message-dispatch/src/lib.rs b/bridges/primitives/message-dispatch/src/lib.rs
deleted file mode 100644
index 07e448ee7ae62604399c693e9195c7b43b796d09..0000000000000000000000000000000000000000
--- a/bridges/primitives/message-dispatch/src/lib.rs
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright 2019-2021 Parity Technologies (UK) Ltd.
-// This file is part of Parity Bridges Common.
-
-// Parity Bridges Common 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.
-
-// Parity Bridges Common 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 Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
-
-//! A common interface for all Bridge Message Dispatch modules.
-
-#![cfg_attr(not(feature = "std"), no_std)]
-#![warn(missing_docs)]
-
-use bp_runtime::{
-	messages::{DispatchFeePayment, MessageDispatchResult},
-	ChainId, Size,
-};
-use codec::{Decode, Encode};
-use frame_support::RuntimeDebug;
-use scale_info::TypeInfo;
-use sp_std::prelude::*;
-
-/// Message dispatch weight.
-pub type Weight = u64;
-
-/// Spec version type.
-pub type SpecVersion = u32;
-
-/// A generic trait to dispatch arbitrary messages delivered over the bridge.
-pub trait MessageDispatch<AccountId, BridgeMessageId> {
-	/// A type of the message to be dispatched.
-	type Message: codec::Decode;
-
-	/// Estimate dispatch weight.
-	///
-	/// This function must: (1) be instant and (2) return correct upper bound
-	/// of dispatch weight.
-	fn dispatch_weight(message: &Self::Message) -> Weight;
-
-	/// Dispatches the message internally.
-	///
-	/// `source_chain` indicates the chain where the message came from.
-	/// `target_chain` indicates the chain where message dispatch happens.
-	///
-	/// `id` is a short unique identifier of the message.
-	///
-	/// If message is `Ok`, then it should be dispatched. If it is `Err`, then it's just
-	/// a sign that some other component has rejected the message even before it has
-	/// reached `dispatch` method (right now this may only be caused if we fail to decode
-	/// the whole message).
-	///
-	/// Returns unspent dispatch weight.
-	fn dispatch<P: FnOnce(&AccountId, Weight) -> Result<(), ()>>(
-		source_chain: ChainId,
-		target_chain: ChainId,
-		id: BridgeMessageId,
-		message: Result<Self::Message, ()>,
-		pay_dispatch_fee: P,
-	) -> MessageDispatchResult;
-}
-
-/// Origin of a Call when it is dispatched on the target chain.
-///
-/// The source chain can (and should) verify that the message can be dispatched on the target chain
-/// with a particular origin given the source chain's origin. This can be done with the
-/// `verify_message_origin()` function.
-#[derive(RuntimeDebug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo)]
-pub enum CallOrigin<SourceChainAccountId, TargetChainAccountPublic, TargetChainSignature> {
-	/// Call is sent by the Root origin on the source chain. On the target chain it is dispatched
-	/// from a derived account.
-	///
-	/// The derived account represents the source Root account on the target chain. This is useful
-	/// if the target chain needs some way of knowing that a call came from a privileged origin on
-	/// the source chain (maybe to allow a configuration change for example).
-	SourceRoot,
-
-	/// Call is sent by `SourceChainAccountId` on the source chain. On the target chain it is
-	/// dispatched from an account controlled by a private key on the target chain.
-	///
-	/// The account can be identified by `TargetChainAccountPublic`. The proof that the
-	/// `SourceChainAccountId` controls `TargetChainAccountPublic` is the `TargetChainSignature`
-	/// over `(Call, SourceChainAccountId, TargetChainSpecVersion, SourceChainBridgeId).encode()`.
-	///
-	/// NOTE sending messages using this origin (or any other) does not have replay protection!
-	/// The assumption is that both the source account and the target account is controlled by
-	/// the same entity, so source-chain replay protection is sufficient.
-	/// As a consequence, it's extremely important for the target chain user to never produce
-	/// a signature with their target-private key on something that could be sent over the bridge,
-	/// i.e. if the target user signs `(<some-source-account-id>, Call::Transfer(X, 5))`
-	/// The owner of `some-source-account-id` can send that message multiple times, which would
-	/// result with multiple transfer calls being dispatched on the target chain.
-	/// So please, NEVER USE YOUR PRIVATE KEY TO SIGN SOMETHING YOU DON'T FULLY UNDERSTAND!
-	TargetAccount(SourceChainAccountId, TargetChainAccountPublic, TargetChainSignature),
-
-	/// Call is sent by the `SourceChainAccountId` on the source chain. On the target chain it is
-	/// dispatched from a derived account ID.
-	///
-	/// The account ID on the target chain is derived from the source account ID. This is useful if
-	/// you need a way to represent foreign accounts on this chain for call dispatch purposes.
-	///
-	/// Note that the derived account does not need to have a private key on the target chain. This
-	/// origin can therefore represent proxies, pallets, etc. as well as "regular" accounts.
-	SourceAccount(SourceChainAccountId),
-}
-
-/// Message payload type used by dispatch module.
-#[derive(RuntimeDebug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo)]
-pub struct MessagePayload<
-	SourceChainAccountId,
-	TargetChainAccountPublic,
-	TargetChainSignature,
-	Call,
-> {
-	/// Runtime specification version. We only dispatch messages that have the same
-	/// runtime version. Otherwise we risk to misinterpret encoded calls.
-	pub spec_version: SpecVersion,
-	/// Weight of the call, declared by the message sender. If it is less than actual
-	/// static weight, the call is not dispatched.
-	pub weight: Weight,
-	/// Call origin to be used during dispatch.
-	pub origin: CallOrigin<SourceChainAccountId, TargetChainAccountPublic, TargetChainSignature>,
-	/// Where the fee for dispatching message is paid?
-	pub dispatch_fee_payment: DispatchFeePayment,
-	/// The call itself.
-	pub call: Call,
-}
-
-impl<SourceChainAccountId, TargetChainAccountPublic, TargetChainSignature> Size
-	for MessagePayload<SourceChainAccountId, TargetChainAccountPublic, TargetChainSignature, Vec<u8>>
-{
-	fn size_hint(&self) -> u32 {
-		self.call.len() as _
-	}
-}
diff --git a/bridges/primitives/runtime/src/lib.rs b/bridges/primitives/runtime/src/lib.rs
index 1d8a40339ab0c40db6fb77756bf59018a64caa1b..da6f376ae4f492e4cc7b5310f9ee26beb5cb678b 100644
--- a/bridges/primitives/runtime/src/lib.rs
+++ b/bridges/primitives/runtime/src/lib.rs
@@ -136,15 +136,15 @@ pub trait Size {
 	fn size_hint(&self) -> u32;
 }
 
-impl Size for &[u8] {
+impl Size for () {
 	fn size_hint(&self) -> u32 {
-		self.len() as _
+		0
 	}
 }
 
-impl Size for () {
+impl Size for Vec<u8> {
 	fn size_hint(&self) -> u32 {
-		0
+		self.len() as _
 	}
 }
 
diff --git a/bridges/primitives/token-swap/Cargo.toml b/bridges/primitives/token-swap/Cargo.toml
deleted file mode 100644
index 7ef5845d2aba7090d9a81f92a36f59da9c57af25..0000000000000000000000000000000000000000
--- a/bridges/primitives/token-swap/Cargo.toml
+++ /dev/null
@@ -1,38 +0,0 @@
-[package]
-name = "bp-token-swap"
-description = "Primitives of the pallet-bridge-token-swap pallet"
-version = "0.1.0"
-authors = ["Parity Technologies <admin@parity.io>"]
-edition = "2021"
-license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
-
-[dependencies]
-codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false }
-scale-info = { version = "2.1.1", default-features = false, features = ["derive"] }
-
-# Bridge Dependencies
-
-bp-runtime = { path = "../runtime", default-features = false }
-
-# Substrate Dependencies
-
-frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
-sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
-sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
-sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
-
-[dev-dependencies]
-hex = "0.4"
-hex-literal = "0.3"
-
-[features]
-default = ["std"]
-std = [
-	"bp-runtime/std",
-	"codec/std",
-	"frame-support/std",
-	"scale-info/std",
-	"sp-core/std",
-	"sp-io/std",
-	"sp-std/std",
-]
diff --git a/bridges/primitives/token-swap/src/lib.rs b/bridges/primitives/token-swap/src/lib.rs
deleted file mode 100644
index 79363e5477a449018b9eeb2a13d86295d77b98d2..0000000000000000000000000000000000000000
--- a/bridges/primitives/token-swap/src/lib.rs
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright 2019-2021 Parity Technologies (UK) Ltd.
-// This file is part of Parity Bridges Common.
-
-// Parity Bridges Common 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.
-
-// Parity Bridges Common 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 Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
-
-#![cfg_attr(not(feature = "std"), no_std)]
-
-pub mod storage_keys;
-
-use codec::{Decode, Encode};
-use frame_support::{weights::Weight, RuntimeDebug};
-use scale_info::TypeInfo;
-use sp_core::{H256, U256};
-use sp_io::hashing::blake2_256;
-use sp_std::vec::Vec;
-
-/// Pending token swap state.
-#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq, TypeInfo)]
-pub enum TokenSwapState {
-	/// The swap has been started using the `start_claim` call, but we have no proof that it has
-	/// happened at the Bridged chain.
-	Started,
-	/// The swap has happened at the Bridged chain and may be claimed by the Bridged chain party
-	/// using the `claim_swap` call.
-	Confirmed,
-	/// The swap has failed at the Bridged chain and This chain party may cancel it using the
-	/// `cancel_swap` call.
-	Failed,
-}
-
-/// Token swap type.
-///
-/// Different swap types give a different guarantees regarding possible swap
-/// replay protection.
-#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq, TypeInfo)]
-pub enum TokenSwapType<ThisBlockNumber> {
-	/// The `target_account_at_bridged_chain` is temporary and only have funds for single swap.
-	///
-	/// ***WARNING**: if `target_account_at_bridged_chain` still exists after the swap has been
-	/// completed (either by claiming or canceling), the `source_account_at_this_chain` will be
-	/// able to restart the swap again and repeat the swap until `target_account_at_bridged_chain`
-	/// depletes.
-	TemporaryTargetAccountAtBridgedChain,
-	/// This swap type prevents `source_account_at_this_chain` from restarting the swap after it
-	/// has been completed. There are two consequences:
-	///
-	/// 1) the `source_account_at_this_chain` won't be able to call `start_swap` after given
-	/// <ThisBlockNumber>; 2) the `target_account_at_bridged_chain` won't be able to call
-	/// `claim_swap` (over the bridge) before    block `<ThisBlockNumber + 1>`.
-	///
-	/// The second element is the nonce of the swap. You must care about its uniqueness if you're
-	/// planning to perform another swap with exactly the same parameters (i.e. same amount, same
-	/// accounts, same `ThisBlockNumber`) to avoid collisions.
-	LockClaimUntilBlock(ThisBlockNumber, U256),
-}
-
-/// An intention to swap `source_balance_at_this_chain` owned by `source_account_at_this_chain`
-/// to `target_balance_at_bridged_chain` owned by `target_account_at_bridged_chain`.
-///
-/// **IMPORTANT NOTE**: this structure is always the same during single token swap. So even
-/// when chain changes, the meaning of This and Bridged are still used to point to the same chains.
-/// This chain is always the chain where swap has been started. And the Bridged chain is the other
-/// chain.
-#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq, TypeInfo)]
-pub struct TokenSwap<ThisBlockNumber, ThisBalance, ThisAccountId, BridgedBalance, BridgedAccountId>
-{
-	/// The type of the swap.
-	pub swap_type: TokenSwapType<ThisBlockNumber>,
-	/// This chain balance to be swapped with `target_balance_at_bridged_chain`.
-	pub source_balance_at_this_chain: ThisBalance,
-	/// Account id of the party acting at This chain and owning the `source_account_at_this_chain`.
-	pub source_account_at_this_chain: ThisAccountId,
-	/// Bridged chain balance to be swapped with `source_balance_at_this_chain`.
-	pub target_balance_at_bridged_chain: BridgedBalance,
-	/// Account id of the party acting at the Bridged chain and owning the
-	/// `target_balance_at_bridged_chain`.
-	pub target_account_at_bridged_chain: BridgedAccountId,
-}
-
-impl<ThisBlockNumber, ThisBalance, ThisAccountId, BridgedBalance, BridgedAccountId>
-	TokenSwap<ThisBlockNumber, ThisBalance, ThisAccountId, BridgedBalance, BridgedAccountId>
-where
-	TokenSwap<ThisBlockNumber, ThisBalance, ThisAccountId, BridgedBalance, BridgedAccountId>:
-		Encode,
-{
-	/// Returns hash, used to identify this token swap.
-	pub fn hash(&self) -> H256 {
-		self.using_encoded(blake2_256).into()
-	}
-}
-
-/// SCALE-encoded `Currency::transfer` call on the bridged chain.
-pub type RawBridgedTransferCall = Vec<u8>;
-
-/// Token swap creation parameters.
-#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq, TypeInfo)]
-pub struct TokenSwapCreation<BridgedAccountPublic, ThisChainBalance, BridgedAccountSignature> {
-	/// Public key of the `target_account_at_bridged_chain` account used to verify
-	/// `bridged_currency_transfer_signature`.
-	pub target_public_at_bridged_chain: BridgedAccountPublic,
-	/// Fee that the `source_account_at_this_chain` is ready to pay for the tokens
-	/// transfer message delivery and dispatch.
-	pub swap_delivery_and_dispatch_fee: ThisChainBalance,
-	/// Specification version of the Bridged chain.
-	pub bridged_chain_spec_version: u32,
-	/// SCALE-encoded tokens transfer call at the Bridged chain.
-	pub bridged_currency_transfer: RawBridgedTransferCall,
-	/// Dispatch weight of the tokens transfer call at the Bridged chain.
-	pub bridged_currency_transfer_weight: Weight,
-	/// The signature of the `target_account_at_bridged_chain` for the message
-	/// returned by the `pallet_bridge_dispatch::account_ownership_digest()` function call.
-	pub bridged_currency_transfer_signature: BridgedAccountSignature,
-}
diff --git a/bridges/primitives/token-swap/src/storage_keys.rs b/bridges/primitives/token-swap/src/storage_keys.rs
deleted file mode 100644
index d0aafc0d5c2730e60cc525cc57f84b89048289eb..0000000000000000000000000000000000000000
--- a/bridges/primitives/token-swap/src/storage_keys.rs
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2019-2021 Parity Technologies (UK) Ltd.
-// This file is part of Parity Bridges Common.
-
-// Parity Bridges Common 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.
-
-// Parity Bridges Common 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 Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
-
-//! Storage keys of bridge token swap pallet.
-
-use frame_support::Identity;
-use sp_core::{storage::StorageKey, H256};
-
-/// Name of the `PendingSwaps` storage map.
-pub const PENDING_SWAPS_MAP_NAME: &str = "PendingSwaps";
-
-/// Storage key of `PendingSwaps` value with given token swap hash.
-pub fn pending_swaps_key(pallet_prefix: &str, token_swap_hash: H256) -> StorageKey {
-	bp_runtime::storage_map_final_key::<Identity>(
-		pallet_prefix,
-		PENDING_SWAPS_MAP_NAME,
-		token_swap_hash.as_ref(),
-	)
-}
-
-#[cfg(test)]
-mod tests {
-	use super::*;
-	use hex_literal::hex;
-
-	#[test]
-	fn pending_swaps_key_computed_properly() {
-		// If this test fails, then something has been changed in module storage that may break
-		// all previous swaps.
-		let storage_key = pending_swaps_key("BridgeTokenSwap", [42u8; 32].into()).0;
-		assert_eq!(
-			storage_key,
-			hex!("76276da64e7a4f454760eedeb4bad11adca2227fef56ad07cc424f1f5d128b9a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a").to_vec(),
-			"Unexpected storage key: {}",
-			hex::encode(&storage_key),
-		);
-	}
-}
diff --git a/bridges/relays/bin-substrate/Cargo.toml b/bridges/relays/bin-substrate/Cargo.toml
index 018fbfd2dded11f9c80b2184235d5c3bd3fa9fd2..1d1166d1a9d1da3bd78e2439f2aeaad3c18ddf54 100644
--- a/bridges/relays/bin-substrate/Cargo.toml
+++ b/bridges/relays/bin-substrate/Cargo.toml
@@ -25,24 +25,20 @@ strum = { version = "0.21.0", features = ["derive"] }
 bp-header-chain = { path = "../../primitives/header-chain" }
 bp-kusama = { path = "../../primitives/chain-kusama" }
 bp-messages = { path = "../../primitives/messages" }
-bp-message-dispatch = { path = "../../primitives/message-dispatch" }
 bp-millau = { path = "../../primitives/chain-millau" }
 bp-polkadot = { path = "../../primitives/chain-polkadot" }
 bp-rialto = { path = "../../primitives/chain-rialto" }
 bp-rialto-parachain = { path = "../../primitives/chain-rialto-parachain" }
 bp-rococo = { path = "../../primitives/chain-rococo" }
 bp-runtime = { path = "../../primitives/runtime" }
-bp-token-swap = { path = "../../primitives/token-swap" }
 bp-westend = { path = "../../primitives/chain-westend" }
 bp-wococo = { path = "../../primitives/chain-wococo" }
 bridge-runtime-common = { path = "../../bin/runtime-common" }
 finality-relay = { path = "../finality" }
 messages-relay = { path = "../messages" }
 millau-runtime = { path = "../../bin/millau/runtime" }
-pallet-bridge-dispatch = { path = "../../modules/dispatch" }
 pallet-bridge-grandpa = { path = "../../modules/grandpa" }
 pallet-bridge-messages = { path = "../../modules/messages" }
-pallet-bridge-token-swap = { path = "../../modules/token-swap" }
 relay-kusama-client = { path = "../client-kusama" }
 relay-millau-client = { path = "../client-millau" }
 relay-polkadot-client = { path = "../client-polkadot" }
diff --git a/bridges/relays/bin-substrate/src/chains/kusama.rs b/bridges/relays/bin-substrate/src/chains/kusama.rs
index 9cdc6cd125e02d9db4b026e57350b629e5d43f27..2b18475d680aea1e664d5eb4e427513c7f27fafe 100644
--- a/bridges/relays/bin-substrate/src/chains/kusama.rs
+++ b/bridges/relays/bin-substrate/src/chains/kusama.rs
@@ -14,82 +14,46 @@
 // You should have received a copy of the GNU General Public License
 // along with Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
 
-use anyhow::anyhow;
-use bp_message_dispatch::{CallOrigin, MessagePayload};
+use bp_messages::LaneId;
 use bp_runtime::EncodedOrDecodedCall;
-use codec::Decode;
-use frame_support::weights::{DispatchClass, DispatchInfo, Pays, Weight};
 use relay_kusama_client::Kusama;
+use relay_substrate_client::BalanceOf;
 use sp_version::RuntimeVersion;
 
 use crate::cli::{
 	bridge,
-	encode_call::{self, Call, CliEncodeCall},
-	encode_message,
-	send_message::{self, DispatchFeePayment},
+	encode_message::{CliEncodeMessage, RawMessage},
 	CliChain,
 };
 
-/// Weight of the `system::remark` call at Kusama.
-///
-/// This weight is larger (x2) than actual weight at current Kusama runtime to avoid unsuccessful
-/// calls in the future. But since it is used only in tests (and on test chains), this is ok.
-pub(crate) const SYSTEM_REMARK_CALL_WEIGHT: Weight = 2 * 1_345_000;
-
-impl CliEncodeCall for Kusama {
-	fn encode_call(call: &Call) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
-		Ok(match call {
-			Call::Raw { data } => EncodedOrDecodedCall::Encoded(data.0.clone()),
-			Call::Remark { remark_payload, .. } => relay_kusama_client::runtime::Call::System(
-				relay_kusama_client::runtime::SystemCall::remark(
-					remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(),
-				),
-			)
-			.into(),
-			Call::BridgeSendMessage { lane, payload, fee, bridge_instance_index } =>
-				match *bridge_instance_index {
-					bridge::KUSAMA_TO_POLKADOT_INDEX => {
-						let payload = Decode::decode(&mut &*payload.0)?;
-						relay_kusama_client::runtime::Call::BridgePolkadotMessages(
-							relay_kusama_client::runtime::BridgePolkadotMessagesCall::send_message(
-								lane.0, payload, fee.0,
-							),
-						)
-						.into()
-					},
-					_ => anyhow::bail!(
-						"Unsupported target bridge pallet with instance index: {}",
-						bridge_instance_index
+impl CliEncodeMessage for Kusama {
+	fn encode_send_message_call(
+		lane: LaneId,
+		payload: RawMessage,
+		fee: BalanceOf<Self>,
+		bridge_instance_index: u8,
+	) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
+		Ok(match bridge_instance_index {
+			bridge::KUSAMA_TO_POLKADOT_INDEX =>
+				relay_kusama_client::runtime::Call::BridgePolkadotMessages(
+					relay_kusama_client::runtime::BridgePolkadotMessagesCall::send_message(
+						lane, payload, fee,
 					),
-				},
-			_ => anyhow::bail!("Unsupported Kusama call: {:?}", call),
+				)
+				.into(),
+			_ => anyhow::bail!(
+				"Unsupported target bridge pallet with instance index: {}",
+				bridge_instance_index
+			),
 		})
 	}
-
-	fn get_dispatch_info(call: &EncodedOrDecodedCall<Self::Call>) -> anyhow::Result<DispatchInfo> {
-		match *call {
-			EncodedOrDecodedCall::Decoded(relay_kusama_client::runtime::Call::System(
-				relay_kusama_client::runtime::SystemCall::remark(_),
-			)) => Ok(DispatchInfo {
-				weight: crate::chains::kusama::SYSTEM_REMARK_CALL_WEIGHT,
-				class: DispatchClass::Normal,
-				pays_fee: Pays::Yes,
-			}),
-			_ => anyhow::bail!("Unsupported Kusama call: {:?}", call),
-		}
-	}
 }
 
 impl CliChain for Kusama {
 	const RUNTIME_VERSION: RuntimeVersion = bp_kusama::VERSION;
 
 	type KeyPair = sp_core::sr25519::Pair;
-	type MessagePayload = MessagePayload<
-		bp_kusama::AccountId,
-		bp_polkadot::AccountPublic,
-		bp_polkadot::Signature,
-		Vec<u8>,
-	>;
+	type MessagePayload = Vec<u8>;
 
 	fn ss58_format() -> u16 {
 		sp_core::crypto::Ss58AddressFormat::from(
@@ -97,39 +61,4 @@ impl CliChain for Kusama {
 		)
 		.into()
 	}
-
-	fn encode_message(
-		message: encode_message::MessagePayload,
-	) -> anyhow::Result<Self::MessagePayload> {
-		match message {
-			encode_message::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0)
-				.map_err(|e| anyhow!("Failed to decode Kusama's MessagePayload: {:?}", e)),
-			encode_message::MessagePayload::Call { mut call, mut sender, dispatch_weight } => {
-				type Source = Kusama;
-				type Target = relay_polkadot_client::Polkadot;
-
-				sender.enforce_chain::<Source>();
-				let spec_version = Target::RUNTIME_VERSION.spec_version;
-				let origin = CallOrigin::SourceAccount(sender.raw_id());
-				encode_call::preprocess_call::<Source, Target>(
-					&mut call,
-					bridge::KUSAMA_TO_POLKADOT_INDEX,
-				);
-				let call = Target::encode_call(&call)?;
-				let dispatch_weight = dispatch_weight.map(Ok).unwrap_or_else(|| {
-					Err(anyhow::format_err!(
-						"Please specify dispatch weight of the encoded Polkadot call"
-					))
-				})?;
-
-				Ok(send_message::message_payload(
-					spec_version,
-					dispatch_weight,
-					origin,
-					&call,
-					DispatchFeePayment::AtSourceChain,
-				))
-			},
-		}
-	}
 }
diff --git a/bridges/relays/bin-substrate/src/chains/millau.rs b/bridges/relays/bin-substrate/src/chains/millau.rs
index 1fc1e8308ef451a58c42a33e40d55fb96a2bf692..a9e99771f59228e12264be9e011056ffc0e62385 100644
--- a/bridges/relays/bin-substrate/src/chains/millau.rs
+++ b/bridges/relays/bin-substrate/src/chains/millau.rs
@@ -18,106 +18,46 @@
 
 use crate::cli::{
 	bridge,
-	encode_call::{self, Call, CliEncodeCall},
-	encode_message,
-	send_message::{self, DispatchFeePayment},
+	encode_message::{CliEncodeMessage, RawMessage},
 	CliChain,
 };
-use anyhow::anyhow;
-use bp_message_dispatch::{CallOrigin, MessagePayload};
+use bp_messages::LaneId;
 use bp_runtime::EncodedOrDecodedCall;
-use codec::Decode;
-use frame_support::weights::{DispatchInfo, GetDispatchInfo};
 use relay_millau_client::Millau;
+use relay_substrate_client::BalanceOf;
 use sp_version::RuntimeVersion;
 
-impl CliEncodeCall for Millau {
-	fn encode_call(call: &Call) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
-		Ok(match call {
-			Call::Raw { data } => Self::Call::decode(&mut &*data.0)?.into(),
-			Call::Remark { remark_payload, .. } =>
-				millau_runtime::Call::System(millau_runtime::SystemCall::remark {
-					remark: remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(),
-				})
-				.into(),
-			Call::Transfer { recipient, amount } =>
-				millau_runtime::Call::Balances(millau_runtime::BalancesCall::transfer {
-					dest: recipient.raw_id(),
-					value: amount.cast(),
-				})
-				.into(),
-			Call::BridgeSendMessage { lane, payload, fee, bridge_instance_index } =>
-				match *bridge_instance_index {
-					bridge::MILLAU_TO_RIALTO_INDEX => {
-						let payload = Decode::decode(&mut &*payload.0)?;
-						millau_runtime::Call::BridgeRialtoMessages(
-							millau_runtime::MessagesCall::send_message {
-								lane_id: lane.0,
-								payload,
-								delivery_and_dispatch_fee: fee.cast(),
-							},
-						)
-						.into()
-					},
-					_ => anyhow::bail!(
-						"Unsupported target bridge pallet with instance index: {}",
-						bridge_instance_index
-					),
+impl CliEncodeMessage for Millau {
+	fn encode_send_message_call(
+		lane: LaneId,
+		payload: RawMessage,
+		fee: BalanceOf<Self>,
+		bridge_instance_index: u8,
+	) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
+		Ok(match bridge_instance_index {
+			bridge::MILLAU_TO_RIALTO_INDEX => millau_runtime::Call::BridgeRialtoMessages(
+				millau_runtime::MessagesCall::send_message {
+					lane_id: lane,
+					payload,
+					delivery_and_dispatch_fee: fee,
 				},
+			)
+			.into(),
+			_ => anyhow::bail!(
+				"Unsupported target bridge pallet with instance index: {}",
+				bridge_instance_index
+			),
 		})
 	}
-
-	fn get_dispatch_info(call: &EncodedOrDecodedCall<Self::Call>) -> anyhow::Result<DispatchInfo> {
-		Ok(call.to_decoded()?.get_dispatch_info())
-	}
 }
 
 impl CliChain for Millau {
 	const RUNTIME_VERSION: RuntimeVersion = millau_runtime::VERSION;
 
 	type KeyPair = sp_core::sr25519::Pair;
-	type MessagePayload = MessagePayload<
-		bp_millau::AccountId,
-		bp_rialto::AccountSigner,
-		bp_rialto::Signature,
-		Vec<u8>,
-	>;
+	type MessagePayload = Vec<u8>;
 
 	fn ss58_format() -> u16 {
 		millau_runtime::SS58Prefix::get() as u16
 	}
-
-	// TODO [#854|#843] support multiple bridges?
-	fn encode_message(
-		message: encode_message::MessagePayload,
-	) -> anyhow::Result<Self::MessagePayload> {
-		match message {
-			encode_message::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0)
-				.map_err(|e| anyhow!("Failed to decode Millau's MessagePayload: {:?}", e)),
-			encode_message::MessagePayload::Call { mut call, mut sender, dispatch_weight } => {
-				type Source = Millau;
-				type Target = relay_rialto_client::Rialto;
-
-				sender.enforce_chain::<Source>();
-				let spec_version = Target::RUNTIME_VERSION.spec_version;
-				let origin = CallOrigin::SourceAccount(sender.raw_id());
-				encode_call::preprocess_call::<Source, Target>(
-					&mut call,
-					bridge::MILLAU_TO_RIALTO_INDEX,
-				);
-				let call = Target::encode_call(&call)?;
-				let dispatch_weight = dispatch_weight.map(Ok).unwrap_or_else(|| {
-					call.to_decoded().map(|call| call.get_dispatch_info().weight)
-				})?;
-
-				Ok(send_message::message_payload(
-					spec_version,
-					dispatch_weight,
-					origin,
-					&call,
-					DispatchFeePayment::AtSourceChain,
-				))
-			},
-		}
-	}
 }
diff --git a/bridges/relays/bin-substrate/src/chains/mod.rs b/bridges/relays/bin-substrate/src/chains/mod.rs
index 16901143e19fbc1936eff5750e74cde9081c409a..9b3416f901cfa8f71e878ec2fa0fa0cbbd55d9e4 100644
--- a/bridges/relays/bin-substrate/src/chains/mod.rs
+++ b/bridges/relays/bin-substrate/src/chains/mod.rs
@@ -41,95 +41,28 @@ mod wococo;
 
 #[cfg(test)]
 mod tests {
-	use crate::cli::{encode_call, send_message};
+	use crate::cli::encode_message;
 	use bp_messages::source_chain::TargetHeaderChain;
 	use bp_runtime::Chain as _;
 	use codec::Encode;
-	use frame_support::dispatch::GetDispatchInfo;
 	use relay_millau_client::Millau;
 	use relay_rialto_client::Rialto;
 	use relay_substrate_client::{SignParam, TransactionSignScheme, UnsignedTransaction};
-	use sp_core::Pair;
-	use sp_runtime::traits::{IdentifyAccount, Verify};
 
 	#[test]
-	fn millau_signature_is_valid_on_rialto() {
-		let millau_sign = relay_millau_client::SigningParams::from_string("//Dave", None).unwrap();
-
-		let call =
-			rialto_runtime::Call::System(rialto_runtime::SystemCall::remark { remark: vec![] });
-
-		let millau_public: bp_millau::AccountSigner = millau_sign.public().into();
-		let millau_account_id: bp_millau::AccountId = millau_public.into_account();
-
-		let digest = millau_runtime::millau_to_rialto_account_ownership_digest(
-			&call,
-			millau_account_id,
-			rialto_runtime::VERSION.spec_version,
-		);
-
-		let rialto_signer =
-			relay_rialto_client::SigningParams::from_string("//Dave", None).unwrap();
-		let signature = rialto_signer.sign(&digest);
-
-		assert!(signature.verify(&digest[..], &rialto_signer.public()));
-	}
-
-	#[test]
-	fn rialto_signature_is_valid_on_millau() {
-		let rialto_sign = relay_rialto_client::SigningParams::from_string("//Dave", None).unwrap();
-
-		let call =
-			millau_runtime::Call::System(millau_runtime::SystemCall::remark { remark: vec![] });
-
-		let rialto_public: bp_rialto::AccountSigner = rialto_sign.public().into();
-		let rialto_account_id: bp_rialto::AccountId = rialto_public.into_account();
-
-		let digest = rialto_runtime::rialto_to_millau_account_ownership_digest(
-			&call,
-			rialto_account_id,
-			millau_runtime::VERSION.spec_version,
-		);
-
-		let millau_signer =
-			relay_millau_client::SigningParams::from_string("//Dave", None).unwrap();
-		let signature = millau_signer.sign(&digest);
-
-		assert!(signature.verify(&digest[..], &millau_signer.public()));
-	}
-
-	#[test]
-	fn maximal_rialto_to_millau_message_arguments_size_is_computed_correctly() {
+	fn maximal_rialto_to_millau_message_size_is_computed_correctly() {
 		use rialto_runtime::millau_messages::Millau;
 
-		let maximal_remark_size = encode_call::compute_maximal_message_arguments_size(
+		let maximal_message_size = encode_message::compute_maximal_message_size(
 			bp_rialto::Rialto::max_extrinsic_size(),
 			bp_millau::Millau::max_extrinsic_size(),
 		);
 
-		let call: millau_runtime::Call =
-			millau_runtime::SystemCall::remark { remark: vec![42; maximal_remark_size as _] }
-				.into();
-		let payload = send_message::message_payload(
-			Default::default(),
-			call.get_dispatch_info().weight,
-			bp_message_dispatch::CallOrigin::SourceRoot,
-			&call,
-			send_message::DispatchFeePayment::AtSourceChain,
-		);
-		assert_eq!(Millau::verify_message(&payload), Ok(()));
+		let message = vec![42; maximal_message_size as _];
+		assert_eq!(Millau::verify_message(&message), Ok(()));
 
-		let call: millau_runtime::Call =
-			millau_runtime::SystemCall::remark { remark: vec![42; (maximal_remark_size + 1) as _] }
-				.into();
-		let payload = send_message::message_payload(
-			Default::default(),
-			call.get_dispatch_info().weight,
-			bp_message_dispatch::CallOrigin::SourceRoot,
-			&call,
-			send_message::DispatchFeePayment::AtSourceChain,
-		);
-		assert!(Millau::verify_message(&payload).is_err());
+		let message = vec![42; (maximal_message_size + 1) as _];
+		assert!(Millau::verify_message(&message).is_err());
 	}
 
 	#[test]
@@ -141,65 +74,6 @@ mod tests {
 			"We can't actually send maximal messages to Rialto from Millau, because Millau extrinsics can't be that large",
 		)
 	}
-
-	#[test]
-	fn maximal_rialto_to_millau_message_dispatch_weight_is_computed_correctly() {
-		use rialto_runtime::millau_messages::Millau;
-
-		let maximal_dispatch_weight = send_message::compute_maximal_message_dispatch_weight(
-			bp_millau::Millau::max_extrinsic_weight(),
-		);
-		let call: millau_runtime::Call =
-			rialto_runtime::SystemCall::remark { remark: vec![] }.into();
-
-		let payload = send_message::message_payload(
-			Default::default(),
-			maximal_dispatch_weight,
-			bp_message_dispatch::CallOrigin::SourceRoot,
-			&call,
-			send_message::DispatchFeePayment::AtSourceChain,
-		);
-		assert_eq!(Millau::verify_message(&payload), Ok(()));
-
-		let payload = send_message::message_payload(
-			Default::default(),
-			maximal_dispatch_weight + 1,
-			bp_message_dispatch::CallOrigin::SourceRoot,
-			&call,
-			send_message::DispatchFeePayment::AtSourceChain,
-		);
-		assert!(Millau::verify_message(&payload).is_err());
-	}
-
-	#[test]
-	fn maximal_weight_fill_block_to_rialto_is_generated_correctly() {
-		use millau_runtime::rialto_messages::Rialto;
-
-		let maximal_dispatch_weight = send_message::compute_maximal_message_dispatch_weight(
-			bp_rialto::Rialto::max_extrinsic_weight(),
-		);
-		let call: rialto_runtime::Call =
-			millau_runtime::SystemCall::remark { remark: vec![] }.into();
-
-		let payload = send_message::message_payload(
-			Default::default(),
-			maximal_dispatch_weight,
-			bp_message_dispatch::CallOrigin::SourceRoot,
-			&call,
-			send_message::DispatchFeePayment::AtSourceChain,
-		);
-		assert_eq!(Rialto::verify_message(&payload), Ok(()));
-
-		let payload = send_message::message_payload(
-			Default::default(),
-			maximal_dispatch_weight + 1,
-			bp_message_dispatch::CallOrigin::SourceRoot,
-			&call,
-			send_message::DispatchFeePayment::AtSourceChain,
-		);
-		assert!(Rialto::verify_message(&payload).is_err());
-	}
-
 	#[test]
 	fn rialto_tx_extra_bytes_constant_is_correct() {
 		let rialto_call =
diff --git a/bridges/relays/bin-substrate/src/chains/polkadot.rs b/bridges/relays/bin-substrate/src/chains/polkadot.rs
index 7ae1cbc4777779e3445cc3290a0b678b9c6d2bed..3ef7523f2a5330c9aa644ebcdb246b67f64ff0dc 100644
--- a/bridges/relays/bin-substrate/src/chains/polkadot.rs
+++ b/bridges/relays/bin-substrate/src/chains/polkadot.rs
@@ -14,82 +14,46 @@
 // You should have received a copy of the GNU General Public License
 // along with Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
 
-use anyhow::anyhow;
-use bp_message_dispatch::{CallOrigin, MessagePayload};
+use bp_messages::LaneId;
 use bp_runtime::EncodedOrDecodedCall;
-use codec::Decode;
-use frame_support::weights::{DispatchClass, DispatchInfo, Pays, Weight};
 use relay_polkadot_client::Polkadot;
+use relay_substrate_client::BalanceOf;
 use sp_version::RuntimeVersion;
 
 use crate::cli::{
 	bridge,
-	encode_call::{self, Call, CliEncodeCall},
-	encode_message,
-	send_message::{self, DispatchFeePayment},
+	encode_message::{CliEncodeMessage, RawMessage},
 	CliChain,
 };
 
-/// Weight of the `system::remark` call at Polkadot.
-///
-/// This weight is larger (x2) than actual weight at current Polkadot runtime to avoid unsuccessful
-/// calls in the future. But since it is used only in tests (and on test chains), this is ok.
-pub(crate) const SYSTEM_REMARK_CALL_WEIGHT: Weight = 2 * 1_345_000;
-
-impl CliEncodeCall for Polkadot {
-	fn encode_call(call: &Call) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
-		Ok(match call {
-			Call::Raw { data } => EncodedOrDecodedCall::Encoded(data.0.clone()),
-			Call::Remark { remark_payload, .. } => relay_polkadot_client::runtime::Call::System(
-				relay_polkadot_client::runtime::SystemCall::remark(
-					remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(),
-				),
-			)
-			.into(),
-			Call::BridgeSendMessage { lane, payload, fee, bridge_instance_index } =>
-				match *bridge_instance_index {
-					bridge::POLKADOT_TO_KUSAMA_INDEX => {
-						let payload = Decode::decode(&mut &*payload.0)?;
-						relay_polkadot_client::runtime::Call::BridgeKusamaMessages(
-							relay_polkadot_client::runtime::BridgeKusamaMessagesCall::send_message(
-								lane.0, payload, fee.0,
-							),
-						)
-						.into()
-					},
-					_ => anyhow::bail!(
-						"Unsupported target bridge pallet with instance index: {}",
-						bridge_instance_index
+impl CliEncodeMessage for Polkadot {
+	fn encode_send_message_call(
+		lane: LaneId,
+		payload: RawMessage,
+		fee: BalanceOf<Self>,
+		bridge_instance_index: u8,
+	) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
+		Ok(match bridge_instance_index {
+			bridge::POLKADOT_TO_KUSAMA_INDEX =>
+				relay_polkadot_client::runtime::Call::BridgeKusamaMessages(
+					relay_polkadot_client::runtime::BridgeKusamaMessagesCall::send_message(
+						lane, payload, fee,
 					),
-				},
-			_ => anyhow::bail!("Unsupported Polkadot call: {:?}", call),
+				)
+				.into(),
+			_ => anyhow::bail!(
+				"Unsupported target bridge pallet with instance index: {}",
+				bridge_instance_index
+			),
 		})
 	}
-
-	fn get_dispatch_info(call: &EncodedOrDecodedCall<Self::Call>) -> anyhow::Result<DispatchInfo> {
-		match *call {
-			EncodedOrDecodedCall::Decoded(relay_polkadot_client::runtime::Call::System(
-				relay_polkadot_client::runtime::SystemCall::remark(_),
-			)) => Ok(DispatchInfo {
-				weight: crate::chains::polkadot::SYSTEM_REMARK_CALL_WEIGHT,
-				class: DispatchClass::Normal,
-				pays_fee: Pays::Yes,
-			}),
-			_ => anyhow::bail!("Unsupported Polkadot call: {:?}", call),
-		}
-	}
 }
 
 impl CliChain for Polkadot {
 	const RUNTIME_VERSION: RuntimeVersion = bp_polkadot::VERSION;
 
 	type KeyPair = sp_core::sr25519::Pair;
-	type MessagePayload = MessagePayload<
-		bp_polkadot::AccountId,
-		bp_kusama::AccountPublic,
-		bp_kusama::Signature,
-		Vec<u8>,
-	>;
+	type MessagePayload = Vec<u8>;
 
 	fn ss58_format() -> u16 {
 		sp_core::crypto::Ss58AddressFormat::from(
@@ -97,39 +61,4 @@ impl CliChain for Polkadot {
 		)
 		.into()
 	}
-
-	fn encode_message(
-		message: encode_message::MessagePayload,
-	) -> anyhow::Result<Self::MessagePayload> {
-		match message {
-			encode_message::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0)
-				.map_err(|e| anyhow!("Failed to decode Polkadot's MessagePayload: {:?}", e)),
-			encode_message::MessagePayload::Call { mut call, mut sender, dispatch_weight } => {
-				type Source = Polkadot;
-				type Target = relay_kusama_client::Kusama;
-
-				sender.enforce_chain::<Source>();
-				let spec_version = Target::RUNTIME_VERSION.spec_version;
-				let origin = CallOrigin::SourceAccount(sender.raw_id());
-				encode_call::preprocess_call::<Source, Target>(
-					&mut call,
-					bridge::POLKADOT_TO_KUSAMA_INDEX,
-				);
-				let call = Target::encode_call(&call)?;
-				let dispatch_weight = dispatch_weight.map(Ok).unwrap_or_else(|| {
-					Err(anyhow::format_err!(
-						"Please specify dispatch weight of the encoded Kusama call"
-					))
-				})?;
-
-				Ok(send_message::message_payload(
-					spec_version,
-					dispatch_weight,
-					origin,
-					&call,
-					DispatchFeePayment::AtSourceChain,
-				))
-			},
-		}
-	}
 }
diff --git a/bridges/relays/bin-substrate/src/chains/rialto.rs b/bridges/relays/bin-substrate/src/chains/rialto.rs
index 8f26a64a4e326f6d3cf6647c8e465d223f10bb93..0255a055a5742fa5be52d19ca5addd43973b0ad9 100644
--- a/bridges/relays/bin-substrate/src/chains/rialto.rs
+++ b/bridges/relays/bin-substrate/src/chains/rialto.rs
@@ -18,105 +18,46 @@
 
 use crate::cli::{
 	bridge,
-	encode_call::{self, Call, CliEncodeCall},
-	encode_message,
-	send_message::{self, DispatchFeePayment},
+	encode_message::{CliEncodeMessage, RawMessage},
 	CliChain,
 };
-use anyhow::anyhow;
-use bp_message_dispatch::{CallOrigin, MessagePayload};
+use bp_messages::LaneId;
 use bp_runtime::EncodedOrDecodedCall;
-use codec::Decode;
-use frame_support::weights::{DispatchInfo, GetDispatchInfo};
 use relay_rialto_client::Rialto;
+use relay_substrate_client::BalanceOf;
 use sp_version::RuntimeVersion;
 
-impl CliEncodeCall for Rialto {
-	fn encode_call(call: &Call) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
-		Ok(match call {
-			Call::Raw { data } => Self::Call::decode(&mut &*data.0)?.into(),
-			Call::Remark { remark_payload, .. } =>
-				rialto_runtime::Call::System(rialto_runtime::SystemCall::remark {
-					remark: remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(),
-				})
-				.into(),
-			Call::Transfer { recipient, amount } =>
-				rialto_runtime::Call::Balances(rialto_runtime::BalancesCall::transfer {
-					dest: recipient.raw_id().into(),
-					value: amount.0,
-				})
-				.into(),
-			Call::BridgeSendMessage { lane, payload, fee, bridge_instance_index } =>
-				match *bridge_instance_index {
-					bridge::RIALTO_TO_MILLAU_INDEX => {
-						let payload = Decode::decode(&mut &*payload.0)?;
-						rialto_runtime::Call::BridgeMillauMessages(
-							rialto_runtime::MessagesCall::send_message {
-								lane_id: lane.0,
-								payload,
-								delivery_and_dispatch_fee: fee.0,
-							},
-						)
-						.into()
-					},
-					_ => anyhow::bail!(
-						"Unsupported target bridge pallet with instance index: {}",
-						bridge_instance_index
-					),
+impl CliEncodeMessage for Rialto {
+	fn encode_send_message_call(
+		lane: LaneId,
+		payload: RawMessage,
+		fee: BalanceOf<Self>,
+		bridge_instance_index: u8,
+	) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
+		Ok(match bridge_instance_index {
+			bridge::RIALTO_TO_MILLAU_INDEX => rialto_runtime::Call::BridgeMillauMessages(
+				rialto_runtime::MessagesCall::send_message {
+					lane_id: lane,
+					payload,
+					delivery_and_dispatch_fee: fee,
 				},
+			)
+			.into(),
+			_ => anyhow::bail!(
+				"Unsupported target bridge pallet with instance index: {}",
+				bridge_instance_index
+			),
 		})
 	}
-
-	fn get_dispatch_info(call: &EncodedOrDecodedCall<Self::Call>) -> anyhow::Result<DispatchInfo> {
-		Ok(call.to_decoded()?.get_dispatch_info())
-	}
 }
 
 impl CliChain for Rialto {
 	const RUNTIME_VERSION: RuntimeVersion = rialto_runtime::VERSION;
 
 	type KeyPair = sp_core::sr25519::Pair;
-	type MessagePayload = MessagePayload<
-		bp_rialto::AccountId,
-		bp_millau::AccountSigner,
-		bp_millau::Signature,
-		Vec<u8>,
-	>;
+	type MessagePayload = Vec<u8>;
 
 	fn ss58_format() -> u16 {
 		rialto_runtime::SS58Prefix::get() as u16
 	}
-
-	fn encode_message(
-		message: encode_message::MessagePayload,
-	) -> anyhow::Result<Self::MessagePayload> {
-		match message {
-			encode_message::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0)
-				.map_err(|e| anyhow!("Failed to decode Rialto's MessagePayload: {:?}", e)),
-			encode_message::MessagePayload::Call { mut call, mut sender, dispatch_weight } => {
-				type Source = Rialto;
-				type Target = relay_millau_client::Millau;
-
-				sender.enforce_chain::<Source>();
-				let spec_version = Target::RUNTIME_VERSION.spec_version;
-				let origin = CallOrigin::SourceAccount(sender.raw_id());
-				encode_call::preprocess_call::<Source, Target>(
-					&mut call,
-					bridge::RIALTO_TO_MILLAU_INDEX,
-				);
-				let call = Target::encode_call(&call)?;
-				let dispatch_weight = dispatch_weight.map(Ok).unwrap_or_else(|| {
-					call.to_decoded().map(|call| call.get_dispatch_info().weight)
-				})?;
-
-				Ok(send_message::message_payload(
-					spec_version,
-					dispatch_weight,
-					origin,
-					&call,
-					DispatchFeePayment::AtSourceChain,
-				))
-			},
-		}
-	}
 }
diff --git a/bridges/relays/bin-substrate/src/chains/rialto_parachain.rs b/bridges/relays/bin-substrate/src/chains/rialto_parachain.rs
index 0ed39faa543b7f103b67232f082f577f7d16e816..8e87c3ede706f1009e789e59ff7e8de3ab272f84 100644
--- a/bridges/relays/bin-substrate/src/chains/rialto_parachain.rs
+++ b/bridges/relays/bin-substrate/src/chains/rialto_parachain.rs
@@ -16,63 +16,17 @@
 
 //! Rialto parachain specification for CLI.
 
-use crate::cli::{
-	encode_call::{Call, CliEncodeCall},
-	encode_message, CliChain,
-};
-use bp_message_dispatch::MessagePayload;
-use bp_runtime::EncodedOrDecodedCall;
-use codec::Decode;
-use frame_support::weights::{DispatchInfo, GetDispatchInfo};
+use crate::cli::CliChain;
 use relay_rialto_parachain_client::RialtoParachain;
 use sp_version::RuntimeVersion;
 
-impl CliEncodeCall for RialtoParachain {
-	fn encode_call(call: &Call) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
-		Ok(match call {
-			Call::Raw { data } => Self::Call::decode(&mut &*data.0)?.into(),
-			Call::Remark { remark_payload, .. } => rialto_parachain_runtime::Call::System(
-				rialto_parachain_runtime::SystemCall::remark {
-					remark: remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(),
-				},
-			)
-			.into(),
-			Call::Transfer { recipient, amount } => rialto_parachain_runtime::Call::Balances(
-				rialto_parachain_runtime::BalancesCall::transfer {
-					dest: recipient.raw_id().into(),
-					value: amount.0,
-				},
-			)
-			.into(),
-			Call::BridgeSendMessage { .. } => {
-				anyhow::bail!("Bridge messages are not (yet) supported here",)
-			},
-		})
-	}
-
-	fn get_dispatch_info(call: &EncodedOrDecodedCall<Self::Call>) -> anyhow::Result<DispatchInfo> {
-		Ok(call.to_decoded()?.get_dispatch_info())
-	}
-}
-
 impl CliChain for RialtoParachain {
 	const RUNTIME_VERSION: RuntimeVersion = rialto_parachain_runtime::VERSION;
 
 	type KeyPair = sp_core::sr25519::Pair;
-	type MessagePayload = MessagePayload<
-		bp_rialto_parachain::AccountId,
-		bp_millau::AccountSigner,
-		bp_millau::Signature,
-		Vec<u8>,
-	>;
+	type MessagePayload = Vec<u8>;
 
 	fn ss58_format() -> u16 {
 		rialto_parachain_runtime::SS58Prefix::get() as u16
 	}
-
-	fn encode_message(
-		_message: encode_message::MessagePayload,
-	) -> anyhow::Result<Self::MessagePayload> {
-		anyhow::bail!("Not supported")
-	}
 }
diff --git a/bridges/relays/bin-substrate/src/chains/rococo.rs b/bridges/relays/bin-substrate/src/chains/rococo.rs
index ceef4c1f532c9c5f14da4eb69c9b329a7586db15..0d2b800e79bf8078f08906f3abf4b00d6f3369d7 100644
--- a/bridges/relays/bin-substrate/src/chains/rococo.rs
+++ b/bridges/relays/bin-substrate/src/chains/rococo.rs
@@ -14,119 +14,47 @@
 // You should have received a copy of the GNU General Public License
 // along with Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
 
-use anyhow::anyhow;
-use bp_message_dispatch::{CallOrigin, MessagePayload};
+use bp_messages::LaneId;
 use bp_runtime::EncodedOrDecodedCall;
-use codec::Decode;
-use frame_support::weights::{DispatchClass, DispatchInfo, Pays, Weight};
 use relay_rococo_client::Rococo;
+use relay_substrate_client::BalanceOf;
 use sp_version::RuntimeVersion;
 
 use crate::cli::{
 	bridge,
-	encode_call::{self, Call, CliEncodeCall},
-	encode_message,
-	send_message::{self, DispatchFeePayment},
+	encode_message::{CliEncodeMessage, RawMessage},
 	CliChain,
 };
 
-/// Weight of the `system::remark` call at Rococo.
-///
-/// This weight is larger (x2) than actual weight at current Rococo runtime to avoid unsuccessful
-/// calls in the future. But since it is used only in tests (and on test chains), this is ok.
-pub(crate) const SYSTEM_REMARK_CALL_WEIGHT: Weight = 2 * 1_345_000;
-
-impl CliEncodeCall for Rococo {
-	fn encode_call(call: &Call) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
-		Ok(match call {
-			Call::Raw { data } => EncodedOrDecodedCall::Encoded(data.0.clone()),
-			Call::Remark { remark_payload, .. } => relay_rococo_client::runtime::Call::System(
-				relay_rococo_client::runtime::SystemCall::remark(
-					remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(),
-				),
-			)
-			.into(),
-			Call::BridgeSendMessage { lane, payload, fee, bridge_instance_index } =>
-				match *bridge_instance_index {
-					bridge::ROCOCO_TO_WOCOCO_INDEX => {
-						let payload = Decode::decode(&mut &*payload.0)?;
-						relay_rococo_client::runtime::Call::BridgeWococoMessages(
-							relay_rococo_client::runtime::BridgeWococoMessagesCall::send_message(
-								lane.0, payload, fee.0,
-							),
-						)
-						.into()
-					},
-					_ => anyhow::bail!(
-						"Unsupported target bridge pallet with instance index: {}",
-						bridge_instance_index
+impl CliEncodeMessage for Rococo {
+	fn encode_send_message_call(
+		lane: LaneId,
+		payload: RawMessage,
+		fee: BalanceOf<Self>,
+		bridge_instance_index: u8,
+	) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
+		Ok(match bridge_instance_index {
+			bridge::ROCOCO_TO_WOCOCO_INDEX =>
+				relay_rococo_client::runtime::Call::BridgeWococoMessages(
+					relay_rococo_client::runtime::BridgeWococoMessagesCall::send_message(
+						lane, payload, fee,
 					),
-				},
-			_ => anyhow::bail!("The call is not supported"),
+				)
+				.into(),
+			_ => anyhow::bail!(
+				"Unsupported target bridge pallet with instance index: {}",
+				bridge_instance_index
+			),
 		})
 	}
-
-	fn get_dispatch_info(call: &EncodedOrDecodedCall<Self::Call>) -> anyhow::Result<DispatchInfo> {
-		match *call {
-			EncodedOrDecodedCall::Decoded(relay_rococo_client::runtime::Call::System(
-				relay_rococo_client::runtime::SystemCall::remark(_),
-			)) => Ok(DispatchInfo {
-				weight: SYSTEM_REMARK_CALL_WEIGHT,
-				class: DispatchClass::Normal,
-				pays_fee: Pays::Yes,
-			}),
-			_ => anyhow::bail!("Unsupported Rococo call: {:?}", call),
-		}
-	}
 }
-
 impl CliChain for Rococo {
 	const RUNTIME_VERSION: RuntimeVersion = bp_rococo::VERSION;
 
 	type KeyPair = sp_core::sr25519::Pair;
-	type MessagePayload = MessagePayload<
-		bp_rococo::AccountId,
-		bp_wococo::AccountPublic,
-		bp_wococo::Signature,
-		Vec<u8>,
-	>;
+	type MessagePayload = Vec<u8>;
 
 	fn ss58_format() -> u16 {
 		42
 	}
-
-	fn encode_message(
-		message: encode_message::MessagePayload,
-	) -> anyhow::Result<Self::MessagePayload> {
-		match message {
-			encode_message::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0)
-				.map_err(|e| anyhow!("Failed to decode Rococo's MessagePayload: {:?}", e)),
-			encode_message::MessagePayload::Call { mut call, mut sender, dispatch_weight } => {
-				type Source = Rococo;
-				type Target = relay_wococo_client::Wococo;
-
-				sender.enforce_chain::<Source>();
-				let spec_version = Target::RUNTIME_VERSION.spec_version;
-				let origin = CallOrigin::SourceAccount(sender.raw_id());
-				encode_call::preprocess_call::<Source, Target>(
-					&mut call,
-					bridge::ROCOCO_TO_WOCOCO_INDEX,
-				);
-				let call = Target::encode_call(&call)?;
-				let dispatch_weight = dispatch_weight.map(Ok).unwrap_or_else(|| {
-					Err(anyhow::format_err!(
-						"Please specify dispatch weight of the encoded Wococo call"
-					))
-				})?;
-
-				Ok(send_message::message_payload(
-					spec_version,
-					dispatch_weight,
-					origin,
-					&call,
-					DispatchFeePayment::AtSourceChain,
-				))
-			},
-		}
-	}
 }
diff --git a/bridges/relays/bin-substrate/src/chains/westend.rs b/bridges/relays/bin-substrate/src/chains/westend.rs
index 8d3b5db9ab37f02869b95b88d88d76807c5d63df..eb578ddb78348020496c9460099180238ab81503 100644
--- a/bridges/relays/bin-substrate/src/chains/westend.rs
+++ b/bridges/relays/bin-substrate/src/chains/westend.rs
@@ -16,8 +16,7 @@
 
 //! Westend chain specification for CLI.
 
-use crate::cli::{encode_message, CliChain};
-use anyhow::anyhow;
+use crate::cli::CliChain;
 use relay_westend_client::Westend;
 use sp_version::RuntimeVersion;
 
@@ -25,7 +24,7 @@ impl CliChain for Westend {
 	const RUNTIME_VERSION: RuntimeVersion = bp_westend::VERSION;
 
 	type KeyPair = sp_core::sr25519::Pair;
-	type MessagePayload = ();
+	type MessagePayload = Vec<u8>;
 
 	fn ss58_format() -> u16 {
 		sp_core::crypto::Ss58AddressFormat::from(
@@ -33,10 +32,4 @@ impl CliChain for Westend {
 		)
 		.into()
 	}
-
-	fn encode_message(
-		_message: encode_message::MessagePayload,
-	) -> anyhow::Result<Self::MessagePayload> {
-		Err(anyhow!("Sending messages from Westend is not yet supported."))
-	}
 }
diff --git a/bridges/relays/bin-substrate/src/chains/wococo.rs b/bridges/relays/bin-substrate/src/chains/wococo.rs
index 46dec2a3c90e31a852f2a6e7ad534540e074edfb..8edb132a83abc89ac18f5b13c637992a7c184e75 100644
--- a/bridges/relays/bin-substrate/src/chains/wococo.rs
+++ b/bridges/relays/bin-substrate/src/chains/wococo.rs
@@ -14,113 +14,48 @@
 // You should have received a copy of the GNU General Public License
 // along with Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
 
-use anyhow::anyhow;
-use bp_message_dispatch::{CallOrigin, MessagePayload};
+use bp_messages::LaneId;
 use bp_runtime::EncodedOrDecodedCall;
-use codec::Decode;
-use frame_support::weights::{DispatchClass, DispatchInfo, Pays};
+use relay_substrate_client::BalanceOf;
 use relay_wococo_client::Wococo;
 use sp_version::RuntimeVersion;
 
 use crate::cli::{
 	bridge,
-	encode_call::{self, Call, CliEncodeCall},
-	encode_message,
-	send_message::{self, DispatchFeePayment},
+	encode_message::{CliEncodeMessage, RawMessage},
 	CliChain,
 };
 
-impl CliEncodeCall for Wococo {
-	fn encode_call(call: &Call) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
-		Ok(match call {
-			Call::Raw { data } => EncodedOrDecodedCall::Encoded(data.0.clone()),
-			Call::Remark { remark_payload, .. } => relay_wococo_client::runtime::Call::System(
-				relay_wococo_client::runtime::SystemCall::remark(
-					remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(),
-				),
-			)
-			.into(),
-			Call::BridgeSendMessage { lane, payload, fee, bridge_instance_index } =>
-				match *bridge_instance_index {
-					bridge::WOCOCO_TO_ROCOCO_INDEX => {
-						let payload = Decode::decode(&mut &*payload.0)?;
-						relay_wococo_client::runtime::Call::BridgeRococoMessages(
-							relay_wococo_client::runtime::BridgeRococoMessagesCall::send_message(
-								lane.0, payload, fee.0,
-							),
-						)
-						.into()
-					},
-					_ => anyhow::bail!(
-						"Unsupported target bridge pallet with instance index: {}",
-						bridge_instance_index
+impl CliEncodeMessage for Wococo {
+	fn encode_send_message_call(
+		lane: LaneId,
+		payload: RawMessage,
+		fee: BalanceOf<Self>,
+		bridge_instance_index: u8,
+	) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
+		Ok(match bridge_instance_index {
+			bridge::WOCOCO_TO_ROCOCO_INDEX =>
+				relay_wococo_client::runtime::Call::BridgeRococoMessages(
+					relay_wococo_client::runtime::BridgeRococoMessagesCall::send_message(
+						lane, payload, fee,
 					),
-				},
-			_ => anyhow::bail!("The call is not supported"),
+				)
+				.into(),
+			_ => anyhow::bail!(
+				"Unsupported target bridge pallet with instance index: {}",
+				bridge_instance_index
+			),
 		})
 	}
-
-	fn get_dispatch_info(call: &EncodedOrDecodedCall<Self::Call>) -> anyhow::Result<DispatchInfo> {
-		match *call {
-			EncodedOrDecodedCall::Decoded(relay_wococo_client::runtime::Call::System(
-				relay_wococo_client::runtime::SystemCall::remark(_),
-			)) => Ok(DispatchInfo {
-				weight: crate::chains::rococo::SYSTEM_REMARK_CALL_WEIGHT,
-				class: DispatchClass::Normal,
-				pays_fee: Pays::Yes,
-			}),
-			_ => anyhow::bail!("Unsupported Wococo call: {:?}", call),
-		}
-	}
 }
 
 impl CliChain for Wococo {
 	const RUNTIME_VERSION: RuntimeVersion = bp_wococo::VERSION;
 
 	type KeyPair = sp_core::sr25519::Pair;
-	type MessagePayload = MessagePayload<
-		bp_wococo::AccountId,
-		bp_rococo::AccountPublic,
-		bp_rococo::Signature,
-		Vec<u8>,
-	>;
+	type MessagePayload = Vec<u8>;
 
 	fn ss58_format() -> u16 {
 		42
 	}
-
-	fn encode_message(
-		message: encode_message::MessagePayload,
-	) -> anyhow::Result<Self::MessagePayload> {
-		match message {
-			encode_message::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0)
-				.map_err(|e| anyhow!("Failed to decode Wococo's MessagePayload: {:?}", e)),
-			encode_message::MessagePayload::Call { mut call, mut sender, dispatch_weight } => {
-				type Source = Wococo;
-				type Target = relay_rococo_client::Rococo;
-
-				sender.enforce_chain::<Source>();
-				let spec_version = Target::RUNTIME_VERSION.spec_version;
-				let origin = CallOrigin::SourceAccount(sender.raw_id());
-				encode_call::preprocess_call::<Source, Target>(
-					&mut call,
-					bridge::WOCOCO_TO_ROCOCO_INDEX,
-				);
-				let call = Target::encode_call(&call)?;
-				let dispatch_weight = dispatch_weight.map(Ok).unwrap_or_else(|| {
-					Err(anyhow::format_err!(
-						"Please specify dispatch weight of the encoded Rococo call"
-					))
-				})?;
-
-				Ok(send_message::message_payload(
-					spec_version,
-					dispatch_weight,
-					origin,
-					&call,
-					DispatchFeePayment::AtSourceChain,
-				))
-			},
-		}
-	}
 }
diff --git a/bridges/relays/bin-substrate/src/cli/bridge.rs b/bridges/relays/bin-substrate/src/cli/bridge.rs
index 2eb836a84a753947b05a1fb0ad667c1788ad6388..c8476725fff2f1e8943ae4a55860106d6f6ac1e8 100644
--- a/bridges/relays/bin-substrate/src/cli/bridge.rs
+++ b/bridges/relays/bin-substrate/src/cli/bridge.rs
@@ -73,12 +73,9 @@ macro_rules! select_full_bridge {
 				// Send-message / Estimate-fee
 				#[allow(unused_imports)]
 				use bp_rialto::TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD;
-				// Send-message
-				#[allow(unused_imports)]
-				use millau_runtime::millau_to_rialto_account_ownership_digest as account_ownership_digest;
 
 				$generic
-			}
+			},
 			FullBridge::RialtoToMillau => {
 				type Source = relay_rialto_client::Rialto;
 				#[allow(dead_code)]
@@ -96,12 +93,8 @@ macro_rules! select_full_bridge {
 				#[allow(unused_imports)]
 				use bp_millau::TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD;
 
-				// Send-message
-				#[allow(unused_imports)]
-				use rialto_runtime::rialto_to_millau_account_ownership_digest as account_ownership_digest;
-
 				$generic
-			}
+			},
 			FullBridge::RococoToWococo => {
 				type Source = relay_rococo_client::Rococo;
 				#[allow(dead_code)]
@@ -118,12 +111,9 @@ macro_rules! select_full_bridge {
 				// Send-message / Estimate-fee
 				#[allow(unused_imports)]
 				use bp_wococo::TO_WOCOCO_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD;
-				// Send-message
-				#[allow(unused_imports)]
-				use relay_rococo_client::runtime::rococo_to_wococo_account_ownership_digest as account_ownership_digest;
 
 				$generic
-			}
+			},
 			FullBridge::WococoToRococo => {
 				type Source = relay_wococo_client::Wococo;
 				#[allow(dead_code)]
@@ -140,12 +130,9 @@ macro_rules! select_full_bridge {
 				// Send-message / Estimate-fee
 				#[allow(unused_imports)]
 				use bp_rococo::TO_ROCOCO_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD;
-				// Send-message
-				#[allow(unused_imports)]
-				use relay_wococo_client::runtime::wococo_to_rococo_account_ownership_digest as account_ownership_digest;
 
 				$generic
-			}
+			},
 			FullBridge::KusamaToPolkadot => {
 				type Source = relay_kusama_client::Kusama;
 				#[allow(dead_code)]
@@ -162,12 +149,9 @@ macro_rules! select_full_bridge {
 				// Send-message / Estimate-fee
 				#[allow(unused_imports)]
 				use bp_polkadot::TO_POLKADOT_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD;
-				// Send-message
-				#[allow(unused_imports)]
-				use relay_kusama_client::runtime::kusama_to_polkadot_account_ownership_digest as account_ownership_digest;
 
 				$generic
-			}
+			},
 			FullBridge::PolkadotToKusama => {
 				type Source = relay_polkadot_client::Polkadot;
 				#[allow(dead_code)]
@@ -184,12 +168,9 @@ macro_rules! select_full_bridge {
 				// Send-message / Estimate-fee
 				#[allow(unused_imports)]
 				use bp_kusama::TO_KUSAMA_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD;
-				// Send-message
-				#[allow(unused_imports)]
-				use relay_polkadot_client::runtime::polkadot_to_kusama_account_ownership_digest as account_ownership_digest;
 
 				$generic
-			}
+			},
 		}
 	};
 }
diff --git a/bridges/relays/bin-substrate/src/cli/derive_account.rs b/bridges/relays/bin-substrate/src/cli/derive_account.rs
deleted file mode 100644
index 5b809eb69f22237ebf0505861e2ffbbcf73eba9b..0000000000000000000000000000000000000000
--- a/bridges/relays/bin-substrate/src/cli/derive_account.rs
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2019-2021 Parity Technologies (UK) Ltd.
-// This file is part of Parity Bridges Common.
-
-// Parity Bridges Common 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.
-
-// Parity Bridges Common 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 Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
-
-use crate::{
-	cli::{bridge::FullBridge, AccountId},
-	select_full_bridge,
-};
-use relay_substrate_client::Chain;
-use structopt::StructOpt;
-use strum::VariantNames;
-
-/// Given a source chain `AccountId`, derive the corresponding `AccountId` for the target chain.
-///
-/// The (derived) target chain `AccountId` is going to be used as dispatch origin of the call
-/// that has been sent over the bridge.
-/// This account can also be used to receive target-chain funds (or other form of ownership),
-/// since messages sent over the bridge will be able to spend these.
-#[derive(StructOpt)]
-pub struct DeriveAccount {
-	/// A bridge instance to initialize.
-	#[structopt(possible_values = FullBridge::VARIANTS, case_insensitive = true)]
-	bridge: FullBridge,
-	/// Source-chain address to derive Target-chain address from.
-	account: AccountId,
-}
-
-impl DeriveAccount {
-	/// Parse CLI arguments and derive account.
-	///
-	/// Returns both the Source account in correct SS58 format and the derived account.
-	fn derive_account(&self) -> (AccountId, AccountId) {
-		select_full_bridge!(self.bridge, {
-			let mut account = self.account.clone();
-			account.enforce_chain::<Source>();
-			let acc = bp_runtime::SourceAccount::Account(account.raw_id());
-			let id = derive_account(acc);
-			let derived_account = AccountId::from_raw::<Target>(id);
-			(account, derived_account)
-		})
-	}
-
-	/// Run the command.
-	pub async fn run(self) -> anyhow::Result<()> {
-		select_full_bridge!(self.bridge, {
-			let (account, derived_account) = self.derive_account();
-			println!("Source address:\n{} ({})", account, Source::NAME);
-			println!("->Corresponding (derived) address:\n{} ({})", derived_account, Target::NAME,);
-
-			Ok(())
-		})
-	}
-}
-
-#[cfg(test)]
-mod tests {
-	use super::*;
-
-	fn derive_account_cli(bridge: &str, account: &str) -> (AccountId, AccountId) {
-		DeriveAccount::from_iter(vec!["derive-account", bridge, account]).derive_account()
-	}
-
-	#[test]
-	fn should_derive_accounts_correctly() {
-		// given
-		let rialto = "5sauUXUfPjmwxSgmb3tZ5d6yx24eZX4wWJ2JtVUBaQqFbvEU";
-		let millau = "752paRyW1EGfq9YLTSSqcSJ5hqnBDidBmaftGhBo8fy6ypW9";
-
-		// when
-		let (rialto_parsed, rialto_derived) = derive_account_cli("rialto-to-millau", rialto);
-		let (millau_parsed, millau_derived) = derive_account_cli("millau-to-rialto", millau);
-		let (millau2_parsed, millau2_derived) = derive_account_cli("millau-to-rialto", rialto);
-
-		// then
-		assert_eq!(format!("{}", rialto_parsed), rialto);
-		assert_eq!(format!("{}", millau_parsed), millau);
-		assert_eq!(format!("{}", millau2_parsed), millau);
-
-		assert_eq!(
-			format!("{}", rialto_derived),
-			"74GNQjmkcfstRftSQPJgMREchqHM56EvAUXRc266cZ1NYVW5"
-		);
-		assert_eq!(
-			format!("{}", millau_derived),
-			"5rERgaT1Z8nM3et2epA5i1VtEBfp5wkhwHtVE8HK7BRbjAH2"
-		);
-		assert_eq!(millau_derived, millau2_derived);
-	}
-}
diff --git a/bridges/relays/bin-substrate/src/cli/encode_call.rs b/bridges/relays/bin-substrate/src/cli/encode_call.rs
deleted file mode 100644
index e288e2c13d6cd06ca84c790828f08e47bb1b7c87..0000000000000000000000000000000000000000
--- a/bridges/relays/bin-substrate/src/cli/encode_call.rs
+++ /dev/null
@@ -1,354 +0,0 @@
-// Copyright 2019-2021 Parity Technologies (UK) Ltd.
-// This file is part of Parity Bridges Common.
-
-// Parity Bridges Common 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.
-
-// Parity Bridges Common 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 Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
-
-use crate::{
-	cli::{
-		bridge::FullBridge, AccountId, Balance, CliChain, ExplicitOrMaximal, HexBytes, HexLaneId,
-	},
-	select_full_bridge,
-};
-use bp_runtime::EncodedOrDecodedCall;
-use frame_support::weights::DispatchInfo;
-use relay_substrate_client::Chain;
-use structopt::StructOpt;
-use strum::VariantNames;
-
-/// Encode source chain runtime call.
-#[derive(StructOpt, Debug)]
-pub struct EncodeCall {
-	/// A bridge instance to encode call for.
-	#[structopt(possible_values = FullBridge::VARIANTS, case_insensitive = true)]
-	bridge: FullBridge,
-	#[structopt(flatten)]
-	call: Call,
-}
-
-/// All possible messages that may be delivered to generic Substrate chain.
-///
-/// Note this enum may be used in the context of both Source (as part of `encode-call`)
-/// and Target chain (as part of `encode-message/send-message`).
-#[derive(StructOpt, Debug, PartialEq, Eq)]
-pub enum Call {
-	/// Raw bytes for the message
-	Raw {
-		/// Raw, SCALE-encoded message
-		data: HexBytes,
-	},
-	/// Make an on-chain remark (comment).
-	Remark {
-		/// Explicit remark payload.
-		#[structopt(long, conflicts_with("remark-size"))]
-		remark_payload: Option<HexBytes>,
-		/// Remark size. If not passed, small UTF8-encoded string is generated by relay as remark.
-		#[structopt(long, conflicts_with("remark-payload"))]
-		remark_size: Option<ExplicitOrMaximal<usize>>,
-	},
-	/// Transfer the specified `amount` of native tokens to a particular `recipient`.
-	Transfer {
-		/// Address of an account to receive the transfer.
-		#[structopt(long)]
-		recipient: AccountId,
-		/// Amount of target tokens to send in target chain base currency units.
-		#[structopt(long)]
-		amount: Balance,
-	},
-	/// A call to the specific Bridge Messages pallet to queue message to be sent over a bridge.
-	BridgeSendMessage {
-		/// An index of the bridge instance which represents the expected target chain.
-		#[structopt(skip = 255)]
-		bridge_instance_index: u8,
-		/// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`.
-		#[structopt(long, default_value = "00000000")]
-		lane: HexLaneId,
-		/// Raw SCALE-encoded Message Payload to submit to the messages pallet.
-		///
-		/// This can be obtained by encoding call for the target chain.
-		#[structopt(long)]
-		payload: HexBytes,
-		/// Declared delivery and dispatch fee in base source-chain currency units.
-		#[structopt(long)]
-		fee: Balance,
-	},
-}
-
-pub trait CliEncodeCall: Chain {
-	/// Encode a CLI call.
-	fn encode_call(call: &Call) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>>;
-
-	/// Get dispatch info for the call.
-	fn get_dispatch_info(call: &EncodedOrDecodedCall<Self::Call>) -> anyhow::Result<DispatchInfo>;
-}
-
-impl EncodeCall {
-	fn encode(&mut self) -> anyhow::Result<HexBytes> {
-		select_full_bridge!(self.bridge, {
-			preprocess_call::<Source, Target>(&mut self.call, self.bridge.bridge_instance_index());
-			let call = Source::encode_call(&self.call)?;
-
-			let encoded = HexBytes::encode(&call);
-
-			log::info!(target: "bridge", "Generated {} call: {:#?}", Source::NAME, call);
-			log::info!(target: "bridge", "Weight of {} call: {}", Source::NAME, Source::get_dispatch_info(&call)
-				.map(|dispatch_info| format!("{}", dispatch_info.weight))
-				.unwrap_or_else(|_| "<unknown>".to_string())
-			);
-			log::info!(target: "bridge", "Encoded {} call: {:?}", Source::NAME, encoded);
-
-			Ok(encoded)
-		})
-	}
-
-	/// Run the command.
-	pub async fn run(mut self) -> anyhow::Result<()> {
-		println!("{:?}", self.encode()?);
-		Ok(())
-	}
-}
-
-/// Prepare the call to be passed to [`CliEncodeCall::encode_call`].
-///
-/// This function will fill in all optional and missing pieces and will make sure that
-/// values are converted to bridge-specific ones.
-///
-/// Most importantly, the method will fill-in [`bridge_instance_index`] parameter for
-/// target-chain specific calls.
-pub(crate) fn preprocess_call<Source: CliEncodeCall + CliChain, Target: CliEncodeCall>(
-	call: &mut Call,
-	bridge_instance: u8,
-) {
-	match *call {
-		Call::Raw { .. } => {},
-		Call::Remark { ref remark_size, ref mut remark_payload } =>
-			if remark_payload.is_none() {
-				*remark_payload = Some(HexBytes(generate_remark_payload(
-					remark_size,
-					compute_maximal_message_arguments_size(
-						Source::max_extrinsic_size(),
-						Target::max_extrinsic_size(),
-					),
-				)));
-			},
-		Call::Transfer { ref mut recipient, .. } => {
-			recipient.enforce_chain::<Source>();
-		},
-		Call::BridgeSendMessage { ref mut bridge_instance_index, .. } => {
-			*bridge_instance_index = bridge_instance;
-		},
-	};
-}
-
-fn generate_remark_payload(
-	remark_size: &Option<ExplicitOrMaximal<usize>>,
-	maximal_allowed_size: u32,
-) -> Vec<u8> {
-	match remark_size {
-		Some(ExplicitOrMaximal::Explicit(remark_size)) => vec![0; *remark_size],
-		Some(ExplicitOrMaximal::Maximal) => vec![0; maximal_allowed_size as _],
-		None => format!(
-			"Unix time: {}",
-			std::time::SystemTime::now()
-				.duration_since(std::time::SystemTime::UNIX_EPOCH)
-				.unwrap_or_default()
-				.as_secs(),
-		)
-		.as_bytes()
-		.to_vec(),
-	}
-}
-
-pub(crate) fn compute_maximal_message_arguments_size(
-	maximal_source_extrinsic_size: u32,
-	maximal_target_extrinsic_size: u32,
-) -> u32 {
-	// assume that both signed extensions and other arguments fit 1KB
-	let service_tx_bytes_on_source_chain = 1024;
-	let maximal_source_extrinsic_size =
-		maximal_source_extrinsic_size - service_tx_bytes_on_source_chain;
-	let maximal_call_size = bridge_runtime_common::messages::target::maximal_incoming_message_size(
-		maximal_target_extrinsic_size,
-	);
-	let maximal_call_size = if maximal_call_size > maximal_source_extrinsic_size {
-		maximal_source_extrinsic_size
-	} else {
-		maximal_call_size
-	};
-
-	// bytes in Call encoding that are used to encode everything except arguments
-	let service_bytes = 1 + 1 + 4;
-	maximal_call_size - service_bytes
-}
-
-#[cfg(test)]
-mod tests {
-	use super::*;
-	use crate::cli::send_message::SendMessage;
-
-	#[test]
-	fn should_encode_transfer_call() {
-		// given
-		let mut encode_call = EncodeCall::from_iter(vec![
-			"encode-call",
-			"rialto-to-millau",
-			"transfer",
-			"--amount",
-			"12345",
-			"--recipient",
-			"5sauUXUfPjmwxSgmb3tZ5d6yx24eZX4wWJ2JtVUBaQqFbvEU",
-		]);
-
-		// when
-		let hex = encode_call.encode().unwrap();
-
-		// then
-		assert_eq!(
-			format!("{:?}", hex),
-			"0x040000d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27de5c0"
-		);
-	}
-
-	#[test]
-	fn should_encode_remark_with_default_payload() {
-		// given
-		let mut encode_call =
-			EncodeCall::from_iter(vec!["encode-call", "rialto-to-millau", "remark"]);
-
-		// when
-		let hex = encode_call.encode().unwrap();
-
-		// then
-		assert!(format!("{:?}", hex).starts_with("0x000154556e69782074696d653a"));
-	}
-
-	#[test]
-	fn should_encode_remark_with_explicit_payload() {
-		// given
-		let mut encode_call = EncodeCall::from_iter(vec![
-			"encode-call",
-			"rialto-to-millau",
-			"remark",
-			"--remark-payload",
-			"1234",
-		]);
-
-		// when
-		let hex = encode_call.encode().unwrap();
-
-		// then
-		assert_eq!(format!("{:?}", hex), "0x0001081234");
-	}
-
-	#[test]
-	fn should_encode_remark_with_size() {
-		// given
-		let mut encode_call = EncodeCall::from_iter(vec![
-			"encode-call",
-			"rialto-to-millau",
-			"remark",
-			"--remark-size",
-			"12",
-		]);
-
-		// when
-		let hex = encode_call.encode().unwrap();
-
-		// then
-		assert_eq!(format!("{:?}", hex), "0x000130000000000000000000000000");
-	}
-
-	#[test]
-	fn should_disallow_both_payload_and_size() {
-		// when
-		let err = EncodeCall::from_iter_safe(vec![
-			"encode-call",
-			"rialto-to-millau",
-			"remark",
-			"--remark-payload",
-			"1234",
-			"--remark-size",
-			"12",
-		])
-		.unwrap_err();
-
-		// then
-		assert_eq!(err.kind, structopt::clap::ErrorKind::ArgumentConflict);
-
-		let info = err.info.unwrap();
-		assert!(
-			info.contains(&"remark-payload".to_string()) |
-				info.contains(&"remark-size".to_string())
-		)
-	}
-
-	#[test]
-	fn should_encode_raw_call() {
-		// given
-		let mut encode_call = EncodeCall::from_iter(vec![
-			"encode-call",
-			"rialto-to-millau",
-			"raw",
-			"040000d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27de5c0",
-		]);
-
-		// when
-		let hex = encode_call.encode().unwrap();
-
-		// then
-		assert_eq!(
-			format!("{:?}", hex),
-			"0x040000d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27de5c0"
-		);
-	}
-
-	#[async_std::test]
-	async fn should_encode_bridge_send_message_call() {
-		// given
-		let encode_message = SendMessage::from_iter(vec![
-			"send-message",
-			"millau-to-rialto",
-			"--source-port",
-			"10946",
-			"--source-signer",
-			"//Alice",
-			"--target-signer",
-			"//Alice",
-			"--origin",
-			"Target",
-			"remark",
-		])
-		.encode_payload()
-		.await
-		.unwrap();
-
-		let mut encode_call = EncodeCall::from_iter(vec![
-			"encode-call",
-			"rialto-to-millau",
-			"bridge-send-message",
-			"--fee",
-			"12345",
-			"--payload",
-			format!("{:}", &HexBytes::encode(&encode_message)).as_str(),
-		]);
-
-		// when
-		let call_hex = encode_call.encode().unwrap();
-
-		// then
-		assert!(format!("{:?}", call_hex).starts_with(
-			"0x0f030000000001000000000000000000000001d43593c715fdd31c61141abd04a99fd6822c8558854cc\
-			de39a5684e7a56da27d01d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01"
-		))
-	}
-}
diff --git a/bridges/relays/bin-substrate/src/cli/encode_message.rs b/bridges/relays/bin-substrate/src/cli/encode_message.rs
index 677fc29ef15313c3f50bb1b1d3b51b5ba0a9f278..e74d6da766d521c4db013d7b34b6df383fa02244 100644
--- a/bridges/relays/bin-substrate/src/cli/encode_message.rs
+++ b/bridges/relays/bin-substrate/src/cli/encode_message.rs
@@ -14,107 +14,80 @@
 // You should have received a copy of the GNU General Public License
 // along with Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
 
-use crate::{
-	cli::{bridge::FullBridge, AccountId, CliChain, HexBytes},
-	select_full_bridge,
-};
-use frame_support::weights::Weight;
+use crate::cli::{ExplicitOrMaximal, HexBytes};
+use bp_messages::LaneId;
+use bp_runtime::EncodedOrDecodedCall;
+use relay_substrate_client::Chain;
 use structopt::StructOpt;
-use strum::VariantNames;
 
-/// Generic message payload.
+/// All possible messages that may be delivered to generic Substrate chain.
+///
+/// Note this enum may be used in the context of both Source (as part of `encode-call`)
+/// and Target chain (as part of `encode-message/send-message`).
 #[derive(StructOpt, Debug, PartialEq, Eq)]
-pub enum MessagePayload {
-	/// Raw, SCALE-encoded `MessagePayload`.
+pub enum Message {
+	/// Raw bytes for the message.
 	Raw {
-		/// Hex-encoded SCALE data.
+		/// Raw message bytes.
 		data: HexBytes,
 	},
-	/// Construct message to send over the bridge.
-	Call {
-		/// Message details.
-		#[structopt(flatten)]
-		call: crate::cli::encode_call::Call,
-		/// SS58 encoded Source account that will send the payload.
-		#[structopt(long)]
-		sender: AccountId,
-		/// Weight of the call.
-		///
-		/// It must be specified if the chain runtime is not bundled with the relay, or if
-		/// you want to override bundled weight.
-		#[structopt(long)]
-		dispatch_weight: Option<Weight>,
+	/// Message with given size.
+	Sized {
+		/// Sized of the message.
+		size: ExplicitOrMaximal<u32>,
 	},
 }
 
-/// A `MessagePayload` to encode.
-#[derive(StructOpt)]
-pub struct EncodeMessage {
-	/// A bridge instance to initialize.
-	#[structopt(possible_values = FullBridge::VARIANTS, case_insensitive = true)]
-	bridge: FullBridge,
-	#[structopt(flatten)]
-	payload: MessagePayload,
-}
-
-impl EncodeMessage {
-	/// Run the command.
-	pub fn encode(self) -> anyhow::Result<HexBytes> {
-		select_full_bridge!(self.bridge, {
-			let payload =
-				Source::encode_message(self.payload).map_err(|e| anyhow::format_err!("{}", e))?;
-			Ok(HexBytes::encode(&payload))
-		})
-	}
+/// Raw, SCALE-encoded message payload used in expected deployment.
+pub type RawMessage = Vec<u8>;
 
-	/// Run the command.
-	pub async fn run(self) -> anyhow::Result<()> {
-		let payload = self.encode()?;
-		println!("{:?}", payload);
-		Ok(())
-	}
+pub trait CliEncodeMessage: Chain {
+	/// Encode a send message call.
+	fn encode_send_message_call(
+		lane: LaneId,
+		message: RawMessage,
+		fee: Self::Balance,
+		bridge_instance_index: u8,
+	) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>>;
 }
 
-#[cfg(test)]
-mod tests {
-	use super::*;
-	use sp_core::crypto::Ss58Codec;
-
-	#[test]
-	fn should_encode_raw_message() {
-		// given
-		let msg = "01000000e88514000000000002d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d003c040130000000000000000000000000";
-		let encode_message =
-			EncodeMessage::from_iter(vec!["encode-message", "rialto-to-millau", "raw", msg]);
-
-		// when
-		let hex = encode_message.encode().unwrap();
-
-		// then
-		assert_eq!(format!("{:?}", hex), format!("0x{}", msg));
-	}
-
-	#[test]
-	fn should_encode_remark_with_size() {
-		// given
-		let sender = sp_keyring::AccountKeyring::Alice.to_account_id().to_ss58check();
-		let encode_message = EncodeMessage::from_iter(vec![
-			"encode-message",
-			"rialto-to-millau",
-			"call",
-			"--sender",
-			&sender,
-			"--dispatch-weight",
-			"42",
-			"remark",
-			"--remark-size",
-			"12",
-		]);
+/// Encode message payload passed through CLI flags.
+pub(crate) fn encode_message<Source: Chain, Target: Chain>(
+	message: &Message,
+) -> anyhow::Result<RawMessage> {
+	Ok(match message {
+		Message::Raw { ref data } => data.0.clone(),
+		Message::Sized { ref size } => match *size {
+			ExplicitOrMaximal::Explicit(size) => vec![42; size as usize],
+			ExplicitOrMaximal::Maximal => {
+				let maximal_size = compute_maximal_message_size(
+					Source::max_extrinsic_size(),
+					Target::max_extrinsic_size(),
+				);
+				vec![42; maximal_size as usize]
+			},
+		},
+	})
+}
 
-		// when
-		let hex = encode_message.encode().unwrap();
+/// Compute maximal message size, given max extrinsic size at source and target chains.
+pub(crate) fn compute_maximal_message_size(
+	maximal_source_extrinsic_size: u32,
+	maximal_target_extrinsic_size: u32,
+) -> u32 {
+	// assume that both signed extensions and other arguments fit 1KB
+	let service_tx_bytes_on_source_chain = 1024;
+	let maximal_source_extrinsic_size =
+		maximal_source_extrinsic_size - service_tx_bytes_on_source_chain;
+	let maximal_message_size =
+		bridge_runtime_common::messages::target::maximal_incoming_message_size(
+			maximal_target_extrinsic_size,
+		);
+	let maximal_message_size = if maximal_message_size > maximal_source_extrinsic_size {
+		maximal_source_extrinsic_size
+	} else {
+		maximal_message_size
+	};
 
-		// then
-		assert_eq!(format!("{:?}", hex), "0x010000002a0000000000000002d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d003c000130000000000000000000000000");
-	}
+	maximal_message_size
 }
diff --git a/bridges/relays/bin-substrate/src/cli/estimate_fee.rs b/bridges/relays/bin-substrate/src/cli/estimate_fee.rs
index bab625314e824547f1ed839604d1543f3b43d3dc..bf13996ec52befc3701c7f08328f126689609d29 100644
--- a/bridges/relays/bin-substrate/src/cli/estimate_fee.rs
+++ b/bridges/relays/bin-substrate/src/cli/estimate_fee.rs
@@ -17,7 +17,7 @@
 use crate::{
 	cli::{
 		bridge::FullBridge, relay_headers_and_messages::CONVERSION_RATE_ALLOWED_DIFFERENCE_RATIO,
-		Balance, CliChain, HexBytes, HexLaneId, SourceConnectionParams,
+		Balance, HexBytes, HexLaneId, SourceConnectionParams,
 	},
 	select_full_bridge,
 };
@@ -48,7 +48,7 @@ pub struct EstimateFee {
 	conversion_rate_override: Option<ConversionRateOverride>,
 	/// Payload to send over the bridge.
 	#[structopt(flatten)]
-	payload: crate::cli::encode_message::MessagePayload,
+	payload: crate::cli::encode_message::Message,
 }
 
 /// A way to override conversion rate between bridge tokens.
@@ -82,8 +82,8 @@ impl EstimateFee {
 		select_full_bridge!(bridge, {
 			let source_client = source.to_client::<Source>().await?;
 			let lane = lane.into();
-			let payload =
-				Source::encode_message(payload).map_err(|e| anyhow::format_err!("{:?}", e))?;
+			let payload = crate::cli::encode_message::encode_message::<Source, Target>(&payload)
+				.map_err(|e| anyhow::format_err!("{:?}", e))?;
 
 			let fee = estimate_message_delivery_and_dispatch_fee::<Source, Target, _>(
 				&source_client,
@@ -219,14 +219,10 @@ async fn do_estimate_message_delivery_and_dispatch_fee<Source: Chain, P: Encode>
 #[cfg(test)]
 mod tests {
 	use super::*;
-	use crate::cli::{encode_call, RuntimeVersionType, SourceRuntimeVersionParams};
-	use sp_core::crypto::Ss58Codec;
+	use crate::cli::{RuntimeVersionType, SourceRuntimeVersionParams};
 
 	#[test]
 	fn should_parse_cli_options() {
-		// given
-		let alice = sp_keyring::AccountKeyring::Alice.to_account_id().to_ss58check();
-
 		// when
 		let res = EstimateFee::from_iter(vec![
 			"estimate_fee",
@@ -235,13 +231,7 @@ mod tests {
 			"1234",
 			"--conversion-rate-override",
 			"42.5",
-			"call",
-			"--sender",
-			&alice,
-			"--dispatch-weight",
-			"42",
-			"remark",
-			"--remark-payload",
+			"raw",
 			"1234",
 		]);
 
@@ -262,13 +252,8 @@ mod tests {
 						source_transaction_version: None,
 					}
 				},
-				payload: crate::cli::encode_message::MessagePayload::Call {
-					sender: alice.parse().unwrap(),
-					call: encode_call::Call::Remark {
-						remark_payload: Some(HexBytes(vec![0x12, 0x34])),
-						remark_size: None,
-					},
-					dispatch_weight: Some(42),
+				payload: crate::cli::encode_message::Message::Raw {
+					data: HexBytes(vec![0x12, 0x34])
 				}
 			}
 		);
diff --git a/bridges/relays/bin-substrate/src/cli/mod.rs b/bridges/relays/bin-substrate/src/cli/mod.rs
index df57537f588ec6788a2d1cb1689fd6d096935af7..fddae4ee7abb5419eb897fff298547071d279a4b 100644
--- a/bridges/relays/bin-substrate/src/cli/mod.rs
+++ b/bridges/relays/bin-substrate/src/cli/mod.rs
@@ -20,19 +20,16 @@ use std::convert::TryInto;
 
 use codec::{Decode, Encode};
 use relay_substrate_client::ChainRuntimeVersion;
-use sp_runtime::app_crypto::Ss58Codec;
 use structopt::{clap::arg_enum, StructOpt};
 use strum::{EnumString, EnumVariantNames};
 
 use bp_messages::LaneId;
 
 pub(crate) mod bridge;
-pub(crate) mod encode_call;
 pub(crate) mod encode_message;
 pub(crate) mod estimate_fee;
 pub(crate) mod send_message;
 
-mod derive_account;
 mod init_bridge;
 mod register_parachain;
 mod reinit_bridge;
@@ -40,7 +37,6 @@ mod relay_headers;
 mod relay_headers_and_messages;
 mod relay_messages;
 mod resubmit_transactions;
-mod swap_tokens;
 
 /// Parse relay CLI args.
 pub fn parse_args() -> Command {
@@ -83,25 +79,10 @@ pub enum Command {
 	/// The message is being sent to the source chain, delivered to the target chain and dispatched
 	/// there.
 	SendMessage(send_message::SendMessage),
-	/// Generate SCALE-encoded `Call` for choosen network.
-	///
-	/// The call can be used either as message payload or can be wrapped into a transaction
-	/// and executed on the chain directly.
-	EncodeCall(encode_call::EncodeCall),
-	/// Generate SCALE-encoded `MessagePayload` object that can be sent over selected bridge.
-	///
-	/// The `MessagePayload` can be then fed to `Messages::send_message` function and sent over
-	/// the bridge.
-	EncodeMessage(encode_message::EncodeMessage),
 	/// Estimate Delivery and Dispatch Fee required for message submission to messages pallet.
 	EstimateFee(estimate_fee::EstimateFee),
-	/// Given a source chain `AccountId`, derive the corresponding `AccountId` for the target
-	/// chain.
-	DeriveAccount(derive_account::DeriveAccount),
 	/// Resubmit transactions with increased tip if they are stalled.
 	ResubmitTransactions(resubmit_transactions::ResubmitTransactions),
-	/// Swap tokens using token-swap bridge.
-	SwapTokens(swap_tokens::SwapTokens),
 	/// Register parachain.
 	RegisterParachain(register_parachain::RegisterParachain),
 }
@@ -134,12 +115,8 @@ impl Command {
 			Self::InitBridge(arg) => arg.run().await?,
 			Self::ReinitBridge(arg) => arg.run().await?,
 			Self::SendMessage(arg) => arg.run().await?,
-			Self::EncodeCall(arg) => arg.run().await?,
-			Self::EncodeMessage(arg) => arg.run().await?,
 			Self::EstimateFee(arg) => arg.run().await?,
-			Self::DeriveAccount(arg) => arg.run().await?,
 			Self::ResubmitTransactions(arg) => arg.run().await?,
-			Self::SwapTokens(arg) => arg.run().await?,
 			Self::RegisterParachain(arg) => arg.run().await?,
 		}
 		Ok(())
@@ -184,66 +161,7 @@ impl Balance {
 	}
 }
 
-/// Generic account id with custom parser.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct AccountId {
-	account: sp_runtime::AccountId32,
-	ss58_format: sp_core::crypto::Ss58AddressFormat,
-}
-
-impl std::fmt::Display for AccountId {
-	fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
-		write!(fmt, "{}", self.account.to_ss58check_with_version(self.ss58_format))
-	}
-}
-
-impl std::str::FromStr for AccountId {
-	type Err = String;
-
-	fn from_str(s: &str) -> Result<Self, Self::Err> {
-		let (account, ss58_format) = sp_runtime::AccountId32::from_ss58check_with_version(s)
-			.map_err(|err| format!("Unable to decode SS58 address: {:?}", err))?;
-		Ok(Self { account, ss58_format })
-	}
-}
-
-const SS58_FORMAT_PROOF: &str = "u16 -> Ss58Format is infallible; qed";
-
-impl AccountId {
-	/// Create new SS58-formatted address from raw account id.
-	pub fn from_raw<T: CliChain>(account: sp_runtime::AccountId32) -> Self {
-		Self { account, ss58_format: T::ss58_format().try_into().expect(SS58_FORMAT_PROOF) }
-	}
-
-	/// Enforces formatting account to be for given [`CliChain`] type.
-	///
-	/// This will change the `ss58format` of the account to match the requested one.
-	/// Note that a warning will be produced in case the current format does not match
-	/// the requested one, but the conversion always succeeds.
-	pub fn enforce_chain<T: CliChain>(&mut self) {
-		let original = self.clone();
-		self.ss58_format = T::ss58_format().try_into().expect(SS58_FORMAT_PROOF);
-		log::debug!("{} SS58 format: {} (RAW: {})", self, self.ss58_format, self.account);
-		if original.ss58_format != self.ss58_format {
-			log::warn!(
-				target: "bridge",
-				"Address {} does not seem to match {}'s SS58 format (got: {}, expected: {}).\nConverted to: {}",
-				original,
-				T::NAME,
-				original.ss58_format,
-				self.ss58_format,
-				self,
-			)
-		}
-	}
-
-	/// Returns the raw (no SS58-prefixed) account id.
-	pub fn raw_id(&self) -> sp_runtime::AccountId32 {
-		self.account.clone()
-	}
-}
-
-/// Bridge-supported network definition.
+// Bridge-supported network definition.
 ///
 /// Used to abstract away CLI commands.
 pub trait CliChain: relay_substrate_client::Chain {
@@ -262,11 +180,6 @@ pub trait CliChain: relay_substrate_client::Chain {
 
 	/// Numeric value of SS58 format.
 	fn ss58_format() -> u16;
-
-	/// Construct message payload to be sent over the bridge.
-	fn encode_message(
-		message: crate::cli::encode_message::MessagePayload,
-	) -> anyhow::Result<Self::MessagePayload>;
 }
 
 /// Lane id.
@@ -623,29 +536,8 @@ declare_chain_options!(Parachain, parachain);
 
 #[cfg(test)]
 mod tests {
-	use std::str::FromStr;
-
-	use sp_core::Pair;
-
 	use super::*;
-
-	#[test]
-	fn should_format_addresses_with_ss58_format() {
-		// given
-		let rialto1 = "5sauUXUfPjmwxSgmb3tZ5d6yx24eZX4wWJ2JtVUBaQqFbvEU";
-		let rialto2 = "5rERgaT1Z8nM3et2epA5i1VtEBfp5wkhwHtVE8HK7BRbjAH2";
-		let millau1 = "752paRyW1EGfq9YLTSSqcSJ5hqnBDidBmaftGhBo8fy6ypW9";
-		let millau2 = "74GNQjmkcfstRftSQPJgMREchqHM56EvAUXRc266cZ1NYVW5";
-
-		let expected = vec![rialto1, rialto2, millau1, millau2];
-
-		// when
-		let parsed = expected.iter().map(|s| AccountId::from_str(s).unwrap()).collect::<Vec<_>>();
-
-		let actual = parsed.iter().map(|a| format!("{}", a)).collect::<Vec<_>>();
-
-		assert_eq!(actual, expected)
-	}
+	use sp_core::Pair;
 
 	#[test]
 	fn hex_bytes_display_matches_from_str_for_clap() {
diff --git a/bridges/relays/bin-substrate/src/cli/register_parachain.rs b/bridges/relays/bin-substrate/src/cli/register_parachain.rs
index c761a5dd1a6039f4ee61dc6edee5bfa01753aa0d..79515b31dcfa9b40aafef709790dbe9c1f4546de 100644
--- a/bridges/relays/bin-substrate/src/cli/register_parachain.rs
+++ b/bridges/relays/bin-substrate/src/cli/register_parachain.rs
@@ -15,8 +15,7 @@
 // along with Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
 
 use crate::cli::{
-	swap_tokens::wait_until_transaction_is_finalized, Balance, ParachainConnectionParams,
-	RelaychainConnectionParams, RelaychainSigningParams,
+	Balance, ParachainConnectionParams, RelaychainConnectionParams, RelaychainSigningParams,
 };
 
 use codec::Encode;
@@ -30,7 +29,8 @@ use polkadot_runtime_common::{
 };
 use polkadot_runtime_parachains::paras::ParaLifecycle;
 use relay_substrate_client::{
-	AccountIdOf, CallOf, Chain, Client, SignParam, TransactionSignScheme, UnsignedTransaction,
+	AccountIdOf, CallOf, Chain, Client, HashOf, SignParam, Subscription, TransactionSignScheme,
+	TransactionStatusOf, UnsignedTransaction,
 };
 use rialto_runtime::SudoCall;
 use sp_core::{
@@ -270,6 +270,46 @@ impl RegisterParachain {
 	}
 }
 
+/// Wait until transaction is included into finalized block.
+///
+/// Returns the hash of the finalized block with transaction.
+pub(crate) async fn wait_until_transaction_is_finalized<C: Chain>(
+	subscription: Subscription<TransactionStatusOf<C>>,
+) -> anyhow::Result<HashOf<C>> {
+	loop {
+		let transaction_status = subscription.next().await?;
+		match transaction_status {
+			Some(TransactionStatusOf::<C>::FinalityTimeout(_)) |
+			Some(TransactionStatusOf::<C>::Usurped(_)) |
+			Some(TransactionStatusOf::<C>::Dropped) |
+			Some(TransactionStatusOf::<C>::Invalid) |
+			None =>
+				return Err(anyhow::format_err!(
+					"We've been waiting for finalization of {} transaction, but it now has the {:?} status",
+					C::NAME,
+					transaction_status,
+				)),
+			Some(TransactionStatusOf::<C>::Finalized(block_hash)) => {
+				log::trace!(
+					target: "bridge",
+					"{} transaction has been finalized at block {}",
+					C::NAME,
+					block_hash,
+				);
+				return Ok(block_hash)
+			},
+			_ => {
+				log::trace!(
+					target: "bridge",
+					"Received intermediate status of {} transaction: {:?}",
+					C::NAME,
+					transaction_status,
+				);
+			},
+		}
+	}
+}
+
 /// Wait until parachain state is changed.
 async fn wait_para_state<Relaychain: Chain>(
 	relay_client: &Client<Relaychain>,
diff --git a/bridges/relays/bin-substrate/src/cli/reinit_bridge.rs b/bridges/relays/bin-substrate/src/cli/reinit_bridge.rs
index dc902055d20bd366709af9a49c36e367511da41f..79869ad03151bf184d60c39276e1bb1767f66a82 100644
--- a/bridges/relays/bin-substrate/src/cli/reinit_bridge.rs
+++ b/bridges/relays/bin-substrate/src/cli/reinit_bridge.rs
@@ -20,7 +20,7 @@ use crate::{
 		polkadot_headers_to_kusama::PolkadotFinalityToKusama,
 	},
 	cli::{
-		swap_tokens::wait_until_transaction_is_finalized, SourceConnectionParams,
+		register_parachain::wait_until_transaction_is_finalized, SourceConnectionParams,
 		TargetConnectionParams, TargetSigningParams,
 	},
 };
diff --git a/bridges/relays/bin-substrate/src/cli/send_message.rs b/bridges/relays/bin-substrate/src/cli/send_message.rs
index ddb1ff59b5d087f4e1a7577bd17082932dbf81f3..53187009d3e21296a6c873ca68bb1ee0c56e44c6 100644
--- a/bridges/relays/bin-substrate/src/cli/send_message.rs
+++ b/bridges/relays/bin-substrate/src/cli/send_message.rs
@@ -16,18 +16,14 @@
 
 use crate::cli::{
 	bridge::FullBridge,
-	encode_call::{self, CliEncodeCall},
+	encode_message::{self, CliEncodeMessage},
 	estimate_fee::{estimate_message_delivery_and_dispatch_fee, ConversionRateOverride},
-	Balance, ExplicitOrMaximal, HexBytes, HexLaneId, Origins, SourceConnectionParams,
-	SourceSigningParams, TargetConnectionParams, TargetSigningParams,
+	Balance, HexBytes, HexLaneId, SourceConnectionParams, SourceSigningParams,
 };
-use bp_message_dispatch::{CallOrigin, MessagePayload};
-use bp_runtime::Chain as _;
 use codec::Encode;
-use frame_support::weights::Weight;
 use relay_substrate_client::{Chain, SignParam, TransactionSignScheme, UnsignedTransaction};
 use sp_core::{Bytes, Pair};
-use sp_runtime::{traits::IdentifyAccount, AccountId32, MultiSignature, MultiSigner};
+use sp_runtime::AccountId32;
 use std::fmt::Debug;
 use structopt::StructOpt;
 use strum::{EnumString, EnumVariantNames, VariantNames};
@@ -61,8 +57,6 @@ pub struct SendMessage {
 	source: SourceConnectionParams,
 	#[structopt(flatten)]
 	source_sign: SourceSigningParams,
-	#[structopt(flatten)]
-	target_sign: TargetSigningParams,
 	/// Hex-encoded lane id. Defaults to `00000000`.
 	#[structopt(long, default_value = "00000000")]
 	lane: HexLaneId,
@@ -72,104 +66,20 @@ pub struct SendMessage {
 	/// your message won't be relayed.
 	#[structopt(long)]
 	conversion_rate_override: Option<ConversionRateOverride>,
-	/// Where dispatch fee is paid?
-	#[structopt(
-		long,
-		possible_values = DispatchFeePayment::VARIANTS,
-		case_insensitive = true,
-		default_value = "at-source-chain",
-	)]
-	dispatch_fee_payment: DispatchFeePayment,
-	/// Dispatch weight of the message. If not passed, determined automatically.
-	#[structopt(long)]
-	dispatch_weight: Option<ExplicitOrMaximal<Weight>>,
 	/// Delivery and dispatch fee in source chain base currency units. If not passed, determined
 	/// automatically.
 	#[structopt(long)]
 	fee: Option<Balance>,
 	/// Message type.
 	#[structopt(subcommand)]
-	message: crate::cli::encode_call::Call,
-	/// The origin to use when dispatching the message on the target chain. Defaults to
-	/// `SourceAccount`.
-	#[structopt(long, possible_values = &Origins::variants(), default_value = "Source")]
-	origin: Origins,
-
-	// Normally we don't need to connect to the target chain to send message. But for testing
-	// we may want to use **actual** `spec_version` of the target chain when composing a message.
-	// Then we'll need to read version from the target chain node.
-	#[structopt(flatten)]
-	target: TargetConnectionParams,
+	message: crate::cli::encode_message::Message,
 }
 
 impl SendMessage {
-	pub async fn encode_payload(
-		&mut self,
-	) -> anyhow::Result<MessagePayload<AccountId32, MultiSigner, MultiSignature, Vec<u8>>> {
-		crate::select_full_bridge!(self.bridge, {
-			let SendMessage {
-				source_sign,
-				target_sign,
-				ref mut message,
-				dispatch_fee_payment,
-				dispatch_weight,
-				origin,
-				bridge,
-				..
-			} = self;
-
-			let source_sign = source_sign.to_keypair::<Source>()?;
-
-			encode_call::preprocess_call::<Source, Target>(message, bridge.bridge_instance_index());
-			let target_call = Target::encode_call(message)?;
-			let target_spec_version = self.target.selected_chain_spec_version::<Target>().await?;
-
-			let payload = {
-				let target_call_weight = prepare_call_dispatch_weight(
-					dispatch_weight,
-					|| {
-						Ok(ExplicitOrMaximal::Explicit(
-							Target::get_dispatch_info(&target_call)?.weight,
-						))
-					},
-					compute_maximal_message_dispatch_weight(Target::max_extrinsic_weight()),
-				)?;
-				let source_sender_public: MultiSigner = source_sign.public().into();
-				let source_account_id = source_sender_public.into_account();
-
-				message_payload(
-					target_spec_version,
-					target_call_weight,
-					match origin {
-						Origins::Source => CallOrigin::SourceAccount(source_account_id),
-						Origins::Target => {
-							let target_sign = target_sign.to_keypair::<Target>()?;
-							let digest = account_ownership_digest(
-								&target_call,
-								source_account_id.clone(),
-								target_spec_version,
-							);
-							let target_origin_public = target_sign.public();
-							let digest_signature = target_sign.sign(&digest);
-							CallOrigin::TargetAccount(
-								source_account_id,
-								target_origin_public.into(),
-								digest_signature.into(),
-							)
-						},
-					},
-					&target_call,
-					*dispatch_fee_payment,
-				)
-			};
-			Ok(payload)
-		})
-	}
-
 	/// Run the command.
-	pub async fn run(mut self) -> anyhow::Result<()> {
+	pub async fn run(self) -> anyhow::Result<()> {
 		crate::select_full_bridge!(self.bridge, {
-			let payload = self.encode_payload().await?;
+			let payload = encode_message::encode_message::<Source, Target>(&self.message)?;
 
 			let source_client = self.source.to_client::<Source>().await?;
 			let source_sign = self.source_sign.to_keypair::<Source>()?;
@@ -189,14 +99,13 @@ impl SendMessage {
 					.await? as _,
 				),
 			};
-			let dispatch_weight = payload.weight;
 			let payload_len = payload.encode().len();
-			let send_message_call = Source::encode_call(&encode_call::Call::BridgeSendMessage {
-				bridge_instance_index: self.bridge.bridge_instance_index(),
-				lane: self.lane,
-				payload: HexBytes::encode(&payload),
-				fee,
-			})?;
+			let send_message_call = Source::encode_send_message_call(
+				self.lane.0,
+				payload,
+				fee.cast().into(),
+				self.bridge.bridge_instance_index(),
+			)?;
 
 			let source_genesis_hash = *source_client.genesis_hash();
 			let (spec_version, transaction_version) =
@@ -228,11 +137,10 @@ impl SendMessage {
 
 					log::info!(
 						target: "bridge",
-						"Sending message to {}. Lane: {:?}. Size: {}. Dispatch weight: {}. Fee: {}",
+						"Sending message to {}. Lane: {:?}. Size: {}. Fee: {}",
 						Target::NAME,
 						lane,
 						payload_len,
-						dispatch_weight,
 						fee,
 					);
 					log::info!(
@@ -260,66 +168,15 @@ impl SendMessage {
 	}
 }
 
-fn prepare_call_dispatch_weight(
-	user_specified_dispatch_weight: &Option<ExplicitOrMaximal<Weight>>,
-	weight_from_pre_dispatch_call: impl Fn() -> anyhow::Result<ExplicitOrMaximal<Weight>>,
-	maximal_allowed_weight: Weight,
-) -> anyhow::Result<Weight> {
-	match user_specified_dispatch_weight
-		.clone()
-		.map(Ok)
-		.unwrap_or_else(weight_from_pre_dispatch_call)?
-	{
-		ExplicitOrMaximal::Explicit(weight) => Ok(weight),
-		ExplicitOrMaximal::Maximal => Ok(maximal_allowed_weight),
-	}
-}
-
-pub(crate) fn message_payload<SAccountId, TPublic, TSignature>(
-	spec_version: u32,
-	weight: Weight,
-	origin: CallOrigin<SAccountId, TPublic, TSignature>,
-	call: &impl Encode,
-	dispatch_fee_payment: DispatchFeePayment,
-) -> MessagePayload<SAccountId, TPublic, TSignature, Vec<u8>>
-where
-	SAccountId: Encode + Debug,
-	TPublic: Encode + Debug,
-	TSignature: Encode + Debug,
-{
-	// Display nicely formatted call.
-	let payload = MessagePayload {
-		spec_version,
-		weight,
-		origin,
-		dispatch_fee_payment: dispatch_fee_payment.into(),
-		call: HexBytes::encode(call),
-	};
-
-	log::info!(target: "bridge", "Created Message Payload: {:#?}", payload);
-	log::info!(target: "bridge", "Encoded Message Payload: {:?}", HexBytes::encode(&payload));
-
-	// re-pack to return `Vec<u8>`
-	let MessagePayload { spec_version, weight, origin, dispatch_fee_payment, call } = payload;
-	MessagePayload { spec_version, weight, origin, dispatch_fee_payment, call: call.0 }
-}
-
-pub(crate) fn compute_maximal_message_dispatch_weight(maximal_extrinsic_weight: Weight) -> Weight {
-	bridge_runtime_common::messages::target::maximal_incoming_message_dispatch_weight(
-		maximal_extrinsic_weight,
-	)
-}
-
 #[cfg(test)]
 mod tests {
 	use super::*;
-	use crate::cli::CliChain;
-	use hex_literal::hex;
+	use crate::cli::ExplicitOrMaximal;
 
-	#[async_std::test]
-	async fn send_remark_rialto_to_millau() {
+	#[test]
+	fn send_raw_rialto_to_millau() {
 		// given
-		let mut send_message = SendMessage::from_iter(vec![
+		let send_message = SendMessage::from_iter(vec![
 			"send-message",
 			"rialto-to-millau",
 			"--source-port",
@@ -328,117 +185,48 @@ mod tests {
 			"//Alice",
 			"--conversion-rate-override",
 			"0.75",
-			"remark",
-			"--remark-payload",
-			"1234",
+			"raw",
+			"dead",
 		]);
 
-		// when
-		let payload = send_message.encode_payload().await.unwrap();
-
 		// then
+		assert_eq!(send_message.bridge, FullBridge::RialtoToMillau);
+		assert_eq!(send_message.source.source_port, 1234);
+		assert_eq!(send_message.source_sign.source_signer, Some("//Alice".into()));
 		assert_eq!(
-			payload,
-			MessagePayload {
-				spec_version: relay_millau_client::Millau::RUNTIME_VERSION.spec_version,
-				weight: 0,
-				origin: CallOrigin::SourceAccount(
-					sp_keyring::AccountKeyring::Alice.to_account_id()
-				),
-				dispatch_fee_payment: bp_runtime::messages::DispatchFeePayment::AtSourceChain,
-				call: hex!("0001081234").to_vec(),
-			}
+			send_message.conversion_rate_override,
+			Some(ConversionRateOverride::Explicit(0.75))
 		);
-	}
-
-	#[async_std::test]
-	async fn send_remark_millau_to_rialto() {
-		// given
-		let mut send_message = SendMessage::from_iter(vec![
-			"send-message",
-			"millau-to-rialto",
-			"--source-port",
-			"1234",
-			"--source-signer",
-			"//Alice",
-			"--origin",
-			"Target",
-			"--target-signer",
-			"//Bob",
-			"--conversion-rate-override",
-			"metric",
-			"remark",
-			"--remark-payload",
-			"1234",
-		]);
-
-		// when
-		let payload = send_message.encode_payload().await.unwrap();
-
-		// then
-		// Since signatures are randomized we extract it from here and only check the rest.
-		let signature = match payload.origin {
-			CallOrigin::TargetAccount(_, _, ref sig) => sig.clone(),
-			_ => panic!("Unexpected `CallOrigin`: {:?}", payload),
-		};
 		assert_eq!(
-			payload,
-			MessagePayload {
-				spec_version: relay_millau_client::Millau::RUNTIME_VERSION.spec_version,
-				weight: 0,
-				origin: CallOrigin::TargetAccount(
-					sp_keyring::AccountKeyring::Alice.to_account_id(),
-					sp_keyring::AccountKeyring::Bob.into(),
-					signature,
-				),
-				dispatch_fee_payment: bp_runtime::messages::DispatchFeePayment::AtSourceChain,
-				call: hex!("0001081234").to_vec(),
-			}
+			send_message.message,
+			crate::cli::encode_message::Message::Raw { data: HexBytes(vec![0xDE, 0xAD]) }
 		);
 	}
 
 	#[test]
-	fn accepts_send_message_command_without_target_sign_options() {
-		// given
-		let send_message = SendMessage::from_iter_safe(vec![
-			"send-message",
-			"rialto-to-millau",
-			"--source-port",
-			"1234",
-			"--source-signer",
-			"//Alice",
-			"--origin",
-			"Target",
-			"remark",
-			"--remark-payload",
-			"1234",
-		]);
-
-		assert!(send_message.is_ok());
-	}
-
-	#[async_std::test]
-	async fn accepts_non_default_dispatch_fee_payment() {
+	fn send_sized_rialto_to_millau() {
 		// given
-		let mut send_message = SendMessage::from_iter(vec![
+		let send_message = SendMessage::from_iter(vec![
 			"send-message",
 			"rialto-to-millau",
 			"--source-port",
 			"1234",
 			"--source-signer",
 			"//Alice",
-			"--dispatch-fee-payment",
-			"at-target-chain",
-			"remark",
+			"--conversion-rate-override",
+			"metric",
+			"sized",
+			"max",
 		]);
 
-		// when
-		let payload = send_message.encode_payload().await.unwrap();
-
 		// then
+		assert_eq!(send_message.bridge, FullBridge::RialtoToMillau);
+		assert_eq!(send_message.source.source_port, 1234);
+		assert_eq!(send_message.source_sign.source_signer, Some("//Alice".into()));
+		assert_eq!(send_message.conversion_rate_override, Some(ConversionRateOverride::Metric));
 		assert_eq!(
-			payload.dispatch_fee_payment,
-			bp_runtime::messages::DispatchFeePayment::AtTargetChain
+			send_message.message,
+			crate::cli::encode_message::Message::Sized { size: ExplicitOrMaximal::Maximal }
 		);
 	}
 }
diff --git a/bridges/relays/bin-substrate/src/cli/swap_tokens.rs b/bridges/relays/bin-substrate/src/cli/swap_tokens.rs
deleted file mode 100644
index 1467df3711c35319092b4bfd7be2d563abc40241..0000000000000000000000000000000000000000
--- a/bridges/relays/bin-substrate/src/cli/swap_tokens.rs
+++ /dev/null
@@ -1,869 +0,0 @@
-// Copyright 2019-2021 Parity Technologies (UK) Ltd.
-// This file is part of Parity Bridges Common.
-
-// Parity Bridges Common 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.
-
-// Parity Bridges Common 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 Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
-
-//! Tokens swap using token-swap bridge pallet.
-
-// TokenSwapBalances fields are never directly accessed, but the whole struct is printed
-// to show token swap progress
-#![allow(dead_code)]
-
-use codec::Encode;
-use num_traits::One;
-use rand::random;
-use structopt::StructOpt;
-use strum::{EnumString, EnumVariantNames, VariantNames};
-
-use frame_support::dispatch::GetDispatchInfo;
-use relay_substrate_client::{
-	AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, CallOf, Chain, ChainWithBalances,
-	Client, Error as SubstrateError, HashOf, SignParam, SignatureOf, Subscription,
-	TransactionSignScheme, TransactionStatusOf, UnsignedTransaction,
-};
-use sp_core::{blake2_256, storage::StorageKey, Bytes, Pair, U256};
-use sp_runtime::traits::{Convert, Header as HeaderT};
-
-use crate::cli::{
-	estimate_fee::ConversionRateOverride, Balance, CliChain, SourceConnectionParams,
-	SourceSigningParams, TargetConnectionParams, TargetSigningParams,
-};
-
-/// Swap tokens.
-#[derive(StructOpt, Debug, PartialEq)]
-pub struct SwapTokens {
-	/// A bridge instance to use in token swap.
-	#[structopt(possible_values = SwapTokensBridge::VARIANTS, case_insensitive = true)]
-	bridge: SwapTokensBridge,
-
-	#[structopt(flatten)]
-	source: SourceConnectionParams,
-	#[structopt(flatten)]
-	source_sign: SourceSigningParams,
-
-	#[structopt(flatten)]
-	target: TargetConnectionParams,
-	#[structopt(flatten)]
-	target_sign: TargetSigningParams,
-
-	#[structopt(subcommand)]
-	swap_type: TokenSwapType,
-	/// Source chain balance that source signer wants to swap.
-	#[structopt(long)]
-	source_balance: Balance,
-	/// Target chain balance that target signer wants to swap.
-	#[structopt(long)]
-	target_balance: Balance,
-	/// A way to override conversion rate from target to source tokens.
-	///
-	/// If not specified, conversion rate from runtime storage is used. It may be obsolete and
-	/// your message won't be relayed.
-	#[structopt(long)]
-	target_to_source_conversion_rate_override: Option<ConversionRateOverride>,
-	/// A way to override conversion rate from source to target tokens.
-	///
-	/// If not specified, conversion rate from runtime storage is used. It may be obsolete and
-	/// your message won't be relayed.
-	#[structopt(long)]
-	source_to_target_conversion_rate_override: Option<ConversionRateOverride>,
-}
-
-/// Token swap type.
-#[derive(StructOpt, Debug, PartialEq, Eq, Clone)]
-pub enum TokenSwapType {
-	/// The `target_sign` is temporary and only have funds for single swap.
-	NoLock,
-	/// This swap type prevents `source_signer` from restarting the swap after it has been
-	/// completed.
-	LockUntilBlock {
-		/// Number of blocks before the swap expires.
-		#[structopt(long)]
-		blocks_before_expire: u32,
-		/// Unique swap nonce.
-		#[structopt(long)]
-		swap_nonce: Option<U256>,
-	},
-}
-
-/// Swap tokens bridge.
-#[derive(Debug, EnumString, EnumVariantNames, PartialEq)]
-#[strum(serialize_all = "kebab_case")]
-pub enum SwapTokensBridge {
-	/// Use token-swap pallet deployed at Millau to swap tokens with Rialto.
-	MillauToRialto,
-}
-
-macro_rules! select_bridge {
-	($bridge: expr, $generic: tt) => {
-		match $bridge {
-			SwapTokensBridge::MillauToRialto => {
-				type Source = relay_millau_client::Millau;
-				type Target = relay_rialto_client::Rialto;
-				const SOURCE_SPEC_VERSION: u32 = millau_runtime::VERSION.spec_version;
-				const TARGET_SPEC_VERSION: u32 = rialto_runtime::VERSION.spec_version;
-
-				type FromSwapToThisAccountIdConverter = bp_rialto::AccountIdConverter;
-
-				use bp_millau::{
-					derive_account_from_rialto_id as derive_source_account_from_target_account,
-					TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_TARGET_TO_SOURCE_MESSAGE_FEE_METHOD,
-					WITH_RIALTO_TOKEN_SWAP_PALLET_NAME as TOKEN_SWAP_PALLET_NAME,
-				};
-				use bp_rialto::{
-					derive_account_from_millau_id as derive_target_account_from_source_account,
-					TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_SOURCE_TO_TARGET_MESSAGE_FEE_METHOD,
-				};
-
-				const SOURCE_CHAIN_ID: bp_runtime::ChainId = bp_runtime::MILLAU_CHAIN_ID;
-				const TARGET_CHAIN_ID: bp_runtime::ChainId = bp_runtime::RIALTO_CHAIN_ID;
-
-				const SOURCE_TO_TARGET_LANE_ID: bp_messages::LaneId = *b"swap";
-				const TARGET_TO_SOURCE_LANE_ID: bp_messages::LaneId = [0, 0, 0, 0];
-
-				$generic
-			},
-		}
-	};
-}
-
-impl SwapTokens {
-	/// Run the command.
-	pub async fn run(self) -> anyhow::Result<()> {
-		select_bridge!(self.bridge, {
-			let source_client = self.source.to_client::<Source>().await?;
-			let source_sign = self.source_sign.to_keypair::<Target>()?;
-			let target_client = self.target.to_client::<Target>().await?;
-			let target_sign = self.target_sign.to_keypair::<Target>()?;
-			let target_to_source_conversion_rate_override =
-				self.target_to_source_conversion_rate_override;
-			let source_to_target_conversion_rate_override =
-				self.source_to_target_conversion_rate_override;
-
-			// names of variables in this function are matching names used by the
-			// `pallet-bridge-token-swap`
-
-			// prepare token swap intention
-			let token_swap = self
-				.prepare_token_swap::<Source, Target>(&source_client, &source_sign, &target_sign)
-				.await?;
-
-			// group all accounts that will be used later
-			let accounts = TokenSwapAccounts {
-				source_account_at_bridged_chain: derive_target_account_from_source_account(
-					bp_runtime::SourceAccount::Account(
-						token_swap.source_account_at_this_chain.clone(),
-					),
-				),
-				target_account_at_this_chain: derive_source_account_from_target_account(
-					bp_runtime::SourceAccount::Account(
-						token_swap.target_account_at_bridged_chain.clone(),
-					),
-				),
-				source_account_at_this_chain: token_swap.source_account_at_this_chain.clone(),
-				target_account_at_bridged_chain: token_swap.target_account_at_bridged_chain.clone(),
-				swap_account: FromSwapToThisAccountIdConverter::convert(
-					token_swap.using_encoded(blake2_256).into(),
-				),
-			};
-
-			// account balances are used to demonstrate what's happening :)
-			let initial_balances =
-				read_account_balances(&accounts, &source_client, &target_client).await?;
-
-			// before calling something that may fail, log what we're trying to do
-			log::info!(target: "bridge", "Starting swap: {:?}", token_swap);
-			log::info!(target: "bridge", "Swap accounts: {:?}", accounts);
-			log::info!(target: "bridge", "Initial account balances: {:?}", initial_balances);
-
-			//
-			// Step 1: swap is created
-			//
-
-			// prepare `Currency::transfer` call that will happen at the target chain
-			let bridged_currency_transfer: CallOf<Target> = pallet_balances::Call::transfer {
-				dest: accounts.source_account_at_bridged_chain.clone().into(),
-				value: token_swap.target_balance_at_bridged_chain,
-			}
-			.into();
-			let bridged_currency_transfer_weight =
-				bridged_currency_transfer.get_dispatch_info().weight;
-
-			// sign message
-			let bridged_chain_spec_version = TARGET_SPEC_VERSION;
-			let signature_payload = pallet_bridge_dispatch::account_ownership_digest(
-				&bridged_currency_transfer,
-				&accounts.swap_account,
-				&bridged_chain_spec_version,
-				SOURCE_CHAIN_ID,
-				TARGET_CHAIN_ID,
-			);
-			let bridged_currency_transfer_signature: SignatureOf<Target> =
-				target_sign.sign(&signature_payload).into();
-
-			// prepare `create_swap` call
-			let target_public_at_bridged_chain: AccountPublicOf<Target> =
-				target_sign.public().into();
-			let swap_delivery_and_dispatch_fee =
-				crate::cli::estimate_fee::estimate_message_delivery_and_dispatch_fee::<
-					Source,
-					Target,
-					_,
-				>(
-					&source_client,
-					target_to_source_conversion_rate_override,
-					ESTIMATE_SOURCE_TO_TARGET_MESSAGE_FEE_METHOD,
-					SOURCE_TO_TARGET_LANE_ID,
-					bp_message_dispatch::MessagePayload {
-						spec_version: TARGET_SPEC_VERSION,
-						weight: bridged_currency_transfer_weight,
-						origin: bp_message_dispatch::CallOrigin::TargetAccount(
-							accounts.swap_account.clone(),
-							target_public_at_bridged_chain.clone(),
-							bridged_currency_transfer_signature.clone(),
-						),
-						dispatch_fee_payment:
-							bp_runtime::messages::DispatchFeePayment::AtTargetChain,
-						call: bridged_currency_transfer.encode(),
-					},
-				)
-				.await?;
-			let create_swap_call: CallOf<Source> = pallet_bridge_token_swap::Call::create_swap {
-				swap: token_swap.clone(),
-				swap_creation_params: Box::new(bp_token_swap::TokenSwapCreation {
-					target_public_at_bridged_chain,
-					swap_delivery_and_dispatch_fee,
-					bridged_chain_spec_version,
-					bridged_currency_transfer: bridged_currency_transfer.encode(),
-					bridged_currency_transfer_weight,
-					bridged_currency_transfer_signature,
-				}),
-			}
-			.into();
-
-			// start tokens swap
-			let source_genesis_hash = *source_client.genesis_hash();
-			let create_swap_signer = source_sign.clone();
-			let (spec_version, transaction_version) =
-				source_client.simple_runtime_version().await?;
-			let swap_created_at = wait_until_transaction_is_finalized::<Source>(
-				source_client
-					.submit_and_watch_signed_extrinsic(
-						accounts.source_account_at_this_chain.clone(),
-						move |_, transaction_nonce| {
-							Ok(Bytes(
-								Source::sign_transaction(SignParam {
-									spec_version,
-									transaction_version,
-									genesis_hash: source_genesis_hash,
-									signer: create_swap_signer,
-									era: relay_substrate_client::TransactionEra::immortal(),
-									unsigned: UnsignedTransaction::new(
-										create_swap_call.into(),
-										transaction_nonce,
-									),
-								})?
-								.encode(),
-							))
-						},
-					)
-					.await?,
-			)
-			.await?;
-
-			// read state of swap after it has been created
-			let token_swap_hash = token_swap.hash();
-			let token_swap_storage_key = bp_token_swap::storage_keys::pending_swaps_key(
-				TOKEN_SWAP_PALLET_NAME,
-				token_swap_hash,
-			);
-			match read_token_swap_state(&source_client, swap_created_at, &token_swap_storage_key)
-				.await?
-			{
-				Some(bp_token_swap::TokenSwapState::Started) => {
-					log::info!(target: "bridge", "Swap has been successfully started");
-					let intermediate_balances =
-						read_account_balances(&accounts, &source_client, &target_client).await?;
-					log::info!(target: "bridge", "Intermediate balances: {:?}", intermediate_balances);
-				},
-				Some(token_swap_state) =>
-					return Err(anyhow::format_err!(
-						"Fresh token swap has unexpected state: {:?}",
-						token_swap_state,
-					)),
-				None => return Err(anyhow::format_err!("Failed to start token swap")),
-			};
-
-			//
-			// Step 2: message is being relayed to the target chain and dispathed there
-			//
-
-			// wait until message is dispatched at the target chain and dispatch result delivered
-			// back to source chain
-			let token_swap_state = wait_until_token_swap_state_is_changed(
-				&source_client,
-				&token_swap_storage_key,
-				bp_token_swap::TokenSwapState::Started,
-			)
-			.await?;
-			let is_transfer_succeeded = match token_swap_state {
-				Some(bp_token_swap::TokenSwapState::Started) => {
-					unreachable!("wait_until_token_swap_state_is_changed only returns if state is not Started; qed",)
-				},
-				None =>
-					return Err(anyhow::format_err!("Fresh token swap has disappeared unexpectedly")),
-				Some(bp_token_swap::TokenSwapState::Confirmed) => {
-					log::info!(
-						target: "bridge",
-						"Transfer has been successfully dispatched at the target chain. Swap can be claimed",
-					);
-					true
-				},
-				Some(bp_token_swap::TokenSwapState::Failed) => {
-					log::info!(
-						target: "bridge",
-						"Transfer has been dispatched with an error at the target chain. Swap can be canceled",
-					);
-					false
-				},
-			};
-
-			// by this time: (1) token swap account has been created and (2) if transfer has been
-			// successfully dispatched, both target chain balances have changed
-			let intermediate_balances =
-				read_account_balances(&accounts, &source_client, &target_client).await?;
-			log::info!(target: "bridge", "Intermediate balances: {:?}", intermediate_balances);
-
-			// transfer has been dispatched, but we may need to wait until block where swap can be
-			// claimed/canceled
-			if let bp_token_swap::TokenSwapType::LockClaimUntilBlock(
-				ref last_available_block_number,
-				_,
-			) = token_swap.swap_type
-			{
-				wait_until_swap_unlocked(
-					&source_client,
-					last_available_block_number + BlockNumberOf::<Source>::one(),
-				)
-				.await?;
-			}
-
-			//
-			// Step 3: we may now claim or cancel the swap
-			//
-
-			if is_transfer_succeeded {
-				log::info!(target: "bridge", "Claiming the swap");
-
-				// prepare `claim_swap` message that will be sent over the bridge
-				let claim_swap_call: CallOf<Source> =
-					pallet_bridge_token_swap::Call::claim_swap { swap: token_swap }.into();
-				let claim_swap_message = bp_message_dispatch::MessagePayload {
-					spec_version: SOURCE_SPEC_VERSION,
-					weight: claim_swap_call.get_dispatch_info().weight,
-					origin: bp_message_dispatch::CallOrigin::SourceAccount(
-						accounts.target_account_at_bridged_chain.clone(),
-					),
-					dispatch_fee_payment: bp_runtime::messages::DispatchFeePayment::AtSourceChain,
-					call: claim_swap_call.encode(),
-				};
-				let claim_swap_delivery_and_dispatch_fee =
-					crate::cli::estimate_fee::estimate_message_delivery_and_dispatch_fee::<
-						Target,
-						Source,
-						_,
-					>(
-						&target_client,
-						source_to_target_conversion_rate_override,
-						ESTIMATE_TARGET_TO_SOURCE_MESSAGE_FEE_METHOD,
-						TARGET_TO_SOURCE_LANE_ID,
-						claim_swap_message.clone(),
-					)
-					.await?;
-				let send_message_call: CallOf<Target> =
-					pallet_bridge_messages::Call::send_message {
-						lane_id: TARGET_TO_SOURCE_LANE_ID,
-						payload: claim_swap_message,
-						delivery_and_dispatch_fee: claim_swap_delivery_and_dispatch_fee,
-					}
-					.into();
-
-				// send `claim_swap` message
-				let target_genesis_hash = *target_client.genesis_hash();
-				let (spec_version, transaction_version) =
-					target_client.simple_runtime_version().await?;
-				let _ = wait_until_transaction_is_finalized::<Target>(
-					target_client
-						.submit_and_watch_signed_extrinsic(
-							accounts.target_account_at_bridged_chain.clone(),
-							move |_, transaction_nonce| {
-								Ok(Bytes(
-									Target::sign_transaction(SignParam {
-										spec_version,
-										transaction_version,
-										genesis_hash: target_genesis_hash,
-										signer: target_sign,
-										era: relay_substrate_client::TransactionEra::immortal(),
-										unsigned: UnsignedTransaction::new(
-											send_message_call.into(),
-											transaction_nonce,
-										),
-									})?
-									.encode(),
-								))
-							},
-						)
-						.await?,
-				)
-				.await?;
-
-				// wait until swap state is updated
-				let token_swap_state = wait_until_token_swap_state_is_changed(
-					&source_client,
-					&token_swap_storage_key,
-					bp_token_swap::TokenSwapState::Confirmed,
-				)
-				.await?;
-				if token_swap_state != None {
-					return Err(anyhow::format_err!(
-						"Confirmed token swap state has been changed to {:?} unexpectedly",
-						token_swap_state
-					))
-				}
-			} else {
-				log::info!(target: "bridge", "Cancelling the swap");
-				let cancel_swap_call: CallOf<Source> =
-					pallet_bridge_token_swap::Call::cancel_swap { swap: token_swap.clone() }.into();
-				let (spec_version, transaction_version) =
-					source_client.simple_runtime_version().await?;
-				let _ = wait_until_transaction_is_finalized::<Source>(
-					source_client
-						.submit_and_watch_signed_extrinsic(
-							accounts.source_account_at_this_chain.clone(),
-							move |_, transaction_nonce| {
-								Ok(Bytes(
-									Source::sign_transaction(SignParam {
-										spec_version,
-										transaction_version,
-										genesis_hash: source_genesis_hash,
-										signer: source_sign,
-										era: relay_substrate_client::TransactionEra::immortal(),
-										unsigned: UnsignedTransaction::new(
-											cancel_swap_call.into(),
-											transaction_nonce,
-										),
-									})?
-									.encode(),
-								))
-							},
-						)
-						.await?,
-				)
-				.await?;
-			}
-
-			// print final balances
-			let final_balances =
-				read_account_balances(&accounts, &source_client, &target_client).await?;
-			log::info!(target: "bridge", "Final account balances: {:?}", final_balances);
-
-			Ok(())
-		})
-	}
-
-	/// Prepare token swap intention.
-	async fn prepare_token_swap<Source: CliChain, Target: CliChain>(
-		&self,
-		source_client: &Client<Source>,
-		source_sign: &Source::KeyPair,
-		target_sign: &Target::KeyPair,
-	) -> anyhow::Result<
-		bp_token_swap::TokenSwap<
-			BlockNumberOf<Source>,
-			BalanceOf<Source>,
-			AccountIdOf<Source>,
-			BalanceOf<Target>,
-			AccountIdOf<Target>,
-		>,
-	>
-	where
-		AccountIdOf<Source>: From<<Source::KeyPair as Pair>::Public>,
-		AccountIdOf<Target>: From<<Target::KeyPair as Pair>::Public>,
-		BalanceOf<Source>: From<u64>,
-		BalanceOf<Target>: From<u64>,
-	{
-		// accounts that are directly controlled by participants
-		let source_account_at_this_chain: AccountIdOf<Source> = source_sign.public().into();
-		let target_account_at_bridged_chain: AccountIdOf<Target> = target_sign.public().into();
-
-		// balances that we're going to swap
-		let source_balance_at_this_chain: BalanceOf<Source> = self.source_balance.cast().into();
-		let target_balance_at_bridged_chain: BalanceOf<Target> = self.target_balance.cast().into();
-
-		// prepare token swap intention
-		Ok(bp_token_swap::TokenSwap {
-			swap_type: self.prepare_token_swap_type(source_client).await?,
-			source_balance_at_this_chain,
-			source_account_at_this_chain: source_account_at_this_chain.clone(),
-			target_balance_at_bridged_chain,
-			target_account_at_bridged_chain: target_account_at_bridged_chain.clone(),
-		})
-	}
-
-	/// Prepare token swap type.
-	async fn prepare_token_swap_type<Source: Chain>(
-		&self,
-		source_client: &Client<Source>,
-	) -> anyhow::Result<bp_token_swap::TokenSwapType<BlockNumberOf<Source>>> {
-		match self.swap_type {
-			TokenSwapType::NoLock =>
-				Ok(bp_token_swap::TokenSwapType::TemporaryTargetAccountAtBridgedChain),
-			TokenSwapType::LockUntilBlock { blocks_before_expire, ref swap_nonce } => {
-				let blocks_before_expire: BlockNumberOf<Source> = blocks_before_expire.into();
-				let current_source_block_number = *source_client.best_header().await?.number();
-				Ok(bp_token_swap::TokenSwapType::LockClaimUntilBlock(
-					current_source_block_number + blocks_before_expire,
-					swap_nonce.unwrap_or_else(|| {
-						U256::from(random::<u128>()).overflowing_mul(U256::from(random::<u128>())).0
-					}),
-				))
-			},
-		}
-	}
-}
-
-/// Accounts that are participating in the swap.
-#[derive(Debug)]
-struct TokenSwapAccounts<ThisAccountId, BridgedAccountId> {
-	source_account_at_this_chain: ThisAccountId,
-	source_account_at_bridged_chain: BridgedAccountId,
-	target_account_at_bridged_chain: BridgedAccountId,
-	target_account_at_this_chain: ThisAccountId,
-	swap_account: ThisAccountId,
-}
-
-/// Swap accounts balances.
-#[derive(Debug)]
-struct TokenSwapBalances<ThisBalance, BridgedBalance> {
-	source_account_at_this_chain_balance: Option<ThisBalance>,
-	source_account_at_bridged_chain_balance: Option<BridgedBalance>,
-	target_account_at_bridged_chain_balance: Option<BridgedBalance>,
-	target_account_at_this_chain_balance: Option<ThisBalance>,
-	swap_account_balance: Option<ThisBalance>,
-}
-
-/// Read swap accounts balances.
-async fn read_account_balances<Source: ChainWithBalances, Target: ChainWithBalances>(
-	accounts: &TokenSwapAccounts<AccountIdOf<Source>, AccountIdOf<Target>>,
-	source_client: &Client<Source>,
-	target_client: &Client<Target>,
-) -> anyhow::Result<TokenSwapBalances<BalanceOf<Source>, BalanceOf<Target>>> {
-	Ok(TokenSwapBalances {
-		source_account_at_this_chain_balance: read_account_balance(
-			source_client,
-			&accounts.source_account_at_this_chain,
-		)
-		.await?,
-		source_account_at_bridged_chain_balance: read_account_balance(
-			target_client,
-			&accounts.source_account_at_bridged_chain,
-		)
-		.await?,
-		target_account_at_bridged_chain_balance: read_account_balance(
-			target_client,
-			&accounts.target_account_at_bridged_chain,
-		)
-		.await?,
-		target_account_at_this_chain_balance: read_account_balance(
-			source_client,
-			&accounts.target_account_at_this_chain,
-		)
-		.await?,
-		swap_account_balance: read_account_balance(source_client, &accounts.swap_account).await?,
-	})
-}
-
-/// Read account balance.
-async fn read_account_balance<C: ChainWithBalances>(
-	client: &Client<C>,
-	account: &AccountIdOf<C>,
-) -> anyhow::Result<Option<BalanceOf<C>>> {
-	match client.free_native_balance(account.clone()).await {
-		Ok(balance) => Ok(Some(balance)),
-		Err(SubstrateError::AccountDoesNotExist) => Ok(None),
-		Err(error) => Err(anyhow::format_err!(
-			"Failed to read balance of {} account {:?}: {:?}",
-			C::NAME,
-			account,
-			error,
-		)),
-	}
-}
-
-/// Wait until transaction is included into finalized block.
-///
-/// Returns the hash of the finalized block with transaction.
-pub(crate) async fn wait_until_transaction_is_finalized<C: Chain>(
-	subscription: Subscription<TransactionStatusOf<C>>,
-) -> anyhow::Result<HashOf<C>> {
-	loop {
-		let transaction_status = subscription.next().await?;
-		match transaction_status {
-			Some(TransactionStatusOf::<C>::FinalityTimeout(_)) |
-			Some(TransactionStatusOf::<C>::Usurped(_)) |
-			Some(TransactionStatusOf::<C>::Dropped) |
-			Some(TransactionStatusOf::<C>::Invalid) |
-			None =>
-				return Err(anyhow::format_err!(
-					"We've been waiting for finalization of {} transaction, but it now has the {:?} status",
-					C::NAME,
-					transaction_status,
-				)),
-			Some(TransactionStatusOf::<C>::Finalized(block_hash)) => {
-				log::trace!(
-					target: "bridge",
-					"{} transaction has been finalized at block {}",
-					C::NAME,
-					block_hash,
-				);
-				return Ok(block_hash)
-			},
-			_ => {
-				log::trace!(
-					target: "bridge",
-					"Received intermediate status of {} transaction: {:?}",
-					C::NAME,
-					transaction_status,
-				);
-			},
-		}
-	}
-}
-
-/// Waits until token swap state is changed from `Started` to something else.
-async fn wait_until_token_swap_state_is_changed<C: Chain>(
-	client: &Client<C>,
-	swap_state_storage_key: &StorageKey,
-	previous_token_swap_state: bp_token_swap::TokenSwapState,
-) -> anyhow::Result<Option<bp_token_swap::TokenSwapState>> {
-	log::trace!(target: "bridge", "Waiting for token swap state change");
-	loop {
-		async_std::task::sleep(C::AVERAGE_BLOCK_INTERVAL).await;
-
-		let best_block = client.best_finalized_header_number().await?;
-		let best_block_hash = client.block_hash_by_number(best_block).await?;
-		log::trace!(target: "bridge", "Inspecting {} block {}/{}", C::NAME, best_block, best_block_hash);
-
-		let token_swap_state =
-			read_token_swap_state(client, best_block_hash, swap_state_storage_key).await?;
-		match token_swap_state {
-			Some(new_token_swap_state) if new_token_swap_state == previous_token_swap_state => {},
-			_ => {
-				log::trace!(
-					target: "bridge",
-					"Token swap state has been changed from {:?} to {:?}",
-					previous_token_swap_state,
-					token_swap_state,
-				);
-				return Ok(token_swap_state)
-			},
-		}
-	}
-}
-
-/// Waits until swap can be claimed or canceled.
-async fn wait_until_swap_unlocked<C: Chain>(
-	client: &Client<C>,
-	required_block_number: BlockNumberOf<C>,
-) -> anyhow::Result<()> {
-	log::trace!(target: "bridge", "Waiting for token swap unlock");
-	loop {
-		async_std::task::sleep(C::AVERAGE_BLOCK_INTERVAL).await;
-
-		let best_block = client.best_finalized_header_number().await?;
-		let best_block_hash = client.block_hash_by_number(best_block).await?;
-		if best_block >= required_block_number {
-			return Ok(())
-		}
-
-		log::trace!(target: "bridge", "Skipping {} block {}/{}", C::NAME, best_block, best_block_hash);
-	}
-}
-
-/// Read state of the active token swap.
-async fn read_token_swap_state<C: Chain>(
-	client: &Client<C>,
-	at_block: C::Hash,
-	swap_state_storage_key: &StorageKey,
-) -> anyhow::Result<Option<bp_token_swap::TokenSwapState>> {
-	Ok(client.storage_value(swap_state_storage_key.clone(), Some(at_block)).await?)
-}
-
-#[cfg(test)]
-mod tests {
-	use super::*;
-	use crate::cli::{RuntimeVersionType, SourceRuntimeVersionParams, TargetRuntimeVersionParams};
-
-	#[test]
-	fn swap_tokens_millau_to_rialto_no_lock() {
-		let swap_tokens = SwapTokens::from_iter(vec![
-			"swap-tokens",
-			"millau-to-rialto",
-			"--source-host",
-			"127.0.0.1",
-			"--source-port",
-			"9000",
-			"--source-signer",
-			"//Alice",
-			"--source-balance",
-			"8000000000",
-			"--target-host",
-			"127.0.0.1",
-			"--target-port",
-			"9001",
-			"--target-signer",
-			"//Bob",
-			"--target-balance",
-			"9000000000",
-			"no-lock",
-		]);
-
-		assert_eq!(
-			swap_tokens,
-			SwapTokens {
-				bridge: SwapTokensBridge::MillauToRialto,
-				source: SourceConnectionParams {
-					source_host: "127.0.0.1".into(),
-					source_port: 9000,
-					source_secure: false,
-					source_runtime_version: SourceRuntimeVersionParams {
-						source_version_mode: RuntimeVersionType::Bundle,
-						source_spec_version: None,
-						source_transaction_version: None,
-					}
-				},
-				source_sign: SourceSigningParams {
-					source_signer: Some("//Alice".into()),
-					source_signer_password: None,
-					source_signer_file: None,
-					source_signer_password_file: None,
-					source_transactions_mortality: None,
-				},
-				target: TargetConnectionParams {
-					target_host: "127.0.0.1".into(),
-					target_port: 9001,
-					target_secure: false,
-					target_runtime_version: TargetRuntimeVersionParams {
-						target_version_mode: RuntimeVersionType::Bundle,
-						target_spec_version: None,
-						target_transaction_version: None,
-					}
-				},
-				target_sign: TargetSigningParams {
-					target_signer: Some("//Bob".into()),
-					target_signer_password: None,
-					target_signer_file: None,
-					target_signer_password_file: None,
-					target_transactions_mortality: None,
-				},
-				swap_type: TokenSwapType::NoLock,
-				source_balance: Balance(8000000000),
-				target_balance: Balance(9000000000),
-				target_to_source_conversion_rate_override: None,
-				source_to_target_conversion_rate_override: None,
-			}
-		);
-	}
-
-	#[test]
-	fn swap_tokens_millau_to_rialto_lock_until() {
-		let swap_tokens = SwapTokens::from_iter(vec![
-			"swap-tokens",
-			"millau-to-rialto",
-			"--source-host",
-			"127.0.0.1",
-			"--source-port",
-			"9000",
-			"--source-signer",
-			"//Alice",
-			"--source-balance",
-			"8000000000",
-			"--target-host",
-			"127.0.0.1",
-			"--target-port",
-			"9001",
-			"--target-signer",
-			"//Bob",
-			"--target-balance",
-			"9000000000",
-			"--target-to-source-conversion-rate-override",
-			"metric",
-			"--source-to-target-conversion-rate-override",
-			"84.56",
-			"lock-until-block",
-			"--blocks-before-expire",
-			"1",
-		]);
-
-		assert_eq!(
-			swap_tokens,
-			SwapTokens {
-				bridge: SwapTokensBridge::MillauToRialto,
-				source: SourceConnectionParams {
-					source_host: "127.0.0.1".into(),
-					source_port: 9000,
-					source_secure: false,
-					source_runtime_version: SourceRuntimeVersionParams {
-						source_version_mode: RuntimeVersionType::Bundle,
-						source_spec_version: None,
-						source_transaction_version: None,
-					}
-				},
-				source_sign: SourceSigningParams {
-					source_signer: Some("//Alice".into()),
-					source_signer_password: None,
-					source_signer_file: None,
-					source_signer_password_file: None,
-					source_transactions_mortality: None,
-				},
-				target: TargetConnectionParams {
-					target_host: "127.0.0.1".into(),
-					target_port: 9001,
-					target_secure: false,
-					target_runtime_version: TargetRuntimeVersionParams {
-						target_version_mode: RuntimeVersionType::Bundle,
-						target_spec_version: None,
-						target_transaction_version: None,
-					}
-				},
-				target_sign: TargetSigningParams {
-					target_signer: Some("//Bob".into()),
-					target_signer_password: None,
-					target_signer_file: None,
-					target_signer_password_file: None,
-					target_transactions_mortality: None,
-				},
-				swap_type: TokenSwapType::LockUntilBlock {
-					blocks_before_expire: 1,
-					swap_nonce: None,
-				},
-				source_balance: Balance(8000000000),
-				target_balance: Balance(9000000000),
-				target_to_source_conversion_rate_override: Some(ConversionRateOverride::Metric),
-				source_to_target_conversion_rate_override: Some(ConversionRateOverride::Explicit(
-					84.56
-				)),
-			}
-		);
-	}
-}
diff --git a/bridges/relays/client-kusama/Cargo.toml b/bridges/relays/client-kusama/Cargo.toml
index 8ab3a27fd7c9928a3588d633a5481d154d8fd342..f6aee9dae2200d22c1e9f6890ddb98653d114f0b 100644
--- a/bridges/relays/client-kusama/Cargo.toml
+++ b/bridges/relays/client-kusama/Cargo.toml
@@ -15,13 +15,11 @@ scale-info = { version = "2.1.1", features = ["derive"] }
 
 bp-header-chain = { path = "../../primitives/header-chain" }
 bp-kusama = { path = "../../primitives/chain-kusama" }
-bp-message-dispatch = { path = "../../primitives/message-dispatch" }
 bp-messages = { path = "../../primitives/messages" }
 bp-polkadot = { path = "../../primitives/chain-polkadot" }
 bp-polkadot-core = { path = "../../primitives/polkadot-core" }
 bp-runtime = { path = "../../primitives/runtime" }
 bridge-runtime-common = { path = "../../bin/runtime-common" }
-pallet-bridge-dispatch = { path = "../../modules/dispatch" }
 
 # Substrate Dependencies
 
diff --git a/bridges/relays/client-kusama/src/runtime.rs b/bridges/relays/client-kusama/src/runtime.rs
index 59a919e6cb97164a20d959c5d9de8313b694f098..370486d1b834718130b1733e16fbb3a6be8723ab 100644
--- a/bridges/relays/client-kusama/src/runtime.rs
+++ b/bridges/relays/client-kusama/src/runtime.rs
@@ -27,30 +27,6 @@ use sp_runtime::FixedU128;
 /// Unchecked Kusama extrinsic.
 pub type UncheckedExtrinsic = bp_polkadot_core::UncheckedExtrinsic<Call>;
 
-/// Polkadot account ownership digest from Kusama.
-///
-/// The byte vector returned by this function should be signed with a Polkadot account private key.
-/// This way, the owner of `kusama_account_id` on Kusama proves that the Polkadot account private
-/// key is also under his control.
-pub fn kusama_to_polkadot_account_ownership_digest<Call, AccountId, SpecVersion>(
-	polkadot_call: &Call,
-	kusama_account_id: AccountId,
-	polkadot_spec_version: SpecVersion,
-) -> Vec<u8>
-where
-	Call: codec::Encode,
-	AccountId: codec::Encode,
-	SpecVersion: codec::Encode,
-{
-	pallet_bridge_dispatch::account_ownership_digest(
-		polkadot_call,
-		kusama_account_id,
-		polkadot_spec_version,
-		bp_runtime::KUSAMA_CHAIN_ID,
-		bp_runtime::POLKADOT_CHAIN_ID,
-	)
-}
-
 /// Kusama Runtime `Call` enum.
 ///
 /// The enum represents a subset of possible `Call`s we can send to Kusama chain.
@@ -115,16 +91,7 @@ pub enum BridgePolkadotMessagesCall {
 	#[codec(index = 2)]
 	update_pallet_parameter(BridgePolkadotMessagesParameter),
 	#[codec(index = 3)]
-	send_message(
-		LaneId,
-		bp_message_dispatch::MessagePayload<
-			bp_kusama::AccountId,
-			bp_polkadot::AccountId,
-			bp_polkadot::AccountPublic,
-			Vec<u8>,
-		>,
-		bp_kusama::Balance,
-	),
+	send_message(LaneId, Vec<u8>, bp_kusama::Balance),
 	#[codec(index = 5)]
 	receive_messages_proof(
 		bp_polkadot::AccountId,
diff --git a/bridges/relays/client-polkadot/Cargo.toml b/bridges/relays/client-polkadot/Cargo.toml
index 1d61f0b4cdcee731eac59c774b7e90bec9da2d93..d52ddd9adf4c8fd5ce263c7f4f828df8d8f44807 100644
--- a/bridges/relays/client-polkadot/Cargo.toml
+++ b/bridges/relays/client-polkadot/Cargo.toml
@@ -15,13 +15,11 @@ scale-info = { version = "2.1.1", features = ["derive"] }
 
 bp-header-chain = { path = "../../primitives/header-chain" }
 bp-kusama = { path = "../../primitives/chain-kusama" }
-bp-message-dispatch = { path = "../../primitives/message-dispatch" }
 bp-messages = { path = "../../primitives/messages" }
 bp-polkadot = { path = "../../primitives/chain-polkadot" }
 bp-polkadot-core = { path = "../../primitives/polkadot-core" }
 bp-runtime = { path = "../../primitives/runtime" }
 bridge-runtime-common = { path = "../../bin/runtime-common" }
-pallet-bridge-dispatch = { path = "../../modules/dispatch" }
 
 # Substrate Dependencies
 
diff --git a/bridges/relays/client-polkadot/src/runtime.rs b/bridges/relays/client-polkadot/src/runtime.rs
index fa45115a6b5c24da5464de7cff33fa5f4884d367..15421d94c699b3212741aa6ca3b3c1a522734bf8 100644
--- a/bridges/relays/client-polkadot/src/runtime.rs
+++ b/bridges/relays/client-polkadot/src/runtime.rs
@@ -27,30 +27,6 @@ use sp_runtime::FixedU128;
 /// Unchecked Polkadot extrinsic.
 pub type UncheckedExtrinsic = bp_polkadot_core::UncheckedExtrinsic<Call>;
 
-/// Kusama account ownership digest from Polkadot.
-///
-/// The byte vector returned by this function should be signed with a Kusama account private key.
-/// This way, the owner of `kusam_account_id` on Polkadot proves that the Kusama account private key
-/// is also under his control.
-pub fn polkadot_to_kusama_account_ownership_digest<Call, AccountId, SpecVersion>(
-	kusama_call: &Call,
-	kusam_account_id: AccountId,
-	kusama_spec_version: SpecVersion,
-) -> Vec<u8>
-where
-	Call: codec::Encode,
-	AccountId: codec::Encode,
-	SpecVersion: codec::Encode,
-{
-	pallet_bridge_dispatch::account_ownership_digest(
-		kusama_call,
-		kusam_account_id,
-		kusama_spec_version,
-		bp_runtime::POLKADOT_CHAIN_ID,
-		bp_runtime::KUSAMA_CHAIN_ID,
-	)
-}
-
 /// Polkadot Runtime `Call` enum.
 ///
 /// The enum represents a subset of possible `Call`s we can send to Polkadot chain.
@@ -115,16 +91,7 @@ pub enum BridgeKusamaMessagesCall {
 	#[codec(index = 2)]
 	update_pallet_parameter(BridgeKusamaMessagesParameter),
 	#[codec(index = 3)]
-	send_message(
-		LaneId,
-		bp_message_dispatch::MessagePayload<
-			bp_polkadot::AccountId,
-			bp_kusama::AccountId,
-			bp_kusama::AccountPublic,
-			Vec<u8>,
-		>,
-		bp_polkadot::Balance,
-	),
+	send_message(LaneId, Vec<u8>, bp_polkadot::Balance),
 	#[codec(index = 5)]
 	receive_messages_proof(
 		bp_kusama::AccountId,
diff --git a/bridges/relays/client-rococo/Cargo.toml b/bridges/relays/client-rococo/Cargo.toml
index a2d84c496077bfddedba69f048329d9f5ea58061..e806ad594c21a92d87f1577522b47552b7030e29 100644
--- a/bridges/relays/client-rococo/Cargo.toml
+++ b/bridges/relays/client-rococo/Cargo.toml
@@ -15,13 +15,11 @@ scale-info = { version = "2.1.1", features = ["derive"] }
 
 bridge-runtime-common = { path = "../../bin/runtime-common" }
 bp-header-chain = { path = "../../primitives/header-chain" }
-bp-message-dispatch = { path = "../../primitives/message-dispatch" }
 bp-messages = { path = "../../primitives/messages" }
 bp-polkadot-core = { path = "../../primitives/polkadot-core" }
 bp-rococo = { path = "../../primitives/chain-rococo" }
 bp-runtime = { path = "../../primitives/runtime" }
 bp-wococo = { path = "../../primitives/chain-wococo" }
-pallet-bridge-dispatch = { path = "../../modules/dispatch" }
 pallet-bridge-messages = { path = "../../modules/messages" }
 
 # Substrate Dependencies
diff --git a/bridges/relays/client-rococo/src/runtime.rs b/bridges/relays/client-rococo/src/runtime.rs
index b13808059964a2250e1c4a5edcb8b189e1632bd4..249e75a709ff52a6d3aad21e3309833bb19bc3bf 100644
--- a/bridges/relays/client-rococo/src/runtime.rs
+++ b/bridges/relays/client-rococo/src/runtime.rs
@@ -26,30 +26,6 @@ use scale_info::TypeInfo;
 /// Unchecked Rococo extrinsic.
 pub type UncheckedExtrinsic = bp_polkadot_core::UncheckedExtrinsic<Call>;
 
-/// Wococo account ownership digest from Rococo.
-///
-/// The byte vector returned by this function should be signed with a Wococo account private key.
-/// This way, the owner of `rococo_account_id` on Rococo proves that the Wococo account private key
-/// is also under his control.
-pub fn rococo_to_wococo_account_ownership_digest<Call, AccountId, SpecVersion>(
-	wococo_call: &Call,
-	rococo_account_id: AccountId,
-	wococo_spec_version: SpecVersion,
-) -> Vec<u8>
-where
-	Call: codec::Encode,
-	AccountId: codec::Encode,
-	SpecVersion: codec::Encode,
-{
-	pallet_bridge_dispatch::account_ownership_digest(
-		wococo_call,
-		rococo_account_id,
-		wococo_spec_version,
-		bp_runtime::ROCOCO_CHAIN_ID,
-		bp_runtime::WOCOCO_CHAIN_ID,
-	)
-}
-
 /// Rococo Runtime `Call` enum.
 ///
 /// The enum represents a subset of possible `Call`s we can send to Rococo chain.
@@ -107,16 +83,7 @@ pub enum BridgeGrandpaWococoCall {
 #[allow(non_camel_case_types)]
 pub enum BridgeWococoMessagesCall {
 	#[codec(index = 3)]
-	send_message(
-		LaneId,
-		bp_message_dispatch::MessagePayload<
-			bp_rococo::AccountId,
-			bp_wococo::AccountId,
-			bp_wococo::AccountPublic,
-			Vec<u8>,
-		>,
-		bp_rococo::Balance,
-	),
+	send_message(LaneId, Vec<u8>, bp_rococo::Balance),
 	#[codec(index = 5)]
 	receive_messages_proof(
 		bp_wococo::AccountId,
diff --git a/bridges/relays/client-wococo/Cargo.toml b/bridges/relays/client-wococo/Cargo.toml
index d9d892a9206d4467e3ed11429f17f5778e7fa9d1..b322849d94adcc1e6e063d103cfa911e0130aa68 100644
--- a/bridges/relays/client-wococo/Cargo.toml
+++ b/bridges/relays/client-wococo/Cargo.toml
@@ -14,13 +14,11 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive"
 # Bridge dependencies
 bridge-runtime-common = { path = "../../bin/runtime-common" }
 bp-header-chain = { path = "../../primitives/header-chain" }
-bp-message-dispatch = { path = "../../primitives/message-dispatch" }
 bp-messages = { path = "../../primitives/messages" }
 bp-polkadot-core = { path = "../../primitives/polkadot-core" }
 bp-rococo = { path = "../../primitives/chain-rococo" }
 bp-runtime = { path = "../../primitives/runtime" }
 bp-wococo = { path = "../../primitives/chain-wococo" }
-pallet-bridge-dispatch = { path = "../../modules/dispatch" }
 pallet-bridge-messages = { path = "../../modules/messages" }
 
 # Substrate Dependencies
diff --git a/bridges/relays/client-wococo/src/runtime.rs b/bridges/relays/client-wococo/src/runtime.rs
index b28e053086b161ccbdc32adc4fff01634d2a7ea7..f7b9c03bf9cd8f821f88820a9fe3c34f77d2fe6a 100644
--- a/bridges/relays/client-wococo/src/runtime.rs
+++ b/bridges/relays/client-wococo/src/runtime.rs
@@ -26,30 +26,6 @@ use scale_info::TypeInfo;
 /// Unchecked Wococo extrinsic.
 pub type UncheckedExtrinsic = bp_polkadot_core::UncheckedExtrinsic<Call>;
 
-/// Rococo account ownership digest from Wococo.
-///
-/// The byte vector returned by this function should be signed with a Rococo account private key.
-/// This way, the owner of `wococo_account_id` on Rococo proves that the Rococo account private key
-/// is also under his control.
-pub fn wococo_to_rococo_account_ownership_digest<Call, AccountId, SpecVersion>(
-	rococo_call: &Call,
-	wococo_account_id: AccountId,
-	rococo_spec_version: SpecVersion,
-) -> Vec<u8>
-where
-	Call: codec::Encode,
-	AccountId: codec::Encode,
-	SpecVersion: codec::Encode,
-{
-	pallet_bridge_dispatch::account_ownership_digest(
-		rococo_call,
-		wococo_account_id,
-		rococo_spec_version,
-		bp_runtime::WOCOCO_CHAIN_ID,
-		bp_runtime::ROCOCO_CHAIN_ID,
-	)
-}
-
 /// Wococo Runtime `Call` enum.
 ///
 /// The enum represents a subset of possible `Call`s we can send to Rococo chain.
@@ -107,16 +83,7 @@ pub enum BridgeGrandpaRococoCall {
 #[allow(non_camel_case_types)]
 pub enum BridgeRococoMessagesCall {
 	#[codec(index = 3)]
-	send_message(
-		LaneId,
-		bp_message_dispatch::MessagePayload<
-			bp_rococo::AccountId,
-			bp_wococo::AccountId,
-			bp_wococo::AccountPublic,
-			Vec<u8>,
-		>,
-		bp_rococo::Balance,
-	),
+	send_message(LaneId, Vec<u8>, bp_rococo::Balance),
 	#[codec(index = 5)]
 	receive_messages_proof(
 		bp_rococo::AccountId,