diff --git a/Cargo.lock b/Cargo.lock
index 9f2a1a068918379151562b7b81e73ef0c5631471..93ee9cc99c446a5722e7cdff692507c7ee02a605 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1054,6 +1054,7 @@ dependencies = [
  "pallet-balances",
  "pallet-collator-selection",
  "pallet-session",
+ "pallet-timestamp",
  "pallet-xcm",
  "pallet-xcm-bridge-hub-router",
  "parachains-common",
@@ -2099,6 +2100,7 @@ dependencies = [
  "pallet-bridge-messages",
  "pallet-bridge-parachains",
  "pallet-bridge-relayers",
+ "pallet-timestamp",
  "pallet-utility",
  "parachains-common",
  "parachains-runtimes-test-utils",
@@ -11430,6 +11432,7 @@ dependencies = [
  "pallet-balances",
  "pallet-collator-selection",
  "pallet-session",
+ "pallet-timestamp",
  "pallet-xcm",
  "parity-scale-codec",
  "polkadot-parachain-primitives",
diff --git a/bridges/snowbridge/README.md b/bridges/snowbridge/README.md
index 49b9c2eaf553780176897a770bad9579d53bfaa9..6561df401120e9c5c5d6ee2762eb1423b5d6daaf 100644
--- a/bridges/snowbridge/README.md
+++ b/bridges/snowbridge/README.md
@@ -1,32 +1,40 @@
-# Snowbridge
-[![codecov](https://codecov.io/gh/Snowfork/snowbridge/branch/main/graph/badge.svg?token=9hvgSws4rN)](https://codecov.io/gh/Snowfork/snowbridge)
+# Snowbridge ·
+[![codecov](https://codecov.io/gh/Snowfork/polkadot-sdk/branch/snowbridge/graph/badge.svg?token=9hvgSws4rN)](https://codecov.io/gh/Snowfork/polkadot-sdk)
 ![GitHub](https://img.shields.io/github/license/Snowfork/snowbridge)
 
 Snowbridge is a trustless bridge between Polkadot and Ethereum. For documentation, visit https://docs.snowbridge.network.
 
 ## Components
 
+The Snowbridge project lives in two repositories:
+
+- [Snowfork/Polkadot-sdk](https://github.com/Snowfork/polkadot-sdk): The Snowbridge parachain and pallets live in
+a fork of the Polkadot SDK. Changes are eventually contributed back to
+[paritytech/Polkadot-sdk](https://github.com/paritytech/polkadot-sdk)
+- [Snowfork/snowbridge](https://github.com/Snowfork/snowbridge): The rest of the Snowbridge components, like contracts,
+off-chain relayer, end-to-end tests and test-net setup code.
+
 ### Parachain
 
-Polkadot parachain and our pallets. See [parachain/README.md](https://github.com/Snowfork/snowbridge/blob/main/parachain/README.md).
+Polkadot parachain and our pallets. See [README.md](https://github.com/Snowfork/polkadot-sdk/blob/snowbridge/bridges/snowbridge/README.md).
 
 ### Contracts
 
-Ethereum contracts and unit tests. See [contracts/README.md](https://github.com/Snowfork/snowbridge/blob/main/contracts/README.md)
+Ethereum contracts and unit tests. See [Snowfork/snowbridge/contracts/README.md](https://github.com/Snowfork/snowbridge/blob/main/contracts/README.md)
 
 ### Relayer
 
 Off-chain relayer services for relaying messages between Polkadot and Ethereum. See
-[relayer/README.md](https://github.com/Snowfork/snowbridge/blob/main/relayer/README.md)
+[Snowfork/snowbridge/relayer/README.md](https://github.com/Snowfork/snowbridge/blob/main/relayer/README.md)
 
 ### Local Testnet
 
 Scripts to provision a local testnet, running the above services to bridge between local deployments of Polkadot and
-Ethereum. See [web/packages/test/README.md](https://github.com/Snowfork/snowbridge/blob/main/web/packages/test/README.md).
+Ethereum. See [Snowfork/snowbridge/web/packages/test/README.md](https://github.com/Snowfork/snowbridge/blob/main/web/packages/test/README.md).
 
 ### Smoke Tests
 
-Integration tests for our local testnet. See [smoketest/README.md](https://github.com/Snowfork/snowbridge/blob/main/smoketest/README.md).
+Integration tests for our local testnet. See [Snowfork/snowbridge/smoketest/README.md](https://github.com/Snowfork/snowbridge/blob/main/smoketest/README.md).
 
 ## Development
 
@@ -83,7 +91,7 @@ direnv allow
 
 ### Upgrading the Rust toolchain
 
-Sometimes we would like to upgrade rust toolchain. First update `parachain/rust-toolchain.toml` as required and then
+Sometimes we would like to upgrade rust toolchain. First update `rust-toolchain.toml` as required and then
 update `flake.lock` running
 ```sh
 nix flake lock --update-input rust-overlay
diff --git a/bridges/snowbridge/pallets/system/src/lib.rs b/bridges/snowbridge/pallets/system/src/lib.rs
index b7f38fb753d31bd67acb78174e175f90fc711175..6e5ceb5e9b1d42796567c3da5e549b2af3cfd4de 100644
--- a/bridges/snowbridge/pallets/system/src/lib.rs
+++ b/bridges/snowbridge/pallets/system/src/lib.rs
@@ -37,8 +37,6 @@
 //! `force_update_channel` and extrinsics to manage agents and channels for system parachains.
 #![cfg_attr(not(feature = "std"), no_std)]
 
-pub use pallet::*;
-
 #[cfg(test)]
 mod mock;
 
@@ -79,6 +77,8 @@ use xcm_executor::traits::ConvertLocation;
 #[cfg(feature = "runtime-benchmarks")]
 use frame_support::traits::OriginTrait;
 
+pub use pallet::*;
+
 pub type BalanceOf<T> =
 	<<T as pallet::Config>::Token as Inspect<<T as frame_system::Config>::AccountId>>::Balance;
 pub type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
diff --git a/bridges/snowbridge/runtime/test-common/src/lib.rs b/bridges/snowbridge/runtime/test-common/src/lib.rs
index c9bbce98e575d5e55015aa7814d8cd57a5c3a966..29b0e738c182e3a9dd930fe8596fc5430470d5e0 100644
--- a/bridges/snowbridge/runtime/test-common/src/lib.rs
+++ b/bridges/snowbridge/runtime/test-common/src/lib.rs
@@ -13,9 +13,9 @@ use parachains_runtimes_test_utils::{
 };
 use snowbridge_core::{ChannelId, ParaId};
 use snowbridge_pallet_ethereum_client_fixtures::*;
-use sp_core::H160;
+use sp_core::{H160, U256};
 use sp_keyring::AccountKeyring::*;
-use sp_runtime::{traits::Header, AccountId32, SaturatedConversion, Saturating};
+use sp_runtime::{traits::Header, AccountId32, DigestItem, SaturatedConversion, Saturating};
 use xcm::{
 	latest::prelude::*,
 	v3::Error::{self, Barrier},
@@ -53,7 +53,8 @@ where
 		+ parachain_info::Config
 		+ pallet_collator_selection::Config
 		+ cumulus_pallet_parachain_system::Config
-		+ snowbridge_pallet_outbound_queue::Config,
+		+ snowbridge_pallet_outbound_queue::Config
+		+ pallet_timestamp::Config,
 	XcmConfig: xcm_executor::Config,
 {
 	let assethub_parachain_location = Location::new(1, Parachain(assethub_parachain_id));
@@ -125,7 +126,8 @@ pub fn send_transfer_token_message_success<Runtime, XcmConfig>(
 		+ pallet_message_queue::Config
 		+ cumulus_pallet_parachain_system::Config
 		+ snowbridge_pallet_outbound_queue::Config
-		+ snowbridge_pallet_system::Config,
+		+ snowbridge_pallet_system::Config
+		+ pallet_timestamp::Config,
 	XcmConfig: xcm_executor::Config,
 	ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
 	<Runtime as frame_system::Config>::AccountId: From<sp_runtime::AccountId32> + AsRef<[u8]>,
@@ -193,12 +195,100 @@ pub fn send_transfer_token_message_success<Runtime, XcmConfig>(
 
 			let digest = included_head.digest();
 
-			//let digest = frame_system::Pallet::<Runtime>::digest();
 			let digest_items = digest.logs();
 			assert!(digest_items.len() == 1 && digest_items[0].as_other().is_some());
 		});
 }
 
+pub fn ethereum_outbound_queue_processes_messages_before_message_queue_works<
+	Runtime,
+	XcmConfig,
+	AllPalletsWithoutSystem,
+>(
+	collator_session_key: CollatorSessionKeys<Runtime>,
+	runtime_para_id: u32,
+	assethub_parachain_id: u32,
+	weth_contract_address: H160,
+	destination_address: H160,
+	fee_amount: u128,
+	snowbridge_pallet_outbound_queue: Box<
+		dyn Fn(Vec<u8>) -> Option<snowbridge_pallet_outbound_queue::Event<Runtime>>,
+	>,
+) where
+	Runtime: frame_system::Config
+		+ pallet_balances::Config
+		+ pallet_session::Config
+		+ pallet_xcm::Config
+		+ parachain_info::Config
+		+ pallet_collator_selection::Config
+		+ pallet_message_queue::Config
+		+ cumulus_pallet_parachain_system::Config
+		+ snowbridge_pallet_outbound_queue::Config
+		+ snowbridge_pallet_system::Config
+		+ pallet_timestamp::Config,
+	XcmConfig: xcm_executor::Config,
+	AllPalletsWithoutSystem:
+		OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
+	ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
+	<Runtime as frame_system::Config>::AccountId: From<sp_runtime::AccountId32> + AsRef<[u8]>,
+{
+	ExtBuilder::<Runtime>::default()
+		.with_collators(collator_session_key.collators())
+		.with_session_keys(collator_session_key.session_keys())
+		.with_para_id(runtime_para_id.into())
+		.with_tracing()
+		.build()
+		.execute_with(|| {
+			<snowbridge_pallet_system::Pallet<Runtime>>::initialize(
+				runtime_para_id.into(),
+				assethub_parachain_id.into(),
+			)
+			.unwrap();
+
+			// fund asset hub sovereign account enough so it can pay fees
+			initial_fund::<Runtime>(assethub_parachain_id, 5_000_000_000_000);
+
+			let outcome = send_transfer_token_message::<Runtime, XcmConfig>(
+				assethub_parachain_id,
+				weth_contract_address,
+				destination_address,
+				fee_amount,
+			);
+
+			assert_ok!(outcome.ensure_complete());
+
+			// check events
+			let mut events = <frame_system::Pallet<Runtime>>::events()
+				.into_iter()
+				.filter_map(|e| snowbridge_pallet_outbound_queue(e.event.encode()));
+			assert!(events.any(|e| matches!(
+				e,
+				snowbridge_pallet_outbound_queue::Event::MessageQueued { .. }
+			)));
+
+			let next_block_number: U256 = <frame_system::Pallet<Runtime>>::block_number()
+				.saturating_add(BlockNumberFor::<Runtime>::from(1u32))
+				.into();
+
+			let included_head =
+				RuntimeHelper::<Runtime, AllPalletsWithoutSystem>::run_to_block_with_finalize(
+					next_block_number.as_u32(),
+				);
+			let digest = included_head.digest();
+			let digest_items = digest.logs();
+
+			let mut found_outbound_digest = false;
+			for digest_item in digest_items {
+				match digest_item {
+					DigestItem::Other(_) => found_outbound_digest = true,
+					_ => {},
+				}
+			}
+
+			assert_eq!(found_outbound_digest, true);
+		});
+}
+
 pub fn send_unpaid_transfer_token_message<Runtime, XcmConfig>(
 	collator_session_key: CollatorSessionKeys<Runtime>,
 	runtime_para_id: u32,
@@ -213,7 +303,8 @@ pub fn send_unpaid_transfer_token_message<Runtime, XcmConfig>(
 		+ parachain_info::Config
 		+ pallet_collator_selection::Config
 		+ cumulus_pallet_parachain_system::Config
-		+ snowbridge_pallet_outbound_queue::Config,
+		+ snowbridge_pallet_outbound_queue::Config
+		+ pallet_timestamp::Config,
 	XcmConfig: xcm_executor::Config,
 	ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
 {
@@ -301,7 +392,8 @@ pub fn send_transfer_token_message_failure<Runtime, XcmConfig>(
 		+ pallet_collator_selection::Config
 		+ cumulus_pallet_parachain_system::Config
 		+ snowbridge_pallet_outbound_queue::Config
-		+ snowbridge_pallet_system::Config,
+		+ snowbridge_pallet_system::Config
+		+ pallet_timestamp::Config,
 	XcmConfig: xcm_executor::Config,
 	ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
 {
@@ -349,7 +441,8 @@ pub fn ethereum_extrinsic<Runtime>(
 		+ cumulus_pallet_parachain_system::Config
 		+ snowbridge_pallet_outbound_queue::Config
 		+ snowbridge_pallet_system::Config
-		+ snowbridge_pallet_ethereum_client::Config,
+		+ snowbridge_pallet_ethereum_client::Config
+		+ pallet_timestamp::Config,
 	ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
 	<Runtime as pallet_utility::Config>::RuntimeCall:
 		From<snowbridge_pallet_ethereum_client::Call<Runtime>>,
@@ -430,7 +523,8 @@ pub fn ethereum_to_polkadot_message_extrinsics_work<Runtime>(
 		+ cumulus_pallet_parachain_system::Config
 		+ snowbridge_pallet_outbound_queue::Config
 		+ snowbridge_pallet_system::Config
-		+ snowbridge_pallet_ethereum_client::Config,
+		+ snowbridge_pallet_ethereum_client::Config
+		+ pallet_timestamp::Config,
 	ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
 	<Runtime as pallet_utility::Config>::RuntimeCall:
 		From<snowbridge_pallet_ethereum_client::Call<Runtime>>,
diff --git a/bridges/snowbridge/scripts/contribute-upstream.sh b/bridges/snowbridge/scripts/contribute-upstream.sh
new file mode 100755
index 0000000000000000000000000000000000000000..8aa2d2a7035e2f213c0fc2090952b4b162739963
--- /dev/null
+++ b/bridges/snowbridge/scripts/contribute-upstream.sh
@@ -0,0 +1,80 @@
+#!/bin/bash
+
+# A script to cleanup the Snowfork fork of the polkadot-sdk to contribute it upstream back to parity/polkadot-sdk
+# ./bridges/snowbridge/scripts/contribute-upstream.sh <branchname>
+
+# show CLI help
+function show_help() {
+  set +x
+  echo " "
+  echo Error: $1
+  echo "Usage:"
+  echo "  ./bridges/snowbridge/scripts/contribute-upstream.sh <branchname>         Exit with code 0 if pallets code is well decoupled from the other code in the repo"
+  exit 1
+}
+
+if [[ -z "$1" ]]; then
+    echo "Please provide a branch name you would like your upstream branch to be named"
+    exit 1
+fi
+
+branch_name=$1
+
+set -eux
+
+# let's avoid any restrictions on where this script can be called for - snowbridge repo may be
+# plugged into any other repo folder. So the script (and other stuff that needs to be removed)
+# may be located either in call dir, or one of it subdirs.
+SNOWBRIDGE_FOLDER="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )/../"
+
+# Get the current Git branch name
+current_branch=$(git rev-parse --abbrev-ref HEAD)
+
+if [ "$current_branch" = "$branch_name" ] || git branch | grep -q "$branch_name"; then
+    echo "Already on requested branch or branch exists, not creating."
+else
+    git branch "$branch_name"
+fi
+
+git checkout "$branch_name"
+
+# remove everything we think is not required for our needs
+rm -rf rust-toolchain.toml
+rm -rf $SNOWBRIDGE_FOLDER/.cargo
+rm -rf $SNOWBRIDGE_FOLDER/.github
+rm -rf $SNOWBRIDGE_FOLDER/SECURITY.md
+rm -rf $SNOWBRIDGE_FOLDER/.gitignore
+rm -rf $SNOWBRIDGE_FOLDER/templates
+rm -rf $SNOWBRIDGE_FOLDER/pallets/ethereum-client/fuzz
+
+pushd $SNOWBRIDGE_FOLDER
+
+# let's test if everything we need compiles
+cargo check -p snowbridge-pallet-ethereum-client
+cargo check -p snowbridge-pallet-ethereum-client --features runtime-benchmarks
+cargo check -p snowbridge-pallet-ethereum-client --features try-runtime
+cargo check -p snowbridge-pallet-inbound-queue
+cargo check -p snowbridge-pallet-inbound-queue --features runtime-benchmarks
+cargo check -p snowbridge-pallet-inbound-queue --features try-runtime
+cargo check -p snowbridge-pallet-outbound-queue
+cargo check -p snowbridge-pallet-outbound-queue --features runtime-benchmarks
+cargo check -p snowbridge-pallet-outbound-queue --features try-runtime
+cargo check -p snowbridge-pallet-system
+cargo check -p snowbridge-pallet-system --features runtime-benchmarks
+cargo check -p snowbridge-pallet-system --features try-runtime
+
+# we're removing lock file after all checks are done. Otherwise we may use different
+# Substrate/Polkadot/Cumulus commits and our checks will fail
+rm -f $SNOWBRIDGE_FOLDER/Cargo.toml
+rm -f $SNOWBRIDGE_FOLDER/Cargo.lock
+
+popd
+
+# Replace Parity's CI files, that we have overwritten in our fork, to run our own CI
+rm -rf .github
+git remote -v | grep -w parity || git remote add parity https://github.com/paritytech/polkadot-sdk
+git fetch parity master
+git checkout parity/master -- .github
+git add -- .github
+
+echo "OK"
diff --git a/bridges/snowbridge/scripts/verify-pallets-build.sh b/bridges/snowbridge/scripts/verify-pallets-build.sh
deleted file mode 100755
index a62f48c84d4fd34731c20365a20097e086aa2c99..0000000000000000000000000000000000000000
--- a/bridges/snowbridge/scripts/verify-pallets-build.sh
+++ /dev/null
@@ -1,116 +0,0 @@
-#!/bin/bash
-
-# A script to remove everything from snowbridge repository/subtree, except:
-#
-# - parachain
-# - readme
-# - license
-
-set -eu
-
-# show CLI help
-function show_help() {
-  set +x
-  echo " "
-  echo Error: $1
-  echo "Usage:"
-  echo "  ./scripts/verify-pallets-build.sh          Exit with code 0 if pallets code is well decoupled from the other code in the repo"
-  echo "Options:"
-  echo "  --no-revert                                Leaves only runtime code on exit"
-  echo "  --ignore-git-state                         Ignores git actual state"
-  exit 1
-}
-
-# parse CLI args
-NO_REVERT=
-IGNORE_GIT_STATE=
-for i in "$@"
-do
-	case $i in
-		--no-revert)
-			NO_REVERT=true
-			shift
-			;;
-		--ignore-git-state)
-			IGNORE_GIT_STATE=true
-			shift
-			;;
-		*)
-			show_help "Unknown option: $i"
-			;;
-	esac
-done
-
-# the script is able to work only on clean git copy, unless we want to ignore this check
-[[ ! -z "${IGNORE_GIT_STATE}" ]] || [[ -z "$(git status --porcelain)" ]] || { echo >&2 "The git copy must be clean"; exit 1; }
-
-# let's avoid any restrictions on where this script can be called for - snowbridge repo may be
-# plugged into any other repo folder. So the script (and other stuff that needs to be removed)
-# may be located either in call dir, or one of it subdirs.
-SNOWBRIDGE_FOLDER="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )/../.."
-
-# remove everything we think is not required for our needs
-rm -rf $SNOWBRIDGE_FOLDER/.cargo
-rm -rf $SNOWBRIDGE_FOLDER/.github
-rm -rf $SNOWBRIDGE_FOLDER/contracts
-rm -rf $SNOWBRIDGE_FOLDER/codecov.yml
-rm -rf $SNOWBRIDGE_FOLDER/docs
-rm -rf $SNOWBRIDGE_FOLDER/hooks
-rm -rf $SNOWBRIDGE_FOLDER/relayer
-rm -rf $SNOWBRIDGE_FOLDER/scripts
-rm -rf $SNOWBRIDGE_FOLDER/SECURITY.md
-rm -rf $SNOWBRIDGE_FOLDER/smoketest
-rm -rf $SNOWBRIDGE_FOLDER/web
-rm -rf $SNOWBRIDGE_FOLDER/.envrc-example
-rm -rf $SNOWBRIDGE_FOLDER/.gitbook.yaml
-rm -rf $SNOWBRIDGE_FOLDER/.gitignore
-rm -rf $SNOWBRIDGE_FOLDER/.gitmodules
-rm -rf $SNOWBRIDGE_FOLDER/_typos.toml
-rm -rf $SNOWBRIDGE_FOLDER/_codecov.yml
-rm -rf $SNOWBRIDGE_FOLDER/flake.lock
-rm -rf $SNOWBRIDGE_FOLDER/flake.nix
-rm -rf $SNOWBRIDGE_FOLDER/go.work
-rm -rf $SNOWBRIDGE_FOLDER/go.work.sum
-rm -rf $SNOWBRIDGE_FOLDER/polkadot-sdk
-rm -rf $SNOWBRIDGE_FOLDER/rust-toolchain.toml
-rm -rf $SNOWBRIDGE_FOLDER/parachain/rustfmt.toml
-rm -rf $SNOWBRIDGE_FOLDER/parachain/.gitignore
-rm -rf $SNOWBRIDGE_FOLDER/parachain/templates
-rm -rf $SNOWBRIDGE_FOLDER/parachain/.cargo
-rm -rf $SNOWBRIDGE_FOLDER/parachain/.config
-rm -rf $SNOWBRIDGE_FOLDER/parachain/pallets/ethereum-client/fuzz
-
-cd bridges/snowbridge/parachain
-
-# fix polkadot-sdk paths in Cargo.toml files
-find "." -name 'Cargo.toml' | while read -r file; do
-    replace=$(printf '../../' )
-    if [[ "$(uname)" = "Darwin" ]] || [[ "$(uname)" = *BSD ]]; then
-        sed -i '' "s|polkadot-sdk/|$replace|g" "$file"
-    else
-        sed -i "s|polkadot-sdk/|$replace|g" "$file"
-    fi
-done
-
-# let's test if everything we need compiles
-cargo check -p snowbridge-pallet-ethereum-client
-cargo check -p snowbridge-pallet-ethereum-client --features runtime-benchmarks
-cargo check -p snowbridge-pallet-ethereum-client --features try-runtime
-cargo check -p snowbridge-pallet-inbound-queue
-cargo check -p snowbridge-pallet-inbound-queue --features runtime-benchmarks
-cargo check -p snowbridge-pallet-inbound-queue --features try-runtime
-cargo check -p snowbridge-pallet-outbound-queue
-cargo check -p snowbridge-pallet-outbound-queue --features runtime-benchmarks
-cargo check -p snowbridge-pallet-outbound-queue --features try-runtime
-cargo check -p snowbridge-pallet-system
-cargo check -p snowbridge-pallet-system --features runtime-benchmarks
-cargo check -p snowbridge-pallet-system --features try-runtime
-
-cd -
-
-# we're removing lock file after all checks are done. Otherwise we may use different
-# Substrate/Polkadot/Cumulus commits and our checks will fail
-rm -f $SNOWBRIDGE_FOLDER/parachain/Cargo.toml
-rm -f $SNOWBRIDGE_FOLDER/parachain/Cargo.lock
-
-echo "OK"
diff --git a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml
index 89c4925cb1ac232cfdb95e20fb3a117cc186bef8..883c93c97b4de6774e86ee83b84d246dc1427f7f 100644
--- a/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml
+++ b/cumulus/parachains/runtimes/assets/test-utils/Cargo.toml
@@ -17,6 +17,7 @@ frame-support = { path = "../../../../../substrate/frame/support", default-featu
 frame-system = { path = "../../../../../substrate/frame/system", default-features = false }
 pallet-assets = { path = "../../../../../substrate/frame/assets", default-features = false }
 pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false }
+pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false }
 pallet-session = { path = "../../../../../substrate/frame/session", default-features = false }
 sp-io = { path = "../../../../../substrate/primitives/io", default-features = false }
 sp-runtime = { path = "../../../../../substrate/primitives/runtime", default-features = false }
@@ -59,6 +60,7 @@ std = [
 	"pallet-balances/std",
 	"pallet-collator-selection/std",
 	"pallet-session/std",
+	"pallet-timestamp/std",
 	"pallet-xcm-bridge-hub-router/std",
 	"pallet-xcm/std",
 	"parachain-info/std",
diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs
index 4007d926983ed97a8cae705428c1d61184173cb7..53e10956bd0d1d233555a8e4df1ae23fe351c678 100644
--- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs
+++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs
@@ -70,7 +70,8 @@ pub fn teleports_for_native_asset_works<
 		+ parachain_info::Config
 		+ pallet_collator_selection::Config
 		+ cumulus_pallet_parachain_system::Config
-		+ cumulus_pallet_xcmp_queue::Config,
+		+ cumulus_pallet_xcmp_queue::Config
+		+ pallet_timestamp::Config,
 	AllPalletsWithoutSystem:
 		OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
 	AccountIdOf<Runtime>: Into<[u8; 32]>,
@@ -350,7 +351,8 @@ pub fn teleports_for_foreign_assets_works<
 		+ pallet_collator_selection::Config
 		+ cumulus_pallet_parachain_system::Config
 		+ cumulus_pallet_xcmp_queue::Config
-		+ pallet_assets::Config<ForeignAssetsPalletInstance>,
+		+ pallet_assets::Config<ForeignAssetsPalletInstance>
+		+ pallet_timestamp::Config,
 	AllPalletsWithoutSystem:
 		OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
 	AccountIdOf<Runtime>: Into<[u8; 32]>,
@@ -701,7 +703,8 @@ pub fn asset_transactor_transfer_with_local_consensus_currency_works<Runtime, Xc
 		+ pallet_xcm::Config
 		+ parachain_info::Config
 		+ pallet_collator_selection::Config
-		+ cumulus_pallet_parachain_system::Config,
+		+ cumulus_pallet_parachain_system::Config
+		+ pallet_timestamp::Config,
 	AccountIdOf<Runtime>: Into<[u8; 32]>,
 	ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
 	BalanceOf<Runtime>: From<Balance>,
@@ -826,7 +829,8 @@ pub fn asset_transactor_transfer_with_pallet_assets_instance_works<
 		+ parachain_info::Config
 		+ pallet_collator_selection::Config
 		+ cumulus_pallet_parachain_system::Config
-		+ pallet_assets::Config<AssetsPalletInstance>,
+		+ pallet_assets::Config<AssetsPalletInstance>
+		+ pallet_timestamp::Config,
 	AccountIdOf<Runtime>: Into<[u8; 32]>,
 	ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
 	BalanceOf<Runtime>: From<Balance>,
@@ -1093,7 +1097,8 @@ pub fn create_and_manage_foreign_assets_for_local_consensus_parachain_assets_wor
 		+ parachain_info::Config
 		+ pallet_collator_selection::Config
 		+ cumulus_pallet_parachain_system::Config
-		+ pallet_assets::Config<ForeignAssetsPalletInstance>,
+		+ pallet_assets::Config<ForeignAssetsPalletInstance>
+		+ pallet_timestamp::Config,
 	AccountIdOf<Runtime>: Into<[u8; 32]>,
 	ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
 	BalanceOf<Runtime>: From<Balance>,
@@ -1422,7 +1427,8 @@ pub fn reserve_transfer_native_asset_to_non_teleport_para_works<
 		+ parachain_info::Config
 		+ pallet_collator_selection::Config
 		+ cumulus_pallet_parachain_system::Config
-		+ cumulus_pallet_xcmp_queue::Config,
+		+ cumulus_pallet_xcmp_queue::Config
+		+ pallet_timestamp::Config,
 	AllPalletsWithoutSystem:
 		OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
 	AccountIdOf<Runtime>: Into<[u8; 32]>,
diff --git a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs
index 66ed3417951a35b922108f97bd480942487ccffc..1cce3b647cf0446a2246417b5383594fb501e600 100644
--- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs
+++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases_over_bridge.rs
@@ -70,7 +70,8 @@ pub fn limited_reserve_transfer_assets_for_native_asset_works<
 		+ parachain_info::Config
 		+ pallet_collator_selection::Config
 		+ cumulus_pallet_parachain_system::Config
-		+ cumulus_pallet_xcmp_queue::Config,
+		+ cumulus_pallet_xcmp_queue::Config
+		+ pallet_timestamp::Config,
 	AllPalletsWithoutSystem:
 		OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
 	AccountIdOf<Runtime>: Into<[u8; 32]>,
@@ -347,7 +348,8 @@ pub fn receive_reserve_asset_deposited_from_different_consensus_works<
 		+ pallet_collator_selection::Config
 		+ cumulus_pallet_parachain_system::Config
 		+ cumulus_pallet_xcmp_queue::Config
-		+ pallet_assets::Config<ForeignAssetsPalletInstance>,
+		+ pallet_assets::Config<ForeignAssetsPalletInstance>
+		+ pallet_timestamp::Config,
 	AllPalletsWithoutSystem:
 		OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
 	AccountIdOf<Runtime>: Into<[u8; 32]> + From<[u8; 32]>,
@@ -510,7 +512,8 @@ pub fn report_bridge_status_from_xcm_bridge_router_works<
 		+ pallet_collator_selection::Config
 		+ cumulus_pallet_parachain_system::Config
 		+ cumulus_pallet_xcmp_queue::Config
-		+ pallet_xcm_bridge_hub_router::Config<XcmBridgeHubRouterInstance>,
+		+ pallet_xcm_bridge_hub_router::Config<XcmBridgeHubRouterInstance>
+		+ pallet_timestamp::Config,
 	AllPalletsWithoutSystem:
 		OnInitialize<BlockNumberFor<Runtime>> + OnFinalize<BlockNumberFor<Runtime>>,
 	AccountIdOf<Runtime>: Into<[u8; 32]>,
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs
index d1eac089f670ac9d72b33991bfd87dd9c02c4f7a..ae50d2a93cb94a9b6570ca91c251f63e9b325334 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/lib.rs
@@ -730,7 +730,7 @@ construct_runtime!(
 
 		// Message Queue. Importantly, is registered last so that messages are processed after
 		// the `on_initialize` hooks of bridging pallets.
-		MessageQueue: pallet_message_queue = 250,
+		MessageQueue: pallet_message_queue = 175,
 	}
 );
 
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs
index b2e5cc9ef06fe827749416ce357ce28c8453f9b9..b9f43624b652f97ec1616664548baaadb5e4c05f 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs
@@ -20,9 +20,9 @@ use bp_polkadot_core::Signature;
 use bridge_hub_rococo_runtime::{
 	bridge_to_bulletin_config::OnBridgeHubRococoRefundRococoBulletinMessages,
 	bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages,
-	xcm_config::XcmConfig, BridgeRejectObsoleteHeadersAndMessages, Executive,
-	MessageQueueServiceWeight, Runtime, RuntimeCall, RuntimeEvent, SessionKeys, SignedExtra,
-	UncheckedExtrinsic,
+	xcm_config::XcmConfig, AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages,
+	Executive, MessageQueueServiceWeight, Runtime, RuntimeCall, RuntimeEvent, SessionKeys,
+	SignedExtra, UncheckedExtrinsic,
 };
 use codec::{Decode, Encode};
 use cumulus_primitives_core::XcmError::{FailedToTransactAsset, NotHoldingFees};
@@ -135,6 +135,32 @@ fn ethereum_to_polkadot_message_extrinsics_work() {
 	);
 }
 
+/// Tests that the digest items are as expected when a Ethereum Outbound message is received.
+/// If the MessageQueue pallet is configured before (i.e. the MessageQueue pallet is listed before
+/// the EthereumOutboundQueue in the construct_runtime macro) the EthereumOutboundQueue, this test
+/// will fail.
+#[test]
+pub fn ethereum_outbound_queue_processes_messages_before_message_queue_works() {
+	snowbridge_runtime_test_common::ethereum_outbound_queue_processes_messages_before_message_queue_works::<
+		Runtime,
+		XcmConfig,
+		AllPalletsWithoutSystem,
+	>(
+		collator_session_keys(),
+		1013,
+		1000,
+		H160::random(),
+		H160::random(),
+		DefaultBridgeHubEthereumBaseFee::get(),
+		Box::new(|runtime_event_encoded: Vec<u8>| {
+			match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
+				Ok(RuntimeEvent::EthereumOutboundQueue(event)) => Some(event),
+				_ => None,
+			}
+		}),
+	)
+}
+
 fn construct_extrinsic(
 	sender: sp_keyring::AccountKeyring,
 	call: RuntimeCall,
diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml
index d34b5cd0eed1ef3f9c8192f0eb0bd3fdfdfa2abf..5f2a6e050d83c3db662f8ff4896d32dc8a28fde3 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml
+++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml
@@ -25,6 +25,7 @@ sp-std = { path = "../../../../../substrate/primitives/std", default-features =
 sp-tracing = { path = "../../../../../substrate/primitives/tracing" }
 pallet-balances = { path = "../../../../../substrate/frame/balances", default-features = false }
 pallet-utility = { path = "../../../../../substrate/frame/utility", default-features = false }
+pallet-timestamp = { path = "../../../../../substrate/frame/timestamp", default-features = false }
 
 # Cumulus
 asset-test-utils = { path = "../../assets/test-utils" }
@@ -73,6 +74,7 @@ std = [
 	"pallet-bridge-messages/std",
 	"pallet-bridge-parachains/std",
 	"pallet-bridge-relayers/std",
+	"pallet-timestamp/std",
 	"pallet-utility/std",
 	"parachains-common/std",
 	"parachains-runtimes-test-utils/std",
diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs
index 4f634c184aa84faa6466102ef5fee30f254bad43..2b48f2e3d515f625532d9c5f50fabadb9a89517a 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/test_cases/helpers.rs
@@ -197,7 +197,9 @@ where
 pub(crate) fn initialize_bridge_grandpa_pallet<Runtime, GPI>(
 	init_data: bp_header_chain::InitializationData<BridgedHeader<Runtime, GPI>>,
 ) where
-	Runtime: BridgeGrandpaConfig<GPI>,
+	Runtime: BridgeGrandpaConfig<GPI>
+		+ cumulus_pallet_parachain_system::Config
+		+ pallet_timestamp::Config,
 {
 	pallet_bridge_grandpa::Pallet::<Runtime, GPI>::initialize(
 		RuntimeHelper::<Runtime>::root_origin(),
diff --git a/cumulus/parachains/runtimes/test-utils/Cargo.toml b/cumulus/parachains/runtimes/test-utils/Cargo.toml
index a61e05de13fa6dff6e54f583a00683d4a270e429..eda88beb7dabb41bd4075ec5ab6bf8ec2f42d3c8 100644
--- a/cumulus/parachains/runtimes/test-utils/Cargo.toml
+++ b/cumulus/parachains/runtimes/test-utils/Cargo.toml
@@ -17,6 +17,7 @@ frame-support = { path = "../../../../substrate/frame/support", default-features
 frame-system = { path = "../../../../substrate/frame/system", default-features = false }
 pallet-balances = { path = "../../../../substrate/frame/balances", default-features = false }
 pallet-session = { path = "../../../../substrate/frame/session", default-features = false }
+pallet-timestamp = { path = "../../../../substrate/frame/timestamp", default-features = false }
 sp-consensus-aura = { path = "../../../../substrate/primitives/consensus/aura", default-features = false }
 sp-io = { path = "../../../../substrate/primitives/io", default-features = false }
 sp-runtime = { path = "../../../../substrate/primitives/runtime", default-features = false }
@@ -59,6 +60,7 @@ std = [
 	"pallet-balances/std",
 	"pallet-collator-selection/std",
 	"pallet-session/std",
+	"pallet-timestamp/std",
 	"pallet-xcm/std",
 	"parachain-info/std",
 	"polkadot-parachain-primitives/std",
diff --git a/cumulus/parachains/runtimes/test-utils/src/lib.rs b/cumulus/parachains/runtimes/test-utils/src/lib.rs
index b4eb57fcb66f412cd697cfd4d6efd1f551ef7eb6..e62daa16a1256fa993a97d82d4f6df96f261018b 100644
--- a/cumulus/parachains/runtimes/test-utils/src/lib.rs
+++ b/cumulus/parachains/runtimes/test-utils/src/lib.rs
@@ -34,7 +34,7 @@ use polkadot_parachain_primitives::primitives::{
 };
 use sp_consensus_aura::{SlotDuration, AURA_ENGINE_ID};
 use sp_core::{Encode, U256};
-use sp_runtime::{traits::Header, BuildStorage, Digest, DigestItem};
+use sp_runtime::{traits::Header, BuildStorage, Digest, DigestItem, SaturatedConversion};
 use xcm::{
 	latest::{Asset, Location, XcmContext, XcmHash},
 	prelude::*,
@@ -129,6 +129,7 @@ pub trait BasicParachainRuntime:
 	+ parachain_info::Config
 	+ pallet_collator_selection::Config
 	+ cumulus_pallet_parachain_system::Config
+	+ pallet_timestamp::Config
 {
 }
 
@@ -140,7 +141,8 @@ where
 		+ pallet_xcm::Config
 		+ parachain_info::Config
 		+ pallet_collator_selection::Config
-		+ cumulus_pallet_parachain_system::Config,
+		+ cumulus_pallet_parachain_system::Config
+		+ pallet_timestamp::Config,
 	ValidatorIdOf<T>: From<AccountIdOf<T>>,
 {
 }
@@ -259,8 +261,10 @@ pub struct RuntimeHelper<Runtime, AllPalletsWithoutSystem>(
 );
 /// Utility function that advances the chain to the desired block number.
 /// If an author is provided, that author information is injected to all the blocks in the meantime.
-impl<Runtime: frame_system::Config, AllPalletsWithoutSystem>
-	RuntimeHelper<Runtime, AllPalletsWithoutSystem>
+impl<
+		Runtime: frame_system::Config + cumulus_pallet_parachain_system::Config + pallet_timestamp::Config,
+		AllPalletsWithoutSystem,
+	> RuntimeHelper<Runtime, AllPalletsWithoutSystem>
 where
 	AccountIdOf<Runtime>:
 		Into<<<Runtime as frame_system::Config>::RuntimeOrigin as OriginTrait>::AccountId>,
@@ -296,6 +300,65 @@ where
 		last_header.expect("run_to_block empty block range")
 	}
 
+	pub fn run_to_block_with_finalize(n: u32) -> HeaderFor<Runtime> {
+		let mut last_header = None;
+		loop {
+			let block_number = frame_system::Pallet::<Runtime>::block_number();
+			if block_number >= n.into() {
+				break
+			}
+			// Set the new block number and author
+			let header = frame_system::Pallet::<Runtime>::finalize();
+
+			let pre_digest = Digest {
+				logs: vec![DigestItem::PreRuntime(AURA_ENGINE_ID, block_number.encode())],
+			};
+			frame_system::Pallet::<Runtime>::reset_events();
+
+			let next_block_number = block_number + 1u32.into();
+			frame_system::Pallet::<Runtime>::initialize(
+				&next_block_number,
+				&header.hash(),
+				&pre_digest,
+			);
+			AllPalletsWithoutSystem::on_initialize(next_block_number);
+
+			let parent_head = HeadData(header.encode());
+			let sproof_builder = RelayStateSproofBuilder {
+				para_id: <Runtime>::SelfParaId::get(),
+				included_para_head: parent_head.clone().into(),
+				..Default::default()
+			};
+
+			let (relay_parent_storage_root, relay_chain_state) =
+				sproof_builder.into_state_root_and_proof();
+			let inherent_data = ParachainInherentData {
+				validation_data: PersistedValidationData {
+					parent_head,
+					relay_parent_number: (block_number.saturated_into::<u32>() * 2 + 1).into(),
+					relay_parent_storage_root,
+					max_pov_size: 100_000_000,
+				},
+				relay_chain_state,
+				downward_messages: Default::default(),
+				horizontal_messages: Default::default(),
+			};
+
+			let _ = cumulus_pallet_parachain_system::Pallet::<Runtime>::set_validation_data(
+				Runtime::RuntimeOrigin::none(),
+				inherent_data,
+			);
+			let _ = pallet_timestamp::Pallet::<Runtime>::set(
+				Runtime::RuntimeOrigin::none(),
+				300_u32.into(),
+			);
+			AllPalletsWithoutSystem::on_finalize(next_block_number);
+			let header = frame_system::Pallet::<Runtime>::finalize();
+			last_header = Some(header);
+		}
+		last_header.expect("run_to_block empty block range")
+	}
+
 	pub fn root_origin() -> <Runtime as frame_system::Config>::RuntimeOrigin {
 		<Runtime as frame_system::Config>::RuntimeOrigin::root()
 	}
diff --git a/cumulus/parachains/runtimes/test-utils/src/test_cases.rs b/cumulus/parachains/runtimes/test-utils/src/test_cases.rs
index f78bf9877ec2443a9ce3d754a533f3ee6a3cf14a..1c58df189b673af60bc3e4a9ae7391294287e2aa 100644
--- a/cumulus/parachains/runtimes/test-utils/src/test_cases.rs
+++ b/cumulus/parachains/runtimes/test-utils/src/test_cases.rs
@@ -37,7 +37,8 @@ pub fn change_storage_constant_by_governance_works<Runtime, StorageConstant, Sto
 		+ pallet_xcm::Config
 		+ parachain_info::Config
 		+ pallet_collator_selection::Config
-		+ cumulus_pallet_parachain_system::Config,
+		+ cumulus_pallet_parachain_system::Config
+		+ pallet_timestamp::Config,
 	ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
 	StorageConstant: Get<StorageConstantType>,
 	StorageConstantType: Encode + PartialEq + std::fmt::Debug,
@@ -107,7 +108,8 @@ pub fn set_storage_keys_by_governance_works<Runtime>(
 		+ pallet_xcm::Config
 		+ parachain_info::Config
 		+ pallet_collator_selection::Config
-		+ cumulus_pallet_parachain_system::Config,
+		+ cumulus_pallet_parachain_system::Config
+		+ pallet_timestamp::Config,
 	ValidatorIdOf<Runtime>: From<AccountIdOf<Runtime>>,
 {
 	let mut runtime = ExtBuilder::<Runtime>::default()