diff --git a/bridges/primitives/runtime/src/chain.rs b/bridges/primitives/runtime/src/chain.rs
index 1c80622472291e2ab8afbf4b446c6bff823cc5d6..5a7fafe9f67c0b0917cf52f0560ee48001aa0d8e 100644
--- a/bridges/primitives/runtime/src/chain.rs
+++ b/bridges/primitives/runtime/src/chain.rs
@@ -27,7 +27,7 @@ use sp_runtime::{
 use sp_std::{convert::TryFrom, fmt::Debug, hash::Hash, str::FromStr, vec, vec::Vec};
 
 /// Chain call, that is either SCALE-encoded, or decoded.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
 pub enum EncodedOrDecodedCall<ChainCall> {
 	/// The call that is SCALE-encoded.
 	///
diff --git a/bridges/relays/client-millau/src/lib.rs b/bridges/relays/client-millau/src/lib.rs
index e131f42494b314b4ed79fd8df96260eae5a5d620..eae9d9b4586a539efdede9d1308f64c66b8844bf 100644
--- a/bridges/relays/client-millau/src/lib.rs
+++ b/bridges/relays/client-millau/src/lib.rs
@@ -31,7 +31,7 @@ use std::time::Duration;
 pub type HeaderId = relay_utils::HeaderId<millau_runtime::Hash, millau_runtime::BlockNumber>;
 
 /// Millau chain definition.
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone, Copy, PartialEq)]
 pub struct Millau;
 
 impl ChainBase for Millau {
@@ -154,8 +154,8 @@ impl TransactionSignScheme for Millau {
 		let extra = &tx.signature.as_ref()?.2;
 		Some(UnsignedTransaction {
 			call: tx.function.into(),
-			nonce: Compact::<IndexOf<Self::Chain>>::decode(&mut &extra.4.encode()[..]).ok()?.into(),
-			tip: Compact::<BalanceOf<Self::Chain>>::decode(&mut &extra.6.encode()[..])
+			nonce: Compact::<IndexOf<Self::Chain>>::decode(&mut &extra.5.encode()[..]).ok()?.into(),
+			tip: Compact::<BalanceOf<Self::Chain>>::decode(&mut &extra.7.encode()[..])
 				.ok()?
 				.into(),
 		})
@@ -167,3 +167,32 @@ pub type SigningParams = sp_core::sr25519::Pair;
 
 /// Millau header type used in headers sync.
 pub type SyncHeader = relay_substrate_client::SyncHeader<millau_runtime::Header>;
+
+#[cfg(test)]
+mod tests {
+	use super::*;
+	use relay_substrate_client::TransactionEra;
+
+	#[test]
+	fn parse_transaction_works() {
+		let unsigned = UnsignedTransaction {
+			call: millau_runtime::Call::System(millau_runtime::SystemCall::remark {
+				remark: b"Hello world!".to_vec(),
+			})
+			.into(),
+			nonce: 777,
+			tip: 888,
+		};
+		let signed_transaction = Millau::sign_transaction(SignParam {
+			spec_version: 42,
+			transaction_version: 50000,
+			genesis_hash: [42u8; 64].into(),
+			signer: sp_core::sr25519::Pair::from_seed_slice(&[1u8; 32]).unwrap(),
+			era: TransactionEra::immortal(),
+			unsigned: unsigned.clone(),
+		})
+		.unwrap();
+		let parsed_transaction = Millau::parse_transaction(signed_transaction).unwrap();
+		assert_eq!(parsed_transaction, unsigned);
+	}
+}
diff --git a/bridges/relays/client-rialto/src/lib.rs b/bridges/relays/client-rialto/src/lib.rs
index 78e5f4431493d7f26aaea944ef72ed82a746d54b..858227e8083f653f56e0b5af177dd40dd2f608af 100644
--- a/bridges/relays/client-rialto/src/lib.rs
+++ b/bridges/relays/client-rialto/src/lib.rs
@@ -31,7 +31,7 @@ use std::time::Duration;
 pub type HeaderId = relay_utils::HeaderId<rialto_runtime::Hash, rialto_runtime::BlockNumber>;
 
 /// Rialto chain definition
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone, Copy, PartialEq)]
 pub struct Rialto;
 
 impl ChainBase for Rialto {
@@ -152,8 +152,8 @@ impl TransactionSignScheme for Rialto {
 		let extra = &tx.signature.as_ref()?.2;
 		Some(UnsignedTransaction {
 			call: tx.function.into(),
-			nonce: Compact::<IndexOf<Self::Chain>>::decode(&mut &extra.4.encode()[..]).ok()?.into(),
-			tip: Compact::<BalanceOf<Self::Chain>>::decode(&mut &extra.6.encode()[..])
+			nonce: Compact::<IndexOf<Self::Chain>>::decode(&mut &extra.5.encode()[..]).ok()?.into(),
+			tip: Compact::<BalanceOf<Self::Chain>>::decode(&mut &extra.7.encode()[..])
 				.ok()?
 				.into(),
 		})
@@ -165,3 +165,32 @@ pub type SigningParams = sp_core::sr25519::Pair;
 
 /// Rialto header type used in headers sync.
 pub type SyncHeader = relay_substrate_client::SyncHeader<rialto_runtime::Header>;
+
+#[cfg(test)]
+mod tests {
+	use super::*;
+	use relay_substrate_client::TransactionEra;
+
+	#[test]
+	fn parse_transaction_works() {
+		let unsigned = UnsignedTransaction {
+			call: rialto_runtime::Call::System(rialto_runtime::SystemCall::remark {
+				remark: b"Hello world!".to_vec(),
+			})
+			.into(),
+			nonce: 777,
+			tip: 888,
+		};
+		let signed_transaction = Rialto::sign_transaction(SignParam {
+			spec_version: 42,
+			transaction_version: 50000,
+			genesis_hash: [42u8; 32].into(),
+			signer: sp_core::sr25519::Pair::from_seed_slice(&[1u8; 32]).unwrap(),
+			era: TransactionEra::immortal(),
+			unsigned: unsigned.clone(),
+		})
+		.unwrap();
+		let parsed_transaction = Rialto::parse_transaction(signed_transaction).unwrap();
+		assert_eq!(parsed_transaction, unsigned);
+	}
+}
diff --git a/bridges/relays/client-substrate/src/chain.rs b/bridges/relays/client-substrate/src/chain.rs
index c3b0c32d5a4c014a85b12adfd3cb5dc8275439ee..60adfb0a88ac2dd97ddaed1974b30bd68f14a6ad 100644
--- a/bridges/relays/client-substrate/src/chain.rs
+++ b/bridges/relays/client-substrate/src/chain.rs
@@ -134,7 +134,7 @@ pub trait BlockWithJustification<Header> {
 }
 
 /// Transaction before it is signed.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct UnsignedTransaction<C: Chain> {
 	/// Runtime call of this transaction.
 	pub call: EncodedOrDecodedCall<C::Call>,