diff --git a/bridges/bin/millau/node/Cargo.toml b/bridges/bin/millau/node/Cargo.toml
index b07cc29a06adcbe2037c27df1c4e3a03aec87d10..3825b92b703c24307004b700513ff769c3553fdf 100644
--- a/bridges/bin/millau/node/Cargo.toml
+++ b/bridges/bin/millau/node/Cargo.toml
@@ -10,7 +10,7 @@ repository = "https://github.com/paritytech/parity-bridges-common/"
 license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
-clap = { version = "3.0", features = ["derive"] }
+clap = { version = "3.1", features = ["derive"] }
 jsonrpc-core = "18.0"
 serde_json = "1.0.59"
 
diff --git a/bridges/bin/millau/node/src/service.rs b/bridges/bin/millau/node/src/service.rs
index db64af878ff3229ab7ef5868ba6146ebb59451d3..15f88269aa9c6971dfe67fdc40d7568b090dc01a 100644
--- a/bridges/bin/millau/node/src/service.rs
+++ b/bridges/bin/millau/node/src/service.rs
@@ -37,7 +37,6 @@ use sc_finality_grandpa::SharedVoterState;
 use sc_keystore::LocalKeystore;
 use sc_service::{error::Error as ServiceError, Configuration, TaskManager};
 use sc_telemetry::{Telemetry, TelemetryWorker};
-use sp_consensus::SlotData;
 use sp_consensus_aura::sr25519::AuthorityPair as AuraPair;
 use std::{sync::Arc, time::Duration};
 
@@ -141,7 +140,7 @@ pub fn new_partial(
 		telemetry.as_ref().map(|x| x.handle()),
 	)?;
 
-	let slot_duration = sc_consensus_aura::slot_duration(&*client)?.slot_duration();
+	let slot_duration = sc_consensus_aura::slot_duration(&*client)?;
 
 	let import_queue =
 		sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _, _>(ImportQueueParams {
@@ -152,7 +151,7 @@ pub fn new_partial(
 				let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
 
 				let slot =
-					sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration(
+					sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration(
 						*timestamp,
 						slot_duration,
 					);
@@ -349,7 +348,6 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
 			sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone());
 
 		let slot_duration = sc_consensus_aura::slot_duration(&*client)?;
-		let raw_slot_duration = slot_duration.slot_duration();
 
 		let aura = sc_consensus_aura::start_aura::<AuraPair, _, _, _, _, _, _, _, _, _, _, _>(
 			StartAuraParams {
@@ -362,9 +360,9 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
 					let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
 
 					let slot =
-						sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration(
+						sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration(
 							*timestamp,
-							raw_slot_duration,
+							slot_duration,
 						);
 
 					Ok((timestamp, slot))
diff --git a/bridges/bin/millau/runtime/Cargo.toml b/bridges/bin/millau/runtime/Cargo.toml
index b9f64d1f5d3357281473f55e6943deb3e9d292cd..162404b77e7de4bb8c9bc22125ecb628cc0c8d4c 100644
--- a/bridges/bin/millau/runtime/Cargo.toml
+++ b/bridges/bin/millau/runtime/Cargo.toml
@@ -9,9 +9,9 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
 hex-literal = "0.3"
-codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive"] }
+codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] }
 libsecp256k1 = { version = "0.7", optional = true, default-features = false, features = ["hmac"] }
-scale-info = { version = "1.0", default-features = false, features = ["derive"] }
+scale-info = { version = "2.0.1", default-features = false, features = ["derive"] }
 serde = { version = "1.0", optional = true, features = ["derive"] }
 
 # Bridge dependencies
@@ -124,7 +124,7 @@ std = [
 ]
 runtime-benchmarks = [
 	"bridge-runtime-common/runtime-benchmarks",
-	"frame-benchmarking",
+	"frame-benchmarking/runtime-benchmarks",
 	"frame-support/runtime-benchmarks",
 	"frame-system/runtime-benchmarks",
 	"libsecp256k1",
diff --git a/bridges/bin/millau/runtime/src/lib.rs b/bridges/bin/millau/runtime/src/lib.rs
index 5f8e503233557000f1eaf5daed9dcb2bcb22a82f..d2da5affb235b17ca0d0014c05bcdbfc67d6cee8 100644
--- a/bridges/bin/millau/runtime/src/lib.rs
+++ b/bridges/bin/millau/runtime/src/lib.rs
@@ -21,8 +21,6 @@
 #![recursion_limit = "256"]
 // Runtime-generated enums
 #![allow(clippy::large_enum_variant)]
-// Runtime-generated DecodeLimit::decode_all_With_depth_limit
-#![allow(clippy::unnecessary_mut_passed)]
 // From construct_runtime macro
 #![allow(clippy::from_over_into)]
 
@@ -543,6 +541,7 @@ pub type SignedBlock = generic::SignedBlock<Block>;
 pub type BlockId = generic::BlockId<Block>;
 /// The SignedExtension to the basic transaction logic.
 pub type SignedExtra = (
+	frame_system::CheckNonZeroSender<Runtime>,
 	frame_system::CheckSpecVersion<Runtime>,
 	frame_system::CheckTxVersion<Runtime>,
 	frame_system::CheckGenesis<Runtime>,
@@ -913,7 +912,6 @@ impl_runtime_apis! {
 			add_benchmark!(params, batches, pallet_bridge_grandpa, BridgeRialtoGrandpa);
 			add_benchmark!(params, batches, pallet_bridge_token_swap, BridgeRialtoTokenSwap);
 
-			if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) }
 			Ok(batches)
 		}
 	}
diff --git a/bridges/bin/rialto-parachain/node/Cargo.toml b/bridges/bin/rialto-parachain/node/Cargo.toml
index 81ed68a127b230bc322e56d09e9c01061b85e022..41021a35ed2b002e8baaa0b2e399d3fce3a6bed8 100644
--- a/bridges/bin/rialto-parachain/node/Cargo.toml
+++ b/bridges/bin/rialto-parachain/node/Cargo.toml
@@ -18,10 +18,10 @@ default = []
 runtime-benchmarks = ['rialto-parachain-runtime/runtime-benchmarks']
 
 [dependencies]
-clap = { version = "3.0", features = ["derive"] }
+clap = { version = "3.1", features = ["derive"] }
 derive_more = '0.99.2'
 log = '0.4.14'
-codec = { package = 'parity-scale-codec', version = '2.0.0' }
+codec = { package = 'parity-scale-codec', version = '3.0.0' }
 serde = { version = '1.0', features = ['derive'] }
 hex-literal = '0.3.1'
 
@@ -81,7 +81,7 @@ cumulus-client-service = { git = "https://github.com/paritytech/cumulus", branch
 cumulus-primitives-core = { git = "https://github.com/paritytech/cumulus", branch = "master" }
 cumulus-primitives-parachain-inherent = { git = "https://github.com/paritytech/cumulus", branch = "master" }
 cumulus-relay-chain-interface = { git = "https://github.com/paritytech/cumulus", branch = "master" }
-cumulus-relay-chain-local = { git = "https://github.com/paritytech/cumulus", branch = "master" }
+cumulus-relay-chain-inprocess-interface = { git = "https://github.com/paritytech/cumulus", branch = "master" }
 
 # Polkadot dependencies
 polkadot-cli = { git = "https://github.com/paritytech/polkadot", branch = "master" }
diff --git a/bridges/bin/rialto-parachain/node/src/cli.rs b/bridges/bin/rialto-parachain/node/src/cli.rs
index 7abb72cb876cd3f24c8959725603129f11b89b05..89d049f022e3e7185b1baff8653cd44e01153ebe 100644
--- a/bridges/bin/rialto-parachain/node/src/cli.rs
+++ b/bridges/bin/rialto-parachain/node/src/cli.rs
@@ -15,7 +15,7 @@
 // along with Parity Bridges Common.  If not, see <http://www.gnu.org/licenses/>.
 
 use crate::chain_spec;
-use clap::{AppSettings, Parser};
+use clap::Parser;
 use std::path::PathBuf;
 
 /// Sub-commands supported by the collator.
@@ -94,11 +94,11 @@ pub struct ExportGenesisWasmCommand {
 }
 
 #[derive(Debug, Parser)]
-#[clap(setting(
-	AppSettings::PropagateVersion |
-	AppSettings::ArgsNegateSubcommands |
-	AppSettings::SubcommandsNegateReqs,
-))]
+#[clap(
+	propagate_version = true,
+	args_conflicts_with_subcommands = true,
+	subcommand_negates_reqs = true
+)]
 pub struct Cli {
 	#[clap(subcommand)]
 	pub subcommand: Option<Subcommand>,
diff --git a/bridges/bin/rialto-parachain/node/src/command.rs b/bridges/bin/rialto-parachain/node/src/command.rs
index 9a69042a803429d36dbbe2f9c2905b7dc9c8e229..c47e742675da169002019f9aacd3fcce811ffb81 100644
--- a/bridges/bin/rialto-parachain/node/src/command.rs
+++ b/bridges/bin/rialto-parachain/node/src/command.rs
@@ -265,6 +265,7 @@ pub fn run() -> Result<()> {
 			},
 		None => {
 			let runner = cli.create_runner(&cli.run.normalize())?;
+			let collator_options = cli.run.collator_options();
 
 			runner.run_node_until_exit(|config| async move {
 				let para_id =
@@ -278,7 +279,7 @@ pub fn run() -> Result<()> {
 				let id = ParaId::from(cli.parachain_id.or(para_id).expect("Missing ParaId"));
 
 				let parachain_account =
-					AccountIdConversion::<polkadot_primitives::v0::AccountId>::into_account(&id);
+					AccountIdConversion::<polkadot_primitives::v2::AccountId>::into_account(&id);
 
 				let state_version =
 					RelayChainCli::native_runtime_version(&config.chain_spec).state_version();
@@ -298,7 +299,7 @@ pub fn run() -> Result<()> {
 				info!("Parachain genesis state: {}", genesis_state);
 				info!("Is collating: {}", if config.role.is_authority() { "yes" } else { "no" });
 
-				crate::service::start_node(config, polkadot_config, id)
+				crate::service::start_node(config, polkadot_config, collator_options, id)
 					.await
 					.map(|r| r.0)
 					.map_err(Into::into)
diff --git a/bridges/bin/rialto-parachain/node/src/service.rs b/bridges/bin/rialto-parachain/node/src/service.rs
index 61f705086e997665cdf632dc230ede91ebbb5682..a2299e17457d9266f88fecb94f00ee3424c9af55 100644
--- a/bridges/bin/rialto-parachain/node/src/service.rs
+++ b/bridges/bin/rialto-parachain/node/src/service.rs
@@ -28,6 +28,7 @@ use std::{sync::Arc, time::Duration};
 use rialto_parachain_runtime::RuntimeApi;
 
 // Cumulus Imports
+use cumulus_client_cli::CollatorOptions;
 use cumulus_client_consensus_aura::{AuraConsensus, BuildAuraConsensusParams, SlotProportion};
 use cumulus_client_consensus_common::ParachainConsensus;
 use cumulus_client_network::BlockAnnounceValidator;
@@ -35,8 +36,8 @@ use cumulus_client_service::{
 	prepare_node_config, start_collator, start_full_node, StartCollatorParams, StartFullNodeParams,
 };
 use cumulus_primitives_core::ParaId;
-use cumulus_relay_chain_interface::RelayChainInterface;
-use cumulus_relay_chain_local::build_relay_chain_interface;
+use cumulus_relay_chain_inprocess_interface::build_inprocess_relay_chain;
+use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface};
 
 // Substrate Imports
 use sc_client_api::ExecutorProvider;
@@ -45,7 +46,6 @@ use sc_network::NetworkService;
 use sc_service::{Configuration, PartialComponents, Role, TFullBackend, TFullClient, TaskManager};
 use sc_telemetry::{Telemetry, TelemetryHandle, TelemetryWorker, TelemetryWorkerHandle};
 use sp_api::ConstructRuntimeApi;
-use sp_consensus::SlotData;
 use sp_keystore::SyncCryptoStorePtr;
 use sp_runtime::traits::BlakeTwo256;
 use substrate_prometheus_endpoint::Registry;
@@ -195,6 +195,7 @@ where
 async fn start_node_impl<RuntimeApi, Executor, RB, BIQ, BIC>(
 	parachain_config: Configuration,
 	polkadot_config: Configuration,
+	collator_options: CollatorOptions,
 	id: ParaId,
 	rpc_ext_builder: RB,
 	build_import_queue: BIQ,
@@ -270,12 +271,16 @@ where
 	let (mut telemetry, telemetry_worker_handle) = params.other;
 
 	let mut task_manager = params.task_manager;
-	let (relay_chain_interface, collator_key) =
-		build_relay_chain_interface(polkadot_config, telemetry_worker_handle, &mut task_manager)
-			.map_err(|e| match e {
-				polkadot_service::Error::Sub(x) => x,
-				s => format!("{}", s).into(),
-			})?;
+	let (relay_chain_interface, collator_key) = build_inprocess_relay_chain(
+		polkadot_config,
+		&parachain_config,
+		telemetry_worker_handle,
+		&mut task_manager,
+	)
+	.map_err(|e| match e {
+		RelayChainError::ServiceError(polkadot_service::Error::Sub(x)) => x,
+		s => s.to_string().into(),
+	})?;
 
 	let client = params.client.clone();
 	let backend = params.backend.clone();
@@ -350,7 +355,7 @@ where
 			spawner,
 			parachain_consensus,
 			import_queue,
-			collator_key,
+			collator_key: collator_key.expect("Command line arguments do not allow this. qed"),
 			relay_chain_slot_duration,
 		};
 
@@ -364,6 +369,7 @@ where
 			relay_chain_interface,
 			relay_chain_slot_duration,
 			import_queue,
+			collator_options,
 		};
 
 		start_full_node(params)?;
@@ -405,9 +411,9 @@ pub fn parachain_build_import_queue(
 			let time = sp_timestamp::InherentDataProvider::from_system_time();
 
 			let slot =
-				sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration(
+				sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration(
 					*time,
-					slot_duration.slot_duration(),
+					slot_duration,
 				);
 
 			Ok((time, slot))
@@ -424,6 +430,7 @@ pub fn parachain_build_import_queue(
 pub async fn start_node(
 	parachain_config: Configuration,
 	polkadot_config: Configuration,
+	collator_options: CollatorOptions,
 	id: ParaId,
 ) -> sc_service::error::Result<(
 	TaskManager,
@@ -432,6 +439,7 @@ pub async fn start_node(
 	start_node_impl::<RuntimeApi, ParachainRuntimeExecutor, _, _, _>(
 		parachain_config,
 		polkadot_config,
+		collator_options,
 		id,
 		|deny_unsafe, client, pool| {
 			use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi};
@@ -481,9 +489,9 @@ pub async fn start_node(
 						).await;
 							let time = sp_timestamp::InherentDataProvider::from_system_time();
 
-							let slot = sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_duration(
+							let slot = sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration(
 							*time,
-							slot_duration.slot_duration(),
+							slot_duration,
 						);
 
 							let parachain_inherent = parachain_inherent.ok_or_else(|| {
diff --git a/bridges/bin/rialto-parachain/runtime/Cargo.toml b/bridges/bin/rialto-parachain/runtime/Cargo.toml
index d3bb30c3c8532c332c35202d50933c6523eb908d..1d0870fcbcd80f527a04f741786830eb082b520e 100644
--- a/bridges/bin/rialto-parachain/runtime/Cargo.toml
+++ b/bridges/bin/rialto-parachain/runtime/Cargo.toml
@@ -11,9 +11,9 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
 
 [dependencies]
-codec = { package = 'parity-scale-codec', version = '2.0.0', default-features = false, features = ['derive']}
+codec = { package = 'parity-scale-codec', version = '3.0.0', default-features = false, features = ['derive']}
 log = { version = "0.4.14", default-features = false }
-scale-info = { version = "1.0", default-features = false, features = ["derive"] }
+scale-info = { version = "2.0.1", default-features = false, features = ["derive"] }
 serde = { version = '1.0', optional = true, features = ['derive'] }
 
 # Bridge depedencies
diff --git a/bridges/bin/rialto-parachain/runtime/src/lib.rs b/bridges/bin/rialto-parachain/runtime/src/lib.rs
index e499c89f13acd66ee79df22c1c93a3ee53d95ba5..646521f329399fdd45262fae8c307e6d3642261d 100644
--- a/bridges/bin/rialto-parachain/runtime/src/lib.rs
+++ b/bridges/bin/rialto-parachain/runtime/src/lib.rs
@@ -42,7 +42,7 @@ use sp_version::RuntimeVersion;
 
 // A few exports that help ease life for downstream crates.
 pub use frame_support::{
-	construct_runtime, match_type, parameter_types,
+	construct_runtime, match_types, parameter_types,
 	traits::{Everything, IsInVec, Randomness},
 	weights::{
 		constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},
@@ -86,6 +86,7 @@ pub type SignedBlock = generic::SignedBlock<Block>;
 pub type BlockId = generic::BlockId<Block>;
 /// The SignedExtension to the basic transaction logic.
 pub type SignedExtra = (
+	frame_system::CheckNonZeroSender<Runtime>,
 	frame_system::CheckSpecVersion<Runtime>,
 	frame_system::CheckGenesis<Runtime>,
 	frame_system::CheckEra<Runtime>,
@@ -350,7 +351,7 @@ parameter_types! {
 	pub const MaxAuthorities: u32 = 100_000;
 }
 
-match_type! {
+match_types! {
 	pub type ParentOrParentsUnitPlurality: impl Contains<MultiLocation> = {
 		MultiLocation { parents: 1, interior: Here } |
 		MultiLocation { parents: 1, interior: X1(Plurality { id: BodyId::Unit, .. }) }
@@ -423,6 +424,9 @@ impl cumulus_pallet_xcmp_queue::Config for Runtime {
 	type ChannelInfo = ParachainSystem;
 	type VersionWrapper = ();
 	type ExecuteOverweightOrigin = EnsureRoot<AccountId>;
+	type ControllerOrigin = EnsureRoot<AccountId>;
+	type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
+	type WeightInfo = ();
 }
 
 impl cumulus_pallet_dmp_queue::Config for Runtime {
@@ -613,7 +617,6 @@ impl_runtime_apis! {
 			add_benchmark!(params, batches, pallet_balances, Balances);
 			add_benchmark!(params, batches, pallet_timestamp, Timestamp);
 
-			if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) }
 			Ok(batches)
 		}
 	}
diff --git a/bridges/bin/rialto/node/Cargo.toml b/bridges/bin/rialto/node/Cargo.toml
index 34a2ec1d8b846edc16357b13f49299e24f9a2f3a..e44ceb45faa97226f2a65f197367d1a1832a8921 100644
--- a/bridges/bin/rialto/node/Cargo.toml
+++ b/bridges/bin/rialto/node/Cargo.toml
@@ -10,11 +10,11 @@ repository = "https://github.com/paritytech/parity-bridges-common/"
 license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
-clap = { version = "3.0", features = ["derive"] }
+clap = { version = "3.1", features = ["derive"] }
 futures = "0.3"
 jsonrpc-core = "18.0"
-kvdb = "0.10"
-kvdb-rocksdb = "0.12"
+kvdb = "0.11"
+kvdb-rocksdb = "0.15"
 lru = "0.7"
 serde_json = "1.0.59"
 thiserror = "1.0"
diff --git a/bridges/bin/rialto/node/src/chain_spec.rs b/bridges/bin/rialto/node/src/chain_spec.rs
index 6bfacba83a1e1c6f002cb0d17e90cd24f60ce602..10315e33c853a61fe885115bb871543ee758ca3a 100644
--- a/bridges/bin/rialto/node/src/chain_spec.rs
+++ b/bridges/bin/rialto/node/src/chain_spec.rs
@@ -16,7 +16,7 @@
 
 use beefy_primitives::crypto::AuthorityId as BeefyId;
 use bp_rialto::derive_account_from_millau_id;
-use polkadot_primitives::v1::{AssignmentId, ValidatorId};
+use polkadot_primitives::v2::{AssignmentId, ValidatorId};
 use rialto_runtime::{
 	AccountId, BabeConfig, BalancesConfig, BeefyConfig, BridgeMillauMessagesConfig,
 	ConfigurationConfig, GenesisConfig, GrandpaConfig, SessionConfig, SessionKeys, Signature,
@@ -253,8 +253,8 @@ fn testnet_genesis(
 				validation_upgrade_cooldown: 2u32,
 				validation_upgrade_delay: 2,
 				code_retention_period: 1200,
-				max_code_size: polkadot_primitives::v1::MAX_CODE_SIZE,
-				max_pov_size: polkadot_primitives::v1::MAX_POV_SIZE,
+				max_code_size: polkadot_primitives::v2::MAX_CODE_SIZE,
+				max_pov_size: polkadot_primitives::v2::MAX_POV_SIZE,
 				max_head_data_size: 32 * 1024,
 				group_rotation_frequency: 20,
 				chain_availability_period: 4,
@@ -263,7 +263,7 @@ fn testnet_genesis(
 				max_upward_queue_size: 1024 * 1024,
 				max_downward_message_size: 1024 * 1024,
 				ump_service_total_weight: 100_000_000_000,
-				max_upward_message_size: 1024 * 1024,
+				max_upward_message_size: 50 * 1024,
 				max_upward_message_num_per_candidate: 5,
 				hrmp_sender_deposit: 0,
 				hrmp_recipient_deposit: 0,
diff --git a/bridges/bin/rialto/node/src/cli.rs b/bridges/bin/rialto/node/src/cli.rs
index 20155a1469e46ed2eda227467ffa08f97584c4f5..bb7f54998dd5fbb51626c0ebaeecaacf78aaab41 100644
--- a/bridges/bin/rialto/node/src/cli.rs
+++ b/bridges/bin/rialto/node/src/cli.rs
@@ -14,7 +14,7 @@
 // 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 clap::{AppSettings, Parser};
+use clap::Parser;
 use sc_cli::RunCmd;
 
 #[derive(Debug, Parser)]
@@ -70,11 +70,11 @@ pub enum Subcommand {
 	Benchmark(frame_benchmarking_cli::BenchmarkCmd),
 
 	/// FOR INTERNAL USE: analog of the "prepare-worker" command of the polkadot binary.
-	#[clap(name = "prepare-worker", setting = AppSettings::Hidden)]
+	#[clap(name = "prepare-worker", hide = true)]
 	PvfPrepareWorker(ValidationWorkerCommand),
 
 	/// FOR INTERNAL USE: analog of the "execute-worker" command of the polkadot binary.
-	#[clap(name = "execute-worker", setting = AppSettings::Hidden)]
+	#[clap(name = "execute-worker", hide = true)]
 	PvfExecuteWorker(ValidationWorkerCommand),
 }
 
diff --git a/bridges/bin/rialto/node/src/command.rs b/bridges/bin/rialto/node/src/command.rs
index 1d81de2cb0c4d10aee576c637385d22b194bb8d4..da92837f06c09f47ebe40c9fa264c3c2890b9af4 100644
--- a/bridges/bin/rialto/node/src/command.rs
+++ b/bridges/bin/rialto/node/src/command.rs
@@ -192,6 +192,7 @@ pub fn run() -> sc_cli::Result<()> {
 						let jaeger_agent = None;
 						let telemetry_worker_handle = None;
 						let program_path = None;
+						let overseer_enable_anyways = false;
 
 						polkadot_service::new_full::<rialto_runtime::RuntimeApi, ExecutorDispatch, _>(
 							config,
@@ -201,6 +202,7 @@ pub fn run() -> sc_cli::Result<()> {
 							jaeger_agent,
 							telemetry_worker_handle,
 							program_path,
+							overseer_enable_anyways,
 							overseer_gen,
 						)
 							.map(|full| full.task_manager)
diff --git a/bridges/bin/rialto/runtime/Cargo.toml b/bridges/bin/rialto/runtime/Cargo.toml
index 5cfa11e12a9af696f38cadf0064cec25f63d884a..59b9a8e9b575537c04461961af4f8584f81b18aa 100644
--- a/bridges/bin/rialto/runtime/Cargo.toml
+++ b/bridges/bin/rialto/runtime/Cargo.toml
@@ -8,11 +8,11 @@ repository = "https://github.com/paritytech/parity-bridges-common/"
 license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
-codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive"] }
+codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] }
 hex-literal = "0.3"
 libsecp256k1 = { version = "0.7", optional = true, default-features = false, features = ["hmac"] }
 log = { version = "0.4.14", default-features = false }
-scale-info = { version = "1.0", default-features = false, features = ["derive"] }
+scale-info = { version = "2.0.1", default-features = false, features = ["derive"] }
 serde = { version = "1.0", optional = true, features = ["derive"] }
 
 # Bridge dependencies
@@ -137,7 +137,7 @@ std = [
 ]
 runtime-benchmarks = [
 	"bridge-runtime-common/runtime-benchmarks",
-	"frame-benchmarking",
+	"frame-benchmarking/runtime-benchmarks",
 	"frame-support/runtime-benchmarks",
 	"frame-system/runtime-benchmarks",
 	"libsecp256k1",
diff --git a/bridges/bin/rialto/runtime/src/lib.rs b/bridges/bin/rialto/runtime/src/lib.rs
index 8dd4c2cc278764d7301bf5d4b9852efb42c465d5..87cddf5e268db92c9684cfaec2b513cac9a102fc 100644
--- a/bridges/bin/rialto/runtime/src/lib.rs
+++ b/bridges/bin/rialto/runtime/src/lib.rs
@@ -21,8 +21,6 @@
 #![recursion_limit = "256"]
 // Runtime-generated enums
 #![allow(clippy::large_enum_variant)]
-// Runtime-generated DecodeLimit::decode_all_With_depth_limit
-#![allow(clippy::unnecessary_mut_passed)]
 // From construct_runtime macro
 #![allow(clippy::from_over_into)]
 
@@ -534,6 +532,7 @@ pub type SignedBlock = generic::SignedBlock<Block>;
 pub type BlockId = generic::BlockId<Block>;
 /// The SignedExtension to the basic transaction logic.
 pub type SignedExtra = (
+	frame_system::CheckNonZeroSender<Runtime>,
 	frame_system::CheckSpecVersion<Runtime>,
 	frame_system::CheckTxVersion<Runtime>,
 	frame_system::CheckGenesis<Runtime>,
@@ -717,55 +716,55 @@ impl_runtime_apis! {
 	}
 
 	impl polkadot_primitives::v2::ParachainHost<Block, Hash, BlockNumber> for Runtime {
-		fn validators() -> Vec<polkadot_primitives::v1::ValidatorId> {
-			polkadot_runtime_parachains::runtime_api_impl::v1::validators::<Runtime>()
+		fn validators() -> Vec<polkadot_primitives::v2::ValidatorId> {
+			polkadot_runtime_parachains::runtime_api_impl::v2::validators::<Runtime>()
 		}
 
-		fn validator_groups() -> (Vec<Vec<polkadot_primitives::v1::ValidatorIndex>>, polkadot_primitives::v1::GroupRotationInfo<BlockNumber>) {
-			polkadot_runtime_parachains::runtime_api_impl::v1::validator_groups::<Runtime>()
+		fn validator_groups() -> (Vec<Vec<polkadot_primitives::v2::ValidatorIndex>>, polkadot_primitives::v2::GroupRotationInfo<BlockNumber>) {
+			polkadot_runtime_parachains::runtime_api_impl::v2::validator_groups::<Runtime>()
 		}
 
-		fn availability_cores() -> Vec<polkadot_primitives::v1::CoreState<Hash, BlockNumber>> {
-			polkadot_runtime_parachains::runtime_api_impl::v1::availability_cores::<Runtime>()
+		fn availability_cores() -> Vec<polkadot_primitives::v2::CoreState<Hash, BlockNumber>> {
+			polkadot_runtime_parachains::runtime_api_impl::v2::availability_cores::<Runtime>()
 		}
 
-		fn persisted_validation_data(para_id: polkadot_primitives::v1::Id, assumption: polkadot_primitives::v1::OccupiedCoreAssumption)
-			-> Option<polkadot_primitives::v1::PersistedValidationData<Hash, BlockNumber>> {
-			polkadot_runtime_parachains::runtime_api_impl::v1::persisted_validation_data::<Runtime>(para_id, assumption)
+		fn persisted_validation_data(para_id: polkadot_primitives::v2::Id, assumption: polkadot_primitives::v2::OccupiedCoreAssumption)
+			-> Option<polkadot_primitives::v2::PersistedValidationData<Hash, BlockNumber>> {
+			polkadot_runtime_parachains::runtime_api_impl::v2::persisted_validation_data::<Runtime>(para_id, assumption)
 		}
 
 		fn assumed_validation_data(
-			para_id: polkadot_primitives::v1::Id,
+			para_id: polkadot_primitives::v2::Id,
 			expected_persisted_validation_data_hash: Hash,
-		) -> Option<(polkadot_primitives::v1::PersistedValidationData<Hash, BlockNumber>, polkadot_primitives::v1::ValidationCodeHash)> {
-			polkadot_runtime_parachains::runtime_api_impl::v1::assumed_validation_data::<Runtime>(
+		) -> Option<(polkadot_primitives::v2::PersistedValidationData<Hash, BlockNumber>, polkadot_primitives::v2::ValidationCodeHash)> {
+			polkadot_runtime_parachains::runtime_api_impl::v2::assumed_validation_data::<Runtime>(
 				para_id,
 				expected_persisted_validation_data_hash,
 			)
 		}
 
 		fn check_validation_outputs(
-			para_id: polkadot_primitives::v1::Id,
-			outputs: polkadot_primitives::v1::CandidateCommitments,
+			para_id: polkadot_primitives::v2::Id,
+			outputs: polkadot_primitives::v2::CandidateCommitments,
 		) -> bool {
-			polkadot_runtime_parachains::runtime_api_impl::v1::check_validation_outputs::<Runtime>(para_id, outputs)
+			polkadot_runtime_parachains::runtime_api_impl::v2::check_validation_outputs::<Runtime>(para_id, outputs)
 		}
 
-		fn session_index_for_child() -> polkadot_primitives::v1::SessionIndex {
-			polkadot_runtime_parachains::runtime_api_impl::v1::session_index_for_child::<Runtime>()
+		fn session_index_for_child() -> polkadot_primitives::v2::SessionIndex {
+			polkadot_runtime_parachains::runtime_api_impl::v2::session_index_for_child::<Runtime>()
 		}
 
-		fn validation_code(para_id: polkadot_primitives::v1::Id, assumption: polkadot_primitives::v1::OccupiedCoreAssumption)
-			-> Option<polkadot_primitives::v1::ValidationCode> {
-			polkadot_runtime_parachains::runtime_api_impl::v1::validation_code::<Runtime>(para_id, assumption)
+		fn validation_code(para_id: polkadot_primitives::v2::Id, assumption: polkadot_primitives::v2::OccupiedCoreAssumption)
+			-> Option<polkadot_primitives::v2::ValidationCode> {
+			polkadot_runtime_parachains::runtime_api_impl::v2::validation_code::<Runtime>(para_id, assumption)
 		}
 
-		fn candidate_pending_availability(para_id: polkadot_primitives::v1::Id) -> Option<polkadot_primitives::v1::CommittedCandidateReceipt<Hash>> {
-			polkadot_runtime_parachains::runtime_api_impl::v1::candidate_pending_availability::<Runtime>(para_id)
+		fn candidate_pending_availability(para_id: polkadot_primitives::v2::Id) -> Option<polkadot_primitives::v2::CommittedCandidateReceipt<Hash>> {
+			polkadot_runtime_parachains::runtime_api_impl::v2::candidate_pending_availability::<Runtime>(para_id)
 		}
 
-		fn candidate_events() -> Vec<polkadot_primitives::v1::CandidateEvent<Hash>> {
-			polkadot_runtime_parachains::runtime_api_impl::v1::candidate_events::<Runtime, _>(|ev| {
+		fn candidate_events() -> Vec<polkadot_primitives::v2::CandidateEvent<Hash>> {
+			polkadot_runtime_parachains::runtime_api_impl::v2::candidate_events::<Runtime, _>(|ev| {
 				match ev {
 					Event::Inclusion(ev) => {
 						Some(ev)
@@ -775,46 +774,46 @@ impl_runtime_apis! {
 			})
 		}
 
-		fn session_info(index: polkadot_primitives::v1::SessionIndex) -> Option<polkadot_primitives::v2::SessionInfo> {
-			polkadot_runtime_parachains::runtime_api_impl::v1::session_info::<Runtime>(index)
+		fn session_info(index: polkadot_primitives::v2::SessionIndex) -> Option<polkadot_primitives::v2::SessionInfo> {
+			polkadot_runtime_parachains::runtime_api_impl::v2::session_info::<Runtime>(index)
 		}
 
-		fn dmq_contents(recipient: polkadot_primitives::v1::Id) -> Vec<polkadot_primitives::v1::InboundDownwardMessage<BlockNumber>> {
-			polkadot_runtime_parachains::runtime_api_impl::v1::dmq_contents::<Runtime>(recipient)
+		fn dmq_contents(recipient: polkadot_primitives::v2::Id) -> Vec<polkadot_primitives::v2::InboundDownwardMessage<BlockNumber>> {
+			polkadot_runtime_parachains::runtime_api_impl::v2::dmq_contents::<Runtime>(recipient)
 		}
 
 		fn inbound_hrmp_channels_contents(
-			recipient: polkadot_primitives::v1::Id
-		) -> BTreeMap<polkadot_primitives::v1::Id, Vec<polkadot_primitives::v1::InboundHrmpMessage<BlockNumber>>> {
-			polkadot_runtime_parachains::runtime_api_impl::v1::inbound_hrmp_channels_contents::<Runtime>(recipient)
+			recipient: polkadot_primitives::v2::Id
+		) -> BTreeMap<polkadot_primitives::v2::Id, Vec<polkadot_primitives::v2::InboundHrmpMessage<BlockNumber>>> {
+			polkadot_runtime_parachains::runtime_api_impl::v2::inbound_hrmp_channels_contents::<Runtime>(recipient)
 		}
 
-		fn validation_code_by_hash(hash: polkadot_primitives::v1::ValidationCodeHash) -> Option<polkadot_primitives::v1::ValidationCode> {
-			polkadot_runtime_parachains::runtime_api_impl::v1::validation_code_by_hash::<Runtime>(hash)
+		fn validation_code_by_hash(hash: polkadot_primitives::v2::ValidationCodeHash) -> Option<polkadot_primitives::v2::ValidationCode> {
+			polkadot_runtime_parachains::runtime_api_impl::v2::validation_code_by_hash::<Runtime>(hash)
 		}
 
-		fn on_chain_votes() -> Option<polkadot_primitives::v1::ScrapedOnChainVotes<Hash>> {
-			polkadot_runtime_parachains::runtime_api_impl::v1::on_chain_votes::<Runtime>()
+		fn on_chain_votes() -> Option<polkadot_primitives::v2::ScrapedOnChainVotes<Hash>> {
+			polkadot_runtime_parachains::runtime_api_impl::v2::on_chain_votes::<Runtime>()
 		}
 
-		fn submit_pvf_check_statement(stmt: polkadot_primitives::v2::PvfCheckStatement, signature: polkadot_primitives::v1::ValidatorSignature) {
-			polkadot_runtime_parachains::runtime_api_impl::v1::submit_pvf_check_statement::<Runtime>(stmt, signature)
+		fn submit_pvf_check_statement(stmt: polkadot_primitives::v2::PvfCheckStatement, signature: polkadot_primitives::v2::ValidatorSignature) {
+			polkadot_runtime_parachains::runtime_api_impl::v2::submit_pvf_check_statement::<Runtime>(stmt, signature)
 		}
 
-		fn pvfs_require_precheck() -> Vec<polkadot_primitives::v1::ValidationCodeHash> {
-			polkadot_runtime_parachains::runtime_api_impl::v1::pvfs_require_precheck::<Runtime>()
+		fn pvfs_require_precheck() -> Vec<polkadot_primitives::v2::ValidationCodeHash> {
+			polkadot_runtime_parachains::runtime_api_impl::v2::pvfs_require_precheck::<Runtime>()
 		}
 
-		fn validation_code_hash(para_id: polkadot_primitives::v1::Id, assumption: polkadot_primitives::v1::OccupiedCoreAssumption)
-			-> Option<polkadot_primitives::v1::ValidationCodeHash>
+		fn validation_code_hash(para_id: polkadot_primitives::v2::Id, assumption: polkadot_primitives::v2::OccupiedCoreAssumption)
+			-> Option<polkadot_primitives::v2::ValidationCodeHash>
 		{
-			polkadot_runtime_parachains::runtime_api_impl::v1::validation_code_hash::<Runtime>(para_id, assumption)
+			polkadot_runtime_parachains::runtime_api_impl::v2::validation_code_hash::<Runtime>(para_id, assumption)
 		}
 	}
 
 	impl sp_authority_discovery::AuthorityDiscoveryApi<Block> for Runtime {
 		fn authorities() -> Vec<AuthorityDiscoveryId> {
-			polkadot_runtime_parachains::runtime_api_impl::v1::relevant_authority_ids::<Runtime>()
+			polkadot_runtime_parachains::runtime_api_impl::v2::relevant_authority_ids::<Runtime>()
 		}
 	}
 
diff --git a/bridges/bin/rialto/runtime/src/parachains.rs b/bridges/bin/rialto/runtime/src/parachains.rs
index 9a316ef0e2a78f1a7e8d7d3f5ef81a1af7e5a71f..20a9aeb28c0dfed04731d5d26343213c08ad3112 100644
--- a/bridges/bin/rialto/runtime/src/parachains.rs
+++ b/bridges/bin/rialto/runtime/src/parachains.rs
@@ -23,7 +23,7 @@ use crate::{
 
 use frame_support::{parameter_types, weights::Weight};
 use frame_system::EnsureRoot;
-use polkadot_primitives::v1::ValidatorIndex;
+use polkadot_primitives::v2::ValidatorIndex;
 use polkadot_runtime_common::{paras_registrar, paras_sudo_wrapper, slots};
 use polkadot_runtime_parachains::{
 	configuration as parachains_configuration, dmp as parachains_dmp, hrmp as parachains_hrmp,
@@ -108,6 +108,7 @@ impl parachains_ump::Config for Runtime {
 	type UmpSink = ();
 	type FirstMessageFactorPercent = FirstMessageFactorPercent;
 	type ExecuteOverweightOrigin = EnsureRoot<AccountId>;
+	type WeightInfo = parachains_ump::TestWeightInfo;
 }
 
 // required onboarding pallets. We're not going to use auctions or crowdloans, so they're missing
diff --git a/bridges/bin/runtime-common/Cargo.toml b/bridges/bin/runtime-common/Cargo.toml
index 54055e10c5fb546e8b07d0ed7474f4fe7d4f87d4..abd84364ce2cdbb85996409ab365ff1ccf8617c4 100644
--- a/bridges/bin/runtime-common/Cargo.toml
+++ b/bridges/bin/runtime-common/Cargo.toml
@@ -8,10 +8,10 @@ repository = "https://github.com/paritytech/parity-bridges-common/"
 license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
-codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive"] }
+codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] }
 ed25519-dalek = { version = "1.0", default-features = false, optional = true }
 hash-db = { version = "0.15.2", default-features = false }
-scale-info = { version = "1.0", default-features = false, features = ["derive"] }
+scale-info = { version = "2.0.1", default-features = false, features = ["derive"] }
 static_assertions = { version = "1.1", optional = true }
 
 # Bridge dependencies
diff --git a/bridges/modules/dispatch/Cargo.toml b/bridges/modules/dispatch/Cargo.toml
index d073f8722e9049341f14e9942500e315d0bbd414..833d5cca77a71e5c167a1c4e97d4158e114e08da 100644
--- a/bridges/modules/dispatch/Cargo.toml
+++ b/bridges/modules/dispatch/Cargo.toml
@@ -7,9 +7,9 @@ edition = "2021"
 license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
-codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false }
+codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false }
 log = { version = "0.4.14", default-features = false }
-scale-info = { version = "1.0", default-features = false, features = ["derive"] }
+scale-info = { version = "2.0.1", default-features = false, features = ["derive"] }
 
 # Bridge dependencies
 
diff --git a/bridges/modules/grandpa/Cargo.toml b/bridges/modules/grandpa/Cargo.toml
index 779bf18fe2e6428440b11f14c4e4ee3156ad5f95..eac80375da1282f0577bbac1c771b12c03250038 100644
--- a/bridges/modules/grandpa/Cargo.toml
+++ b/bridges/modules/grandpa/Cargo.toml
@@ -8,11 +8,11 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false }
-finality-grandpa = { version = "0.14.0", default-features = false }
+codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false }
+finality-grandpa = { version = "0.15.0", default-features = false }
 log = { version = "0.4.14", default-features = false }
 num-traits = { version = "0.2", default-features = false }
-scale-info = { version = "1.0", default-features = false, features = ["derive"] }
+scale-info = { version = "2.0.1", default-features = false, features = ["derive"] }
 serde = { version = "1.0", optional = true }
 
 # Bridge Dependencies
@@ -58,5 +58,5 @@ std = [
 ]
 runtime-benchmarks = [
 	"bp-test-utils",
-	"frame-benchmarking",
+	"frame-benchmarking/runtime-benchmarks",
 ]
diff --git a/bridges/modules/messages/Cargo.toml b/bridges/modules/messages/Cargo.toml
index ee575dbe67bbff299105897a3dabfb361b55dfa8..804f323f10b6f6b8b2e99d3a0b978e57e3f0ca9c 100644
--- a/bridges/modules/messages/Cargo.toml
+++ b/bridges/modules/messages/Cargo.toml
@@ -7,11 +7,11 @@ edition = "2021"
 license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
-bitvec = { version = "0.20", default-features = false, features = ["alloc"] }
-codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false }
+bitvec = { version = "1", default-features = false, features = ["alloc"] }
+codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false }
 log = { version = "0.4.14", default-features = false }
 num-traits = { version = "0.2", default-features = false }
-scale-info = { version = "1.0", default-features = false, features = ["derive"] }
+scale-info = { version = "2.0.1", default-features = false, features = ["derive"] }
 serde = { version = "1.0.101", optional = true, features = ["derive"] }
 
 # Bridge dependencies
@@ -51,5 +51,5 @@ std = [
 	"sp-std/std",
 ]
 runtime-benchmarks = [
-	"frame-benchmarking",
+	"frame-benchmarking/runtime-benchmarks",
 ]
diff --git a/bridges/modules/messages/src/mock.rs b/bridges/modules/messages/src/mock.rs
index 2669ddfbef26ff38224769a25506b161448604ee..75dcce8df04495e29fb0b0a2cea742e6ee61985d 100644
--- a/bridges/modules/messages/src/mock.rs
+++ b/bridges/modules/messages/src/mock.rs
@@ -543,7 +543,7 @@ pub fn unrewarded_relayer(
 			begin,
 			end,
 			dispatch_results: if end >= begin {
-				bitvec![Msb0, u8; 1; (end - begin + 1) as _]
+				bitvec![u8, Msb0; 1; (end - begin + 1) as _]
 			} else {
 				Default::default()
 			},
diff --git a/bridges/modules/messages/src/outbound_lane.rs b/bridges/modules/messages/src/outbound_lane.rs
index c05437596db82af9f4ca4d3bacae457aa32c58dc..cfdc81acc315b807288a320acb80bddd14b4da88 100644
--- a/bridges/modules/messages/src/outbound_lane.rs
+++ b/bridges/modules/messages/src/outbound_lane.rs
@@ -260,7 +260,7 @@ mod tests {
 		DeliveredMessages {
 			begin: *nonces.start(),
 			end: *nonces.end(),
-			dispatch_results: bitvec![Msb0, u8; 1; (nonces.end() - nonces.start() + 1) as _],
+			dispatch_results: bitvec![u8, Msb0; 1; (nonces.end() - nonces.start() + 1) as _],
 		}
 	}
 
diff --git a/bridges/modules/shift-session-manager/Cargo.toml b/bridges/modules/shift-session-manager/Cargo.toml
index 694e0a82da9f44a1c292766f029aaaa620c8edae..30a5618b115f21324aa26cd5bc624089ccc7397b 100644
--- a/bridges/modules/shift-session-manager/Cargo.toml
+++ b/bridges/modules/shift-session-manager/Cargo.toml
@@ -7,8 +7,8 @@ edition = "2021"
 license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
-codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false }
-scale-info = { version = "1.0", default-features = false, features = ["derive"] }
+codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false }
+scale-info = { version = "2.0.1", default-features = false, features = ["derive"] }
 
 # Substrate Dependencies
 
diff --git a/bridges/modules/token-swap/Cargo.toml b/bridges/modules/token-swap/Cargo.toml
index 7ccb50200c1f6303101c514c7492ce0e7550e2e2..aad395fb7a30607aa49d76718c22e50848b3f666 100644
--- a/bridges/modules/token-swap/Cargo.toml
+++ b/bridges/modules/token-swap/Cargo.toml
@@ -7,9 +7,9 @@ edition = "2021"
 license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
-codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false }
+codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false }
 log = { version = "0.4.14", default-features = false }
-scale-info = { version = "1.0", default-features = false, features = ["derive"] }
+scale-info = { version = "2.0.1", default-features = false, features = ["derive"] }
 serde = { version = "1.0", optional = true }
 
 # Bridge dependencies
@@ -55,5 +55,5 @@ std = [
 	"sp-std/std",
 ]
 runtime-benchmarks = [
-	"frame-benchmarking",
+	"frame-benchmarking/runtime-benchmarks",
 ]
diff --git a/bridges/primitives/chain-kusama/src/lib.rs b/bridges/primitives/chain-kusama/src/lib.rs
index d1d4c79df194337d3d789cc6606e17e67fc10af2..ca5c545267da70c5ff59cf79d5bf7e8de2af5bd8 100644
--- a/bridges/primitives/chain-kusama/src/lib.rs
+++ b/bridges/primitives/chain-kusama/src/lib.rs
@@ -17,8 +17,6 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 // RuntimeApi generated functions
 #![allow(clippy::too_many_arguments)]
-// Runtime-generated DecodeLimit::decode_all_with_depth_limit
-#![allow(clippy::unnecessary_mut_passed)]
 
 use bp_messages::{LaneId, MessageDetails, MessageNonce};
 use frame_support::weights::{
diff --git a/bridges/primitives/chain-millau/Cargo.toml b/bridges/primitives/chain-millau/Cargo.toml
index c35c1f07348e4dd2d8c3d89393850a226b6ce0ed..0aaeb5b6bf9d4ebd2f48055682960233307f3915 100644
--- a/bridges/primitives/chain-millau/Cargo.toml
+++ b/bridges/primitives/chain-millau/Cargo.toml
@@ -14,10 +14,10 @@ bp-messages = { path = "../messages", default-features = false }
 bp-runtime = { path = "../runtime", default-features = false }
 fixed-hash = { version = "0.7.0", default-features = false }
 hash256-std-hasher = { version = "0.15.2", default-features = false }
-impl-codec = { version = "0.5.1", default-features = false }
+impl-codec = { version = "0.6", default-features = false }
 impl-serde = { version = "0.3.1", optional = true }
-parity-util-mem = { version = "0.10", default-features = false, features = ["primitive-types"] }
-scale-info = { version = "1.0", default-features = false, features = ["derive"] }
+parity-util-mem = { version = "0.11", default-features = false, features = ["primitive-types"] }
+scale-info = { version = "2.0.1", default-features = false, features = ["derive"] }
 serde = { version = "1.0", optional = true, features = ["derive"] }
 
 # Substrate Based Dependencies
diff --git a/bridges/primitives/chain-millau/src/lib.rs b/bridges/primitives/chain-millau/src/lib.rs
index 3a2f120f465c2e2868b2be6a895791621b902451..ff8d53859535b46a55a05743a69a1c78f600bfe6 100644
--- a/bridges/primitives/chain-millau/src/lib.rs
+++ b/bridges/primitives/chain-millau/src/lib.rs
@@ -17,8 +17,6 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 // RuntimeApi generated functions
 #![allow(clippy::too_many_arguments)]
-// Runtime-generated DecodeLimit::decode_all_With_depth_limit
-#![allow(clippy::unnecessary_mut_passed)]
 
 mod millau_hash;
 
diff --git a/bridges/primitives/chain-polkadot/src/lib.rs b/bridges/primitives/chain-polkadot/src/lib.rs
index 0627a9952032c0f140c17243ef3c04259aee0268..52202c3897fea11c1771cbf1d5cce6f5a12a5761 100644
--- a/bridges/primitives/chain-polkadot/src/lib.rs
+++ b/bridges/primitives/chain-polkadot/src/lib.rs
@@ -17,8 +17,6 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 // RuntimeApi generated functions
 #![allow(clippy::too_many_arguments)]
-// Runtime-generated DecodeLimit::decode_all_with_depth_limit
-#![allow(clippy::unnecessary_mut_passed)]
 
 use bp_messages::{LaneId, MessageDetails, MessageNonce};
 use frame_support::weights::{
diff --git a/bridges/primitives/chain-rialto-parachain/src/lib.rs b/bridges/primitives/chain-rialto-parachain/src/lib.rs
index 786226cf93c99735df4b15486d8c25ca3a406656..f3f449c7af3e1f4254b8be4d4b3a4d402021eeb9 100644
--- a/bridges/primitives/chain-rialto-parachain/src/lib.rs
+++ b/bridges/primitives/chain-rialto-parachain/src/lib.rs
@@ -17,8 +17,6 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 // RuntimeApi generated functions
 #![allow(clippy::too_many_arguments)]
-// Runtime-generated DecodeLimit::decode_all_With_depth_limit
-#![allow(clippy::unnecessary_mut_passed)]
 
 use bp_runtime::Chain;
 use frame_support::{
diff --git a/bridges/primitives/chain-rialto/src/lib.rs b/bridges/primitives/chain-rialto/src/lib.rs
index 33b30a183d643270f833192b9cf3bf5737b2ee7e..4bf20489bc8517d833f0e76653f3fdacd0777ef5 100644
--- a/bridges/primitives/chain-rialto/src/lib.rs
+++ b/bridges/primitives/chain-rialto/src/lib.rs
@@ -17,8 +17,6 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 // RuntimeApi generated functions
 #![allow(clippy::too_many_arguments)]
-// Runtime-generated DecodeLimit::decode_all_With_depth_limit
-#![allow(clippy::unnecessary_mut_passed)]
 
 use bp_messages::{LaneId, MessageDetails, MessageNonce};
 use bp_runtime::Chain;
diff --git a/bridges/primitives/chain-rococo/Cargo.toml b/bridges/primitives/chain-rococo/Cargo.toml
index 684b294a266fb298c2db31d01142f0db25089778..814cd09bf170c5ddf2a067761ae543d728420222 100644
--- a/bridges/primitives/chain-rococo/Cargo.toml
+++ b/bridges/primitives/chain-rococo/Cargo.toml
@@ -7,7 +7,7 @@ edition = "2021"
 license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
-parity-scale-codec = { version = "2.2.0", default-features = false, features = ["derive"] }
+parity-scale-codec = { version = "3.0.0", default-features = false, features = ["derive"] }
 smallvec = "1.7"
 
 # Bridge Dependencies
diff --git a/bridges/primitives/chain-rococo/src/lib.rs b/bridges/primitives/chain-rococo/src/lib.rs
index f8c080d8511645495f4135a2eda5fd3ba8d2a226..a05d55ad8bd83b90b775dfc665176fe63ee9907c 100644
--- a/bridges/primitives/chain-rococo/src/lib.rs
+++ b/bridges/primitives/chain-rococo/src/lib.rs
@@ -17,8 +17,6 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 // RuntimeApi generated functions
 #![allow(clippy::too_many_arguments)]
-// Runtime-generated DecodeLimit::decode_all_with_depth_limit
-#![allow(clippy::unnecessary_mut_passed)]
 
 use bp_messages::{LaneId, MessageDetails, MessageNonce};
 use frame_support::weights::{
diff --git a/bridges/primitives/chain-westend/Cargo.toml b/bridges/primitives/chain-westend/Cargo.toml
index e1d3ade7fe65b415bce9c9fc7a25486f87905500..ee6e2b9be99a0182b366857092498a4faacf149d 100644
--- a/bridges/primitives/chain-westend/Cargo.toml
+++ b/bridges/primitives/chain-westend/Cargo.toml
@@ -7,8 +7,8 @@ edition = "2021"
 license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
-parity-scale-codec = { version = "2.2.0", default-features = false, features = ["derive"] }
-scale-info = { version = "1.0", default-features = false, features = ["derive"] }
+parity-scale-codec = { version = "3.0.0", default-features = false, features = ["derive"] }
+scale-info = { version = "2.0.1", default-features = false, features = ["derive"] }
 smallvec = "1.7"
 
 # Bridge Dependencies
diff --git a/bridges/primitives/chain-westend/src/lib.rs b/bridges/primitives/chain-westend/src/lib.rs
index af0ad27c9bc10b60a752785ed602619c2d1d4784..c7ebe4b00fd5d2c90b46ad1b90c9e60ed7e3347f 100644
--- a/bridges/primitives/chain-westend/src/lib.rs
+++ b/bridges/primitives/chain-westend/src/lib.rs
@@ -17,8 +17,6 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 // RuntimeApi generated functions
 #![allow(clippy::too_many_arguments)]
-// Runtime-generated DecodeLimit::decode_all_with_depth_limit
-#![allow(clippy::unnecessary_mut_passed)]
 
 use frame_support::weights::{
 	WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial,
diff --git a/bridges/primitives/chain-wococo/Cargo.toml b/bridges/primitives/chain-wococo/Cargo.toml
index dcae1844784e9ec45d4bef45371b36dd153df02b..633cdd15c1f56918f78863e67562d340d62d096f 100644
--- a/bridges/primitives/chain-wococo/Cargo.toml
+++ b/bridges/primitives/chain-wococo/Cargo.toml
@@ -7,7 +7,7 @@ edition = "2021"
 license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
-parity-scale-codec = { version = "2.2.0", default-features = false, features = ["derive"] }
+parity-scale-codec = { version = "3.0.0", default-features = false, features = ["derive"] }
 
 # Bridge Dependencies
 bp-messages = { path = "../messages", default-features = false }
diff --git a/bridges/primitives/chain-wococo/src/lib.rs b/bridges/primitives/chain-wococo/src/lib.rs
index 4b387a846cf311dc7e21b5a902b10abc21822ffd..f39543114c78bfe1656d3a33f975ce47541a2389 100644
--- a/bridges/primitives/chain-wococo/src/lib.rs
+++ b/bridges/primitives/chain-wococo/src/lib.rs
@@ -17,8 +17,6 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 // RuntimeApi generated functions
 #![allow(clippy::too_many_arguments)]
-// Runtime-generated DecodeLimit::decode_all_with_depth_limit
-#![allow(clippy::unnecessary_mut_passed)]
 
 use bp_messages::{LaneId, MessageDetails, MessageNonce};
 use sp_runtime::FixedU128;
diff --git a/bridges/primitives/header-chain/Cargo.toml b/bridges/primitives/header-chain/Cargo.toml
index 29aa34048e6291f30af35d6f94ba1f8aba1d1dd9..7cd688d0d81972cda68db604793c7476e33de6f1 100644
--- a/bridges/primitives/header-chain/Cargo.toml
+++ b/bridges/primitives/header-chain/Cargo.toml
@@ -7,9 +7,9 @@ edition = "2021"
 license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
-codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false }
-finality-grandpa = { version = "0.14.0", default-features = false }
-scale-info = { version = "1.0", default-features = false, features = ["derive"] }
+codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false }
+finality-grandpa = { version = "0.15.0", default-features = false }
+scale-info = { version = "2.0.1", default-features = false, features = ["derive"] }
 serde = { version = "1.0", optional = true }
 
 # Bridge dependencies
diff --git a/bridges/primitives/message-dispatch/Cargo.toml b/bridges/primitives/message-dispatch/Cargo.toml
index 6a3a2fdbdf7be219eff1b92db45bbb034c1a5469..39b2d00111e15129f185f165f91478ab164faedb 100644
--- a/bridges/primitives/message-dispatch/Cargo.toml
+++ b/bridges/primitives/message-dispatch/Cargo.toml
@@ -8,8 +8,8 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
 bp-runtime = { path = "../runtime", default-features = false }
-codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false }
-scale-info = { version = "1.0", default-features = false, features = ["derive"] }
+codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false }
+scale-info = { version = "2.0.1", default-features = false, features = ["derive"] }
 
 # Substrate Dependencies
 
diff --git a/bridges/primitives/messages/Cargo.toml b/bridges/primitives/messages/Cargo.toml
index 2142ad028173ae94a0cf9dacbd49575cbdf4650d..2a84f74d225bdc0c70c11dd8fed2f5142d4c9df1 100644
--- a/bridges/primitives/messages/Cargo.toml
+++ b/bridges/primitives/messages/Cargo.toml
@@ -7,10 +7,10 @@ edition = "2021"
 license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
-bitvec = { version = "0.20", default-features = false, features = ["alloc"] }
-codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false, features = ["derive", "bit-vec"] }
+bitvec = { version = "1", default-features = false, features = ["alloc"] }
+codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "bit-vec"] }
 impl-trait-for-tuples = "0.2"
-scale-info = { version = "1.0", default-features = false, features = ["bit-vec", "derive"] }
+scale-info = { version = "2.0.1", default-features = false, features = ["bit-vec", "derive"] }
 serde = { version = "1.0", optional = true, features = ["derive"] }
 
 # Bridge dependencies
diff --git a/bridges/primitives/messages/src/lib.rs b/bridges/primitives/messages/src/lib.rs
index 691ed57794db75ed96a7c187ee65a98c34959537..a4f204d238f7daec031f960a74f578063fa7d29d 100644
--- a/bridges/primitives/messages/src/lib.rs
+++ b/bridges/primitives/messages/src/lib.rs
@@ -194,7 +194,7 @@ pub struct MessageDetails<OutboundMessageFee> {
 }
 
 /// Bit vector of message dispatch results.
-pub type DispatchResultsBitVec = BitVec<Msb0, u8>;
+pub type DispatchResultsBitVec = BitVec<u8, Msb0>;
 
 /// Unrewarded relayer entry stored in the inbound lane data.
 ///
@@ -225,11 +225,9 @@ impl DeliveredMessages {
 	/// Create new `DeliveredMessages` struct that confirms delivery of single nonce with given
 	/// dispatch result.
 	pub fn new(nonce: MessageNonce, dispatch_result: bool) -> Self {
-		DeliveredMessages {
-			begin: nonce,
-			end: nonce,
-			dispatch_results: bitvec![Msb0, u8; if dispatch_result { 1 } else { 0 }],
-		}
+		let mut dispatch_results = BitVec::with_capacity(1);
+		dispatch_results.push(if dispatch_result { true } else { false });
+		DeliveredMessages { begin: nonce, end: nonce, dispatch_results }
 	}
 
 	/// Return total count of delivered messages.
@@ -368,7 +366,7 @@ mod tests {
 							messages: DeliveredMessages::new(i as _, true),
 						};
 						entry.messages.dispatch_results = bitvec![
-							Msb0, u8;
+							u8, Msb0;
 							1;
 							(messages_count / relayer_entries) as _
 						];
@@ -394,7 +392,7 @@ mod tests {
 	#[test]
 	fn message_dispatch_result_works() {
 		let delivered_messages =
-			DeliveredMessages { begin: 100, end: 150, dispatch_results: bitvec![Msb0, u8; 1; 151] };
+			DeliveredMessages { begin: 100, end: 150, dispatch_results: bitvec![u8, Msb0; 1; 151] };
 
 		assert!(!delivered_messages.contains_message(99));
 		assert!(delivered_messages.contains_message(100));
diff --git a/bridges/primitives/polkadot-core/Cargo.toml b/bridges/primitives/polkadot-core/Cargo.toml
index b35ac74ad5652deb0eaa07441b296cb015a9e747..1542a784ef561553122a6b438198d73a6242c178 100644
--- a/bridges/primitives/polkadot-core/Cargo.toml
+++ b/bridges/primitives/polkadot-core/Cargo.toml
@@ -7,8 +7,8 @@ edition = "2021"
 license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
-parity-scale-codec = { version = "2.2.0", default-features = false, features = ["derive"] }
-scale-info = { version = "1.0", default-features = false, features = ["derive"] }
+parity-scale-codec = { version = "3.0.0", default-features = false, features = ["derive"] }
+scale-info = { version = "2.0.1", default-features = false, features = ["derive"] }
 
 # Bridge Dependencies
 
diff --git a/bridges/primitives/polkadot-core/src/lib.rs b/bridges/primitives/polkadot-core/src/lib.rs
index a56adfd2337eb74d238a69922badce0edcbc1c47..79db07b82cbb0b59c9f55a9a8a61fdf13e10e6dd 100644
--- a/bridges/primitives/polkadot-core/src/lib.rs
+++ b/bridges/primitives/polkadot-core/src/lib.rs
@@ -239,11 +239,12 @@ pub type UncheckedExtrinsic<Call> = generic::UncheckedExtrinsic<
 pub type Address = MultiAddress<AccountId, ()>;
 
 /// A type of the data encoded as part of the transaction.
-pub type SignedExtra = ((), (), (), sp_runtime::generic::Era, Compact<Nonce>, (), Compact<Balance>);
+pub type SignedExtra =
+	((), (), (), (), sp_runtime::generic::Era, Compact<Nonce>, (), Compact<Balance>);
 
 /// Parameters which are part of the payload used to produce transaction signature,
 /// but don't end up in the transaction itself (i.e. inherent part of the runtime).
-pub type AdditionalSigned = (u32, u32, Hash, Hash, (), (), ());
+pub type AdditionalSigned = ((), u32, u32, Hash, Hash, (), (), ());
 
 /// A simplified version of signed extensions meant for producing signed transactions
 /// and signed payload in the client code.
@@ -287,6 +288,7 @@ impl<Call> SignedExtensions<Call> {
 	) -> Self {
 		Self {
 			encode_payload: (
+				(),              // non-zero sender
 				(),              // spec version
 				(),              // tx version
 				(),              // genesis
@@ -296,6 +298,7 @@ impl<Call> SignedExtensions<Call> {
 				tip.into(),      // transaction payment / tip (compact encoding)
 			),
 			additional_signed: Some((
+				(),
 				spec_version,
 				transaction_version,
 				genesis_hash,
@@ -312,12 +315,12 @@ impl<Call> SignedExtensions<Call> {
 impl<Call> SignedExtensions<Call> {
 	/// Return signer nonce, used to craft transaction.
 	pub fn nonce(&self) -> Nonce {
-		self.encode_payload.4.into()
+		self.encode_payload.5.into()
 	}
 
 	/// Return transaction tip.
 	pub fn tip(&self) -> Balance {
-		self.encode_payload.6.into()
+		self.encode_payload.7.into()
 	}
 }
 
diff --git a/bridges/primitives/runtime/Cargo.toml b/bridges/primitives/runtime/Cargo.toml
index 51b817fd40382e432bb53bce94ce43443016fb8b..085cfb9dbc6d4b91f75601ac017e64ed1ebfe202 100644
--- a/bridges/primitives/runtime/Cargo.toml
+++ b/bridges/primitives/runtime/Cargo.toml
@@ -7,10 +7,10 @@ edition = "2021"
 license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
-codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false }
+codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false }
 hash-db = { version = "0.15.2", default-features = false }
 num-traits = { version = "0.2", default-features = false }
-scale-info = { version = "1.0", default-features = false, features = ["derive"] }
+scale-info = { version = "2.0.1", default-features = false, features = ["derive"] }
 
 # Substrate Dependencies
 
diff --git a/bridges/primitives/runtime/src/storage_proof.rs b/bridges/primitives/runtime/src/storage_proof.rs
index 177b0f8664e4caded1a6348c25acf61ecf29a118..4a99ab6210f49e45871dd35ffb88a5c1dc4ddf7f 100644
--- a/bridges/primitives/runtime/src/storage_proof.rs
+++ b/bridges/primitives/runtime/src/storage_proof.rs
@@ -88,8 +88,7 @@ pub fn craft_valid_storage_proof() -> (sp_core::H256, StorageProof) {
 	let proof = StorageProof::new(
 		prove_read(backend, &[&b"key1"[..], &b"key2"[..], &b"key22"[..]])
 			.unwrap()
-			.iter_nodes()
-			.collect(),
+			.iter_nodes(),
 	);
 
 	(root, proof)
diff --git a/bridges/primitives/test-utils/Cargo.toml b/bridges/primitives/test-utils/Cargo.toml
index 0703b4f0f92659cd0863ca52148c4ede57e9b9e1..6da5c7c0f4b5fdaa1383f46feae6567fcfd26316 100644
--- a/bridges/primitives/test-utils/Cargo.toml
+++ b/bridges/primitives/test-utils/Cargo.toml
@@ -7,9 +7,9 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
 bp-header-chain = { path = "../header-chain", default-features = false  }
-codec = { package = "parity-scale-codec", version = "2.2.0", default-features = false }
+codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false }
 ed25519-dalek = { version = "1.0", default-features = false, features = ["u64_backend"] }
-finality-grandpa = { version = "0.14.0", default-features = false }
+finality-grandpa = { version = "0.15.0", default-features = false }
 sp-application-crypto = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
 sp-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false  }
 sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
diff --git a/bridges/primitives/token-swap/Cargo.toml b/bridges/primitives/token-swap/Cargo.toml
index 66af0be2f76d43d3a6d124ee7fece58504f618eb..9097856f853ac64a764cf23b19a40e8fb2e83833 100644
--- a/bridges/primitives/token-swap/Cargo.toml
+++ b/bridges/primitives/token-swap/Cargo.toml
@@ -7,8 +7,8 @@ edition = "2021"
 license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
-codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false }
-scale-info = { version = "1.0", default-features = false, features = ["derive"] }
+codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false }
+scale-info = { version = "2.0.1", default-features = false, features = ["derive"] }
 
 # Bridge Dependencies
 
diff --git a/bridges/relays/bin-substrate/Cargo.toml b/bridges/relays/bin-substrate/Cargo.toml
index 7083d265da5e734d5bc1c8e0efd89529f1b40850..fb8ff467d047dc48d3df605334f5e2bbe11e4203 100644
--- a/bridges/relays/bin-substrate/Cargo.toml
+++ b/bridges/relays/bin-substrate/Cargo.toml
@@ -9,7 +9,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 anyhow = "1.0"
 async-std = "1.9.0"
 async-trait = "0.1.42"
-codec = { package = "parity-scale-codec", version = "2.2.0" }
+codec = { package = "parity-scale-codec", version = "3.0.0" }
 futures = "0.3.12"
 hex = "0.4"
 log = "0.4.14"
@@ -79,4 +79,4 @@ hex-literal = "0.3"
 pallet-bridge-grandpa = { path = "../../modules/grandpa" }
 sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" }
 tempfile = "3.2"
-finality-grandpa = { version = "0.14.0" }
+finality-grandpa = { version = "0.15.0" }
diff --git a/bridges/relays/bin-substrate/src/cli/register_parachain.rs b/bridges/relays/bin-substrate/src/cli/register_parachain.rs
index 4d751437558907ab0be18c52de69baaea19adca5..c761a5dd1a6039f4ee61dc6edee5bfa01753aa0d 100644
--- a/bridges/relays/bin-substrate/src/cli/register_parachain.rs
+++ b/bridges/relays/bin-substrate/src/cli/register_parachain.rs
@@ -107,8 +107,8 @@ impl RegisterParachain {
 			let para_id: ParaId = relay_client
 				.storage_value(StorageKey(para_id_key.to_vec()), None)
 				.await?
-				.unwrap_or(polkadot_primitives::v1::LOWEST_PUBLIC_ID)
-				.max(polkadot_primitives::v1::LOWEST_PUBLIC_ID);
+				.unwrap_or(polkadot_primitives::v2::LOWEST_PUBLIC_ID)
+				.max(polkadot_primitives::v2::LOWEST_PUBLIC_ID);
 			log::info!(target: "bridge", "Going to reserve parachain id: {:?}", para_id);
 
 			// step 1: reserve a parachain id
diff --git a/bridges/relays/client-kusama/Cargo.toml b/bridges/relays/client-kusama/Cargo.toml
index 91a78719bbc2185edd94e03d664f773d4fbd65d5..35c24c1089e60248315d4bedd5d38a78c9d61631 100644
--- a/bridges/relays/client-kusama/Cargo.toml
+++ b/bridges/relays/client-kusama/Cargo.toml
@@ -6,10 +6,10 @@ edition = "2021"
 license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
-codec = { package = "parity-scale-codec", version = "2.2.0" }
+codec = { package = "parity-scale-codec", version = "3.0.0" }
 relay-substrate-client = { path = "../client-substrate" }
 relay-utils = { path = "../utils" }
-scale-info = { version = "1.0", features = ["derive"] }
+scale-info = { version = "2.0.1", features = ["derive"] }
 
 # Bridge dependencies
 
diff --git a/bridges/relays/client-millau/Cargo.toml b/bridges/relays/client-millau/Cargo.toml
index 3f193ffff033c13a9a4aaa1d4bbe612014864fd7..9893243345518b3b9a11a043e1d82c3298086a00 100644
--- a/bridges/relays/client-millau/Cargo.toml
+++ b/bridges/relays/client-millau/Cargo.toml
@@ -6,7 +6,7 @@ edition = "2021"
 license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
-codec = { package = "parity-scale-codec", version = "2.2.0" }
+codec = { package = "parity-scale-codec", version = "3.0.0" }
 relay-substrate-client = { path = "../client-substrate" }
 relay-utils = { path = "../utils" }
 
diff --git a/bridges/relays/client-millau/src/lib.rs b/bridges/relays/client-millau/src/lib.rs
index b0c1dc0dc7cd5c9a14fa51eefd9cd2a9a6cc56b7..e131f42494b314b4ed79fd8df96260eae5a5d620 100644
--- a/bridges/relays/client-millau/src/lib.rs
+++ b/bridges/relays/client-millau/src/lib.rs
@@ -105,6 +105,7 @@ impl TransactionSignScheme for Millau {
 		let raw_payload = SignedPayload::from_raw(
 			param.unsigned.call.clone(),
 			(
+				frame_system::CheckNonZeroSender::<millau_runtime::Runtime>::new(),
 				frame_system::CheckSpecVersion::<millau_runtime::Runtime>::new(),
 				frame_system::CheckTxVersion::<millau_runtime::Runtime>::new(),
 				frame_system::CheckGenesis::<millau_runtime::Runtime>::new(),
@@ -114,6 +115,7 @@ impl TransactionSignScheme for Millau {
 				pallet_transaction_payment::ChargeTransactionPayment::<millau_runtime::Runtime>::from(param.unsigned.tip),
 			),
 			(
+				(),
 				param.spec_version,
 				param.transaction_version,
 				param.genesis_hash,
diff --git a/bridges/relays/client-polkadot/Cargo.toml b/bridges/relays/client-polkadot/Cargo.toml
index 5c6904d57b356d617a51524fb4c1307a91ed5b25..96cfa2ce1bacf4cdecc65ef4c9f8b6687e25c308 100644
--- a/bridges/relays/client-polkadot/Cargo.toml
+++ b/bridges/relays/client-polkadot/Cargo.toml
@@ -6,10 +6,10 @@ edition = "2021"
 license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
-codec = { package = "parity-scale-codec", version = "2.2.0" }
+codec = { package = "parity-scale-codec", version = "3.0.0" }
 relay-substrate-client = { path = "../client-substrate" }
 relay-utils = { path = "../utils" }
-scale-info = { version = "1.0", features = ["derive"] }
+scale-info = { version = "2.0.1", features = ["derive"] }
 
 # Bridge dependencies
 
diff --git a/bridges/relays/client-rialto/Cargo.toml b/bridges/relays/client-rialto/Cargo.toml
index f8ceb3a925641814e51c653c6bd848b9ac446695..37c55dd5f153fcba803888d131809eb0f948d3bf 100644
--- a/bridges/relays/client-rialto/Cargo.toml
+++ b/bridges/relays/client-rialto/Cargo.toml
@@ -6,7 +6,7 @@ edition = "2021"
 license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
-codec = { package = "parity-scale-codec", version = "2.2.0" }
+codec = { package = "parity-scale-codec", version = "3.0.0" }
 relay-substrate-client = { path = "../client-substrate" }
 relay-utils = { path = "../utils" }
 
diff --git a/bridges/relays/client-rialto/src/lib.rs b/bridges/relays/client-rialto/src/lib.rs
index 5cd21d55e75479ecf7c679bf3dbc86eb71a05dd4..78e5f4431493d7f26aaea944ef72ed82a746d54b 100644
--- a/bridges/relays/client-rialto/src/lib.rs
+++ b/bridges/relays/client-rialto/src/lib.rs
@@ -105,6 +105,7 @@ impl TransactionSignScheme for Rialto {
 		let raw_payload = SignedPayload::from_raw(
 			param.unsigned.call.clone(),
 			(
+				frame_system::CheckNonZeroSender::<rialto_runtime::Runtime>::new(),
 				frame_system::CheckSpecVersion::<rialto_runtime::Runtime>::new(),
 				frame_system::CheckTxVersion::<rialto_runtime::Runtime>::new(),
 				frame_system::CheckGenesis::<rialto_runtime::Runtime>::new(),
@@ -114,6 +115,7 @@ impl TransactionSignScheme for Rialto {
 				pallet_transaction_payment::ChargeTransactionPayment::<rialto_runtime::Runtime>::from(param.unsigned.tip),
 			),
 			(
+				(),
 				param.spec_version,
 				param.transaction_version,
 				param.genesis_hash,
diff --git a/bridges/relays/client-rococo/Cargo.toml b/bridges/relays/client-rococo/Cargo.toml
index 8d256dc8814f894530ef4f68db7512fb01449d0e..2b78684a853cb491c46ca8382737ed0d96a5b2de 100644
--- a/bridges/relays/client-rococo/Cargo.toml
+++ b/bridges/relays/client-rococo/Cargo.toml
@@ -6,10 +6,10 @@ edition = "2021"
 license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
-codec = { package = "parity-scale-codec", version = "2.2.0" }
+codec = { package = "parity-scale-codec", version = "3.0.0" }
 relay-substrate-client = { path = "../client-substrate" }
 relay-utils = { path = "../utils" }
-scale-info = { version = "1.0", features = ["derive"] }
+scale-info = { version = "2.0.1", features = ["derive"] }
 
 # Bridge dependencies
 
diff --git a/bridges/relays/client-substrate/Cargo.toml b/bridges/relays/client-substrate/Cargo.toml
index 0f3e35c6f438f78d7fc23dc430196c35b25e68c2..dad864965e29ed5a195daac7bbf3e8c76139f59c 100644
--- a/bridges/relays/client-substrate/Cargo.toml
+++ b/bridges/relays/client-substrate/Cargo.toml
@@ -8,13 +8,13 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 [dependencies]
 async-std = { version = "1.6.5", features = ["attributes"] }
 async-trait = "0.1.40"
-codec = { package = "parity-scale-codec", version = "2.2.0" }
-jsonrpsee-proc-macros = "0.3.1"
-jsonrpsee-ws-client = "0.3.1"
+codec = { package = "parity-scale-codec", version = "3.0.0" }
+jsonrpsee = { version = "0.8", features = ["macros", "ws-client"] }
 log = "0.4.11"
 num-traits = "0.2"
 rand = "0.7"
-tokio = "1.8"
+serde = { version = "1.0" }
+tokio = { version = "1.8", features = ["rt-multi-thread"] }
 thiserror = "1.0.26"
 
 # Bridge dependencies
diff --git a/bridges/relays/client-substrate/src/chain.rs b/bridges/relays/client-substrate/src/chain.rs
index 6987fbae1c6b94234d8e805ac6755c6e6e58ceea..c3b0c32d5a4c014a85b12adfd3cb5dc8275439ee 100644
--- a/bridges/relays/client-substrate/src/chain.rs
+++ b/bridges/relays/client-substrate/src/chain.rs
@@ -18,7 +18,7 @@ use bp_messages::MessageNonce;
 use bp_runtime::{Chain as ChainBase, EncodedOrDecodedCall, HashOf, TransactionEraOf};
 use codec::{Codec, Encode};
 use frame_support::weights::{Weight, WeightToFeePolynomial};
-use jsonrpsee_ws_client::types::{DeserializeOwned, Serialize};
+use jsonrpsee::core::{DeserializeOwned, Serialize};
 use num_traits::Zero;
 use sc_transaction_pool_api::TransactionStatus;
 use sp_core::{storage::StorageKey, Pair};
diff --git a/bridges/relays/client-substrate/src/client.rs b/bridges/relays/client-substrate/src/client.rs
index f35281e2d35c58807a27939c22f5a111edacdc12..1e48bc3339668cdfafe8e8165e50c232e2b37f06 100644
--- a/bridges/relays/client-substrate/src/client.rs
+++ b/bridges/relays/client-substrate/src/client.rs
@@ -18,8 +18,9 @@
 
 use crate::{
 	chain::{Chain, ChainWithBalances, TransactionStatusOf},
-	rpc::Substrate,
-	ConnectionParams, Error, HashOf, HeaderIdOf, Result,
+	rpc::SubstrateClient,
+	AccountIdOf, BlockNumberOf, ConnectionParams, Error, HashOf, HeaderIdOf, HeaderOf, IndexOf,
+	Result,
 };
 
 use async_std::sync::{Arc, Mutex};
@@ -27,12 +28,10 @@ use async_trait::async_trait;
 use codec::{Decode, Encode};
 use frame_system::AccountInfo;
 use futures::{SinkExt, StreamExt};
-use jsonrpsee_ws_client::{
-	types::{
-		self as jsonrpsee_types, traits::SubscriptionClient, v2::params::JsonRpcParams,
-		DeserializeOwned,
-	},
-	WsClient as RpcClient, WsClientBuilder as RpcClientBuilder,
+use jsonrpsee::{
+	core::{client::SubscriptionClientT, DeserializeOwned},
+	types::params::ParamsSer,
+	ws_client::{WsClient as RpcClient, WsClientBuilder as RpcClientBuilder},
 };
 use num_traits::{Bounded, CheckedSub, One, Zero};
 use pallet_balances::AccountData;
@@ -154,7 +153,15 @@ impl<C: Chain> Client<C> {
 		let genesis_hash_client = client.clone();
 		let genesis_hash = tokio
 			.spawn(async move {
-				Substrate::<C>::chain_get_block_hash(&*genesis_hash_client, number).await
+				SubstrateClient::<
+					AccountIdOf<C>,
+					BlockNumberOf<C>,
+					HashOf<C>,
+					HeaderOf<C>,
+					IndexOf<C>,
+					C::SignedBlock,
+				>::chain_get_block_hash(&*genesis_hash_client, Some(number))
+				.await
 			})
 			.await??;
 
@@ -210,7 +217,15 @@ impl<C: Chain> Client<C> {
 	/// Returns true if client is connected to at least one peer and is in synced state.
 	pub async fn ensure_synced(&self) -> Result<()> {
 		self.jsonrpsee_execute(|client| async move {
-			let health = Substrate::<C>::system_health(&*client).await?;
+			let health = SubstrateClient::<
+				AccountIdOf<C>,
+				BlockNumberOf<C>,
+				HashOf<C>,
+				HeaderOf<C>,
+				IndexOf<C>,
+				C::SignedBlock,
+			>::system_health(&*client)
+			.await?;
 			let is_synced = !health.is_syncing && (!health.should_have_peers || health.peers > 0);
 			if is_synced {
 				Ok(())
@@ -229,7 +244,15 @@ impl<C: Chain> Client<C> {
 	/// Return hash of the best finalized block.
 	pub async fn best_finalized_header_hash(&self) -> Result<C::Hash> {
 		self.jsonrpsee_execute(|client| async move {
-			Ok(Substrate::<C>::chain_get_finalized_head(&*client).await?)
+			Ok(SubstrateClient::<
+				AccountIdOf<C>,
+				BlockNumberOf<C>,
+				HashOf<C>,
+				HeaderOf<C>,
+				IndexOf<C>,
+				C::SignedBlock,
+			>::chain_get_finalized_head(&*client)
+			.await?)
 		})
 		.await
 	}
@@ -245,7 +268,15 @@ impl<C: Chain> Client<C> {
 		C::Header: DeserializeOwned,
 	{
 		self.jsonrpsee_execute(|client| async move {
-			Ok(Substrate::<C>::chain_get_header(&*client, None).await?)
+			Ok(SubstrateClient::<
+				AccountIdOf<C>,
+				BlockNumberOf<C>,
+				HashOf<C>,
+				HeaderOf<C>,
+				IndexOf<C>,
+				C::SignedBlock,
+			>::chain_get_header(&*client, None)
+			.await?)
 		})
 		.await
 	}
@@ -253,7 +284,15 @@ impl<C: Chain> Client<C> {
 	/// Get a Substrate block from its hash.
 	pub async fn get_block(&self, block_hash: Option<C::Hash>) -> Result<C::SignedBlock> {
 		self.jsonrpsee_execute(move |client| async move {
-			Ok(Substrate::<C>::chain_get_block(&*client, block_hash).await?)
+			Ok(SubstrateClient::<
+				AccountIdOf<C>,
+				BlockNumberOf<C>,
+				HashOf<C>,
+				HeaderOf<C>,
+				IndexOf<C>,
+				C::SignedBlock,
+			>::chain_get_block(&*client, block_hash)
+			.await?)
 		})
 		.await
 	}
@@ -264,7 +303,15 @@ impl<C: Chain> Client<C> {
 		C::Header: DeserializeOwned,
 	{
 		self.jsonrpsee_execute(move |client| async move {
-			Ok(Substrate::<C>::chain_get_header(&*client, block_hash).await?)
+			Ok(SubstrateClient::<
+				AccountIdOf<C>,
+				BlockNumberOf<C>,
+				HashOf<C>,
+				HeaderOf<C>,
+				IndexOf<C>,
+				C::SignedBlock,
+			>::chain_get_header(&*client, Some(block_hash))
+			.await?)
 		})
 		.await
 	}
@@ -272,7 +319,15 @@ impl<C: Chain> Client<C> {
 	/// Get a Substrate block hash by its number.
 	pub async fn block_hash_by_number(&self, number: C::BlockNumber) -> Result<C::Hash> {
 		self.jsonrpsee_execute(move |client| async move {
-			Ok(Substrate::<C>::chain_get_block_hash(&*client, number).await?)
+			Ok(SubstrateClient::<
+				AccountIdOf<C>,
+				BlockNumberOf<C>,
+				HashOf<C>,
+				HeaderOf<C>,
+				IndexOf<C>,
+				C::SignedBlock,
+			>::chain_get_block_hash(&*client, Some(number))
+			.await?)
 		})
 		.await
 	}
@@ -290,7 +345,15 @@ impl<C: Chain> Client<C> {
 	/// Return runtime version.
 	pub async fn runtime_version(&self) -> Result<RuntimeVersion> {
 		self.jsonrpsee_execute(move |client| async move {
-			Ok(Substrate::<C>::state_runtime_version(&*client).await?)
+			Ok(SubstrateClient::<
+				AccountIdOf<C>,
+				BlockNumberOf<C>,
+				HashOf<C>,
+				HeaderOf<C>,
+				IndexOf<C>,
+				C::SignedBlock,
+			>::state_runtime_version(&*client)
+			.await?)
 		})
 		.await
 	}
@@ -316,7 +379,15 @@ impl<C: Chain> Client<C> {
 		block_hash: Option<C::Hash>,
 	) -> Result<Option<StorageData>> {
 		self.jsonrpsee_execute(move |client| async move {
-			Ok(Substrate::<C>::state_get_storage(&*client, storage_key, block_hash).await?)
+			Ok(SubstrateClient::<
+				AccountIdOf<C>,
+				BlockNumberOf<C>,
+				HashOf<C>,
+				HeaderOf<C>,
+				IndexOf<C>,
+				C::SignedBlock,
+			>::state_get_storage(&*client, storage_key, block_hash)
+			.await?)
 		})
 		.await
 	}
@@ -328,10 +399,16 @@ impl<C: Chain> Client<C> {
 	{
 		self.jsonrpsee_execute(move |client| async move {
 			let storage_key = C::account_info_storage_key(&account);
-			let encoded_account_data =
-				Substrate::<C>::state_get_storage(&*client, storage_key, None)
-					.await?
-					.ok_or(Error::AccountDoesNotExist)?;
+			let encoded_account_data = SubstrateClient::<
+				AccountIdOf<C>,
+				BlockNumberOf<C>,
+				HashOf<C>,
+				HeaderOf<C>,
+				IndexOf<C>,
+				C::SignedBlock,
+			>::state_get_storage(&*client, storage_key, None)
+			.await?
+			.ok_or(Error::AccountDoesNotExist)?;
 			let decoded_account_data = AccountInfo::<C::Index, AccountData<C::Balance>>::decode(
 				&mut &encoded_account_data.0[..],
 			)
@@ -346,7 +423,15 @@ impl<C: Chain> Client<C> {
 	/// Note: It's the caller's responsibility to make sure `account` is a valid SS58 address.
 	pub async fn next_account_index(&self, account: C::AccountId) -> Result<C::Index> {
 		self.jsonrpsee_execute(move |client| async move {
-			Ok(Substrate::<C>::system_account_next_index(&*client, account).await?)
+			Ok(SubstrateClient::<
+				AccountIdOf<C>,
+				BlockNumberOf<C>,
+				HashOf<C>,
+				HeaderOf<C>,
+				IndexOf<C>,
+				C::SignedBlock,
+			>::system_account_next_index(&*client, account)
+			.await?)
 		})
 		.await
 	}
@@ -356,7 +441,15 @@ impl<C: Chain> Client<C> {
 	/// Note: The given transaction needs to be SCALE encoded beforehand.
 	pub async fn submit_unsigned_extrinsic(&self, transaction: Bytes) -> Result<C::Hash> {
 		self.jsonrpsee_execute(move |client| async move {
-			let tx_hash = Substrate::<C>::author_submit_extrinsic(&*client, transaction).await?;
+			let tx_hash = SubstrateClient::<
+				AccountIdOf<C>,
+				BlockNumberOf<C>,
+				HashOf<C>,
+				HeaderOf<C>,
+				IndexOf<C>,
+				C::SignedBlock,
+			>::author_submit_extrinsic(&*client, transaction)
+			.await?;
 			log::trace!(target: "bridge", "Sent transaction to Substrate node: {:?}", tx_hash);
 			Ok(tx_hash)
 		})
@@ -391,7 +484,15 @@ impl<C: Chain> Client<C> {
 
 		self.jsonrpsee_execute(move |client| async move {
 			let extrinsic = prepare_extrinsic(best_header_id, transaction_nonce)?;
-			let tx_hash = Substrate::<C>::author_submit_extrinsic(&*client, extrinsic).await?;
+			let tx_hash = SubstrateClient::<
+				AccountIdOf<C>,
+				BlockNumberOf<C>,
+				HashOf<C>,
+				HeaderOf<C>,
+				IndexOf<C>,
+				C::SignedBlock,
+			>::author_submit_extrinsic(&*client, extrinsic)
+			.await?;
 			log::trace!(target: "bridge", "Sent transaction to {} node: {:?}", C::NAME, tx_hash);
 			Ok(tx_hash)
 		})
@@ -416,8 +517,8 @@ impl<C: Chain> Client<C> {
 				let subscription = client
 					.subscribe(
 						"author_submitAndWatchExtrinsic",
-						JsonRpcParams::Array(vec![jsonrpsee_types::to_json_value(extrinsic)
-							.map_err(|e| Error::RpcError(e.into()))?]),
+						Some(ParamsSer::Array(vec![jsonrpsee::core::to_json_value(extrinsic)
+							.map_err(|e| Error::RpcError(e.into()))?])),
 						"author_unwatchExtrinsic",
 					)
 					.await?;
@@ -438,7 +539,15 @@ impl<C: Chain> Client<C> {
 	/// Returns pending extrinsics from transaction pool.
 	pub async fn pending_extrinsics(&self) -> Result<Vec<Bytes>> {
 		self.jsonrpsee_execute(move |client| async move {
-			Ok(Substrate::<C>::author_pending_extrinsics(&*client).await?)
+			Ok(SubstrateClient::<
+				AccountIdOf<C>,
+				BlockNumberOf<C>,
+				HashOf<C>,
+				HeaderOf<C>,
+				IndexOf<C>,
+				C::SignedBlock,
+			>::author_pending_extrinsics(&*client)
+			.await?)
 		})
 		.await
 	}
@@ -453,8 +562,15 @@ impl<C: Chain> Client<C> {
 			let call = SUB_API_TXPOOL_VALIDATE_TRANSACTION.to_string();
 			let data = Bytes((TransactionSource::External, transaction, at_block).encode());
 
-			let encoded_response =
-				Substrate::<C>::state_call(&*client, call, data, Some(at_block)).await?;
+			let encoded_response = SubstrateClient::<
+				AccountIdOf<C>,
+				BlockNumberOf<C>,
+				HashOf<C>,
+				HeaderOf<C>,
+				IndexOf<C>,
+				C::SignedBlock,
+			>::state_call(&*client, call, data, Some(at_block))
+			.await?;
 			let validity = TransactionValidity::decode(&mut &encoded_response.0[..])
 				.map_err(Error::ResponseParseFailed)?;
 
@@ -469,8 +585,15 @@ impl<C: Chain> Client<C> {
 		transaction: Bytes,
 	) -> Result<InclusionFee<C::Balance>> {
 		self.jsonrpsee_execute(move |client| async move {
-			let fee_details =
-				Substrate::<C>::payment_query_fee_details(&*client, transaction, None).await?;
+			let fee_details = SubstrateClient::<
+				AccountIdOf<C>,
+				BlockNumberOf<C>,
+				HashOf<C>,
+				HeaderOf<C>,
+				IndexOf<C>,
+				C::SignedBlock,
+			>::payment_query_fee_details(&*client, transaction, None)
+			.await?;
 			let inclusion_fee = fee_details
 				.inclusion_fee
 				.map(|inclusion_fee| InclusionFee {
@@ -502,8 +625,15 @@ impl<C: Chain> Client<C> {
 			let call = SUB_API_GRANDPA_AUTHORITIES.to_string();
 			let data = Bytes(Vec::new());
 
-			let encoded_response =
-				Substrate::<C>::state_call(&*client, call, data, Some(block)).await?;
+			let encoded_response = SubstrateClient::<
+				AccountIdOf<C>,
+				BlockNumberOf<C>,
+				HashOf<C>,
+				HeaderOf<C>,
+				IndexOf<C>,
+				C::SignedBlock,
+			>::state_call(&*client, call, data, Some(block))
+			.await?;
 			let authority_list = encoded_response.0;
 
 			Ok(authority_list)
@@ -519,9 +649,16 @@ impl<C: Chain> Client<C> {
 		at_block: Option<C::Hash>,
 	) -> Result<Bytes> {
 		self.jsonrpsee_execute(move |client| async move {
-			Substrate::<C>::state_call(&*client, method, data, at_block)
-				.await
-				.map_err(Into::into)
+			SubstrateClient::<
+				AccountIdOf<C>,
+				BlockNumberOf<C>,
+				HashOf<C>,
+				HeaderOf<C>,
+				IndexOf<C>,
+				C::SignedBlock,
+			>::state_call(&*client, method, data, at_block)
+			.await
+			.map_err(Into::into)
 		})
 		.await
 	}
@@ -533,10 +670,19 @@ impl<C: Chain> Client<C> {
 		at_block: C::Hash,
 	) -> Result<StorageProof> {
 		self.jsonrpsee_execute(move |client| async move {
-			Substrate::<C>::state_prove_storage(&*client, keys, Some(at_block))
-				.await
-				.map(|proof| StorageProof::new(proof.proof.into_iter().map(|b| b.0).collect()))
-				.map_err(Into::into)
+			SubstrateClient::<
+				AccountIdOf<C>,
+				BlockNumberOf<C>,
+				HashOf<C>,
+				HeaderOf<C>,
+				IndexOf<C>,
+				C::SignedBlock,
+			>::state_prove_storage(&*client, keys, Some(at_block))
+			.await
+			.map(|proof| {
+				StorageProof::new(proof.proof.into_iter().map(|b| b.0).collect::<Vec<_>>())
+			})
+			.map_err(Into::into)
 		})
 		.await
 	}
@@ -544,7 +690,15 @@ impl<C: Chain> Client<C> {
 	/// Return `tokenDecimals` property from the set of chain properties.
 	pub async fn token_decimals(&self) -> Result<Option<u64>> {
 		self.jsonrpsee_execute(move |client| async move {
-			let system_properties = Substrate::<C>::system_properties(&*client).await?;
+			let system_properties = SubstrateClient::<
+				AccountIdOf<C>,
+				BlockNumberOf<C>,
+				HashOf<C>,
+				HeaderOf<C>,
+				IndexOf<C>,
+				C::SignedBlock,
+			>::system_properties(&*client)
+			.await?;
 			Ok(system_properties.get("tokenDecimals").and_then(|v| v.as_u64()))
 		})
 		.await
@@ -557,7 +711,7 @@ impl<C: Chain> Client<C> {
 				Ok(client
 					.subscribe(
 						"grandpa_subscribeJustifications",
-						JsonRpcParams::NoParams,
+						None,
 						"grandpa_unsubscribeJustifications",
 					)
 					.await?)
@@ -597,32 +751,32 @@ impl<T: DeserializeOwned> Subscription<T> {
 	async fn background_worker(
 		chain_name: String,
 		item_type: String,
-		mut subscription: jsonrpsee_types::Subscription<T>,
+		mut subscription: jsonrpsee::core::client::Subscription<T>,
 		mut sender: futures::channel::mpsc::Sender<Option<T>>,
 	) {
 		loop {
 			match subscription.next().await {
-				Ok(Some(item)) =>
+				Some(Ok(item)) =>
 					if sender.send(Some(item)).await.is_err() {
 						break
 					},
-				Ok(None) => {
+				Some(Err(e)) => {
 					log::trace!(
 						target: "bridge",
-						"{} {} subscription stream has returned None. Stream needs to be restarted.",
+						"{} {} subscription stream has returned '{:?}'. Stream needs to be restarted.",
 						chain_name,
 						item_type,
+						e,
 					);
 					let _ = sender.send(None).await;
 					break
 				},
-				Err(e) => {
+				None => {
 					log::trace!(
 						target: "bridge",
-						"{} {} subscription stream has returned '{:?}'. Stream needs to be restarted.",
+						"{} {} subscription stream has returned None. Stream needs to be restarted.",
 						chain_name,
 						item_type,
-						e,
 					);
 					let _ = sender.send(None).await;
 					break
diff --git a/bridges/relays/client-substrate/src/error.rs b/bridges/relays/client-substrate/src/error.rs
index 309531dd260992294525ce27961b2d663bee1f29..e698f2596c5fa400d400c6f600922cedf985cb22 100644
--- a/bridges/relays/client-substrate/src/error.rs
+++ b/bridges/relays/client-substrate/src/error.rs
@@ -16,7 +16,7 @@
 
 //! Substrate node RPC errors.
 
-use jsonrpsee_ws_client::types::Error as RpcError;
+use jsonrpsee::core::Error as RpcError;
 use relay_utils::MaybeConnectionError;
 use sc_rpc_api::system::Health;
 use sp_runtime::transaction_validity::TransactionValidityError;
diff --git a/bridges/relays/client-substrate/src/rpc.rs b/bridges/relays/client-substrate/src/rpc.rs
index b792347d7a2ba962c822b01bb1832a1ace9884e9..a0172d1e550136639b8991d2f63a77131b5c3059 100644
--- a/bridges/relays/client-substrate/src/rpc.rs
+++ b/bridges/relays/client-substrate/src/rpc.rs
@@ -16,8 +16,7 @@
 
 //! The most generic Substrate node RPC interface.
 
-use crate::chain::Chain;
-
+use jsonrpsee::{core::RpcResult, proc_macros::rpc};
 use pallet_transaction_payment_rpc_runtime_api::FeeDetails;
 use sc_rpc_api::{state::ReadProof, system::Health};
 use sp_core::{
@@ -27,35 +26,51 @@ use sp_core::{
 use sp_rpc::number::NumberOrHex;
 use sp_version::RuntimeVersion;
 
-jsonrpsee_proc_macros::rpc_client_api! {
-	pub(crate) Substrate<C: Chain> {
-		#[rpc(method = "system_health", positional_params)]
-		fn system_health() -> Health;
-		#[rpc(method = "system_properties", positional_params)]
-		fn system_properties() -> sc_chain_spec::Properties;
-		#[rpc(method = "chain_getHeader", positional_params)]
-		fn chain_get_header(block_hash: Option<C::Hash>) -> C::Header;
-		#[rpc(method = "chain_getFinalizedHead", positional_params)]
-		fn chain_get_finalized_head() -> C::Hash;
-		#[rpc(method = "chain_getBlock", positional_params)]
-		fn chain_get_block(block_hash: Option<C::Hash>) -> C::SignedBlock;
-		#[rpc(method = "chain_getBlockHash", positional_params)]
-		fn chain_get_block_hash(block_number: Option<C::BlockNumber>) -> C::Hash;
-		#[rpc(method = "system_accountNextIndex", positional_params)]
-		fn system_account_next_index(account_id: C::AccountId) -> C::Index;
-		#[rpc(method = "author_submitExtrinsic", positional_params)]
-		fn author_submit_extrinsic(extrinsic: Bytes) -> C::Hash;
-		#[rpc(method = "author_pendingExtrinsics", positional_params)]
-		fn author_pending_extrinsics() -> Vec<Bytes>;
-		#[rpc(method = "state_call", positional_params)]
-		fn state_call(method: String, data: Bytes, at_block: Option<C::Hash>) -> Bytes;
-		#[rpc(method = "state_getStorage", positional_params)]
-		fn state_get_storage(key: StorageKey, at_block: Option<C::Hash>) -> Option<StorageData>;
-		#[rpc(method = "state_getReadProof", positional_params)]
-		fn state_prove_storage(keys: Vec<StorageKey>, hash: Option<C::Hash>) -> ReadProof<C::Hash>;
-		#[rpc(method = "state_getRuntimeVersion", positional_params)]
-		fn state_runtime_version() -> RuntimeVersion;
-		#[rpc(method = "payment_queryFeeDetails", positional_params)]
-		fn payment_query_fee_details(extrinsic: Bytes, at_block: Option<C::Hash>) -> FeeDetails<NumberOrHex>;
-	}
+#[rpc(client)]
+pub(crate) trait Substrate<AccountId, BlockNumber, Hash, Header, Index, SignedBlock> {
+	#[method(name = "system_health", param_kind = array)]
+	async fn system_health(&self) -> RpcResult<Health>;
+	#[method(name = "system_properties", param_kind = array)]
+	async fn system_properties(&self) -> RpcResult<sc_chain_spec::Properties>;
+	#[method(name = "chain_getHeader", param_kind = array)]
+	async fn chain_get_header(&self, block_hash: Option<Hash>) -> RpcResult<Header>;
+	#[method(name = "chain_getFinalizedHead", param_kind = array)]
+	async fn chain_get_finalized_head(&self) -> RpcResult<Hash>;
+	#[method(name = "chain_getBlock", param_kind = array)]
+	async fn chain_get_block(&self, block_hash: Option<Hash>) -> RpcResult<SignedBlock>;
+	#[method(name = "chain_getBlockHash", param_kind = array)]
+	async fn chain_get_block_hash(&self, block_number: Option<BlockNumber>) -> RpcResult<Hash>;
+	#[method(name = "system_accountNextIndex", param_kind = array)]
+	async fn system_account_next_index(&self, account_id: AccountId) -> RpcResult<Index>;
+	#[method(name = "author_submitExtrinsic", param_kind = array)]
+	async fn author_submit_extrinsic(&self, extrinsic: Bytes) -> RpcResult<Hash>;
+	#[method(name = "author_pendingExtrinsics", param_kind = array)]
+	async fn author_pending_extrinsics(&self) -> RpcResult<Vec<Bytes>>;
+	#[method(name = "state_call", param_kind = array)]
+	async fn state_call(
+		&self,
+		method: String,
+		data: Bytes,
+		at_block: Option<Hash>,
+	) -> RpcResult<Bytes>;
+	#[method(name = "state_getStorage", param_kind = array)]
+	async fn state_get_storage(
+		&self,
+		key: StorageKey,
+		at_block: Option<Hash>,
+	) -> RpcResult<Option<StorageData>>;
+	#[method(name = "state_getReadProof", param_kind = array)]
+	async fn state_prove_storage(
+		&self,
+		keys: Vec<StorageKey>,
+		hash: Option<Hash>,
+	) -> RpcResult<ReadProof<Hash>>;
+	#[method(name = "state_getRuntimeVersion", param_kind = array)]
+	async fn state_runtime_version(&self) -> RpcResult<RuntimeVersion>;
+	#[method(name = "payment_queryFeeDetails", param_kind = array)]
+	async fn payment_query_fee_details(
+		&self,
+		extrinsic: Bytes,
+		at_block: Option<Hash>,
+	) -> RpcResult<FeeDetails<NumberOrHex>>;
 }
diff --git a/bridges/relays/client-westend/Cargo.toml b/bridges/relays/client-westend/Cargo.toml
index 8a0e6434d09ab1564fb93d3e4beb94b277326f59..d38aa162994595a42ad06b7d8864400766003b31 100644
--- a/bridges/relays/client-westend/Cargo.toml
+++ b/bridges/relays/client-westend/Cargo.toml
@@ -6,7 +6,7 @@ edition = "2021"
 license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
-codec = { package = "parity-scale-codec", version = "2.2.0" }
+codec = { package = "parity-scale-codec", version = "3.0.0" }
 relay-substrate-client = { path = "../client-substrate" }
 relay-utils = { path = "../utils" }
 
diff --git a/bridges/relays/client-wococo/Cargo.toml b/bridges/relays/client-wococo/Cargo.toml
index 201a727fc47552c1a9393b96d344d250c1070fd0..6845ac34c84a079d4d2d7e4160cccc4ecd632f52 100644
--- a/bridges/relays/client-wococo/Cargo.toml
+++ b/bridges/relays/client-wococo/Cargo.toml
@@ -6,10 +6,10 @@ edition = "2021"
 license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
 
 [dependencies]
-codec = { package = "parity-scale-codec", version = "2.2.0" }
+codec = { package = "parity-scale-codec", version = "3.0.0" }
 relay-substrate-client = { path = "../client-substrate" }
 relay-utils = { path = "../utils" }
-scale-info = { version = "1.0", default-features = false, features = ["derive"] }
+scale-info = { version = "2.0.1", default-features = false, features = ["derive"] }
 
 # Bridge dependencies
 bridge-runtime-common = { path = "../../bin/runtime-common" }
diff --git a/bridges/relays/lib-substrate-relay/Cargo.toml b/bridges/relays/lib-substrate-relay/Cargo.toml
index 52e800caa77c77d38de832d1ece1ac4ff2c70364..e2cabf52f449b397c1fbf385988a57bab45e2ad4 100644
--- a/bridges/relays/lib-substrate-relay/Cargo.toml
+++ b/bridges/relays/lib-substrate-relay/Cargo.toml
@@ -10,18 +10,17 @@ anyhow = "1.0"
 thiserror = "1.0.26"
 async-std = "1.9.0"
 async-trait = "0.1.42"
-codec = { package = "parity-scale-codec", version = "2.2.0" }
+codec = { package = "parity-scale-codec", version = "3.0.0" }
 futures = "0.3.12"
 num-traits = "0.2"
 log = "0.4.14"
 
-
 # Bridge dependencies
 
 bp-header-chain = { path = "../../primitives/header-chain" }
 bridge-runtime-common = { path = "../../bin/runtime-common" }
 
-finality-grandpa = { version = "0.14.0" }
+finality-grandpa = { version = "0.15.0" }
 finality-relay = { path = "../finality" }
 relay-utils = { path = "../utils" }
 messages-relay = { path = "../messages" }
diff --git a/bridges/relays/utils/Cargo.toml b/bridges/relays/utils/Cargo.toml
index 123c23176786ce6261da43aa4ecdf4d2d6037523..bb69849da26b0f75e8f6d2624cd71ac84b9637c3 100644
--- a/bridges/relays/utils/Cargo.toml
+++ b/bridges/relays/utils/Cargo.toml
@@ -20,6 +20,7 @@ num-traits = "0.2"
 serde_json = "1.0"
 sysinfo = "0.15"
 time = { version = "0.3", features = ["formatting", "local-offset", "std"] }
+tokio = { version = "1.8", features = ["rt"] }
 thiserror = "1.0.26"
 
 # Bridge dependencies
diff --git a/bridges/relays/utils/src/relay_loop.rs b/bridges/relays/utils/src/relay_loop.rs
index a992aaaf57ee505f970e86d6b571115702b43621..521a6345d3e39c988657266b1a68f300c469460a 100644
--- a/bridges/relays/utils/src/relay_loop.rs
+++ b/bridges/relays/utils/src/relay_loop.rs
@@ -187,12 +187,32 @@ impl<SC, TC, LM> LoopMetrics<SC, TC, LM> {
 
 			let registry = self.registry;
 			async_std::task::spawn(async move {
-				let result = init_prometheus(socket_addr, registry).await;
-				log::trace!(
-					target: "bridge-metrics",
-					"Prometheus endpoint has exited with result: {:?}",
-					result,
-				);
+				let runtime =
+					match tokio::runtime::Builder::new_current_thread().enable_all().build() {
+						Ok(runtime) => runtime,
+						Err(err) => {
+							log::trace!(
+								target: "bridge-metrics",
+								"Failed to create tokio runtime. Prometheus meterics are not available: {:?}",
+								err,
+							);
+							return
+						},
+					};
+
+				let _ = runtime.block_on(async move {
+					log::trace!(
+						target: "bridge-metrics",
+						"Starting prometheus endpoint at: {:?}",
+						socket_addr,
+					);
+					let result = init_prometheus(socket_addr, registry).await;
+					log::trace!(
+						target: "bridge-metrics",
+						"Prometheus endpoint has exited with result: {:?}",
+						result,
+					);
+				});
 			});
 		}