diff --git a/bridges/bin/millau/runtime/src/lib.rs b/bridges/bin/millau/runtime/src/lib.rs
index 09f17cf6cf53401a4c0e5ba55efef36f19823e7a..095250a55861a2399c48772a6905815f8cfde6eb 100644
--- a/bridges/bin/millau/runtime/src/lib.rs
+++ b/bridges/bin/millau/runtime/src/lib.rs
@@ -32,18 +32,8 @@ pub mod rialto_messages;
 pub mod rialto_parachain_messages;
 pub mod xcm_config;
 
-use crate::{
-	rialto_messages::{ToRialtoMessagePayload, WithRialtoMessageBridge},
-	rialto_parachain_messages::{
-		ToRialtoParachainMessagePayload, WithRialtoParachainMessageBridge,
-	},
-};
-
 use beefy_primitives::{crypto::AuthorityId as BeefyId, mmr::MmrLeafVersion, ValidatorSet};
 use bp_runtime::{HeaderId, HeaderIdProvider};
-use bridge_runtime_common::messages::{
-	source::estimate_message_dispatch_and_delivery_fee, MessageBridge,
-};
 use codec::Decode;
 use pallet_grandpa::{
 	fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList,
@@ -57,7 +47,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, Perquintill,
+	ApplyExtrinsicResult, FixedPointNumber, Perquintill,
 };
 use sp_std::prelude::*;
 #[cfg(feature = "std")]
@@ -476,9 +466,6 @@ parameter_types! {
 		bp_rialto::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX;
 	pub const MaxUnconfirmedMessagesAtInboundLane: bp_messages::MessageNonce =
 		bp_rialto::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX;
-	// `IdentityFee` is used by Millau => we may use weight directly
-	pub const GetDeliveryConfirmationTransactionFee: Balance =
-		bp_millau::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT.ref_time() as _;
 	pub const RootAccountForPayments: Option<AccountId> = None;
 	pub const RialtoChainId: bp_runtime::ChainId = bp_runtime::RIALTO_CHAIN_ID;
 	pub const RialtoParachainChainId: bp_runtime::ChainId = bp_runtime::RIALTO_PARACHAIN_CHAIN_ID;
@@ -490,17 +477,14 @@ pub type WithRialtoMessagesInstance = ();
 impl pallet_bridge_messages::Config<WithRialtoMessagesInstance> for Runtime {
 	type RuntimeEvent = RuntimeEvent;
 	type WeightInfo = pallet_bridge_messages::weights::BridgeWeight<Runtime>;
-	type Parameter = rialto_messages::MillauToRialtoMessagesParameter;
 	type MaxMessagesToPruneAtOnce = MaxMessagesToPruneAtOnce;
 	type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane;
 	type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane;
 
 	type MaximalOutboundPayloadSize = crate::rialto_messages::ToRialtoMaximalOutboundPayloadSize;
 	type OutboundPayload = crate::rialto_messages::ToRialtoMessagePayload;
-	type OutboundMessageFee = Balance;
 
 	type InboundPayload = crate::rialto_messages::FromRialtoMessagePayload;
-	type InboundMessageFee = bp_rialto::Balance;
 	type InboundRelayer = bp_rialto::AccountId;
 
 	type TargetHeaderChain = crate::rialto_messages::Rialto;
@@ -509,7 +493,6 @@ impl pallet_bridge_messages::Config<WithRialtoMessagesInstance> for Runtime {
 		pallet_bridge_relayers::MessageDeliveryAndDispatchPaymentAdapter<
 			Runtime,
 			WithRialtoMessagesInstance,
-			GetDeliveryConfirmationTransactionFee,
 		>;
 	type OnMessageAccepted = ();
 	type OnDeliveryConfirmed = ();
@@ -525,7 +508,6 @@ pub type WithRialtoParachainMessagesInstance = pallet_bridge_messages::Instance1
 impl pallet_bridge_messages::Config<WithRialtoParachainMessagesInstance> for Runtime {
 	type RuntimeEvent = RuntimeEvent;
 	type WeightInfo = pallet_bridge_messages::weights::BridgeWeight<Runtime>;
-	type Parameter = rialto_parachain_messages::MillauToRialtoParachainMessagesParameter;
 	type MaxMessagesToPruneAtOnce = MaxMessagesToPruneAtOnce;
 	type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane;
 	type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane;
@@ -533,10 +515,8 @@ impl pallet_bridge_messages::Config<WithRialtoParachainMessagesInstance> for Run
 	type MaximalOutboundPayloadSize =
 		crate::rialto_parachain_messages::ToRialtoParachainMaximalOutboundPayloadSize;
 	type OutboundPayload = crate::rialto_parachain_messages::ToRialtoParachainMessagePayload;
-	type OutboundMessageFee = Balance;
 
 	type InboundPayload = crate::rialto_parachain_messages::FromRialtoParachainMessagePayload;
-	type InboundMessageFee = bp_rialto_parachain::Balance;
 	type InboundRelayer = bp_rialto_parachain::AccountId;
 
 	type TargetHeaderChain = crate::rialto_parachain_messages::RialtoParachain;
@@ -545,7 +525,6 @@ impl pallet_bridge_messages::Config<WithRialtoParachainMessagesInstance> for Run
 		pallet_bridge_relayers::MessageDeliveryAndDispatchPaymentAdapter<
 			Runtime,
 			WithRialtoParachainMessagesInstance,
-			GetDeliveryConfirmationTransactionFee,
 		>;
 	type OnMessageAccepted = ();
 	type OnDeliveryConfirmed = ();
@@ -941,24 +920,12 @@ impl_runtime_apis! {
 		}
 	}
 
-	impl bp_rialto::ToRialtoOutboundLaneApi<Block, Balance, ToRialtoMessagePayload> for Runtime {
-		fn estimate_message_delivery_and_dispatch_fee(
-			_lane_id: bp_messages::LaneId,
-			payload: ToRialtoMessagePayload,
-			rialto_to_this_conversion_rate: Option<FixedU128>,
-		) -> Option<Balance> {
-			estimate_message_dispatch_and_delivery_fee::<WithRialtoMessageBridge>(
-				&payload,
-				WithRialtoMessageBridge::RELAYER_FEE_PERCENT,
-				rialto_to_this_conversion_rate,
-			).ok()
-		}
-
+	impl bp_rialto::ToRialtoOutboundLaneApi<Block> for Runtime {
 		fn message_details(
 			lane: bp_messages::LaneId,
 			begin: bp_messages::MessageNonce,
 			end: bp_messages::MessageNonce,
-		) -> Vec<bp_messages::OutboundMessageDetails<Balance>> {
+		) -> Vec<bp_messages::OutboundMessageDetails> {
 			bridge_runtime_common::messages_api::outbound_message_details::<
 				Runtime,
 				WithRialtoMessagesInstance,
@@ -966,10 +933,10 @@ impl_runtime_apis! {
 		}
 	}
 
-	impl bp_rialto::FromRialtoInboundLaneApi<Block, bp_rialto::Balance> for Runtime {
+	impl bp_rialto::FromRialtoInboundLaneApi<Block> for Runtime {
 		fn message_details(
 			lane: bp_messages::LaneId,
-			messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails<bp_rialto::Balance>)>,
+			messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails)>,
 		) -> Vec<bp_messages::InboundMessageDetails> {
 			bridge_runtime_common::messages_api::inbound_message_details::<
 				Runtime,
@@ -978,24 +945,12 @@ impl_runtime_apis! {
 		}
 	}
 
-	impl bp_rialto_parachain::ToRialtoParachainOutboundLaneApi<Block, Balance, ToRialtoParachainMessagePayload> for Runtime {
-		fn estimate_message_delivery_and_dispatch_fee(
-			_lane_id: bp_messages::LaneId,
-			payload: ToRialtoParachainMessagePayload,
-			rialto_parachain_to_this_conversion_rate: Option<FixedU128>,
-		) -> Option<Balance> {
-			estimate_message_dispatch_and_delivery_fee::<WithRialtoParachainMessageBridge>(
-				&payload,
-				WithRialtoParachainMessageBridge::RELAYER_FEE_PERCENT,
-				rialto_parachain_to_this_conversion_rate,
-			).ok()
-		}
-
+	impl bp_rialto_parachain::ToRialtoParachainOutboundLaneApi<Block> for Runtime {
 		fn message_details(
 			lane: bp_messages::LaneId,
 			begin: bp_messages::MessageNonce,
 			end: bp_messages::MessageNonce,
-		) -> Vec<bp_messages::OutboundMessageDetails<Balance>> {
+		) -> Vec<bp_messages::OutboundMessageDetails> {
 			bridge_runtime_common::messages_api::outbound_message_details::<
 				Runtime,
 				WithRialtoParachainMessagesInstance,
@@ -1003,10 +958,10 @@ impl_runtime_apis! {
 		}
 	}
 
-	impl bp_rialto_parachain::FromRialtoParachainInboundLaneApi<Block, bp_rialto_parachain::Balance> for Runtime {
+	impl bp_rialto_parachain::FromRialtoParachainInboundLaneApi<Block> for Runtime {
 		fn message_details(
 			lane: bp_messages::LaneId,
-			messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails<bp_rialto_parachain::Balance>)>,
+			messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails)>,
 		) -> Vec<bp_messages::InboundMessageDetails> {
 			bridge_runtime_common::messages_api::inbound_message_details::<
 				Runtime,
@@ -1060,13 +1015,11 @@ impl_runtime_apis! {
 			let mut batches = Vec::<BenchmarkBatch>::new();
 			let params = (&config, &whitelist);
 
-			use bridge_runtime_common::messages_benchmarking::{prepare_message_delivery_proof, prepare_message_proof, prepare_outbound_message};
-			use bridge_runtime_common::messages;
+			use bridge_runtime_common::messages_benchmarking::{prepare_message_delivery_proof, prepare_message_proof};
 			use pallet_bridge_messages::benchmarking::{
 				Pallet as MessagesBench,
 				Config as MessagesConfig,
 				MessageDeliveryProofParams,
-				MessageParams,
 				MessageProofParams,
 			};
 			use pallet_bridge_parachains::benchmarking::{
@@ -1076,18 +1029,10 @@ impl_runtime_apis! {
 			use rialto_messages::WithRialtoMessageBridge;
 
 			impl MessagesConfig<WithRialtoMessagesInstance> for Runtime {
-				fn maximal_message_size() -> u32 {
-					messages::source::maximal_message_size::<WithRialtoMessageBridge>()
-				}
-
 				fn bridged_relayer_id() -> Self::InboundRelayer {
 					[0u8; 32].into()
 				}
 
-				fn account_balance(account: &Self::AccountId) -> Self::OutboundMessageFee {
-					pallet_balances::Pallet::<Runtime>::free_balance(account)
-				}
-
 				fn endow_account(account: &Self::AccountId) {
 					pallet_balances::Pallet::<Runtime>::make_free_balance_be(
 						account,
@@ -1095,12 +1040,6 @@ impl_runtime_apis! {
 					);
 				}
 
-				fn prepare_outbound_message(
-					params: MessageParams<Self::AccountId>,
-				) -> (rialto_messages::ToRialtoMessagePayload, Balance) {
-					(prepare_outbound_message::<WithRialtoMessageBridge>(params), Self::message_fee())
-				}
-
 				fn prepare_message_proof(
 					params: MessageProofParams,
 				) -> (rialto_messages::FromRialtoMessagesProof, Weight) {
diff --git a/bridges/bin/millau/runtime/src/rialto_messages.rs b/bridges/bin/millau/runtime/src/rialto_messages.rs
index c6bc308a8e81958072a120f6c73d8770d3f32bc2..c0868298a3276d898f2a335769a67ac57445d286 100644
--- a/bridges/bin/millau/runtime/src/rialto_messages.rs
+++ b/bridges/bin/millau/runtime/src/rialto_messages.rs
@@ -21,35 +21,20 @@ use crate::{OriginCaller, RialtoGrandpaInstance, Runtime, RuntimeCall, RuntimeOr
 use bp_messages::{
 	source_chain::TargetHeaderChain,
 	target_chain::{ProvedMessages, SourceHeaderChain},
-	InboundLaneData, LaneId, Message, MessageNonce, Parameter as MessagesParameter,
+	InboundLaneData, LaneId, Message, MessageNonce,
 };
 use bp_runtime::{ChainId, MILLAU_CHAIN_ID, RIALTO_CHAIN_ID};
-use bridge_runtime_common::messages::{
-	self, BasicConfirmationTransactionEstimation, MessageBridge, MessageTransaction,
-};
-use codec::{Decode, Encode};
-use frame_support::{dispatch::DispatchClass, parameter_types, weights::Weight, RuntimeDebug};
-use scale_info::TypeInfo;
-use sp_runtime::{traits::Saturating, FixedPointNumber, FixedU128};
-use sp_std::convert::TryFrom;
+use bridge_runtime_common::messages::{self, MessageBridge};
+use frame_support::{parameter_types, weights::Weight, RuntimeDebug};
 
 /// Default lane that is used to send messages to Rialto.
 pub const DEFAULT_XCM_LANE_TO_RIALTO: LaneId = [0, 0, 0, 0];
-/// Initial value of `RialtoToMillauConversionRate` parameter.
-pub const INITIAL_RIALTO_TO_MILLAU_CONVERSION_RATE: FixedU128 =
-	FixedU128::from_inner(FixedU128::DIV);
-/// Initial value of `RialtoFeeMultiplier` parameter.
-pub const INITIAL_RIALTO_FEE_MULTIPLIER: FixedU128 = FixedU128::from_inner(FixedU128::DIV);
 /// Weight of 2 XCM instructions is for simple `Trap(42)` program, coming through bridge
 /// (it is prepended with `UniversalOrigin` instruction). It is used just for simplest manual
 /// tests, confirming that we don't break encoding somewhere between.
 pub const BASE_XCM_WEIGHT_TWICE: u64 = 2 * crate::xcm_config::BASE_XCM_WEIGHT;
 
 parameter_types! {
-	/// Rialto to Millau conversion rate. Initially we treat both tokens as equal.
-	pub storage RialtoToMillauConversionRate: FixedU128 = INITIAL_RIALTO_TO_MILLAU_CONVERSION_RATE;
-	/// Fee multiplier value at Rialto chain.
-	pub storage RialtoFeeMultiplier: FixedU128 = INITIAL_RIALTO_FEE_MULTIPLIER;
 	/// Weight credit for our test messages.
 	///
 	/// 2 XCM instructions is for simple `Trap(42)` program, coming through bridge
@@ -91,7 +76,6 @@ pub type ToRialtoMaximalOutboundPayloadSize =
 pub struct WithRialtoMessageBridge;
 
 impl MessageBridge for WithRialtoMessageBridge {
-	const RELAYER_FEE_PERCENT: u32 = 10;
 	const THIS_CHAIN_ID: ChainId = MILLAU_CHAIN_ID;
 	const BRIDGED_CHAIN_ID: ChainId = RIALTO_CHAIN_ID;
 	const BRIDGED_MESSAGES_PALLET_NAME: &'static str = bp_millau::WITH_MILLAU_MESSAGES_PALLET_NAME;
@@ -100,16 +84,6 @@ impl MessageBridge for WithRialtoMessageBridge {
 	type BridgedChain = Rialto;
 	type BridgedHeaderChain =
 		pallet_bridge_grandpa::GrandpaChainHeaders<Runtime, RialtoGrandpaInstance>;
-
-	fn bridged_balance_to_this_balance(
-		bridged_balance: bp_rialto::Balance,
-		bridged_to_this_conversion_rate_override: Option<FixedU128>,
-	) -> bp_millau::Balance {
-		let conversion_rate = bridged_to_this_conversion_rate_override
-			.unwrap_or_else(RialtoToMillauConversionRate::get);
-		bp_millau::Balance::try_from(conversion_rate.saturating_mul_int(bridged_balance))
-			.unwrap_or(bp_millau::Balance::MAX)
-	}
 }
 
 /// Millau chain from message lane point of view.
@@ -123,12 +97,6 @@ impl messages::UnderlyingChainProvider for Millau {
 impl messages::ThisChainWithMessages for Millau {
 	type RuntimeOrigin = RuntimeOrigin;
 	type RuntimeCall = RuntimeCall;
-	type ConfirmationTransactionEstimation = BasicConfirmationTransactionEstimation<
-		bp_millau::AccountId,
-		{ bp_millau::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT.ref_time() },
-		{ bp_rialto::EXTRA_STORAGE_PROOF_SIZE },
-		{ bp_millau::TX_EXTRA_BYTES },
-	>;
 
 	fn is_message_accepted(send_origin: &Self::RuntimeOrigin, lane: &LaneId) -> bool {
 		let here_location =
@@ -153,21 +121,6 @@ impl messages::ThisChainWithMessages for Millau {
 	fn maximal_pending_messages_at_outbound_lane() -> MessageNonce {
 		MessageNonce::MAX
 	}
-
-	fn transaction_payment(transaction: MessageTransaction<Weight>) -> bp_millau::Balance {
-		// `transaction` may represent transaction from the future, when multiplier value will
-		// be larger, so let's use slightly increased value
-		let multiplier = FixedU128::saturating_from_rational(110, 100)
-			.saturating_mul(pallet_transaction_payment::Pallet::<Runtime>::next_fee_multiplier());
-		// in our testnets, both per-byte fee and weight-to-fee are 1:1
-		messages::transaction_payment(
-			bp_millau::BlockWeights::get().get(DispatchClass::Normal).base_extrinsic,
-			1,
-			multiplier,
-			|weight| weight.ref_time() as _,
-			transaction,
-		)
-	}
 }
 
 /// Rialto chain from message lane point of view.
@@ -182,45 +135,6 @@ impl messages::BridgedChainWithMessages for Rialto {
 	fn verify_dispatch_weight(_message_payload: &[u8]) -> bool {
 		true
 	}
-
-	fn estimate_delivery_transaction(
-		message_payload: &[u8],
-		include_pay_dispatch_fee_cost: bool,
-		message_dispatch_weight: Weight,
-	) -> MessageTransaction<Weight> {
-		let message_payload_len = u32::try_from(message_payload.len()).unwrap_or(u32::MAX);
-		let extra_bytes_in_payload = message_payload_len
-			.saturating_sub(pallet_bridge_messages::EXPECTED_DEFAULT_MESSAGE_LENGTH);
-
-		MessageTransaction {
-			dispatch_weight: bp_rialto::ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT
-				.saturating_mul(extra_bytes_in_payload as u64)
-				.saturating_add(bp_rialto::DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT)
-				.saturating_sub(if include_pay_dispatch_fee_cost {
-					Weight::from_ref_time(0)
-				} else {
-					bp_rialto::PAY_INBOUND_DISPATCH_FEE_WEIGHT
-				})
-				.saturating_add(message_dispatch_weight),
-			size: message_payload_len
-				.saturating_add(bp_millau::EXTRA_STORAGE_PROOF_SIZE)
-				.saturating_add(bp_rialto::TX_EXTRA_BYTES),
-		}
-	}
-
-	fn transaction_payment(transaction: MessageTransaction<Weight>) -> bp_rialto::Balance {
-		// we don't have a direct access to the value of multiplier at Rialto chain
-		// => it is a messages module parameter
-		let multiplier = RialtoFeeMultiplier::get();
-		// in our testnets, both per-byte fee and weight-to-fee are 1:1
-		messages::transaction_payment(
-			bp_rialto::BlockWeights::get().get(DispatchClass::Normal).base_extrinsic,
-			1,
-			multiplier,
-			|weight| weight.ref_time() as _,
-			transaction,
-		)
-	}
 }
 
 impl TargetHeaderChain<ToRialtoMessagePayload, bp_millau::AccountId> for Rialto {
@@ -242,7 +156,7 @@ impl TargetHeaderChain<ToRialtoMessagePayload, bp_millau::AccountId> for Rialto
 	}
 }
 
-impl SourceHeaderChain<bp_rialto::Balance> for Rialto {
+impl SourceHeaderChain for Rialto {
 	type Error = &'static str;
 	// The proof is:
 	// - hash of the header this proof has been created with;
@@ -254,28 +168,12 @@ impl SourceHeaderChain<bp_rialto::Balance> for Rialto {
 	fn verify_messages_proof(
 		proof: Self::MessagesProof,
 		messages_count: u32,
-	) -> Result<ProvedMessages<Message<bp_rialto::Balance>>, Self::Error> {
+	) -> Result<ProvedMessages<Message>, Self::Error> {
 		messages::target::verify_messages_proof::<WithRialtoMessageBridge>(proof, messages_count)
 			.map_err(Into::into)
 	}
 }
 
-/// Millau -> Rialto message lane pallet parameters.
-#[derive(RuntimeDebug, Clone, Encode, Decode, PartialEq, Eq, TypeInfo)]
-pub enum MillauToRialtoMessagesParameter {
-	/// The conversion formula we use is: `MillauTokens = RialtoTokens * conversion_rate`.
-	RialtoToMillauConversionRate(FixedU128),
-}
-
-impl MessagesParameter for MillauToRialtoMessagesParameter {
-	fn save(&self) {
-		match *self {
-			MillauToRialtoMessagesParameter::RialtoToMillauConversionRate(ref conversion_rate) =>
-				RialtoToMillauConversionRate::set(conversion_rate),
-		}
-	}
-}
-
 #[cfg(test)]
 mod tests {
 	use super::*;
@@ -295,13 +193,7 @@ mod tests {
 	fn ensure_millau_message_lane_weights_are_correct() {
 		type Weights = pallet_bridge_messages::weights::BridgeWeight<Runtime>;
 
-		pallet_bridge_messages::ensure_weights_are_correct::<Weights>(
-			bp_millau::DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT,
-			bp_millau::ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT,
-			bp_millau::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT,
-			bp_millau::PAY_INBOUND_DISPATCH_FEE_WEIGHT,
-			DbWeight::get(),
-		);
+		pallet_bridge_messages::ensure_weights_are_correct::<Weights>();
 
 		let max_incoming_message_proof_size = bp_rialto::EXTRA_STORAGE_PROOF_SIZE.saturating_add(
 			messages::target::maximal_incoming_message_size(bp_millau::Millau::max_extrinsic_size()),
@@ -366,13 +258,5 @@ mod tests {
 					bp_rialto::WITH_RIALTO_MESSAGES_PALLET_NAME,
 			},
 		});
-
-		assert_eq!(
-			RialtoToMillauConversionRate::key().to_vec(),
-			bp_runtime::storage_parameter_key(
-				bp_millau::RIALTO_TO_MILLAU_CONVERSION_RATE_PARAMETER_NAME
-			)
-			.0,
-		);
 	}
 }
diff --git a/bridges/bin/millau/runtime/src/rialto_parachain_messages.rs b/bridges/bin/millau/runtime/src/rialto_parachain_messages.rs
index da4ca9d83cb2e5a646282f38c7282e56acd5a6e0..8655edd59f491979cba220298bb6c7970109bfd5 100644
--- a/bridges/bin/millau/runtime/src/rialto_parachain_messages.rs
+++ b/bridges/bin/millau/runtime/src/rialto_parachain_messages.rs
@@ -21,17 +21,11 @@ use crate::{Runtime, RuntimeCall, RuntimeOrigin, WithRialtoParachainsInstance};
 use bp_messages::{
 	source_chain::TargetHeaderChain,
 	target_chain::{ProvedMessages, SourceHeaderChain},
-	InboundLaneData, LaneId, Message, MessageNonce, Parameter as MessagesParameter,
+	InboundLaneData, LaneId, Message, MessageNonce,
 };
 use bp_runtime::{ChainId, MILLAU_CHAIN_ID, RIALTO_PARACHAIN_CHAIN_ID};
-use bridge_runtime_common::messages::{
-	self, BasicConfirmationTransactionEstimation, MessageBridge, MessageTransaction,
-};
-use codec::{Decode, Encode};
-use frame_support::{dispatch::DispatchClass, parameter_types, weights::Weight, RuntimeDebug};
-use scale_info::TypeInfo;
-use sp_runtime::{traits::Saturating, FixedPointNumber, FixedU128};
-use sp_std::convert::TryFrom;
+use bridge_runtime_common::messages::{self, MessageBridge};
+use frame_support::{parameter_types, weights::Weight, RuntimeDebug};
 
 /// Default lane that is used to send messages to Rialto parachain.
 pub const DEFAULT_XCM_LANE_TO_RIALTO_PARACHAIN: LaneId = [0, 0, 0, 0];
@@ -40,18 +34,7 @@ pub const DEFAULT_XCM_LANE_TO_RIALTO_PARACHAIN: LaneId = [0, 0, 0, 0];
 /// tests, confirming that we don't break encoding somewhere between.
 pub const BASE_XCM_WEIGHT_TWICE: u64 = 2 * crate::xcm_config::BASE_XCM_WEIGHT;
 
-/// Initial value of `RialtoParachainToMillauConversionRate` parameter.
-pub const INITIAL_RIALTO_PARACHAIN_TO_MILLAU_CONVERSION_RATE: FixedU128 =
-	FixedU128::from_inner(FixedU128::DIV);
-/// Initial value of `RialtoParachainFeeMultiplier` parameter.
-pub const INITIAL_RIALTO_PARACHAIN_FEE_MULTIPLIER: FixedU128 =
-	FixedU128::from_inner(FixedU128::DIV);
-
 parameter_types! {
-	/// RialtoParachain to Millau conversion rate. Initially we treat both tokens as equal.
-	pub storage RialtoParachainToMillauConversionRate: FixedU128 = INITIAL_RIALTO_PARACHAIN_TO_MILLAU_CONVERSION_RATE;
-	/// Fee multiplier value at RialtoParachain chain.
-	pub storage RialtoParachainFeeMultiplier: FixedU128 = INITIAL_RIALTO_PARACHAIN_FEE_MULTIPLIER;
 	/// Weight credit for our test messages.
 	///
 	/// 2 XCM instructions is for simple `Trap(42)` program, coming through bridge
@@ -95,7 +78,6 @@ pub type ToRialtoParachainMaximalOutboundPayloadSize =
 pub struct WithRialtoParachainMessageBridge;
 
 impl MessageBridge for WithRialtoParachainMessageBridge {
-	const RELAYER_FEE_PERCENT: u32 = 10;
 	const THIS_CHAIN_ID: ChainId = MILLAU_CHAIN_ID;
 	const BRIDGED_CHAIN_ID: ChainId = RIALTO_PARACHAIN_CHAIN_ID;
 	const BRIDGED_MESSAGES_PALLET_NAME: &'static str = bp_millau::WITH_MILLAU_MESSAGES_PALLET_NAME;
@@ -107,16 +89,6 @@ impl MessageBridge for WithRialtoParachainMessageBridge {
 		WithRialtoParachainsInstance,
 		bp_rialto_parachain::RialtoParachain,
 	>;
-
-	fn bridged_balance_to_this_balance(
-		bridged_balance: bp_rialto_parachain::Balance,
-		bridged_to_this_conversion_rate_override: Option<FixedU128>,
-	) -> bp_millau::Balance {
-		let conversion_rate = bridged_to_this_conversion_rate_override
-			.unwrap_or_else(RialtoParachainToMillauConversionRate::get);
-		bp_millau::Balance::try_from(conversion_rate.saturating_mul_int(bridged_balance))
-			.unwrap_or(bp_millau::Balance::MAX)
-	}
 }
 
 /// Millau chain from message lane point of view.
@@ -130,12 +102,6 @@ impl messages::UnderlyingChainProvider for Millau {
 impl messages::ThisChainWithMessages for Millau {
 	type RuntimeCall = RuntimeCall;
 	type RuntimeOrigin = RuntimeOrigin;
-	type ConfirmationTransactionEstimation = BasicConfirmationTransactionEstimation<
-		bp_rialto_parachain::AccountId,
-		{ bp_millau::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT.ref_time() },
-		{ bp_rialto_parachain::EXTRA_STORAGE_PROOF_SIZE },
-		{ bp_millau::TX_EXTRA_BYTES },
-	>;
 
 	fn is_message_accepted(_send_origin: &Self::RuntimeOrigin, lane: &LaneId) -> bool {
 		*lane == DEFAULT_XCM_LANE_TO_RIALTO_PARACHAIN || *lane == [0, 0, 0, 1]
@@ -144,21 +110,6 @@ impl messages::ThisChainWithMessages for Millau {
 	fn maximal_pending_messages_at_outbound_lane() -> MessageNonce {
 		MessageNonce::MAX
 	}
-
-	fn transaction_payment(transaction: MessageTransaction<Weight>) -> bp_millau::Balance {
-		// `transaction` may represent transaction from the future, when multiplier value will
-		// be larger, so let's use slightly increased value
-		let multiplier = FixedU128::saturating_from_rational(110, 100)
-			.saturating_mul(pallet_transaction_payment::Pallet::<Runtime>::next_fee_multiplier());
-		// in our testnets, both per-byte fee and weight-to-fee are 1:1
-		messages::transaction_payment(
-			bp_millau::BlockWeights::get().get(DispatchClass::Normal).base_extrinsic,
-			1,
-			multiplier,
-			|weight| weight.ref_time() as _,
-			transaction,
-		)
-	}
 }
 
 /// RialtoParachain chain from message lane point of view.
@@ -173,49 +124,6 @@ impl messages::BridgedChainWithMessages for RialtoParachain {
 	fn verify_dispatch_weight(_message_payload: &[u8]) -> bool {
 		true
 	}
-
-	fn estimate_delivery_transaction(
-		message_payload: &[u8],
-		include_pay_dispatch_fee_cost: bool,
-		message_dispatch_weight: Weight,
-	) -> MessageTransaction<Weight> {
-		let message_payload_len = u32::try_from(message_payload.len()).unwrap_or(u32::MAX);
-		let extra_bytes_in_payload = message_payload_len
-			.saturating_sub(pallet_bridge_messages::EXPECTED_DEFAULT_MESSAGE_LENGTH);
-
-		MessageTransaction {
-			dispatch_weight: bp_rialto_parachain::ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT
-				.saturating_mul(extra_bytes_in_payload as _)
-				.saturating_add(bp_rialto_parachain::DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT)
-				.saturating_sub(if include_pay_dispatch_fee_cost {
-					Weight::from_ref_time(0)
-				} else {
-					bp_rialto_parachain::PAY_INBOUND_DISPATCH_FEE_WEIGHT
-				})
-				.saturating_add(message_dispatch_weight),
-			size: message_payload_len
-				.saturating_add(bp_millau::EXTRA_STORAGE_PROOF_SIZE)
-				.saturating_add(bp_rialto_parachain::TX_EXTRA_BYTES),
-		}
-	}
-
-	fn transaction_payment(
-		transaction: MessageTransaction<Weight>,
-	) -> bp_rialto_parachain::Balance {
-		// we don't have a direct access to the value of multiplier at RialtoParachain chain
-		// => it is a messages module parameter
-		let multiplier = RialtoParachainFeeMultiplier::get();
-		// in our testnets, both per-byte fee and weight-to-fee are 1:1
-		messages::transaction_payment(
-			bp_rialto_parachain::BlockWeights::get()
-				.get(DispatchClass::Normal)
-				.base_extrinsic,
-			1,
-			multiplier,
-			|weight| weight.ref_time() as _,
-			transaction,
-		)
-	}
 }
 
 impl TargetHeaderChain<ToRialtoParachainMessagePayload, bp_millau::AccountId> for RialtoParachain {
@@ -237,7 +145,7 @@ impl TargetHeaderChain<ToRialtoParachainMessagePayload, bp_millau::AccountId> fo
 	}
 }
 
-impl SourceHeaderChain<bp_rialto_parachain::Balance> for RialtoParachain {
+impl SourceHeaderChain for RialtoParachain {
 	type Error = &'static str;
 	// The proof is:
 	// - hash of the header this proof has been created with;
@@ -249,7 +157,7 @@ impl SourceHeaderChain<bp_rialto_parachain::Balance> for RialtoParachain {
 	fn verify_messages_proof(
 		proof: Self::MessagesProof,
 		messages_count: u32,
-	) -> Result<ProvedMessages<Message<bp_rialto_parachain::Balance>>, Self::Error> {
+	) -> Result<ProvedMessages<Message>, Self::Error> {
 		messages::target::verify_messages_proof::<WithRialtoParachainMessageBridge>(
 			proof,
 			messages_count,
@@ -257,20 +165,3 @@ impl SourceHeaderChain<bp_rialto_parachain::Balance> for RialtoParachain {
 		.map_err(Into::into)
 	}
 }
-
-/// Millau -> RialtoParachain message lane pallet parameters.
-#[derive(RuntimeDebug, Clone, Encode, Decode, PartialEq, Eq, TypeInfo)]
-pub enum MillauToRialtoParachainMessagesParameter {
-	/// The conversion formula we use is: `MillauTokens = RialtoParachainTokens * conversion_rate`.
-	RialtoParachainToMillauConversionRate(FixedU128),
-}
-
-impl MessagesParameter for MillauToRialtoParachainMessagesParameter {
-	fn save(&self) {
-		match *self {
-			MillauToRialtoParachainMessagesParameter::RialtoParachainToMillauConversionRate(
-				ref conversion_rate,
-			) => RialtoParachainToMillauConversionRate::set(conversion_rate),
-		}
-	}
-}
diff --git a/bridges/bin/millau/runtime/src/xcm_config.rs b/bridges/bin/millau/runtime/src/xcm_config.rs
index 9a5851c8d05522c726231ef2b02ab844d7408f80..32b14f27a3b800793d478a21574f2a09f64a03a9 100644
--- a/bridges/bin/millau/runtime/src/xcm_config.rs
+++ b/bridges/bin/millau/runtime/src/xcm_config.rs
@@ -271,7 +271,7 @@ mod tests {
 	fn xcm_messages_are_sent_using_bridge_router() {
 		new_test_ext().execute_with(|| {
 			let xcm: Xcm<()> = vec![Instruction::Trap(42)].into();
-			let expected_fee = MultiAssets::from((Here, 4_259_858_152_u64));
+			let expected_fee = MultiAssets::from((Here, 1_000_000_u128));
 			let expected_hash =
 				([0u8, 0u8, 0u8, 0u8], 1u64).using_encoded(sp_io::hashing::blake2_256);
 
@@ -305,7 +305,7 @@ mod tests {
 
 			let mut incoming_message = DispatchMessage {
 				key: MessageKey { lane_id: [0, 0, 0, 0], nonce: 1 },
-				data: DispatchMessageData { payload: Ok((location, xcm).into()), fee: 0 },
+				data: DispatchMessageData { payload: Ok((location, xcm).into()) },
 			};
 
 			let dispatch_weight = MessageDispatcher::dispatch_weight(&mut incoming_message);
diff --git a/bridges/bin/rialto-parachain/runtime/src/lib.rs b/bridges/bin/rialto-parachain/runtime/src/lib.rs
index c427bfac59a84bd48d00b9d8238a70ae30fcf102..c5b9e50d067c0f235fc1573dc091d6088e4ec0da 100644
--- a/bridges/bin/rialto-parachain/runtime/src/lib.rs
+++ b/bridges/bin/rialto-parachain/runtime/src/lib.rs
@@ -26,14 +26,9 @@
 #[cfg(feature = "std")]
 include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
 
-use crate::millau_messages::{
-	ToMillauMessagePayload, WithMillauMessageBridge, DEFAULT_XCM_LANE_TO_MILLAU,
-};
+use crate::millau_messages::{WithMillauMessageBridge, DEFAULT_XCM_LANE_TO_MILLAU};
 
-use bridge_runtime_common::messages::{
-	source::{estimate_message_dispatch_and_delivery_fee, XcmBridge, XcmBridgeAdapter},
-	MessageBridge,
-};
+use bridge_runtime_common::messages::source::{XcmBridge, XcmBridgeAdapter};
 use cumulus_pallet_parachain_system::AnyRelayNumber;
 use sp_api::impl_runtime_apis;
 use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
@@ -41,7 +36,7 @@ use sp_runtime::{
 	create_runtime_str, generic, impl_opaque_keys,
 	traits::{AccountIdLookup, Block as BlockT},
 	transaction_validity::{TransactionSource, TransactionValidity},
-	ApplyExtrinsicResult, FixedU128,
+	ApplyExtrinsicResult,
 };
 
 use sp_std::prelude::*;
@@ -557,9 +552,6 @@ parameter_types! {
 		bp_millau::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX;
 	pub const MaxUnconfirmedMessagesAtInboundLane: bp_messages::MessageNonce =
 		bp_millau::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX;
-	// `IdentityFee` is used by Rialto => we may use weight directly
-	pub const GetDeliveryConfirmationTransactionFee: Balance =
-		bp_rialto_parachain::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT.ref_time() as _;
 	pub const RootAccountForPayments: Option<AccountId> = None;
 	pub const BridgedChainId: bp_runtime::ChainId = bp_runtime::MILLAU_CHAIN_ID;
 }
@@ -570,17 +562,14 @@ pub type WithMillauMessagesInstance = ();
 impl pallet_bridge_messages::Config<WithMillauMessagesInstance> for Runtime {
 	type RuntimeEvent = RuntimeEvent;
 	type WeightInfo = pallet_bridge_messages::weights::BridgeWeight<Runtime>;
-	type Parameter = millau_messages::RialtoParachainToMillauMessagesParameter;
 	type MaxMessagesToPruneAtOnce = MaxMessagesToPruneAtOnce;
 	type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane;
 	type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane;
 
 	type MaximalOutboundPayloadSize = crate::millau_messages::ToMillauMaximalOutboundPayloadSize;
 	type OutboundPayload = crate::millau_messages::ToMillauMessagePayload;
-	type OutboundMessageFee = Balance;
 
 	type InboundPayload = crate::millau_messages::FromMillauMessagePayload;
-	type InboundMessageFee = bp_millau::Balance;
 	type InboundRelayer = bp_millau::AccountId;
 
 	type TargetHeaderChain = crate::millau_messages::Millau;
@@ -589,7 +578,6 @@ impl pallet_bridge_messages::Config<WithMillauMessagesInstance> for Runtime {
 		pallet_bridge_relayers::MessageDeliveryAndDispatchPaymentAdapter<
 			Runtime,
 			WithMillauMessagesInstance,
-			GetDeliveryConfirmationTransactionFee,
 		>;
 	type OnMessageAccepted = ();
 	type OnDeliveryConfirmed = ();
@@ -748,24 +736,12 @@ impl_runtime_apis! {
 		}
 	}
 
-	impl bp_millau::ToMillauOutboundLaneApi<Block, Balance, ToMillauMessagePayload> for Runtime {
-		fn estimate_message_delivery_and_dispatch_fee(
-			_lane_id: bp_messages::LaneId,
-			payload: ToMillauMessagePayload,
-			millau_to_this_conversion_rate: Option<FixedU128>,
-		) -> Option<Balance> {
-			estimate_message_dispatch_and_delivery_fee::<WithMillauMessageBridge>(
-				&payload,
-				WithMillauMessageBridge::RELAYER_FEE_PERCENT,
-				millau_to_this_conversion_rate,
-			).ok()
-		}
-
+	impl bp_millau::ToMillauOutboundLaneApi<Block> for Runtime {
 		fn message_details(
 			lane: bp_messages::LaneId,
 			begin: bp_messages::MessageNonce,
 			end: bp_messages::MessageNonce,
-		) -> Vec<bp_messages::OutboundMessageDetails<Balance>> {
+		) -> Vec<bp_messages::OutboundMessageDetails> {
 			bridge_runtime_common::messages_api::outbound_message_details::<
 				Runtime,
 				WithMillauMessagesInstance,
@@ -773,10 +749,10 @@ impl_runtime_apis! {
 		}
 	}
 
-	impl bp_millau::FromMillauInboundLaneApi<Block, bp_millau::Balance> for Runtime {
+	impl bp_millau::FromMillauInboundLaneApi<Block> for Runtime {
 		fn message_details(
 			lane: bp_messages::LaneId,
-			messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails<bp_millau::Balance>)>,
+			messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails)>,
 		) -> Vec<bp_messages::InboundMessageDetails> {
 			bridge_runtime_common::messages_api::inbound_message_details::<
 				Runtime,
@@ -882,7 +858,7 @@ mod tests {
 			let xcm: Xcm<()> = vec![Instruction::Trap(42)].into();
 
 			let send_result = send_xcm::<XcmRouter>(dest.into(), xcm);
-			let expected_fee = MultiAssets::from((Here, Fungibility::Fungible(4_259_858_152_u128)));
+			let expected_fee = MultiAssets::from((Here, Fungibility::Fungible(1_000_000_u128)));
 			let expected_hash =
 				([0u8, 0u8, 0u8, 0u8], 1u64).using_encoded(sp_io::hashing::blake2_256);
 			assert_eq!(send_result, Ok((expected_hash, expected_fee)),);
@@ -906,7 +882,7 @@ mod tests {
 
 			let mut incoming_message = DispatchMessage {
 				key: MessageKey { lane_id: [0, 0, 0, 0], nonce: 1 },
-				data: DispatchMessageData { payload: Ok((location, xcm).into()), fee: 0 },
+				data: DispatchMessageData { payload: Ok((location, xcm).into()) },
 			};
 
 			let dispatch_weight = MessageDispatcher::dispatch_weight(&mut incoming_message);
diff --git a/bridges/bin/rialto-parachain/runtime/src/millau_messages.rs b/bridges/bin/rialto-parachain/runtime/src/millau_messages.rs
index 60bc038339620206087a1a1b78e461045990a211..ceabcd57b6663f21dfb6efaf5227c1aece01e1a7 100644
--- a/bridges/bin/rialto-parachain/runtime/src/millau_messages.rs
+++ b/bridges/bin/rialto-parachain/runtime/src/millau_messages.rs
@@ -24,35 +24,20 @@ use crate::{MillauGrandpaInstance, OriginCaller, Runtime, RuntimeCall, RuntimeOr
 use bp_messages::{
 	source_chain::TargetHeaderChain,
 	target_chain::{ProvedMessages, SourceHeaderChain},
-	InboundLaneData, LaneId, Message, MessageNonce, Parameter as MessagesParameter,
+	InboundLaneData, LaneId, Message, MessageNonce,
 };
 use bp_runtime::{ChainId, MILLAU_CHAIN_ID, RIALTO_PARACHAIN_CHAIN_ID};
-use bridge_runtime_common::messages::{
-	self, BasicConfirmationTransactionEstimation, MessageBridge, MessageTransaction,
-};
-use codec::{Decode, Encode};
-use frame_support::{dispatch::DispatchClass, parameter_types, weights::Weight, RuntimeDebug};
-use scale_info::TypeInfo;
-use sp_runtime::{traits::Saturating, FixedPointNumber, FixedU128};
-use sp_std::convert::TryFrom;
+use bridge_runtime_common::messages::{self, MessageBridge};
+use frame_support::{parameter_types, weights::Weight, RuntimeDebug};
 
 /// Default lane that is used to send messages to Millau.
 pub const DEFAULT_XCM_LANE_TO_MILLAU: LaneId = [0, 0, 0, 0];
-/// Initial value of `MillauToRialtoParachainConversionRate` parameter.
-pub const INITIAL_MILLAU_TO_RIALTO_PARACHAIN_CONVERSION_RATE: FixedU128 =
-	FixedU128::from_inner(FixedU128::DIV);
-/// Initial value of `MillauFeeMultiplier` parameter.
-pub const INITIAL_MILLAU_FEE_MULTIPLIER: FixedU128 = FixedU128::from_inner(FixedU128::DIV);
 /// Weight of 2 XCM instructions is for simple `Trap(42)` program, coming through bridge
 /// (it is prepended with `UniversalOrigin` instruction). It is used just for simplest manual
 /// tests, confirming that we don't break encoding somewhere between.
 pub const BASE_XCM_WEIGHT_TWICE: u64 = 2 * crate::BASE_XCM_WEIGHT;
 
 parameter_types! {
-	/// Millau to RialtoParachain conversion rate. Initially we treat both tokens as equal.
-	pub storage MillauToRialtoParachainConversionRate: FixedU128 = INITIAL_MILLAU_TO_RIALTO_PARACHAIN_CONVERSION_RATE;
-	/// Fee multiplier value at Millau chain.
-	pub storage MillauFeeMultiplier: FixedU128 = INITIAL_MILLAU_FEE_MULTIPLIER;
 	/// Weight credit for our test messages.
 	///
 	/// 2 XCM instructions is for simple `Trap(42)` program, coming through bridge
@@ -94,7 +79,6 @@ pub type ToMillauMaximalOutboundPayloadSize =
 pub struct WithMillauMessageBridge;
 
 impl MessageBridge for WithMillauMessageBridge {
-	const RELAYER_FEE_PERCENT: u32 = 10;
 	const THIS_CHAIN_ID: ChainId = RIALTO_PARACHAIN_CHAIN_ID;
 	const BRIDGED_CHAIN_ID: ChainId = MILLAU_CHAIN_ID;
 	const BRIDGED_MESSAGES_PALLET_NAME: &'static str =
@@ -104,16 +88,6 @@ impl MessageBridge for WithMillauMessageBridge {
 	type BridgedChain = Millau;
 	type BridgedHeaderChain =
 		pallet_bridge_grandpa::GrandpaChainHeaders<Runtime, MillauGrandpaInstance>;
-
-	fn bridged_balance_to_this_balance(
-		bridged_balance: bp_millau::Balance,
-		bridged_to_this_conversion_rate_override: Option<FixedU128>,
-	) -> bp_rialto_parachain::Balance {
-		let conversion_rate = bridged_to_this_conversion_rate_override
-			.unwrap_or_else(MillauToRialtoParachainConversionRate::get);
-		bp_rialto_parachain::Balance::try_from(conversion_rate.saturating_mul_int(bridged_balance))
-			.unwrap_or(bp_rialto_parachain::Balance::MAX)
-	}
 }
 
 /// RialtoParachain chain from message lane point of view.
@@ -127,12 +101,6 @@ impl messages::UnderlyingChainProvider for RialtoParachain {
 impl messages::ThisChainWithMessages for RialtoParachain {
 	type RuntimeCall = RuntimeCall;
 	type RuntimeOrigin = RuntimeOrigin;
-	type ConfirmationTransactionEstimation = BasicConfirmationTransactionEstimation<
-		bp_rialto_parachain::AccountId,
-		{ bp_rialto_parachain::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT.ref_time() },
-		{ bp_millau::EXTRA_STORAGE_PROOF_SIZE },
-		{ bp_rialto_parachain::TX_EXTRA_BYTES },
-	>;
 
 	fn is_message_accepted(send_origin: &Self::RuntimeOrigin, lane: &LaneId) -> bool {
 		let here_location = xcm::v3::MultiLocation::from(crate::UniversalLocation::get());
@@ -156,25 +124,6 @@ impl messages::ThisChainWithMessages for RialtoParachain {
 	fn maximal_pending_messages_at_outbound_lane() -> MessageNonce {
 		MessageNonce::MAX
 	}
-
-	fn transaction_payment(
-		transaction: MessageTransaction<Weight>,
-	) -> bp_rialto_parachain::Balance {
-		// `transaction` may represent transaction from the future, when multiplier value will
-		// be larger, so let's use slightly increased value
-		let multiplier = FixedU128::saturating_from_rational(110, 100)
-			.saturating_mul(pallet_transaction_payment::Pallet::<Runtime>::next_fee_multiplier());
-		// in our testnets, both per-byte fee and weight-to-fee are 1:1
-		messages::transaction_payment(
-			bp_rialto_parachain::BlockWeights::get()
-				.get(DispatchClass::Normal)
-				.base_extrinsic,
-			1,
-			multiplier,
-			|weight| weight.ref_time() as _,
-			transaction,
-		)
-	}
 }
 
 /// Millau chain from message lane point of view.
@@ -189,45 +138,6 @@ impl messages::BridgedChainWithMessages for Millau {
 	fn verify_dispatch_weight(_message_payload: &[u8]) -> bool {
 		true
 	}
-
-	fn estimate_delivery_transaction(
-		message_payload: &[u8],
-		include_pay_dispatch_fee_cost: bool,
-		message_dispatch_weight: Weight,
-	) -> MessageTransaction<Weight> {
-		let message_payload_len = u32::try_from(message_payload.len()).unwrap_or(u32::MAX);
-		let extra_bytes_in_payload = message_payload_len
-			.saturating_sub(pallet_bridge_messages::EXPECTED_DEFAULT_MESSAGE_LENGTH);
-
-		MessageTransaction {
-			dispatch_weight: bp_millau::ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT
-				.saturating_mul(extra_bytes_in_payload as u64)
-				.saturating_add(bp_millau::DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT)
-				.saturating_sub(if include_pay_dispatch_fee_cost {
-					Weight::from_ref_time(0)
-				} else {
-					bp_millau::PAY_INBOUND_DISPATCH_FEE_WEIGHT
-				})
-				.saturating_add(message_dispatch_weight),
-			size: message_payload_len
-				.saturating_add(bp_rialto_parachain::EXTRA_STORAGE_PROOF_SIZE)
-				.saturating_add(bp_millau::TX_EXTRA_BYTES),
-		}
-	}
-
-	fn transaction_payment(transaction: MessageTransaction<Weight>) -> bp_millau::Balance {
-		// we don't have a direct access to the value of multiplier at Millau chain
-		// => it is a messages module parameter
-		let multiplier = MillauFeeMultiplier::get();
-		// in our testnets, both per-byte fee and weight-to-fee are 1:1
-		messages::transaction_payment(
-			bp_millau::BlockWeights::get().get(DispatchClass::Normal).base_extrinsic,
-			1,
-			multiplier,
-			|weight| weight.ref_time() as _,
-			transaction,
-		)
-	}
 }
 
 impl TargetHeaderChain<ToMillauMessagePayload, bp_rialto_parachain::AccountId> for Millau {
@@ -249,7 +159,7 @@ impl TargetHeaderChain<ToMillauMessagePayload, bp_rialto_parachain::AccountId> f
 	}
 }
 
-impl SourceHeaderChain<bp_millau::Balance> for Millau {
+impl SourceHeaderChain for Millau {
 	type Error = &'static str;
 	// The proof is:
 	// - hash of the header this proof has been created with;
@@ -261,25 +171,8 @@ impl SourceHeaderChain<bp_millau::Balance> for Millau {
 	fn verify_messages_proof(
 		proof: Self::MessagesProof,
 		messages_count: u32,
-	) -> Result<ProvedMessages<Message<bp_millau::Balance>>, Self::Error> {
+	) -> Result<ProvedMessages<Message>, Self::Error> {
 		messages::target::verify_messages_proof::<WithMillauMessageBridge>(proof, messages_count)
 			.map_err(Into::into)
 	}
 }
-
-/// RialtoParachain -> Millau message lane pallet parameters.
-#[derive(RuntimeDebug, Clone, Encode, Decode, PartialEq, Eq, TypeInfo)]
-pub enum RialtoParachainToMillauMessagesParameter {
-	/// The conversion formula we use is: `RialtoParachainTokens = MillauTokens * conversion_rate`.
-	MillauToRialtoParachainConversionRate(FixedU128),
-}
-
-impl MessagesParameter for RialtoParachainToMillauMessagesParameter {
-	fn save(&self) {
-		match *self {
-			RialtoParachainToMillauMessagesParameter::MillauToRialtoParachainConversionRate(
-				ref conversion_rate,
-			) => MillauToRialtoParachainConversionRate::set(conversion_rate),
-		}
-	}
-}
diff --git a/bridges/bin/rialto/runtime/src/lib.rs b/bridges/bin/rialto/runtime/src/lib.rs
index 53b0f821f3e48786fa0035ecdfbb1383ee123b4b..3ce0b650dc5f1b41d6c0b9275b9ccc389f38f3c4 100644
--- a/bridges/bin/rialto/runtime/src/lib.rs
+++ b/bridges/bin/rialto/runtime/src/lib.rs
@@ -32,13 +32,8 @@ pub mod millau_messages;
 pub mod parachains;
 pub mod xcm_config;
 
-use crate::millau_messages::{ToMillauMessagePayload, WithMillauMessageBridge};
-
 use beefy_primitives::{crypto::AuthorityId as BeefyId, mmr::MmrLeafVersion, ValidatorSet};
 use bp_runtime::{HeaderId, HeaderIdProvider};
-use bridge_runtime_common::messages::{
-	source::estimate_message_dispatch_and_delivery_fee, MessageBridge,
-};
 use pallet_grandpa::{
 	fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList,
 };
@@ -54,7 +49,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, Perquintill,
+	ApplyExtrinsicResult, FixedPointNumber, Perquintill,
 };
 use sp_std::{collections::btree_map::BTreeMap, prelude::*};
 #[cfg(feature = "std")]
@@ -445,9 +440,6 @@ parameter_types! {
 		bp_millau::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX;
 	pub const MaxUnconfirmedMessagesAtInboundLane: bp_messages::MessageNonce =
 		bp_millau::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX;
-	// `IdentityFee` is used by Rialto => we may use weight directly
-	pub const GetDeliveryConfirmationTransactionFee: Balance =
-		bp_rialto::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT.ref_time() as _;
 	pub const RootAccountForPayments: Option<AccountId> = None;
 	pub const BridgedChainId: bp_runtime::ChainId = bp_runtime::MILLAU_CHAIN_ID;
 }
@@ -458,17 +450,14 @@ pub type WithMillauMessagesInstance = ();
 impl pallet_bridge_messages::Config<WithMillauMessagesInstance> for Runtime {
 	type RuntimeEvent = RuntimeEvent;
 	type WeightInfo = pallet_bridge_messages::weights::BridgeWeight<Runtime>;
-	type Parameter = millau_messages::RialtoToMillauMessagesParameter;
 	type MaxMessagesToPruneAtOnce = MaxMessagesToPruneAtOnce;
 	type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane;
 	type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane;
 
 	type MaximalOutboundPayloadSize = crate::millau_messages::ToMillauMaximalOutboundPayloadSize;
 	type OutboundPayload = crate::millau_messages::ToMillauMessagePayload;
-	type OutboundMessageFee = Balance;
 
 	type InboundPayload = crate::millau_messages::FromMillauMessagePayload;
-	type InboundMessageFee = bp_millau::Balance;
 	type InboundRelayer = bp_millau::AccountId;
 
 	type TargetHeaderChain = crate::millau_messages::Millau;
@@ -477,7 +466,6 @@ impl pallet_bridge_messages::Config<WithMillauMessagesInstance> for Runtime {
 		pallet_bridge_relayers::MessageDeliveryAndDispatchPaymentAdapter<
 			Runtime,
 			WithMillauMessagesInstance,
-			GetDeliveryConfirmationTransactionFee,
 		>;
 	type OnMessageAccepted = ();
 	type OnDeliveryConfirmed = ();
@@ -958,24 +946,12 @@ impl_runtime_apis! {
 		}
 	}
 
-	impl bp_millau::ToMillauOutboundLaneApi<Block, Balance, ToMillauMessagePayload> for Runtime {
-		fn estimate_message_delivery_and_dispatch_fee(
-			_lane_id: bp_messages::LaneId,
-			payload: ToMillauMessagePayload,
-			millau_to_this_conversion_rate: Option<FixedU128>,
-		) -> Option<Balance> {
-			estimate_message_dispatch_and_delivery_fee::<WithMillauMessageBridge>(
-				&payload,
-				WithMillauMessageBridge::RELAYER_FEE_PERCENT,
-				millau_to_this_conversion_rate,
-			).ok()
-		}
-
+	impl bp_millau::ToMillauOutboundLaneApi<Block> for Runtime {
 		fn message_details(
 			lane: bp_messages::LaneId,
 			begin: bp_messages::MessageNonce,
 			end: bp_messages::MessageNonce,
-		) -> Vec<bp_messages::OutboundMessageDetails<Balance>> {
+		) -> Vec<bp_messages::OutboundMessageDetails> {
 			bridge_runtime_common::messages_api::outbound_message_details::<
 				Runtime,
 				WithMillauMessagesInstance,
@@ -983,10 +959,10 @@ impl_runtime_apis! {
 		}
 	}
 
-	impl bp_millau::FromMillauInboundLaneApi<Block, bp_millau::Balance> for Runtime {
+	impl bp_millau::FromMillauInboundLaneApi<Block> for Runtime {
 		fn message_details(
 			lane: bp_messages::LaneId,
-			messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails<bp_millau::Balance>)>,
+			messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails)>,
 		) -> Vec<bp_messages::InboundMessageDetails> {
 			bridge_runtime_common::messages_api::inbound_message_details::<
 				Runtime,
diff --git a/bridges/bin/rialto/runtime/src/millau_messages.rs b/bridges/bin/rialto/runtime/src/millau_messages.rs
index cf8812eaf9a69ef40220dd64eb57752f44bc2ab5..9eb6c82f3678d313216a0f139f1888d05b35b8f5 100644
--- a/bridges/bin/rialto/runtime/src/millau_messages.rs
+++ b/bridges/bin/rialto/runtime/src/millau_messages.rs
@@ -21,33 +21,18 @@ use crate::{MillauGrandpaInstance, OriginCaller, Runtime, RuntimeCall, RuntimeOr
 use bp_messages::{
 	source_chain::TargetHeaderChain,
 	target_chain::{ProvedMessages, SourceHeaderChain},
-	InboundLaneData, LaneId, Message, MessageNonce, Parameter as MessagesParameter,
+	InboundLaneData, LaneId, Message, MessageNonce,
 };
 use bp_runtime::{ChainId, MILLAU_CHAIN_ID, RIALTO_CHAIN_ID};
-use bridge_runtime_common::messages::{
-	self, BasicConfirmationTransactionEstimation, MessageBridge, MessageTransaction,
-};
-use codec::{Decode, Encode};
-use frame_support::{dispatch::DispatchClass, parameter_types, weights::Weight, RuntimeDebug};
-use scale_info::TypeInfo;
-use sp_runtime::{traits::Saturating, FixedPointNumber, FixedU128};
-use sp_std::convert::TryFrom;
-
-/// Initial value of `MillauToRialtoConversionRate` parameter.
-pub const INITIAL_MILLAU_TO_RIALTO_CONVERSION_RATE: FixedU128 =
-	FixedU128::from_inner(FixedU128::DIV);
-/// Initial value of `MillauFeeMultiplier` parameter.
-pub const INITIAL_MILLAU_FEE_MULTIPLIER: FixedU128 = FixedU128::from_inner(FixedU128::DIV);
+use bridge_runtime_common::messages::{self, MessageBridge};
+use frame_support::{parameter_types, weights::Weight, RuntimeDebug};
+
 /// Weight of 2 XCM instructions is for simple `Trap(42)` program, coming through bridge
 /// (it is prepended with `UniversalOrigin` instruction). It is used just for simplest manual
 /// tests, confirming that we don't break encoding somewhere between.
 pub const BASE_XCM_WEIGHT_TWICE: u64 = 2 * crate::xcm_config::BASE_XCM_WEIGHT;
 
 parameter_types! {
-	/// Millau to Rialto conversion rate. Initially we treat both tokens as equal.
-	pub storage MillauToRialtoConversionRate: FixedU128 = INITIAL_MILLAU_TO_RIALTO_CONVERSION_RATE;
-	/// Fee multiplier value at Millau chain.
-	pub storage MillauFeeMultiplier: FixedU128 = INITIAL_MILLAU_FEE_MULTIPLIER;
 	/// Weight credit for our test messages.
 	///
 	/// 2 XCM instructions is for simple `Trap(42)` program, coming through bridge
@@ -89,7 +74,6 @@ pub type ToMillauMaximalOutboundPayloadSize =
 pub struct WithMillauMessageBridge;
 
 impl MessageBridge for WithMillauMessageBridge {
-	const RELAYER_FEE_PERCENT: u32 = 10;
 	const THIS_CHAIN_ID: ChainId = RIALTO_CHAIN_ID;
 	const BRIDGED_CHAIN_ID: ChainId = MILLAU_CHAIN_ID;
 	const BRIDGED_MESSAGES_PALLET_NAME: &'static str = bp_rialto::WITH_RIALTO_MESSAGES_PALLET_NAME;
@@ -98,16 +82,6 @@ impl MessageBridge for WithMillauMessageBridge {
 	type BridgedChain = Millau;
 	type BridgedHeaderChain =
 		pallet_bridge_grandpa::GrandpaChainHeaders<Runtime, MillauGrandpaInstance>;
-
-	fn bridged_balance_to_this_balance(
-		bridged_balance: bp_millau::Balance,
-		bridged_to_this_conversion_rate_override: Option<FixedU128>,
-	) -> bp_rialto::Balance {
-		let conversion_rate = bridged_to_this_conversion_rate_override
-			.unwrap_or_else(MillauToRialtoConversionRate::get);
-		bp_rialto::Balance::try_from(conversion_rate.saturating_mul_int(bridged_balance))
-			.unwrap_or(bp_rialto::Balance::MAX)
-	}
 }
 
 /// Rialto chain from message lane point of view.
@@ -121,12 +95,6 @@ impl messages::UnderlyingChainProvider for Rialto {
 impl messages::ThisChainWithMessages for Rialto {
 	type RuntimeOrigin = RuntimeOrigin;
 	type RuntimeCall = RuntimeCall;
-	type ConfirmationTransactionEstimation = BasicConfirmationTransactionEstimation<
-		bp_rialto::AccountId,
-		{ bp_rialto::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT.ref_time() },
-		{ bp_millau::EXTRA_STORAGE_PROOF_SIZE },
-		{ bp_rialto::TX_EXTRA_BYTES },
-	>;
 
 	fn is_message_accepted(send_origin: &Self::RuntimeOrigin, lane: &LaneId) -> bool {
 		let here_location =
@@ -151,21 +119,6 @@ impl messages::ThisChainWithMessages for Rialto {
 	fn maximal_pending_messages_at_outbound_lane() -> MessageNonce {
 		MessageNonce::MAX
 	}
-
-	fn transaction_payment(transaction: MessageTransaction<Weight>) -> bp_rialto::Balance {
-		// `transaction` may represent transaction from the future, when multiplier value will
-		// be larger, so let's use slightly increased value
-		let multiplier = FixedU128::saturating_from_rational(110, 100)
-			.saturating_mul(pallet_transaction_payment::Pallet::<Runtime>::next_fee_multiplier());
-		// in our testnets, both per-byte fee and weight-to-fee are 1:1
-		messages::transaction_payment(
-			bp_rialto::BlockWeights::get().get(DispatchClass::Normal).base_extrinsic,
-			1,
-			multiplier,
-			|weight| weight.ref_time() as _,
-			transaction,
-		)
-	}
 }
 
 /// Millau chain from message lane point of view.
@@ -180,45 +133,6 @@ impl messages::BridgedChainWithMessages for Millau {
 	fn verify_dispatch_weight(_message_payload: &[u8]) -> bool {
 		true
 	}
-
-	fn estimate_delivery_transaction(
-		message_payload: &[u8],
-		include_pay_dispatch_fee_cost: bool,
-		message_dispatch_weight: Weight,
-	) -> MessageTransaction<Weight> {
-		let message_payload_len = u32::try_from(message_payload.len()).unwrap_or(u32::MAX);
-		let extra_bytes_in_payload = message_payload_len
-			.saturating_sub(pallet_bridge_messages::EXPECTED_DEFAULT_MESSAGE_LENGTH);
-
-		MessageTransaction {
-			dispatch_weight: bp_millau::ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT
-				.saturating_mul(extra_bytes_in_payload as u64)
-				.saturating_add(bp_millau::DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT)
-				.saturating_sub(if include_pay_dispatch_fee_cost {
-					Weight::from_ref_time(0)
-				} else {
-					bp_millau::PAY_INBOUND_DISPATCH_FEE_WEIGHT
-				})
-				.saturating_add(message_dispatch_weight),
-			size: message_payload_len
-				.saturating_add(bp_rialto::EXTRA_STORAGE_PROOF_SIZE)
-				.saturating_add(bp_millau::TX_EXTRA_BYTES),
-		}
-	}
-
-	fn transaction_payment(transaction: MessageTransaction<Weight>) -> bp_millau::Balance {
-		// we don't have a direct access to the value of multiplier at Millau chain
-		// => it is a messages module parameter
-		let multiplier = MillauFeeMultiplier::get();
-		// in our testnets, both per-byte fee and weight-to-fee are 1:1
-		messages::transaction_payment(
-			bp_millau::BlockWeights::get().get(DispatchClass::Normal).base_extrinsic,
-			1,
-			multiplier,
-			|weight| weight.ref_time() as _,
-			transaction,
-		)
-	}
 }
 
 impl TargetHeaderChain<ToMillauMessagePayload, bp_rialto::AccountId> for Millau {
@@ -240,7 +154,7 @@ impl TargetHeaderChain<ToMillauMessagePayload, bp_rialto::AccountId> for Millau
 	}
 }
 
-impl SourceHeaderChain<bp_millau::Balance> for Millau {
+impl SourceHeaderChain for Millau {
 	type Error = &'static str;
 	// The proof is:
 	// - hash of the header this proof has been created with;
@@ -252,28 +166,12 @@ impl SourceHeaderChain<bp_millau::Balance> for Millau {
 	fn verify_messages_proof(
 		proof: Self::MessagesProof,
 		messages_count: u32,
-	) -> Result<ProvedMessages<Message<bp_millau::Balance>>, Self::Error> {
+	) -> Result<ProvedMessages<Message>, Self::Error> {
 		messages::target::verify_messages_proof::<WithMillauMessageBridge>(proof, messages_count)
 			.map_err(Into::into)
 	}
 }
 
-/// Rialto -> Millau message lane pallet parameters.
-#[derive(RuntimeDebug, Clone, Encode, Decode, PartialEq, Eq, TypeInfo)]
-pub enum RialtoToMillauMessagesParameter {
-	/// The conversion formula we use is: `RialtoTokens = MillauTokens * conversion_rate`.
-	MillauToRialtoConversionRate(FixedU128),
-}
-
-impl MessagesParameter for RialtoToMillauMessagesParameter {
-	fn save(&self) {
-		match *self {
-			RialtoToMillauMessagesParameter::MillauToRialtoConversionRate(ref conversion_rate) =>
-				MillauToRialtoConversionRate::set(conversion_rate),
-		}
-	}
-}
-
 #[cfg(test)]
 mod tests {
 	use super::*;
@@ -291,13 +189,7 @@ mod tests {
 	fn ensure_rialto_message_lane_weights_are_correct() {
 		type Weights = pallet_bridge_messages::weights::BridgeWeight<Runtime>;
 
-		pallet_bridge_messages::ensure_weights_are_correct::<Weights>(
-			bp_rialto::DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT,
-			bp_rialto::ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT,
-			bp_rialto::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT,
-			bp_rialto::PAY_INBOUND_DISPATCH_FEE_WEIGHT,
-			DbWeight::get(),
-		);
+		pallet_bridge_messages::ensure_weights_are_correct::<Weights>();
 
 		let max_incoming_message_proof_size = bp_millau::EXTRA_STORAGE_PROOF_SIZE.saturating_add(
 			messages::target::maximal_incoming_message_size(bp_rialto::Rialto::max_extrinsic_size()),
@@ -362,13 +254,5 @@ mod tests {
 					bp_millau::WITH_MILLAU_MESSAGES_PALLET_NAME,
 			},
 		});
-
-		assert_eq!(
-			MillauToRialtoConversionRate::key().to_vec(),
-			bp_runtime::storage_parameter_key(
-				bp_rialto::MILLAU_TO_RIALTO_CONVERSION_RATE_PARAMETER_NAME
-			)
-			.0,
-		);
 	}
 }
diff --git a/bridges/bin/rialto/runtime/src/xcm_config.rs b/bridges/bin/rialto/runtime/src/xcm_config.rs
index 780ce710ba9f6247504130c0693623779ef695ef..b874ec8ce8534f285e9ef846b52e66eb77c2833f 100644
--- a/bridges/bin/rialto/runtime/src/xcm_config.rs
+++ b/bridges/bin/rialto/runtime/src/xcm_config.rs
@@ -238,7 +238,7 @@ mod tests {
 			let xcm: Xcm<()> = vec![Instruction::Trap(42)].into();
 
 			let send_result = send_xcm::<XcmRouter>(dest.into(), xcm);
-			let expected_fee = MultiAssets::from((Here, 4_259_858_152_u128));
+			let expected_fee = MultiAssets::from((Here, 1_000_000_u128));
 			let expected_hash =
 				([0u8, 0u8, 0u8, 0u8], 1u64).using_encoded(sp_io::hashing::blake2_256);
 			assert_eq!(send_result, Ok((expected_hash, expected_fee)),);
@@ -262,7 +262,7 @@ mod tests {
 
 			let mut incoming_message = DispatchMessage {
 				key: MessageKey { lane_id: [0, 0, 0, 0], nonce: 1 },
-				data: DispatchMessageData { payload: Ok((location, xcm).into()), fee: 0 },
+				data: DispatchMessageData { payload: Ok((location, xcm).into()) },
 			};
 
 			let dispatch_weight = MessageDispatcher::dispatch_weight(&mut incoming_message);
diff --git a/bridges/bin/runtime-common/src/integrity.rs b/bridges/bin/runtime-common/src/integrity.rs
index 3b64d1e8afea5c25ac9d7dfcb6a36fc95600b42f..a9a2c06470c97a82ee93c3bd997638d98b3cac1a 100644
--- a/bridges/bin/runtime-common/src/integrity.rs
+++ b/bridges/bin/runtime-common/src/integrity.rs
@@ -88,10 +88,8 @@ macro_rules! assert_bridge_messages_pallet_types(
 			use static_assertions::assert_type_eq_all;
 
 			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<CallOf<ThisChain<$bridge>>>);
-			assert_type_eq_all!(<$r as MessagesConfig<$i>>::InboundMessageFee, BalanceOf<BridgedChain<$bridge>>);
 			assert_type_eq_all!(<$r as MessagesConfig<$i>>::InboundRelayer, AccountIdOf<BridgedChain<$bridge>>);
 
 			assert_type_eq_all!(<$r as MessagesConfig<$i>>::TargetHeaderChain, BridgedChain<$bridge>);
diff --git a/bridges/bin/runtime-common/src/messages.rs b/bridges/bin/runtime-common/src/messages.rs
index 320b91539b94550ca05879486d98ad99207a96fc..3bbf6df4f559aac2b66094c1ef04ad0c2403e216 100644
--- a/bridges/bin/runtime-common/src/messages.rs
+++ b/bridges/bin/runtime-common/src/messages.rs
@@ -24,26 +24,19 @@ use bp_header_chain::{HeaderChain, HeaderChainError};
 use bp_messages::{
 	source_chain::LaneMessageVerifier,
 	target_chain::{DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages},
-	InboundLaneData, LaneId, Message, MessageData, MessageKey, MessageNonce, OutboundLaneData,
+	InboundLaneData, LaneId, Message, MessageKey, MessageNonce, MessagePayload, OutboundLaneData,
 };
 use bp_runtime::{messages::MessageDispatchResult, Chain, ChainId, Size, StorageProofChecker};
-use codec::{Decode, DecodeLimit, Encode, MaxEncodedLen};
+use codec::{Decode, DecodeLimit, Encode};
 use frame_support::{traits::Get, weights::Weight, RuntimeDebug};
 use hash_db::Hasher;
 use scale_info::TypeInfo;
-use sp_runtime::{
-	traits::{AtLeast32BitUnsigned, CheckedAdd, CheckedDiv, CheckedMul},
-	FixedPointNumber, FixedPointOperand, FixedU128,
-};
 use sp_std::{convert::TryFrom, fmt::Debug, marker::PhantomData, vec::Vec};
 use sp_trie::StorageProof;
 use xcm::latest::prelude::*;
 
 /// Bidirectional message bridge.
 pub trait MessageBridge {
-	/// Relayer interest (in percents).
-	const RELAYER_FEE_PERCENT: u32;
-
 	/// Identifier of this chain.
 	const THIS_CHAIN_ID: ChainId;
 	/// Identifier of the Bridged chain.
@@ -59,60 +52,6 @@ pub trait MessageBridge {
 	type BridgedChain: BridgedChainWithMessages;
 	/// Bridged header chain.
 	type BridgedHeaderChain: HeaderChain<UnderlyingChainOf<Self::BridgedChain>>;
-
-	/// Convert Bridged chain balance into This chain balance.
-	fn bridged_balance_to_this_balance(
-		bridged_balance: BalanceOf<BridgedChain<Self>>,
-		bridged_to_this_conversion_rate_override: Option<FixedU128>,
-	) -> BalanceOf<ThisChain<Self>>;
-}
-
-/// Message related transaction parameters estimation.
-#[derive(RuntimeDebug)]
-pub struct MessageTransaction<Weight> {
-	/// The estimated dispatch weight of the transaction.
-	pub dispatch_weight: Weight,
-	/// The estimated size of the encoded transaction.
-	pub size: u32,
-}
-
-/// Helper trait for estimating the size and weight of a single message delivery confirmation
-/// transaction.
-pub trait ConfirmationTransactionEstimation<Weight> {
-	// Estimate size and weight of single message delivery confirmation transaction.
-	fn estimate_delivery_confirmation_transaction() -> MessageTransaction<Weight>;
-}
-
-/// Default implementation for `ConfirmationTransactionEstimation`.
-pub struct BasicConfirmationTransactionEstimation<
-	AccountId: MaxEncodedLen,
-	const MAX_CONFIRMATION_TX_WEIGHT: u64,
-	const EXTRA_STORAGE_PROOF_SIZE: u32,
-	const TX_EXTRA_BYTES: u32,
->(PhantomData<AccountId>);
-
-impl<
-		AccountId: MaxEncodedLen,
-		const MAX_CONFIRMATION_TX_WEIGHT: u64,
-		const EXTRA_STORAGE_PROOF_SIZE: u32,
-		const TX_EXTRA_BYTES: u32,
-	> ConfirmationTransactionEstimation<Weight>
-	for BasicConfirmationTransactionEstimation<
-		AccountId,
-		MAX_CONFIRMATION_TX_WEIGHT,
-		EXTRA_STORAGE_PROOF_SIZE,
-		TX_EXTRA_BYTES,
-	>
-{
-	fn estimate_delivery_confirmation_transaction() -> MessageTransaction<Weight> {
-		let inbound_data_size = InboundLaneData::<AccountId>::encoded_size_hint_u32(1, 1);
-		MessageTransaction {
-			dispatch_weight: Weight::from_ref_time(MAX_CONFIRMATION_TX_WEIGHT),
-			size: inbound_data_size
-				.saturating_add(EXTRA_STORAGE_PROOF_SIZE)
-				.saturating_add(TX_EXTRA_BYTES),
-		}
-	}
 }
 
 /// A trait that provides the type of the underlying chain.
@@ -127,9 +66,6 @@ pub trait ThisChainWithMessages: UnderlyingChainProvider {
 	type RuntimeOrigin;
 	/// Call type on the chain.
 	type RuntimeCall: Encode + Decode;
-	/// Helper for estimating the size and weight of a single message delivery confirmation
-	/// transaction at this chain.
-	type ConfirmationTransactionEstimation: ConfirmationTransactionEstimation<Weight>;
 
 	/// Do we accept message sent by given origin to given lane?
 	fn is_message_accepted(origin: &Self::RuntimeOrigin, lane: &LaneId) -> bool;
@@ -138,14 +74,6 @@ pub trait ThisChainWithMessages: UnderlyingChainProvider {
 	///
 	/// Any messages over this limit, will be rejected.
 	fn maximal_pending_messages_at_outbound_lane() -> MessageNonce;
-
-	/// Estimate size and weight of single message delivery confirmation transaction at This chain.
-	fn estimate_delivery_confirmation_transaction() -> MessageTransaction<Weight> {
-		Self::ConfirmationTransactionEstimation::estimate_delivery_confirmation_transaction()
-	}
-
-	/// Returns minimal transaction fee that must be paid for given transaction at This chain.
-	fn transaction_payment(transaction: MessageTransaction<Weight>) -> BalanceOf<Self>;
 }
 
 /// Bridged chain that has `pallet-bridge-messages` module.
@@ -153,17 +81,6 @@ pub trait BridgedChainWithMessages: UnderlyingChainProvider {
 	/// 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(
-		message_payload: &[u8],
-		include_pay_dispatch_fee_cost: bool,
-		message_dispatch_weight: Weight,
-	) -> MessageTransaction<Weight>;
-
-	/// Returns minimal transaction fee that must be paid for given transaction at the Bridged
-	/// chain.
-	fn transaction_payment(transaction: MessageTransaction<Weight>) -> BalanceOf<Self>;
 }
 
 /// This chain in context of message bridge.
@@ -188,33 +105,6 @@ pub type CallOf<C> = <C as ThisChainWithMessages>::RuntimeCall;
 /// Raw storage proof type (just raw trie nodes).
 pub type RawStorageProof = Vec<Vec<u8>>;
 
-/// Compute fee of transaction at runtime where regular transaction payment pallet is being used.
-///
-/// The value of `multiplier` parameter is the expected value of
-/// `pallet_transaction_payment::NextFeeMultiplier` at the moment when transaction is submitted. If
-/// you're charging this payment in advance (and that's what happens with delivery and confirmation
-/// transaction in this crate), then there's a chance that the actual fee will be larger than what
-/// is paid in advance. So the value must be chosen carefully.
-pub fn transaction_payment<Balance: AtLeast32BitUnsigned + FixedPointOperand>(
-	base_extrinsic_weight: Weight,
-	per_byte_fee: Balance,
-	multiplier: FixedU128,
-	weight_to_fee: impl Fn(Weight) -> Balance,
-	transaction: MessageTransaction<Weight>,
-) -> Balance {
-	// base fee is charged for every tx
-	let base_fee = weight_to_fee(base_extrinsic_weight);
-
-	// non-adjustable per-byte fee
-	let len_fee = per_byte_fee.saturating_mul(Balance::from(transaction.size));
-
-	// the adjustable part of the fee
-	let unadjusted_weight_fee = weight_to_fee(transaction.dispatch_weight);
-	let adjusted_weight_fee = multiplier.saturating_mul_int(unadjusted_weight_fee);
-
-	base_fee.saturating_add(len_fee).saturating_add(adjusted_weight_fee)
-}
-
 /// Sub-module that is declaring types required for processing This -> Bridged chain messages.
 pub mod source {
 	use super::*;
@@ -286,15 +176,9 @@ pub mod source {
 	pub const TOO_MANY_PENDING_MESSAGES: &str = "Too many pending messages at the lane.";
 	/// The error message returned from LaneMessageVerifier when call origin is mismatch.
 	pub const BAD_ORIGIN: &str = "Unable to match the source origin to expected target origin.";
-	/// The error message returned from LaneMessageVerifier when the message fee is too low.
-	pub const TOO_LOW_FEE: &str = "Provided fee is below minimal threshold required by the lane.";
 
-	impl<B>
-		LaneMessageVerifier<
-			OriginOf<ThisChain<B>>,
-			FromThisChainMessagePayload,
-			BalanceOf<ThisChain<B>>,
-		> for FromThisChainMessageVerifier<B>
+	impl<B> LaneMessageVerifier<OriginOf<ThisChain<B>>, FromThisChainMessagePayload>
+		for FromThisChainMessageVerifier<B>
 	where
 		B: MessageBridge,
 		// matches requirements from the `frame_system::Config::Origin`
@@ -306,10 +190,9 @@ pub mod source {
 
 		fn verify_message(
 			submitter: &OriginOf<ThisChain<B>>,
-			delivery_and_dispatch_fee: &BalanceOf<ThisChain<B>>,
 			lane: &LaneId,
 			lane_outbound_data: &OutboundLaneData,
-			payload: &FromThisChainMessagePayload,
+			_payload: &FromThisChainMessagePayload,
 		) -> Result<(), Self::Error> {
 			// reject message if lane is blocked
 			if !ThisChain::<B>::is_message_accepted(submitter, lane) {
@@ -325,17 +208,6 @@ pub mod source {
 				return Err(TOO_MANY_PENDING_MESSAGES)
 			}
 
-			let minimal_fee_in_this_tokens = estimate_message_dispatch_and_delivery_fee::<B>(
-				payload,
-				B::RELAYER_FEE_PERCENT,
-				None,
-			)?;
-
-			// compare with actual fee paid
-			if *delivery_and_dispatch_fee < minimal_fee_in_this_tokens {
-				return Err(TOO_LOW_FEE)
-			}
-
 			Ok(())
 		}
 	}
@@ -376,52 +248,6 @@ pub mod source {
 		Ok(())
 	}
 
-	/// Estimate delivery and dispatch fee that must be paid for delivering a message to the Bridged
-	/// chain.
-	///
-	/// 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,
-		relayer_fee_percent: u32,
-		bridged_to_this_conversion_rate: Option<FixedU128>,
-	) -> Result<BalanceOf<ThisChain<B>>, &'static str> {
-		// the fee (in Bridged tokens) of all transactions that are made on the Bridged chain
-		//
-		// 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 delivery_transaction = BridgedChain::<B>::estimate_delivery_transaction(
-			&payload.encode(),
-			true,
-			Weight::zero(),
-		);
-		let delivery_transaction_fee = BridgedChain::<B>::transaction_payment(delivery_transaction);
-
-		// the fee (in This tokens) of all transactions that are made on This chain
-		let confirmation_transaction = ThisChain::<B>::estimate_delivery_confirmation_transaction();
-		let confirmation_transaction_fee =
-			ThisChain::<B>::transaction_payment(confirmation_transaction);
-
-		// minimal fee (in This tokens) is a sum of all required fees
-		let minimal_fee = B::bridged_balance_to_this_balance(
-			delivery_transaction_fee,
-			bridged_to_this_conversion_rate,
-		)
-		.checked_add(&confirmation_transaction_fee);
-
-		// before returning, add extra fee that is paid to the relayer (relayer interest)
-		minimal_fee
-			.and_then(|fee|
-			// having message with fee that is near the `Balance::MAX_VALUE` of the chain is
-			// unlikely and should be treated as an error
-			// => let's do multiplication first
-			fee
-				.checked_mul(&relayer_fee_percent.into())
-				.and_then(|interest| interest.checked_div(&100u32.into()))
-				.and_then(|interest| fee.checked_add(&interest)))
-			.ok_or("Overflow when computing minimal required message delivery and dispatch fee")
-	}
-
 	/// Verify proof of This -> Bridged chain messages delivery.
 	///
 	/// This function is used when Bridged chain is directly using GRANDPA finality. For Bridged
@@ -462,7 +288,6 @@ pub mod source {
 		/// Runtime message sender adapter.
 		type MessageSender: bp_messages::source_chain::MessagesBridge<
 			OriginOf<ThisChain<Self::MessageBridge>>,
-			BalanceOf<ThisChain<Self::MessageBridge>>,
 			FromThisChainMessagePayload,
 		>;
 
@@ -484,7 +309,7 @@ pub mod source {
 		BalanceOf<ThisChain<T::MessageBridge>>: Into<Fungibility>,
 		OriginOf<ThisChain<T::MessageBridge>>: From<pallet_xcm::Origin>,
 	{
-		type Ticket = (BalanceOf<ThisChain<T::MessageBridge>>, FromThisChainMessagePayload);
+		type Ticket = FromThisChainMessagePayload;
 
 		fn validate(
 			dest: &mut Option<MultiLocation>,
@@ -499,39 +324,22 @@ pub mod source {
 			let route = T::build_destination();
 			let msg = (route, msg.take().ok_or(SendError::MissingArgument)?).encode();
 
-			let fee = estimate_message_dispatch_and_delivery_fee::<T::MessageBridge>(
-				&msg,
-				T::MessageBridge::RELAYER_FEE_PERCENT,
-				None,
-			);
-			let fee = match fee {
-				Ok(fee) => fee,
-				Err(e) => {
-					log::trace!(
-						target: "runtime::bridge",
-						"Failed to comupte fee for XCM message to {:?}: {:?}",
-						T::MessageBridge::BRIDGED_CHAIN_ID,
-						e,
-					);
-					*dest = Some(d);
-					return Err(SendError::Transport(e))
-				},
-			};
-			let fee_assets = MultiAssets::from((Here, fee));
+			// let's just take fixed (out of thin air) fee per message in our test bridges
+			// (this code won't be used in production anyway)
+			let fee_assets = MultiAssets::from((Here, 1_000_000_u128));
 
-			Ok(((fee, msg), fee_assets))
+			Ok((msg, fee_assets))
 		}
 
 		fn deliver(ticket: Self::Ticket) -> Result<XcmHash, SendError> {
 			use bp_messages::source_chain::MessagesBridge;
 
 			let lane = T::xcm_lane();
-			let (fee, msg) = ticket;
+			let msg = ticket;
 			let result = T::MessageSender::send_message(
 				pallet_xcm::Origin::from(MultiLocation::from(T::universal_location())).into(),
 				lane,
 				msg,
-				fee,
 			);
 			result
 				.map(|artifacts| {
@@ -633,7 +441,7 @@ pub mod target {
 	}
 
 	impl<B: MessageBridge, XcmExecutor, XcmWeigher, WeightCredit>
-		MessageDispatch<AccountIdOf<ThisChain<B>>, BalanceOf<BridgedChain<B>>>
+		MessageDispatch<AccountIdOf<ThisChain<B>>>
 		for FromBridgedChainMessageDispatch<B, XcmExecutor, XcmWeigher, WeightCredit>
 	where
 		XcmExecutor: xcm::v3::ExecuteXcm<CallOf<ThisChain<B>>>,
@@ -643,7 +451,7 @@ pub mod target {
 		type DispatchPayload = FromBridgedChainMessagePayload<CallOf<ThisChain<B>>>;
 
 		fn dispatch_weight(
-			message: &mut DispatchMessage<Self::DispatchPayload, BalanceOf<BridgedChain<B>>>,
+			message: &mut DispatchMessage<Self::DispatchPayload>,
 		) -> frame_support::weights::Weight {
 			match message.data.payload {
 				Ok(ref mut payload) => {
@@ -673,7 +481,7 @@ pub mod target {
 
 		fn dispatch(
 			_relayer_account: &AccountIdOf<ThisChain<B>>,
-			message: DispatchMessage<Self::DispatchPayload, BalanceOf<BridgedChain<B>>>,
+			message: DispatchMessage<Self::DispatchPayload>,
 		) -> MessageDispatchResult {
 			let message_id = (message.key.lane_id, message.key.nonce);
 			let do_dispatch = move || -> sp_std::result::Result<Outcome, codec::Error> {
@@ -738,7 +546,7 @@ pub mod target {
 	pub fn verify_messages_proof<B: MessageBridge>(
 		proof: FromBridgedChainMessagesProof<HashOf<BridgedChain<B>>>,
 		messages_count: u32,
-	) -> Result<ProvedMessages<Message<BalanceOf<BridgedChain<B>>>>, MessageProofError> {
+	) -> Result<ProvedMessages<Message>, MessageProofError> {
 		let FromBridgedChainMessagesProof {
 			bridged_header_hash,
 			storage_proof,
@@ -779,11 +587,9 @@ pub mod target {
 					let raw_message_data = parser
 						.read_raw_message(&message_key)
 						.ok_or(MessageProofError::MissingRequiredMessage)?;
-					let message_data = MessageData::<BalanceOf<BridgedChain<B>>>::decode(
-						&mut &raw_message_data[..],
-					)
-					.map_err(|_| MessageProofError::FailedToDecodeMessage)?;
-					messages.push(Message { key: message_key, data: message_data });
+					let payload = MessagePayload::decode(&mut &raw_message_data[..])
+						.map_err(|_| MessageProofError::FailedToDecodeMessage)?;
+					messages.push(Message { key: message_key, payload });
 				}
 
 				// Now let's check if proof contains outbound lane state proof. It is optional, so
@@ -885,11 +691,6 @@ mod tests {
 	use sp_runtime::traits::{BlakeTwo256, Header as _};
 	use std::cell::RefCell;
 
-	const DELIVERY_TRANSACTION_WEIGHT: Weight = Weight::from_ref_time(100);
-	const DELIVERY_CONFIRMATION_TRANSACTION_WEIGHT: u64 = 100;
-	const THIS_CHAIN_WEIGHT_TO_BALANCE_RATE: u32 = 2;
-	const BRIDGED_CHAIN_WEIGHT_TO_BALANCE_RATE: u32 = 4;
-	const BRIDGED_CHAIN_TO_THIS_CHAIN_BALANCE_RATE: u32 = 6;
 	const BRIDGED_CHAIN_MIN_EXTRINSIC_WEIGHT: usize = 5;
 	const BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT: usize = 2048;
 	const BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE: u32 = 1024;
@@ -900,7 +701,6 @@ mod tests {
 	struct OnThisChainBridge;
 
 	impl MessageBridge for OnThisChainBridge {
-		const RELAYER_FEE_PERCENT: u32 = 10;
 		const THIS_CHAIN_ID: ChainId = *b"this";
 		const BRIDGED_CHAIN_ID: ChainId = *b"brdg";
 		const BRIDGED_MESSAGES_PALLET_NAME: &'static str = "";
@@ -908,16 +708,6 @@ mod tests {
 		type ThisChain = ThisChain;
 		type BridgedChain = BridgedChain;
 		type BridgedHeaderChain = BridgedHeaderChain;
-
-		fn bridged_balance_to_this_balance(
-			bridged_balance: BridgedChainBalance,
-			bridged_to_this_conversion_rate_override: Option<FixedU128>,
-		) -> ThisChainBalance {
-			let conversion_rate = bridged_to_this_conversion_rate_override
-				.map(|r| r.to_float() as u32)
-				.unwrap_or(BRIDGED_CHAIN_TO_THIS_CHAIN_BALANCE_RATE);
-			bridged_balance as ThisChainBalance * conversion_rate as ThisChainBalance
-		}
 	}
 
 	/// Bridge that is deployed on BridgedChain and allows sending/receiving messages to/from
@@ -926,7 +716,6 @@ mod tests {
 	struct OnBridgedChainBridge;
 
 	impl MessageBridge for OnBridgedChainBridge {
-		const RELAYER_FEE_PERCENT: u32 = 20;
 		const THIS_CHAIN_ID: ChainId = *b"brdg";
 		const BRIDGED_CHAIN_ID: ChainId = *b"this";
 		const BRIDGED_MESSAGES_PALLET_NAME: &'static str = "";
@@ -934,13 +723,6 @@ mod tests {
 		type ThisChain = BridgedChain;
 		type BridgedChain = ThisChain;
 		type BridgedHeaderChain = ThisHeaderChain;
-
-		fn bridged_balance_to_this_balance(
-			_this_balance: ThisChainBalance,
-			_bridged_to_this_conversion_rate_override: Option<FixedU128>,
-		) -> BridgedChainBalance {
-			unreachable!()
-		}
 	}
 
 	#[derive(Clone, Debug)]
@@ -989,6 +771,7 @@ mod tests {
 		fn max_extrinsic_size() -> u32 {
 			BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE
 		}
+
 		fn max_extrinsic_weight() -> Weight {
 			Weight::zero()
 		}
@@ -1003,12 +786,6 @@ mod tests {
 	impl ThisChainWithMessages for ThisChain {
 		type RuntimeOrigin = ThisChainOrigin;
 		type RuntimeCall = ThisChainCall;
-		type ConfirmationTransactionEstimation = BasicConfirmationTransactionEstimation<
-			ThisChainAccountId,
-			{ DELIVERY_CONFIRMATION_TRANSACTION_WEIGHT },
-			0,
-			0,
-		>;
 
 		fn is_message_accepted(_send_origin: &Self::RuntimeOrigin, lane: &LaneId) -> bool {
 			lane == TEST_LANE_ID
@@ -1017,31 +794,12 @@ mod tests {
 		fn maximal_pending_messages_at_outbound_lane() -> MessageNonce {
 			MAXIMAL_PENDING_MESSAGES_AT_TEST_LANE
 		}
-
-		fn transaction_payment(transaction: MessageTransaction<Weight>) -> BalanceOf<Self> {
-			transaction
-				.dispatch_weight
-				.saturating_mul(THIS_CHAIN_WEIGHT_TO_BALANCE_RATE as u64)
-				.ref_time() as _
-		}
 	}
 
 	impl BridgedChainWithMessages for ThisChain {
 		fn verify_dispatch_weight(_message_payload: &[u8]) -> bool {
 			unreachable!()
 		}
-
-		fn estimate_delivery_transaction(
-			_message_payload: &[u8],
-			_include_pay_dispatch_fee_cost: bool,
-			_message_dispatch_weight: Weight,
-		) -> MessageTransaction<Weight> {
-			unreachable!()
-		}
-
-		fn transaction_payment(_transaction: MessageTransaction<Weight>) -> BalanceOf<Self> {
-			unreachable!()
-		}
 	}
 
 	struct BridgedUnderlyingChain;
@@ -1078,8 +836,6 @@ mod tests {
 	impl ThisChainWithMessages for BridgedChain {
 		type RuntimeOrigin = BridgedChainOrigin;
 		type RuntimeCall = BridgedChainCall;
-		type ConfirmationTransactionEstimation =
-			BasicConfirmationTransactionEstimation<BridgedChainAccountId, 0, 0, 0>;
 
 		fn is_message_accepted(_send_origin: &Self::RuntimeOrigin, _lane: &LaneId) -> bool {
 			unreachable!()
@@ -1088,10 +844,6 @@ mod tests {
 		fn maximal_pending_messages_at_outbound_lane() -> MessageNonce {
 			unreachable!()
 		}
-
-		fn transaction_payment(_transaction: MessageTransaction<Weight>) -> BalanceOf<Self> {
-			unreachable!()
-		}
 	}
 
 	impl BridgedChainWithMessages for BridgedChain {
@@ -1099,24 +851,6 @@ mod tests {
 			message_payload.len() >= BRIDGED_CHAIN_MIN_EXTRINSIC_WEIGHT &&
 				message_payload.len() <= BRIDGED_CHAIN_MAX_EXTRINSIC_WEIGHT
 		}
-
-		fn estimate_delivery_transaction(
-			_message_payload: &[u8],
-			_include_pay_dispatch_fee_cost: bool,
-			message_dispatch_weight: Weight,
-		) -> MessageTransaction<Weight> {
-			MessageTransaction {
-				dispatch_weight: DELIVERY_TRANSACTION_WEIGHT + message_dispatch_weight,
-				size: 0,
-			}
-		}
-
-		fn transaction_payment(transaction: MessageTransaction<Weight>) -> BalanceOf<Self> {
-			transaction
-				.dispatch_weight
-				.saturating_mul(BRIDGED_CHAIN_WEIGHT_TO_BALANCE_RATE as u64)
-				.ref_time() as _
-		}
 	}
 
 	thread_local! {
@@ -1152,50 +886,11 @@ mod tests {
 		vec![42]
 	}
 
-	#[test]
-	fn message_fee_is_checked_by_verifier() {
-		const EXPECTED_MINIMAL_FEE: u32 = 2860;
-
-		// payload of the This -> Bridged chain message
-		let payload = regular_outbound_message_payload();
-
-		// let's check if estimation matching hardcoded value
-		assert_eq!(
-			source::estimate_message_dispatch_and_delivery_fee::<OnThisChainBridge>(
-				&payload,
-				OnThisChainBridge::RELAYER_FEE_PERCENT,
-				None,
-			),
-			Ok(EXPECTED_MINIMAL_FEE),
-		);
-
-		// and now check that the verifier checks the fee
-		assert_eq!(
-			source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
-				&ThisChainOrigin(Ok(frame_system::RawOrigin::Root)),
-				&1,
-				TEST_LANE_ID,
-				&test_lane_outbound_data(),
-				&payload,
-			),
-			Err(source::TOO_LOW_FEE)
-		);
-		assert!(source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
-			&ThisChainOrigin(Ok(frame_system::RawOrigin::Root)),
-			&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!(
 			source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
 				&ThisChainOrigin(Ok(frame_system::RawOrigin::Root)),
-				&1_000_000,
 				b"dsbl",
 				&test_lane_outbound_data(),
 				&regular_outbound_message_payload(),
@@ -1209,7 +904,6 @@ mod tests {
 		assert_eq!(
 			source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
 				&ThisChainOrigin(Ok(frame_system::RawOrigin::Root)),
-				&1_000_000,
 				TEST_LANE_ID,
 				&OutboundLaneData {
 					latest_received_nonce: 100,
@@ -1267,7 +961,7 @@ mod tests {
 	fn using_messages_proof<R>(
 		nonces_end: MessageNonce,
 		outbound_lane_data: Option<OutboundLaneData>,
-		encode_message: impl Fn(MessageNonce, &MessageData<BridgedChainBalance>) -> Option<Vec<u8>>,
+		encode_message: impl Fn(MessageNonce, &MessagePayload) -> Option<Vec<u8>>,
 		encode_outbound_lane_data: impl Fn(&OutboundLaneData) -> Vec<u8>,
 		test: impl Fn(target::FromBridgedChainMessagesProof<H256>) -> R,
 	) -> R {
@@ -1366,10 +1060,9 @@ mod tests {
 				|n, m| {
 					let mut m = m.encode();
 					if n == 5 {
-						m = MessageData { fee: 0, payload: vec![0u8; 42] }.encode();
-						m.truncate(2);
+						m = vec![42]
 					}
-					Some(m.encode())
+					Some(m)
 				},
 				encode_lane_data,
 				|proof| target::verify_messages_proof::<OnThisChainBridge>(proof, 10),
@@ -1464,7 +1157,7 @@ mod tests {
 					}),
 					messages: vec![Message {
 						key: MessageKey { lane_id: *TEST_LANE_ID, nonce: 1 },
-						data: MessageData { payload: vec![42], fee: 0 },
+						payload: vec![42],
 					}],
 				},
 			)]
@@ -1483,53 +1176,4 @@ mod tests {
 			Err(target::MessageProofError::MessagesCountMismatch),
 		);
 	}
-
-	#[test]
-	fn transaction_payment_works_with_zero_multiplier() {
-		use sp_runtime::traits::Zero;
-
-		assert_eq!(
-			transaction_payment(
-				Weight::from_ref_time(100),
-				10,
-				FixedU128::zero(),
-				|weight| weight.ref_time(),
-				MessageTransaction { size: 50, dispatch_weight: Weight::from_ref_time(777) },
-			),
-			100 + 50 * 10,
-		);
-	}
-
-	#[test]
-	fn transaction_payment_works_with_non_zero_multiplier() {
-		use sp_runtime::traits::One;
-
-		assert_eq!(
-			transaction_payment::<u64>(
-				Weight::from_ref_time(100),
-				10,
-				FixedU128::one(),
-				|weight| weight.ref_time(),
-				MessageTransaction { size: 50, dispatch_weight: Weight::from_ref_time(777) },
-			),
-			100 + 50 * 10 + 777,
-		);
-	}
-
-	#[test]
-	fn conversion_rate_override_works() {
-		let payload = regular_outbound_message_payload();
-		let regular_fee = source::estimate_message_dispatch_and_delivery_fee::<OnThisChainBridge>(
-			&payload,
-			OnThisChainBridge::RELAYER_FEE_PERCENT,
-			None,
-		);
-		let overrided_fee = source::estimate_message_dispatch_and_delivery_fee::<OnThisChainBridge>(
-			&payload,
-			OnThisChainBridge::RELAYER_FEE_PERCENT,
-			Some(FixedU128::from_float((BRIDGED_CHAIN_TO_THIS_CHAIN_BALANCE_RATE * 2) as f64)),
-		);
-
-		assert!(regular_fee < overrided_fee);
-	}
 }
diff --git a/bridges/bin/runtime-common/src/messages_api.rs b/bridges/bin/runtime-common/src/messages_api.rs
index 28090daee5ae0a6f01dfd4fd6d241b47c4d45d0a..199e062fe9826cc44527ffe825a44a530fb618ef 100644
--- a/bridges/bin/runtime-common/src/messages_api.rs
+++ b/bridges/bin/runtime-common/src/messages_api.rs
@@ -26,7 +26,7 @@ pub fn outbound_message_details<Runtime, MessagesPalletInstance>(
 	lane: LaneId,
 	begin: MessageNonce,
 	end: MessageNonce,
-) -> Vec<OutboundMessageDetails<Runtime::OutboundMessageFee>>
+) -> Vec<OutboundMessageDetails>
 where
 	Runtime: pallet_bridge_messages::Config<MessagesPalletInstance>,
 	MessagesPalletInstance: 'static,
@@ -40,10 +40,7 @@ where
 				// dispatch message weight is always zero at the source chain, since we're paying for
 				// dispatch at the target chain
 				dispatch_weight: frame_support::weights::Weight::zero(),
-				size: message_data.payload.len() as _,
-				delivery_and_dispatch_fee: message_data.fee,
-				// we're delivering XCM messages here, so fee is always paid at the target chain
-				dispatch_fee_payment: bp_runtime::messages::DispatchFeePayment::AtTargetChain,
+				size: message_data.len() as _,
 			})
 		})
 		.collect()
@@ -52,7 +49,7 @@ where
 /// Implementation of the `To*InboundLaneApi::message_details`.
 pub fn inbound_message_details<Runtime, MessagesPalletInstance>(
 	lane: LaneId,
-	messages: Vec<(MessagePayload, OutboundMessageDetails<Runtime::InboundMessageFee>)>,
+	messages: Vec<(MessagePayload, OutboundMessageDetails)>,
 ) -> Vec<InboundMessageDetails>
 where
 	Runtime: pallet_bridge_messages::Config<MessagesPalletInstance>,
diff --git a/bridges/bin/runtime-common/src/messages_benchmarking.rs b/bridges/bin/runtime-common/src/messages_benchmarking.rs
index 24df69dc90a5e26e2503b189ca53cee545865c16..919c03583b8823608658e9d131e93750d26a1fd6 100644
--- a/bridges/bin/runtime-common/src/messages_benchmarking.rs
+++ b/bridges/bin/runtime-common/src/messages_benchmarking.rs
@@ -21,8 +21,7 @@
 
 use crate::{
 	messages::{
-		source::{FromBridgedChainMessagesDeliveryProof, FromThisChainMessagePayload},
-		target::FromBridgedChainMessagesProof,
+		source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof,
 		AccountIdOf, BalanceOf, BridgedChain, CallOf, HashOf, MessageBridge, ThisChain,
 	},
 	messages_generation::{
@@ -34,25 +33,12 @@ use bp_messages::storage_keys;
 use bp_runtime::{record_all_trie_keys, StorageProofSize};
 use codec::Encode;
 use frame_support::{dispatch::GetDispatchInfo, weights::Weight};
-use pallet_bridge_messages::benchmarking::{
-	MessageDeliveryProofParams, MessageParams, MessageProofParams,
-};
+use pallet_bridge_messages::benchmarking::{MessageDeliveryProofParams, MessageProofParams};
 use sp_core::Hasher;
 use sp_runtime::traits::{Header, MaybeSerializeDeserialize, Zero};
 use sp_std::{fmt::Debug, prelude::*};
 use sp_trie::{trie_types::TrieDBMutBuilderV1, LayoutV1, MemoryDB, Recorder, TrieMut};
 
-/// Prepare outbound message for the `send_message` call.
-pub fn prepare_outbound_message<B>(
-	params: MessageParams<AccountIdOf<ThisChain<B>>>,
-) -> FromThisChainMessagePayload
-where
-	B: MessageBridge,
-	BalanceOf<ThisChain<B>>: From<u64>,
-{
-	vec![0; params.size as usize]
-}
-
 /// Prepare proof of messages for the `receive_messages_proof` call.
 ///
 /// In addition to returning valid messages proof, environment is prepared to verify this message
diff --git a/bridges/bin/runtime-common/src/messages_extension.rs b/bridges/bin/runtime-common/src/messages_extension.rs
index c5fb897b926810b923f45055b867022b7863fd16..28606d58dadfa00a7b59da791408bbbdd9957580 100644
--- a/bridges/bin/runtime-common/src/messages_extension.rs
+++ b/bridges/bin/runtime-common/src/messages_extension.rs
@@ -31,7 +31,6 @@ use sp_runtime::transaction_validity::TransactionValidity;
 impl<
 		BridgedHeaderHash,
 		SourceHeaderChain: bp_messages::target_chain::SourceHeaderChain<
-			<T as Config<I>>::InboundMessageFee,
 			MessagesProof = FromBridgedChainMessagesProof<BridgedHeaderHash>,
 		>,
 		TargetHeaderChain: bp_messages::source_chain::TargetHeaderChain<
diff --git a/bridges/bin/runtime-common/src/messages_generation.rs b/bridges/bin/runtime-common/src/messages_generation.rs
index 822b635cc9b63ea5688a0e034171e05e7e710129..560033d122a84a86c693599571f1ff930dc81a6a 100644
--- a/bridges/bin/runtime-common/src/messages_generation.rs
+++ b/bridges/bin/runtime-common/src/messages_generation.rs
@@ -18,23 +18,19 @@
 
 #![cfg(any(feature = "runtime-benchmarks", test))]
 
-use crate::messages::{BalanceOf, BridgedChain, HashOf, HasherOf, MessageBridge, RawStorageProof};
+use crate::messages::{BridgedChain, HashOf, HasherOf, MessageBridge, RawStorageProof};
 
 use bp_messages::{
-	storage_keys, LaneId, MessageData, MessageKey, MessageNonce, MessagePayload, OutboundLaneData,
+	storage_keys, LaneId, MessageKey, MessageNonce, MessagePayload, OutboundLaneData,
 };
 use bp_runtime::{record_all_trie_keys, StorageProofSize};
 use codec::Encode;
 use sp_core::Hasher;
-use sp_runtime::traits::Zero;
 use sp_std::{ops::RangeInclusive, prelude::*};
 use sp_trie::{trie_types::TrieDBMutBuilderV1, LayoutV1, MemoryDB, Recorder, TrieMut};
 
 /// Simple and correct message data encode function.
-pub(crate) fn encode_all_messages<B: Encode>(
-	_: MessageNonce,
-	m: &MessageData<B>,
-) -> Option<Vec<u8>> {
+pub(crate) fn encode_all_messages(_: MessageNonce, m: &MessagePayload) -> Option<Vec<u8>> {
 	Some(m.encode())
 }
 
@@ -52,7 +48,7 @@ pub(crate) fn prepare_messages_storage_proof<B>(
 	outbound_lane_data: Option<OutboundLaneData>,
 	size: StorageProofSize,
 	message_payload: MessagePayload,
-	encode_message: impl Fn(MessageNonce, &MessageData<BalanceOf<BridgedChain<B>>>) -> Option<Vec<u8>>,
+	encode_message: impl Fn(MessageNonce, &MessagePayload) -> Option<Vec<u8>>,
 	encode_outbound_lane_data: impl Fn(&OutboundLaneData) -> Vec<u8>,
 ) -> (HashOf<BridgedChain<B>>, RawStorageProof)
 where
@@ -71,12 +67,8 @@ where
 		// insert messages
 		for nonce in message_nonces {
 			let message_key = MessageKey { lane_id: lane, nonce };
-			let message_data = MessageData {
-				fee: BalanceOf::<BridgedChain<B>>::zero(),
-				payload: message_payload.clone(),
-			};
-			let message_data = match encode_message(nonce, &message_data) {
-				Some(message_data) => message_data,
+			let message_payload = match encode_message(nonce, &message_payload) {
+				Some(message_payload) => message_payload,
 				None => continue,
 			};
 			let storage_key = storage_keys::message_key(
@@ -85,7 +77,7 @@ where
 				message_key.nonce,
 			)
 			.0;
-			trie.insert(&storage_key, &message_data)
+			trie.insert(&storage_key, &message_payload)
 				.map_err(|_| "TrieMut::insert has failed")
 				.expect("TrieMut::insert should not fail in benchmarks");
 			storage_keys.push(storage_key);
diff --git a/bridges/modules/grandpa/src/weights.rs b/bridges/modules/grandpa/src/weights.rs
index bb9d5270b54fa19a414bf05318e33e1bffd11cff..6997713face51399653de7c158933d86000a115d 100644
--- a/bridges/modules/grandpa/src/weights.rs
+++ b/bridges/modules/grandpa/src/weights.rs
@@ -17,7 +17,7 @@
 //! Autogenerated weights for `pallet_bridge_grandpa`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2022-10-04, STEPS: 50, REPEAT: 20
+//! DATE: 2022-11-17, STEPS: 50, REPEAT: 20
 //! LOW RANGE: [], HIGH RANGE: []
 //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled
 //! CHAIN: Some("dev"), DB CACHE: 1024
@@ -59,9 +59,9 @@ pub trait WeightInfo {
 pub struct BridgeWeight<T>(PhantomData<T>);
 impl<T: frame_system::Config> WeightInfo for BridgeWeight<T> {
 	fn submit_finality_proof(p: u32, v: u32) -> Weight {
-		Weight::from_ref_time(105_417_000 as u64)
-			.saturating_add(Weight::from_ref_time(40_923_000 as u64).saturating_mul(p as u64))
-			.saturating_add(Weight::from_ref_time(1_691_000 as u64).saturating_mul(v as u64))
+		Weight::from_ref_time(198_274_668 as u64)
+			.saturating_add(Weight::from_ref_time(39_830_948 as u64).saturating_mul(p as u64))
+			.saturating_add(Weight::from_ref_time(1_535_681 as u64).saturating_mul(v as u64))
 			.saturating_add(T::DbWeight::get().reads(7 as u64))
 			.saturating_add(T::DbWeight::get().writes(6 as u64))
 	}
@@ -70,9 +70,9 @@ impl<T: frame_system::Config> WeightInfo for BridgeWeight<T> {
 // For backwards compatibility and tests
 impl WeightInfo for () {
 	fn submit_finality_proof(p: u32, v: u32) -> Weight {
-		Weight::from_ref_time(105_417_000 as u64)
-			.saturating_add(Weight::from_ref_time(40_923_000 as u64).saturating_mul(p as u64))
-			.saturating_add(Weight::from_ref_time(1_691_000 as u64).saturating_mul(v as u64))
+		Weight::from_ref_time(198_274_668 as u64)
+			.saturating_add(Weight::from_ref_time(39_830_948 as u64).saturating_mul(p as u64))
+			.saturating_add(Weight::from_ref_time(1_535_681 as u64).saturating_mul(v as u64))
 			.saturating_add(RocksDbWeight::get().reads(7 as u64))
 			.saturating_add(RocksDbWeight::get().writes(6 as u64))
 	}
diff --git a/bridges/modules/messages/src/benchmarking.rs b/bridges/modules/messages/src/benchmarking.rs
index e7650f17214db5e1acf7210b196f0e5b6c055de5..254ba6cbace30a5730e85b5d0629a447b839b876 100644
--- a/bridges/modules/messages/src/benchmarking.rs
+++ b/bridges/modules/messages/src/benchmarking.rs
@@ -18,35 +18,25 @@
 
 use crate::{
 	inbound_lane::InboundLaneStorage, inbound_lane_storage, outbound_lane,
-	outbound_lane::ReceivalConfirmationResult, weights_ext::EXPECTED_DEFAULT_MESSAGE_LENGTH, Call,
-	OutboundLanes, OutboundMessages,
+	weights_ext::EXPECTED_DEFAULT_MESSAGE_LENGTH, Call, OutboundLanes,
 };
 
 use bp_messages::{
 	source_chain::TargetHeaderChain, target_chain::SourceHeaderChain, DeliveredMessages,
-	InboundLaneData, LaneId, MessageData, MessageKey, MessageNonce, OutboundLaneData,
-	UnrewardedRelayer, UnrewardedRelayersState,
+	InboundLaneData, LaneId, MessageNonce, OutboundLaneData, UnrewardedRelayer,
+	UnrewardedRelayersState,
 };
-use bp_runtime::{messages::DispatchFeePayment, StorageProofSize};
+use bp_runtime::StorageProofSize;
 use frame_benchmarking::{account, benchmarks_instance_pallet};
-use frame_support::{traits::Get, weights::Weight};
+use frame_support::weights::Weight;
 use frame_system::RawOrigin;
-use sp_std::{collections::vec_deque::VecDeque, convert::TryInto, ops::RangeInclusive, prelude::*};
+use sp_std::{ops::RangeInclusive, prelude::*};
 
 const SEED: u32 = 0;
 
 /// Pallet we're benchmarking here.
 pub struct Pallet<T: Config<I>, I: 'static>(crate::Pallet<T, I>);
 
-/// Benchmark-specific message parameters.
-#[derive(Debug)]
-pub struct MessageParams<ThisAccountId> {
-	/// Size of the message payload.
-	pub size: u32,
-	/// Message sender account.
-	pub sender_account: ThisAccountId,
-}
-
 /// Benchmark-specific message proof parameters.
 #[derive(Debug)]
 pub struct MessageProofParams {
@@ -58,8 +48,6 @@ pub struct MessageProofParams {
 	pub outbound_lane_data: Option<OutboundLaneData>,
 	/// Proof size requirements.
 	pub size: StorageProofSize,
-	/// Where the fee for dispatching message is paid?
-	pub dispatch_fee_payment: DispatchFeePayment,
 }
 
 /// Benchmark-specific message delivery proof parameters.
@@ -79,29 +67,14 @@ pub trait Config<I: 'static>: crate::Config<I> {
 	fn bench_lane_id() -> LaneId {
 		Default::default()
 	}
-	/// Get maximal size of the message payload.
-	fn maximal_message_size() -> u32;
 	/// Return id of relayer account at the bridged chain.
 	fn bridged_relayer_id() -> Self::InboundRelayer;
-	/// Return balance of given account.
-	fn account_balance(account: &Self::AccountId) -> Self::OutboundMessageFee;
 	/// Create given account and give it enough balance for test purposes.
 	fn endow_account(account: &Self::AccountId);
-	/// Fee paid by submitter for single message delivery.
-	fn message_fee() -> Self::OutboundMessageFee {
-		100_000_000_000_000.into()
-	}
-	/// Prepare message to send over lane.
-	fn prepare_outbound_message(
-		params: MessageParams<Self::AccountId>,
-	) -> (Self::OutboundPayload, Self::OutboundMessageFee);
 	/// Prepare messages proof to receive by the module.
 	fn prepare_message_proof(
 		params: MessageProofParams,
-	) -> (
-		<Self::SourceHeaderChain as SourceHeaderChain<Self::InboundMessageFee>>::MessagesProof,
-		Weight,
-	);
+	) -> (<Self::SourceHeaderChain as SourceHeaderChain>::MessagesProof, Weight);
 	/// Prepare messages delivery proof to receive by the module.
 	fn prepare_message_delivery_proof(
 		params: MessageDeliveryProofParams<Self::AccountId>,
@@ -115,156 +88,6 @@ benchmarks_instance_pallet! {
 	// Benchmarks that are used directly by the runtime.
 	//
 
-	// Benchmark `send_message` extrinsic with the worst possible conditions:
-	// * outbound lane already has state, so it needs to be read and decoded;
-	// * relayers fund account does not exists (in practice it needs to exist in production environment);
-	// * maximal number of messages is being pruned during the call;
-	// * message size is minimal for the target chain.
-	//
-	// Result of this benchmark is used as a base weight for `send_message` call. Then the 'message weight'
-	// (estimated using `send_half_maximal_message_worst_case` and `send_maximal_message_worst_case`) is
-	// added.
-	send_minimal_message_worst_case {
-		let lane_id = T::bench_lane_id();
-		let sender = account("sender", 0, SEED);
-		T::endow_account(&sender);
-
-		// 'send' messages that are to be pruned when our message is sent
-		for _nonce in 1..=T::MaxMessagesToPruneAtOnce::get() {
-			send_regular_message::<T, I>();
-		}
-		confirm_message_delivery::<T, I>(T::MaxMessagesToPruneAtOnce::get());
-
-		let (payload, fee) = T::prepare_outbound_message(MessageParams {
-			size: 0,
-			sender_account: sender.clone(),
-		});
-	}: send_message(RawOrigin::Signed(sender), lane_id, payload, fee)
-	verify {
-		assert_eq!(
-			crate::OutboundLanes::<T, I>::get(&T::bench_lane_id()).latest_generated_nonce,
-			T::MaxMessagesToPruneAtOnce::get() + 1,
-		);
-	}
-
-	// Benchmark `send_message` extrinsic with the worst possible conditions:
-	// * outbound lane already has state, so it needs to be read and decoded;
-	// * relayers fund account does not exists (in practice it needs to exist in production environment);
-	// * maximal number of messages is being pruned during the call;
-	// * message size is 1KB.
-	//
-	// With single KB of message size, the weight of the call is increased (roughly) by
-	// `(send_16_kb_message_worst_case - send_1_kb_message_worst_case) / 15`.
-	send_1_kb_message_worst_case {
-		let lane_id = T::bench_lane_id();
-		let sender = account("sender", 0, SEED);
-		T::endow_account(&sender);
-
-		// 'send' messages that are to be pruned when our message is sent
-		for _nonce in 1..=T::MaxMessagesToPruneAtOnce::get() {
-			send_regular_message::<T, I>();
-		}
-		confirm_message_delivery::<T, I>(T::MaxMessagesToPruneAtOnce::get());
-
-		let size = 1024;
-		assert!(
-			T::maximal_message_size() > size,
-			"This benchmark can only be used with runtime that accepts 1KB messages",
-		);
-
-		let (payload, fee) = T::prepare_outbound_message(MessageParams {
-			size,
-			sender_account: sender.clone(),
-		});
-	}: send_message(RawOrigin::Signed(sender), lane_id, payload, fee)
-	verify {
-		assert_eq!(
-			crate::OutboundLanes::<T, I>::get(&T::bench_lane_id()).latest_generated_nonce,
-			T::MaxMessagesToPruneAtOnce::get() + 1,
-		);
-	}
-
-	// Benchmark `send_message` extrinsic with the worst possible conditions:
-	// * outbound lane already has state, so it needs to be read and decoded;
-	// * relayers fund account does not exists (in practice it needs to exist in production environment);
-	// * maximal number of messages is being pruned during the call;
-	// * message size is 16KB.
-	//
-	// With single KB of message size, the weight of the call is increased (roughly) by
-	// `(send_16_kb_message_worst_case - send_1_kb_message_worst_case) / 15`.
-	send_16_kb_message_worst_case {
-		let lane_id = T::bench_lane_id();
-		let sender = account("sender", 0, SEED);
-		T::endow_account(&sender);
-
-		// 'send' messages that are to be pruned when our message is sent
-		for _nonce in 1..=T::MaxMessagesToPruneAtOnce::get() {
-			send_regular_message::<T, I>();
-		}
-		confirm_message_delivery::<T, I>(T::MaxMessagesToPruneAtOnce::get());
-
-		let size = 16 * 1024;
-		assert!(
-			T::maximal_message_size() > size,
-			"This benchmark can only be used with runtime that accepts 16KB messages",
-		);
-
-		let (payload, fee) = T::prepare_outbound_message(MessageParams {
-			size,
-			sender_account: sender.clone(),
-		});
-	}: send_message(RawOrigin::Signed(sender), lane_id, payload, fee)
-	verify {
-		assert_eq!(
-			crate::OutboundLanes::<T, I>::get(&T::bench_lane_id()).latest_generated_nonce,
-			T::MaxMessagesToPruneAtOnce::get() + 1,
-		);
-	}
-
-	// Benchmark `increase_message_fee` with following conditions:
-	// * message has maximal message;
-	// * submitter account is killed because its balance is less than ED after payment.
-	//
-	// Result of this benchmark is directly used by weight formula of the call.
-	maximal_increase_message_fee {
-		let sender = account("sender", 42, SEED);
-		T::endow_account(&sender);
-
-		let additional_fee = T::account_balance(&sender);
-		let lane_id = T::bench_lane_id();
-		let nonce = 1;
-
-		send_regular_message_with_payload::<T, I>(vec![42u8; T::maximal_message_size() as _]);
-	}: increase_message_fee(RawOrigin::Signed(sender.clone()), lane_id, nonce, additional_fee)
-	verify {
-		assert_eq!(
-			OutboundMessages::<T, I>::get(MessageKey { lane_id, nonce }).unwrap().fee,
-			T::message_fee() + additional_fee,
-		);
-	}
-
-	// Benchmark `increase_message_fee` with following conditions:
-	// * message size varies from minimal to maximal;
-	// * submitter account is killed because its balance is less than ED after payment.
-	increase_message_fee {
-		let i in 0..T::maximal_message_size().try_into().unwrap_or_default();
-
-		let sender = account("sender", 42, SEED);
-		T::endow_account(&sender);
-
-		let additional_fee = T::account_balance(&sender);
-		let lane_id = T::bench_lane_id();
-		let nonce = 1;
-
-		send_regular_message_with_payload::<T, I>(vec![42u8; i as _]);
-	}: increase_message_fee(RawOrigin::Signed(sender.clone()), lane_id, nonce, additional_fee)
-	verify {
-		assert_eq!(
-			OutboundMessages::<T, I>::get(MessageKey { lane_id, nonce }).unwrap().fee,
-			T::message_fee() + additional_fee,
-		);
-	}
-
 	// Benchmark `receive_messages_proof` extrinsic with single minimal-weight message and following conditions:
 	// * proof does not include outbound lane state proof;
 	// * inbound lane already has state, so it needs to be read and decoded;
@@ -286,7 +109,6 @@ benchmarks_instance_pallet! {
 			message_nonces: 21..=21,
 			outbound_lane_data: None,
 			size: StorageProofSize::Minimal(EXPECTED_DEFAULT_MESSAGE_LENGTH),
-			dispatch_fee_payment: DispatchFeePayment::AtTargetChain,
 		});
 	}: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 1, dispatch_weight)
 	verify {
@@ -321,7 +143,6 @@ benchmarks_instance_pallet! {
 			message_nonces: 21..=22,
 			outbound_lane_data: None,
 			size: StorageProofSize::Minimal(EXPECTED_DEFAULT_MESSAGE_LENGTH),
-			dispatch_fee_payment: DispatchFeePayment::AtTargetChain,
 		});
 	}: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 2, dispatch_weight)
 	verify {
@@ -360,7 +181,6 @@ benchmarks_instance_pallet! {
 				latest_generated_nonce: 21,
 			}),
 			size: StorageProofSize::Minimal(EXPECTED_DEFAULT_MESSAGE_LENGTH),
-			dispatch_fee_payment: DispatchFeePayment::AtTargetChain,
 		});
 	}: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 1, dispatch_weight)
 	verify {
@@ -392,7 +212,6 @@ benchmarks_instance_pallet! {
 			message_nonces: 21..=21,
 			outbound_lane_data: None,
 			size: StorageProofSize::HasExtraNodes(1024),
-			dispatch_fee_payment: DispatchFeePayment::AtTargetChain,
 		});
 	}: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 1, dispatch_weight)
 	verify {
@@ -427,7 +246,6 @@ benchmarks_instance_pallet! {
 			message_nonces: 21..=21,
 			outbound_lane_data: None,
 			size: StorageProofSize::HasExtraNodes(16 * 1024),
-			dispatch_fee_payment: DispatchFeePayment::AtTargetChain,
 		});
 	}: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 1, dispatch_weight)
 	verify {
@@ -461,7 +279,6 @@ benchmarks_instance_pallet! {
 			message_nonces: 21..=21,
 			outbound_lane_data: None,
 			size: StorageProofSize::Minimal(EXPECTED_DEFAULT_MESSAGE_LENGTH),
-			dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
 		});
 	}: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 1, dispatch_weight)
 	verify {
@@ -479,7 +296,6 @@ benchmarks_instance_pallet! {
 	// This is base benchmark for all other confirmations delivery benchmarks.
 	receive_delivery_proof_for_single_message {
 		let relayer_id: T::AccountId = account("relayer", 0, SEED);
-		let relayer_balance = T::account_balance(&relayer_id);
 
 		// send message that we're going to confirm
 		send_regular_message::<T, I>();
@@ -515,7 +331,6 @@ benchmarks_instance_pallet! {
 	//   - weight(receive_delivery_proof_for_single_message)`.
 	receive_delivery_proof_for_two_messages_by_single_relayer {
 		let relayer_id: T::AccountId = account("relayer", 0, SEED);
-		let relayer_balance = T::account_balance(&relayer_id);
 
 		// send message that we're going to confirm
 		send_regular_message::<T, I>();
@@ -554,9 +369,7 @@ benchmarks_instance_pallet! {
 	//   - weight(receive_delivery_proof_for_two_messages_by_single_relayer)`.
 	receive_delivery_proof_for_two_messages_by_two_relayers {
 		let relayer1_id: T::AccountId = account("relayer1", 1, SEED);
-		let relayer1_balance = T::account_balance(&relayer1_id);
 		let relayer2_id: T::AccountId = account("relayer2", 2, SEED);
-		let relayer2_balance = T::account_balance(&relayer2_id);
 
 		// send message that we're going to confirm
 		send_regular_message::<T, I>();
@@ -593,28 +406,7 @@ benchmarks_instance_pallet! {
 
 fn send_regular_message<T: Config<I>, I: 'static>() {
 	let mut outbound_lane = outbound_lane::<T, I>(T::bench_lane_id());
-	outbound_lane.send_message(MessageData { payload: vec![], fee: T::message_fee() });
-}
-
-fn send_regular_message_with_payload<T: Config<I>, I: 'static>(payload: Vec<u8>) {
-	let mut outbound_lane = outbound_lane::<T, I>(T::bench_lane_id());
-	outbound_lane.send_message(MessageData { payload, fee: T::message_fee() });
-}
-
-fn confirm_message_delivery<T: Config<I>, I: 'static>(nonce: MessageNonce) {
-	let mut outbound_lane = outbound_lane::<T, I>(T::bench_lane_id());
-	let latest_received_nonce = outbound_lane.data().latest_received_nonce;
-	let mut relayers = VecDeque::with_capacity((nonce - latest_received_nonce) as usize);
-	for nonce in latest_received_nonce + 1..=nonce {
-		relayers.push_back(UnrewardedRelayer {
-			relayer: (),
-			messages: DeliveredMessages::new(nonce, true),
-		});
-	}
-	assert!(matches!(
-		outbound_lane.confirm_delivery(nonce - latest_received_nonce, nonce, &relayers),
-		ReceivalConfirmationResult::ConfirmedMessages(_),
-	));
+	outbound_lane.send_message(vec![]);
 }
 
 fn receive_messages<T: Config<I>, I: 'static>(nonce: MessageNonce) {
diff --git a/bridges/modules/messages/src/inbound_lane.rs b/bridges/modules/messages/src/inbound_lane.rs
index bee1df06c5a7154584cc8f59273ede27a2cccc29..ba4483e608c3c48a647569247ce7a6c6f760c452 100644
--- a/bridges/modules/messages/src/inbound_lane.rs
+++ b/bridges/modules/messages/src/inbound_lane.rs
@@ -31,8 +31,6 @@ use sp_std::prelude::PartialEq;
 
 /// Inbound lane storage.
 pub trait InboundLaneStorage {
-	/// Delivery and dispatch fee type on source chain.
-	type MessageFee;
 	/// Id of relayer on source chain.
 	type Relayer: Clone + PartialEq;
 
@@ -183,12 +181,12 @@ impl<S: InboundLaneStorage> InboundLane<S> {
 	}
 
 	/// Receive new message.
-	pub fn receive_message<P: MessageDispatch<AccountId, S::MessageFee>, AccountId>(
+	pub fn receive_message<P: MessageDispatch<AccountId>, AccountId>(
 		&mut self,
 		relayer_at_bridged_chain: &S::Relayer,
 		relayer_at_this_chain: &AccountId,
 		nonce: MessageNonce,
-		message_data: DispatchMessageData<P::DispatchPayload, S::MessageFee>,
+		message_data: DispatchMessageData<P::DispatchPayload>,
 	) -> ReceivalResult {
 		let mut data = self.storage.data();
 		let is_correct_message = nonce == data.last_delivered_nonce() + 1;
@@ -242,9 +240,9 @@ mod tests {
 	use crate::{
 		inbound_lane,
 		mock::{
-			dispatch_result, message_data, run_test, unrewarded_relayer, TestMessageDispatch,
-			TestRuntime, REGULAR_PAYLOAD, TEST_LANE_ID, TEST_RELAYER_A, TEST_RELAYER_B,
-			TEST_RELAYER_C,
+			dispatch_result, inbound_message_data, run_test, unrewarded_relayer,
+			TestMessageDispatch, TestRuntime, REGULAR_PAYLOAD, TEST_LANE_ID, TEST_RELAYER_A,
+			TEST_RELAYER_B, TEST_RELAYER_C,
 		},
 		RuntimeInboundLaneStorage,
 	};
@@ -258,7 +256,7 @@ mod tests {
 				&TEST_RELAYER_A,
 				&TEST_RELAYER_A,
 				nonce,
-				message_data(REGULAR_PAYLOAD).into()
+				inbound_message_data(REGULAR_PAYLOAD)
 			),
 			ReceivalResult::Dispatched(dispatch_result(0))
 		);
@@ -386,7 +384,7 @@ mod tests {
 					&TEST_RELAYER_A,
 					&TEST_RELAYER_A,
 					10,
-					message_data(REGULAR_PAYLOAD).into()
+					inbound_message_data(REGULAR_PAYLOAD)
 				),
 				ReceivalResult::InvalidNonce
 			);
@@ -406,7 +404,7 @@ mod tests {
 						&(TEST_RELAYER_A + current_nonce),
 						&(TEST_RELAYER_A + current_nonce),
 						current_nonce,
-						message_data(REGULAR_PAYLOAD).into()
+						inbound_message_data(REGULAR_PAYLOAD)
 					),
 					ReceivalResult::Dispatched(dispatch_result(0))
 				);
@@ -417,7 +415,7 @@ mod tests {
 					&(TEST_RELAYER_A + max_nonce + 1),
 					&(TEST_RELAYER_A + max_nonce + 1),
 					max_nonce + 1,
-					message_data(REGULAR_PAYLOAD).into()
+					inbound_message_data(REGULAR_PAYLOAD)
 				),
 				ReceivalResult::TooManyUnrewardedRelayers,
 			);
@@ -427,7 +425,7 @@ mod tests {
 					&(TEST_RELAYER_A + max_nonce),
 					&(TEST_RELAYER_A + max_nonce),
 					max_nonce + 1,
-					message_data(REGULAR_PAYLOAD).into()
+					inbound_message_data(REGULAR_PAYLOAD)
 				),
 				ReceivalResult::TooManyUnrewardedRelayers,
 			);
@@ -445,7 +443,7 @@ mod tests {
 						&TEST_RELAYER_A,
 						&TEST_RELAYER_A,
 						current_nonce,
-						message_data(REGULAR_PAYLOAD).into()
+						inbound_message_data(REGULAR_PAYLOAD)
 					),
 					ReceivalResult::Dispatched(dispatch_result(0))
 				);
@@ -456,7 +454,7 @@ mod tests {
 					&TEST_RELAYER_B,
 					&TEST_RELAYER_B,
 					max_nonce + 1,
-					message_data(REGULAR_PAYLOAD).into()
+					inbound_message_data(REGULAR_PAYLOAD)
 				),
 				ReceivalResult::TooManyUnconfirmedMessages,
 			);
@@ -466,7 +464,7 @@ mod tests {
 					&TEST_RELAYER_A,
 					&TEST_RELAYER_A,
 					max_nonce + 1,
-					message_data(REGULAR_PAYLOAD).into()
+					inbound_message_data(REGULAR_PAYLOAD)
 				),
 				ReceivalResult::TooManyUnconfirmedMessages,
 			);
@@ -482,7 +480,7 @@ mod tests {
 					&TEST_RELAYER_A,
 					&TEST_RELAYER_A,
 					1,
-					message_data(REGULAR_PAYLOAD).into()
+					inbound_message_data(REGULAR_PAYLOAD)
 				),
 				ReceivalResult::Dispatched(dispatch_result(0))
 			);
@@ -491,7 +489,7 @@ mod tests {
 					&TEST_RELAYER_B,
 					&TEST_RELAYER_B,
 					2,
-					message_data(REGULAR_PAYLOAD).into()
+					inbound_message_data(REGULAR_PAYLOAD)
 				),
 				ReceivalResult::Dispatched(dispatch_result(0))
 			);
@@ -500,7 +498,7 @@ mod tests {
 					&TEST_RELAYER_A,
 					&TEST_RELAYER_A,
 					3,
-					message_data(REGULAR_PAYLOAD).into()
+					inbound_message_data(REGULAR_PAYLOAD)
 				),
 				ReceivalResult::Dispatched(dispatch_result(0))
 			);
@@ -524,7 +522,7 @@ mod tests {
 					&TEST_RELAYER_A,
 					&TEST_RELAYER_A,
 					1,
-					message_data(REGULAR_PAYLOAD).into()
+					inbound_message_data(REGULAR_PAYLOAD)
 				),
 				ReceivalResult::Dispatched(dispatch_result(0))
 			);
@@ -533,7 +531,7 @@ mod tests {
 					&TEST_RELAYER_B,
 					&TEST_RELAYER_B,
 					1,
-					message_data(REGULAR_PAYLOAD).into()
+					inbound_message_data(REGULAR_PAYLOAD)
 				),
 				ReceivalResult::InvalidNonce,
 			);
@@ -560,7 +558,7 @@ mod tests {
 					&TEST_RELAYER_A,
 					&TEST_RELAYER_A,
 					1,
-					message_data(payload).into()
+					inbound_message_data(payload)
 				),
 				ReceivalResult::Dispatched(dispatch_result(1))
 			);
diff --git a/bridges/modules/messages/src/lib.rs b/bridges/modules/messages/src/lib.rs
index 66f568e698c9ec6cf9b0f2f62d725df9638c7fcf..d6a5ffe453c0bd59e743c5b18432811e9dc71da2 100644
--- a/bridges/modules/messages/src/lib.rs
+++ b/bridges/modules/messages/src/lib.rs
@@ -38,7 +38,7 @@
 #![allow(clippy::unused_unit)]
 
 pub use inbound_lane::StoredInboundLaneData;
-pub use outbound_lane::StoredMessageData;
+pub use outbound_lane::StoredMessagePayload;
 pub use weights::WeightInfo;
 pub use weights_ext::{
 	ensure_able_to_receive_confirmation, ensure_able_to_receive_message,
@@ -59,17 +59,16 @@ use bp_messages::{
 		DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages, SourceHeaderChain,
 	},
 	total_unrewarded_messages, DeliveredMessages, InboundLaneData, InboundMessageDetails, LaneId,
-	MessageData, MessageKey, MessageNonce, MessagePayload, MessagesOperatingMode, OutboundLaneData,
-	OutboundMessageDetails, Parameter as MessagesParameter, UnrewardedRelayer,
-	UnrewardedRelayersState,
+	MessageKey, MessageNonce, MessagePayload, MessagesOperatingMode, OutboundLaneData,
+	OutboundMessageDetails, UnrewardedRelayer, UnrewardedRelayersState,
 };
 use bp_runtime::{BasicOperatingMode, ChainId, OwnedBridgeModule, Size};
 use codec::{Decode, Encode, MaxEncodedLen};
 use frame_support::{dispatch::PostDispatchInfo, ensure, fail, traits::Get};
-use num_traits::{SaturatingAdd, Zero};
+use num_traits::Zero;
 use sp_std::{
-	cell::RefCell, cmp::PartialOrd, collections::vec_deque::VecDeque, marker::PhantomData,
-	ops::RangeInclusive, prelude::*,
+	cell::RefCell, collections::vec_deque::VecDeque, marker::PhantomData, ops::RangeInclusive,
+	prelude::*,
 };
 
 mod inbound_lane;
@@ -108,11 +107,6 @@ pub mod pallet {
 		/// Gets the chain id value from the instance.
 		#[pallet::constant]
 		type BridgedChainId: Get<ChainId>;
-		/// Pallet parameter that is opaque to the pallet itself, but may be used by the runtime
-		/// for integrating the pallet.
-		///
-		/// All pallet parameters may only be updated either by the root, or by the pallet owner.
-		type Parameter: MessagesParameter;
 
 		/// Maximal number of messages that may be pruned during maintenance. Maintenance occurs
 		/// whenever new message is sent. The reason is that if you want to use lane, you should
@@ -142,25 +136,14 @@ pub mod pallet {
 		/// these messages are from different lanes.
 		type MaxUnconfirmedMessagesAtInboundLane: Get<MessageNonce>;
 
-		/// Maximal size of the outbound payload.
+		/// Maximal encoded size of the outbound payload.
 		#[pallet::constant]
 		type MaximalOutboundPayloadSize: Get<u32>;
 		/// Payload type of outbound messages. This payload is dispatched on the bridged chain.
 		type OutboundPayload: Parameter + Size;
-		/// Message fee type of outbound messages. This fee is paid on this chain.
-		type OutboundMessageFee: Default
-			+ From<u64>
-			+ PartialOrd
-			+ Parameter
-			+ SaturatingAdd
-			+ Zero
-			+ Copy
-			+ MaxEncodedLen;
 
 		/// Payload type of inbound messages. This payload is dispatched on this chain.
 		type InboundPayload: Decode;
-		/// Message fee type of inbound messages. This fee is paid on the bridged chain.
-		type InboundMessageFee: Decode + Zero;
 		/// Identifier of relayer that deliver messages to this chain. Relayer reward is paid on the
 		/// bridged chain.
 		type InboundRelayer: Parameter + MaxEncodedLen;
@@ -170,16 +153,11 @@ pub mod pallet {
 		/// Target header chain.
 		type TargetHeaderChain: TargetHeaderChain<Self::OutboundPayload, Self::AccountId>;
 		/// Message payload verifier.
-		type LaneMessageVerifier: LaneMessageVerifier<
-			Self::RuntimeOrigin,
-			Self::OutboundPayload,
-			Self::OutboundMessageFee,
-		>;
+		type LaneMessageVerifier: LaneMessageVerifier<Self::RuntimeOrigin, Self::OutboundPayload>;
 		/// Message delivery payment.
 		type MessageDeliveryAndDispatchPayment: MessageDeliveryAndDispatchPayment<
 			Self::RuntimeOrigin,
 			Self::AccountId,
-			Self::OutboundMessageFee,
 		>;
 		/// Handler for accepted messages.
 		type OnMessageAccepted: OnMessageAccepted;
@@ -189,19 +167,17 @@ pub mod pallet {
 		// Types that are used by inbound_lane (on target chain).
 
 		/// Source header chain, as it is represented on target chain.
-		type SourceHeaderChain: SourceHeaderChain<Self::InboundMessageFee>;
+		type SourceHeaderChain: SourceHeaderChain;
 		/// Message dispatch.
 		type MessageDispatch: MessageDispatch<
 			Self::AccountId,
-			Self::InboundMessageFee,
 			DispatchPayload = Self::InboundPayload,
 		>;
 	}
 
 	/// Shortcut to messages proof type for Config.
-	type MessagesProofOf<T, I> = <<T as Config<I>>::SourceHeaderChain as SourceHeaderChain<
-		<T as Config<I>>::InboundMessageFee,
-	>>::MessagesProof;
+	type MessagesProofOf<T, I> =
+		<<T as Config<I>>::SourceHeaderChain as SourceHeaderChain>::MessagesProof;
 	/// Shortcut to messages delivery proof type for Config.
 	type MessagesDeliveryProofOf<T, I> =
 		<<T as Config<I>>::TargetHeaderChain as TargetHeaderChain<
@@ -241,101 +217,6 @@ pub mod pallet {
 			<Self as OwnedBridgeModule<_>>::set_operating_mode(origin, operating_mode)
 		}
 
-		/// Update pallet parameter.
-		///
-		/// May only be called either by root, or by `PalletOwner`.
-		///
-		/// The weight is: single read for permissions check + 2 writes for parameter value and
-		/// event.
-		#[pallet::weight((T::DbWeight::get().reads_writes(1, 2), DispatchClass::Operational))]
-		pub fn update_pallet_parameter(
-			origin: OriginFor<T>,
-			parameter: T::Parameter,
-		) -> DispatchResult {
-			Self::ensure_owner_or_root(origin)?;
-			parameter.save();
-			Self::deposit_event(Event::ParameterUpdated { parameter });
-			Ok(())
-		}
-
-		/// Send message over lane.
-		#[pallet::weight(T::WeightInfo::send_message_weight(payload, T::DbWeight::get()))]
-		pub fn send_message(
-			origin: OriginFor<T>,
-			lane_id: LaneId,
-			payload: T::OutboundPayload,
-			delivery_and_dispatch_fee: T::OutboundMessageFee,
-		) -> DispatchResultWithPostInfo {
-			crate::send_message::<T, I>(origin, lane_id, payload, delivery_and_dispatch_fee).map(
-				|sent_message| PostDispatchInfo {
-					actual_weight: Some(sent_message.weight),
-					pays_fee: Pays::Yes,
-				},
-			)
-		}
-
-		/// Pay additional fee for the message.
-		#[pallet::weight(T::WeightInfo::maximal_increase_message_fee())]
-		pub fn increase_message_fee(
-			origin: OriginFor<T>,
-			lane_id: LaneId,
-			nonce: MessageNonce,
-			additional_fee: T::OutboundMessageFee,
-		) -> DispatchResultWithPostInfo {
-			Self::ensure_not_halted().map_err(Error::<T, I>::BridgeModule)?;
-			// if someone tries to pay for already-delivered message, we're rejecting this intention
-			// (otherwise this additional fee will be locked forever in relayers fund)
-			//
-			// if someone tries to pay for not-yet-sent message, we're rejecting this intention, or
-			// we're risking to have mess in the storage
-			let lane = outbound_lane::<T, I>(lane_id);
-			ensure!(
-				nonce > lane.data().latest_received_nonce,
-				Error::<T, I>::MessageIsAlreadyDelivered
-			);
-			ensure!(
-				nonce <= lane.data().latest_generated_nonce,
-				Error::<T, I>::MessageIsNotYetSent
-			);
-
-			// withdraw additional fee from submitter
-			T::MessageDeliveryAndDispatchPayment::pay_delivery_and_dispatch_fee(
-				&origin,
-				&additional_fee,
-			)
-			.map_err(|err| {
-				log::trace!(
-					target: LOG_TARGET,
-					"Submitter can't pay additional fee {:?} for the message {:?}/{:?}: {:?}",
-					additional_fee,
-					lane_id,
-					nonce,
-					err,
-				);
-
-				Error::<T, I>::FailedToWithdrawMessageFee
-			})?;
-
-			// and finally update fee in the storage
-			let message_key = MessageKey { lane_id, nonce };
-			let message_size = OutboundMessages::<T, I>::mutate(message_key, |message_data| {
-				// saturating_add is fine here - overflow here means that someone controls all
-				// chain funds, which shouldn't ever happen + `pay_delivery_and_dispatch_fee`
-				// above will fail before we reach here
-				let message_data = message_data.as_mut().expect(
-					"the message is sent and not yet delivered; so it is in the storage; qed",
-				);
-				message_data.fee = message_data.fee.saturating_add(&additional_fee);
-				message_data.payload.len()
-			});
-
-			// compute actual dispatch weight that depends on the stored message size
-			let actual_weight = T::WeightInfo::maximal_increase_message_fee()
-				.min(T::WeightInfo::increase_message_fee(message_size as _));
-
-			Ok(PostDispatchInfo { actual_weight: Some(actual_weight), pays_fee: Pays::Yes })
-		}
-
 		/// Receive messages proof from bridged chain.
 		///
 		/// The weight of the call assumes that the transaction always brings outbound lane
@@ -378,7 +259,6 @@ pub mod pallet {
 			// verify messages proof && convert proof into messages
 			let messages = verify_and_decode_messages_proof::<
 				T::SourceHeaderChain,
-				T::InboundMessageFee,
 				T::InboundPayload,
 			>(proof, messages_count)
 			.map_err(|err| {
@@ -636,8 +516,6 @@ pub mod pallet {
 	#[pallet::event]
 	#[pallet::generate_deposit(pub(super) fn deposit_event)]
 	pub enum Event<T: Config<I>, I: 'static = ()> {
-		/// Pallet parameter has been updated.
-		ParameterUpdated { parameter: T::Parameter },
 		/// Message has been accepted and is waiting to be delivered.
 		MessageAccepted { lane_id: LaneId, nonce: MessageNonce },
 		/// Messages in the inclusive range have been delivered to the bridged chain.
@@ -709,7 +587,7 @@ pub mod pallet {
 	/// All queued outbound messages.
 	#[pallet::storage]
 	pub type OutboundMessages<T: Config<I>, I: 'static = ()> =
-		StorageMap<_, Blake2_128Concat, MessageKey, StoredMessageData<T, I>>;
+		StorageMap<_, Blake2_128Concat, MessageKey, StoredMessagePayload<T, I>>;
 
 	#[pallet::genesis_config]
 	pub struct GenesisConfig<T: Config<I>, I: 'static = ()> {
@@ -744,10 +622,7 @@ pub mod pallet {
 
 	impl<T: Config<I>, I: 'static> Pallet<T, I> {
 		/// Get stored data of the outbound message with given nonce.
-		pub fn outbound_message_data(
-			lane: LaneId,
-			nonce: MessageNonce,
-		) -> Option<MessageData<T::OutboundMessageFee>> {
+		pub fn outbound_message_data(lane: LaneId, nonce: MessageNonce) -> Option<MessagePayload> {
 			OutboundMessages::<T, I>::get(MessageKey { lane_id: lane, nonce }).map(Into::into)
 		}
 
@@ -755,12 +630,11 @@ pub mod pallet {
 		pub fn inbound_message_data(
 			lane: LaneId,
 			payload: MessagePayload,
-			outbound_details: OutboundMessageDetails<T::InboundMessageFee>,
+			outbound_details: OutboundMessageDetails,
 		) -> InboundMessageDetails {
 			let mut dispatch_message = DispatchMessage {
 				key: MessageKey { lane_id: lane, nonce: outbound_details.nonce },
-				data: MessageData { payload, fee: outbound_details.delivery_and_dispatch_fee }
-					.into(),
+				data: payload.into(),
 			};
 			InboundMessageDetails {
 				dispatch_weight: T::MessageDispatch::dispatch_weight(&mut dispatch_message),
@@ -769,12 +643,8 @@ pub mod pallet {
 	}
 }
 
-impl<T, I>
-	bp_messages::source_chain::MessagesBridge<
-		T::RuntimeOrigin,
-		T::OutboundMessageFee,
-		T::OutboundPayload,
-	> for Pallet<T, I>
+impl<T, I> bp_messages::source_chain::MessagesBridge<T::RuntimeOrigin, T::OutboundPayload>
+	for Pallet<T, I>
 where
 	T: Config<I>,
 	I: 'static,
@@ -785,9 +655,8 @@ where
 		sender: T::RuntimeOrigin,
 		lane: LaneId,
 		message: T::OutboundPayload,
-		delivery_and_dispatch_fee: T::OutboundMessageFee,
 	) -> Result<SendMessageArtifacts, Self::Error> {
-		crate::send_message::<T, I>(sender, lane, message, delivery_and_dispatch_fee)
+		crate::send_message::<T, I>(sender, lane, message)
 	}
 }
 
@@ -796,21 +665,14 @@ fn send_message<T: Config<I>, I: 'static>(
 	submitter: T::RuntimeOrigin,
 	lane_id: LaneId,
 	payload: T::OutboundPayload,
-	delivery_and_dispatch_fee: T::OutboundMessageFee,
 ) -> sp_std::result::Result<
 	SendMessageArtifacts,
 	sp_runtime::DispatchErrorWithPostInfo<PostDispatchInfo>,
 > {
 	ensure_normal_operating_mode::<T, I>()?;
 
-	// the most lightweigh check is the message size check
-	ensure!(
-		payload.size() <= T::MaximalOutboundPayloadSize::get(),
-		Error::<T, I>::MessageIsTooLarge,
-	);
-
 	// initially, actual (post-dispatch) weight is equal to pre-dispatch weight
-	let mut actual_weight = T::WeightInfo::send_message_weight(&payload, T::DbWeight::get());
+	let mut actual_weight = frame_support::weights::Weight::zero(); // TODO (https://github.com/paritytech/parity-bridges-common/issues/1647): remove this
 
 	// let's first check if message can be delivered to target chain
 	T::TargetHeaderChain::verify_message(&payload).map_err(|err| {
@@ -826,46 +688,28 @@ fn send_message<T: Config<I>, I: 'static>(
 
 	// now let's enforce any additional lane rules
 	let mut lane = outbound_lane::<T, I>(lane_id);
-	T::LaneMessageVerifier::verify_message(
-		&submitter,
-		&delivery_and_dispatch_fee,
-		&lane_id,
-		&lane.data(),
-		&payload,
-	)
-	.map_err(|err| {
-		log::trace!(
-			target: LOG_TARGET,
-			"Message to lane {:?} is rejected by lane verifier: {:?}",
-			lane_id,
-			err,
-		);
-
-		Error::<T, I>::MessageRejectedByLaneVerifier
-	})?;
-
-	// let's withdraw delivery and dispatch fee from submitter
-	T::MessageDeliveryAndDispatchPayment::pay_delivery_and_dispatch_fee(
-		&submitter,
-		&delivery_and_dispatch_fee,
-	)
-	.map_err(|err| {
-		log::trace!(
-			target: LOG_TARGET,
-			"Message to lane {:?} is rejected because submitter is unable to pay fee {:?}: {:?}",
-			lane_id,
-			delivery_and_dispatch_fee,
-			err,
-		);
+	T::LaneMessageVerifier::verify_message(&submitter, &lane_id, &lane.data(), &payload).map_err(
+		|err| {
+			log::trace!(
+				target: LOG_TARGET,
+				"Message to lane {:?} is rejected by lane verifier: {:?}",
+				lane_id,
+				err,
+			);
 
-		Error::<T, I>::FailedToWithdrawMessageFee
-	})?;
+			Error::<T, I>::MessageRejectedByLaneVerifier
+		},
+	)?;
 
 	// finally, save message in outbound storage and emit event
 	let encoded_payload = payload.encode();
 	let encoded_payload_len = encoded_payload.len();
-	let nonce =
-		lane.send_message(MessageData { payload: encoded_payload, fee: delivery_and_dispatch_fee });
+	ensure!(
+		encoded_payload_len <= T::MaximalOutboundPayloadSize::get() as usize,
+		Error::<T, I>::MessageIsTooLarge
+	);
+	let nonce = lane.send_message(encoded_payload);
+
 	// Guaranteed to be called outside only when the message is accepted.
 	// We assume that the maximum weight call back used is `single_message_callback_overhead`, so do
 	// not perform complex db operation in callback. If you want to, put these magic logic in
@@ -920,32 +764,26 @@ fn send_message<T: Config<I>, I: 'static>(
 	Ok(SendMessageArtifacts { nonce, weight: actual_weight })
 }
 
-/// Calculate the relayers rewards
+/// Calculate the number of messages that the relayers have delivered.
 pub fn calc_relayers_rewards<T, I>(
-	lane_id: LaneId,
 	messages_relayers: VecDeque<UnrewardedRelayer<T::AccountId>>,
 	received_range: &RangeInclusive<MessageNonce>,
-) -> RelayersRewards<T::AccountId, T::OutboundMessageFee>
+) -> RelayersRewards<T::AccountId>
 where
 	T: frame_system::Config + crate::Config<I>,
 	I: 'static,
 {
 	// remember to reward relayers that have delivered messages
 	// this loop is bounded by `T::MaxUnrewardedRelayerEntriesAtInboundLane` on the bridged chain
-	let mut relayers_rewards: RelayersRewards<_, T::OutboundMessageFee> = RelayersRewards::new();
+	let mut relayers_rewards = RelayersRewards::new();
 	for entry in messages_relayers {
 		let nonce_begin = sp_std::cmp::max(entry.messages.begin, *received_range.start());
 		let nonce_end = sp_std::cmp::min(entry.messages.end, *received_range.end());
 
 		// loop won't proceed if current entry is ahead of received range (begin > end).
 		// this loop is bound by `T::MaxUnconfirmedMessagesAtInboundLane` on the bridged chain
-		let mut relayer_reward = relayers_rewards.entry(entry.relayer).or_default();
-		for nonce in nonce_begin..=nonce_end {
-			let key = MessageKey { lane_id, nonce };
-			let message_data = OutboundMessages::<T, I>::get(key)
-				.expect("message was just confirmed; we never prune unconfirmed messages; qed");
-			relayer_reward.reward = relayer_reward.reward.saturating_add(&message_data.fee);
-			relayer_reward.messages += 1;
+		if nonce_end >= nonce_begin {
+			*relayers_rewards.entry(entry.relayer).or_default() += nonce_end - nonce_begin + 1;
 		}
 	}
 	relayers_rewards
@@ -995,7 +833,6 @@ struct RuntimeInboundLaneStorage<T: Config<I>, I: 'static = ()> {
 }
 
 impl<T: Config<I>, I: 'static> InboundLaneStorage for RuntimeInboundLaneStorage<T, I> {
-	type MessageFee = T::InboundMessageFee;
 	type Relayer = T::InboundRelayer;
 
 	fn id(&self) -> LaneId {
@@ -1041,8 +878,6 @@ struct RuntimeOutboundLaneStorage<T, I = ()> {
 }
 
 impl<T: Config<I>, I: 'static> OutboundLaneStorage for RuntimeOutboundLaneStorage<T, I> {
-	type MessageFee = T::OutboundMessageFee;
-
 	fn id(&self) -> LaneId {
 		self.lane_id
 	}
@@ -1056,17 +891,20 @@ impl<T: Config<I>, I: 'static> OutboundLaneStorage for RuntimeOutboundLaneStorag
 	}
 
 	#[cfg(test)]
-	fn message(&self, nonce: &MessageNonce) -> Option<MessageData<T::OutboundMessageFee>> {
+	fn message(&self, nonce: &MessageNonce) -> Option<MessagePayload> {
 		OutboundMessages::<T, I>::get(MessageKey { lane_id: self.lane_id, nonce: *nonce })
 			.map(Into::into)
 	}
 
-	fn save_message(
-		&mut self,
-		nonce: MessageNonce,
-		mesage_data: MessageData<T::OutboundMessageFee>,
-	) {
-		OutboundMessages::<T, I>::insert(MessageKey { lane_id: self.lane_id, nonce }, mesage_data);
+	fn save_message(&mut self, nonce: MessageNonce, message_payload: MessagePayload) {
+		OutboundMessages::<T, I>::insert(
+			MessageKey { lane_id: self.lane_id, nonce },
+			StoredMessagePayload::<T, I>::try_from(message_payload).expect(
+				"save_message is called after all checks in send_message; \
+					send_message checks message size; \
+					qed",
+			),
+		);
 	}
 
 	fn remove_message(&mut self, nonce: &MessageNonce) {
@@ -1075,10 +913,10 @@ impl<T: Config<I>, I: 'static> OutboundLaneStorage for RuntimeOutboundLaneStorag
 }
 
 /// Verify messages proof and return proved messages with decoded payload.
-fn verify_and_decode_messages_proof<Chain: SourceHeaderChain<Fee>, Fee, DispatchPayload: Decode>(
+fn verify_and_decode_messages_proof<Chain: SourceHeaderChain, DispatchPayload: Decode>(
 	proof: Chain::MessagesProof,
 	messages_count: u32,
-) -> Result<ProvedMessages<DispatchMessage<DispatchPayload, Fee>>, Chain::Error> {
+) -> Result<ProvedMessages<DispatchMessage<DispatchPayload>>, Chain::Error> {
 	// `receive_messages_proof` weight formula and `MaxUnconfirmedMessagesAtInboundLane` check
 	// guarantees that the `message_count` is sane and Vec<Message> may be allocated.
 	// (tx with too many messages will either be rejected from the pool, or will fail earlier)
@@ -1102,12 +940,12 @@ fn verify_and_decode_messages_proof<Chain: SourceHeaderChain<Fee>, Fee, Dispatch
 mod tests {
 	use super::*;
 	use crate::mock::{
-		message, message_payload, run_test, unrewarded_relayer, Balance, RuntimeEvent as TestEvent,
+		message, message_payload, run_test, unrewarded_relayer, RuntimeEvent as TestEvent,
 		RuntimeOrigin, TestMessageDeliveryAndDispatchPayment, TestMessagesDeliveryProof,
-		TestMessagesParameter, TestMessagesProof, TestOnDeliveryConfirmed1,
-		TestOnDeliveryConfirmed2, TestOnMessageAccepted, TestRuntime, TokenConversionRate,
-		MAX_OUTBOUND_PAYLOAD_SIZE, PAYLOAD_REJECTED_BY_TARGET_CHAIN, REGULAR_PAYLOAD, TEST_LANE_ID,
-		TEST_RELAYER_A, TEST_RELAYER_B,
+		TestMessagesProof, TestOnDeliveryConfirmed1, TestOnDeliveryConfirmed2,
+		TestOnMessageAccepted, TestRuntime, MAX_OUTBOUND_PAYLOAD_SIZE,
+		PAYLOAD_REJECTED_BY_TARGET_CHAIN, REGULAR_PAYLOAD, TEST_LANE_ID, TEST_RELAYER_A,
+		TEST_RELAYER_B,
 	};
 	use bp_messages::{UnrewardedRelayer, UnrewardedRelayersState};
 	use bp_test_utils::generate_owned_bridge_module_tests;
@@ -1146,15 +984,13 @@ mod tests {
 
 		let message_nonce =
 			outbound_lane::<TestRuntime, ()>(TEST_LANE_ID).data().latest_generated_nonce + 1;
-		let weight = Pallet::<TestRuntime>::send_message(
+		let weight = send_message::<TestRuntime, ()>(
 			RuntimeOrigin::signed(1),
 			TEST_LANE_ID,
 			REGULAR_PAYLOAD,
-			REGULAR_PAYLOAD.declared_weight.ref_time(),
 		)
 		.expect("send_message has failed")
-		.actual_weight
-		.expect("send_message always returns Some");
+		.weight;
 
 		// check event with assigned nonce
 		assert_eq!(
@@ -1169,12 +1005,6 @@ mod tests {
 			}],
 		);
 
-		// check that fee has been withdrawn from submitter
-		assert!(TestMessageDeliveryAndDispatchPayment::is_fee_paid(
-			1,
-			REGULAR_PAYLOAD.declared_weight.ref_time()
-		));
-
 		weight
 	}
 
@@ -1217,102 +1047,6 @@ mod tests {
 		);
 	}
 
-	#[test]
-	fn pallet_parameter_may_be_updated_by_root() {
-		run_test(|| {
-			get_ready_for_events();
-
-			let parameter = TestMessagesParameter::TokenConversionRate(10.into());
-			assert_ok!(Pallet::<TestRuntime>::update_pallet_parameter(
-				RuntimeOrigin::root(),
-				parameter.clone(),
-			));
-
-			assert_eq!(TokenConversionRate::get(), 10.into());
-			assert_eq!(
-				System::<TestRuntime>::events(),
-				vec![EventRecord {
-					phase: Phase::Initialization,
-					event: TestEvent::Messages(Event::ParameterUpdated { parameter }),
-					topics: vec![],
-				}],
-			);
-		});
-	}
-
-	#[test]
-	fn pallet_parameter_may_be_updated_by_owner() {
-		run_test(|| {
-			PalletOwner::<TestRuntime>::put(2);
-			get_ready_for_events();
-
-			let parameter = TestMessagesParameter::TokenConversionRate(10.into());
-			assert_ok!(Pallet::<TestRuntime>::update_pallet_parameter(
-				RuntimeOrigin::signed(2),
-				parameter.clone(),
-			));
-
-			assert_eq!(TokenConversionRate::get(), 10.into());
-			assert_eq!(
-				System::<TestRuntime>::events(),
-				vec![EventRecord {
-					phase: Phase::Initialization,
-					event: TestEvent::Messages(Event::ParameterUpdated { parameter }),
-					topics: vec![],
-				}],
-			);
-		});
-	}
-
-	#[test]
-	fn pallet_parameter_cant_be_updated_by_arbitrary_submitter() {
-		run_test(|| {
-			assert_noop!(
-				Pallet::<TestRuntime>::update_pallet_parameter(
-					RuntimeOrigin::signed(2),
-					TestMessagesParameter::TokenConversionRate(10.into()),
-				),
-				DispatchError::BadOrigin,
-			);
-
-			PalletOwner::<TestRuntime>::put(2);
-
-			assert_noop!(
-				Pallet::<TestRuntime>::update_pallet_parameter(
-					RuntimeOrigin::signed(1),
-					TestMessagesParameter::TokenConversionRate(10.into()),
-				),
-				DispatchError::BadOrigin,
-			);
-		});
-	}
-
-	#[test]
-	fn fixed_u128_works_as_i_think() {
-		// this test is here just to be sure that conversion rate may be represented with FixedU128
-		run_test(|| {
-			use sp_runtime::{FixedPointNumber, FixedU128};
-
-			// 1:1 conversion that we use by default for testnets
-			let rialto_token = 1u64;
-			let rialto_token_in_millau_tokens =
-				TokenConversionRate::get().saturating_mul_int(rialto_token);
-			assert_eq!(rialto_token_in_millau_tokens, 1);
-
-			// let's say conversion rate is 1:1.7
-			let conversion_rate = FixedU128::saturating_from_rational(170, 100);
-			let rialto_tokens = 100u64;
-			let rialto_tokens_in_millau_tokens = conversion_rate.saturating_mul_int(rialto_tokens);
-			assert_eq!(rialto_tokens_in_millau_tokens, 170);
-
-			// let's say conversion rate is 1:0.25
-			let conversion_rate = FixedU128::saturating_from_rational(25, 100);
-			let rialto_tokens = 100u64;
-			let rialto_tokens_in_millau_tokens = conversion_rate.saturating_mul_int(rialto_tokens);
-			assert_eq!(rialto_tokens_in_millau_tokens, 25);
-		});
-	}
-
 	#[test]
 	fn pallet_rejects_transactions_if_halted() {
 		run_test(|| {
@@ -1324,25 +1058,14 @@ mod tests {
 			));
 
 			assert_noop!(
-				Pallet::<TestRuntime>::send_message(
+				send_message::<TestRuntime, ()>(
 					RuntimeOrigin::signed(1),
 					TEST_LANE_ID,
 					REGULAR_PAYLOAD,
-					REGULAR_PAYLOAD.declared_weight.ref_time(),
 				),
 				Error::<TestRuntime, ()>::NotOperatingNormally,
 			);
 
-			assert_noop!(
-				Pallet::<TestRuntime>::increase_message_fee(
-					RuntimeOrigin::signed(1),
-					TEST_LANE_ID,
-					1,
-					1,
-				),
-				Error::<TestRuntime, ()>::BridgeModule(bp_runtime::OwnedBridgeModuleError::Halted),
-			);
-
 			assert_noop!(
 				Pallet::<TestRuntime>::receive_messages_proof(
 					RuntimeOrigin::signed(1),
@@ -1389,22 +1112,14 @@ mod tests {
 			);
 
 			assert_noop!(
-				Pallet::<TestRuntime>::send_message(
+				send_message::<TestRuntime, ()>(
 					RuntimeOrigin::signed(1),
 					TEST_LANE_ID,
 					REGULAR_PAYLOAD,
-					REGULAR_PAYLOAD.declared_weight.ref_time(),
 				),
 				Error::<TestRuntime, ()>::NotOperatingNormally,
 			);
 
-			assert_ok!(Pallet::<TestRuntime>::increase_message_fee(
-				RuntimeOrigin::signed(1),
-				TEST_LANE_ID,
-				1,
-				1,
-			));
-
 			assert_ok!(Pallet::<TestRuntime>::receive_messages_proof(
 				RuntimeOrigin::signed(1),
 				TEST_RELAYER_A,
@@ -1451,25 +1166,23 @@ mod tests {
 				.extra
 				.extend_from_slice(&[0u8; MAX_OUTBOUND_PAYLOAD_SIZE as usize]);
 			assert_noop!(
-				Pallet::<TestRuntime>::send_message(
+				send_message::<TestRuntime, ()>(
 					RuntimeOrigin::signed(1),
 					TEST_LANE_ID,
 					message_payload.clone(),
-					Balance::MAX,
 				),
 				Error::<TestRuntime, ()>::MessageIsTooLarge,
 			);
 
 			// let's check that we're able to send `MAX_OUTBOUND_PAYLOAD_SIZE` messages
-			while message_payload.size() > MAX_OUTBOUND_PAYLOAD_SIZE {
+			while message_payload.encoded_size() as u32 > MAX_OUTBOUND_PAYLOAD_SIZE {
 				message_payload.extra.pop();
 			}
-			assert_eq!(message_payload.size(), MAX_OUTBOUND_PAYLOAD_SIZE);
-			assert_ok!(Pallet::<TestRuntime>::send_message(
+			assert_eq!(message_payload.encoded_size() as u32, MAX_OUTBOUND_PAYLOAD_SIZE);
+			assert_ok!(send_message::<TestRuntime, ()>(
 				RuntimeOrigin::signed(1),
 				TEST_LANE_ID,
 				message_payload,
-				Balance::MAX,
 			),);
 		})
 	}
@@ -1479,11 +1192,10 @@ mod tests {
 		run_test(|| {
 			// messages with this payload are rejected by target chain verifier
 			assert_noop!(
-				Pallet::<TestRuntime>::send_message(
+				send_message::<TestRuntime, ()>(
 					RuntimeOrigin::signed(1),
 					TEST_LANE_ID,
 					PAYLOAD_REJECTED_BY_TARGET_CHAIN,
-					PAYLOAD_REJECTED_BY_TARGET_CHAIN.declared_weight.ref_time(),
 				),
 				Error::<TestRuntime, ()>::MessageRejectedByChainVerifier,
 			);
@@ -1494,34 +1206,15 @@ mod tests {
 	fn lane_verifier_rejects_invalid_message_in_send_message() {
 		run_test(|| {
 			// messages with zero fee are rejected by lane verifier
+			let mut message = REGULAR_PAYLOAD;
+			message.reject_by_lane_verifier = true;
 			assert_noop!(
-				Pallet::<TestRuntime>::send_message(
-					RuntimeOrigin::signed(1),
-					TEST_LANE_ID,
-					REGULAR_PAYLOAD,
-					0
-				),
+				send_message::<TestRuntime, ()>(RuntimeOrigin::signed(1), TEST_LANE_ID, message,),
 				Error::<TestRuntime, ()>::MessageRejectedByLaneVerifier,
 			);
 		});
 	}
 
-	#[test]
-	fn message_send_fails_if_submitter_cant_pay_message_fee() {
-		run_test(|| {
-			TestMessageDeliveryAndDispatchPayment::reject_payments();
-			assert_noop!(
-				Pallet::<TestRuntime>::send_message(
-					RuntimeOrigin::signed(1),
-					TEST_LANE_ID,
-					REGULAR_PAYLOAD,
-					REGULAR_PAYLOAD.declared_weight.ref_time(),
-				),
-				Error::<TestRuntime, ()>::FailedToWithdrawMessageFee,
-			);
-		});
-	}
-
 	#[test]
 	fn receive_messages_proof_works() {
 		run_test(|| {
@@ -1665,17 +1358,15 @@ mod tests {
 	#[test]
 	fn receive_messages_delivery_proof_rewards_relayers() {
 		run_test(|| {
-			assert_ok!(Pallet::<TestRuntime>::send_message(
+			assert_ok!(send_message::<TestRuntime, ()>(
 				RuntimeOrigin::signed(1),
 				TEST_LANE_ID,
 				REGULAR_PAYLOAD,
-				1000,
 			));
-			assert_ok!(Pallet::<TestRuntime>::send_message(
+			assert_ok!(send_message::<TestRuntime, ()>(
 				RuntimeOrigin::signed(1),
 				TEST_LANE_ID,
 				REGULAR_PAYLOAD,
-				2000,
 			));
 
 			// this reports delivery of message 1 => reward is paid to TEST_RELAYER_A
@@ -1697,8 +1388,8 @@ mod tests {
 					..Default::default()
 				},
 			));
-			assert!(TestMessageDeliveryAndDispatchPayment::is_reward_paid(TEST_RELAYER_A, 1000));
-			assert!(!TestMessageDeliveryAndDispatchPayment::is_reward_paid(TEST_RELAYER_B, 2000));
+			assert!(TestMessageDeliveryAndDispatchPayment::is_reward_paid(TEST_RELAYER_A, 1));
+			assert!(!TestMessageDeliveryAndDispatchPayment::is_reward_paid(TEST_RELAYER_B, 1));
 
 			// this reports delivery of both message 1 and message 2 => reward is paid only to
 			// TEST_RELAYER_B
@@ -1723,8 +1414,8 @@ mod tests {
 					..Default::default()
 				},
 			));
-			assert!(!TestMessageDeliveryAndDispatchPayment::is_reward_paid(TEST_RELAYER_A, 1000));
-			assert!(TestMessageDeliveryAndDispatchPayment::is_reward_paid(TEST_RELAYER_B, 2000));
+			assert!(!TestMessageDeliveryAndDispatchPayment::is_reward_paid(TEST_RELAYER_A, 1));
+			assert!(TestMessageDeliveryAndDispatchPayment::is_reward_paid(TEST_RELAYER_B, 1));
 		});
 	}
 
@@ -1829,7 +1520,7 @@ mod tests {
 	fn receive_messages_accepts_single_message_with_invalid_payload() {
 		run_test(|| {
 			let mut invalid_message = message(1, REGULAR_PAYLOAD);
-			invalid_message.data.payload = Vec::new();
+			invalid_message.payload = Vec::new();
 
 			assert_ok!(Pallet::<TestRuntime, ()>::receive_messages_proof(
 				RuntimeOrigin::signed(1),
@@ -1848,7 +1539,7 @@ mod tests {
 	fn receive_messages_accepts_batch_with_message_with_invalid_payload() {
 		run_test(|| {
 			let mut invalid_message = message(2, REGULAR_PAYLOAD);
-			invalid_message.data.payload = Vec::new();
+			invalid_message.payload = Vec::new();
 
 			assert_ok!(Pallet::<TestRuntime, ()>::receive_messages_proof(
 				RuntimeOrigin::signed(1),
@@ -1884,73 +1575,6 @@ mod tests {
 		});
 	}
 
-	#[test]
-	fn increase_message_fee_fails_if_message_is_already_delivered() {
-		run_test(|| {
-			send_regular_message();
-			receive_messages_delivery_proof();
-
-			assert_noop!(
-				Pallet::<TestRuntime, ()>::increase_message_fee(
-					RuntimeOrigin::signed(1),
-					TEST_LANE_ID,
-					1,
-					100,
-				),
-				Error::<TestRuntime, ()>::MessageIsAlreadyDelivered,
-			);
-		});
-	}
-
-	#[test]
-	fn increase_message_fee_fails_if_message_is_not_yet_sent() {
-		run_test(|| {
-			assert_noop!(
-				Pallet::<TestRuntime, ()>::increase_message_fee(
-					RuntimeOrigin::signed(1),
-					TEST_LANE_ID,
-					1,
-					100,
-				),
-				Error::<TestRuntime, ()>::MessageIsNotYetSent,
-			);
-		});
-	}
-
-	#[test]
-	fn increase_message_fee_fails_if_submitter_cant_pay_additional_fee() {
-		run_test(|| {
-			send_regular_message();
-
-			TestMessageDeliveryAndDispatchPayment::reject_payments();
-
-			assert_noop!(
-				Pallet::<TestRuntime, ()>::increase_message_fee(
-					RuntimeOrigin::signed(1),
-					TEST_LANE_ID,
-					1,
-					100,
-				),
-				Error::<TestRuntime, ()>::FailedToWithdrawMessageFee,
-			);
-		});
-	}
-
-	#[test]
-	fn increase_message_fee_succeeds() {
-		run_test(|| {
-			send_regular_message();
-
-			assert_ok!(Pallet::<TestRuntime, ()>::increase_message_fee(
-				RuntimeOrigin::signed(1),
-				TEST_LANE_ID,
-				1,
-				100,
-			),);
-			assert!(TestMessageDeliveryAndDispatchPayment::is_fee_paid(1, 100));
-		});
-	}
-
 	#[test]
 	fn weight_refund_from_receive_messages_proof_works() {
 		run_test(|| {
@@ -2187,101 +1811,6 @@ mod tests {
 		});
 	}
 
-	#[test]
-	fn increase_message_fee_weight_depends_on_message_size() {
-		run_test(|| {
-			let mut small_payload = message_payload(0, 100);
-			let mut large_payload = message_payload(1, 100);
-			small_payload.extra = vec![1; MAX_OUTBOUND_PAYLOAD_SIZE as usize / 10];
-			large_payload.extra = vec![2; MAX_OUTBOUND_PAYLOAD_SIZE as usize / 5];
-
-			assert_ok!(Pallet::<TestRuntime>::send_message(
-				RuntimeOrigin::signed(1),
-				TEST_LANE_ID,
-				small_payload,
-				100,
-			));
-			assert_ok!(Pallet::<TestRuntime>::send_message(
-				RuntimeOrigin::signed(1),
-				TEST_LANE_ID,
-				large_payload,
-				100,
-			));
-
-			let small_weight = Pallet::<TestRuntime>::increase_message_fee(
-				RuntimeOrigin::signed(1),
-				TEST_LANE_ID,
-				1,
-				1,
-			)
-			.expect("increase_message_fee has failed")
-			.actual_weight
-			.expect("increase_message_fee always returns Some");
-
-			let large_weight = Pallet::<TestRuntime>::increase_message_fee(
-				RuntimeOrigin::signed(1),
-				TEST_LANE_ID,
-				2,
-				1,
-			)
-			.expect("increase_message_fee has failed")
-			.actual_weight
-			.expect("increase_message_fee always returns Some");
-
-			assert!(
-				large_weight.ref_time() > small_weight.ref_time(),
-				"Actual post-dispatch weigth for larger message {} must be larger than {} for small message",
-				large_weight,
-				small_weight,
-			);
-		});
-	}
-
-	#[test]
-	fn weight_is_refunded_for_messages_that_are_not_pruned() {
-		run_test(|| {
-			// send first MAX messages - no messages are pruned
-			let max_messages_to_prune = crate::mock::MaxMessagesToPruneAtOnce::get();
-			let when_zero_messages_are_pruned = send_regular_message();
-			let mut delivered_messages = DeliveredMessages::new(1, true);
-			for _ in 1..max_messages_to_prune {
-				assert_eq!(send_regular_message(), when_zero_messages_are_pruned);
-				delivered_messages.note_dispatched_message(true);
-			}
-
-			// confirm delivery of all sent messages
-			assert_ok!(Pallet::<TestRuntime>::receive_messages_delivery_proof(
-				RuntimeOrigin::signed(1),
-				TestMessagesDeliveryProof(Ok((
-					TEST_LANE_ID,
-					InboundLaneData {
-						last_confirmed_nonce: 1,
-						relayers: vec![UnrewardedRelayer {
-							relayer: 0,
-							messages: delivered_messages,
-						}]
-						.into_iter()
-						.collect(),
-					},
-				))),
-				UnrewardedRelayersState {
-					unrewarded_relayer_entries: 1,
-					total_messages: max_messages_to_prune,
-					last_delivered_nonce: max_messages_to_prune,
-					..Default::default()
-				},
-			));
-
-			// when next message is sent, MAX messages are pruned
-			let weight_when_max_messages_are_pruned = send_regular_message();
-			assert_eq!(
-				weight_when_max_messages_are_pruned,
-				when_zero_messages_are_pruned +
-					crate::mock::DbWeight::get().writes(max_messages_to_prune),
-			);
-		});
-	}
-
 	#[test]
 	fn message_accepted_callbacks_are_called() {
 		run_test(|| {
@@ -2302,27 +1831,6 @@ mod tests {
 		});
 	}
 
-	#[test]
-	fn message_accepted_refunds_non_zero_weight() {
-		run_test(|| {
-			TestOnMessageAccepted::set_consumed_weight_per_message(
-				crate::mock::DbWeight::get().writes(1),
-			);
-			let actual_callback_weight = send_regular_message();
-			let pre_dispatch_weight = <TestRuntime as Config>::WeightInfo::send_message_weight(
-				&REGULAR_PAYLOAD,
-				crate::mock::DbWeight::get(),
-			);
-			let prune_weight = crate::mock::DbWeight::get()
-				.writes(<TestRuntime as Config>::MaxMessagesToPruneAtOnce::get());
-
-			assert_eq!(
-				pre_dispatch_weight.saturating_sub(actual_callback_weight),
-				crate::mock::DbWeight::get().reads(1).saturating_add(prune_weight)
-			);
-		});
-	}
-
 	#[test]
 	fn storage_keys_computed_properly() {
 		assert_eq!(
@@ -2360,9 +1868,6 @@ mod tests {
 						nonce: 0,
 						dispatch_weight: Weight::from_ref_time(0),
 						size: 0,
-						delivery_and_dispatch_fee: 0,
-						dispatch_fee_payment:
-							bp_runtime::messages::DispatchFeePayment::AtTargetChain,
 					},
 				),
 				InboundMessageDetails { dispatch_weight: REGULAR_PAYLOAD.declared_weight },
diff --git a/bridges/modules/messages/src/mock.rs b/bridges/modules/messages/src/mock.rs
index fd4c45a0eaa9ca6c2399b3c4e3f13cc414cd1d3d..afda37ba8be7b1cc7d6418dfc7fed2c8da06926c 100644
--- a/bridges/modules/messages/src/mock.rs
+++ b/bridges/modules/messages/src/mock.rs
@@ -26,10 +26,11 @@ use bp_messages::{
 		OnMessageAccepted, TargetHeaderChain,
 	},
 	target_chain::{
-		DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages, SourceHeaderChain,
+		DispatchMessage, DispatchMessageData, MessageDispatch, ProvedLaneMessages, ProvedMessages,
+		SourceHeaderChain,
 	},
-	DeliveredMessages, InboundLaneData, LaneId, Message, MessageData, MessageKey, MessageNonce,
-	OutboundLaneData, Parameter as MessagesParameter, UnrewardedRelayer,
+	DeliveredMessages, InboundLaneData, LaneId, Message, MessageKey, MessageNonce, MessagePayload,
+	OutboundLaneData, UnrewardedRelayer,
 };
 use bp_runtime::{messages::MessageDispatchResult, Size};
 use codec::{Decode, Encode};
@@ -42,7 +43,7 @@ use sp_core::H256;
 use sp_runtime::{
 	testing::Header as SubstrateHeader,
 	traits::{BlakeTwo256, IdentityLookup},
-	FixedU128, Perbill,
+	Perbill,
 };
 use std::{
 	collections::{BTreeMap, VecDeque},
@@ -55,6 +56,8 @@ pub type Balance = u64;
 pub struct TestPayload {
 	/// Field that may be used to identify messages.
 	pub id: u64,
+	/// Reject this message by lane verifier?
+	pub reject_by_lane_verifier: bool,
 	/// Dispatch weight that is declared by the message sender.
 	pub declared_weight: Weight,
 	/// Message dispatch result.
@@ -140,38 +143,20 @@ parameter_types! {
 	pub const MaxMessagesToPruneAtOnce: u64 = 10;
 	pub const MaxUnrewardedRelayerEntriesAtInboundLane: u64 = 16;
 	pub const MaxUnconfirmedMessagesAtInboundLane: u64 = 32;
-	pub storage TokenConversionRate: FixedU128 = 1.into();
 	pub const TestBridgedChainId: bp_runtime::ChainId = *b"test";
 }
 
-#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, TypeInfo)]
-pub enum TestMessagesParameter {
-	TokenConversionRate(FixedU128),
-}
-
-impl MessagesParameter for TestMessagesParameter {
-	fn save(&self) {
-		match *self {
-			TestMessagesParameter::TokenConversionRate(conversion_rate) =>
-				TokenConversionRate::set(&conversion_rate),
-		}
-	}
-}
-
 impl Config for TestRuntime {
 	type RuntimeEvent = RuntimeEvent;
 	type WeightInfo = ();
-	type Parameter = TestMessagesParameter;
 	type MaxMessagesToPruneAtOnce = MaxMessagesToPruneAtOnce;
 	type MaxUnrewardedRelayerEntriesAtInboundLane = MaxUnrewardedRelayerEntriesAtInboundLane;
 	type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane;
 
 	type MaximalOutboundPayloadSize = frame_support::traits::ConstU32<MAX_OUTBOUND_PAYLOAD_SIZE>;
 	type OutboundPayload = TestPayload;
-	type OutboundMessageFee = TestMessageFee;
 
 	type InboundPayload = TestPayload;
-	type InboundMessageFee = TestMessageFee;
 	type InboundRelayer = TestRelayer;
 
 	type TargetHeaderChain = TestTargetHeaderChain;
@@ -219,7 +204,7 @@ pub const REGULAR_PAYLOAD: TestPayload = message_payload(0, 50);
 pub const PAYLOAD_REJECTED_BY_TARGET_CHAIN: TestPayload = message_payload(1, 50);
 
 /// Vec of proved messages, grouped by lane.
-pub type MessagesByLaneVec = Vec<(LaneId, ProvedLaneMessages<Message<TestMessageFee>>)>;
+pub type MessagesByLaneVec = Vec<(LaneId, ProvedLaneMessages<Message>)>;
 
 /// Test messages proof.
 #[derive(Debug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo)]
@@ -233,14 +218,12 @@ impl Size for TestMessagesProof {
 	}
 }
 
-impl From<Result<Vec<Message<TestMessageFee>>, ()>> for TestMessagesProof {
-	fn from(result: Result<Vec<Message<TestMessageFee>>, ()>) -> Self {
+impl From<Result<Vec<Message>, ()>> for TestMessagesProof {
+	fn from(result: Result<Vec<Message>, ()>) -> Self {
 		Self {
 			result: result.map(|messages| {
-				let mut messages_by_lane: BTreeMap<
-					LaneId,
-					ProvedLaneMessages<Message<TestMessageFee>>,
-				> = BTreeMap::new();
+				let mut messages_by_lane: BTreeMap<LaneId, ProvedLaneMessages<Message>> =
+					BTreeMap::new();
 				for message in messages {
 					messages_by_lane.entry(message.key.lane_id).or_default().messages.push(message);
 				}
@@ -288,17 +271,16 @@ impl TargetHeaderChain<TestPayload, TestRelayer> for TestTargetHeaderChain {
 #[derive(Debug, Default)]
 pub struct TestLaneMessageVerifier;
 
-impl LaneMessageVerifier<RuntimeOrigin, TestPayload, TestMessageFee> for TestLaneMessageVerifier {
+impl LaneMessageVerifier<RuntimeOrigin, TestPayload> for TestLaneMessageVerifier {
 	type Error = &'static str;
 
 	fn verify_message(
 		_submitter: &RuntimeOrigin,
-		delivery_and_dispatch_fee: &TestMessageFee,
 		_lane: &LaneId,
 		_lane_outbound_data: &OutboundLaneData,
-		_payload: &TestPayload,
+		payload: &TestPayload,
 	) -> Result<(), Self::Error> {
-		if *delivery_and_dispatch_fee != 0 {
+		if !payload.reject_by_lane_verifier {
 			Ok(())
 		} else {
 			Err(TEST_ERROR)
@@ -311,18 +293,6 @@ impl LaneMessageVerifier<RuntimeOrigin, TestPayload, TestMessageFee> for TestLan
 pub struct TestMessageDeliveryAndDispatchPayment;
 
 impl TestMessageDeliveryAndDispatchPayment {
-	/// Reject all payments.
-	pub fn reject_payments() {
-		frame_support::storage::unhashed::put(b":reject-message-fee:", &true);
-	}
-
-	/// Returns true if given fee has been paid by given submitter.
-	pub fn is_fee_paid(submitter: AccountId, fee: TestMessageFee) -> bool {
-		let raw_origin: Result<frame_system::RawOrigin<_>, _> =
-			RuntimeOrigin::signed(submitter).into();
-		frame_support::storage::unhashed::get(b":message-fee:") == Some((raw_origin.unwrap(), fee))
-	}
-
 	/// Returns true if given relayer has been rewarded with given balance. The reward-paid flag is
 	/// cleared after the call.
 	pub fn is_reward_paid(relayer: AccountId, fee: TestMessageFee) -> bool {
@@ -331,34 +301,21 @@ impl TestMessageDeliveryAndDispatchPayment {
 	}
 }
 
-impl MessageDeliveryAndDispatchPayment<RuntimeOrigin, AccountId, TestMessageFee>
+impl MessageDeliveryAndDispatchPayment<RuntimeOrigin, AccountId>
 	for TestMessageDeliveryAndDispatchPayment
 {
 	type Error = &'static str;
 
-	fn pay_delivery_and_dispatch_fee(
-		submitter: &RuntimeOrigin,
-		fee: &TestMessageFee,
-	) -> Result<(), Self::Error> {
-		if frame_support::storage::unhashed::get(b":reject-message-fee:") == Some(true) {
-			return Err(TEST_ERROR)
-		}
-
-		let raw_origin: Result<frame_system::RawOrigin<_>, _> = submitter.clone().into();
-		frame_support::storage::unhashed::put(b":message-fee:", &(raw_origin.unwrap(), fee));
-		Ok(())
-	}
-
 	fn pay_relayers_rewards(
-		lane_id: LaneId,
+		_lane_id: LaneId,
 		message_relayers: VecDeque<UnrewardedRelayer<AccountId>>,
 		_confirmation_relayer: &AccountId,
 		received_range: &RangeInclusive<MessageNonce>,
 	) {
 		let relayers_rewards =
-			calc_relayers_rewards::<TestRuntime, ()>(lane_id, message_relayers, received_range);
+			calc_relayers_rewards::<TestRuntime, ()>(message_relayers, received_range);
 		for (relayer, reward) in &relayers_rewards {
-			let key = (b":relayer-reward:", relayer, reward.reward).encode();
+			let key = (b":relayer-reward:", relayer, reward).encode();
 			frame_support::storage::unhashed::put(&key, &true);
 		}
 	}
@@ -450,7 +407,7 @@ impl OnDeliveryConfirmed for TestOnDeliveryConfirmed2 {
 #[derive(Debug)]
 pub struct TestSourceHeaderChain;
 
-impl SourceHeaderChain<TestMessageFee> for TestSourceHeaderChain {
+impl SourceHeaderChain for TestSourceHeaderChain {
 	type Error = &'static str;
 
 	type MessagesProof = TestMessagesProof;
@@ -458,7 +415,7 @@ impl SourceHeaderChain<TestMessageFee> for TestSourceHeaderChain {
 	fn verify_messages_proof(
 		proof: Self::MessagesProof,
 		_messages_count: u32,
-	) -> Result<ProvedMessages<Message<TestMessageFee>>, Self::Error> {
+	) -> Result<ProvedMessages<Message>, Self::Error> {
 		proof.result.map(|proof| proof.into_iter().collect()).map_err(|_| TEST_ERROR)
 	}
 }
@@ -467,10 +424,10 @@ impl SourceHeaderChain<TestMessageFee> for TestSourceHeaderChain {
 #[derive(Debug)]
 pub struct TestMessageDispatch;
 
-impl MessageDispatch<AccountId, TestMessageFee> for TestMessageDispatch {
+impl MessageDispatch<AccountId> for TestMessageDispatch {
 	type DispatchPayload = TestPayload;
 
-	fn dispatch_weight(message: &mut DispatchMessage<TestPayload, TestMessageFee>) -> Weight {
+	fn dispatch_weight(message: &mut DispatchMessage<TestPayload>) -> Weight {
 		match message.data.payload.as_ref() {
 			Ok(payload) => payload.declared_weight,
 			Err(_) => Weight::from_ref_time(0),
@@ -479,7 +436,7 @@ impl MessageDispatch<AccountId, TestMessageFee> for TestMessageDispatch {
 
 	fn dispatch(
 		_relayer_account: &AccountId,
-		message: DispatchMessage<TestPayload, TestMessageFee>,
+		message: DispatchMessage<TestPayload>,
 	) -> MessageDispatchResult {
 		match message.data.payload.as_ref() {
 			Ok(payload) => payload.dispatch_result.clone(),
@@ -489,25 +446,31 @@ impl MessageDispatch<AccountId, TestMessageFee> for TestMessageDispatch {
 }
 
 /// Return test lane message with given nonce and payload.
-pub fn message(nonce: MessageNonce, payload: TestPayload) -> Message<TestMessageFee> {
-	Message { key: MessageKey { lane_id: TEST_LANE_ID, nonce }, data: message_data(payload) }
+pub fn message(nonce: MessageNonce, payload: TestPayload) -> Message {
+	Message { key: MessageKey { lane_id: TEST_LANE_ID, nonce }, payload: payload.encode() }
+}
+
+/// Return valid outbound message data, constructed from given payload.
+pub fn outbound_message_data(payload: TestPayload) -> MessagePayload {
+	payload.encode()
+}
+
+/// Return valid inbound (dispatch) message data, constructed from given payload.
+pub fn inbound_message_data(payload: TestPayload) -> DispatchMessageData<TestPayload> {
+	DispatchMessageData { payload: Ok(payload) }
 }
 
 /// Constructs message payload using given arguments and zero unspent weight.
 pub const fn message_payload(id: u64, declared_weight: u64) -> TestPayload {
 	TestPayload {
 		id,
+		reject_by_lane_verifier: false,
 		declared_weight: Weight::from_ref_time(declared_weight),
 		dispatch_result: dispatch_result(0),
 		extra: Vec::new(),
 	}
 }
 
-/// Return message data with valid fee for given payload.
-pub fn message_data(payload: TestPayload) -> MessageData<TestMessageFee> {
-	MessageData { payload: payload.encode(), fee: 1 }
-}
-
 /// Returns message dispatch result with given unspent weight.
 pub const fn dispatch_result(unspent_weight: u64) -> MessageDispatchResult {
 	MessageDispatchResult {
diff --git a/bridges/modules/messages/src/outbound_lane.rs b/bridges/modules/messages/src/outbound_lane.rs
index bdd503c811e737995c2440b2bb85173e098ca7fc..890b85072ab9d73c23577e6844f9ebf1991ec2aa 100644
--- a/bridges/modules/messages/src/outbound_lane.rs
+++ b/bridges/modules/messages/src/outbound_lane.rs
@@ -20,19 +20,14 @@ use crate::Config;
 
 use bitvec::prelude::*;
 use bp_messages::{
-	DeliveredMessages, DispatchResultsBitVec, LaneId, MessageData, MessageNonce, OutboundLaneData,
-	UnrewardedRelayer,
+	DeliveredMessages, DispatchResultsBitVec, LaneId, MessageNonce, MessagePayload,
+	OutboundLaneData, UnrewardedRelayer,
 };
-use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};
-use frame_support::{traits::Get, RuntimeDebug};
-use scale_info::{Type, TypeInfo};
+use frame_support::{BoundedVec, RuntimeDebug};
 use sp_std::collections::vec_deque::VecDeque;
 
 /// Outbound lane storage.
 pub trait OutboundLaneStorage {
-	/// Delivery and dispatch fee type on source chain.
-	type MessageFee;
-
 	/// Lane id.
 	fn id(&self) -> LaneId;
 	/// Get lane data from the storage.
@@ -41,64 +36,15 @@ pub trait OutboundLaneStorage {
 	fn set_data(&mut self, data: OutboundLaneData);
 	/// Returns saved outbound message payload.
 	#[cfg(test)]
-	fn message(&self, nonce: &MessageNonce) -> Option<MessageData<Self::MessageFee>>;
+	fn message(&self, nonce: &MessageNonce) -> Option<MessagePayload>;
 	/// Save outbound message in the storage.
-	fn save_message(&mut self, nonce: MessageNonce, message_data: MessageData<Self::MessageFee>);
+	fn save_message(&mut self, nonce: MessageNonce, message_payload: MessagePayload);
 	/// Remove outbound message from the storage.
 	fn remove_message(&mut self, nonce: &MessageNonce);
 }
 
 /// Outbound message data wrapper that implements `MaxEncodedLen`.
-///
-/// We have already had `MaxEncodedLen`-like functionality before, but its usage has
-/// been localized and we haven't been passing it everywhere. This wrapper allows us
-/// to avoid passing these generic bounds all over the code.
-///
-/// The encoding of this type matches encoding of the corresponding `MessageData`.
-#[derive(Encode, Decode, Clone, RuntimeDebug, PartialEq, Eq)]
-pub struct StoredMessageData<T: Config<I>, I: 'static>(pub MessageData<T::OutboundMessageFee>);
-
-impl<T: Config<I>, I: 'static> sp_std::ops::Deref for StoredMessageData<T, I> {
-	type Target = MessageData<T::OutboundMessageFee>;
-
-	fn deref(&self) -> &Self::Target {
-		&self.0
-	}
-}
-
-impl<T: Config<I>, I: 'static> sp_std::ops::DerefMut for StoredMessageData<T, I> {
-	fn deref_mut(&mut self) -> &mut Self::Target {
-		&mut self.0
-	}
-}
-
-impl<T: Config<I>, I: 'static> From<StoredMessageData<T, I>>
-	for MessageData<T::OutboundMessageFee>
-{
-	fn from(data: StoredMessageData<T, I>) -> Self {
-		data.0
-	}
-}
-
-impl<T: Config<I>, I: 'static> TypeInfo for StoredMessageData<T, I> {
-	type Identity = Self;
-
-	fn type_info() -> Type {
-		MessageData::<T::OutboundMessageFee>::type_info()
-	}
-}
-
-impl<T: Config<I>, I: 'static> EncodeLike<StoredMessageData<T, I>>
-	for MessageData<T::OutboundMessageFee>
-{
-}
-
-impl<T: Config<I>, I: 'static> MaxEncodedLen for StoredMessageData<T, I> {
-	fn max_encoded_len() -> usize {
-		T::OutboundMessageFee::max_encoded_len()
-			.saturating_add(T::MaximalOutboundPayloadSize::get() as usize)
-	}
-}
+pub type StoredMessagePayload<T, I> = BoundedVec<u8, <T as Config<I>>::MaximalOutboundPayloadSize>;
 
 /// Result of messages receival confirmation.
 #[derive(RuntimeDebug, PartialEq, Eq)]
@@ -143,12 +89,12 @@ impl<S: OutboundLaneStorage> OutboundLane<S> {
 	/// Send message over lane.
 	///
 	/// Returns new message nonce.
-	pub fn send_message(&mut self, message_data: MessageData<S::MessageFee>) -> MessageNonce {
+	pub fn send_message(&mut self, message_payload: MessagePayload) -> MessageNonce {
 		let mut data = self.storage.data();
 		let nonce = data.latest_generated_nonce + 1;
 		data.latest_generated_nonce = nonce;
 
-		self.storage.save_message(nonce, message_data);
+		self.storage.save_message(nonce, message_payload);
 		self.storage.set_data(data);
 
 		nonce
@@ -295,8 +241,8 @@ mod tests {
 	use super::*;
 	use crate::{
 		mock::{
-			message_data, run_test, unrewarded_relayer, TestRelayer, TestRuntime, REGULAR_PAYLOAD,
-			TEST_LANE_ID,
+			outbound_message_data, run_test, unrewarded_relayer, TestRelayer, TestRuntime,
+			REGULAR_PAYLOAD, TEST_LANE_ID,
 		},
 		outbound_lane,
 	};
@@ -324,9 +270,9 @@ mod tests {
 	) -> ReceivalConfirmationResult {
 		run_test(|| {
 			let mut lane = outbound_lane::<TestRuntime, _>(TEST_LANE_ID);
-			lane.send_message(message_data(REGULAR_PAYLOAD));
-			lane.send_message(message_data(REGULAR_PAYLOAD));
-			lane.send_message(message_data(REGULAR_PAYLOAD));
+			lane.send_message(outbound_message_data(REGULAR_PAYLOAD));
+			lane.send_message(outbound_message_data(REGULAR_PAYLOAD));
+			lane.send_message(outbound_message_data(REGULAR_PAYLOAD));
 			assert_eq!(lane.storage.data().latest_generated_nonce, 3);
 			assert_eq!(lane.storage.data().latest_received_nonce, 0);
 			let result = lane.confirm_delivery(3, latest_received_nonce, relayers);
@@ -341,7 +287,7 @@ mod tests {
 		run_test(|| {
 			let mut lane = outbound_lane::<TestRuntime, _>(TEST_LANE_ID);
 			assert_eq!(lane.storage.data().latest_generated_nonce, 0);
-			assert_eq!(lane.send_message(message_data(REGULAR_PAYLOAD)), 1);
+			assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 1);
 			assert!(lane.storage.message(&1).is_some());
 			assert_eq!(lane.storage.data().latest_generated_nonce, 1);
 		});
@@ -351,9 +297,9 @@ mod tests {
 	fn confirm_delivery_works() {
 		run_test(|| {
 			let mut lane = outbound_lane::<TestRuntime, _>(TEST_LANE_ID);
-			assert_eq!(lane.send_message(message_data(REGULAR_PAYLOAD)), 1);
-			assert_eq!(lane.send_message(message_data(REGULAR_PAYLOAD)), 2);
-			assert_eq!(lane.send_message(message_data(REGULAR_PAYLOAD)), 3);
+			assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 1);
+			assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 2);
+			assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 3);
 			assert_eq!(lane.storage.data().latest_generated_nonce, 3);
 			assert_eq!(lane.storage.data().latest_received_nonce, 0);
 			assert_eq!(
@@ -369,9 +315,9 @@ mod tests {
 	fn confirm_delivery_rejects_nonce_lesser_than_latest_received() {
 		run_test(|| {
 			let mut lane = outbound_lane::<TestRuntime, _>(TEST_LANE_ID);
-			lane.send_message(message_data(REGULAR_PAYLOAD));
-			lane.send_message(message_data(REGULAR_PAYLOAD));
-			lane.send_message(message_data(REGULAR_PAYLOAD));
+			lane.send_message(outbound_message_data(REGULAR_PAYLOAD));
+			lane.send_message(outbound_message_data(REGULAR_PAYLOAD));
+			lane.send_message(outbound_message_data(REGULAR_PAYLOAD));
 			assert_eq!(lane.storage.data().latest_generated_nonce, 3);
 			assert_eq!(lane.storage.data().latest_received_nonce, 0);
 			assert_eq!(
@@ -470,9 +416,9 @@ mod tests {
 			assert_eq!(lane.prune_messages(100), 0);
 			assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1);
 			// when nothing is confirmed, nothing is pruned
-			lane.send_message(message_data(REGULAR_PAYLOAD));
-			lane.send_message(message_data(REGULAR_PAYLOAD));
-			lane.send_message(message_data(REGULAR_PAYLOAD));
+			lane.send_message(outbound_message_data(REGULAR_PAYLOAD));
+			lane.send_message(outbound_message_data(REGULAR_PAYLOAD));
+			lane.send_message(outbound_message_data(REGULAR_PAYLOAD));
 			assert_eq!(lane.prune_messages(100), 0);
 			assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1);
 			// after confirmation, some messages are received
@@ -496,9 +442,9 @@ mod tests {
 	fn confirm_delivery_detects_when_more_than_expected_messages_are_confirmed() {
 		run_test(|| {
 			let mut lane = outbound_lane::<TestRuntime, _>(TEST_LANE_ID);
-			lane.send_message(message_data(REGULAR_PAYLOAD));
-			lane.send_message(message_data(REGULAR_PAYLOAD));
-			lane.send_message(message_data(REGULAR_PAYLOAD));
+			lane.send_message(outbound_message_data(REGULAR_PAYLOAD));
+			lane.send_message(outbound_message_data(REGULAR_PAYLOAD));
+			lane.send_message(outbound_message_data(REGULAR_PAYLOAD));
 			assert_eq!(
 				lane.confirm_delivery(0, 3, &unrewarded_relayers(1..=3)),
 				ReceivalConfirmationResult::TryingToConfirmMoreMessagesThanExpected(3),
diff --git a/bridges/modules/messages/src/weights.rs b/bridges/modules/messages/src/weights.rs
index 3801b57b61a4ce2a73e5eaff1332490253224ba2..2ae60c17fafb956c2eb74123da447d8b6d37378f 100644
--- a/bridges/modules/messages/src/weights.rs
+++ b/bridges/modules/messages/src/weights.rs
@@ -17,7 +17,7 @@
 //! Autogenerated weights for `pallet_bridge_messages`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2022-10-17, STEPS: 50, REPEAT: 20
+//! DATE: 2022-11-17, STEPS: 50, REPEAT: 20
 //! LOW RANGE: [], HIGH RANGE: []
 //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled
 //! CHAIN: Some("dev"), DB CACHE: 1024
@@ -50,11 +50,6 @@ use sp_std::marker::PhantomData;
 
 /// Weight functions needed for `pallet_bridge_messages`.
 pub trait WeightInfo {
-	fn send_minimal_message_worst_case() -> Weight;
-	fn send_1_kb_message_worst_case() -> Weight;
-	fn send_16_kb_message_worst_case() -> Weight;
-	fn maximal_increase_message_fee() -> Weight;
-	fn increase_message_fee(i: u32) -> Weight;
 	fn receive_single_message_proof() -> Weight;
 	fn receive_two_messages_proof() -> Weight;
 	fn receive_single_message_proof_with_outbound_lane_state() -> Weight;
@@ -71,150 +66,98 @@ pub trait WeightInfo {
 /// Those weights are test only and must never be used in production.
 pub struct BridgeWeight<T>(PhantomData<T>);
 impl<T: frame_system::Config> WeightInfo for BridgeWeight<T> {
-	fn send_minimal_message_worst_case() -> Weight {
-		Weight::from_ref_time(61_807_000 as u64)
-			.saturating_add(T::DbWeight::get().reads(5 as u64))
-			.saturating_add(T::DbWeight::get().writes(10 as u64))
-	}
-	fn send_1_kb_message_worst_case() -> Weight {
-		Weight::from_ref_time(65_074_000 as u64)
-			.saturating_add(T::DbWeight::get().reads(5 as u64))
-			.saturating_add(T::DbWeight::get().writes(10 as u64))
-	}
-	fn send_16_kb_message_worst_case() -> Weight {
-		Weight::from_ref_time(73_584_000 as u64)
-			.saturating_add(T::DbWeight::get().reads(5 as u64))
-			.saturating_add(T::DbWeight::get().writes(10 as u64))
-	}
-	fn maximal_increase_message_fee() -> Weight {
-		Weight::from_ref_time(2_522_629_000 as u64)
-			.saturating_add(T::DbWeight::get().reads(3 as u64))
-			.saturating_add(T::DbWeight::get().writes(1 as u64))
-	}
-	fn increase_message_fee(i: u32) -> Weight {
-		Weight::from_ref_time(27_072_000 as u64)
-			.saturating_add(Weight::from_ref_time(892 as u64).saturating_mul(i as u64))
-			.saturating_add(T::DbWeight::get().reads(3 as u64))
-			.saturating_add(T::DbWeight::get().writes(1 as u64))
-	}
 	fn receive_single_message_proof() -> Weight {
-		Weight::from_ref_time(49_628_000 as u64)
+		Weight::from_ref_time(50_596_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(4 as u64))
 			.saturating_add(T::DbWeight::get().writes(2 as u64))
 	}
 	fn receive_two_messages_proof() -> Weight {
-		Weight::from_ref_time(61_514_000 as u64)
+		Weight::from_ref_time(77_041_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(4 as u64))
 			.saturating_add(T::DbWeight::get().writes(2 as u64))
 	}
 	fn receive_single_message_proof_with_outbound_lane_state() -> Weight {
-		Weight::from_ref_time(65_960_000 as u64)
+		Weight::from_ref_time(58_331_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(4 as u64))
 			.saturating_add(T::DbWeight::get().writes(2 as u64))
 	}
 	fn receive_single_message_proof_1_kb() -> Weight {
-		Weight::from_ref_time(48_009_000 as u64)
+		Weight::from_ref_time(48_061_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(3 as u64))
 			.saturating_add(T::DbWeight::get().writes(1 as u64))
 	}
 	fn receive_single_message_proof_16_kb() -> Weight {
-		Weight::from_ref_time(100_439_000 as u64)
+		Weight::from_ref_time(101_601_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(3 as u64))
 			.saturating_add(T::DbWeight::get().writes(1 as u64))
 	}
 	fn receive_single_prepaid_message_proof() -> Weight {
-		Weight::from_ref_time(50_463_000 as u64)
+		Weight::from_ref_time(49_646_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(4 as u64))
 			.saturating_add(T::DbWeight::get().writes(2 as u64))
 	}
 	fn receive_delivery_proof_for_single_message() -> Weight {
-		Weight::from_ref_time(57_383_000 as u64)
-			.saturating_add(T::DbWeight::get().reads(5 as u64))
+		Weight::from_ref_time(55_108_000 as u64)
+			.saturating_add(T::DbWeight::get().reads(4 as u64))
 			.saturating_add(T::DbWeight::get().writes(2 as u64))
 	}
 	fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight {
-		Weight::from_ref_time(62_003_000 as u64)
-			.saturating_add(T::DbWeight::get().reads(6 as u64))
+		Weight::from_ref_time(53_917_000 as u64)
+			.saturating_add(T::DbWeight::get().reads(4 as u64))
 			.saturating_add(T::DbWeight::get().writes(2 as u64))
 	}
 	fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight {
-		Weight::from_ref_time(64_401_000 as u64)
-			.saturating_add(T::DbWeight::get().reads(7 as u64))
+		Weight::from_ref_time(57_335_000 as u64)
+			.saturating_add(T::DbWeight::get().reads(5 as u64))
 			.saturating_add(T::DbWeight::get().writes(3 as u64))
 	}
 }
 
 // For backwards compatibility and tests
 impl WeightInfo for () {
-	fn send_minimal_message_worst_case() -> Weight {
-		Weight::from_ref_time(61_807_000 as u64)
-			.saturating_add(RocksDbWeight::get().reads(5 as u64))
-			.saturating_add(RocksDbWeight::get().writes(10 as u64))
-	}
-	fn send_1_kb_message_worst_case() -> Weight {
-		Weight::from_ref_time(65_074_000 as u64)
-			.saturating_add(RocksDbWeight::get().reads(5 as u64))
-			.saturating_add(RocksDbWeight::get().writes(10 as u64))
-	}
-	fn send_16_kb_message_worst_case() -> Weight {
-		Weight::from_ref_time(73_584_000 as u64)
-			.saturating_add(RocksDbWeight::get().reads(5 as u64))
-			.saturating_add(RocksDbWeight::get().writes(10 as u64))
-	}
-	fn maximal_increase_message_fee() -> Weight {
-		Weight::from_ref_time(2_522_629_000 as u64)
-			.saturating_add(RocksDbWeight::get().reads(3 as u64))
-			.saturating_add(RocksDbWeight::get().writes(1 as u64))
-	}
-	fn increase_message_fee(i: u32) -> Weight {
-		Weight::from_ref_time(27_072_000 as u64)
-			.saturating_add(Weight::from_ref_time(892 as u64).saturating_mul(i as u64))
-			.saturating_add(RocksDbWeight::get().reads(3 as u64))
-			.saturating_add(RocksDbWeight::get().writes(1 as u64))
-	}
 	fn receive_single_message_proof() -> Weight {
-		Weight::from_ref_time(49_628_000 as u64)
+		Weight::from_ref_time(50_596_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(4 as u64))
 			.saturating_add(RocksDbWeight::get().writes(2 as u64))
 	}
 	fn receive_two_messages_proof() -> Weight {
-		Weight::from_ref_time(61_514_000 as u64)
+		Weight::from_ref_time(77_041_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(4 as u64))
 			.saturating_add(RocksDbWeight::get().writes(2 as u64))
 	}
 	fn receive_single_message_proof_with_outbound_lane_state() -> Weight {
-		Weight::from_ref_time(65_960_000 as u64)
+		Weight::from_ref_time(58_331_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(4 as u64))
 			.saturating_add(RocksDbWeight::get().writes(2 as u64))
 	}
 	fn receive_single_message_proof_1_kb() -> Weight {
-		Weight::from_ref_time(48_009_000 as u64)
+		Weight::from_ref_time(48_061_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(3 as u64))
 			.saturating_add(RocksDbWeight::get().writes(1 as u64))
 	}
 	fn receive_single_message_proof_16_kb() -> Weight {
-		Weight::from_ref_time(100_439_000 as u64)
+		Weight::from_ref_time(101_601_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(3 as u64))
 			.saturating_add(RocksDbWeight::get().writes(1 as u64))
 	}
 	fn receive_single_prepaid_message_proof() -> Weight {
-		Weight::from_ref_time(50_463_000 as u64)
+		Weight::from_ref_time(49_646_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(4 as u64))
 			.saturating_add(RocksDbWeight::get().writes(2 as u64))
 	}
 	fn receive_delivery_proof_for_single_message() -> Weight {
-		Weight::from_ref_time(57_383_000 as u64)
-			.saturating_add(RocksDbWeight::get().reads(5 as u64))
+		Weight::from_ref_time(55_108_000 as u64)
+			.saturating_add(RocksDbWeight::get().reads(4 as u64))
 			.saturating_add(RocksDbWeight::get().writes(2 as u64))
 	}
 	fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight {
-		Weight::from_ref_time(62_003_000 as u64)
-			.saturating_add(RocksDbWeight::get().reads(6 as u64))
+		Weight::from_ref_time(53_917_000 as u64)
+			.saturating_add(RocksDbWeight::get().reads(4 as u64))
 			.saturating_add(RocksDbWeight::get().writes(2 as u64))
 	}
 	fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight {
-		Weight::from_ref_time(64_401_000 as u64)
-			.saturating_add(RocksDbWeight::get().reads(7 as u64))
+		Weight::from_ref_time(57_335_000 as u64)
+			.saturating_add(RocksDbWeight::get().reads(5 as u64))
 			.saturating_add(RocksDbWeight::get().writes(3 as u64))
 	}
 }
diff --git a/bridges/modules/messages/src/weights_ext.rs b/bridges/modules/messages/src/weights_ext.rs
index 80a1b9cdf8ad5d33163f681c5e9bdc4889d399ab..5ad86c817dcee915f78888bef7392cb9a5b000a7 100644
--- a/bridges/modules/messages/src/weights_ext.rs
+++ b/bridges/modules/messages/src/weights_ext.rs
@@ -35,82 +35,16 @@ const SIGNED_EXTENSIONS_SIZE: u32 = 1024;
 pub const EXTRA_STORAGE_PROOF_SIZE: u32 = 1024;
 
 /// Ensure that weights from `WeightInfoExt` implementation are looking correct.
-pub fn ensure_weights_are_correct<W: WeightInfoExt>(
-	expected_default_message_delivery_tx_weight: Weight,
-	expected_additional_byte_delivery_weight: Weight,
-	expected_messages_delivery_confirmation_tx_weight: Weight,
-	expected_pay_inbound_dispatch_fee_weight: Weight,
-	db_weight: RuntimeDbWeight,
-) {
-	// verify `send_message` weight components
-	assert_ne!(W::send_message_overhead(), Weight::zero());
-	assert_ne!(W::send_message_size_overhead(0), Weight::zero());
-
+pub fn ensure_weights_are_correct<W: WeightInfoExt>() {
 	// verify `receive_messages_proof` weight components
 	assert_ne!(W::receive_messages_proof_overhead(), Weight::zero());
 	assert_ne!(W::receive_messages_proof_messages_overhead(1), Weight::zero());
 	assert_ne!(W::receive_messages_proof_outbound_lane_state_overhead(), Weight::zero());
 	assert_ne!(W::storage_proof_size_overhead(1), Weight::zero());
 
-	// verify that the hardcoded value covers `receive_messages_proof` weight
-	let actual_single_regular_message_delivery_tx_weight = W::receive_messages_proof_weight(
-		&PreComputedSize(
-			(EXPECTED_DEFAULT_MESSAGE_LENGTH + W::expected_extra_storage_proof_size()) as usize,
-		),
-		1,
-		Weight::zero(),
-	);
-	assert!(
-		actual_single_regular_message_delivery_tx_weight
-			.all_lte(expected_default_message_delivery_tx_weight),
-		"Default message delivery transaction weight {} is larger than expected weight {}",
-		actual_single_regular_message_delivery_tx_weight,
-		expected_default_message_delivery_tx_weight,
-	);
-
-	// verify that hardcoded value covers additional byte length of `receive_messages_proof` weight
-	let actual_additional_byte_delivery_weight = W::storage_proof_size_overhead(1);
-	assert!(
-		actual_additional_byte_delivery_weight.all_lte(expected_additional_byte_delivery_weight),
-		"Single additional byte delivery weight {} is larger than expected weight {}",
-		actual_additional_byte_delivery_weight,
-		expected_additional_byte_delivery_weight,
-	);
-
 	// verify `receive_messages_delivery_proof` weight components
 	assert_ne!(W::receive_messages_delivery_proof_overhead(), Weight::zero());
 	assert_ne!(W::storage_proof_size_overhead(1), Weight::zero());
-
-	// `receive_messages_delivery_proof_messages_overhead` and
-	// `receive_messages_delivery_proof_relayers_overhead` may return zero if rewards are not paid
-	// during confirmations delivery, so we're not checking it here
-
-	// verify that the hardcoded value covers `receive_messages_delivery_proof` weight
-	let actual_messages_delivery_confirmation_tx_weight = W::receive_messages_delivery_proof_weight(
-		&PreComputedSize(W::expected_extra_storage_proof_size() as usize),
-		&UnrewardedRelayersState {
-			unrewarded_relayer_entries: 1,
-			total_messages: 1,
-			..Default::default()
-		},
-		db_weight,
-	);
-	assert!(
-		actual_messages_delivery_confirmation_tx_weight
-			.all_lte(expected_messages_delivery_confirmation_tx_weight),
-		"Messages delivery confirmation transaction weight {} is larger than expected weight {}",
-		actual_messages_delivery_confirmation_tx_weight,
-		expected_messages_delivery_confirmation_tx_weight,
-	);
-
-	// verify pay-dispatch-fee overhead for inbound messages
-	let actual_pay_inbound_dispatch_fee_weight = W::pay_inbound_dispatch_fee_overhead();
-	assert!(
-		actual_pay_inbound_dispatch_fee_weight.all_lte(expected_pay_inbound_dispatch_fee_weight),
-		"Weight {} of pay-dispatch-fee overhead for inbound messages is larger than expected weight {}",
-		actual_pay_inbound_dispatch_fee_weight,
-		expected_pay_inbound_dispatch_fee_weight,
-	);
 }
 
 /// Ensure that we're able to receive maximal (by-size and by-weight) message from other chain.
@@ -198,17 +132,6 @@ 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 {
-		let transaction_overhead = Self::send_message_overhead();
-		let message_size_overhead = Self::send_message_size_overhead(message.size());
-		let call_back_overhead = Self::single_message_callback_overhead(db_weight);
-
-		transaction_overhead
-			.saturating_add(message_size_overhead)
-			.saturating_add(call_back_overhead)
-	}
-
 	/// Weight of message delivery extrinsic.
 	fn receive_messages_proof_weight(
 		proof: &impl Size,
@@ -274,20 +197,6 @@ pub trait WeightInfoExt: WeightInfo {
 
 	// Functions that are used by extrinsics weights formulas.
 
-	/// Returns weight of message send transaction (`send_message`).
-	fn send_message_overhead() -> Weight {
-		Self::send_minimal_message_worst_case()
-	}
-
-	/// Returns weight that needs to be accounted when message of given size is sent
-	/// (`send_message`).
-	fn send_message_size_overhead(message_size: u32) -> Weight {
-		let message_size_in_kb = (1024u64 + message_size as u64) / 1024;
-		let single_kb_weight =
-			(Self::send_16_kb_message_worst_case() - Self::send_1_kb_message_worst_case()) / 15;
-		message_size_in_kb * single_kb_weight
-	}
-
 	/// Returns weight overhead of message delivery transaction (`receive_messages_proof`).
 	fn receive_messages_proof_overhead() -> Weight {
 		let weight_of_two_messages_and_two_tx_overheads =
diff --git a/bridges/modules/parachains/src/weights.rs b/bridges/modules/parachains/src/weights.rs
index 43cd68b01d1dcd1b30de1b026bbb52935c164421..5c9206d0ca0a8634a878c3855ce97f15387faf73 100644
--- a/bridges/modules/parachains/src/weights.rs
+++ b/bridges/modules/parachains/src/weights.rs
@@ -17,7 +17,7 @@
 //! Autogenerated weights for `pallet_bridge_parachains`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2022-10-04, STEPS: 50, REPEAT: 20
+//! DATE: 2022-11-17, STEPS: 50, REPEAT: 20
 //! LOW RANGE: [], HIGH RANGE: []
 //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled
 //! CHAIN: Some("dev"), DB CACHE: 1024
@@ -61,19 +61,19 @@ pub trait WeightInfo {
 pub struct BridgeWeight<T>(PhantomData<T>);
 impl<T: frame_system::Config> WeightInfo for BridgeWeight<T> {
 	fn submit_parachain_heads_with_n_parachains(p: u32) -> Weight {
-		Weight::from_ref_time(0 as u64)
-			.saturating_add(Weight::from_ref_time(24_869_000 as u64).saturating_mul(p as u64))
+		Weight::from_ref_time(51_173_000 as u64)
+			.saturating_add(Weight::from_ref_time(24_495_968 as u64).saturating_mul(p as u64))
 			.saturating_add(T::DbWeight::get().reads(2 as u64))
 			.saturating_add(T::DbWeight::get().reads((2 as u64).saturating_mul(p as u64)))
 			.saturating_add(T::DbWeight::get().writes((3 as u64).saturating_mul(p as u64)))
 	}
 	fn submit_parachain_heads_with_1kb_proof() -> Weight {
-		Weight::from_ref_time(56_262_000 as u64)
+		Weight::from_ref_time(58_175_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(4 as u64))
 			.saturating_add(T::DbWeight::get().writes(3 as u64))
 	}
 	fn submit_parachain_heads_with_16kb_proof() -> Weight {
-		Weight::from_ref_time(105_189_000 as u64)
+		Weight::from_ref_time(101_796_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(4 as u64))
 			.saturating_add(T::DbWeight::get().writes(3 as u64))
 	}
@@ -82,19 +82,19 @@ impl<T: frame_system::Config> WeightInfo for BridgeWeight<T> {
 // For backwards compatibility and tests
 impl WeightInfo for () {
 	fn submit_parachain_heads_with_n_parachains(p: u32) -> Weight {
-		Weight::from_ref_time(0 as u64)
-			.saturating_add(Weight::from_ref_time(24_869_000 as u64).saturating_mul(p as u64))
+		Weight::from_ref_time(51_173_000 as u64)
+			.saturating_add(Weight::from_ref_time(24_495_968 as u64).saturating_mul(p as u64))
 			.saturating_add(RocksDbWeight::get().reads(2 as u64))
 			.saturating_add(RocksDbWeight::get().reads((2 as u64).saturating_mul(p as u64)))
 			.saturating_add(RocksDbWeight::get().writes((3 as u64).saturating_mul(p as u64)))
 	}
 	fn submit_parachain_heads_with_1kb_proof() -> Weight {
-		Weight::from_ref_time(56_262_000 as u64)
+		Weight::from_ref_time(58_175_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(4 as u64))
 			.saturating_add(RocksDbWeight::get().writes(3 as u64))
 	}
 	fn submit_parachain_heads_with_16kb_proof() -> Weight {
-		Weight::from_ref_time(105_189_000 as u64)
+		Weight::from_ref_time(101_796_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(4 as u64))
 			.saturating_add(RocksDbWeight::get().writes(3 as u64))
 	}
diff --git a/bridges/modules/relayers/src/mock.rs b/bridges/modules/relayers/src/mock.rs
index d090da3e6da56ccaa9c12899bff8f6a25878e28f..f2ae936ae8c9ba097d167832ba2760a5177bd6ef 100644
--- a/bridges/modules/relayers/src/mock.rs
+++ b/bridges/modules/relayers/src/mock.rs
@@ -97,17 +97,14 @@ parameter_types! {
 impl pallet_bridge_messages::Config for TestRuntime {
 	type RuntimeEvent = RuntimeEvent;
 	type WeightInfo = ();
-	type Parameter = ();
 	type MaxMessagesToPruneAtOnce = frame_support::traits::ConstU64<0>;
 	type MaxUnrewardedRelayerEntriesAtInboundLane = frame_support::traits::ConstU64<8>;
 	type MaxUnconfirmedMessagesAtInboundLane = frame_support::traits::ConstU64<8>;
 
 	type MaximalOutboundPayloadSize = frame_support::traits::ConstU32<1024>;
 	type OutboundPayload = ();
-	type OutboundMessageFee = Balance;
 
 	type InboundPayload = ();
-	type InboundMessageFee = Balance;
 	type InboundRelayer = AccountId;
 
 	type TargetHeaderChain = ForbidOutboundMessages;
diff --git a/bridges/modules/relayers/src/payment_adapter.rs b/bridges/modules/relayers/src/payment_adapter.rs
index d472810c5ccff541b8df59db7b25c24fac7b8a90..772d07d2ad971072f0b17968fb5a53ecdc6d8932 100644
--- a/bridges/modules/relayers/src/payment_adapter.rs
+++ b/bridges/modules/relayers/src/payment_adapter.rs
@@ -20,43 +20,31 @@
 use crate::{Config, RelayerRewards};
 
 use bp_messages::source_chain::{MessageDeliveryAndDispatchPayment, RelayersRewards};
-use frame_support::{sp_runtime::SaturatedConversion, traits::Get};
-use sp_arithmetic::traits::{Saturating, Zero};
+use frame_support::sp_runtime::SaturatedConversion;
+use sp_arithmetic::traits::{Saturating, UniqueSaturatedFrom, Zero};
 use sp_std::{collections::vec_deque::VecDeque, marker::PhantomData, ops::RangeInclusive};
 
 /// Adapter that allows relayers pallet to be used as a delivery+dispatch payment mechanism
 /// for the messages pallet.
-pub struct MessageDeliveryAndDispatchPaymentAdapter<T, MessagesInstance, GetConfirmationFee>(
-	PhantomData<(T, MessagesInstance, GetConfirmationFee)>,
+pub struct MessageDeliveryAndDispatchPaymentAdapter<T, MessagesInstance>(
+	PhantomData<(T, MessagesInstance)>,
 );
 
-impl<T, MessagesInstance, GetConfirmationFee>
-	MessageDeliveryAndDispatchPayment<T::RuntimeOrigin, T::AccountId, T::Reward>
-	for MessageDeliveryAndDispatchPaymentAdapter<T, MessagesInstance, GetConfirmationFee>
+impl<T, MessagesInstance> MessageDeliveryAndDispatchPayment<T::RuntimeOrigin, T::AccountId>
+	for MessageDeliveryAndDispatchPaymentAdapter<T, MessagesInstance>
 where
-	T: Config + pallet_bridge_messages::Config<MessagesInstance, OutboundMessageFee = T::Reward>,
+	T: Config + pallet_bridge_messages::Config<MessagesInstance>,
 	MessagesInstance: 'static,
-	GetConfirmationFee: Get<T::Reward>,
 {
 	type Error = &'static str;
 
-	fn pay_delivery_and_dispatch_fee(
-		_submitter: &T::RuntimeOrigin,
-		_fee: &T::Reward,
-	) -> Result<(), Self::Error> {
-		// nothing shall happen here, because XCM deals with fee payment (planned to be burnt?
-		// or transferred to the treasury?)
-		Ok(())
-	}
-
 	fn pay_relayers_rewards(
-		lane_id: bp_messages::LaneId,
+		_lane_id: bp_messages::LaneId,
 		messages_relayers: VecDeque<bp_messages::UnrewardedRelayer<T::AccountId>>,
 		confirmation_relayer: &T::AccountId,
 		received_range: &RangeInclusive<bp_messages::MessageNonce>,
 	) {
 		let relayers_rewards = pallet_bridge_messages::calc_relayers_rewards::<T, MessagesInstance>(
-			lane_id,
 			messages_relayers,
 			received_range,
 		);
@@ -64,7 +52,10 @@ where
 		register_relayers_rewards::<T>(
 			confirmation_relayer,
 			relayers_rewards,
-			GetConfirmationFee::get(),
+			// TODO (https://github.com/paritytech/parity-bridges-common/issues/1318): this shall be fixed
+			// in some way. ATM the future of the `register_relayers_rewards` is not yet known
+			100_000_u32.into(),
+			10_000_u32.into(),
 		);
 	}
 }
@@ -72,13 +63,17 @@ where
 // Update rewards to given relayers, optionally rewarding confirmation relayer.
 fn register_relayers_rewards<T: Config>(
 	confirmation_relayer: &T::AccountId,
-	relayers_rewards: RelayersRewards<T::AccountId, T::Reward>,
+	relayers_rewards: RelayersRewards<T::AccountId>,
+	delivery_fee: T::Reward,
 	confirmation_fee: T::Reward,
 ) {
 	// reward every relayer except `confirmation_relayer`
 	let mut confirmation_relayer_reward = T::Reward::zero();
-	for (relayer, reward) in relayers_rewards {
-		let mut relayer_reward = reward.reward;
+	for (relayer, messages) in relayers_rewards {
+		// sane runtime configurations guarantee that the number of messages will be below
+		// `u32::MAX`
+		let mut relayer_reward =
+			T::Reward::unique_saturated_from(messages).saturating_mul(delivery_fee);
 
 		if relayer != *confirmation_relayer {
 			// If delivery confirmation is submitted by other relayer, let's deduct confirmation fee
@@ -87,12 +82,11 @@ fn register_relayers_rewards<T: Config>(
 			// If confirmation fee has been increased (or if it was the only component of message
 			// fee), then messages relayer may receive zero reward.
 			let mut confirmation_reward =
-				T::Reward::saturated_from(reward.messages).saturating_mul(confirmation_fee);
+				T::Reward::saturated_from(messages).saturating_mul(confirmation_fee);
 			confirmation_reward = sp_std::cmp::min(confirmation_reward, relayer_reward);
 			relayer_reward = relayer_reward.saturating_sub(confirmation_reward);
 			confirmation_relayer_reward =
 				confirmation_relayer_reward.saturating_add(confirmation_reward);
-
 			register_relayer_reward::<T>(&relayer, relayer_reward);
 		} else {
 			// If delivery confirmation is submitted by this relayer, let's add confirmation fee
@@ -134,32 +128,27 @@ mod tests {
 	const RELAYER_2: AccountId = 2;
 	const RELAYER_3: AccountId = 3;
 
-	fn relayers_rewards() -> RelayersRewards<AccountId, Balance> {
-		vec![
-			(RELAYER_1, bp_messages::source_chain::RelayerRewards { reward: 100, messages: 2 }),
-			(RELAYER_2, bp_messages::source_chain::RelayerRewards { reward: 100, messages: 3 }),
-		]
-		.into_iter()
-		.collect()
+	fn relayers_rewards() -> RelayersRewards<AccountId> {
+		vec![(RELAYER_1, 2), (RELAYER_2, 3)].into_iter().collect()
 	}
 
 	#[test]
 	fn confirmation_relayer_is_rewarded_if_it_has_also_delivered_messages() {
 		run_test(|| {
-			register_relayers_rewards::<TestRuntime>(&RELAYER_2, relayers_rewards(), 10);
+			register_relayers_rewards::<TestRuntime>(&RELAYER_2, relayers_rewards(), 50, 10);
 
 			assert_eq!(RelayerRewards::<TestRuntime>::get(RELAYER_1), Some(80));
-			assert_eq!(RelayerRewards::<TestRuntime>::get(RELAYER_2), Some(120));
+			assert_eq!(RelayerRewards::<TestRuntime>::get(RELAYER_2), Some(170));
 		});
 	}
 
 	#[test]
 	fn confirmation_relayer_is_rewarded_if_it_has_not_delivered_any_delivered_messages() {
 		run_test(|| {
-			register_relayers_rewards::<TestRuntime>(&RELAYER_3, relayers_rewards(), 10);
+			register_relayers_rewards::<TestRuntime>(&RELAYER_3, relayers_rewards(), 50, 10);
 
 			assert_eq!(RelayerRewards::<TestRuntime>::get(RELAYER_1), Some(80));
-			assert_eq!(RelayerRewards::<TestRuntime>::get(RELAYER_2), Some(70));
+			assert_eq!(RelayerRewards::<TestRuntime>::get(RELAYER_2), Some(120));
 			assert_eq!(RelayerRewards::<TestRuntime>::get(RELAYER_3), Some(50));
 		});
 	}
@@ -167,11 +156,11 @@ mod tests {
 	#[test]
 	fn only_confirmation_relayer_is_rewarded_if_confirmation_fee_has_significantly_increased() {
 		run_test(|| {
-			register_relayers_rewards::<TestRuntime>(&RELAYER_3, relayers_rewards(), 1000);
+			register_relayers_rewards::<TestRuntime>(&RELAYER_3, relayers_rewards(), 50, 1000);
 
 			assert_eq!(RelayerRewards::<TestRuntime>::get(RELAYER_1), None);
 			assert_eq!(RelayerRewards::<TestRuntime>::get(RELAYER_2), None);
-			assert_eq!(RelayerRewards::<TestRuntime>::get(RELAYER_3), Some(200));
+			assert_eq!(RelayerRewards::<TestRuntime>::get(RELAYER_3), Some(250));
 		});
 	}
 }
diff --git a/bridges/modules/relayers/src/weights.rs b/bridges/modules/relayers/src/weights.rs
index b8df8c94499cc35ddd02e7b0edf73fbaaff052c5..7bcd8711a9eac2a4d66dd8a3479f1f80e709d171 100644
--- a/bridges/modules/relayers/src/weights.rs
+++ b/bridges/modules/relayers/src/weights.rs
@@ -17,7 +17,7 @@
 //! Autogenerated weights for `pallet_bridge_relayers`
 //!
 //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2022-10-04, STEPS: 50, REPEAT: 20
+//! DATE: 2022-11-17, STEPS: 50, REPEAT: 20
 //! LOW RANGE: [], HIGH RANGE: []
 //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled
 //! CHAIN: Some("dev"), DB CACHE: 1024
@@ -59,7 +59,7 @@ pub trait WeightInfo {
 pub struct BridgeWeight<T>(PhantomData<T>);
 impl<T: frame_system::Config> WeightInfo for BridgeWeight<T> {
 	fn claim_rewards() -> Weight {
-		Weight::from_ref_time(55_856_000 as u64)
+		Weight::from_ref_time(59_334_000 as u64)
 			.saturating_add(T::DbWeight::get().reads(2 as u64))
 			.saturating_add(T::DbWeight::get().writes(2 as u64))
 	}
@@ -68,7 +68,7 @@ impl<T: frame_system::Config> WeightInfo for BridgeWeight<T> {
 // For backwards compatibility and tests
 impl WeightInfo for () {
 	fn claim_rewards() -> Weight {
-		Weight::from_ref_time(55_856_000 as u64)
+		Weight::from_ref_time(59_334_000 as u64)
 			.saturating_add(RocksDbWeight::get().reads(2 as u64))
 			.saturating_add(RocksDbWeight::get().writes(2 as u64))
 	}
diff --git a/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs b/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs
index 0d1a81be10292b7f5cf3bbd85e11f10fc86d4af2..aa65f378542a61db9fd56781dae228db5ab21e8b 100644
--- a/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs
+++ b/bridges/primitives/chain-bridge-hub-rococo/src/lib.rs
@@ -27,12 +27,12 @@ use bp_runtime::{
 use frame_support::{
 	dispatch::DispatchClass,
 	parameter_types,
-	sp_runtime::{FixedU128, MultiAddress, MultiSigner},
+	sp_runtime::{MultiAddress, MultiSigner},
 	weights::{
 		constants::ExtrinsicBaseWeight, WeightToFeeCoefficient, WeightToFeeCoefficients,
 		WeightToFeePolynomial,
 	},
-	Parameter, RuntimeDebug,
+	RuntimeDebug,
 };
 use sp_std::prelude::*;
 
diff --git a/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs b/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs
index 33c4dcca127e3037e71a6af339b1baef03ce69f9..5cee3f14dd6ddb2c32de9b84e8486e3fb8f63afe 100644
--- a/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs
+++ b/bridges/primitives/chain-bridge-hub-wococo/src/lib.rs
@@ -27,16 +27,14 @@ pub use bp_bridge_hub_rococo::{
 	account_info_storage_key, AccountId, AccountPublic, AccountSigner, Address, Balance,
 	BlockLength, BlockNumber, BlockWeights, Hash, Hasher, Hashing, Header, Index, Nonce,
 	SS58Prefix, Signature, SignedBlock, SignedExtensions, UncheckedExtrinsic, WeightToFee,
-	ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT, DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT,
-	EXTRA_STORAGE_PROOF_SIZE, MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT,
 	MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX,
-	PAY_INBOUND_DISPATCH_FEE_WEIGHT, TX_EXTRA_BYTES,
+	TX_EXTRA_BYTES,
 };
 use bp_messages::*;
 use bp_runtime::{
 	decl_bridge_finality_runtime_apis, decl_bridge_messages_runtime_apis, Chain, Parachain,
 };
-use frame_support::{dispatch::DispatchClass, sp_runtime::FixedU128, Parameter, RuntimeDebug};
+use frame_support::{dispatch::DispatchClass, RuntimeDebug};
 use sp_std::prelude::*;
 
 /// BridgeHubWococo parachain.
diff --git a/bridges/primitives/chain-millau/src/lib.rs b/bridges/primitives/chain-millau/src/lib.rs
index 9c0b4782e37ebff172797d729628ff97f4655b07..07cdb0c27f6ed1b33fc8bd564b189209359f6ef8 100644
--- a/bridges/primitives/chain-millau/src/lib.rs
+++ b/bridges/primitives/chain-millau/src/lib.rs
@@ -27,14 +27,14 @@ use bp_runtime::{decl_bridge_runtime_apis, Chain};
 use frame_support::{
 	dispatch::DispatchClass,
 	weights::{constants::WEIGHT_PER_SECOND, IdentityFee, Weight},
-	Parameter, RuntimeDebug,
+	RuntimeDebug,
 };
 use frame_system::limits;
 use scale_info::TypeInfo;
 use sp_core::{storage::StateVersion, Hasher as HasherT};
 use sp_runtime::{
 	traits::{IdentifyAccount, Verify},
-	FixedU128, MultiSignature, MultiSigner, Perbill,
+	MultiSignature, MultiSigner, Perbill,
 };
 use sp_std::prelude::*;
 use sp_trie::{LayoutV0, LayoutV1, TrieConfiguration};
@@ -69,38 +69,6 @@ pub const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 128;
 /// Maximal number of unconfirmed messages in Millau confirmation transaction.
 pub const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 128;
 
-/// Weight of single regular message delivery transaction on Millau chain.
-///
-/// This value is a result of `pallet_bridge_messages::Pallet::receive_messages_proof_weight()` call
-/// for the case when single message of `pallet_bridge_messages::EXPECTED_DEFAULT_MESSAGE_LENGTH`
-/// bytes is delivered. The message must have dispatch weight set to zero. The result then must be
-/// rounded up to account possible future runtime upgrades.
-pub const DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT: Weight = Weight::from_ref_time(1_500_000_000);
-
-/// Increase of delivery transaction weight on Millau chain with every additional message byte.
-///
-/// This value is a result of
-/// `pallet_bridge_messages::WeightInfoExt::storage_proof_size_overhead(1)` call. The result then
-/// must be rounded up to account possible future runtime upgrades.
-pub const ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT: Weight = Weight::from_ref_time(25_000);
-
-/// Maximal weight of single message delivery confirmation transaction on Millau chain.
-///
-/// This value is a result of `pallet_bridge_messages::Pallet::receive_messages_delivery_proof`
-/// weight formula computation for the case when single message is confirmed. The result then must
-/// be rounded up to account possible future runtime upgrades.
-pub const MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT: Weight =
-	Weight::from_ref_time(2_000_000_000);
-
-/// Weight of pay-dispatch-fee operation for inbound messages at Millau chain.
-///
-/// This value corresponds to the result of
-/// `pallet_bridge_messages::WeightInfoExt::pay_inbound_dispatch_fee_overhead()` call for your
-/// chain. Don't put too much reserve there, because it is used to **decrease**
-/// `DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT` cost. So putting large reserve would make delivery
-/// transactions cheaper.
-pub const PAY_INBOUND_DISPATCH_FEE_WEIGHT: Weight = Weight::from_ref_time(700_000_000);
-
 /// The target length of a session (how often authorities change) on Millau measured in of number of
 /// blocks.
 ///
@@ -237,13 +205,4 @@ pub const WITH_MILLAU_MESSAGES_PALLET_NAME: &str = "BridgeMillauMessages";
 /// Name of the transaction payment pallet at the Millau runtime.
 pub const TRANSACTION_PAYMENT_PALLET_NAME: &str = "TransactionPayment";
 
-/// 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 RialtoParachain->Millau (actually DOT->KSM) conversion rate stored in the Millau
-/// runtime.
-pub const RIALTO_PARACHAIN_TO_MILLAU_CONVERSION_RATE_PARAMETER_NAME: &str =
-	"RialtoParachainToMillauConversionRate";
-/// Name of the RialtoParachain fee multiplier parameter, stored in the Millau runtime.
-pub const RIALTO_PARACHAIN_FEE_MULTIPLIER_PARAMETER_NAME: &str = "RialtoParachainFeeMultiplier";
-
 decl_bridge_runtime_apis!(millau);
diff --git a/bridges/primitives/chain-rialto-parachain/src/lib.rs b/bridges/primitives/chain-rialto-parachain/src/lib.rs
index 584882425b4db6aaed128338bbd92067c016ba52..82b6a12c182a3842d11c96238ba5ab32d57b9261 100644
--- a/bridges/primitives/chain-rialto-parachain/src/lib.rs
+++ b/bridges/primitives/chain-rialto-parachain/src/lib.rs
@@ -25,13 +25,13 @@ use bp_runtime::{decl_bridge_runtime_apis, Chain, Parachain};
 use frame_support::{
 	dispatch::DispatchClass,
 	weights::{constants::WEIGHT_PER_SECOND, IdentityFee, Weight},
-	Parameter, RuntimeDebug,
+	RuntimeDebug,
 };
 use frame_system::limits;
 use sp_core::Hasher as HasherT;
 use sp_runtime::{
 	traits::{BlakeTwo256, IdentifyAccount, Verify},
-	FixedU128, MultiSignature, MultiSigner, Perbill,
+	MultiSignature, MultiSigner, Perbill,
 };
 use sp_std::vec::Vec;
 
@@ -66,39 +66,6 @@ pub const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 1024;
 /// Maximal number of unconfirmed messages in Rialto confirmation transaction.
 pub const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 1024;
 
-/// Weight of single regular message delivery transaction on RialtoParachain chain.
-///
-/// This value is a result of `pallet_bridge_messages::Pallet::receive_messages_proof_weight()` call
-/// for the case when single message of `pallet_bridge_messages::EXPECTED_DEFAULT_MESSAGE_LENGTH`
-/// bytes is delivered. The message must have dispatch weight set to zero. The result then must be
-/// rounded up to account possible future runtime upgrades.
-pub const DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT: Weight = Weight::from_ref_time(1_500_000_000);
-
-/// Increase of delivery transaction weight on RialtoParachain chain with every additional message
-/// byte.
-///
-/// This value is a result of
-/// `pallet_bridge_messages::WeightInfoExt::storage_proof_size_overhead(1)` call. The result then
-/// must be rounded up to account possible future runtime upgrades.
-pub const ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT: Weight = Weight::from_ref_time(25_000);
-
-/// Maximal weight of single message delivery confirmation transaction on RialtoParachain chain.
-///
-/// This value is a result of `pallet_bridge_messages::Pallet::receive_messages_delivery_proof`
-/// weight formula computation for the case when single message is confirmed. The result then must
-/// be rounded up to account possible future runtime upgrades.
-pub const MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT: Weight =
-	Weight::from_ref_time(2_000_000_000);
-
-/// Weight of pay-dispatch-fee operation for inbound messages at Rialto chain.
-///
-/// This value corresponds to the result of
-/// `pallet_bridge_messages::WeightInfoExt::pay_inbound_dispatch_fee_overhead()` call for your
-/// chain. Don't put too much reserve there, because it is used to **decrease**
-/// `DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT` cost. So putting large reserve would make delivery
-/// transactions cheaper.
-pub const PAY_INBOUND_DISPATCH_FEE_WEIGHT: Weight = Weight::from_ref_time(600_000_000);
-
 /// Block number type used in Rialto.
 pub type BlockNumber = u32;
 
@@ -176,11 +143,4 @@ pub const WITH_RIALTO_PARACHAIN_MESSAGES_PALLET_NAME: &str = "BridgeRialtoParach
 /// Name of the transaction payment pallet at the Rialto parachain runtime.
 pub const TRANSACTION_PAYMENT_PALLET_NAME: &str = "TransactionPayment";
 
-/// Name of the Millau->RialtoParachain (actually KSM->DOT) conversion rate stored in the Rialto
-/// parachain runtime.
-pub const MILLAU_TO_RIALTO_PARACHAIN_CONVERSION_RATE_PARAMETER_NAME: &str =
-	"MillauToRialtoParachainConversionRate";
-/// Name of the Millau fee multiplier parameter, stored in the Rialto parachain runtime.
-pub const MILLAU_FEE_MULTIPLIER_PARAMETER_NAME: &str = "MillauFeeMultiplier";
-
 decl_bridge_runtime_apis!(rialto_parachain);
diff --git a/bridges/primitives/chain-rialto/src/lib.rs b/bridges/primitives/chain-rialto/src/lib.rs
index 4d272fe68399fc78cd87ce984f77f9ce56888ac7..dfb727829d9aa0e6eb806497b954b857e7f8adad 100644
--- a/bridges/primitives/chain-rialto/src/lib.rs
+++ b/bridges/primitives/chain-rialto/src/lib.rs
@@ -25,13 +25,13 @@ use bp_runtime::{decl_bridge_runtime_apis, Chain};
 use frame_support::{
 	dispatch::DispatchClass,
 	weights::{constants::WEIGHT_PER_SECOND, IdentityFee, Weight},
-	Parameter, RuntimeDebug,
+	RuntimeDebug,
 };
 use frame_system::limits;
 use sp_core::Hasher as HasherT;
 use sp_runtime::{
 	traits::{BlakeTwo256, IdentifyAccount, Verify},
-	FixedU128, MultiSignature, MultiSigner, Perbill,
+	MultiSignature, MultiSigner, Perbill,
 };
 use sp_std::prelude::*;
 
@@ -60,38 +60,6 @@ pub const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 1024;
 /// Maximal number of unconfirmed messages in Rialto confirmation transaction.
 pub const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 1024;
 
-/// Weight of single regular message delivery transaction on Rialto chain.
-///
-/// This value is a result of `pallet_bridge_messages::Pallet::receive_messages_proof_weight()` call
-/// for the case when single message of `pallet_bridge_messages::EXPECTED_DEFAULT_MESSAGE_LENGTH`
-/// bytes is delivered. The message must have dispatch weight set to zero. The result then must be
-/// rounded up to account possible future runtime upgrades.
-pub const DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT: Weight = Weight::from_ref_time(1_500_000_000);
-
-/// Increase of delivery transaction weight on Rialto chain with every additional message byte.
-///
-/// This value is a result of
-/// `pallet_bridge_messages::WeightInfoExt::storage_proof_size_overhead(1)` call. The result then
-/// must be rounded up to account possible future runtime upgrades.
-pub const ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT: Weight = Weight::from_ref_time(25_000);
-
-/// Maximal weight of single message delivery confirmation transaction on Rialto chain.
-///
-/// This value is a result of `pallet_bridge_messages::Pallet::receive_messages_delivery_proof`
-/// weight formula computation for the case when single message is confirmed. The result then must
-/// be rounded up to account possible future runtime upgrades.
-pub const MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT: Weight =
-	Weight::from_ref_time(2_000_000_000);
-
-/// Weight of pay-dispatch-fee operation for inbound messages at Rialto chain.
-///
-/// This value corresponds to the result of
-/// `pallet_bridge_messages::WeightInfoExt::pay_inbound_dispatch_fee_overhead()` call for your
-/// chain. Don't put too much reserve there, because it is used to **decrease**
-/// `DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT` cost. So putting large reserve would make delivery
-/// transactions cheaper.
-pub const PAY_INBOUND_DISPATCH_FEE_WEIGHT: Weight = Weight::from_ref_time(700_000_000);
-
 /// The target length of a session (how often authorities change) on Rialto measured in of number of
 /// blocks.
 ///
@@ -203,9 +171,6 @@ pub const WITH_RIALTO_MESSAGES_PALLET_NAME: &str = "BridgeRialtoMessages";
 /// Name of the With-Rialto parachains bridge pallet instance that is deployed at bridged chains.
 pub const WITH_RIALTO_BRIDGE_PARAS_PALLET_NAME: &str = "BridgeRialtoParachains";
 
-/// Name of the Millau->Rialto (actually KSM->DOT) conversion rate stored in the Rialto runtime.
-pub const MILLAU_TO_RIALTO_CONVERSION_RATE_PARAMETER_NAME: &str = "MillauToRialtoConversionRate";
-
 /// Name of the parachain registrar pallet in the Rialto runtime.
 pub const PARAS_REGISTRAR_PALLET_NAME: &str = "Registrar";
 
diff --git a/bridges/primitives/chain-statemine/Cargo.toml b/bridges/primitives/chain-statemine/Cargo.toml
deleted file mode 100644
index 18d186ba41ef5ea88fed90cf7b2691d321ed5f37..0000000000000000000000000000000000000000
--- a/bridges/primitives/chain-statemine/Cargo.toml
+++ /dev/null
@@ -1,24 +0,0 @@
-[package]
-name = "bp-statemine"
-description = "Primitives of Statemine runtime."
-version = "0.1.0"
-authors = ["Parity Technologies <admin@parity.io>"]
-edition = "2021"
-license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
-
-[dependencies]
-
-# Bridge Dependencies
-
-bp-polkadot-core = { path = "../polkadot-core", default-features = false }
-
-# Substrate Based Dependencies
-
-sp-version = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
-
-[features]
-default = ["std"]
-std = [
-	"bp-polkadot-core/std",
-    "sp-version/std",
-]
diff --git a/bridges/primitives/chain-statemine/src/lib.rs b/bridges/primitives/chain-statemine/src/lib.rs
deleted file mode 100644
index 613e4a4f4501a5816ad9dfec0a0511bda9d76b00..0000000000000000000000000000000000000000
--- a/bridges/primitives/chain-statemine/src/lib.rs
+++ /dev/null
@@ -1,38 +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)]
-// RuntimeApi generated functions
-#![allow(clippy::too_many_arguments)]
-
-pub use bp_polkadot_core::*;
-
-use sp_version::RuntimeVersion;
-
-/// Statemine Chain.
-pub type Statemine = PolkadotLike;
-
-/// Known Statemine runtime version.
-pub const VERSION: RuntimeVersion = RuntimeVersion {
-	spec_name: sp_version::create_runtime_str!("statemine"),
-	impl_name: sp_version::create_runtime_str!("statemine"),
-	authoring_version: 1,
-	spec_version: 9300,
-	impl_version: 0,
-	apis: sp_version::create_apis_vec![[]],
-	transaction_version: 8,
-	state_version: 1,
-};
diff --git a/bridges/primitives/messages/src/lib.rs b/bridges/primitives/messages/src/lib.rs
index 8742ff8448d72335f6c517c0378a4dc2e92a46a1..f535a40a9db9ba52abea23b8cb34f3db59352987 100644
--- a/bridges/primitives/messages/src/lib.rs
+++ b/bridges/primitives/messages/src/lib.rs
@@ -21,7 +21,7 @@
 #![allow(clippy::too_many_arguments)]
 
 use bitvec::prelude::*;
-use bp_runtime::{messages::DispatchFeePayment, BasicOperatingMode, OperatingMode};
+use bp_runtime::{BasicOperatingMode, OperatingMode};
 use codec::{Decode, Encode, MaxEncodedLen};
 use frame_support::RuntimeDebug;
 use scale_info::TypeInfo;
@@ -65,16 +65,6 @@ impl OperatingMode for MessagesOperatingMode {
 	}
 }
 
-/// Messages pallet parameter.
-pub trait Parameter: frame_support::Parameter {
-	/// Save parameter value in the runtime storage.
-	fn save(&self);
-}
-
-impl Parameter for () {
-	fn save(&self) {}
-}
-
 /// Lane identifier.
 pub type LaneId = [u8; 4];
 
@@ -96,22 +86,13 @@ pub struct MessageKey {
 	pub nonce: MessageNonce,
 }
 
-/// Message data as it is stored in the storage.
-#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
-pub struct MessageData<Fee> {
-	/// Message payload.
-	pub payload: MessagePayload,
-	/// Message delivery and dispatch fee, paid by the submitter.
-	pub fee: Fee,
-}
-
 /// Message as it is stored in the storage.
 #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)]
-pub struct Message<Fee> {
+pub struct Message {
 	/// Message key.
 	pub key: MessageKey,
-	/// Message data.
-	pub data: MessageData<Fee>,
+	/// Message payload.
+	pub payload: MessagePayload,
 }
 
 /// Inbound lane data.
@@ -198,7 +179,7 @@ impl<RelayerId> InboundLaneData<RelayerId> {
 
 /// Outbound message details, returned by runtime APIs.
 #[derive(Clone, Encode, Decode, RuntimeDebug, PartialEq, Eq)]
-pub struct OutboundMessageDetails<OutboundMessageFee> {
+pub struct OutboundMessageDetails {
 	/// Nonce assigned to the message.
 	pub nonce: MessageNonce,
 	/// Message dispatch weight.
@@ -208,10 +189,6 @@ pub struct OutboundMessageDetails<OutboundMessageFee> {
 	pub dispatch_weight: Weight,
 	/// Size of the encoded message.
 	pub size: u32,
-	/// Delivery+dispatch fee paid by the message submitter at the source chain.
-	pub delivery_and_dispatch_fee: OutboundMessageFee,
-	/// Where the fee for dispatching message is paid?
-	pub dispatch_fee_payment: DispatchFeePayment,
 }
 
 /// Inbound message details, returned by runtime APIs.
diff --git a/bridges/primitives/messages/src/source_chain.rs b/bridges/primitives/messages/src/source_chain.rs
index 8050f994dd3f1a7d0415fab7b3e830f3ccb45c97..6a22ececf8efc6851569a5f3d2b4546b68036603 100644
--- a/bridges/primitives/messages/src/source_chain.rs
+++ b/bridges/primitives/messages/src/source_chain.rs
@@ -27,17 +27,8 @@ use sp_std::{
 	ops::RangeInclusive,
 };
 
-/// Relayers rewards, grouped by relayer account id.
-pub type RelayersRewards<AccountId, Balance> = BTreeMap<AccountId, RelayerRewards<Balance>>;
-
-/// Single relayer rewards.
-#[derive(RuntimeDebug, Default)]
-pub struct RelayerRewards<Balance> {
-	/// Total rewards that are to be paid to the relayer.
-	pub reward: Balance,
-	/// Total number of messages relayed by this relayer.
-	pub messages: MessageNonce,
-}
+/// Number of messages, delivered by relayers.
+pub type RelayersRewards<AccountId> = BTreeMap<AccountId, MessageNonce>;
 
 /// Target chain API. Used by source chain to verify target chain proofs.
 ///
@@ -83,7 +74,7 @@ pub trait TargetHeaderChain<Payload, AccountId> {
 /// Lane3 until some block, ...), then it may be built using this verifier.
 ///
 /// Any fee requirements should also be enforced here.
-pub trait LaneMessageVerifier<SenderOrigin, Payload, Fee> {
+pub trait LaneMessageVerifier<SenderOrigin, Payload> {
 	/// Error type.
 	type Error: Debug + Into<&'static str>;
 
@@ -91,7 +82,6 @@ pub trait LaneMessageVerifier<SenderOrigin, Payload, Fee> {
 	/// lane.
 	fn verify_message(
 		submitter: &SenderOrigin,
-		delivery_and_dispatch_fee: &Fee,
 		lane: &LaneId,
 		outbound_data: &OutboundLaneData,
 		payload: &Payload,
@@ -107,21 +97,10 @@ pub trait LaneMessageVerifier<SenderOrigin, Payload, Fee> {
 /// 3) message-dispatch fee. It is paid by relayer for processing message by target chain;
 /// 4) message-receiving-delivery-transaction-fee. It is submitted to the source node
 /// by relayer.
-///
-/// So to be sure that any non-altruist relayer would agree to deliver message, submitter
-/// should set `delivery_and_dispatch_fee` to at least (equivalent of): sum of fees from (2)
-/// to (4) above, plus some interest for the relayer.
-pub trait MessageDeliveryAndDispatchPayment<SenderOrigin, AccountId, Balance> {
+pub trait MessageDeliveryAndDispatchPayment<SenderOrigin, AccountId> {
 	/// Error type.
 	type Error: Debug + Into<&'static str>;
 
-	/// Withhold/write-off delivery_and_dispatch_fee from submitter account to
-	/// some relayers-fund account.
-	fn pay_delivery_and_dispatch_fee(
-		submitter: &SenderOrigin,
-		fee: &Balance,
-	) -> Result<(), Self::Error>;
-
 	/// Pay rewards for delivering messages to the given relayers.
 	///
 	/// The implementation may also choose to pay reward to the `confirmation_relayer`, which is
@@ -134,18 +113,9 @@ pub trait MessageDeliveryAndDispatchPayment<SenderOrigin, AccountId, Balance> {
 	);
 }
 
-impl<SenderOrigin, AccountId, Balance>
-	MessageDeliveryAndDispatchPayment<SenderOrigin, AccountId, Balance> for ()
-{
+impl<SenderOrigin, AccountId> MessageDeliveryAndDispatchPayment<SenderOrigin, AccountId> for () {
 	type Error = &'static str;
 
-	fn pay_delivery_and_dispatch_fee(
-		_submitter: &SenderOrigin,
-		_fee: &Balance,
-	) -> Result<(), Self::Error> {
-		Ok(())
-	}
-
 	fn pay_relayers_rewards(
 		_lane_id: LaneId,
 		_messages_relayers: VecDeque<UnrewardedRelayer<AccountId>>,
@@ -165,7 +135,7 @@ pub struct SendMessageArtifacts {
 }
 
 /// Messages bridge API to be used from other pallets.
-pub trait MessagesBridge<SenderOrigin, Balance, Payload> {
+pub trait MessagesBridge<SenderOrigin, Payload> {
 	/// Error type.
 	type Error: Debug;
 
@@ -176,7 +146,6 @@ pub trait MessagesBridge<SenderOrigin, Balance, Payload> {
 		sender: SenderOrigin,
 		lane: LaneId,
 		message: Payload,
-		delivery_and_dispatch_fee: Balance,
 	) -> Result<SendMessageArtifacts, Self::Error>;
 }
 
@@ -184,16 +153,13 @@ pub trait MessagesBridge<SenderOrigin, Balance, Payload> {
 #[derive(Eq, RuntimeDebug, PartialEq)]
 pub struct NoopMessagesBridge;
 
-impl<SenderOrigin, Balance, Payload> MessagesBridge<SenderOrigin, Balance, Payload>
-	for NoopMessagesBridge
-{
+impl<SenderOrigin, Payload> MessagesBridge<SenderOrigin, Payload> for NoopMessagesBridge {
 	type Error = &'static str;
 
 	fn send_message(
 		_sender: SenderOrigin,
 		_lane: LaneId,
 		_message: Payload,
-		_delivery_and_dispatch_fee: Balance,
 	) -> Result<SendMessageArtifacts, Self::Error> {
 		Ok(SendMessageArtifacts { nonce: 0, weight: Weight::zero() })
 	}
@@ -266,14 +232,11 @@ impl<Payload, AccountId> TargetHeaderChain<Payload, AccountId> for ForbidOutboun
 	}
 }
 
-impl<SenderOrigin, Payload, Fee> LaneMessageVerifier<SenderOrigin, Payload, Fee>
-	for ForbidOutboundMessages
-{
+impl<SenderOrigin, Payload> LaneMessageVerifier<SenderOrigin, Payload> for ForbidOutboundMessages {
 	type Error = &'static str;
 
 	fn verify_message(
 		_submitter: &SenderOrigin,
-		_delivery_and_dispatch_fee: &Fee,
 		_lane: &LaneId,
 		_outbound_data: &OutboundLaneData,
 		_payload: &Payload,
@@ -282,18 +245,11 @@ impl<SenderOrigin, Payload, Fee> LaneMessageVerifier<SenderOrigin, Payload, Fee>
 	}
 }
 
-impl<SenderOrigin, AccountId, Balance>
-	MessageDeliveryAndDispatchPayment<SenderOrigin, AccountId, Balance> for ForbidOutboundMessages
+impl<SenderOrigin, AccountId> MessageDeliveryAndDispatchPayment<SenderOrigin, AccountId>
+	for ForbidOutboundMessages
 {
 	type Error = &'static str;
 
-	fn pay_delivery_and_dispatch_fee(
-		_submitter: &SenderOrigin,
-		_fee: &Balance,
-	) -> Result<(), Self::Error> {
-		Err(ALL_OUTBOUND_MESSAGES_REJECTED)
-	}
-
 	fn pay_relayers_rewards(
 		_lane_id: LaneId,
 		_messages_relayers: VecDeque<UnrewardedRelayer<AccountId>>,
diff --git a/bridges/primitives/messages/src/target_chain.rs b/bridges/primitives/messages/src/target_chain.rs
index 58419c398bb33e673ae164109bde47fccbca667c..5f682dee16666daf7af078c33960dfb1cd085893 100644
--- a/bridges/primitives/messages/src/target_chain.rs
+++ b/bridges/primitives/messages/src/target_chain.rs
@@ -16,7 +16,7 @@
 
 //! Primitives of messages module, that are used on the target chain.
 
-use crate::{LaneId, Message, MessageData, MessageKey, OutboundLaneData};
+use crate::{LaneId, Message, MessageKey, MessagePayload, OutboundLaneData};
 
 use bp_runtime::{messages::MessageDispatchResult, Size};
 use codec::{Decode, Encode, Error as CodecError};
@@ -38,20 +38,18 @@ pub struct ProvedLaneMessages<Message> {
 
 /// Message data with decoded dispatch payload.
 #[derive(RuntimeDebug)]
-pub struct DispatchMessageData<DispatchPayload, Fee> {
+pub struct DispatchMessageData<DispatchPayload> {
 	/// Result of dispatch payload decoding.
 	pub payload: Result<DispatchPayload, CodecError>,
-	/// Message delivery and dispatch fee, paid by the submitter.
-	pub fee: Fee,
 }
 
 /// Message with decoded dispatch payload.
 #[derive(RuntimeDebug)]
-pub struct DispatchMessage<DispatchPayload, Fee> {
+pub struct DispatchMessage<DispatchPayload> {
 	/// Message key.
 	pub key: MessageKey,
 	/// Message data with decoded dispatch payload.
-	pub data: DispatchMessageData<DispatchPayload, Fee>,
+	pub data: DispatchMessageData<DispatchPayload>,
 }
 
 /// Source chain API. Used by target chain, to verify source chain proofs.
@@ -59,7 +57,7 @@ pub struct DispatchMessage<DispatchPayload, Fee> {
 /// All implementations of this trait should only work with finalized data that
 /// can't change. Wrong implementation may lead to invalid lane states (i.e. lane
 /// that's stuck) and/or processing messages without paying fees.
-pub trait SourceHeaderChain<Fee> {
+pub trait SourceHeaderChain {
 	/// Error type.
 	type Error: Debug + Into<&'static str>;
 
@@ -81,11 +79,11 @@ pub trait SourceHeaderChain<Fee> {
 	fn verify_messages_proof(
 		proof: Self::MessagesProof,
 		messages_count: u32,
-	) -> Result<ProvedMessages<Message<Fee>>, Self::Error>;
+	) -> Result<ProvedMessages<Message>, Self::Error>;
 }
 
 /// Called when inbound message is received.
-pub trait MessageDispatch<AccountId, Fee> {
+pub trait MessageDispatch<AccountId> {
 	/// Decoded message payload type. Valid message may contain invalid payload. In this case
 	/// message is delivered, but dispatch fails. Therefore, two separate types of payload
 	/// (opaque `MessagePayload` used in delivery and this `DispatchPayload` used in dispatch).
@@ -96,7 +94,7 @@ pub trait MessageDispatch<AccountId, Fee> {
 	/// This function must return correct upper bound of dispatch weight. The return value
 	/// of this function is expected to match return value of the corresponding
 	/// `From<Chain>InboundLaneApi::message_details().dispatch_weight` call.
-	fn dispatch_weight(message: &mut DispatchMessage<Self::DispatchPayload, Fee>) -> Weight;
+	fn dispatch_weight(message: &mut DispatchMessage<Self::DispatchPayload>) -> Weight;
 
 	/// Called when inbound message is received.
 	///
@@ -107,7 +105,7 @@ pub trait MessageDispatch<AccountId, Fee> {
 	/// it must be paid inside this method to the `relayer_account`.
 	fn dispatch(
 		relayer_account: &AccountId,
-		message: DispatchMessage<Self::DispatchPayload, Fee>,
+		message: DispatchMessage<Self::DispatchPayload>,
 	) -> MessageDispatchResult;
 }
 
@@ -117,20 +115,15 @@ impl<Message> Default for ProvedLaneMessages<Message> {
 	}
 }
 
-impl<DispatchPayload: Decode, Fee> From<Message<Fee>> for DispatchMessage<DispatchPayload, Fee> {
-	fn from(message: Message<Fee>) -> Self {
-		DispatchMessage { key: message.key, data: message.data.into() }
+impl<DispatchPayload: Decode> From<Message> for DispatchMessage<DispatchPayload> {
+	fn from(message: Message) -> Self {
+		DispatchMessage { key: message.key, data: message.payload.into() }
 	}
 }
 
-impl<DispatchPayload: Decode, Fee> From<MessageData<Fee>>
-	for DispatchMessageData<DispatchPayload, Fee>
-{
-	fn from(data: MessageData<Fee>) -> Self {
-		DispatchMessageData {
-			payload: DispatchPayload::decode(&mut &data.payload[..]),
-			fee: data.fee,
-		}
+impl<DispatchPayload: Decode> From<MessagePayload> for DispatchMessageData<DispatchPayload> {
+	fn from(payload: MessagePayload) -> Self {
+		DispatchMessageData { payload: DispatchPayload::decode(&mut &payload[..]) }
 	}
 }
 
@@ -142,29 +135,26 @@ pub struct ForbidInboundMessages;
 const ALL_INBOUND_MESSAGES_REJECTED: &str =
 	"This chain is configured to reject all inbound messages";
 
-impl<Fee> SourceHeaderChain<Fee> for ForbidInboundMessages {
+impl SourceHeaderChain for ForbidInboundMessages {
 	type Error = &'static str;
 	type MessagesProof = ();
 
 	fn verify_messages_proof(
 		_proof: Self::MessagesProof,
 		_messages_count: u32,
-	) -> Result<ProvedMessages<Message<Fee>>, Self::Error> {
+	) -> Result<ProvedMessages<Message>, Self::Error> {
 		Err(ALL_INBOUND_MESSAGES_REJECTED)
 	}
 }
 
-impl<AccountId, Fee> MessageDispatch<AccountId, Fee> for ForbidInboundMessages {
+impl<AccountId> MessageDispatch<AccountId> for ForbidInboundMessages {
 	type DispatchPayload = ();
 
-	fn dispatch_weight(_message: &mut DispatchMessage<Self::DispatchPayload, Fee>) -> Weight {
+	fn dispatch_weight(_message: &mut DispatchMessage<Self::DispatchPayload>) -> Weight {
 		Weight::MAX
 	}
 
-	fn dispatch(
-		_: &AccountId,
-		_: DispatchMessage<Self::DispatchPayload, Fee>,
-	) -> MessageDispatchResult {
+	fn dispatch(_: &AccountId, _: DispatchMessage<Self::DispatchPayload>) -> MessageDispatchResult {
 		MessageDispatchResult {
 			dispatch_result: false,
 			unspent_weight: Weight::zero(),
diff --git a/bridges/primitives/polkadot-core/src/lib.rs b/bridges/primitives/polkadot-core/src/lib.rs
index 34eb4ae13b19a8ee53e18fea7ad9b7abf6534eea..878c3dc38ebcf1ea136ccb5186102cdf1dd6d8d1 100644
--- a/bridges/primitives/polkadot-core/src/lib.rs
+++ b/bridges/primitives/polkadot-core/src/lib.rs
@@ -126,49 +126,12 @@ pub const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 128;
 /// Maximal number of unconfirmed messages at inbound lane.
 pub const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 8192;
 
-// One important thing about weight-related constants here is that actually we may have
-// different weights on different Polkadot-like chains. But now all deployments are
-// almost the same, so we're exporting constants from this crate.
-
-/// Maximal weight of single message delivery confirmation transaction on Polkadot-like chain.
-///
-/// This value is a result of `pallet_bridge_messages::Pallet::receive_messages_delivery_proof`
-/// weight formula computation for the case when single message is confirmed. The result then must
-/// be rounded up to account possible future runtime upgrades.
-pub const MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT: Weight =
-	Weight::from_ref_time(2_000_000_000);
-
-/// Increase of delivery transaction weight on Polkadot-like chain with every additional message
-/// byte.
-///
-/// This value is a result of
-/// `pallet_bridge_messages::WeightInfoExt::storage_proof_size_overhead(1)` call. The result then
-/// must be rounded up to account possible future runtime upgrades.
-pub const ADDITIONAL_MESSAGE_BYTE_DELIVERY_WEIGHT: Weight = Weight::from_ref_time(25_000);
-
 /// Maximal number of bytes, included in the signed Polkadot-like transaction apart from the encoded
 /// call itself.
 ///
 /// Can be computed by subtracting encoded call size from raw transaction size.
 pub const TX_EXTRA_BYTES: u32 = 256;
 
-/// Weight of single regular message delivery transaction on Polkadot-like chain.
-///
-/// This value is a result of `pallet_bridge_messages::Pallet::receive_messages_proof_weight()` call
-/// for the case when single message of `pallet_bridge_messages::EXPECTED_DEFAULT_MESSAGE_LENGTH`
-/// bytes is delivered. The message must have dispatch weight set to zero. The result then must be
-/// rounded up to account possible future runtime upgrades.
-pub const DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT: Weight = Weight::from_ref_time(1_500_000_000);
-
-/// Weight of pay-dispatch-fee operation for inbound messages at Polkadot-like chain.
-///
-/// This value corresponds to the result of
-/// `pallet_bridge_messages::WeightInfoExt::pay_inbound_dispatch_fee_overhead()` call for your
-/// chain. Don't put too much reserve there, because it is used to **decrease**
-/// `DEFAULT_MESSAGE_DELIVERY_TX_WEIGHT` cost. So putting large reserve would make delivery
-/// transactions cheaper.
-pub const PAY_INBOUND_DISPATCH_FEE_WEIGHT: Weight = Weight::from_ref_time(600_000_000);
-
 /// Re-export `time_units` to make usage easier.
 pub use time_units::*;
 
diff --git a/bridges/primitives/runtime/src/chain.rs b/bridges/primitives/runtime/src/chain.rs
index 6f43c0f35490040b510595b47380057fb5aecd65..d4a8d5aa020b5efacd1343cdb3503e6f107d74e4 100644
--- a/bridges/primitives/runtime/src/chain.rs
+++ b/bridges/primitives/runtime/src/chain.rs
@@ -300,21 +300,7 @@ macro_rules! decl_bridge_messages_runtime_apis {
 					///
 					/// This API is implemented by runtimes that are receiving messages from this chain, not by this
 					/// chain's runtime itself.
-					pub trait [<To $chain:camel OutboundLaneApi>]<OutboundMessageFee: Parameter, OutboundPayload: Parameter> {
-						/// Estimate message delivery and dispatch fee that needs to be paid by the sender on
-						/// this chain.
-						///
-						/// Returns `None` if message is too expensive to be sent to this chain from the bridged chain.
-						///
-						/// Please keep in mind that this method returns the lowest message fee required for message
-						/// to be accepted to the lane. It may be a good idea to pay a bit over this price to account
-						/// for future exchange rate changes and guarantee that relayer would deliver your message
-						/// to the target chain.
-						fn estimate_message_delivery_and_dispatch_fee(
-							lane_id: LaneId,
-							payload: OutboundPayload,
-							[<$chain:lower _to_this_conversion_rate>]: Option<FixedU128>,
-						) -> Option<OutboundMessageFee>;
+					pub trait [<To $chain:camel OutboundLaneApi>] {
 						/// Returns dispatch weight, encoded payload size and delivery+dispatch fee of all
 						/// messages in given inclusive range.
 						///
@@ -324,7 +310,7 @@ macro_rules! decl_bridge_messages_runtime_apis {
 							lane: LaneId,
 							begin: MessageNonce,
 							end: MessageNonce,
-						) -> Vec<OutboundMessageDetails<OutboundMessageFee>>;
+						) -> Vec<OutboundMessageDetails>;
 					}
 
 					/// Inbound message lane API for messages sent by this chain.
@@ -334,11 +320,11 @@ macro_rules! decl_bridge_messages_runtime_apis {
 					///
 					/// Entries of the resulting vector are matching entries of the `messages` vector. Entries of the
 					/// `messages` vector may (and need to) be read using `To<ThisChain>OutboundLaneApi::message_details`.
-					pub trait [<From $chain:camel InboundLaneApi>]<InboundMessageFee: Parameter> {
+					pub trait [<From $chain:camel InboundLaneApi>] {
 						/// Return details of given inbound messages.
 						fn message_details(
 							lane: LaneId,
-							messages: Vec<(MessagePayload, OutboundMessageDetails<InboundMessageFee>)>,
+							messages: Vec<(MessagePayload, OutboundMessageDetails)>,
 						) -> Vec<InboundMessageDetails>;
 					}
 				}
@@ -346,7 +332,7 @@ macro_rules! decl_bridge_messages_runtime_apis {
 
 			pub use [<$chain _messages_api>]::*;
 		}
-	}
+	};
 }
 
 /// Convenience macro that declares bridge finality runtime apis, bridge messages runtime apis
diff --git a/bridges/primitives/runtime/src/messages.rs b/bridges/primitives/runtime/src/messages.rs
index 7a6687c18b776e311dccab8a929abedfd7310f8e..d77b1df7515c6a5fc14f9155435ba243dab63c8a 100644
--- a/bridges/primitives/runtime/src/messages.rs
+++ b/bridges/primitives/runtime/src/messages.rs
@@ -20,20 +20,6 @@ use codec::{Decode, Encode};
 use frame_support::{weights::Weight, RuntimeDebug};
 use scale_info::TypeInfo;
 
-/// Where message dispatch fee is paid?
-#[derive(Encode, Decode, RuntimeDebug, Clone, Copy, PartialEq, Eq, TypeInfo)]
-pub enum DispatchFeePayment {
-	/// The dispatch fee is paid at the source chain.
-	AtSourceChain,
-	/// The dispatch fee is paid at the target chain.
-	///
-	/// The fee will be paid right before the message is dispatched. So in case of any other
-	/// issues (like invalid call encoding, invalid signature, ...) the dispatch module won't
-	/// do any direct transfers. Instead, it'll return fee related to this message dispatch to the
-	/// relayer.
-	AtTargetChain,
-}
-
 /// Message dispatch result.
 #[derive(Encode, Decode, RuntimeDebug, Clone, PartialEq, Eq, TypeInfo)]
 pub struct MessageDispatchResult {
diff --git a/bridges/relays/bin-substrate/Cargo.toml b/bridges/relays/bin-substrate/Cargo.toml
index c214471eb6bdf5ac1325a96122e0cf0987385024..9ae6a98868e391d70c26dd7ad1d97e5057c0b511 100644
--- a/bridges/relays/bin-substrate/Cargo.toml
+++ b/bridges/relays/bin-substrate/Cargo.toml
@@ -30,7 +30,6 @@ 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-statemine = { path = "../../primitives/chain-statemine" }
 bp-westend = { path = "../../primitives/chain-westend" }
 bp-wococo = { path = "../../primitives/chain-wococo" }
 bridge-runtime-common = { path = "../../bin/runtime-common" }
@@ -45,7 +44,6 @@ relay-rialto-parachain-client = { path = "../client-rialto-parachain" }
 relay-bridge-hub-rococo-client = { path = "../client-bridge-hub-rococo" }
 relay-bridge-hub-wococo-client = { path = "../client-bridge-hub-wococo" }
 relay-rococo-client = { path = "../client-rococo" }
-relay-statemine-client = { path = "../client-statemine" }
 relay-substrate-client = { path = "../client-substrate" }
 relay-utils = { path = "../utils" }
 relay-westend-client = { path = "../client-westend" }
diff --git a/bridges/relays/bin-substrate/src/chains/bridge_hub_rococo_messages_to_bridge_hub_wococo.rs b/bridges/relays/bin-substrate/src/chains/bridge_hub_rococo_messages_to_bridge_hub_wococo.rs
index 915dd8296985232c15fdbe726dc05b1d26c7baea..78ef00f6d62485700dfadffd32412c1320b7e547 100644
--- a/bridges/relays/bin-substrate/src/chains/bridge_hub_rococo_messages_to_bridge_hub_wococo.rs
+++ b/bridges/relays/bin-substrate/src/chains/bridge_hub_rococo_messages_to_bridge_hub_wococo.rs
@@ -18,7 +18,6 @@
 
 use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge};
 use bp_messages::Weight;
-use messages_relay::relay_strategy::MixStrategy;
 use relay_bridge_hub_rococo_client::BridgeHubRococo;
 use relay_bridge_hub_wococo_client::BridgeHubWococo;
 use substrate_relay_helper::messages_lane::SubstrateMessageLane;
@@ -55,15 +54,6 @@ substrate_relay_helper::generate_mocked_receive_message_delivery_proof_call_buil
 pub struct BridgeHubRococoMessagesToBridgeHubWococoMessageLane;
 
 impl SubstrateMessageLane for BridgeHubRococoMessagesToBridgeHubWococoMessageLane {
-	const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = None;
-	const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = None;
-
-	const SOURCE_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = None;
-	const TARGET_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = None;
-
-	const AT_SOURCE_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = None;
-	const AT_TARGET_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = None;
-
 	type SourceChain = BridgeHubRococo;
 	type TargetChain = BridgeHubWococo;
 
@@ -71,8 +61,4 @@ impl SubstrateMessageLane for BridgeHubRococoMessagesToBridgeHubWococoMessageLan
 		BridgeHubRococoMessagesToBridgeHubWococoMessageLaneReceiveMessagesProofCallBuilder;
 	type ReceiveMessagesDeliveryProofCallBuilder =
 		BridgeHubRococoMessagesToBridgeHubWococoMessageLaneReceiveMessagesDeliveryProofCallBuilder;
-
-	type TargetToSourceChainConversionRateUpdateBuilder = ();
-
-	type RelayStrategy = MixStrategy;
 }
diff --git a/bridges/relays/bin-substrate/src/chains/bridge_hub_wococo_messages_to_bridge_hub_rococo.rs b/bridges/relays/bin-substrate/src/chains/bridge_hub_wococo_messages_to_bridge_hub_rococo.rs
index 179b9076ba72d05e865741fa99553442016b2614..51e1020e749533a9f5f6405fa9d53ec36d850bff 100644
--- a/bridges/relays/bin-substrate/src/chains/bridge_hub_wococo_messages_to_bridge_hub_rococo.rs
+++ b/bridges/relays/bin-substrate/src/chains/bridge_hub_wococo_messages_to_bridge_hub_rococo.rs
@@ -18,7 +18,6 @@
 
 use crate::cli::bridge::{CliBridgeBase, MessagesCliBridge};
 use bp_messages::Weight;
-use messages_relay::relay_strategy::MixStrategy;
 use relay_bridge_hub_rococo_client::BridgeHubRococo;
 use relay_bridge_hub_wococo_client::BridgeHubWococo;
 use substrate_relay_helper::messages_lane::SubstrateMessageLane;
@@ -55,15 +54,6 @@ substrate_relay_helper::generate_mocked_receive_message_delivery_proof_call_buil
 pub struct BridgeHubWococoMessagesToBridgeHubRococoMessageLane;
 
 impl SubstrateMessageLane for BridgeHubWococoMessagesToBridgeHubRococoMessageLane {
-	const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = None;
-	const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = None;
-
-	const SOURCE_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = None;
-	const TARGET_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = None;
-
-	const AT_SOURCE_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = None;
-	const AT_TARGET_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = None;
-
 	type SourceChain = BridgeHubWococo;
 	type TargetChain = BridgeHubRococo;
 
@@ -71,8 +61,4 @@ impl SubstrateMessageLane for BridgeHubWococoMessagesToBridgeHubRococoMessageLan
 		BridgeHubWococoMessagesToBridgeHubRococoMessageLaneReceiveMessagesProofCallBuilder;
 	type ReceiveMessagesDeliveryProofCallBuilder =
 		BridgeHubWococoMessagesToBridgeHubRococoMessageLaneReceiveMessagesDeliveryProofCallBuilder;
-
-	type TargetToSourceChainConversionRateUpdateBuilder = ();
-
-	type RelayStrategy = MixStrategy;
 }
diff --git a/bridges/relays/bin-substrate/src/chains/millau.rs b/bridges/relays/bin-substrate/src/chains/millau.rs
index 92fc43fbe36fe339e60510c41ec172dcb86f25ba..705755506f78c30901f045ed00784688cafbaa10 100644
--- a/bridges/relays/bin-substrate/src/chains/millau.rs
+++ b/bridges/relays/bin-substrate/src/chains/millau.rs
@@ -16,16 +16,10 @@
 
 //! Millau chain specification for CLI.
 
-use crate::cli::{
-	bridge,
-	encode_message::{CliEncodeMessage, RawMessage},
-	CliChain,
-};
-use bp_messages::LaneId;
+use crate::cli::{bridge, encode_message::CliEncodeMessage, CliChain};
 use bp_rialto_parachain::RIALTO_PARACHAIN_ID;
 use bp_runtime::EncodedOrDecodedCall;
 use relay_millau_client::Millau;
-use relay_substrate_client::BalanceOf;
 use sp_version::RuntimeVersion;
 use xcm::latest::prelude::*;
 
@@ -56,37 +50,6 @@ impl CliEncodeMessage for Millau {
 		})
 		.into())
 	}
-
-	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::RuntimeCall::BridgeRialtoMessages(
-				millau_runtime::MessagesCall::send_message {
-					lane_id: lane,
-					payload,
-					delivery_and_dispatch_fee: fee,
-				},
-			)
-			.into(),
-			bridge::MILLAU_TO_RIALTO_PARACHAIN_INDEX =>
-				millau_runtime::RuntimeCall::BridgeRialtoParachainMessages(
-					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
-			),
-		})
-	}
 }
 
 impl CliChain for Millau {
diff --git a/bridges/relays/bin-substrate/src/chains/millau_messages_to_rialto.rs b/bridges/relays/bin-substrate/src/chains/millau_messages_to_rialto.rs
index 332721e217f0d934a641b0a02b8403c5612bf3a6..b9920db53d85d4c853b26719fbbcd29523bb3e6a 100644
--- a/bridges/relays/bin-substrate/src/chains/millau_messages_to_rialto.rs
+++ b/bridges/relays/bin-substrate/src/chains/millau_messages_to_rialto.rs
@@ -16,7 +16,6 @@
 
 //! Millau-to-Rialto messages sync entrypoint.
 
-use messages_relay::relay_strategy::MixStrategy;
 use relay_millau_client::Millau;
 use relay_rialto_client::Rialto;
 use substrate_relay_helper::messages_lane::{
@@ -27,25 +26,8 @@ use substrate_relay_helper::messages_lane::{
 /// Description of Millau -> Rialto messages bridge.
 #[derive(Clone, Debug)]
 pub struct MillauMessagesToRialto;
-substrate_relay_helper::generate_direct_update_conversion_rate_call_builder!(
-	Millau,
-	MillauMessagesToRialtoUpdateConversionRateCallBuilder,
-	millau_runtime::Runtime,
-	millau_runtime::WithRialtoMessagesInstance,
-	millau_runtime::rialto_messages::MillauToRialtoMessagesParameter::RialtoToMillauConversionRate
-);
 
 impl SubstrateMessageLane for MillauMessagesToRialto {
-	const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> =
-		Some(bp_rialto::MILLAU_TO_RIALTO_CONVERSION_RATE_PARAMETER_NAME);
-	const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> =
-		Some(bp_millau::RIALTO_TO_MILLAU_CONVERSION_RATE_PARAMETER_NAME);
-
-	const SOURCE_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = None;
-	const TARGET_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = None;
-	const AT_SOURCE_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = None;
-	const AT_TARGET_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = None;
-
 	type SourceChain = Millau;
 	type TargetChain = Rialto;
 
@@ -59,9 +41,4 @@ impl SubstrateMessageLane for MillauMessagesToRialto {
 		millau_runtime::Runtime,
 		millau_runtime::WithRialtoMessagesInstance,
 	>;
-
-	type TargetToSourceChainConversionRateUpdateBuilder =
-		MillauMessagesToRialtoUpdateConversionRateCallBuilder;
-
-	type RelayStrategy = MixStrategy;
 }
diff --git a/bridges/relays/bin-substrate/src/chains/millau_messages_to_rialto_parachain.rs b/bridges/relays/bin-substrate/src/chains/millau_messages_to_rialto_parachain.rs
index 04b2b1e46e66a899c6f18dc6729ee51ea4312da4..70cb887fa35d4a22a99ab3a29b182907d1682547 100644
--- a/bridges/relays/bin-substrate/src/chains/millau_messages_to_rialto_parachain.rs
+++ b/bridges/relays/bin-substrate/src/chains/millau_messages_to_rialto_parachain.rs
@@ -16,7 +16,6 @@
 
 //! Millau-to-RialtoParachain messages sync entrypoint.
 
-use messages_relay::relay_strategy::MixStrategy;
 use relay_millau_client::Millau;
 use relay_rialto_parachain_client::RialtoParachain;
 use substrate_relay_helper::messages_lane::{
@@ -27,30 +26,8 @@ use substrate_relay_helper::messages_lane::{
 /// Description of Millau -> RialtoParachain messages bridge.
 #[derive(Clone, Debug)]
 pub struct MillauMessagesToRialtoParachain;
-substrate_relay_helper::generate_direct_update_conversion_rate_call_builder!(
-	Millau,
-	MillauMessagesToRialtoParachainUpdateConversionRateCallBuilder,
-	millau_runtime::Runtime,
-	millau_runtime::WithRialtoParachainMessagesInstance,
-	millau_runtime::rialto_parachain_messages::MillauToRialtoParachainMessagesParameter::RialtoParachainToMillauConversionRate
-);
 
 impl SubstrateMessageLane for MillauMessagesToRialtoParachain {
-	const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> =
-		Some(bp_rialto_parachain::MILLAU_TO_RIALTO_PARACHAIN_CONVERSION_RATE_PARAMETER_NAME);
-	const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> =
-		Some(bp_millau::RIALTO_PARACHAIN_TO_MILLAU_CONVERSION_RATE_PARAMETER_NAME);
-
-	const SOURCE_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> =
-		Some(bp_rialto_parachain::MILLAU_FEE_MULTIPLIER_PARAMETER_NAME);
-	const TARGET_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> =
-		Some(bp_millau::RIALTO_PARACHAIN_FEE_MULTIPLIER_PARAMETER_NAME);
-
-	const AT_SOURCE_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> =
-		Some(bp_millau::TRANSACTION_PAYMENT_PALLET_NAME);
-	const AT_TARGET_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> =
-		Some(bp_rialto_parachain::TRANSACTION_PAYMENT_PALLET_NAME);
-
 	type SourceChain = Millau;
 	type TargetChain = RialtoParachain;
 
@@ -64,9 +41,4 @@ impl SubstrateMessageLane for MillauMessagesToRialtoParachain {
 		millau_runtime::Runtime,
 		millau_runtime::WithRialtoParachainMessagesInstance,
 	>;
-
-	type TargetToSourceChainConversionRateUpdateBuilder =
-		MillauMessagesToRialtoParachainUpdateConversionRateCallBuilder;
-
-	type RelayStrategy = MixStrategy;
 }
diff --git a/bridges/relays/bin-substrate/src/chains/mod.rs b/bridges/relays/bin-substrate/src/chains/mod.rs
index 6bd444cc3959f06dccbb13aae37ea90579f72e3f..7caba7561ddc164644627b0b0913cb62f10f8e82 100644
--- a/bridges/relays/bin-substrate/src/chains/mod.rs
+++ b/bridges/relays/bin-substrate/src/chains/mod.rs
@@ -37,7 +37,6 @@ mod millau;
 mod rialto;
 mod rialto_parachain;
 mod rococo;
-mod statemine;
 mod westend;
 mod wococo;
 
diff --git a/bridges/relays/bin-substrate/src/chains/rialto.rs b/bridges/relays/bin-substrate/src/chains/rialto.rs
index 43ec9dbd224e4fb1958850c1acd45af09d708466..83bccf626b9edbdccfb9eddd5fb6d2c6bff65502 100644
--- a/bridges/relays/bin-substrate/src/chains/rialto.rs
+++ b/bridges/relays/bin-substrate/src/chains/rialto.rs
@@ -16,15 +16,9 @@
 
 //! Rialto chain specification for CLI.
 
-use crate::cli::{
-	bridge,
-	encode_message::{CliEncodeMessage, RawMessage},
-	CliChain,
-};
-use bp_messages::LaneId;
+use crate::cli::{bridge, encode_message::CliEncodeMessage, CliChain};
 use bp_runtime::EncodedOrDecodedCall;
 use relay_rialto_client::Rialto;
-use relay_substrate_client::BalanceOf;
 use sp_version::RuntimeVersion;
 use xcm::latest::prelude::*;
 
@@ -48,28 +42,6 @@ impl CliEncodeMessage for Rialto {
 		})
 		.into())
 	}
-
-	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::RuntimeCall::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
-			),
-		})
-	}
 }
 
 impl CliChain for Rialto {
diff --git a/bridges/relays/bin-substrate/src/chains/rialto_messages_to_millau.rs b/bridges/relays/bin-substrate/src/chains/rialto_messages_to_millau.rs
index e922659ab9a8b125f2ec297b1337158852d71084..80b6b9fdbc6b00cbff9afddb05e7533ac8156c52 100644
--- a/bridges/relays/bin-substrate/src/chains/rialto_messages_to_millau.rs
+++ b/bridges/relays/bin-substrate/src/chains/rialto_messages_to_millau.rs
@@ -16,7 +16,6 @@
 
 //! Rialto-to-Millau messages sync entrypoint.
 
-use messages_relay::relay_strategy::MixStrategy;
 use relay_millau_client::Millau;
 use relay_rialto_client::Rialto;
 use substrate_relay_helper::messages_lane::{
@@ -27,25 +26,8 @@ use substrate_relay_helper::messages_lane::{
 /// Description of Rialto -> Millau messages bridge.
 #[derive(Clone, Debug)]
 pub struct RialtoMessagesToMillau;
-substrate_relay_helper::generate_direct_update_conversion_rate_call_builder!(
-	Rialto,
-	RialtoMessagesToMillauUpdateConversionRateCallBuilder,
-	rialto_runtime::Runtime,
-	rialto_runtime::WithMillauMessagesInstance,
-	rialto_runtime::millau_messages::RialtoToMillauMessagesParameter::MillauToRialtoConversionRate
-);
 
 impl SubstrateMessageLane for RialtoMessagesToMillau {
-	const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> =
-		Some(bp_millau::RIALTO_TO_MILLAU_CONVERSION_RATE_PARAMETER_NAME);
-	const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> =
-		Some(bp_rialto::MILLAU_TO_RIALTO_CONVERSION_RATE_PARAMETER_NAME);
-
-	const SOURCE_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = None;
-	const TARGET_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> = None;
-	const AT_SOURCE_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = None;
-	const AT_TARGET_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> = None;
-
 	type SourceChain = Rialto;
 	type TargetChain = Millau;
 
@@ -59,9 +41,4 @@ impl SubstrateMessageLane for RialtoMessagesToMillau {
 		rialto_runtime::Runtime,
 		rialto_runtime::WithMillauMessagesInstance,
 	>;
-
-	type TargetToSourceChainConversionRateUpdateBuilder =
-		RialtoMessagesToMillauUpdateConversionRateCallBuilder;
-
-	type RelayStrategy = MixStrategy;
 }
diff --git a/bridges/relays/bin-substrate/src/chains/rialto_parachain.rs b/bridges/relays/bin-substrate/src/chains/rialto_parachain.rs
index 546cd04bdde152d3d5a31bf80fe699ade63a8f66..a480dc3eebbc6153711f98cf453009b605d95223 100644
--- a/bridges/relays/bin-substrate/src/chains/rialto_parachain.rs
+++ b/bridges/relays/bin-substrate/src/chains/rialto_parachain.rs
@@ -16,15 +16,9 @@
 
 //! Rialto parachain specification for CLI.
 
-use crate::cli::{
-	bridge,
-	encode_message::{CliEncodeMessage, RawMessage},
-	CliChain,
-};
-use bp_messages::LaneId;
+use crate::cli::{bridge, encode_message::CliEncodeMessage, CliChain};
 use bp_runtime::EncodedOrDecodedCall;
 use relay_rialto_parachain_client::RialtoParachain;
-use relay_substrate_client::BalanceOf;
 use sp_version::RuntimeVersion;
 use xcm::latest::prelude::*;
 
@@ -50,29 +44,6 @@ impl CliEncodeMessage for RialtoParachain {
 		)
 		.into())
 	}
-
-	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_PARACHAIN_TO_MILLAU_INDEX =>
-				rialto_parachain_runtime::RuntimeCall::BridgeMillauMessages(
-					rialto_parachain_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
-			),
-		})
-	}
 }
 
 impl CliChain for RialtoParachain {
diff --git a/bridges/relays/bin-substrate/src/chains/rialto_parachain_messages_to_millau.rs b/bridges/relays/bin-substrate/src/chains/rialto_parachain_messages_to_millau.rs
index ef13920cf8554badb434465599d05095ec32587f..5cca26105b87db01942a6ac9b48c3922ada4d43e 100644
--- a/bridges/relays/bin-substrate/src/chains/rialto_parachain_messages_to_millau.rs
+++ b/bridges/relays/bin-substrate/src/chains/rialto_parachain_messages_to_millau.rs
@@ -16,7 +16,6 @@
 
 //! RialtoParachain-to-Millau messages sync entrypoint.
 
-use messages_relay::relay_strategy::MixStrategy;
 use relay_millau_client::Millau;
 use relay_rialto_parachain_client::RialtoParachain;
 use substrate_relay_helper::messages_lane::{
@@ -27,30 +26,8 @@ use substrate_relay_helper::messages_lane::{
 /// Description of RialtoParachain -> Millau messages bridge.
 #[derive(Clone, Debug)]
 pub struct RialtoParachainMessagesToMillau;
-substrate_relay_helper::generate_direct_update_conversion_rate_call_builder!(
-	RialtoParachain,
-	RialtoParachainMessagesToMillauUpdateConversionRateCallBuilder,
-	rialto_parachain_runtime::Runtime,
-	rialto_parachain_runtime::WithMillauMessagesInstance,
-	rialto_parachain_runtime::millau_messages::RialtoParachainToMillauMessagesParameter::MillauToRialtoParachainConversionRate
-);
 
 impl SubstrateMessageLane for RialtoParachainMessagesToMillau {
-	const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> =
-		Some(bp_millau::RIALTO_PARACHAIN_TO_MILLAU_CONVERSION_RATE_PARAMETER_NAME);
-	const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> =
-		Some(bp_rialto_parachain::MILLAU_TO_RIALTO_PARACHAIN_CONVERSION_RATE_PARAMETER_NAME);
-
-	const SOURCE_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> =
-		Some(bp_millau::RIALTO_PARACHAIN_FEE_MULTIPLIER_PARAMETER_NAME);
-	const TARGET_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str> =
-		Some(bp_rialto_parachain::MILLAU_FEE_MULTIPLIER_PARAMETER_NAME);
-
-	const AT_SOURCE_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> =
-		Some(bp_rialto_parachain::TRANSACTION_PAYMENT_PALLET_NAME);
-	const AT_TARGET_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str> =
-		Some(bp_millau::TRANSACTION_PAYMENT_PALLET_NAME);
-
 	type SourceChain = RialtoParachain;
 	type TargetChain = Millau;
 
@@ -64,9 +41,4 @@ impl SubstrateMessageLane for RialtoParachainMessagesToMillau {
 		rialto_parachain_runtime::Runtime,
 		rialto_parachain_runtime::WithMillauMessagesInstance,
 	>;
-
-	type TargetToSourceChainConversionRateUpdateBuilder =
-		RialtoParachainMessagesToMillauUpdateConversionRateCallBuilder;
-
-	type RelayStrategy = MixStrategy;
 }
diff --git a/bridges/relays/bin-substrate/src/chains/statemine.rs b/bridges/relays/bin-substrate/src/chains/statemine.rs
deleted file mode 100644
index 0c0edd2f3e4841fb8c1a0aeb13fc6eb0b5007b5a..0000000000000000000000000000000000000000
--- a/bridges/relays/bin-substrate/src/chains/statemine.rs
+++ /dev/null
@@ -1,34 +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/>.
-
-//! Statemine chain specification for CLI.
-
-use crate::cli::CliChain;
-use relay_statemine_client::Statemine;
-use sp_version::RuntimeVersion;
-
-impl CliChain for Statemine {
-	const RUNTIME_VERSION: Option<RuntimeVersion> = Some(bp_statemine::VERSION);
-
-	type KeyPair = sp_core::sr25519::Pair;
-
-	fn ss58_format() -> u16 {
-		sp_core::crypto::Ss58AddressFormat::from(
-			sp_core::crypto::Ss58AddressFormatRegistry::KusamaAccount,
-		)
-		.into()
-	}
-}
diff --git a/bridges/relays/bin-substrate/src/cli/bridge.rs b/bridges/relays/bin-substrate/src/cli/bridge.rs
index 0bed036d91a9b87af5ba20dc5cdd5a085e809759..ae2a36cd1d553440f6e0d340a0889d9bdc56672d 100644
--- a/bridges/relays/bin-substrate/src/cli/bridge.rs
+++ b/bridges/relays/bin-substrate/src/cli/bridge.rs
@@ -15,7 +15,6 @@
 // along with Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
 
 use crate::cli::CliChain;
-use messages_relay::relay_strategy::MixStrategy;
 use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber};
 use parachains_relay::ParachainsPipeline;
 use relay_substrate_client::{AccountKeyPairOf, Chain, ChainWithTransactions, RelayChain};
@@ -46,7 +45,7 @@ impl FullBridge {
 			Self::MillauToRialtoParachain => MILLAU_TO_RIALTO_PARACHAIN_INDEX,
 			Self::RialtoParachainToMillau => RIALTO_PARACHAIN_TO_MILLAU_INDEX,
 			Self::BridgeHubRococoToBridgeHubWococo | Self::BridgeHubWococoToBridgeHubRococo =>
-				unimplemented!("TODO: (bridge_instance_index) do we need it or refactor or remove?"),
+				unimplemented!("Relay doesn't support send-message subcommand on bridge hubs"),
 		}
 	}
 }
@@ -102,9 +101,5 @@ pub trait MessagesCliBridge: CliBridgeBase {
 	/// defined bridge.
 	const ESTIMATE_MESSAGE_FEE_METHOD: &'static str;
 	/// The Source -> Destination messages synchronization pipeline.
-	type MessagesLane: SubstrateMessageLane<
-		SourceChain = Self::Source,
-		TargetChain = Self::Target,
-		RelayStrategy = MixStrategy,
-	>;
+	type MessagesLane: SubstrateMessageLane<SourceChain = Self::Source, TargetChain = Self::Target>;
 }
diff --git a/bridges/relays/bin-substrate/src/cli/encode_message.rs b/bridges/relays/bin-substrate/src/cli/encode_message.rs
index 9f9ef37ff0eaa0eef8eda7a12b8c073ec560b55b..c7ca5d51f799344e3afb27abc836c175a53a3646 100644
--- a/bridges/relays/bin-substrate/src/cli/encode_message.rs
+++ b/bridges/relays/bin-substrate/src/cli/encode_message.rs
@@ -15,8 +15,8 @@
 // along with Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
 
 use crate::cli::{ExplicitOrMaximal, HexBytes};
-use bp_messages::LaneId;
 use bp_runtime::EncodedOrDecodedCall;
+use codec::Encode;
 use relay_substrate_client::Chain;
 use structopt::StructOpt;
 
@@ -47,14 +47,6 @@ pub trait CliEncodeMessage: Chain {
 		message: xcm::VersionedXcm<()>,
 		bridge_instance_index: u8,
 	) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>>;
-
-	/// Encode a send message call of the bridge-messages pallet.
-	fn encode_send_message_call(
-		lane: LaneId,
-		message: RawMessage,
-		fee: Self::Balance,
-		bridge_instance_index: u8,
-	) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>>;
 }
 
 /// Encode message payload passed through CLI flags.
@@ -63,15 +55,36 @@ pub(crate) fn encode_message<Source: Chain, Target: Chain>(
 ) -> 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(
+		Message::Sized { ref size } => {
+			let expected_xcm_size = match *size {
+				ExplicitOrMaximal::Explicit(size) => size,
+				ExplicitOrMaximal::Maximal => compute_maximal_message_size(
 					Source::max_extrinsic_size(),
 					Target::max_extrinsic_size(),
+				),
+			};
+
+			// there's no way to craft XCM of the given size - we'll be using `ExpectPallet`
+			// instruction, which has byte vector inside
+			let mut current_vec_size = expected_xcm_size;
+			let xcm = loop {
+				let xcm = xcm::VersionedXcm::<()>::V3(
+					vec![xcm::v3::Instruction::ExpectPallet {
+						index: 0,
+						name: vec![42; current_vec_size as usize],
+						module_name: vec![],
+						crate_major: 0,
+						min_crate_minor: 0,
+					}]
+					.into(),
 				);
-				vec![42; maximal_size as usize]
-			},
+				if xcm.encode().len() <= expected_xcm_size as usize {
+					break xcm
+				}
+
+				current_vec_size -= 1;
+			};
+			xcm.encode()
 		},
 	})
 }
@@ -95,3 +108,38 @@ pub(crate) fn compute_maximal_message_size(
 		maximal_message_size
 	}
 }
+
+#[cfg(test)]
+mod tests {
+	use super::*;
+	use crate::cli::send_message::decode_xcm;
+	use bp_runtime::Chain;
+	use relay_millau_client::Millau;
+	use relay_rialto_client::Rialto;
+
+	#[test]
+	fn encode_explicit_size_message_works() {
+		let msg = encode_message::<Rialto, Millau>(&Message::Sized {
+			size: ExplicitOrMaximal::Explicit(100),
+		})
+		.unwrap();
+		assert_eq!(msg.len(), 100);
+		// check that it decodes to valid xcm
+		let _ = decode_xcm(msg).unwrap();
+	}
+
+	#[test]
+	fn encode_maximal_size_message_works() {
+		let maximal_size = compute_maximal_message_size(
+			Rialto::max_extrinsic_size(),
+			Millau::max_extrinsic_size(),
+		);
+
+		let msg =
+			encode_message::<Rialto, Millau>(&Message::Sized { size: ExplicitOrMaximal::Maximal })
+				.unwrap();
+		assert_eq!(msg.len(), maximal_size as usize);
+		// check that it decodes to valid xcm
+		let _ = decode_xcm(msg).unwrap();
+	}
+}
diff --git a/bridges/relays/bin-substrate/src/cli/estimate_fee.rs b/bridges/relays/bin-substrate/src/cli/estimate_fee.rs
deleted file mode 100644
index 00a175187778c573c61c7a92762f5d2fa88c2980..0000000000000000000000000000000000000000
--- a/bridges/relays/bin-substrate/src/cli/estimate_fee.rs
+++ /dev/null
@@ -1,292 +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::{
-	chains::{
-		millau_headers_to_rialto::MillauToRialtoCliBridge,
-		millau_headers_to_rialto_parachain::MillauToRialtoParachainCliBridge,
-		rialto_headers_to_millau::RialtoToMillauCliBridge,
-		rialto_parachains_to_millau::RialtoParachainToMillauCliBridge,
-	},
-	cli::{
-		bridge::{FullBridge, MessagesCliBridge},
-		chain_schema::*,
-		relay_headers_and_messages::CONVERSION_RATE_ALLOWED_DIFFERENCE_RATIO,
-		Balance, HexBytes, HexLaneId,
-	},
-};
-use async_trait::async_trait;
-use bp_runtime::BalanceOf;
-use codec::{Decode, Encode};
-use relay_substrate_client::{Chain, ChainBase};
-use sp_runtime::FixedU128;
-use std::fmt::Display;
-use structopt::StructOpt;
-use strum::VariantNames;
-use substrate_relay_helper::helpers::tokens_conversion_rate_from_metrics;
-
-/// Estimate Delivery & Dispatch Fee command.
-#[derive(StructOpt, Debug, PartialEq)]
-pub struct EstimateFee {
-	/// A bridge instance to encode call for.
-	#[structopt(possible_values = FullBridge::VARIANTS, case_insensitive = true)]
-	bridge: FullBridge,
-	#[structopt(flatten)]
-	source: SourceConnectionParams,
-	/// Hex-encoded id of lane that will be delivering the message.
-	#[structopt(long, default_value = "00000000")]
-	lane: HexLaneId,
-	/// A way to override conversion rate between bridge tokens.
-	///
-	/// If not specified, conversion rate from runtime storage is used. It may be obsolete and
-	/// your message won't be relayed.
-	#[structopt(long)]
-	conversion_rate_override: Option<ConversionRateOverride>,
-	/// Payload to send over the bridge.
-	#[structopt(flatten)]
-	payload: crate::cli::encode_message::Message,
-}
-
-/// A way to override conversion rate between bridge tokens.
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum ConversionRateOverride {
-	/// The actual conversion rate is computed in the same way how rate metric works.
-	Metric,
-	/// The actual conversion rate is specified explicitly.
-	Explicit(f64),
-}
-
-impl std::str::FromStr for ConversionRateOverride {
-	type Err = String;
-
-	fn from_str(s: &str) -> Result<Self, Self::Err> {
-		if s.to_lowercase() == "metric" {
-			return Ok(ConversionRateOverride::Metric)
-		}
-
-		f64::from_str(s)
-			.map(ConversionRateOverride::Explicit)
-			.map_err(|e| format!("Failed to parse '{e:?}'. Expected 'metric' or explicit value"))
-	}
-}
-
-#[async_trait]
-trait FeeEstimator: MessagesCliBridge
-where
-	<Self::Source as ChainBase>::Balance: Display + Into<u128>,
-{
-	async fn estimate_fee(data: EstimateFee) -> anyhow::Result<()> {
-		let source_client = data.source.into_client::<Self::Source>().await?;
-		let lane = data.lane.into();
-		let payload =
-			crate::cli::encode_message::encode_message::<Self::Source, Self::Target>(&data.payload)
-				.map_err(|e| anyhow::format_err!("{:?}", e))?;
-
-		let fee = estimate_message_delivery_and_dispatch_fee::<Self::Source, Self::Target, _>(
-			&source_client,
-			data.conversion_rate_override,
-			Self::ESTIMATE_MESSAGE_FEE_METHOD,
-			lane,
-			&payload,
-		)
-		.await?;
-
-		log::info!(target: "bridge", "Fee: {:?}", Balance(fee.into()));
-		println!("{fee}");
-		Ok(())
-	}
-}
-
-impl FeeEstimator for MillauToRialtoCliBridge {}
-impl FeeEstimator for RialtoToMillauCliBridge {}
-impl FeeEstimator for MillauToRialtoParachainCliBridge {}
-impl FeeEstimator for RialtoParachainToMillauCliBridge {}
-
-impl EstimateFee {
-	/// Run the command.
-	pub async fn run(self) -> anyhow::Result<()> {
-		match self.bridge {
-			FullBridge::MillauToRialto => MillauToRialtoCliBridge::estimate_fee(self),
-			FullBridge::RialtoToMillau => RialtoToMillauCliBridge::estimate_fee(self),
-			FullBridge::MillauToRialtoParachain =>
-				MillauToRialtoParachainCliBridge::estimate_fee(self),
-			FullBridge::RialtoParachainToMillau =>
-				RialtoParachainToMillauCliBridge::estimate_fee(self),
-			FullBridge::BridgeHubRococoToBridgeHubWococo |
-			FullBridge::BridgeHubWococoToBridgeHubRococo =>
-				unimplemented!("TODO: (EstimateFee) do we need it or refactor or remove?"),
-		}
-		.await
-	}
-}
-
-/// The caller may provide target to source tokens conversion rate override to use in fee
-/// computation.
-pub(crate) async fn estimate_message_delivery_and_dispatch_fee<
-	Source: Chain,
-	Target: Chain,
-	P: Clone + Encode,
->(
-	client: &relay_substrate_client::Client<Source>,
-	conversion_rate_override: Option<ConversionRateOverride>,
-	estimate_fee_method: &str,
-	lane: bp_messages::LaneId,
-	payload: &P,
-) -> anyhow::Result<BalanceOf<Source>> {
-	// actual conversion rate CAN be lesser than the rate stored in the runtime. So we may try to
-	// pay lesser fee for the message delivery. But in this case, message may be rejected by the
-	// lane. So we MUST use the larger of two fees - one computed with stored fee and the one
-	// computed with actual fee.
-
-	let conversion_rate_override =
-		match (conversion_rate_override, Source::TOKEN_ID, Target::TOKEN_ID) {
-			(Some(ConversionRateOverride::Explicit(v)), _, _) => {
-				let conversion_rate_override = FixedU128::from_float(v);
-				log::info!(
-					target: "bridge",
-					"{} -> {} conversion rate override: {:?} (explicit)",
-					Target::NAME,
-					Source::NAME,
-					conversion_rate_override.to_float(),
-				);
-				Some(conversion_rate_override)
-			},
-			(
-				Some(ConversionRateOverride::Metric),
-				Some(source_token_id),
-				Some(target_token_id),
-			) => {
-				let conversion_rate_override =
-					tokens_conversion_rate_from_metrics(target_token_id, source_token_id).await?;
-				// So we have current actual conversion rate and rate that is stored in the runtime.
-				// And we may simply choose the maximal of these. But what if right now there's
-				// rate update transaction on the way, that is updating rate to 10 seconds old
-				// actual rate, which is bigger than the current rate? Then our message will be
-				// rejected.
-				//
-				// So let's increase the actual rate by the same value that the conversion rate
-				// updater is using.
-				let increased_conversion_rate_override = FixedU128::from_float(
-					conversion_rate_override * (1.0 + CONVERSION_RATE_ALLOWED_DIFFERENCE_RATIO),
-				);
-				log::info!(
-					target: "bridge",
-					"{} -> {} conversion rate override: {} (value from metric - {})",
-					Target::NAME,
-					Source::NAME,
-					increased_conversion_rate_override.to_float(),
-					conversion_rate_override,
-				);
-				Some(increased_conversion_rate_override)
-			},
-			_ => None,
-		};
-
-	let without_override = do_estimate_message_delivery_and_dispatch_fee(
-		client,
-		estimate_fee_method,
-		lane,
-		payload,
-		None,
-	)
-	.await?;
-	let with_override = do_estimate_message_delivery_and_dispatch_fee(
-		client,
-		estimate_fee_method,
-		lane,
-		payload,
-		conversion_rate_override,
-	)
-	.await?;
-	let maximal_fee = std::cmp::max(without_override, with_override);
-
-	log::info!(
-		target: "bridge",
-		"Estimated message fee: {:?} = max of {:?} (without rate override) and {:?} (with override to {:?})",
-		maximal_fee,
-		without_override,
-		with_override,
-		conversion_rate_override,
-	);
-
-	Ok(maximal_fee)
-}
-
-/// Estimate message delivery and dispatch fee with given conversion rate override.
-async fn do_estimate_message_delivery_and_dispatch_fee<Source: Chain, P: Encode>(
-	client: &relay_substrate_client::Client<Source>,
-	estimate_fee_method: &str,
-	lane: bp_messages::LaneId,
-	payload: &P,
-	conversion_rate_override: Option<FixedU128>,
-) -> anyhow::Result<BalanceOf<Source>> {
-	let encoded_response = client
-		.state_call(
-			estimate_fee_method.into(),
-			(lane, payload, conversion_rate_override).encode().into(),
-			None,
-		)
-		.await?;
-	let decoded_response: Option<BalanceOf<Source>> = Decode::decode(&mut &encoded_response.0[..])
-		.map_err(relay_substrate_client::Error::ResponseParseFailed)?;
-	let fee = decoded_response.ok_or_else(|| {
-		anyhow::format_err!("Unable to decode fee from: {:?}", HexBytes(encoded_response.to_vec()))
-	})?;
-	Ok(fee)
-}
-
-#[cfg(test)]
-mod tests {
-	use super::*;
-
-	#[test]
-	fn should_parse_cli_options() {
-		// when
-		let res = EstimateFee::from_iter(vec![
-			"estimate_fee",
-			"rialto-to-millau",
-			"--source-port",
-			"1234",
-			"--conversion-rate-override",
-			"42.5",
-			"raw",
-			"1234",
-		]);
-
-		// then
-		assert_eq!(
-			res,
-			EstimateFee {
-				bridge: FullBridge::RialtoToMillau,
-				lane: HexLaneId([0, 0, 0, 0]),
-				conversion_rate_override: Some(ConversionRateOverride::Explicit(42.5)),
-				source: SourceConnectionParams {
-					source_host: "127.0.0.1".into(),
-					source_port: 1234,
-					source_secure: false,
-					source_runtime_version: SourceRuntimeVersionParams {
-						source_version_mode: RuntimeVersionType::Bundle,
-						source_spec_version: None,
-						source_transaction_version: None,
-					}
-				},
-				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 2f2f1f227b70bd9ea1e7b42bf108833e24a1bd15..2086008bc9566a955d865b48646a7764c9764cae 100644
--- a/bridges/relays/bin-substrate/src/cli/mod.rs
+++ b/bridges/relays/bin-substrate/src/cli/mod.rs
@@ -26,7 +26,6 @@ use bp_messages::LaneId;
 
 pub(crate) mod bridge;
 pub(crate) mod encode_message;
-pub(crate) mod estimate_fee;
 pub(crate) mod send_message;
 
 mod chain_schema;
@@ -74,8 +73,6 @@ pub enum Command {
 	/// The message is being sent to the source chain, delivered to the target chain and dispatched
 	/// there.
 	SendMessage(send_message::SendMessage),
-	/// Estimate Delivery and Dispatch Fee required for message submission to messages pallet.
-	EstimateFee(estimate_fee::EstimateFee),
 	/// Resubmit transactions with increased tip if they are stalled.
 	ResubmitTransactions(resubmit_transactions::ResubmitTransactions),
 	/// Register parachain.
@@ -111,7 +108,6 @@ impl Command {
 			Self::RelayHeadersAndMessages(arg) => arg.run().await?,
 			Self::InitBridge(arg) => arg.run().await?,
 			Self::SendMessage(arg) => arg.run().await?,
-			Self::EstimateFee(arg) => arg.run().await?,
 			Self::ResubmitTransactions(arg) => arg.run().await?,
 			Self::RegisterParachain(arg) => arg.run().await?,
 			Self::RelayParachains(arg) => arg.run().await?,
diff --git a/bridges/relays/bin-substrate/src/cli/relay_headers_and_messages/mod.rs b/bridges/relays/bin-substrate/src/cli/relay_headers_and_messages/mod.rs
index 1feba9d6284e536ade0e160ddfa5f7081d958837..49e9c5aa1560f8307562a4a56d3edbfadcfda82c 100644
--- a/bridges/relays/bin-substrate/src/cli/relay_headers_and_messages/mod.rs
+++ b/bridges/relays/bin-substrate/src/cli/relay_headers_and_messages/mod.rs
@@ -31,7 +31,6 @@ mod relay_to_parachain;
 use async_trait::async_trait;
 use std::{marker::PhantomData, sync::Arc};
 use structopt::StructOpt;
-use strum::VariantNames;
 
 use futures::{FutureExt, TryFutureExt};
 use relay_to_parachain::*;
@@ -50,40 +49,27 @@ use crate::{
 			RelayToRelayHeadersCliBridge,
 		},
 		chain_schema::*,
-		relay_messages::RelayerMode,
 		CliChain, HexLaneId, PrometheusParams,
 	},
 	declare_chain_cli_schema,
 };
 use bp_messages::LaneId;
 use bp_runtime::{BalanceOf, BlockNumberOf};
-use messages_relay::relay_strategy::MixStrategy;
 use relay_substrate_client::{
 	AccountIdOf, AccountKeyPairOf, Chain, ChainWithBalances, ChainWithTransactions, Client,
 };
 use relay_utils::metrics::MetricsParams;
 use sp_core::Pair;
 use substrate_relay_helper::{
-	messages_lane::MessagesRelayParams, messages_metrics::StandaloneMessagesMetrics,
-	on_demand::OnDemandRelay, TaggedAccount, TransactionParams,
+	messages_lane::MessagesRelayParams, on_demand::OnDemandRelay, TaggedAccount, TransactionParams,
 };
 
-/// Maximal allowed conversion rate error ratio (abs(real - stored) / stored) that we allow.
-///
-/// If it is zero, then transaction will be submitted every time we see difference between
-/// stored and real conversion rates. If it is large enough (e.g. > than 10 percents, which is 0.1),
-/// then rational relayers may stop relaying messages because they were submitted using
-/// lesser conversion rate.
-pub(crate) const CONVERSION_RATE_ALLOWED_DIFFERENCE_RATIO: f64 = 0.05;
-
 /// Parameters that have the same names across all bridges.
 #[derive(Debug, PartialEq, StructOpt)]
 pub struct HeadersAndMessagesSharedParams {
 	/// Hex-encoded lane identifiers that should be served by the complex relay.
 	#[structopt(long, default_value = "00000000")]
 	pub lane: Vec<HexLaneId>,
-	#[structopt(long, possible_values = RelayerMode::VARIANTS, case_insensitive = true, default_value = "rational")]
-	pub relayer_mode: RelayerMode,
 	/// If passed, only mandatory headers (headers that are changing the GRANDPA authorities set)
 	/// are relayed.
 	#[structopt(long)]
@@ -101,8 +87,6 @@ pub struct Full2WayBridgeCommonParams<
 	pub right: BridgeEndCommonParams<Right>,
 
 	pub metrics_params: MetricsParams,
-	pub left_to_right_metrics: StandaloneMessagesMetrics<Left, Right>,
-	pub right_to_left_metrics: StandaloneMessagesMetrics<Right, Left>,
 }
 
 impl<Left: ChainWithTransactions + CliChain, Right: ChainWithTransactions + CliChain>
@@ -116,19 +100,8 @@ impl<Left: ChainWithTransactions + CliChain, Right: ChainWithTransactions + CliC
 		// Create metrics registry.
 		let metrics_params = shared.prometheus_params.clone().into();
 		let metrics_params = relay_utils::relay_metrics(metrics_params).into_params();
-		let left_to_right_metrics = substrate_relay_helper::messages_metrics::standalone_metrics::<
-			L2R::MessagesLane,
-		>(left.client.clone(), right.client.clone())?;
-		let right_to_left_metrics = left_to_right_metrics.clone().reverse();
-
-		Ok(Self {
-			shared,
-			left,
-			right,
-			metrics_params,
-			left_to_right_metrics,
-			right_to_left_metrics,
-		})
+
+		Ok(Self { shared, left, right, metrics_params })
 	}
 }
 
@@ -146,11 +119,9 @@ struct FullBridge<
 	Target: ChainWithTransactions + CliChain,
 	Bridge: MessagesCliBridge<Source = Source, Target = Target>,
 > {
-	shared: &'a HeadersAndMessagesSharedParams,
 	source: &'a mut BridgeEndCommonParams<Source>,
 	target: &'a mut BridgeEndCommonParams<Target>,
 	metrics_params: &'a MetricsParams,
-	metrics: &'a StandaloneMessagesMetrics<Source, Target>,
 	_phantom_data: PhantomData<Bridge>,
 }
 
@@ -166,55 +137,11 @@ where
 	BalanceOf<Source>: TryFrom<BalanceOf<Target>> + Into<u128>,
 {
 	fn new(
-		shared: &'a HeadersAndMessagesSharedParams,
 		source: &'a mut BridgeEndCommonParams<Source>,
 		target: &'a mut BridgeEndCommonParams<Target>,
 		metrics_params: &'a MetricsParams,
-		metrics: &'a StandaloneMessagesMetrics<Source, Target>,
 	) -> Self {
-		Self { shared, source, target, metrics_params, metrics, _phantom_data: Default::default() }
-	}
-
-	fn start_conversion_rate_update_loop(&mut self) -> anyhow::Result<()> {
-		if let Some(ref messages_pallet_owner) = self.source.messages_pallet_owner {
-			let format_err = || {
-				anyhow::format_err!(
-					"Cannon run conversion rate updater: {} -> {}",
-					Target::NAME,
-					Source::NAME
-				)
-			};
-			substrate_relay_helper::conversion_rate_update::run_conversion_rate_update_loop::<
-				Bridge::MessagesLane,
-			>(
-				self.source.client.clone(),
-				TransactionParams {
-					signer: messages_pallet_owner.clone(),
-					mortality: self.source.transactions_mortality,
-				},
-				self.metrics
-					.target_to_source_conversion_rate
-					.as_ref()
-					.ok_or_else(format_err)?
-					.shared_value_ref(),
-				self.metrics
-					.target_to_base_conversion_rate
-					.as_ref()
-					.ok_or_else(format_err)?
-					.shared_value_ref(),
-				self.metrics
-					.source_to_base_conversion_rate
-					.as_ref()
-					.ok_or_else(format_err)?
-					.shared_value_ref(),
-				CONVERSION_RATE_ALLOWED_DIFFERENCE_RATIO,
-			);
-			self.source.accounts.push(TaggedAccount::MessagesPalletOwner {
-				id: messages_pallet_owner.public().into(),
-				bridged_chain: Target::NAME.to_string(),
-			});
-		}
-		Ok(())
+		Self { source, target, metrics_params, _phantom_data: Default::default() }
 	}
 
 	fn messages_relay_params(
@@ -223,9 +150,6 @@ where
 		target_to_source_headers_relay: Arc<dyn OnDemandRelay<BlockNumberOf<Target>>>,
 		lane_id: LaneId,
 	) -> MessagesRelayParams<Bridge::MessagesLane> {
-		let relayer_mode = self.shared.relayer_mode.into();
-		let relay_strategy = MixStrategy::new(relayer_mode);
-
 		MessagesRelayParams {
 			source_client: self.source.client.clone(),
 			source_transaction_params: TransactionParams {
@@ -241,8 +165,6 @@ where
 			target_to_source_headers_relay: Some(target_to_source_headers_relay),
 			lane_id,
 			metrics_params: self.metrics_params.clone().disable(),
-			standalone_metrics: Some(self.metrics.clone()),
-			relay_strategy,
 		}
 	}
 }
@@ -314,22 +236,18 @@ where
 	fn left_to_right(&mut self) -> FullBridge<Self::Left, Self::Right, Self::L2R> {
 		let common = self.mut_base().mut_common();
 		FullBridge::<_, _, Self::L2R>::new(
-			&common.shared,
 			&mut common.left,
 			&mut common.right,
 			&common.metrics_params,
-			&common.left_to_right_metrics,
 		)
 	}
 
 	fn right_to_left(&mut self) -> FullBridge<Self::Right, Self::Left, Self::R2L> {
 		let common = self.mut_base().mut_common();
 		FullBridge::<_, _, Self::R2L>::new(
-			&common.shared,
 			&mut common.right,
 			&mut common.left,
 			&common.metrics_params,
-			&common.right_to_left_metrics,
 		)
 	}
 
@@ -347,10 +265,6 @@ where
 			});
 		}
 
-		// start conversion rate update loops for left/right chains
-		self.left_to_right().start_conversion_rate_update_loop()?;
-		self.right_to_left().start_conversion_rate_update_loop()?;
-
 		// start on-demand header relays
 		let (left_to_right_on_demand_headers, right_to_left_on_demand_headers) =
 			self.mut_base().start_on_demand_headers_relayers().await?;
@@ -528,7 +442,6 @@ mod tests {
 						HexLaneId([0x00, 0x00, 0x00, 0x00]),
 						HexLaneId([0x73, 0x77, 0x61, 0x70])
 					],
-					relayer_mode: RelayerMode::Rational,
 					only_mandatory_headers: false,
 					prometheus_params: PrometheusParams {
 						no_prometheus: false,
@@ -641,7 +554,6 @@ mod tests {
 				MillauRialtoParachainHeadersAndMessages {
 					shared: HeadersAndMessagesSharedParams {
 						lane: vec![HexLaneId([0x00, 0x00, 0x00, 0x00])],
-						relayer_mode: RelayerMode::Rational,
 						only_mandatory_headers: false,
 						prometheus_params: PrometheusParams {
 							no_prometheus: false,
diff --git a/bridges/relays/bin-substrate/src/cli/relay_messages.rs b/bridges/relays/bin-substrate/src/cli/relay_messages.rs
index 23f9bf0c113f7da9e5d2ff5fe145bd4884e38b78..7f4dc34ac8bffcfa7aa06e2f8dc1bf5dbc54b175 100644
--- a/bridges/relays/bin-substrate/src/cli/relay_messages.rs
+++ b/bridges/relays/bin-substrate/src/cli/relay_messages.rs
@@ -17,7 +17,7 @@
 use async_trait::async_trait;
 use sp_core::Pair;
 use structopt::StructOpt;
-use strum::{EnumString, EnumVariantNames, VariantNames};
+use strum::VariantNames;
 
 use crate::chains::{
 	bridge_hub_rococo_messages_to_bridge_hub_wococo::BridgeHubRococoToBridgeHubWococoMessagesCliBridge,
@@ -27,32 +27,11 @@ use crate::chains::{
 	rialto_headers_to_millau::RialtoToMillauCliBridge,
 	rialto_parachains_to_millau::RialtoParachainToMillauCliBridge,
 };
-use messages_relay::relay_strategy::MixStrategy;
 use relay_substrate_client::{AccountIdOf, AccountKeyPairOf, BalanceOf, ChainWithTransactions};
 use substrate_relay_helper::{messages_lane::MessagesRelayParams, TransactionParams};
 
 use crate::cli::{bridge::*, chain_schema::*, CliChain, HexLaneId, PrometheusParams};
 
-/// Relayer operating mode.
-#[derive(Debug, EnumString, EnumVariantNames, Clone, Copy, PartialEq, Eq)]
-#[strum(serialize_all = "kebab_case")]
-pub enum RelayerMode {
-	/// The relayer doesn't care about rewards.
-	Altruistic,
-	/// The relayer will deliver all messages and confirmations as long as he's not losing any
-	/// funds.
-	Rational,
-}
-
-impl From<RelayerMode> for messages_relay::message_lane_loop::RelayerMode {
-	fn from(mode: RelayerMode) -> Self {
-		match mode {
-			RelayerMode::Altruistic => Self::Altruistic,
-			RelayerMode::Rational => Self::Rational,
-		}
-	}
-}
-
 /// Start messages relayer process.
 #[derive(StructOpt)]
 pub struct RelayMessages {
@@ -62,8 +41,6 @@ pub struct RelayMessages {
 	/// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`.
 	#[structopt(long, default_value = "00000000")]
 	lane: HexLaneId,
-	#[structopt(long, possible_values = RelayerMode::VARIANTS, case_insensitive = true, default_value = "rational")]
-	relayer_mode: RelayerMode,
 	#[structopt(flatten)]
 	source: SourceConnectionParams,
 	#[structopt(flatten)]
@@ -91,8 +68,6 @@ where
 		let target_client = data.target.into_client::<Self::Target>().await?;
 		let target_sign = data.target_sign.to_keypair::<Self::Target>()?;
 		let target_transactions_mortality = data.target_sign.transactions_mortality()?;
-		let relayer_mode = data.relayer_mode.into();
-		let relay_strategy = MixStrategy::new(relayer_mode);
 
 		substrate_relay_helper::messages_lane::run::<Self::MessagesLane>(MessagesRelayParams {
 			source_client,
@@ -109,8 +84,6 @@ where
 			target_to_source_headers_relay: None,
 			lane_id: data.lane.into(),
 			metrics_params: data.prometheus_params.into(),
-			standalone_metrics: None,
-			relay_strategy,
 		})
 		.await
 		.map_err(|e| anyhow::format_err!("{}", e))
@@ -142,43 +115,3 @@ impl RelayMessages {
 		.await
 	}
 }
-
-#[cfg(test)]
-mod tests {
-	use super::*;
-
-	#[test]
-	fn should_use_rational_relayer_mode_by_default() {
-		assert_eq!(
-			RelayMessages::from_iter(vec![
-				"relay-messages",
-				"rialto-to-millau",
-				"--source-port=0",
-				"--source-signer=//Alice",
-				"--target-port=0",
-				"--target-signer=//Alice",
-				"--lane=00000000",
-			])
-			.relayer_mode,
-			RelayerMode::Rational,
-		);
-	}
-
-	#[test]
-	fn should_accept_altruistic_relayer_mode() {
-		assert_eq!(
-			RelayMessages::from_iter(vec![
-				"relay-messages",
-				"rialto-to-millau",
-				"--source-port=0",
-				"--source-signer=//Alice",
-				"--target-port=0",
-				"--target-signer=//Alice",
-				"--lane=00000000",
-				"--relayer-mode=altruistic",
-			])
-			.relayer_mode,
-			RelayerMode::Altruistic,
-		);
-	}
-}
diff --git a/bridges/relays/bin-substrate/src/cli/send_message.rs b/bridges/relays/bin-substrate/src/cli/send_message.rs
index bb46762cee88010246c68cbd4868d657c03dcfec..d492d3422c7062e958519ffd83f9b54047504dd4 100644
--- a/bridges/relays/bin-substrate/src/cli/send_message.rs
+++ b/bridges/relays/bin-substrate/src/cli/send_message.rs
@@ -25,8 +25,7 @@ use crate::{
 		bridge::{FullBridge, MessagesCliBridge},
 		chain_schema::*,
 		encode_message::{self, CliEncodeMessage, RawMessage},
-		estimate_fee::{estimate_message_delivery_and_dispatch_fee, ConversionRateOverride},
-		Balance, CliChain, HexLaneId,
+		CliChain,
 	},
 };
 use async_trait::async_trait;
@@ -35,30 +34,11 @@ use relay_substrate_client::{
 	AccountIdOf, AccountKeyPairOf, Chain, ChainBase, ChainWithTransactions, SignParam,
 	UnsignedTransaction,
 };
-use sp_core::{Bytes, Pair};
+use sp_core::Pair;
 use sp_runtime::AccountId32;
-use std::fmt::{Debug, Display};
+use std::fmt::Display;
 use structopt::StructOpt;
-use strum::{EnumString, EnumVariantNames, VariantNames};
-
-/// Relayer operating mode.
-#[derive(Debug, EnumString, EnumVariantNames, Clone, Copy, PartialEq, Eq)]
-#[strum(serialize_all = "kebab_case")]
-pub enum DispatchFeePayment {
-	/// The dispatch fee is paid at the source chain.
-	AtSourceChain,
-	/// The dispatch fee is paid at the target chain.
-	AtTargetChain,
-}
-
-impl From<DispatchFeePayment> for bp_runtime::messages::DispatchFeePayment {
-	fn from(dispatch_fee_payment: DispatchFeePayment) -> Self {
-		match dispatch_fee_payment {
-			DispatchFeePayment::AtSourceChain => Self::AtSourceChain,
-			DispatchFeePayment::AtTargetChain => Self::AtTargetChain,
-		}
-	}
-}
+use strum::VariantNames;
 
 /// Send bridge message.
 #[derive(StructOpt)]
@@ -70,23 +50,6 @@ pub struct SendMessage {
 	source: SourceConnectionParams,
 	#[structopt(flatten)]
 	source_sign: SourceSigningParams,
-	/// Send message using XCM pallet instead. By default message is sent using
-	/// bridge messages pallet.
-	#[structopt(long)]
-	use_xcm_pallet: bool,
-	/// Hex-encoded lane id. Defaults to `00000000`.
-	#[structopt(long, default_value = "00000000")]
-	lane: HexLaneId,
-	/// A way to override conversion rate between bridge tokens.
-	///
-	/// If not specified, conversion rate from runtime storage is used. It may be obsolete and
-	/// your message won't be relayed.
-	#[structopt(long)]
-	conversion_rate_override: Option<ConversionRateOverride>,
-	/// 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_message::Message,
@@ -111,53 +74,14 @@ where
 		let source_client = data.source.into_client::<Self::Source>().await?;
 		let source_sign = data.source_sign.to_keypair::<Self::Source>()?;
 
-		let lane = data.lane.clone().into();
-		let conversion_rate_override = data.conversion_rate_override;
-		let fee = match data.fee {
-			Some(fee) => fee,
-			None => Balance(
-				estimate_message_delivery_and_dispatch_fee::<Self::Source, Self::Target, _>(
-					&source_client,
-					conversion_rate_override,
-					Self::ESTIMATE_MESSAGE_FEE_METHOD,
-					lane,
-					&payload,
-				)
-				.await?
-				.into(),
-			),
-		};
 		let payload_len = payload.encoded_size();
-		let send_message_call = if data.use_xcm_pallet {
-			Self::Source::encode_send_xcm(
-				decode_xcm(payload)?,
-				data.bridge.bridge_instance_index(),
-			)?
-		} else {
-			Self::Source::encode_send_message_call(
-				data.lane.0,
-				payload,
-				fee.cast().into(),
-				data.bridge.bridge_instance_index(),
-			)?
-		};
+		let send_message_call = Self::Source::encode_send_xcm(
+			decode_xcm(payload)?,
+			data.bridge.bridge_instance_index(),
+		)?;
 
 		let source_genesis_hash = *source_client.genesis_hash();
 		let (spec_version, transaction_version) = source_client.simple_runtime_version().await?;
-		let estimated_transaction_fee = source_client
-			.estimate_extrinsic_fee(Bytes(
-				Self::Source::sign_transaction(
-					SignParam {
-						spec_version,
-						transaction_version,
-						genesis_hash: source_genesis_hash,
-						signer: source_sign.clone(),
-					},
-					UnsignedTransaction::new(send_message_call.clone(), 0),
-				)?
-				.encode(),
-			))
-			.await?;
 		source_client
 			.submit_signed_extrinsic(
 				source_sign.public().into(),
@@ -171,22 +95,10 @@ where
 					let unsigned = UnsignedTransaction::new(send_message_call, transaction_nonce);
 					log::info!(
 						target: "bridge",
-						"Sending message to {}. Lane: {:?}. Size: {}. Fee: {}",
+						"Sending message to {}. Size: {}",
 						Self::Target::NAME,
-						lane,
 						payload_len,
-						fee,
-					);
-					log::info!(
-						target: "bridge",
-						"The source account ({:?}) balance will be reduced by (at most) {} (message fee)
-					+ {} (tx fee	) = {} {} tokens", 				AccountId32::from(source_sign.public()),
-						fee.0,
-						estimated_transaction_fee.inclusion_fee(),
-						fee.0.saturating_add(estimated_transaction_fee.inclusion_fee().into()),
-						Self::Source::NAME,
 					);
-
 					Ok(unsigned)
 				},
 			)
@@ -223,7 +135,7 @@ impl SendMessage {
 }
 
 /// Decode SCALE encoded raw XCM message.
-fn decode_xcm(message: RawMessage) -> anyhow::Result<xcm::VersionedXcm<()>> {
+pub(crate) fn decode_xcm(message: RawMessage) -> anyhow::Result<xcm::VersionedXcm<()>> {
 	Decode::decode(&mut &message[..])
 		.map_err(|e| anyhow::format_err!("Failed to decode XCM program: {:?}", e))
 }
@@ -243,8 +155,6 @@ mod tests {
 			"1234",
 			"--source-signer",
 			"//Alice",
-			"--conversion-rate-override",
-			"0.75",
 			"raw",
 			"dead",
 		]);
@@ -253,10 +163,6 @@ mod tests {
 		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::Explicit(0.75))
-		);
 		assert_eq!(
 			send_message.message,
 			crate::cli::encode_message::Message::Raw { data: HexBytes(vec![0xDE, 0xAD]) }
@@ -273,8 +179,6 @@ mod tests {
 			"1234",
 			"--source-signer",
 			"//Alice",
-			"--conversion-rate-override",
-			"metric",
 			"sized",
 			"max",
 		]);
@@ -283,7 +187,6 @@ mod tests {
 		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!(
 			send_message.message,
 			crate::cli::encode_message::Message::Sized { size: ExplicitOrMaximal::Maximal }
diff --git a/bridges/relays/client-bridge-hub-rococo/src/lib.rs b/bridges/relays/client-bridge-hub-rococo/src/lib.rs
index 375f11423a5246efc5f06d365616f8b0f78b5473..e4740490cb5d0ead4f54903e3e63424fc158de3b 100644
--- a/bridges/relays/client-bridge-hub-rococo/src/lib.rs
+++ b/bridges/relays/client-bridge-hub-rococo/src/lib.rs
@@ -60,7 +60,6 @@ impl Chain for BridgeHubRococo {
 	const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
 		bp_bridge_hub_rococo::BEST_FINALIZED_BRIDGE_HUB_ROCOCO_HEADER_METHOD;
 	const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
-	const STORAGE_PROOF_OVERHEAD: u32 = bp_bridge_hub_rococo::EXTRA_STORAGE_PROOF_SIZE;
 
 	type SignedBlock = bp_bridge_hub_rococo::SignedBlock;
 	type Call = runtime::Call;
@@ -126,8 +125,6 @@ impl ChainWithMessages for BridgeHubRococo {
 	const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str =
 		bp_bridge_hub_rococo::FROM_BRIDGE_HUB_ROCOCO_MESSAGE_DETAILS_METHOD;
 
-	const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight =
-		bp_bridge_hub_rococo::PAY_INBOUND_DISPATCH_FEE_WEIGHT;
 	const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce =
 		bp_bridge_hub_rococo::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX;
 	const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce =
diff --git a/bridges/relays/client-bridge-hub-wococo/src/lib.rs b/bridges/relays/client-bridge-hub-wococo/src/lib.rs
index f00aa6a9fa9106fc09a5d89bfcae4e307a47b06c..3199b3b4fc1c839f3ac119f34dd8001e11605fc6 100644
--- a/bridges/relays/client-bridge-hub-wococo/src/lib.rs
+++ b/bridges/relays/client-bridge-hub-wococo/src/lib.rs
@@ -60,7 +60,6 @@ impl Chain for BridgeHubWococo {
 	const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
 		bp_bridge_hub_wococo::BEST_FINALIZED_BRIDGE_HUB_WOCOCO_HEADER_METHOD;
 	const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
-	const STORAGE_PROOF_OVERHEAD: u32 = bp_bridge_hub_wococo::EXTRA_STORAGE_PROOF_SIZE;
 
 	type SignedBlock = bp_bridge_hub_wococo::SignedBlock;
 	type Call = runtime::Call;
@@ -126,8 +125,6 @@ impl ChainWithMessages for BridgeHubWococo {
 	const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str =
 		bp_bridge_hub_wococo::FROM_BRIDGE_HUB_WOCOCO_MESSAGE_DETAILS_METHOD;
 
-	const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight =
-		bp_bridge_hub_wococo::PAY_INBOUND_DISPATCH_FEE_WEIGHT;
 	const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce =
 		bp_bridge_hub_wococo::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX;
 	const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce =
diff --git a/bridges/relays/client-kusama/src/lib.rs b/bridges/relays/client-kusama/src/lib.rs
index cdf7213df9bbbc7d398d72a1f8c9dfafa85091e6..355f26b8496605c57a1e725746957aa4ffc50d8b 100644
--- a/bridges/relays/client-kusama/src/lib.rs
+++ b/bridges/relays/client-kusama/src/lib.rs
@@ -54,7 +54,6 @@ impl Chain for Kusama {
 	const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
 		bp_kusama::BEST_FINALIZED_KUSAMA_HEADER_METHOD;
 	const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
-	const STORAGE_PROOF_OVERHEAD: u32 = bp_kusama::EXTRA_STORAGE_PROOF_SIZE;
 
 	type SignedBlock = bp_kusama::SignedBlock;
 	type Call = ();
diff --git a/bridges/relays/client-millau/src/lib.rs b/bridges/relays/client-millau/src/lib.rs
index 77f09a89f153a8631eaf999358dbeb90ab199b1d..f8b350d3d0c2e15079756c0e4e5c9faa062b2e12 100644
--- a/bridges/relays/client-millau/src/lib.rs
+++ b/bridges/relays/client-millau/src/lib.rs
@@ -65,8 +65,6 @@ impl ChainWithMessages for Millau {
 		bp_millau::TO_MILLAU_MESSAGE_DETAILS_METHOD;
 	const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str =
 		bp_millau::FROM_MILLAU_MESSAGE_DETAILS_METHOD;
-	const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight =
-		bp_millau::PAY_INBOUND_DISPATCH_FEE_WEIGHT;
 	const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce =
 		bp_millau::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX;
 	const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce =
@@ -82,7 +80,6 @@ impl Chain for Millau {
 	const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
 		bp_millau::BEST_FINALIZED_MILLAU_HEADER_METHOD;
 	const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5);
-	const STORAGE_PROOF_OVERHEAD: u32 = bp_millau::EXTRA_STORAGE_PROOF_SIZE;
 
 	type SignedBlock = millau_runtime::SignedBlock;
 	type Call = millau_runtime::RuntimeCall;
diff --git a/bridges/relays/client-polkadot/src/lib.rs b/bridges/relays/client-polkadot/src/lib.rs
index bb3867fda5318287919ea72d63c8361141c03ed7..101b62b9c35eef75a780a15a4cddbba616fd52a4 100644
--- a/bridges/relays/client-polkadot/src/lib.rs
+++ b/bridges/relays/client-polkadot/src/lib.rs
@@ -54,7 +54,6 @@ impl Chain for Polkadot {
 	const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
 		bp_polkadot::BEST_FINALIZED_POLKADOT_HEADER_METHOD;
 	const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
-	const STORAGE_PROOF_OVERHEAD: u32 = bp_polkadot::EXTRA_STORAGE_PROOF_SIZE;
 
 	type SignedBlock = bp_polkadot::SignedBlock;
 	type Call = ();
diff --git a/bridges/relays/client-rialto-parachain/src/lib.rs b/bridges/relays/client-rialto-parachain/src/lib.rs
index fe7c2c816162f66e73cd972ec3cc7f2e32987a20..8cf74bdf9b1f53f89112f27a8adb9cdcba7ab688 100644
--- a/bridges/relays/client-rialto-parachain/src/lib.rs
+++ b/bridges/relays/client-rialto-parachain/src/lib.rs
@@ -62,7 +62,6 @@ impl Chain for RialtoParachain {
 	const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
 		bp_rialto_parachain::BEST_FINALIZED_RIALTO_PARACHAIN_HEADER_METHOD;
 	const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5);
-	const STORAGE_PROOF_OVERHEAD: u32 = bp_rialto_parachain::EXTRA_STORAGE_PROOF_SIZE;
 
 	type SignedBlock = rialto_parachain_runtime::SignedBlock;
 	type Call = rialto_parachain_runtime::RuntimeCall;
@@ -86,8 +85,6 @@ impl ChainWithMessages for RialtoParachain {
 		bp_rialto_parachain::TO_RIALTO_PARACHAIN_MESSAGE_DETAILS_METHOD;
 	const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str =
 		bp_rialto_parachain::FROM_RIALTO_PARACHAIN_MESSAGE_DETAILS_METHOD;
-	const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight =
-		bp_rialto_parachain::PAY_INBOUND_DISPATCH_FEE_WEIGHT;
 	const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce =
 		bp_rialto_parachain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX;
 	const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce =
@@ -157,7 +154,7 @@ impl ChainWithTransactions for RialtoParachain {
 	}
 
 	fn parse_transaction(_tx: Self::SignedTransaction) -> Option<UnsignedTransaction<Self>> {
-		unimplemented!("TODO")
+		None
 	}
 }
 
diff --git a/bridges/relays/client-rialto/src/lib.rs b/bridges/relays/client-rialto/src/lib.rs
index 45166559b365ad8f49514fbf1f73b4d9dc29eb92..23ecbbd47f6d3fa617ea1243140afe2b5339a4c1 100644
--- a/bridges/relays/client-rialto/src/lib.rs
+++ b/bridges/relays/client-rialto/src/lib.rs
@@ -62,7 +62,6 @@ impl Chain for Rialto {
 	const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
 		bp_rialto::BEST_FINALIZED_RIALTO_HEADER_METHOD;
 	const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5);
-	const STORAGE_PROOF_OVERHEAD: u32 = bp_rialto::EXTRA_STORAGE_PROOF_SIZE;
 
 	type SignedBlock = rialto_runtime::SignedBlock;
 	type Call = rialto_runtime::RuntimeCall;
@@ -85,8 +84,6 @@ impl ChainWithMessages for Rialto {
 		bp_rialto::TO_RIALTO_MESSAGE_DETAILS_METHOD;
 	const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str =
 		bp_rialto::FROM_RIALTO_MESSAGE_DETAILS_METHOD;
-	const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight =
-		bp_rialto::PAY_INBOUND_DISPATCH_FEE_WEIGHT;
 	const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce =
 		bp_rialto::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX;
 	const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce =
diff --git a/bridges/relays/client-rococo/src/lib.rs b/bridges/relays/client-rococo/src/lib.rs
index 5f1ff033559cd6f8c0cc2c1cade39fc5f8385d36..fc3aa76eb44917184d5c1c00fed5ac7e81eedf79 100644
--- a/bridges/relays/client-rococo/src/lib.rs
+++ b/bridges/relays/client-rococo/src/lib.rs
@@ -57,7 +57,6 @@ impl Chain for Rococo {
 	const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
 		bp_rococo::BEST_FINALIZED_ROCOCO_HEADER_METHOD;
 	const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
-	const STORAGE_PROOF_OVERHEAD: u32 = bp_rococo::EXTRA_STORAGE_PROOF_SIZE;
 
 	type SignedBlock = bp_rococo::SignedBlock;
 	type Call = ();
diff --git a/bridges/relays/client-statemine/Cargo.toml b/bridges/relays/client-statemine/Cargo.toml
deleted file mode 100644
index 249f9fd6f43055a7eadfc685df095b9e27a8d420..0000000000000000000000000000000000000000
--- a/bridges/relays/client-statemine/Cargo.toml
+++ /dev/null
@@ -1,24 +0,0 @@
-[package]
-name = "relay-statemine-client"
-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.1.5" }
-relay-substrate-client = { path = "../client-substrate" }
-relay-utils = { path = "../utils" }
-scale-info = { version = "2.1.1", features = ["derive"] }
-
-# Bridge dependencies
-
-bp-polkadot-core = { path = "../../primitives/polkadot-core" }
-bp-statemine = { path = "../../primitives/chain-statemine" }
-
-# Substrate Dependencies
-
-frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" }
-frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" }
-sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
-sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
diff --git a/bridges/relays/client-statemine/src/lib.rs b/bridges/relays/client-statemine/src/lib.rs
deleted file mode 100644
index a5f6fed79f434dc342452cfecbdfdd0865cc0c1e..0000000000000000000000000000000000000000
--- a/bridges/relays/client-statemine/src/lib.rs
+++ /dev/null
@@ -1,112 +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/>.
-
-//! Types used to connect to the Statemine chain.
-
-use codec::Encode;
-use frame_support::weights::Weight;
-use relay_substrate_client::{
-	Chain, ChainBase, ChainWithTransactions, Error as SubstrateError, SignParam,
-	UnsignedTransaction,
-};
-use sp_core::Pair;
-use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount};
-use std::time::Duration;
-
-pub mod runtime;
-
-/// Statemine chain definition
-#[derive(Debug, Clone, Copy)]
-pub struct Statemine;
-
-impl ChainBase for Statemine {
-	type BlockNumber = bp_statemine::BlockNumber;
-	type Hash = bp_statemine::Hash;
-	type Hasher = bp_statemine::Hasher;
-	type Header = bp_statemine::Header;
-
-	type AccountId = bp_statemine::AccountId;
-	type Balance = bp_statemine::Balance;
-	type Index = bp_statemine::Nonce;
-	type Signature = bp_statemine::Signature;
-
-	fn max_extrinsic_size() -> u32 {
-		bp_statemine::Statemine::max_extrinsic_size()
-	}
-
-	fn max_extrinsic_weight() -> Weight {
-		bp_statemine::Statemine::max_extrinsic_weight()
-	}
-}
-
-impl Chain for Statemine {
-	const NAME: &'static str = "Statemine";
-	const TOKEN_ID: Option<&'static str> = Some("kusama");
-	const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = "<unused>";
-	const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
-	const STORAGE_PROOF_OVERHEAD: u32 = bp_statemine::EXTRA_STORAGE_PROOF_SIZE;
-
-	type SignedBlock = bp_statemine::SignedBlock;
-	type Call = runtime::Call;
-}
-
-impl ChainWithTransactions for Statemine {
-	type AccountKeyPair = sp_core::sr25519::Pair;
-	type SignedTransaction = runtime::UncheckedExtrinsic;
-
-	fn sign_transaction(
-		param: SignParam<Self>,
-		unsigned: UnsignedTransaction<Self>,
-	) -> Result<Self::SignedTransaction, SubstrateError> {
-		let raw_payload = SignedPayload::new(
-			unsigned.call.clone(),
-			bp_statemine::SignedExtensions::new(
-				param.spec_version,
-				param.transaction_version,
-				unsigned.era,
-				param.genesis_hash,
-				unsigned.nonce,
-				unsigned.tip,
-			),
-		)
-		.expect("SignedExtension never fails.");
-		let signature = raw_payload.using_encoded(|payload| param.signer.sign(payload));
-		let signer: sp_runtime::MultiSigner = param.signer.public().into();
-		let (call, extra, _) = raw_payload.deconstruct();
-
-		Ok(runtime::UncheckedExtrinsic::new_signed(
-			call,
-			signer.into_account().into(),
-			signature.into(),
-			extra,
-		))
-	}
-
-	fn is_signed(tx: &Self::SignedTransaction) -> bool {
-		tx.signature.is_some()
-	}
-
-	fn is_signed_by(signer: &Self::AccountKeyPair, tx: &Self::SignedTransaction) -> bool {
-		tx.signature
-			.as_ref()
-			.map(|(address, _, _)| *address == bp_statemine::Address::Id(signer.public().into()))
-			.unwrap_or(false)
-	}
-
-	fn parse_transaction(_tx: Self::SignedTransaction) -> Option<UnsignedTransaction<Self>> {
-		unimplemented!("not used on Statemine")
-	}
-}
diff --git a/bridges/relays/client-statemine/src/runtime.rs b/bridges/relays/client-statemine/src/runtime.rs
deleted file mode 100644
index 92924555769e4ccad0bec10a5cf290e8a9b18721..0000000000000000000000000000000000000000
--- a/bridges/relays/client-statemine/src/runtime.rs
+++ /dev/null
@@ -1,68 +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/>.
-
-//! Types that are specific to the Statemine runtime.
-
-use codec::{Decode, Encode};
-use scale_info::TypeInfo;
-use sp_runtime::FixedU128;
-
-/// Unchecked Statemine extrinsic.
-pub type UncheckedExtrinsic = bp_polkadot_core::UncheckedExtrinsic<Call>;
-
-/// Statemine Runtime `Call` enum.
-///
-/// The enum represents a subset of possible `Call`s we can send to Statemine chain.
-/// Ideally this code would be auto-generated from metadata, because we want to
-/// avoid depending directly on the ENTIRE runtime just to get the encoding of `Dispatchable`s.
-///
-/// All entries here (like pretty much in the entire file) must be kept in sync with Statemine
-/// `construct_runtime`, so that we maintain SCALE-compatibility.
-///
-/// See: [link](https://github.com/paritytech/cumulus/blob/master/parachains/runtimes/assets/statemine/src/lib.rs)
-#[allow(clippy::large_enum_variant)]
-#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)]
-pub enum Call {
-	/// With-Statemint bridge pallet.
-	// TODO (https://github.com/paritytech/parity-bridges-common/issues/1626):
-	// must be updated when we'll make appropriate changes in the Statemine runtime
-	#[codec(index = 42)]
-	WithStatemintBridgePallet(WithStatemintBridgePalletCall),
-}
-
-/// Calls of the with-Statemint bridge pallet.
-// TODO (https://github.com/paritytech/parity-bridges-common/issues/1626):
-// must be updated when we'll make appropriate changes in the Statemine runtime
-#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)]
-#[allow(non_camel_case_types)]
-pub enum WithStatemintBridgePalletCall {
-	#[codec(index = 42)]
-	update_dot_to_ksm_conversion_rate(FixedU128),
-}
-
-impl sp_runtime::traits::Dispatchable for Call {
-	type RuntimeOrigin = ();
-	type Config = ();
-	type Info = ();
-	type PostInfo = ();
-
-	fn dispatch(
-		self,
-		_origin: Self::RuntimeOrigin,
-	) -> sp_runtime::DispatchResultWithInfo<Self::PostInfo> {
-		unimplemented!("The Call is not expected to be dispatched.")
-	}
-}
diff --git a/bridges/relays/client-substrate/src/chain.rs b/bridges/relays/client-substrate/src/chain.rs
index 5763d4a61357b202ec09440ee336361be293e86a..0e19cf92b778f78af3d80b4aaf7944342be5765e 100644
--- a/bridges/relays/client-substrate/src/chain.rs
+++ b/bridges/relays/client-substrate/src/chain.rs
@@ -19,7 +19,7 @@ use bp_runtime::{
 	Chain as ChainBase, EncodedOrDecodedCall, HashOf, TransactionEra, TransactionEraOf,
 };
 use codec::{Codec, Encode};
-use frame_support::weights::{Weight, WeightToFee};
+use frame_support::weights::WeightToFee;
 use jsonrpsee::core::{DeserializeOwned, Serialize};
 use num_traits::Zero;
 use sc_transaction_pool_api::TransactionStatus;
@@ -52,8 +52,6 @@ pub trait Chain: ChainBase + Clone {
 	/// How often blocks are produced on that chain. It's suggested to set this value
 	/// to match the block time of the chain.
 	const AVERAGE_BLOCK_INTERVAL: Duration;
-	/// Maximal expected storage proof overhead (in bytes).
-	const STORAGE_PROOF_OVERHEAD: u32;
 
 	/// Block type.
 	type SignedBlock: Member + Serialize + DeserializeOwned + BlockWithJustification<Self::Header>;
@@ -106,10 +104,6 @@ pub trait ChainWithMessages: Chain {
 	/// The method is provided by the runtime that is bridged with this `ChainWithMessages`.
 	const FROM_CHAIN_MESSAGE_DETAILS_METHOD: &'static str;
 
-	/// Additional weight of the dispatch fee payment if dispatch is paid at the target chain
-	/// and this `ChainWithMessages` is the target chain.
-	const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight;
-
 	/// Maximal number of unrewarded relayers in a single confirmation transaction at this
 	/// `ChainWithMessages`.
 	const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce;
diff --git a/bridges/relays/client-substrate/src/metrics/mod.rs b/bridges/relays/client-substrate/src/metrics/mod.rs
index 3b63099e0003662a98d7b1d6f5040a9bad826256..fe200e2d3dca7ea84a41e61f18912acc0d3f4332 100644
--- a/bridges/relays/client-substrate/src/metrics/mod.rs
+++ b/bridges/relays/client-substrate/src/metrics/mod.rs
@@ -17,7 +17,5 @@
 //! Contains several Substrate-specific metrics that may be exposed by relay.
 
 pub use float_storage_value::{FixedU128OrOne, FloatStorageValue, FloatStorageValueMetric};
-pub use storage_proof_overhead::StorageProofOverheadMetric;
 
 mod float_storage_value;
-mod storage_proof_overhead;
diff --git a/bridges/relays/client-substrate/src/metrics/storage_proof_overhead.rs b/bridges/relays/client-substrate/src/metrics/storage_proof_overhead.rs
deleted file mode 100644
index 6e0b74020b70bed92ce4fbec6c474a9f38656452..0000000000000000000000000000000000000000
--- a/bridges/relays/client-substrate/src/metrics/storage_proof_overhead.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::{chain::Chain, client::Client, error::Error};
-
-use async_trait::async_trait;
-use relay_utils::metrics::{
-	metric_name, register, Gauge, Metric, PrometheusError, Registry, StandaloneMetric, U64,
-};
-use sp_core::storage::StorageKey;
-use sp_runtime::traits::Header as HeaderT;
-use sp_storage::well_known_keys::CODE;
-use std::time::Duration;
-
-/// Storage proof overhead update interval (in blocks).
-const UPDATE_INTERVAL_IN_BLOCKS: u32 = 100;
-
-/// Metric that represents extra size of storage proof as unsigned integer gauge.
-///
-/// There's one thing to keep in mind when using this metric: the overhead may be slightly
-/// different for other values, but this metric gives a good estimation.
-#[derive(Debug)]
-pub struct StorageProofOverheadMetric<C: Chain> {
-	client: Client<C>,
-	metric: Gauge<U64>,
-}
-
-impl<C: Chain> Clone for StorageProofOverheadMetric<C> {
-	fn clone(&self) -> Self {
-		StorageProofOverheadMetric { client: self.client.clone(), metric: self.metric.clone() }
-	}
-}
-
-impl<C: Chain> StorageProofOverheadMetric<C> {
-	/// Create new metric instance with given name and help.
-	pub fn new(client: Client<C>, name: String, help: String) -> Result<Self, PrometheusError> {
-		Ok(StorageProofOverheadMetric {
-			client,
-			metric: Gauge::new(metric_name(None, &name), help)?,
-		})
-	}
-
-	/// Returns approximate storage proof size overhead.
-	async fn compute_storage_proof_overhead(&self) -> Result<usize, Error> {
-		let best_header_hash = self.client.best_finalized_header_hash().await?;
-		let best_header = self.client.header_by_hash(best_header_hash).await?;
-
-		let storage_proof = self
-			.client
-			.prove_storage(vec![StorageKey(CODE.to_vec())], best_header_hash)
-			.await?;
-		let storage_proof_size: usize = storage_proof.iter_nodes().map(|n| n.len()).sum();
-
-		let storage_value_reader = bp_runtime::StorageProofChecker::<C::Hasher>::new(
-			*best_header.state_root(),
-			storage_proof,
-		)
-		.map_err(Error::StorageProofError)?;
-		let maybe_encoded_storage_value =
-			storage_value_reader.read_value(CODE).map_err(Error::StorageProofError)?;
-		let encoded_storage_value_size =
-			maybe_encoded_storage_value.ok_or(Error::MissingMandatoryStorageValue)?.len();
-
-		Ok(storage_proof_size - encoded_storage_value_size)
-	}
-}
-
-impl<C: Chain> Metric for StorageProofOverheadMetric<C> {
-	fn register(&self, registry: &Registry) -> Result<(), PrometheusError> {
-		register(self.metric.clone(), registry).map(drop)
-	}
-}
-
-#[async_trait]
-impl<C: Chain> StandaloneMetric for StorageProofOverheadMetric<C> {
-	fn update_interval(&self) -> Duration {
-		C::AVERAGE_BLOCK_INTERVAL * UPDATE_INTERVAL_IN_BLOCKS
-	}
-
-	async fn update(&self) {
-		relay_utils::metrics::set_gauge_value(
-			&self.metric,
-			self.compute_storage_proof_overhead()
-				.await
-				.map(|overhead| Some(overhead as u64)),
-		);
-	}
-}
diff --git a/bridges/relays/client-substrate/src/test_chain.rs b/bridges/relays/client-substrate/src/test_chain.rs
index 8e1832db08453dbf300633cba6b95d5c67a0d4da..4589687d39de1dd2a14040a151b1e9b07887140e 100644
--- a/bridges/relays/client-substrate/src/test_chain.rs
+++ b/bridges/relays/client-substrate/src/test_chain.rs
@@ -54,7 +54,6 @@ impl Chain for TestChain {
 	const TOKEN_ID: Option<&'static str> = None;
 	const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = "TestMethod";
 	const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_millis(0);
-	const STORAGE_PROOF_OVERHEAD: u32 = 0;
 
 	type SignedBlock = sp_runtime::generic::SignedBlock<
 		sp_runtime::generic::Block<Self::Header, sp_runtime::OpaqueExtrinsic>,
diff --git a/bridges/relays/client-westend/src/lib.rs b/bridges/relays/client-westend/src/lib.rs
index 0f650e9e2847fe92a3f78f1f271efbe66edaf78f..6a2944629bed1793bd9bbc4a8b8f9ba35bc66ad9 100644
--- a/bridges/relays/client-westend/src/lib.rs
+++ b/bridges/relays/client-westend/src/lib.rs
@@ -57,7 +57,6 @@ impl Chain for Westend {
 	const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
 		bp_westend::BEST_FINALIZED_WESTEND_HEADER_METHOD;
 	const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
-	const STORAGE_PROOF_OVERHEAD: u32 = bp_westend::EXTRA_STORAGE_PROOF_SIZE;
 
 	type SignedBlock = bp_westend::SignedBlock;
 	type Call = ();
@@ -114,7 +113,6 @@ impl Chain for Westmint {
 	const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
 		bp_westend::BEST_FINALIZED_WESTMINT_HEADER_METHOD;
 	const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
-	const STORAGE_PROOF_OVERHEAD: u32 = bp_westend::EXTRA_STORAGE_PROOF_SIZE;
 
 	type SignedBlock = bp_westend::SignedBlock;
 	type Call = ();
diff --git a/bridges/relays/client-wococo/src/lib.rs b/bridges/relays/client-wococo/src/lib.rs
index b4e9dd74d1985a2061d6df7a7df72da025473408..04b5193afd33aa8e4568a71f2b22f9574d40dca1 100644
--- a/bridges/relays/client-wococo/src/lib.rs
+++ b/bridges/relays/client-wococo/src/lib.rs
@@ -57,7 +57,6 @@ impl Chain for Wococo {
 	const BEST_FINALIZED_HEADER_ID_METHOD: &'static str =
 		bp_wococo::BEST_FINALIZED_WOCOCO_HEADER_METHOD;
 	const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6);
-	const STORAGE_PROOF_OVERHEAD: u32 = bp_wococo::EXTRA_STORAGE_PROOF_SIZE;
 
 	type SignedBlock = bp_wococo::SignedBlock;
 	type Call = ();
diff --git a/bridges/relays/lib-substrate-relay/src/conversion_rate_update.rs b/bridges/relays/lib-substrate-relay/src/conversion_rate_update.rs
deleted file mode 100644
index 3bd9a5a6a1985096547417e30f687fc4bafe90f2..0000000000000000000000000000000000000000
--- a/bridges/relays/lib-substrate-relay/src/conversion_rate_update.rs
+++ /dev/null
@@ -1,439 +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/>.
-
-//! Tools for updating conversion rate that is stored in the runtime storage.
-
-use crate::{messages_lane::SubstrateMessageLane, TransactionParams};
-
-use relay_substrate_client::{
-	transaction_stall_timeout, AccountIdOf, AccountKeyPairOf, CallOf, Chain, ChainWithTransactions,
-	Client, SignParam, TransactionEra, UnsignedTransaction,
-};
-use relay_utils::metrics::F64SharedRef;
-use sp_core::Pair;
-use std::time::{Duration, Instant};
-
-/// Duration between updater iterations.
-const SLEEP_DURATION: Duration = Duration::from_secs(60);
-
-/// Duration which will almost never expire. Since changing conversion rate may require manual
-/// intervention (e.g. if call is made through `multisig` pallet), we don't want relayer to
-/// resubmit transaction often.
-const ALMOST_NEVER_DURATION: Duration = Duration::from_secs(60 * 60 * 24 * 30);
-
-/// Update-conversion-rate transaction status.
-#[derive(Debug, Clone, Copy, PartialEq)]
-enum TransactionStatus {
-	/// We have not submitted any transaction recently.
-	Idle,
-	/// We have recently submitted transaction that should update conversion rate.
-	Submitted(Instant, f64),
-}
-
-/// Different ways of building 'update conversion rate' calls.
-pub trait UpdateConversionRateCallBuilder<C: Chain> {
-	/// Given conversion rate, build call that updates conversion rate in given chain runtime
-	/// storage.
-	fn build_update_conversion_rate_call(conversion_rate: f64) -> anyhow::Result<CallOf<C>>;
-}
-
-impl<C: Chain> UpdateConversionRateCallBuilder<C> for () {
-	fn build_update_conversion_rate_call(_conversion_rate: f64) -> anyhow::Result<CallOf<C>> {
-		Err(anyhow::format_err!("Conversion rate update is not supported at {}", C::NAME))
-	}
-}
-
-/// Macro that generates `UpdateConversionRateCallBuilder` implementation for the case when
-/// you have a direct access to the source chain runtime.
-#[rustfmt::skip]
-#[macro_export]
-macro_rules! generate_direct_update_conversion_rate_call_builder {
-	(
-		$source_chain:ident,
-		$mocked_builder:ident,
-		$runtime:ty,
-		$instance:ty,
-		$parameter:path
-	) => {
-		pub struct $mocked_builder;
-
-		impl $crate::conversion_rate_update::UpdateConversionRateCallBuilder<$source_chain>
-			for $mocked_builder
-		{
-			fn build_update_conversion_rate_call(
-				conversion_rate: f64,
-			) -> anyhow::Result<relay_substrate_client::CallOf<$source_chain>> {
-				Ok(pallet_bridge_messages::Call::update_pallet_parameter::<$runtime, $instance> {
-					parameter: $parameter(sp_runtime::FixedU128::from_float(conversion_rate)),
-				}.into())
-			}
-		}
-	};
-}
-
-/// Macro that generates `UpdateConversionRateCallBuilder` implementation for the case when
-/// you only have an access to the mocked version of source chain runtime. In this case you
-/// should provide "name" of the call variant for the bridge messages calls, the "name" of
-/// the variant for the `update_pallet_parameter` call within that first option and the name
-/// of the conversion rate parameter itself.
-#[rustfmt::skip]
-#[macro_export]
-macro_rules! generate_mocked_update_conversion_rate_call_builder {
-	(
-		$source_chain:ident,
-		$mocked_builder:ident,
-		$bridge_messages:path,
-		$update_pallet_parameter:path,
-		$parameter:path
-	) => {
-		pub struct $mocked_builder;
-
-		impl $crate::conversion_rate_update::UpdateConversionRateCallBuilder<$source_chain>
-			for $mocked_builder
-		{
-			fn build_update_conversion_rate_call(
-				conversion_rate: f64,
-			) -> anyhow::Result<relay_substrate_client::CallOf<$source_chain>> {
-				Ok($bridge_messages($update_pallet_parameter($parameter(
-					sp_runtime::FixedU128::from_float(conversion_rate),
-				))))
-			}
-		}
-	};
-}
-
-/// Run infinite conversion rate updater loop.
-///
-/// The loop is maintaining the Left -> Right conversion rate, used as `RightTokens = LeftTokens *
-/// Rate`.
-pub fn run_conversion_rate_update_loop<Lane>(
-	client: Client<Lane::SourceChain>,
-	transaction_params: TransactionParams<AccountKeyPairOf<Lane::SourceChain>>,
-	left_to_right_stored_conversion_rate: F64SharedRef,
-	left_to_base_conversion_rate: F64SharedRef,
-	right_to_base_conversion_rate: F64SharedRef,
-	max_difference_ratio: f64,
-) where
-	Lane: SubstrateMessageLane,
-	Lane::SourceChain: ChainWithTransactions,
-	AccountIdOf<Lane::SourceChain>: From<<AccountKeyPairOf<Lane::SourceChain> as Pair>::Public>,
-{
-	let stall_timeout = transaction_stall_timeout(
-		transaction_params.mortality,
-		Lane::SourceChain::AVERAGE_BLOCK_INTERVAL,
-		ALMOST_NEVER_DURATION,
-	);
-
-	log::info!(
-		target: "bridge",
-		"Starting {} -> {} conversion rate  (on {}) update loop. Stall timeout: {}s",
-		Lane::TargetChain::NAME,
-		Lane::SourceChain::NAME,
-		Lane::SourceChain::NAME,
-		stall_timeout.as_secs(),
-	);
-
-	async_std::task::spawn(async move {
-		let mut transaction_status = TransactionStatus::Idle;
-		loop {
-			async_std::task::sleep(SLEEP_DURATION).await;
-			let maybe_new_conversion_rate = maybe_select_new_conversion_rate(
-				stall_timeout,
-				&mut transaction_status,
-				&left_to_right_stored_conversion_rate,
-				&left_to_base_conversion_rate,
-				&right_to_base_conversion_rate,
-				max_difference_ratio,
-			)
-			.await;
-			if let Some((prev_conversion_rate, new_conversion_rate)) = maybe_new_conversion_rate {
-				log::info!(
-					target: "bridge",
-					"Going to update {} -> {} (on {}) conversion rate to {}.",
-					Lane::TargetChain::NAME,
-					Lane::SourceChain::NAME,
-					Lane::SourceChain::NAME,
-					new_conversion_rate,
-				);
-
-				let result = update_target_to_source_conversion_rate::<Lane>(
-					client.clone(),
-					transaction_params.clone(),
-					new_conversion_rate,
-				)
-				.await;
-				match result {
-					Ok(()) => {
-						transaction_status =
-							TransactionStatus::Submitted(Instant::now(), prev_conversion_rate);
-					},
-					Err(error) => {
-						log::error!(
-							target: "bridge",
-							"Failed to submit conversion rate update transaction: {:?}",
-							error,
-						);
-					},
-				}
-			}
-		}
-	});
-}
-
-/// Select new conversion rate to submit to the node.
-async fn maybe_select_new_conversion_rate(
-	stall_timeout: Duration,
-	transaction_status: &mut TransactionStatus,
-	left_to_right_stored_conversion_rate: &F64SharedRef,
-	left_to_base_conversion_rate: &F64SharedRef,
-	right_to_base_conversion_rate: &F64SharedRef,
-	max_difference_ratio: f64,
-) -> Option<(f64, f64)> {
-	let left_to_right_stored_conversion_rate =
-		(*left_to_right_stored_conversion_rate.read().await)?;
-	match *transaction_status {
-		TransactionStatus::Idle => (),
-		TransactionStatus::Submitted(submitted_at, _)
-			if Instant::now() - submitted_at > stall_timeout =>
-		{
-			log::error!(
-				target: "bridge",
-				"Conversion rate update transaction has been lost and loop stalled. Restarting",
-			);
-
-			// we assume that our transaction has been lost
-			*transaction_status = TransactionStatus::Idle;
-		},
-		TransactionStatus::Submitted(_, previous_left_to_right_stored_conversion_rate) => {
-			// we can't compare float values from different sources directly, so we only care
-			// whether the stored rate has been changed or not. If it has been changed, then we
-			// assume that our proposal has been accepted.
-			//
-			// float comparison is ok here, because we compare same-origin (stored in runtime
-			// storage) values and if they are different, it means that the value has actually been
-			// updated
-			#[allow(clippy::float_cmp)]
-			if previous_left_to_right_stored_conversion_rate == left_to_right_stored_conversion_rate
-			{
-				// the rate has not been changed => we won't submit any transactions until it is
-				// accepted, or the rate is changed by someone else
-				return None
-			}
-
-			*transaction_status = TransactionStatus::Idle;
-		},
-	}
-
-	let left_to_base_conversion_rate = (*left_to_base_conversion_rate.read().await)?;
-	let right_to_base_conversion_rate = (*right_to_base_conversion_rate.read().await)?;
-	let actual_left_to_right_conversion_rate =
-		left_to_base_conversion_rate / right_to_base_conversion_rate;
-
-	let rate_difference =
-		(actual_left_to_right_conversion_rate - left_to_right_stored_conversion_rate).abs();
-	let rate_difference_ratio = rate_difference / left_to_right_stored_conversion_rate;
-	if rate_difference_ratio < max_difference_ratio {
-		return None
-	}
-
-	Some((left_to_right_stored_conversion_rate, actual_left_to_right_conversion_rate))
-}
-
-/// Update Target -> Source tokens conversion rate, stored in the Source runtime storage.
-pub async fn update_target_to_source_conversion_rate<Lane>(
-	client: Client<Lane::SourceChain>,
-	transaction_params: TransactionParams<AccountKeyPairOf<Lane::SourceChain>>,
-	updated_rate: f64,
-) -> anyhow::Result<()>
-where
-	Lane: SubstrateMessageLane,
-	Lane::SourceChain: ChainWithTransactions,
-	AccountIdOf<Lane::SourceChain>: From<<AccountKeyPairOf<Lane::SourceChain> as Pair>::Public>,
-{
-	let genesis_hash = *client.genesis_hash();
-	let signer_id = transaction_params.signer.public().into();
-	let (spec_version, transaction_version) = client.simple_runtime_version().await?;
-	let call =
-		Lane::TargetToSourceChainConversionRateUpdateBuilder::build_update_conversion_rate_call(
-			updated_rate,
-		)?;
-	client
-		.submit_signed_extrinsic(
-			signer_id,
-			SignParam::<Lane::SourceChain> {
-				spec_version,
-				transaction_version,
-				genesis_hash,
-				signer: transaction_params.signer,
-			},
-			move |best_block_id, transaction_nonce| {
-				Ok(UnsignedTransaction::new(call.into(), transaction_nonce)
-					.era(TransactionEra::new(best_block_id, transaction_params.mortality)))
-			},
-		)
-		.await
-		.map(drop)
-		.map_err(|err| anyhow::format_err!("{:?}", err))
-}
-
-#[cfg(test)]
-mod tests {
-	use super::*;
-	use async_std::sync::{Arc, RwLock};
-
-	const TEST_STALL_TIMEOUT: Duration = Duration::from_secs(60);
-
-	fn test_maybe_select_new_conversion_rate(
-		mut transaction_status: TransactionStatus,
-		stored_conversion_rate: Option<f64>,
-		left_to_base_conversion_rate: Option<f64>,
-		right_to_base_conversion_rate: Option<f64>,
-		max_difference_ratio: f64,
-	) -> (Option<(f64, f64)>, TransactionStatus) {
-		let stored_conversion_rate = Arc::new(RwLock::new(stored_conversion_rate));
-		let left_to_base_conversion_rate = Arc::new(RwLock::new(left_to_base_conversion_rate));
-		let right_to_base_conversion_rate = Arc::new(RwLock::new(right_to_base_conversion_rate));
-		let result = async_std::task::block_on(maybe_select_new_conversion_rate(
-			TEST_STALL_TIMEOUT,
-			&mut transaction_status,
-			&stored_conversion_rate,
-			&left_to_base_conversion_rate,
-			&right_to_base_conversion_rate,
-			max_difference_ratio,
-		));
-		(result, transaction_status)
-	}
-
-	#[test]
-	fn rate_is_not_updated_when_transaction_is_submitted() {
-		let status = TransactionStatus::Submitted(Instant::now(), 10.0);
-		assert_eq!(
-			test_maybe_select_new_conversion_rate(status, Some(10.0), Some(1.0), Some(1.0), 0.0),
-			(None, status),
-		);
-	}
-
-	#[test]
-	fn transaction_state_is_changed_to_idle_when_stored_rate_shanges() {
-		assert_eq!(
-			test_maybe_select_new_conversion_rate(
-				TransactionStatus::Submitted(Instant::now(), 1.0),
-				Some(10.0),
-				Some(1.0),
-				Some(1.0),
-				100.0
-			),
-			(None, TransactionStatus::Idle),
-		);
-	}
-
-	#[test]
-	fn transaction_is_not_submitted_when_left_to_base_rate_is_unknown() {
-		assert_eq!(
-			test_maybe_select_new_conversion_rate(
-				TransactionStatus::Idle,
-				Some(10.0),
-				None,
-				Some(1.0),
-				0.0
-			),
-			(None, TransactionStatus::Idle),
-		);
-	}
-
-	#[test]
-	fn transaction_is_not_submitted_when_right_to_base_rate_is_unknown() {
-		assert_eq!(
-			test_maybe_select_new_conversion_rate(
-				TransactionStatus::Idle,
-				Some(10.0),
-				Some(1.0),
-				None,
-				0.0
-			),
-			(None, TransactionStatus::Idle),
-		);
-	}
-
-	#[test]
-	fn transaction_is_not_submitted_when_stored_rate_is_unknown() {
-		assert_eq!(
-			test_maybe_select_new_conversion_rate(
-				TransactionStatus::Idle,
-				None,
-				Some(1.0),
-				Some(1.0),
-				0.0
-			),
-			(None, TransactionStatus::Idle),
-		);
-	}
-
-	#[test]
-	fn transaction_is_not_submitted_when_difference_is_below_threshold() {
-		assert_eq!(
-			test_maybe_select_new_conversion_rate(
-				TransactionStatus::Idle,
-				Some(1.0),
-				Some(1.0),
-				Some(1.01),
-				0.02
-			),
-			(None, TransactionStatus::Idle),
-		);
-	}
-
-	#[test]
-	fn transaction_is_submitted_when_difference_is_above_threshold() {
-		let left_to_right_stored_conversion_rate = 1.0;
-		let left_to_base_conversion_rate = 18f64;
-		let right_to_base_conversion_rate = 180f64;
-
-		assert!(left_to_base_conversion_rate < right_to_base_conversion_rate);
-
-		assert_eq!(
-			test_maybe_select_new_conversion_rate(
-				TransactionStatus::Idle,
-				Some(left_to_right_stored_conversion_rate),
-				Some(left_to_base_conversion_rate),
-				Some(right_to_base_conversion_rate),
-				0.02
-			),
-			(
-				Some((
-					left_to_right_stored_conversion_rate,
-					left_to_base_conversion_rate / right_to_base_conversion_rate,
-				)),
-				TransactionStatus::Idle
-			),
-		);
-	}
-
-	#[test]
-	fn transaction_expires() {
-		let status = TransactionStatus::Submitted(Instant::now() - TEST_STALL_TIMEOUT / 2, 10.0);
-		assert_eq!(
-			test_maybe_select_new_conversion_rate(status, Some(10.0), Some(1.0), Some(1.0), 0.0),
-			(None, status),
-		);
-
-		let status = TransactionStatus::Submitted(Instant::now() - TEST_STALL_TIMEOUT * 2, 10.0);
-		assert_eq!(
-			test_maybe_select_new_conversion_rate(status, Some(10.0), Some(1.0), Some(1.0), 0.0),
-			(Some((10.0, 1.0)), TransactionStatus::Idle),
-		);
-	}
-}
diff --git a/bridges/relays/lib-substrate-relay/src/helpers.rs b/bridges/relays/lib-substrate-relay/src/helpers.rs
deleted file mode 100644
index 0b824708a89964a00c4bf140141d936b685c44ee..0000000000000000000000000000000000000000
--- a/bridges/relays/lib-substrate-relay/src/helpers.rs
+++ /dev/null
@@ -1,106 +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/>.
-
-//! Substrate relay helpers
-
-use relay_utils::metrics::{FloatJsonValueMetric, PrometheusError, StandaloneMetric};
-
-/// Creates standalone token price metric.
-pub fn token_price_metric(token_id: &str) -> Result<FloatJsonValueMetric, PrometheusError> {
-	FloatJsonValueMetric::new(
-		format!("https://api.coingecko.com/api/v3/simple/price?ids={token_id}&vs_currencies=btc"),
-		format!("$.{token_id}.btc"),
-		format!("{}_to_base_conversion_rate", token_id.replace('-', "_")),
-		format!("Rate used to convert from {} to some BASE tokens", token_id.to_uppercase()),
-	)
-}
-
-/// Compute conversion rate between two tokens immediately, without spawning any metrics.
-///
-/// Returned rate may be used in expression: `from_tokens * rate -> to_tokens`.
-pub async fn tokens_conversion_rate_from_metrics(
-	from_token_id: &str,
-	to_token_id: &str,
-) -> anyhow::Result<f64> {
-	let from_token_metric = token_price_metric(from_token_id)?;
-	from_token_metric.update().await;
-	let to_token_metric = token_price_metric(to_token_id)?;
-	to_token_metric.update().await;
-
-	let from_token_value = *from_token_metric.shared_value_ref().read().await;
-	let to_token_value = *to_token_metric.shared_value_ref().read().await;
-	// `FloatJsonValueMetric` guarantees that the value is positive && normal, so no additional
-	// checks required here
-	match (from_token_value, to_token_value) {
-		(Some(from_token_value), Some(to_token_value)) =>
-			Ok(tokens_conversion_rate(from_token_value, to_token_value)),
-		_ => Err(anyhow::format_err!(
-			"Failed to compute conversion rate from {} to {}",
-			from_token_id,
-			to_token_id,
-		)),
-	}
-}
-
-/// Compute conversion rate between two tokens, given token prices.
-///
-/// Returned rate may be used in expression: `from_tokens * rate -> to_tokens`.
-///
-/// Both prices are assumed to be normal and non-negative.
-pub fn tokens_conversion_rate(from_token_value: f64, to_token_value: f64) -> f64 {
-	from_token_value / to_token_value
-}
-
-#[cfg(test)]
-mod tests {
-	use super::*;
-
-	#[test]
-	fn rialto_to_millau_conversion_rate_is_correct() {
-		let rialto_price = 18.18;
-		let millau_price = 136.35;
-		assert!(rialto_price < millau_price);
-
-		let conversion_rate = tokens_conversion_rate(rialto_price, millau_price);
-		let rialto_amount = 100.0;
-		let millau_amount = rialto_amount * conversion_rate;
-		assert!(
-			rialto_amount > millau_amount,
-			"{} RLT * {} = {} MLU",
-			rialto_amount,
-			conversion_rate,
-			millau_amount,
-		);
-	}
-
-	#[test]
-	fn millau_to_rialto_conversion_rate_is_correct() {
-		let rialto_price = 18.18;
-		let millau_price = 136.35;
-		assert!(rialto_price < millau_price);
-
-		let conversion_rate = tokens_conversion_rate(millau_price, rialto_price);
-		let millau_amount = 100.0;
-		let rialto_amount = millau_amount * conversion_rate;
-		assert!(
-			rialto_amount > millau_amount,
-			"{} MLU * {} = {} RLT",
-			millau_amount,
-			conversion_rate,
-			rialto_amount,
-		);
-	}
-}
diff --git a/bridges/relays/lib-substrate-relay/src/lib.rs b/bridges/relays/lib-substrate-relay/src/lib.rs
index 86e652716f64398a5383b360a18bbea2b3a83785..62ae756e0031e2582dd596d9d1ad84ae6f26bfe4 100644
--- a/bridges/relays/lib-substrate-relay/src/lib.rs
+++ b/bridges/relays/lib-substrate-relay/src/lib.rs
@@ -18,10 +18,8 @@
 
 #![warn(missing_docs)]
 
-pub mod conversion_rate_update;
 pub mod error;
 pub mod finality;
-pub mod helpers;
 pub mod messages_lane;
 pub mod messages_metrics;
 pub mod messages_source;
diff --git a/bridges/relays/lib-substrate-relay/src/messages_lane.rs b/bridges/relays/lib-substrate-relay/src/messages_lane.rs
index 09d02f7448e4decffe2b76f751aab0c92a3780b5..da138a3d1258f9a6b0b75baa59beda57014c9f78 100644
--- a/bridges/relays/lib-substrate-relay/src/messages_lane.rs
+++ b/bridges/relays/lib-substrate-relay/src/messages_lane.rs
@@ -17,8 +17,6 @@
 //! Tools for supporting message lanes between two Substrate-based chains.
 
 use crate::{
-	conversion_rate_update::UpdateConversionRateCallBuilder,
-	messages_metrics::StandaloneMessagesMetrics,
 	messages_source::{SubstrateMessagesProof, SubstrateMessagesSource},
 	messages_target::{SubstrateMessagesDeliveryProof, SubstrateMessagesTarget},
 	on_demand::OnDemandRelay,
@@ -33,49 +31,21 @@ use bridge_runtime_common::messages::{
 };
 use codec::Encode;
 use frame_support::{dispatch::GetDispatchInfo, weights::Weight};
-use messages_relay::{message_lane::MessageLane, relay_strategy::RelayStrategy};
+use messages_relay::message_lane::MessageLane;
 use pallet_bridge_messages::{Call as BridgeMessagesCall, Config as BridgeMessagesConfig};
 use relay_substrate_client::{
 	transaction_stall_timeout, AccountKeyPairOf, BalanceOf, BlockNumberOf, CallOf, Chain,
 	ChainWithMessages, ChainWithTransactions, Client, HashOf,
 };
-use relay_utils::{metrics::MetricsParams, STALL_TIMEOUT};
+use relay_utils::{
+	metrics::{GlobalMetrics, MetricsParams, StandaloneMetric},
+	STALL_TIMEOUT,
+};
 use sp_core::Pair;
 use std::{convert::TryFrom, fmt::Debug, marker::PhantomData};
 
 /// Substrate -> Substrate messages synchronization pipeline.
 pub trait SubstrateMessageLane: 'static + Clone + Debug + Send + Sync {
-	/// Name of the source -> target tokens conversion rate parameter.
-	///
-	/// The parameter is stored at the target chain and the storage key is computed using
-	/// `bp_runtime::storage_parameter_key` function. If value is unknown, it is assumed
-	/// to be 1.
-	const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str>;
-	/// Name of the target -> source tokens conversion rate parameter.
-	///
-	/// The parameter is stored at the source chain and the storage key is computed using
-	/// `bp_runtime::storage_parameter_key` function. If value is unknown, it is assumed
-	/// to be 1.
-	const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str>;
-
-	/// Name of the source chain fee multiplier parameter.
-	///
-	/// The parameter is stored at the target chain and the storage key is computed using
-	/// `bp_runtime::storage_parameter_key` function. If value is unknown, it is assumed
-	/// to be 1.
-	const SOURCE_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str>;
-	/// Name of the target chain fee multiplier parameter.
-	///
-	/// The parameter is stored at the source chain and the storage key is computed using
-	/// `bp_runtime::storage_parameter_key` function. If value is unknown, it is assumed
-	/// to be 1.
-	const TARGET_FEE_MULTIPLIER_PARAMETER_NAME: Option<&'static str>;
-
-	/// Name of the transaction payment pallet, deployed at the source chain.
-	const AT_SOURCE_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str>;
-	/// Name of the transaction payment pallet, deployed at the target chain.
-	const AT_TARGET_TRANSACTION_PAYMENT_PALLET_NAME: Option<&'static str>;
-
 	/// Messages of this chain are relayed to the `TargetChain`.
 	type SourceChain: ChainWithMessages + ChainWithTransactions;
 	/// Messages from the `SourceChain` are dispatched on this chain.
@@ -85,16 +55,6 @@ pub trait SubstrateMessageLane: 'static + Clone + Debug + Send + Sync {
 	type ReceiveMessagesProofCallBuilder: ReceiveMessagesProofCallBuilder<Self>;
 	/// How receive messages delivery proof call is built?
 	type ReceiveMessagesDeliveryProofCallBuilder: ReceiveMessagesDeliveryProofCallBuilder<Self>;
-
-	/// `TargetChain` tokens to `SourceChain` tokens conversion rate update builder.
-	///
-	/// If not applicable to this bridge, you may use `()` here.
-	type TargetToSourceChainConversionRateUpdateBuilder: UpdateConversionRateCallBuilder<
-		Self::SourceChain,
-	>;
-
-	/// Message relay strategy.
-	type RelayStrategy: RelayStrategy;
 }
 
 /// Adapter that allows all `SubstrateMessageLane` to act as `MessageLane`.
@@ -138,10 +98,6 @@ pub struct MessagesRelayParams<P: SubstrateMessageLane> {
 	pub lane_id: LaneId,
 	/// Metrics parameters.
 	pub metrics_params: MetricsParams,
-	/// Pre-registered standalone metrics.
-	pub standalone_metrics: Option<StandaloneMessagesMetrics<P::SourceChain, P::TargetChain>>,
-	/// Relay strategy.
-	pub relay_strategy: P::RelayStrategy,
 }
 
 /// Run Substrate-to-Substrate messages sync loop.
@@ -170,13 +126,6 @@ where
 	let (max_messages_in_single_batch, max_messages_weight_in_single_batch) =
 		(max_messages_in_single_batch / 2, max_messages_weight_in_single_batch / 2);
 
-	let standalone_metrics = params.standalone_metrics.map(Ok).unwrap_or_else(|| {
-		crate::messages_metrics::standalone_metrics::<P>(
-			source_client.clone(),
-			target_client.clone(),
-		)
-	})?;
-
 	log::info!(
 		target: "bridge",
 		"Starting {} -> {} messages relay.\n\t\
@@ -220,7 +169,6 @@ where
 				max_messages_in_single_batch,
 				max_messages_weight_in_single_batch,
 				max_messages_size_in_single_batch,
-				relay_strategy: params.relay_strategy,
 			},
 		},
 		SubstrateMessagesSource::<P>::new(
@@ -236,10 +184,12 @@ where
 			params.lane_id,
 			relayer_id_at_source,
 			params.target_transaction_params,
-			standalone_metrics.clone(),
 			params.source_to_target_headers_relay,
 		),
-		standalone_metrics.register_and_spawn(params.metrics_params)?,
+		{
+			GlobalMetrics::new()?.register_and_spawn(&params.metrics_params.registry)?;
+			params.metrics_params
+		},
 		futures::future::pending(),
 	)
 	.await
@@ -271,7 +221,6 @@ where
 	R: BridgeMessagesConfig<I, InboundRelayer = AccountIdOf<P::SourceChain>>,
 	I: 'static,
 	R::SourceHeaderChain: bp_messages::target_chain::SourceHeaderChain<
-		R::InboundMessageFee,
 		MessagesProof = FromBridgedChainMessagesProof<HashOf<P::SourceChain>>,
 	>,
 	CallOf<P::TargetChain>: From<BridgeMessagesCall<R, I>> + GetDispatchInfo,
diff --git a/bridges/relays/lib-substrate-relay/src/messages_metrics.rs b/bridges/relays/lib-substrate-relay/src/messages_metrics.rs
index 805d002b65f8755d5d5d95db18a9143878f5b5b8..37a6d67baae434562c0b6d96f2d7812f26724cd8 100644
--- a/bridges/relays/lib-substrate-relay/src/messages_metrics.rs
+++ b/bridges/relays/lib-substrate-relay/src/messages_metrics.rs
@@ -16,260 +16,20 @@
 
 //! Tools for supporting message lanes between two Substrate-based chains.
 
-use crate::{helpers::tokens_conversion_rate, messages_lane::SubstrateMessageLane, TaggedAccount};
+use crate::TaggedAccount;
 
 use codec::Decode;
 use frame_system::AccountInfo;
 use pallet_balances::AccountData;
 use relay_substrate_client::{
-	metrics::{
-		FixedU128OrOne, FloatStorageValue, FloatStorageValueMetric, StorageProofOverheadMetric,
-	},
+	metrics::{FloatStorageValue, FloatStorageValueMetric},
 	AccountIdOf, BalanceOf, Chain, ChainWithBalances, Client, Error as SubstrateError, IndexOf,
 };
-use relay_utils::metrics::{
-	FloatJsonValueMetric, GlobalMetrics, MetricsParams, PrometheusError, StandaloneMetric,
-};
+use relay_utils::metrics::{MetricsParams, StandaloneMetric};
 use sp_core::storage::StorageData;
 use sp_runtime::{FixedPointNumber, FixedU128};
 use std::{convert::TryFrom, fmt::Debug, marker::PhantomData};
 
-/// Name of the `NextFeeMultiplier` storage value within the transaction payment pallet.
-const NEXT_FEE_MULTIPLIER_VALUE_NAME: &str = "NextFeeMultiplier";
-
-/// Shared references to the standalone metrics of the message lane relay loop.
-#[derive(Debug, Clone)]
-pub struct StandaloneMessagesMetrics<SC: Chain, TC: Chain> {
-	/// Global metrics.
-	pub global: GlobalMetrics,
-	/// Storage chain proof overhead metric.
-	pub source_storage_proof_overhead: StorageProofOverheadMetric<SC>,
-	/// Target chain proof overhead metric.
-	pub target_storage_proof_overhead: StorageProofOverheadMetric<TC>,
-	/// Source tokens to base conversion rate metric.
-	pub source_to_base_conversion_rate: Option<FloatJsonValueMetric>,
-	/// Target tokens to base conversion rate metric.
-	pub target_to_base_conversion_rate: Option<FloatJsonValueMetric>,
-	/// Source tokens to target tokens conversion rate metric. This rate is stored by the target
-	/// chain.
-	pub source_to_target_conversion_rate: Option<FloatStorageValueMetric<TC, FixedU128OrOne>>,
-	/// Target tokens to source tokens conversion rate metric. This rate is stored by the source
-	/// chain.
-	pub target_to_source_conversion_rate: Option<FloatStorageValueMetric<SC, FixedU128OrOne>>,
-
-	/// Actual source chain fee multiplier.
-	pub source_fee_multiplier: Option<FloatStorageValueMetric<SC, FixedU128OrOne>>,
-	/// Source chain fee multiplier, stored at the target chain.
-	pub source_fee_multiplier_at_target: Option<FloatStorageValueMetric<TC, FixedU128OrOne>>,
-	/// Actual target chain fee multiplier.
-	pub target_fee_multiplier: Option<FloatStorageValueMetric<TC, FixedU128OrOne>>,
-	/// Target chain fee multiplier, stored at the target chain.
-	pub target_fee_multiplier_at_source: Option<FloatStorageValueMetric<SC, FixedU128OrOne>>,
-}
-
-impl<SC: Chain, TC: Chain> StandaloneMessagesMetrics<SC, TC> {
-	/// Swap source and target sides.
-	pub fn reverse(self) -> StandaloneMessagesMetrics<TC, SC> {
-		StandaloneMessagesMetrics {
-			global: self.global,
-			source_storage_proof_overhead: self.target_storage_proof_overhead,
-			target_storage_proof_overhead: self.source_storage_proof_overhead,
-			source_to_base_conversion_rate: self.target_to_base_conversion_rate,
-			target_to_base_conversion_rate: self.source_to_base_conversion_rate,
-			source_to_target_conversion_rate: self.target_to_source_conversion_rate,
-			target_to_source_conversion_rate: self.source_to_target_conversion_rate,
-			source_fee_multiplier: self.target_fee_multiplier,
-			source_fee_multiplier_at_target: self.target_fee_multiplier_at_source,
-			target_fee_multiplier: self.source_fee_multiplier,
-			target_fee_multiplier_at_source: self.source_fee_multiplier_at_target,
-		}
-	}
-
-	/// Register all metrics in the registry.
-	pub fn register_and_spawn(
-		self,
-		metrics: MetricsParams,
-	) -> Result<MetricsParams, PrometheusError> {
-		self.global.register_and_spawn(&metrics.registry)?;
-		self.source_storage_proof_overhead.register_and_spawn(&metrics.registry)?;
-		self.target_storage_proof_overhead.register_and_spawn(&metrics.registry)?;
-		if let Some(m) = self.source_to_base_conversion_rate {
-			m.register_and_spawn(&metrics.registry)?;
-		}
-		if let Some(m) = self.target_to_base_conversion_rate {
-			m.register_and_spawn(&metrics.registry)?;
-		}
-		if let Some(m) = self.target_to_source_conversion_rate {
-			m.register_and_spawn(&metrics.registry)?;
-		}
-		if let Some(m) = self.source_fee_multiplier {
-			m.register_and_spawn(&metrics.registry)?;
-		}
-		if let Some(m) = self.source_fee_multiplier_at_target {
-			m.register_and_spawn(&metrics.registry)?;
-		}
-		if let Some(m) = self.target_fee_multiplier {
-			m.register_and_spawn(&metrics.registry)?;
-		}
-		if let Some(m) = self.target_fee_multiplier_at_source {
-			m.register_and_spawn(&metrics.registry)?;
-		}
-		Ok(metrics)
-	}
-
-	/// Return conversion rate from target to source tokens.
-	pub async fn target_to_source_conversion_rate(&self) -> Option<f64> {
-		let from_token_value =
-			(*self.target_to_base_conversion_rate.as_ref()?.shared_value_ref().read().await)?;
-		let to_token_value =
-			(*self.source_to_base_conversion_rate.as_ref()?.shared_value_ref().read().await)?;
-		Some(tokens_conversion_rate(from_token_value, to_token_value))
-	}
-}
-
-/// Create symmetric standalone metrics for the message lane relay loop.
-///
-/// All metrics returned by this function are exposed by loops that are serving given lane (`P`)
-/// and by loops that are serving reverse lane (`P` with swapped `TargetChain` and `SourceChain`).
-/// We assume that either conversion rate parameters have values in the storage, or they are
-/// initialized with 1:1.
-pub fn standalone_metrics<P: SubstrateMessageLane>(
-	source_client: Client<P::SourceChain>,
-	target_client: Client<P::TargetChain>,
-) -> anyhow::Result<StandaloneMessagesMetrics<P::SourceChain, P::TargetChain>> {
-	Ok(StandaloneMessagesMetrics {
-		global: GlobalMetrics::new()?,
-		source_storage_proof_overhead: StorageProofOverheadMetric::new(
-			source_client.clone(),
-			format!("{}_storage_proof_overhead", P::SourceChain::NAME.to_lowercase()),
-			format!("{} storage proof overhead", P::SourceChain::NAME),
-		)?,
-		target_storage_proof_overhead: StorageProofOverheadMetric::new(
-			target_client.clone(),
-			format!("{}_storage_proof_overhead", P::TargetChain::NAME.to_lowercase()),
-			format!("{} storage proof overhead", P::TargetChain::NAME),
-		)?,
-		source_to_base_conversion_rate: P::SourceChain::TOKEN_ID
-			.map(|source_chain_token_id| {
-				crate::helpers::token_price_metric(source_chain_token_id).map(Some)
-			})
-			.unwrap_or(Ok(None))?,
-		target_to_base_conversion_rate: P::TargetChain::TOKEN_ID
-			.map(|target_chain_token_id| {
-				crate::helpers::token_price_metric(target_chain_token_id).map(Some)
-			})
-			.unwrap_or(Ok(None))?,
-		source_to_target_conversion_rate: P::SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME
-			.map(bp_runtime::storage_parameter_key)
-			.map(|key| {
-				FloatStorageValueMetric::new(
-					FixedU128OrOne::default(),
-					target_client.clone(),
-					key,
-					format!(
-						"{}_{}_to_{}_conversion_rate",
-						P::TargetChain::NAME,
-						P::SourceChain::NAME,
-						P::TargetChain::NAME
-					),
-					format!(
-						"{} to {} tokens conversion rate (used by {})",
-						P::SourceChain::NAME,
-						P::TargetChain::NAME,
-						P::TargetChain::NAME
-					),
-				)
-				.map(Some)
-			})
-			.unwrap_or(Ok(None))?,
-		target_to_source_conversion_rate: P::TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME
-			.map(bp_runtime::storage_parameter_key)
-			.map(|key| {
-				FloatStorageValueMetric::new(
-					FixedU128OrOne::default(),
-					source_client.clone(),
-					key,
-					format!(
-						"{}_{}_to_{}_conversion_rate",
-						P::SourceChain::NAME,
-						P::TargetChain::NAME,
-						P::SourceChain::NAME
-					),
-					format!(
-						"{} to {} tokens conversion rate (used by {})",
-						P::TargetChain::NAME,
-						P::SourceChain::NAME,
-						P::SourceChain::NAME
-					),
-				)
-				.map(Some)
-			})
-			.unwrap_or(Ok(None))?,
-		source_fee_multiplier: P::AT_SOURCE_TRANSACTION_PAYMENT_PALLET_NAME
-			.map(|pallet| bp_runtime::storage_value_key(pallet, NEXT_FEE_MULTIPLIER_VALUE_NAME))
-			.map(|key| {
-				log::trace!(target: "bridge", "{}_fee_multiplier", P::SourceChain::NAME);
-				FloatStorageValueMetric::new(
-					FixedU128OrOne::default(),
-					source_client.clone(),
-					key,
-					format!("{}_fee_multiplier", P::SourceChain::NAME,),
-					format!("{} fee multiplier", P::SourceChain::NAME,),
-				)
-				.map(Some)
-			})
-			.unwrap_or(Ok(None))?,
-		source_fee_multiplier_at_target: P::SOURCE_FEE_MULTIPLIER_PARAMETER_NAME
-			.map(bp_runtime::storage_parameter_key)
-			.map(|key| {
-				FloatStorageValueMetric::new(
-					FixedU128OrOne::default(),
-					target_client.clone(),
-					key,
-					format!("{}_{}_fee_multiplier", P::TargetChain::NAME, P::SourceChain::NAME,),
-					format!(
-						"{} fee multiplier stored at {}",
-						P::SourceChain::NAME,
-						P::TargetChain::NAME,
-					),
-				)
-				.map(Some)
-			})
-			.unwrap_or(Ok(None))?,
-		target_fee_multiplier: P::AT_TARGET_TRANSACTION_PAYMENT_PALLET_NAME
-			.map(|pallet| bp_runtime::storage_value_key(pallet, NEXT_FEE_MULTIPLIER_VALUE_NAME))
-			.map(|key| {
-				log::trace!(target: "bridge", "{}_fee_multiplier", P::TargetChain::NAME);
-				FloatStorageValueMetric::new(
-					FixedU128OrOne::default(),
-					target_client,
-					key,
-					format!("{}_fee_multiplier", P::TargetChain::NAME,),
-					format!("{} fee multiplier", P::TargetChain::NAME,),
-				)
-				.map(Some)
-			})
-			.unwrap_or(Ok(None))?,
-		target_fee_multiplier_at_source: P::TARGET_FEE_MULTIPLIER_PARAMETER_NAME
-			.map(bp_runtime::storage_parameter_key)
-			.map(|key| {
-				FloatStorageValueMetric::new(
-					FixedU128OrOne::default(),
-					source_client,
-					key,
-					format!("{}_{}_fee_multiplier", P::SourceChain::NAME, P::TargetChain::NAME,),
-					format!(
-						"{} fee multiplier stored at {}",
-						P::TargetChain::NAME,
-						P::SourceChain::NAME,
-					),
-				)
-				.map(Some)
-			})
-			.unwrap_or(Ok(None))?,
-	})
-}
-
 /// Add relay accounts balance metrics.
 pub async fn add_relay_balances_metrics<C: ChainWithBalances>(
 	client: Client<C>,
@@ -359,9 +119,6 @@ fn convert_to_token_balance(balance: u128, token_decimals: u32) -> FixedU128 {
 #[cfg(test)]
 mod tests {
 	use super::*;
-	use frame_support::storage::generator::StorageValue;
-	use sp_core::storage::StorageKey;
-
 	#[test]
 	fn token_decimals_used_properly() {
 		let plancks = 425_000_000_000;
@@ -369,12 +126,4 @@ mod tests {
 		let dots = convert_to_token_balance(plancks, token_decimals);
 		assert_eq!(dots, FixedU128::saturating_from_rational(425, 10));
 	}
-
-	#[test]
-	fn next_fee_multiplier_storage_key_is_correct() {
-		assert_eq!(
-			bp_runtime::storage_value_key("TransactionPayment", NEXT_FEE_MULTIPLIER_VALUE_NAME),
-			StorageKey(pallet_transaction_payment::NextFeeMultiplier::<rialto_runtime::Runtime>::storage_value_final_key().to_vec()),
-		);
-	}
 }
diff --git a/bridges/relays/lib-substrate-relay/src/messages_source.rs b/bridges/relays/lib-substrate-relay/src/messages_source.rs
index c02db3fb48a63b188eb827fdedf2af4b67093122..57f84eb6bb19d936529d7ad2cc996a10e58aa73c 100644
--- a/bridges/relays/lib-substrate-relay/src/messages_source.rs
+++ b/bridges/relays/lib-substrate-relay/src/messages_source.rs
@@ -31,13 +31,11 @@ use async_std::sync::Arc;
 use async_trait::async_trait;
 use bp_messages::{
 	storage_keys::{operating_mode_key, outbound_lane_data_key},
-	InboundMessageDetails, LaneId, MessageData, MessageNonce, MessagePayload,
-	MessagesOperatingMode, OutboundLaneData, OutboundMessageDetails, UnrewardedRelayersState,
-};
-use bp_runtime::{messages::DispatchFeePayment, BasicOperatingMode, HeaderIdProvider};
-use bridge_runtime_common::messages::{
-	source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof,
+	InboundMessageDetails, LaneId, MessageNonce, MessagePayload, MessagesOperatingMode,
+	OutboundLaneData, OutboundMessageDetails,
 };
+use bp_runtime::{BasicOperatingMode, HeaderIdProvider};
+use bridge_runtime_common::messages::target::FromBridgedChainMessagesProof;
 use codec::{Decode, Encode};
 use frame_support::weights::Weight;
 use messages_relay::{
@@ -47,11 +45,11 @@ use messages_relay::{
 		SourceClientState,
 	},
 };
-use num_traits::{Bounded, Zero};
+use num_traits::Zero;
 use relay_substrate_client::{
-	AccountIdOf, AccountKeyPairOf, BalanceOf, BlockNumberOf, Chain, ChainWithMessages,
-	ChainWithTransactions, Client, Error as SubstrateError, HashOf, HeaderIdOf, IndexOf, SignParam,
-	TransactionEra, TransactionTracker, UnsignedTransaction,
+	AccountIdOf, AccountKeyPairOf, BalanceOf, BlockNumberOf, Chain, ChainWithMessages, Client,
+	Error as SubstrateError, HashOf, HeaderIdOf, IndexOf, SignParam, TransactionEra,
+	TransactionTracker, UnsignedTransaction,
 };
 use relay_utils::{relay_loop::Client as RelayClient, HeaderId};
 use sp_core::{Bytes, Pair};
@@ -62,7 +60,7 @@ use std::ops::RangeInclusive;
 /// required to submit to the target node: cumulative dispatch weight of bundled messages and
 /// the proof itself.
 pub type SubstrateMessagesProof<C> = (Weight, FromBridgedChainMessagesProof<HashOf<C>>);
-type MessagesToRefine<'a, Balance> = Vec<(MessagePayload, &'a mut OutboundMessageDetails<Balance>)>;
+type MessagesToRefine<'a> = Vec<(MessagePayload, &'a mut OutboundMessageDetails)>;
 
 /// Substrate client as Substrate messages source.
 pub struct SubstrateMessagesSource<P: SubstrateMessageLane> {
@@ -207,9 +205,7 @@ where
 		// prepare arguments of the inbound message details call (if we need it)
 		let mut msgs_to_refine = vec![];
 		for out_msg_details in out_msgs_details.iter_mut() {
-			if out_msg_details.dispatch_fee_payment != DispatchFeePayment::AtTargetChain {
-				continue
-			}
+			// in our current strategy all messages are supposed to be paid at the target chain
 
 			// for pay-at-target messages we may want to ask target chain for
 			// refined dispatch weight
@@ -218,7 +214,7 @@ where
 				&self.lane_id,
 				out_msg_details.nonce,
 			);
-			let msg_data: MessageData<BalanceOf<P::SourceChain>> =
+			let msg_payload: MessagePayload =
 				self.source_client.storage_value(msg_key, Some(id.1)).await?.ok_or_else(|| {
 					SubstrateError::Custom(format!(
 						"Message to {} {:?}/{} is missing from runtime the storage of {} at {:?}",
@@ -230,7 +226,7 @@ where
 					))
 				})?;
 
-			msgs_to_refine.push((msg_data.payload, out_msg_details));
+			msgs_to_refine.push((msg_payload, out_msg_details));
 		}
 
 		for mut msgs_to_refine_batch in
@@ -277,8 +273,7 @@ where
 				MessageDetails {
 					dispatch_weight: out_msg_details.dispatch_weight,
 					size: out_msg_details.size as _,
-					reward: out_msg_details.delivery_and_dispatch_fee,
-					dispatch_fee_payment: out_msg_details.dispatch_fee_payment,
+					reward: Zero::zero(),
 				},
 			);
 		}
@@ -370,39 +365,6 @@ where
 			target_to_source_headers_relay.require_more_headers(id.0).await;
 		}
 	}
-
-	async fn estimate_confirmation_transaction(
-		&self,
-	) -> <MessageLaneAdapter<P> as MessageLane>::SourceChainBalance {
-		let runtime_version = match self.source_client.runtime_version().await {
-			Ok(v) => v,
-			Err(_) => return BalanceOf::<P::SourceChain>::max_value(),
-		};
-		async {
-			let dummy_tx = P::SourceChain::sign_transaction(
-				SignParam::<P::SourceChain> {
-					spec_version: runtime_version.spec_version,
-					transaction_version: runtime_version.transaction_version,
-					genesis_hash: *self.source_client.genesis_hash(),
-					signer: self.transaction_params.signer.clone(),
-				},
-				make_messages_delivery_proof_transaction::<P>(
-					&self.transaction_params,
-					HeaderId(Default::default(), Default::default()),
-					Zero::zero(),
-					prepare_dummy_messages_delivery_proof::<P::SourceChain, P::TargetChain>(),
-					false,
-				)?,
-			)?
-			.encode();
-			self.source_client
-				.estimate_extrinsic_fee(Bytes(dummy_tx))
-				.await
-				.map(|fee| fee.inclusion_fee())
-		}
-		.await
-		.unwrap_or_else(|_| BalanceOf::<P::SourceChain>::max_value())
-	}
 }
 
 /// Ensure that the messages pallet at source chain is active.
@@ -441,30 +403,6 @@ fn make_messages_delivery_proof_transaction<P: SubstrateMessageLane>(
 		.era(TransactionEra::new(source_best_block_id, source_transaction_params.mortality)))
 }
 
-/// Prepare 'dummy' messages delivery proof that will compose the delivery confirmation transaction.
-///
-/// We don't care about proof actually being the valid proof, because its validity doesn't
-/// affect the call weight - we only care about its size.
-fn prepare_dummy_messages_delivery_proof<SC: Chain, TC: Chain>(
-) -> SubstrateMessagesDeliveryProof<TC> {
-	let single_message_confirmation_size =
-		bp_messages::InboundLaneData::<()>::encoded_size_hint_u32(1, 1);
-	let proof_size = TC::STORAGE_PROOF_OVERHEAD.saturating_add(single_message_confirmation_size);
-	(
-		UnrewardedRelayersState {
-			unrewarded_relayer_entries: 1,
-			messages_in_oldest_entry: 1,
-			total_messages: 1,
-			last_delivered_nonce: 1,
-		},
-		FromBridgedChainMessagesDeliveryProof {
-			bridged_header_hash: Default::default(),
-			storage_proof: vec![vec![0; proof_size as usize]],
-			lane: Default::default(),
-		},
-	)
-}
-
 /// Read best blocks from given client.
 ///
 /// This function assumes that the chain that is followed by the `self_client` has
@@ -552,7 +490,7 @@ where
 }
 
 fn validate_out_msgs_details<C: Chain>(
-	out_msgs_details: &[OutboundMessageDetails<C::Balance>],
+	out_msgs_details: &[OutboundMessageDetails],
 	nonces: RangeInclusive<MessageNonce>,
 ) -> Result<(), SubstrateError> {
 	let make_missing_nonce_error = |expected_nonce| {
@@ -601,8 +539,8 @@ fn validate_out_msgs_details<C: Chain>(
 
 fn split_msgs_to_refine<Source: Chain + ChainWithMessages, Target: Chain>(
 	lane_id: LaneId,
-	msgs_to_refine: MessagesToRefine<Source::Balance>,
-) -> Result<Vec<MessagesToRefine<Source::Balance>>, SubstrateError> {
+	msgs_to_refine: MessagesToRefine,
+) -> Result<Vec<MessagesToRefine>, SubstrateError> {
 	let max_batch_size = Target::max_extrinsic_size() as usize;
 	let mut batches = vec![];
 
@@ -635,23 +573,20 @@ fn split_msgs_to_refine<Source: Chain + ChainWithMessages, Target: Chain>(
 #[cfg(test)]
 mod tests {
 	use super::*;
-	use bp_runtime::{messages::DispatchFeePayment, Chain as ChainBase};
-	use codec::MaxEncodedLen;
+	use bp_runtime::Chain as ChainBase;
 	use relay_rialto_client::Rialto;
 	use relay_rococo_client::Rococo;
 	use relay_wococo_client::Wococo;
 
 	fn message_details_from_rpc(
 		nonces: RangeInclusive<MessageNonce>,
-	) -> Vec<OutboundMessageDetails<bp_wococo::Balance>> {
+	) -> Vec<OutboundMessageDetails> {
 		nonces
 			.into_iter()
 			.map(|nonce| bp_messages::OutboundMessageDetails {
 				nonce,
 				dispatch_weight: Weight::zero(),
 				size: 0,
-				delivery_and_dispatch_fee: 0,
-				dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
 			})
 			.collect()
 	}
@@ -704,31 +639,16 @@ mod tests {
 		));
 	}
 
-	#[test]
-	fn prepare_dummy_messages_delivery_proof_works() {
-		let expected_minimal_size =
-			bp_wococo::AccountId::max_encoded_len() as u32 + Rococo::STORAGE_PROOF_OVERHEAD;
-		let dummy_proof = prepare_dummy_messages_delivery_proof::<Wococo, Rococo>();
-		assert!(
-			dummy_proof.1.encode().len() as u32 > expected_minimal_size,
-			"Expected proof size at least {}. Got: {}",
-			expected_minimal_size,
-			dummy_proof.1.encode().len(),
-		);
-	}
-
 	fn check_split_msgs_to_refine(
 		payload_sizes: Vec<usize>,
 		expected_batches: Result<Vec<usize>, ()>,
 	) {
 		let mut out_msgs_details = vec![];
 		for (idx, _) in payload_sizes.iter().enumerate() {
-			out_msgs_details.push(OutboundMessageDetails::<BalanceOf<Rialto>> {
+			out_msgs_details.push(OutboundMessageDetails {
 				nonce: idx as MessageNonce,
 				dispatch_weight: Weight::zero(),
 				size: 0,
-				delivery_and_dispatch_fee: 0,
-				dispatch_fee_payment: DispatchFeePayment::AtTargetChain,
 			});
 		}
 
diff --git a/bridges/relays/lib-substrate-relay/src/messages_target.rs b/bridges/relays/lib-substrate-relay/src/messages_target.rs
index ed4d040b5d8691723b777f3990af2278e4f21b25..22a50acf37eb6bf4e8a699e13a528630c70edc05 100644
--- a/bridges/relays/lib-substrate-relay/src/messages_target.rs
+++ b/bridges/relays/lib-substrate-relay/src/messages_target.rs
@@ -20,7 +20,6 @@
 
 use crate::{
 	messages_lane::{MessageLaneAdapter, ReceiveMessagesProofCallBuilder, SubstrateMessageLane},
-	messages_metrics::StandaloneMessagesMetrics,
 	messages_source::{ensure_messages_pallet_active, read_client_state, SubstrateMessagesProof},
 	on_demand::OnDemandRelay,
 	TransactionParams,
@@ -32,24 +31,18 @@ use bp_messages::{
 	storage_keys::inbound_lane_data_key, total_unrewarded_messages, InboundLaneData, LaneId,
 	MessageNonce, UnrewardedRelayersState,
 };
-use bridge_runtime_common::messages::{
-	source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof,
-};
-use codec::Encode;
-use frame_support::weights::{Weight, WeightToFee};
+use bridge_runtime_common::messages::source::FromBridgedChainMessagesDeliveryProof;
 use messages_relay::{
 	message_lane::{MessageLane, SourceHeaderIdOf, TargetHeaderIdOf},
 	message_lane_loop::{NoncesSubmitArtifacts, TargetClient, TargetClientState},
 };
-use num_traits::{Bounded, Zero};
 use relay_substrate_client::{
-	AccountIdOf, AccountKeyPairOf, BalanceOf, BlockNumberOf, Chain, ChainWithMessages,
-	ChainWithTransactions, Client, Error as SubstrateError, HashOf, HeaderIdOf, IndexOf, SignParam,
-	TransactionEra, TransactionTracker, UnsignedTransaction, WeightToFeeOf,
+	AccountIdOf, AccountKeyPairOf, BalanceOf, BlockNumberOf, Chain, ChainWithMessages, Client,
+	Error as SubstrateError, HashOf, HeaderIdOf, IndexOf, SignParam, TransactionEra,
+	TransactionTracker, UnsignedTransaction,
 };
-use relay_utils::{relay_loop::Client as RelayClient, HeaderId};
-use sp_core::{Bytes, Pair};
-use sp_runtime::{traits::Saturating, FixedPointNumber, FixedU128};
+use relay_utils::relay_loop::Client as RelayClient;
+use sp_core::Pair;
 use std::{collections::VecDeque, convert::TryFrom, ops::RangeInclusive};
 
 /// Message receiving proof returned by the target Substrate node.
@@ -63,7 +56,6 @@ pub struct SubstrateMessagesTarget<P: SubstrateMessageLane> {
 	lane_id: LaneId,
 	relayer_id_at_source: AccountIdOf<P::SourceChain>,
 	transaction_params: TransactionParams<AccountKeyPairOf<P::TargetChain>>,
-	metric_values: StandaloneMessagesMetrics<P::SourceChain, P::TargetChain>,
 	source_to_target_headers_relay: Option<Arc<dyn OnDemandRelay<BlockNumberOf<P::SourceChain>>>>,
 }
 
@@ -75,7 +67,6 @@ impl<P: SubstrateMessageLane> SubstrateMessagesTarget<P> {
 		lane_id: LaneId,
 		relayer_id_at_source: AccountIdOf<P::SourceChain>,
 		transaction_params: TransactionParams<AccountKeyPairOf<P::TargetChain>>,
-		metric_values: StandaloneMessagesMetrics<P::SourceChain, P::TargetChain>,
 		source_to_target_headers_relay: Option<
 			Arc<dyn OnDemandRelay<BlockNumberOf<P::SourceChain>>>,
 		>,
@@ -86,7 +77,6 @@ impl<P: SubstrateMessageLane> SubstrateMessagesTarget<P> {
 			lane_id,
 			relayer_id_at_source,
 			transaction_params,
-			metric_values,
 			source_to_target_headers_relay,
 		}
 	}
@@ -121,7 +111,6 @@ impl<P: SubstrateMessageLane> Clone for SubstrateMessagesTarget<P> {
 			lane_id: self.lane_id,
 			relayer_id_at_source: self.relayer_id_at_source.clone(),
 			transaction_params: self.transaction_params.clone(),
-			metric_values: self.metric_values.clone(),
 			source_to_target_headers_relay: self.source_to_target_headers_relay.clone(),
 		}
 	}
@@ -283,142 +272,6 @@ where
 			source_to_target_headers_relay.require_more_headers(id.0).await;
 		}
 	}
-
-	async fn estimate_delivery_transaction_in_source_tokens(
-		&self,
-		nonces: RangeInclusive<MessageNonce>,
-		total_prepaid_nonces: MessageNonce,
-		total_dispatch_weight: Weight,
-		total_size: u32,
-	) -> Result<<MessageLaneAdapter<P> as MessageLane>::SourceChainBalance, SubstrateError> {
-		let conversion_rate =
-			self.metric_values.target_to_source_conversion_rate().await.ok_or_else(|| {
-				SubstrateError::Custom(format!(
-					"Failed to compute conversion rate from {} to {}",
-					P::TargetChain::NAME,
-					P::SourceChain::NAME,
-				))
-			})?;
-
-		let (spec_version, transaction_version) =
-			self.target_client.simple_runtime_version().await?;
-		// Prepare 'dummy' delivery transaction - we only care about its length and dispatch weight.
-		let delivery_tx = P::TargetChain::sign_transaction(
-			SignParam {
-				spec_version,
-				transaction_version,
-				genesis_hash: Default::default(),
-				signer: self.transaction_params.signer.clone(),
-			},
-			make_messages_delivery_transaction::<P>(
-				&self.transaction_params,
-				HeaderId(Default::default(), Default::default()),
-				Zero::zero(),
-				self.relayer_id_at_source.clone(),
-				nonces.clone(),
-				prepare_dummy_messages_proof::<P::SourceChain>(
-					nonces.clone(),
-					total_dispatch_weight,
-					total_size,
-				),
-				false,
-			)?,
-		)?
-		.encode();
-		let delivery_tx_fee = self.target_client.estimate_extrinsic_fee(Bytes(delivery_tx)).await?;
-		let inclusion_fee_in_target_tokens = delivery_tx_fee.inclusion_fee();
-
-		// The pre-dispatch cost of delivery transaction includes additional fee to cover dispatch
-		// fee payment (Currency::transfer in regular deployment). But if message dispatch has
-		// already been paid at the Source chain, the delivery transaction will refund relayer with
-		// this additional cost. But `estimate_extrinsic_fee` obviously just returns pre-dispatch
-		// cost of the transaction. So if transaction delivers prepaid message, then it may happen
-		// that pre-dispatch cost is larger than reward and `Rational` relayer will refuse to
-		// deliver this message.
-		//
-		// The most obvious solution would be to deduct total weight of dispatch fee payments from
-		// the `total_dispatch_weight` and use regular `estimate_extrinsic_fee` call. But what if
-		// `total_dispatch_weight` is less than total dispatch fee payments weight? Weight is
-		// strictly positive, so we can't use this option.
-		//
-		// Instead we'll be directly using `WeightToFee` and `NextFeeMultiplier` of the Target
-		// chain. This requires more knowledge of the Target chain, but seems there's no better way
-		// to solve this now.
-		let expected_refund_in_target_tokens = if total_prepaid_nonces != 0 {
-			const WEIGHT_DIFFERENCE: Weight = Weight::from_ref_time(100);
-
-			let (spec_version, transaction_version) =
-				self.target_client.simple_runtime_version().await?;
-			let larger_dispatch_weight = total_dispatch_weight.saturating_add(WEIGHT_DIFFERENCE);
-			let dummy_tx = P::TargetChain::sign_transaction(
-				SignParam {
-					spec_version,
-					transaction_version,
-					genesis_hash: Default::default(),
-					signer: self.transaction_params.signer.clone(),
-				},
-				make_messages_delivery_transaction::<P>(
-					&self.transaction_params,
-					HeaderId(Default::default(), Default::default()),
-					Zero::zero(),
-					self.relayer_id_at_source.clone(),
-					nonces.clone(),
-					prepare_dummy_messages_proof::<P::SourceChain>(
-						nonces.clone(),
-						larger_dispatch_weight,
-						total_size,
-					),
-					false,
-				)?,
-			)?
-			.encode();
-			let larger_delivery_tx_fee =
-				self.target_client.estimate_extrinsic_fee(Bytes(dummy_tx)).await?;
-
-			compute_prepaid_messages_refund::<P::TargetChain>(
-				total_prepaid_nonces,
-				compute_fee_multiplier::<P::TargetChain>(
-					delivery_tx_fee.adjusted_weight_fee,
-					total_dispatch_weight,
-					larger_delivery_tx_fee.adjusted_weight_fee,
-					larger_dispatch_weight,
-				),
-			)
-		} else {
-			Zero::zero()
-		};
-
-		let delivery_fee_in_source_tokens =
-			convert_target_tokens_to_source_tokens::<P::SourceChain, P::TargetChain>(
-				FixedU128::from_float(conversion_rate),
-				inclusion_fee_in_target_tokens.saturating_sub(expected_refund_in_target_tokens),
-			);
-
-		log::trace!(
-			target: "bridge",
-			"Estimated {} -> {} messages delivery transaction.\n\t\
-				Total nonces: {:?}\n\t\
-				Prepaid messages: {}\n\t\
-				Total messages size: {}\n\t\
-				Total messages dispatch weight: {}\n\t\
-				Inclusion fee (in {1} tokens): {:?}\n\t\
-				Expected refund (in {1} tokens): {:?}\n\t\
-				{1} -> {0} conversion rate: {:?}\n\t\
-				Expected delivery tx fee (in {0} tokens): {:?}",
-				P::SourceChain::NAME,
-				P::TargetChain::NAME,
-				nonces,
-				total_prepaid_nonces,
-				total_size,
-				total_dispatch_weight,
-				inclusion_fee_in_target_tokens,
-				expected_refund_in_target_tokens,
-				conversion_rate,
-				delivery_fee_in_source_tokens,
-		);
-
-		Ok(delivery_fee_in_source_tokens)
-	}
 }
 
 /// Make messages delivery transaction from given proof.
@@ -443,153 +296,3 @@ fn make_messages_delivery_transaction<P: SubstrateMessageLane>(
 	Ok(UnsignedTransaction::new(call.into(), transaction_nonce)
 		.era(TransactionEra::new(target_best_block_id, target_transaction_params.mortality)))
 }
-
-/// Prepare 'dummy' messages proof that will compose the delivery transaction.
-///
-/// We don't care about proof actually being the valid proof, because its validity doesn't
-/// affect the call weight - we only care about its size.
-fn prepare_dummy_messages_proof<SC: Chain>(
-	nonces: RangeInclusive<MessageNonce>,
-	total_dispatch_weight: Weight,
-	total_size: u32,
-) -> SubstrateMessagesProof<SC> {
-	(
-		total_dispatch_weight,
-		FromBridgedChainMessagesProof {
-			bridged_header_hash: Default::default(),
-			storage_proof: vec![vec![
-				0;
-				SC::STORAGE_PROOF_OVERHEAD.saturating_add(total_size) as usize
-			]],
-			lane: Default::default(),
-			nonces_start: *nonces.start(),
-			nonces_end: *nonces.end(),
-		},
-	)
-}
-
-/// Given delivery transaction fee in target chain tokens and conversion rate to the source
-/// chain tokens, compute transaction cost in source chain tokens.
-fn convert_target_tokens_to_source_tokens<SC: Chain, TC: Chain>(
-	target_to_source_conversion_rate: FixedU128,
-	target_transaction_fee: TC::Balance,
-) -> SC::Balance
-where
-	SC::Balance: TryFrom<TC::Balance>,
-{
-	SC::Balance::try_from(
-		target_to_source_conversion_rate.saturating_mul_int(target_transaction_fee),
-	)
-	.unwrap_or_else(|_| SC::Balance::max_value())
-}
-
-/// Compute fee multiplier that is used by the chain, given a couple of fees for transactions
-/// that are only differ in dispatch weights.
-///
-/// This function assumes that standard transaction payment pallet is used by the chain.
-/// The only fee component that depends on dispatch weight is the `adjusted_weight_fee`.
-///
-/// **WARNING**: this functions will only be accurate if weight-to-fee conversion function
-/// is linear. For non-linear polynomials the error will grow with `weight_difference` growth.
-/// So better to use smaller differences.
-fn compute_fee_multiplier<C: ChainWithMessages>(
-	smaller_adjusted_weight_fee: BalanceOf<C>,
-	smaller_tx_weight: Weight,
-	larger_adjusted_weight_fee: BalanceOf<C>,
-	larger_tx_weight: Weight,
-) -> FixedU128 {
-	let adjusted_weight_fee_difference =
-		larger_adjusted_weight_fee.saturating_sub(smaller_adjusted_weight_fee);
-	let smaller_tx_unadjusted_weight_fee = WeightToFeeOf::<C>::weight_to_fee(&smaller_tx_weight);
-	let larger_tx_unadjusted_weight_fee = WeightToFeeOf::<C>::weight_to_fee(&larger_tx_weight);
-	FixedU128::saturating_from_rational(
-		adjusted_weight_fee_difference,
-		larger_tx_unadjusted_weight_fee.saturating_sub(smaller_tx_unadjusted_weight_fee),
-	)
-}
-
-/// Compute fee that will be refunded to the relayer because dispatch of `total_prepaid_nonces`
-/// messages has been paid at the source chain.
-fn compute_prepaid_messages_refund<C: ChainWithMessages>(
-	total_prepaid_nonces: MessageNonce,
-	fee_multiplier: FixedU128,
-) -> BalanceOf<C> {
-	fee_multiplier.saturating_mul_int(WeightToFeeOf::<C>::weight_to_fee(
-		&C::PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN.saturating_mul(total_prepaid_nonces),
-	))
-}
-
-#[cfg(test)]
-mod tests {
-	use super::*;
-	use relay_rialto_client::Rialto;
-	use relay_rococo_client::Rococo;
-	use relay_wococo_client::Wococo;
-
-	#[test]
-	fn prepare_dummy_messages_proof_works() {
-		const DISPATCH_WEIGHT: Weight = Weight::from_ref_time(1_000_000);
-		const SIZE: u32 = 1_000;
-		let dummy_proof = prepare_dummy_messages_proof::<Rococo>(1..=10, DISPATCH_WEIGHT, SIZE);
-		assert_eq!(dummy_proof.0, DISPATCH_WEIGHT);
-		assert!(
-			dummy_proof.1.encode().len() as u32 > SIZE,
-			"Expected proof size at least {}. Got: {}",
-			SIZE,
-			dummy_proof.1.encode().len(),
-		);
-	}
-
-	#[test]
-	fn convert_target_tokens_to_source_tokens_works() {
-		assert_eq!(
-			convert_target_tokens_to_source_tokens::<Rococo, Wococo>((150, 100).into(), 1_000),
-			1_500
-		);
-		assert_eq!(
-			convert_target_tokens_to_source_tokens::<Rococo, Wococo>((50, 100).into(), 1_000),
-			500
-		);
-		assert_eq!(
-			convert_target_tokens_to_source_tokens::<Rococo, Wococo>((100, 100).into(), 1_000),
-			1_000
-		);
-	}
-
-	#[test]
-	fn compute_fee_multiplier_returns_sane_results() {
-		let multiplier: FixedU128 =
-			bp_rialto::WeightToFee::weight_to_fee(&Weight::from_ref_time(1)).into();
-
-		let smaller_weight = 1_000_000;
-		let smaller_adjusted_weight_fee = multiplier.saturating_mul_int(
-			WeightToFeeOf::<Rialto>::weight_to_fee(&Weight::from_ref_time(smaller_weight)),
-		);
-
-		let larger_weight = smaller_weight + 200_000;
-		let larger_adjusted_weight_fee = multiplier.saturating_mul_int(
-			WeightToFeeOf::<Rialto>::weight_to_fee(&Weight::from_ref_time(larger_weight)),
-		);
-		assert_eq!(
-			compute_fee_multiplier::<Rialto>(
-				smaller_adjusted_weight_fee,
-				Weight::from_ref_time(smaller_weight),
-				larger_adjusted_weight_fee,
-				Weight::from_ref_time(larger_weight),
-			),
-			multiplier,
-		);
-	}
-
-	#[test]
-	fn compute_prepaid_messages_refund_returns_sane_results() {
-		assert!(
-			compute_prepaid_messages_refund::<Rialto>(
-				10,
-				FixedU128::saturating_from_rational(110, 100),
-			) > Rialto::PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN
-				.saturating_mul(10u64)
-				.ref_time() as _
-		);
-	}
-}
diff --git a/bridges/relays/messages/src/lib.rs b/bridges/relays/messages/src/lib.rs
index c9e460300342f46973fe631382a05793478a87eb..9c62cee5ee3db1e0b8825d2893d53422bf44a33c 100644
--- a/bridges/relays/messages/src/lib.rs
+++ b/bridges/relays/messages/src/lib.rs
@@ -29,9 +29,9 @@ mod metrics;
 
 pub mod message_lane;
 pub mod message_lane_loop;
-pub mod relay_strategy;
 
 mod message_race_delivery;
+mod message_race_limits;
 mod message_race_loop;
 mod message_race_receiving;
 mod message_race_strategy;
diff --git a/bridges/relays/messages/src/message_lane_loop.rs b/bridges/relays/messages/src/message_lane_loop.rs
index 8d9f3ded08741a91b5b9d5fd23da99f77c46a72f..6b28dcbaa602cf1005be72e236002162c33ac919 100644
--- a/bridges/relays/messages/src/message_lane_loop.rs
+++ b/bridges/relays/messages/src/message_lane_loop.rs
@@ -30,7 +30,6 @@ use async_trait::async_trait;
 use futures::{channel::mpsc::unbounded, future::FutureExt, stream::StreamExt};
 
 use bp_messages::{LaneId, MessageNonce, UnrewardedRelayersState, Weight};
-use bp_runtime::messages::DispatchFeePayment;
 use relay_utils::{
 	interval, metrics::MetricsParams, process_future_result, relay_loop::Client as RelayClient,
 	retry_backoff, FailedClient, TransactionTracker,
@@ -41,12 +40,11 @@ use crate::{
 	message_race_delivery::run as run_message_delivery_race,
 	message_race_receiving::run as run_message_receiving_race,
 	metrics::MessageLaneLoopMetrics,
-	relay_strategy::RelayStrategy,
 };
 
 /// Message lane loop configuration params.
 #[derive(Debug, Clone)]
-pub struct Params<Strategy: RelayStrategy> {
+pub struct Params {
 	/// Id of lane this loop is servicing.
 	pub lane: LaneId,
 	/// Interval at which we ask target node about its updates.
@@ -56,22 +54,12 @@ pub struct Params<Strategy: RelayStrategy> {
 	/// Delay between moments when connection error happens and our reconnect attempt.
 	pub reconnect_delay: Duration,
 	/// Message delivery race parameters.
-	pub delivery_params: MessageDeliveryParams<Strategy>,
-}
-
-/// Relayer operating mode.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum RelayerMode {
-	/// The relayer doesn't care about rewards.
-	Altruistic,
-	/// The relayer will deliver all messages and confirmations as long as he's not losing any
-	/// funds.
-	Rational,
+	pub delivery_params: MessageDeliveryParams,
 }
 
 /// Message delivery race parameters.
 #[derive(Debug, Clone)]
-pub struct MessageDeliveryParams<Strategy: RelayStrategy> {
+pub struct MessageDeliveryParams {
 	/// Maximal number of unconfirmed relayer entries at the inbound lane. If there's that number
 	/// of entries in the `InboundLaneData::relayers` set, all new messages will be rejected until
 	/// reward payment will be proved (by including outbound lane state to the message delivery
@@ -87,8 +75,6 @@ pub struct MessageDeliveryParams<Strategy: RelayStrategy> {
 	pub max_messages_weight_in_single_batch: Weight,
 	/// Maximal cumulative size of relayed messages in single delivery transaction.
 	pub max_messages_size_in_single_batch: u32,
-	/// Relay strategy
-	pub relay_strategy: Strategy,
 }
 
 /// Message details.
@@ -100,8 +86,6 @@ pub struct MessageDetails<SourceChainBalance> {
 	pub size: u32,
 	/// The relayer reward paid in the source chain tokens.
 	pub reward: SourceChainBalance,
-	/// Where the fee for dispatching message is paid?
-	pub dispatch_fee_payment: DispatchFeePayment,
 }
 
 /// Messages details map.
@@ -173,9 +157,6 @@ pub trait SourceClient<P: MessageLane>: RelayClient {
 
 	/// We need given finalized target header on source to continue synchronization.
 	async fn require_target_header_on_source(&self, id: TargetHeaderIdOf<P>);
-
-	/// Estimate cost of single message confirmation transaction in source chain tokens.
-	async fn estimate_confirmation_transaction(&self) -> P::SourceChainBalance;
 }
 
 /// Target client trait.
@@ -221,18 +202,6 @@ pub trait TargetClient<P: MessageLane>: RelayClient {
 
 	/// We need given finalized source header on target to continue synchronization.
 	async fn require_source_header_on_target(&self, id: SourceHeaderIdOf<P>);
-
-	/// Estimate cost of messages delivery transaction in source chain tokens.
-	///
-	/// Please keep in mind that the returned cost must be converted to the source chain
-	/// tokens, even though the transaction fee will be paid in the target chain tokens.
-	async fn estimate_delivery_transaction_in_source_tokens(
-		&self,
-		nonces: RangeInclusive<MessageNonce>,
-		total_prepaid_nonces: MessageNonce,
-		total_dispatch_weight: Weight,
-		total_size: u32,
-	) -> Result<P::SourceChainBalance, Self::Error>;
 }
 
 /// State of the client.
@@ -272,8 +241,8 @@ pub fn metrics_prefix<P: MessageLane>(lane: &LaneId) -> String {
 }
 
 /// Run message lane service loop.
-pub async fn run<P: MessageLane, Strategy: RelayStrategy>(
-	params: Params<Strategy>,
+pub async fn run<P: MessageLane>(
+	params: Params,
 	source_client: impl SourceClient<P>,
 	target_client: impl TargetClient<P>,
 	metrics_params: MetricsParams,
@@ -283,11 +252,7 @@ pub async fn run<P: MessageLane, Strategy: RelayStrategy>(
 	relay_utils::relay_loop(source_client, target_client)
 		.reconnect_delay(params.reconnect_delay)
 		.with_metrics(metrics_params)
-		.loop_metric(MessageLaneLoopMetrics::new(
-			Some(&metrics_prefix::<P>(&params.lane)),
-			P::SOURCE_NAME,
-			P::TARGET_NAME,
-		)?)?
+		.loop_metric(MessageLaneLoopMetrics::new(Some(&metrics_prefix::<P>(&params.lane)))?)?
 		.expose()
 		.await?
 		.run(metrics_prefix::<P>(&params.lane), move |source_client, target_client, metrics| {
@@ -304,13 +269,8 @@ pub async fn run<P: MessageLane, Strategy: RelayStrategy>(
 
 /// Run one-way message delivery loop until connection with target or source node is lost, or exit
 /// signal is received.
-async fn run_until_connection_lost<
-	P: MessageLane,
-	Strategy: RelayStrategy,
-	SC: SourceClient<P>,
-	TC: TargetClient<P>,
->(
-	params: Params<Strategy>,
+async fn run_until_connection_lost<P: MessageLane, SC: SourceClient<P>, TC: TargetClient<P>>(
+	params: Params,
 	source_client: SC,
 	target_client: TC,
 	metrics_msg: Option<MessageLaneLoopMetrics>,
@@ -477,17 +437,12 @@ pub(crate) mod tests {
 
 	use relay_utils::{HeaderId, MaybeConnectionError, TrackedTransactionStatus};
 
-	use crate::relay_strategy::AltruisticStrategy;
-
 	use super::*;
 
 	pub fn header_id(number: TestSourceHeaderNumber) -> TestSourceHeaderId {
 		HeaderId(number, number)
 	}
 
-	pub const CONFIRMATION_TRANSACTION_COST: TestSourceChainBalance = 1;
-	pub const BASE_MESSAGE_DELIVERY_TRANSACTION_COST: TestSourceChainBalance = 1;
-
 	pub type TestSourceChainBalance = u64;
 	pub type TestSourceHeaderId = HeaderId<TestSourceHeaderNumber, TestSourceHeaderHash>;
 	pub type TestTargetHeaderId = HeaderId<TestTargetHeaderNumber, TestTargetHeaderHash>;
@@ -681,7 +636,6 @@ pub(crate) mod tests {
 							dispatch_weight: Weight::from_ref_time(1),
 							size: 1,
 							reward: 1,
-							dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
 						},
 					)
 				})
@@ -737,10 +691,6 @@ pub(crate) mod tests {
 			(self.tick)(&mut data);
 			(self.post_tick)(&mut data);
 		}
-
-		async fn estimate_confirmation_transaction(&self) -> TestSourceChainBalance {
-			CONFIRMATION_TRANSACTION_COST
-		}
 	}
 
 	#[derive(Clone)]
@@ -871,20 +821,6 @@ pub(crate) mod tests {
 			(self.tick)(&mut data);
 			(self.post_tick)(&mut data);
 		}
-
-		async fn estimate_delivery_transaction_in_source_tokens(
-			&self,
-			nonces: RangeInclusive<MessageNonce>,
-			_total_prepaid_nonces: MessageNonce,
-			total_dispatch_weight: Weight,
-			total_size: u32,
-		) -> Result<TestSourceChainBalance, TestError> {
-			Ok((Weight::from_ref_time(BASE_MESSAGE_DELIVERY_TRANSACTION_COST) *
-				(nonces.end() - nonces.start() + 1) +
-				total_dispatch_weight +
-				Weight::from_ref_time(total_size as u64))
-			.ref_time())
-		}
 	}
 
 	fn run_loop_test(
@@ -920,7 +856,6 @@ pub(crate) mod tests {
 						max_messages_in_single_batch: 4,
 						max_messages_weight_in_single_batch: Weight::from_ref_time(4),
 						max_messages_size_in_single_batch: 4,
-						relay_strategy: AltruisticStrategy,
 					},
 				},
 				source_client,
diff --git a/bridges/relays/messages/src/message_race_delivery.rs b/bridges/relays/messages/src/message_race_delivery.rs
index 9481e47faf88f055907a26d40d3cf2378d49b16c..b49a05dac5cf950ec9d06aa4f2c42838f6594d30 100644
--- a/bridges/relays/messages/src/message_race_delivery.rs
+++ b/bridges/relays/messages/src/message_race_delivery.rs
@@ -28,23 +28,23 @@ use crate::{
 		SourceClient as MessageLaneSourceClient, SourceClientState,
 		TargetClient as MessageLaneTargetClient, TargetClientState,
 	},
+	message_race_limits::{MessageRaceLimits, RelayMessagesBatchReference},
 	message_race_loop::{
 		MessageRace, NoncesRange, RaceState, RaceStrategy, SourceClient, SourceClientNonces,
 		TargetClient, TargetClientNonces,
 	},
 	message_race_strategy::BasicStrategy,
 	metrics::MessageLaneLoopMetrics,
-	relay_strategy::{EnforcementStrategy, RelayMessagesBatchReference, RelayStrategy},
 };
 
 /// Run message delivery race.
-pub async fn run<P: MessageLane, Strategy: RelayStrategy>(
+pub async fn run<P: MessageLane>(
 	source_client: impl MessageLaneSourceClient<P>,
 	source_state_updates: impl FusedStream<Item = SourceClientState<P>>,
 	target_client: impl MessageLaneTargetClient<P>,
 	target_state_updates: impl FusedStream<Item = TargetClientState<P>>,
 	metrics_msg: Option<MessageLaneLoopMetrics>,
-	params: MessageDeliveryParams<Strategy>,
+	params: MessageDeliveryParams,
 ) -> Result<(), FailedClient> {
 	crate::message_race_loop::run(
 		MessageDeliveryRaceSource {
@@ -59,7 +59,7 @@ pub async fn run<P: MessageLane, Strategy: RelayStrategy>(
 			_phantom: Default::default(),
 		},
 		target_state_updates,
-		MessageDeliveryStrategy::<P, Strategy, _, _> {
+		MessageDeliveryStrategy::<P, _, _> {
 			lane_source_client: source_client,
 			lane_target_client: target_client,
 			max_unrewarded_relayer_entries_at_target: params
@@ -68,7 +68,6 @@ pub async fn run<P: MessageLane, Strategy: RelayStrategy>(
 			max_messages_in_single_batch: params.max_messages_in_single_batch,
 			max_messages_weight_in_single_batch: params.max_messages_weight_in_single_batch,
 			max_messages_size_in_single_batch: params.max_messages_size_in_single_batch,
-			relay_strategy: params.relay_strategy,
 			latest_confirmed_nonces_at_source: VecDeque::new(),
 			target_nonces: None,
 			strategy: BasicStrategy::new(),
@@ -231,7 +230,7 @@ struct DeliveryRaceTargetNoncesData {
 }
 
 /// Messages delivery strategy.
-struct MessageDeliveryStrategy<P: MessageLane, Strategy: RelayStrategy, SC, TC> {
+struct MessageDeliveryStrategy<P: MessageLane, SC, TC> {
 	/// The client that is connected to the message lane source node.
 	lane_source_client: SC,
 	/// The client that is connected to the message lane target node.
@@ -246,8 +245,6 @@ struct MessageDeliveryStrategy<P: MessageLane, Strategy: RelayStrategy, SC, TC>
 	max_messages_weight_in_single_batch: Weight,
 	/// Maximal messages size in the single delivery transaction.
 	max_messages_size_in_single_batch: u32,
-	/// Relayer operating mode.
-	relay_strategy: Strategy,
 	/// Latest confirmed nonces at the source client + the header id where we have first met this
 	/// nonce.
 	latest_confirmed_nonces_at_source: VecDeque<(SourceHeaderIdOf<P>, MessageNonce)>,
@@ -268,9 +265,7 @@ type MessageDeliveryStrategyBase<P> = BasicStrategy<
 	<P as MessageLane>::MessagesProof,
 >;
 
-impl<P: MessageLane, Strategy: RelayStrategy, SC, TC> std::fmt::Debug
-	for MessageDeliveryStrategy<P, Strategy, SC, TC>
-{
+impl<P: MessageLane, SC, TC> std::fmt::Debug for MessageDeliveryStrategy<P, SC, TC> {
 	fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
 		fmt.debug_struct("MessageDeliveryStrategy")
 			.field(
@@ -288,7 +283,7 @@ impl<P: MessageLane, Strategy: RelayStrategy, SC, TC> std::fmt::Debug
 	}
 }
 
-impl<P: MessageLane, Strategy: RelayStrategy, SC, TC> MessageDeliveryStrategy<P, Strategy, SC, TC> {
+impl<P: MessageLane, SC, TC> MessageDeliveryStrategy<P, SC, TC> {
 	/// Returns total weight of all undelivered messages.
 	fn total_queued_dispatch_weight(&self) -> Weight {
 		self.strategy
@@ -300,9 +295,8 @@ impl<P: MessageLane, Strategy: RelayStrategy, SC, TC> MessageDeliveryStrategy<P,
 }
 
 #[async_trait]
-impl<P, Strategy: RelayStrategy, SC, TC>
-	RaceStrategy<SourceHeaderIdOf<P>, TargetHeaderIdOf<P>, P::MessagesProof>
-	for MessageDeliveryStrategy<P, Strategy, SC, TC>
+impl<P, SC, TC> RaceStrategy<SourceHeaderIdOf<P>, TargetHeaderIdOf<P>, P::MessagesProof>
+	for MessageDeliveryStrategy<P, SC, TC>
 where
 	P: MessageLane,
 	SC: MessageLaneSourceClient<P>,
@@ -524,8 +518,7 @@ where
 			metrics: self.metrics_msg.clone(),
 		};
 
-		let mut strategy = EnforcementStrategy::new(self.relay_strategy.clone());
-		let range_end = strategy.decide(reference).await?;
+		let range_end = MessageRaceLimits::decide(reference).await?;
 
 		let range_begin = source_queue[0].1.begin();
 		let selected_nonces = range_begin..=range_end;
@@ -562,38 +555,27 @@ impl<SourceChainBalance: std::fmt::Debug> NoncesRange for MessageDetailsMap<Sour
 
 #[cfg(test)]
 mod tests {
-	use bp_runtime::messages::DispatchFeePayment;
-
-	use crate::{
-		message_lane_loop::{
-			tests::{
-				header_id, TestMessageLane, TestMessagesProof, TestSourceChainBalance,
-				TestSourceClient, TestSourceHeaderId, TestTargetClient, TestTargetHeaderId,
-				BASE_MESSAGE_DELIVERY_TRANSACTION_COST, CONFIRMATION_TRANSACTION_COST,
-			},
-			MessageDetails, RelayerMode,
+	use crate::message_lane_loop::{
+		tests::{
+			header_id, TestMessageLane, TestMessagesProof, TestSourceChainBalance,
+			TestSourceClient, TestSourceHeaderId, TestTargetClient, TestTargetHeaderId,
 		},
-		relay_strategy::MixStrategy,
+		MessageDetails,
 	};
 
 	use super::*;
 
 	const DEFAULT_DISPATCH_WEIGHT: Weight = Weight::from_ref_time(1);
 	const DEFAULT_SIZE: u32 = 1;
-	const DEFAULT_REWARD: TestSourceChainBalance = CONFIRMATION_TRANSACTION_COST +
-		BASE_MESSAGE_DELIVERY_TRANSACTION_COST +
-		DEFAULT_DISPATCH_WEIGHT.ref_time() +
-		(DEFAULT_SIZE as TestSourceChainBalance);
 
 	type TestRaceState = RaceState<TestSourceHeaderId, TestTargetHeaderId, TestMessagesProof>;
 	type TestStrategy =
-		MessageDeliveryStrategy<TestMessageLane, MixStrategy, TestSourceClient, TestTargetClient>;
+		MessageDeliveryStrategy<TestMessageLane, TestSourceClient, TestTargetClient>;
 
 	fn source_nonces(
 		new_nonces: RangeInclusive<MessageNonce>,
 		confirmed_nonce: MessageNonce,
 		reward: TestSourceChainBalance,
-		dispatch_fee_payment: DispatchFeePayment,
 	) -> SourceClientNonces<MessageDetailsMap<TestSourceChainBalance>> {
 		SourceClientNonces {
 			new_nonces: new_nonces
@@ -605,7 +587,6 @@ mod tests {
 							dispatch_weight: DEFAULT_DISPATCH_WEIGHT,
 							size: DEFAULT_SIZE,
 							reward,
-							dispatch_fee_payment,
 						},
 					)
 				})
@@ -648,13 +629,11 @@ mod tests {
 				},
 			}),
 			strategy: BasicStrategy::new(),
-			relay_strategy: MixStrategy::new(RelayerMode::Altruistic),
 		};
 
-		race_strategy.strategy.source_nonces_updated(
-			header_id(1),
-			source_nonces(20..=23, 19, DEFAULT_REWARD, DispatchFeePayment::AtSourceChain),
-		);
+		race_strategy
+			.strategy
+			.source_nonces_updated(header_id(1), source_nonces(20..=23, 19, 0));
 
 		let target_nonces = TargetClientNonces { latest_nonce: 19, nonces_data: () };
 		race_strategy
@@ -687,7 +666,6 @@ mod tests {
 							dispatch_weight: Weight::from_ref_time(idx),
 							size: idx as _,
 							reward: idx as _,
-							dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
 						},
 					)
 				})
@@ -978,83 +956,6 @@ mod tests {
 		assert_eq!(strategy.required_source_header_at_target(&header_id(1)), Some(header_id(2)));
 	}
 
-	#[async_std::test]
-	async fn rational_relayer_is_delivering_messages_if_cost_is_equal_to_reward() {
-		let (state, mut strategy) = prepare_strategy();
-		strategy.relay_strategy = MixStrategy::new(RelayerMode::Rational);
-
-		// so now we have:
-		// - 20..=23 with reward = cost
-		// => strategy shall select all 20..=23
-		assert_eq!(
-			strategy.select_nonces_to_deliver(state).await,
-			Some(((20..=23), proof_parameters(false, 4)))
-		);
-	}
-
-	#[async_std::test]
-	async fn rational_relayer_is_not_delivering_messages_if_cost_is_larger_than_reward() {
-		let (mut state, mut strategy) = prepare_strategy();
-		let nonces = source_nonces(
-			24..=25,
-			19,
-			DEFAULT_REWARD - BASE_MESSAGE_DELIVERY_TRANSACTION_COST,
-			DispatchFeePayment::AtSourceChain,
-		);
-		strategy.strategy.source_nonces_updated(header_id(2), nonces);
-		state.best_finalized_source_header_id_at_best_target = Some(header_id(2));
-		strategy.relay_strategy = MixStrategy::new(RelayerMode::Rational);
-
-		// so now we have:
-		// - 20..=23 with reward = cost
-		// - 24..=25 with reward less than cost
-		// => strategy shall only select 20..=23
-		assert_eq!(
-			strategy.select_nonces_to_deliver(state).await,
-			Some(((20..=23), proof_parameters(false, 4)))
-		);
-	}
-
-	#[async_std::test]
-	async fn rational_relayer_is_delivering_unpaid_messages() {
-		async fn test_with_dispatch_fee_payment(
-			dispatch_fee_payment: DispatchFeePayment,
-		) -> Option<(RangeInclusive<MessageNonce>, MessageProofParameters)> {
-			let (mut state, mut strategy) = prepare_strategy();
-			let nonces = source_nonces(
-				24..=24,
-				19,
-				DEFAULT_REWARD - DEFAULT_DISPATCH_WEIGHT.ref_time(),
-				dispatch_fee_payment,
-			);
-			strategy.strategy.source_nonces_updated(header_id(2), nonces);
-			state.best_finalized_source_header_id_at_best_target = Some(header_id(2));
-			strategy.max_unrewarded_relayer_entries_at_target = 100;
-			strategy.max_unconfirmed_nonces_at_target = 100;
-			strategy.max_messages_in_single_batch = 100;
-			strategy.max_messages_weight_in_single_batch = Weight::from_ref_time(100);
-			strategy.max_messages_size_in_single_batch = 100;
-			strategy.relay_strategy = MixStrategy::new(RelayerMode::Rational);
-
-			// so now we have:
-			// - 20..=23 with reward = cost
-			// - 24..=24 with reward less than cost, but we're deducting `DEFAULT_DISPATCH_WEIGHT`
-			//   from the cost, so it should be fine;
-			// => when MSG#24 fee is paid at the target chain, strategy shall select all 20..=24
-			// => when MSG#25 fee is paid at the source chain, strategy shall only select 20..=23
-			strategy.select_nonces_to_deliver(state).await
-		}
-
-		assert_eq!(
-			test_with_dispatch_fee_payment(DispatchFeePayment::AtTargetChain).await,
-			Some(((20..=24), proof_parameters(false, 5)))
-		);
-		assert_eq!(
-			test_with_dispatch_fee_payment(DispatchFeePayment::AtSourceChain).await,
-			Some(((20..=23), proof_parameters(false, 4)))
-		);
-	}
-
 	#[async_std::test]
 	async fn relayer_uses_flattened_view_of_the_source_queue_to_select_nonces() {
 		// Real scenario that has happened on test deployments:
@@ -1066,7 +967,7 @@ mod tests {
 		// This was happening because selector (`select_nonces_for_delivery_transaction`) has been
 		// called for every `source_queue` entry separately without preserving any context.
 		let (mut state, mut strategy) = prepare_strategy();
-		let nonces = source_nonces(24..=25, 19, DEFAULT_REWARD, DispatchFeePayment::AtSourceChain);
+		let nonces = source_nonces(24..=25, 19, 0);
 		strategy.strategy.source_nonces_updated(header_id(2), nonces);
 		strategy.max_unrewarded_relayer_entries_at_target = 100;
 		strategy.max_unconfirmed_nonces_at_target = 100;
diff --git a/bridges/relays/messages/src/relay_strategy/enforcement_strategy.rs b/bridges/relays/messages/src/message_race_limits.rs
similarity index 56%
rename from bridges/relays/messages/src/relay_strategy/enforcement_strategy.rs
rename to bridges/relays/messages/src/message_race_limits.rs
index 59e1b445bdcd5f61b5712057f1c6ae7a38df0fb1..a28d9ba63da965195646df14bf0bf8ccf1e05cf4 100644
--- a/bridges/relays/messages/src/relay_strategy/enforcement_strategy.rs
+++ b/bridges/relays/messages/src/message_race_limits.rs
@@ -17,43 +17,88 @@
 //! enforcement strategy
 
 use num_traits::Zero;
+use std::ops::Range;
 
 use bp_messages::{MessageNonce, Weight};
-use bp_runtime::messages::DispatchFeePayment;
 
 use crate::{
 	message_lane::MessageLane,
 	message_lane_loop::{
-		MessageDetails, SourceClient as MessageLaneSourceClient,
+		MessageDetails, MessageDetailsMap, SourceClient as MessageLaneSourceClient,
 		TargetClient as MessageLaneTargetClient,
 	},
 	message_race_loop::NoncesRange,
-	relay_strategy::{RelayMessagesBatchReference, RelayReference, RelayStrategy},
+	message_race_strategy::SourceRangesQueue,
+	metrics::MessageLaneLoopMetrics,
 };
 
-/// Do hard check and run soft check strategy
-#[derive(Clone)]
-pub struct EnforcementStrategy<Strategy: RelayStrategy> {
-	strategy: Strategy,
+/// Reference data for participating in relay
+pub struct RelayReference<
+	P: MessageLane,
+	SourceClient: MessageLaneSourceClient<P>,
+	TargetClient: MessageLaneTargetClient<P>,
+> {
+	/// The client that is connected to the message lane source node.
+	pub lane_source_client: SourceClient,
+	/// The client that is connected to the message lane target node.
+	pub lane_target_client: TargetClient,
+	/// Metrics reference.
+	pub metrics: Option<MessageLaneLoopMetrics>,
+	/// Messages size summary
+	pub selected_size: u32,
+
+	/// Hard check begin nonce
+	pub hard_selected_begin_nonce: MessageNonce,
+
+	/// Index by all ready nonces
+	pub index: usize,
+	/// Current nonce
+	pub nonce: MessageNonce,
+	/// Current nonce details
+	pub details: MessageDetails<P::SourceChainBalance>,
 }
 
-impl<Strategy: RelayStrategy> EnforcementStrategy<Strategy> {
-	pub fn new(strategy: Strategy) -> Self {
-		Self { strategy }
-	}
+/// Relay reference data
+pub struct RelayMessagesBatchReference<
+	P: MessageLane,
+	SourceClient: MessageLaneSourceClient<P>,
+	TargetClient: MessageLaneTargetClient<P>,
+> {
+	/// Maximal number of relayed messages in single delivery transaction.
+	pub max_messages_in_this_batch: MessageNonce,
+	/// Maximal cumulative dispatch weight of relayed messages in single delivery transaction.
+	pub max_messages_weight_in_single_batch: Weight,
+	/// Maximal cumulative size of relayed messages in single delivery transaction.
+	pub max_messages_size_in_single_batch: u32,
+	/// The client that is connected to the message lane source node.
+	pub lane_source_client: SourceClient,
+	/// The client that is connected to the message lane target node.
+	pub lane_target_client: TargetClient,
+	/// Metrics reference.
+	pub metrics: Option<MessageLaneLoopMetrics>,
+	/// Source queue.
+	pub nonces_queue: SourceRangesQueue<
+		P::SourceHeaderHash,
+		P::SourceHeaderNumber,
+		MessageDetailsMap<P::SourceChainBalance>,
+	>,
+	/// Source queue range
+	pub nonces_queue_range: Range<usize>,
 }
 
-impl<Strategy: RelayStrategy> EnforcementStrategy<Strategy> {
+/// Limits of the message race transactions.
+#[derive(Clone)]
+pub struct MessageRaceLimits;
+
+impl MessageRaceLimits {
 	pub async fn decide<
 		P: MessageLane,
 		SourceClient: MessageLaneSourceClient<P>,
 		TargetClient: MessageLaneTargetClient<P>,
 	>(
-		&mut self,
 		reference: RelayMessagesBatchReference<P, SourceClient, TargetClient>,
 	) -> Option<MessageNonce> {
 		let mut hard_selected_count = 0;
-		let mut soft_selected_count = 0;
 
 		let mut selected_weight = Weight::zero();
 		let mut selected_count: MessageNonce = 0;
@@ -67,17 +112,9 @@ impl<Strategy: RelayStrategy> EnforcementStrategy<Strategy> {
 			lane_target_client: reference.lane_target_client.clone(),
 			metrics: reference.metrics.clone(),
 
-			selected_reward: P::SourceChainBalance::zero(),
-			selected_cost: P::SourceChainBalance::zero(),
 			selected_size: 0,
 
-			total_reward: P::SourceChainBalance::zero(),
-			total_confirmations_cost: P::SourceChainBalance::zero(),
-			total_cost: P::SourceChainBalance::zero(),
-
 			hard_selected_begin_nonce,
-			selected_prepaid_nonces: 0,
-			selected_unpaid_weight: Weight::zero(),
 
 			index: 0,
 			nonce: 0,
@@ -85,7 +122,6 @@ impl<Strategy: RelayStrategy> EnforcementStrategy<Strategy> {
 				dispatch_weight: Weight::zero(),
 				size: 0,
 				reward: P::SourceChainBalance::zero(),
-				dispatch_fee_payment: DispatchFeePayment::AtSourceChain,
 			},
 		};
 
@@ -148,74 +184,14 @@ impl<Strategy: RelayStrategy> EnforcementStrategy<Strategy> {
 			}
 			relay_reference.selected_size = new_selected_size;
 
-			// If dispatch fee has been paid at the source chain, it means that it is **relayer**
-			// who's paying for dispatch at the target chain AND reward must cover this dispatch
-			// fee.
-			//
-			// If dispatch fee is paid at the target chain, it means that it'll be withdrawn from
-			// the dispatch origin account AND reward is not covering this fee.
-			//
-			// So in the latter case we're not adding the dispatch weight to the delivery
-			// transaction weight.
-			let mut new_selected_prepaid_nonces = relay_reference.selected_prepaid_nonces;
-			let new_selected_unpaid_weight = match details.dispatch_fee_payment {
-				DispatchFeePayment::AtSourceChain => {
-					new_selected_prepaid_nonces += 1;
-					relay_reference.selected_unpaid_weight.saturating_add(details.dispatch_weight)
-				},
-				DispatchFeePayment::AtTargetChain => relay_reference.selected_unpaid_weight,
-			};
-			relay_reference.selected_prepaid_nonces = new_selected_prepaid_nonces;
-			relay_reference.selected_unpaid_weight = new_selected_unpaid_weight;
-
-			// now the message has passed all 'strong' checks, and we CAN deliver it. But do we WANT
-			// to deliver it? It depends on the relayer strategy.
-			if self.strategy.decide(&mut relay_reference).await {
-				soft_selected_count = index + 1;
-			}
-
 			hard_selected_count = index + 1;
 			selected_weight = new_selected_weight;
 			selected_count = new_selected_count;
 		}
 
-		if hard_selected_count != soft_selected_count {
-			let hard_selected_end_nonce =
-				hard_selected_begin_nonce + hard_selected_count as MessageNonce - 1;
-			let soft_selected_begin_nonce = hard_selected_begin_nonce;
-			let soft_selected_end_nonce =
-				soft_selected_begin_nonce + soft_selected_count as MessageNonce - 1;
-			log::warn!(
-				target: "bridge",
-				"Relayer may deliver nonces [{:?}; {:?}], but because of its strategy it has selected \
-				nonces [{:?}; {:?}].",
-				hard_selected_begin_nonce,
-				hard_selected_end_nonce,
-				soft_selected_begin_nonce,
-				soft_selected_end_nonce,
-			);
-
-			hard_selected_count = soft_selected_count;
-		}
-
 		if hard_selected_count != 0 {
-			if relay_reference.selected_reward != P::SourceChainBalance::zero() &&
-				relay_reference.selected_cost != P::SourceChainBalance::zero()
-			{
-				log::trace!(
-					target: "bridge",
-					"Expected reward from delivering nonces [{:?}; {:?}] is: {:?} - {:?} = {:?}",
-					hard_selected_begin_nonce,
-					hard_selected_begin_nonce + hard_selected_count as MessageNonce - 1,
-					&relay_reference.selected_reward,
-					&relay_reference.selected_cost,
-					relay_reference.selected_reward - relay_reference.selected_cost,
-				);
-			}
-
 			let selected_max_nonce =
 				hard_selected_begin_nonce + hard_selected_count as MessageNonce - 1;
-			self.strategy.on_final_decision(&relay_reference);
 			Some(selected_max_nonce)
 		} else {
 			None
diff --git a/bridges/relays/messages/src/metrics.rs b/bridges/relays/messages/src/metrics.rs
index f5cc8831c0286743eaad9b77a00b0d21571f20b3..4decb7e092e7108a89a0bbf1c1c80fd49435c1d4 100644
--- a/bridges/relays/messages/src/metrics.rs
+++ b/bridges/relays/messages/src/metrics.rs
@@ -24,7 +24,7 @@ use crate::{
 use bp_messages::MessageNonce;
 use finality_relay::SyncLoopMetrics;
 use relay_utils::metrics::{
-	metric_name, register, Counter, GaugeVec, Metric, Opts, PrometheusError, Registry, U64,
+	metric_name, register, GaugeVec, Metric, Opts, PrometheusError, Registry, U64,
 };
 
 /// Message lane relay metrics.
@@ -39,17 +39,11 @@ pub struct MessageLaneLoopMetrics {
 	/// Lane state nonces: "source_latest_generated", "source_latest_confirmed",
 	/// "target_latest_received", "target_latest_confirmed".
 	lane_state_nonces: GaugeVec<U64>,
-	/// Count of unprofitable message delivery transactions that we have submitted so far.
-	unprofitable_delivery_transactions: Counter<U64>,
 }
 
 impl MessageLaneLoopMetrics {
 	/// Create and register messages loop metrics.
-	pub fn new(
-		prefix: Option<&str>,
-		source_name: &str,
-		target_name: &str,
-	) -> Result<Self, PrometheusError> {
+	pub fn new(prefix: Option<&str>) -> Result<Self, PrometheusError> {
 		Ok(MessageLaneLoopMetrics {
 			source_to_target_finality_metrics: SyncLoopMetrics::new(
 				prefix,
@@ -65,13 +59,6 @@ impl MessageLaneLoopMetrics {
 				Opts::new(metric_name(prefix, "lane_state_nonces"), "Nonces of the lane state"),
 				&["type"],
 			)?,
-			unprofitable_delivery_transactions: Counter::new(
-				metric_name(prefix, "unprofitable_delivery_transactions"),
-				format!(
-					"Count of unprofitable message delivery transactions from {} to {}",
-					source_name, target_name
-				),
-			)?,
 		})
 	}
 
@@ -140,11 +127,6 @@ impl MessageLaneLoopMetrics {
 			.with_label_values(&["target_latest_confirmed"])
 			.set(target_latest_confirmed_nonce);
 	}
-
-	/// Note unprofitable delivery transaction.
-	pub fn note_unprofitable_delivery_transactions(&self) {
-		self.unprofitable_delivery_transactions.inc()
-	}
 }
 
 impl Metric for MessageLaneLoopMetrics {
@@ -152,7 +134,6 @@ impl Metric for MessageLaneLoopMetrics {
 		self.source_to_target_finality_metrics.register(registry)?;
 		self.target_to_source_finality_metrics.register(registry)?;
 		register(self.lane_state_nonces.clone(), registry)?;
-		register(self.unprofitable_delivery_transactions.clone(), registry)?;
 		Ok(())
 	}
 }
diff --git a/bridges/relays/messages/src/relay_strategy/altruistic_strategy.rs b/bridges/relays/messages/src/relay_strategy/altruistic_strategy.rs
deleted file mode 100644
index 7e00678e1317f100e0685e918dec8316cdad3a9f..0000000000000000000000000000000000000000
--- a/bridges/relays/messages/src/relay_strategy/altruistic_strategy.rs
+++ /dev/null
@@ -1,81 +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/>.
-
-//! Altruistic relay strategy
-
-use async_trait::async_trait;
-
-use crate::{
-	message_lane::MessageLane,
-	message_lane_loop::{
-		SourceClient as MessageLaneSourceClient, TargetClient as MessageLaneTargetClient,
-	},
-	relay_strategy::{RelayReference, RelayStrategy},
-};
-
-/// The relayer doesn't care about rewards.
-#[derive(Clone)]
-pub struct AltruisticStrategy;
-
-#[async_trait]
-impl RelayStrategy for AltruisticStrategy {
-	async fn decide<
-		P: MessageLane,
-		SourceClient: MessageLaneSourceClient<P>,
-		TargetClient: MessageLaneTargetClient<P>,
-	>(
-		&mut self,
-		reference: &mut RelayReference<P, SourceClient, TargetClient>,
-	) -> bool {
-		// We don't care about costs and rewards, but we want to report unprofitable transactions.
-		if let Err(e) = reference.update_cost_and_reward().await {
-			log::debug!(
-				target: "bridge",
-				"Failed to update transaction cost and reward: {:?}. \
-				The `unprofitable_delivery_transactions` metric will be inaccurate",
-				e,
-			);
-		}
-
-		true
-	}
-
-	fn on_final_decision<
-		P: MessageLane,
-		SourceClient: MessageLaneSourceClient<P>,
-		TargetClient: MessageLaneTargetClient<P>,
-	>(
-		&self,
-		reference: &RelayReference<P, SourceClient, TargetClient>,
-	) {
-		if let Some(ref metrics) = reference.metrics {
-			if !reference.is_profitable() {
-				log::debug!(
-					target: "bridge",
-					"The relayer has submitted unprofitable {} -> {} message delivery transaction \
-					with {} messages: total cost = {:?}, total reward = {:?}",
-					P::SOURCE_NAME,
-					P::TARGET_NAME,
-					reference.index + 1,
-					reference.total_cost,
-					reference.total_reward,
-				);
-
-				metrics.note_unprofitable_delivery_transactions();
-			}
-		}
-	}
-}
diff --git a/bridges/relays/messages/src/relay_strategy/mix_strategy.rs b/bridges/relays/messages/src/relay_strategy/mix_strategy.rs
deleted file mode 100644
index 331f77b012d22112e4730d6ff5a9d9a91e94726a..0000000000000000000000000000000000000000
--- a/bridges/relays/messages/src/relay_strategy/mix_strategy.rs
+++ /dev/null
@@ -1,72 +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/>.
-
-//! Adapter for using `enum RelayerMode` in a context which requires `RelayStrategy`.
-
-use async_trait::async_trait;
-
-use crate::{
-	message_lane::MessageLane,
-	message_lane_loop::{
-		RelayerMode, SourceClient as MessageLaneSourceClient,
-		TargetClient as MessageLaneTargetClient,
-	},
-	relay_strategy::{AltruisticStrategy, RationalStrategy, RelayReference, RelayStrategy},
-};
-
-/// `RelayerMode` adapter.
-#[derive(Clone)]
-pub struct MixStrategy {
-	relayer_mode: RelayerMode,
-}
-
-impl MixStrategy {
-	/// Create mix strategy instance
-	pub fn new(relayer_mode: RelayerMode) -> Self {
-		Self { relayer_mode }
-	}
-}
-
-#[async_trait]
-impl RelayStrategy for MixStrategy {
-	async fn decide<
-		P: MessageLane,
-		SourceClient: MessageLaneSourceClient<P>,
-		TargetClient: MessageLaneTargetClient<P>,
-	>(
-		&mut self,
-		reference: &mut RelayReference<P, SourceClient, TargetClient>,
-	) -> bool {
-		match self.relayer_mode {
-			RelayerMode::Altruistic => AltruisticStrategy.decide(reference).await,
-			RelayerMode::Rational => RationalStrategy.decide(reference).await,
-		}
-	}
-
-	fn on_final_decision<
-		P: MessageLane,
-		SourceClient: MessageLaneSourceClient<P>,
-		TargetClient: MessageLaneTargetClient<P>,
-	>(
-		&self,
-		reference: &RelayReference<P, SourceClient, TargetClient>,
-	) {
-		match self.relayer_mode {
-			RelayerMode::Altruistic => AltruisticStrategy.on_final_decision(reference),
-			RelayerMode::Rational => RationalStrategy.on_final_decision(reference),
-		}
-	}
-}
diff --git a/bridges/relays/messages/src/relay_strategy/mod.rs b/bridges/relays/messages/src/relay_strategy/mod.rs
deleted file mode 100644
index aa28e63582fd7f9b504a380c0e6191933a4353fe..0000000000000000000000000000000000000000
--- a/bridges/relays/messages/src/relay_strategy/mod.rs
+++ /dev/null
@@ -1,224 +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/>.
-
-//! Relayer strategy
-
-use async_trait::async_trait;
-use bp_messages::{MessageNonce, Weight};
-use sp_arithmetic::traits::Saturating;
-use std::ops::Range;
-
-use crate::{
-	message_lane::MessageLane,
-	message_lane_loop::{
-		MessageDetails, MessageDetailsMap, SourceClient as MessageLaneSourceClient,
-		TargetClient as MessageLaneTargetClient,
-	},
-	message_race_strategy::SourceRangesQueue,
-	metrics::MessageLaneLoopMetrics,
-};
-
-pub(crate) use self::enforcement_strategy::*;
-pub use self::{altruistic_strategy::*, mix_strategy::*, rational_strategy::*};
-
-mod altruistic_strategy;
-mod enforcement_strategy;
-mod mix_strategy;
-mod rational_strategy;
-
-/// Relayer strategy trait
-#[async_trait]
-pub trait RelayStrategy: 'static + Clone + Send + Sync {
-	/// The relayer decide how to process nonce by reference.
-	/// From given set of source nonces, that are ready to be delivered, select nonces
-	/// to fit into single delivery transaction.
-	///
-	/// The function returns last nonce that must be delivered to the target chain.
-	async fn decide<
-		P: MessageLane,
-		SourceClient: MessageLaneSourceClient<P>,
-		TargetClient: MessageLaneTargetClient<P>,
-	>(
-		&mut self,
-		reference: &mut RelayReference<P, SourceClient, TargetClient>,
-	) -> bool;
-
-	/// Notification that the following maximal nonce has been selected for the delivery.
-	fn on_final_decision<
-		P: MessageLane,
-		SourceClient: MessageLaneSourceClient<P>,
-		TargetClient: MessageLaneTargetClient<P>,
-	>(
-		&self,
-		reference: &RelayReference<P, SourceClient, TargetClient>,
-	);
-}
-
-/// Total cost of mesage delivery and confirmation.
-struct MessagesDeliveryCost<SourceChainBalance> {
-	/// Cost of message delivery transaction.
-	pub delivery_transaction_cost: SourceChainBalance,
-	/// Cost of confirmation delivery transaction.
-	pub confirmation_transaction_cost: SourceChainBalance,
-}
-
-/// Reference data for participating in relay
-pub struct RelayReference<
-	P: MessageLane,
-	SourceClient: MessageLaneSourceClient<P>,
-	TargetClient: MessageLaneTargetClient<P>,
-> {
-	/// The client that is connected to the message lane source node.
-	pub lane_source_client: SourceClient,
-	/// The client that is connected to the message lane target node.
-	pub lane_target_client: TargetClient,
-	/// Metrics reference.
-	pub metrics: Option<MessageLaneLoopMetrics>,
-	/// Current block reward summary
-	pub selected_reward: P::SourceChainBalance,
-	/// Current block cost summary
-	pub selected_cost: P::SourceChainBalance,
-	/// Messages size summary
-	pub selected_size: u32,
-
-	/// Current block reward summary
-	pub total_reward: P::SourceChainBalance,
-	/// All confirmations cost
-	pub total_confirmations_cost: P::SourceChainBalance,
-	/// Current block cost summary
-	pub total_cost: P::SourceChainBalance,
-
-	/// Hard check begin nonce
-	pub hard_selected_begin_nonce: MessageNonce,
-	/// Count prepaid nonces
-	pub selected_prepaid_nonces: MessageNonce,
-	/// Unpaid nonces weight summary
-	pub selected_unpaid_weight: Weight,
-
-	/// Index by all ready nonces
-	pub index: usize,
-	/// Current nonce
-	pub nonce: MessageNonce,
-	/// Current nonce details
-	pub details: MessageDetails<P::SourceChainBalance>,
-}
-
-impl<
-		P: MessageLane,
-		SourceClient: MessageLaneSourceClient<P>,
-		TargetClient: MessageLaneTargetClient<P>,
-	> RelayReference<P, SourceClient, TargetClient>
-{
-	/// Returns whether the current `RelayReference` is profitable.
-	pub fn is_profitable(&self) -> bool {
-		self.total_reward >= self.total_cost
-	}
-
-	async fn estimate_messages_delivery_cost(
-		&self,
-	) -> Result<MessagesDeliveryCost<P::SourceChainBalance>, TargetClient::Error> {
-		// technically, multiple confirmations will be delivered in a single transaction,
-		// meaning less loses for relayer. But here we don't know the final relayer yet, so
-		// we're adding a separate transaction for every message. Normally, this cost is covered
-		// by the message sender. Probably reconsider this?
-		let confirmation_transaction_cost =
-			self.lane_source_client.estimate_confirmation_transaction().await;
-
-		let delivery_transaction_cost = self
-			.lane_target_client
-			.estimate_delivery_transaction_in_source_tokens(
-				self.hard_selected_begin_nonce..=
-					(self.hard_selected_begin_nonce + self.index as MessageNonce),
-				self.selected_prepaid_nonces,
-				self.selected_unpaid_weight,
-				self.selected_size,
-			)
-			.await?;
-
-		Ok(MessagesDeliveryCost { confirmation_transaction_cost, delivery_transaction_cost })
-	}
-
-	async fn update_cost_and_reward(&mut self) -> Result<(), TargetClient::Error> {
-		let prev_is_profitable = self.is_profitable();
-		let prev_total_cost = self.total_cost;
-		let prev_total_reward = self.total_reward;
-
-		let MessagesDeliveryCost { confirmation_transaction_cost, delivery_transaction_cost } =
-			self.estimate_messages_delivery_cost().await?;
-		self.total_confirmations_cost =
-			self.total_confirmations_cost.saturating_add(confirmation_transaction_cost);
-		self.total_reward = self.total_reward.saturating_add(self.details.reward);
-		self.total_cost = self.total_confirmations_cost.saturating_add(delivery_transaction_cost);
-
-		if prev_is_profitable && !self.is_profitable() {
-			// if it is the first message that makes reward less than cost, let's log it
-			log::debug!(
-				target: "bridge",
-				"Message with nonce {} (reward = {:?}) changes total cost {:?}->{:?} and makes it larger than \
-				total reward {:?}->{:?}",
-				self.nonce,
-				self.details.reward,
-				prev_total_cost,
-				self.total_cost,
-				prev_total_reward,
-				self.total_reward,
-			);
-		} else if !prev_is_profitable && self.is_profitable() {
-			// if this message makes batch profitable again, let's log it
-			log::debug!(
-				target: "bridge",
-				"Message with nonce {} (reward = {:?}) changes total cost {:?}->{:?} and makes it less than or \
-				equal to the total reward {:?}->{:?} (again)",
-				self.nonce,
-				self.details.reward,
-				prev_total_cost,
-				self.total_cost,
-				prev_total_reward,
-				self.total_reward,
-			);
-		}
-
-		Ok(())
-	}
-}
-
-/// Relay reference data
-pub struct RelayMessagesBatchReference<
-	P: MessageLane,
-	SourceClient: MessageLaneSourceClient<P>,
-	TargetClient: MessageLaneTargetClient<P>,
-> {
-	/// Maximal number of relayed messages in single delivery transaction.
-	pub max_messages_in_this_batch: MessageNonce,
-	/// Maximal cumulative dispatch weight of relayed messages in single delivery transaction.
-	pub max_messages_weight_in_single_batch: Weight,
-	/// Maximal cumulative size of relayed messages in single delivery transaction.
-	pub max_messages_size_in_single_batch: u32,
-	/// The client that is connected to the message lane source node.
-	pub lane_source_client: SourceClient,
-	/// The client that is connected to the message lane target node.
-	pub lane_target_client: TargetClient,
-	/// Metrics reference.
-	pub metrics: Option<MessageLaneLoopMetrics>,
-	/// Source queue.
-	pub nonces_queue: SourceRangesQueue<
-		P::SourceHeaderHash,
-		P::SourceHeaderNumber,
-		MessageDetailsMap<P::SourceChainBalance>,
-	>,
-	/// Source queue range
-	pub nonces_queue_range: Range<usize>,
-}
diff --git a/bridges/relays/messages/src/relay_strategy/rational_strategy.rs b/bridges/relays/messages/src/relay_strategy/rational_strategy.rs
deleted file mode 100644
index 1791670fa45a87e83a4cfb6dbd54f41164c72c11..0000000000000000000000000000000000000000
--- a/bridges/relays/messages/src/relay_strategy/rational_strategy.rs
+++ /dev/null
@@ -1,75 +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/>.
-
-//! Rational relay strategy
-
-use async_trait::async_trait;
-
-use crate::{
-	message_lane::MessageLane,
-	message_lane_loop::{
-		SourceClient as MessageLaneSourceClient, TargetClient as MessageLaneTargetClient,
-	},
-	relay_strategy::{RelayReference, RelayStrategy},
-};
-
-/// The relayer will deliver all messages and confirmations as long as he's not losing any
-/// funds.
-#[derive(Clone)]
-pub struct RationalStrategy;
-
-#[async_trait]
-impl RelayStrategy for RationalStrategy {
-	async fn decide<
-		P: MessageLane,
-		SourceClient: MessageLaneSourceClient<P>,
-		TargetClient: MessageLaneTargetClient<P>,
-	>(
-		&mut self,
-		reference: &mut RelayReference<P, SourceClient, TargetClient>,
-	) -> bool {
-		if let Err(e) = reference.update_cost_and_reward().await {
-			log::debug!(
-				target: "bridge",
-				"Failed to update transaction cost and reward: {:?}. No nonces selected for delivery",
-				e,
-			);
-
-			return false
-		}
-
-		// Rational relayer never wants to lose his funds.
-		if reference.is_profitable() {
-			reference.selected_reward = reference.total_reward;
-			reference.selected_cost = reference.total_cost;
-			return true
-		}
-
-		false
-	}
-
-	fn on_final_decision<
-		P: MessageLane,
-		SourceClient: MessageLaneSourceClient<P>,
-		TargetClient: MessageLaneTargetClient<P>,
-	>(
-		&self,
-		_reference: &RelayReference<P, SourceClient, TargetClient>,
-	) {
-		// rational relayer would never submit unprofitable transactions, so we don't need to do
-		// anything here
-	}
-}