diff --git a/Cargo.lock b/Cargo.lock
index 2e60b28f40e17..8234553b5769a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2069,6 +2069,7 @@ dependencies = [
"snowbridge-rococo-common",
"snowbridge-router-primitives",
"snowbridge-runtime-common",
+ "snowbridge-runtime-tests",
"snowbridge-system",
"snowbridge-system-runtime-api",
"sp-api",
@@ -17462,6 +17463,79 @@ dependencies = [
"staging-xcm-executor",
]
+[[package]]
+name = "snowbridge-runtime-tests"
+version = "0.1.0"
+dependencies = [
+ "assets-common",
+ "cumulus-pallet-aura-ext",
+ "cumulus-pallet-dmp-queue",
+ "cumulus-pallet-parachain-system",
+ "cumulus-pallet-session-benchmarking",
+ "cumulus-pallet-xcm",
+ "cumulus-pallet-xcmp-queue",
+ "cumulus-primitives-core",
+ "cumulus-primitives-utility",
+ "frame-benchmarking",
+ "frame-executive",
+ "frame-support",
+ "frame-system",
+ "frame-system-benchmarking",
+ "frame-system-rpc-runtime-api",
+ "frame-try-runtime",
+ "hex-literal",
+ "log",
+ "pallet-aura",
+ "pallet-authorship",
+ "pallet-balances",
+ "pallet-collator-selection",
+ "pallet-message-queue",
+ "pallet-multisig",
+ "pallet-session",
+ "pallet-timestamp",
+ "pallet-transaction-payment",
+ "pallet-transaction-payment-rpc-runtime-api",
+ "pallet-utility",
+ "pallet-xcm",
+ "pallet-xcm-benchmarks",
+ "parachains-common",
+ "parachains-runtimes-test-utils",
+ "parity-scale-codec",
+ "polkadot-core-primitives",
+ "polkadot-parachain-primitives",
+ "polkadot-runtime-common",
+ "scale-info",
+ "serde",
+ "smallvec",
+ "snowbridge-beacon-primitives",
+ "snowbridge-core",
+ "snowbridge-ethereum-beacon-client",
+ "snowbridge-inbound-queue",
+ "snowbridge-outbound-queue",
+ "snowbridge-outbound-queue-runtime-api",
+ "snowbridge-router-primitives",
+ "snowbridge-system",
+ "snowbridge-system-runtime-api",
+ "sp-api",
+ "sp-block-builder",
+ "sp-consensus-aura",
+ "sp-core",
+ "sp-genesis-builder",
+ "sp-inherents",
+ "sp-io",
+ "sp-offchain",
+ "sp-runtime",
+ "sp-session",
+ "sp-std 8.0.0",
+ "sp-storage 13.0.0",
+ "sp-transaction-pool",
+ "sp-version",
+ "staging-parachain-info",
+ "staging-xcm",
+ "staging-xcm-builder",
+ "staging-xcm-executor",
+]
+
[[package]]
name = "snowbridge-system"
version = "0.1.1"
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml
index f664017b0e5e9..7222f4c82452d 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml
@@ -128,6 +128,7 @@ bridge-runtime-common = { path = "../../../../../bridges/bin/runtime-common", fe
"integrity-test",
] }
sp-keyring = { path = "../../../../../substrate/primitives/keyring" }
+snowbridge-runtime-tests = { path = "../../../../../../parachain/runtime/tests" }
[features]
default = ["std"]
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
new file mode 100644
index 0000000000000..3c7d1caf5a65f
--- /dev/null
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/snowbridge.rs
@@ -0,0 +1,109 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// This file is part of Cumulus.
+
+// Cumulus is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Cumulus is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Cumulus. If not, see .
+
+#![cfg(test)]
+
+use bridge_hub_rococo_runtime::{
+ xcm_config::XcmConfig, MessageQueueServiceWeight, Runtime, RuntimeEvent, SessionKeys,
+};
+use codec::Decode;
+use cumulus_primitives_core::XcmError::{FailedToTransactAsset, NotHoldingFees};
+use frame_support::parameter_types;
+use parachains_common::{AccountId, AuraId, Balance};
+use snowbridge_ethereum_beacon_client::WeightInfo;
+use sp_core::H160;
+use sp_keyring::AccountKeyring::Alice;
+
+parameter_types! {
+ pub const DefaultBridgeHubEthereumBaseFee: Balance = 2_750_872_500_000;
+}
+
+fn collator_session_keys() -> bridge_hub_test_utils::CollatorSessionKeys {
+ bridge_hub_test_utils::CollatorSessionKeys::new(
+ AccountId::from(Alice),
+ AccountId::from(Alice),
+ SessionKeys { aura: AuraId::from(Alice.public()) },
+ )
+}
+
+#[test]
+pub fn transfer_token_to_ethereum_works() {
+ snowbridge_runtime_tests::send_transfer_token_message_success::(
+ collator_session_keys(),
+ 1013,
+ 1000,
+ H160::random(),
+ H160::random(),
+ DefaultBridgeHubEthereumBaseFee::get(),
+ Box::new(|runtime_event_encoded: Vec| {
+ match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) {
+ Ok(RuntimeEvent::EthereumOutboundQueue(event)) => Some(event),
+ _ => None,
+ }
+ }),
+ )
+}
+
+#[test]
+pub fn unpaid_transfer_token_to_ethereum_fails_with_barrier() {
+ snowbridge_runtime_tests::send_unpaid_transfer_token_message::(
+ collator_session_keys(),
+ 1013,
+ 1000,
+ H160::random(),
+ H160::random(),
+ )
+}
+
+#[test]
+pub fn transfer_token_to_ethereum_fee_not_enough() {
+ snowbridge_runtime_tests::send_transfer_token_message_failure::(
+ collator_session_keys(),
+ 1013,
+ 1000,
+ DefaultBridgeHubEthereumBaseFee::get() + 1_000_000_000,
+ H160::random(),
+ H160::random(),
+ // fee not enough
+ 1_000_000_000,
+ NotHoldingFees,
+ )
+}
+
+#[test]
+pub fn transfer_token_to_ethereum_insufficient_fund() {
+ snowbridge_runtime_tests::send_transfer_token_message_failure::(
+ collator_session_keys(),
+ 1013,
+ 1000,
+ 1_000_000_000,
+ H160::random(),
+ H160::random(),
+ DefaultBridgeHubEthereumBaseFee::get(),
+ FailedToTransactAsset("InsufficientBalance"),
+ )
+}
+
+#[test]
+fn max_message_queue_service_weight_is_more_than_beacon_extrinsic_weights() {
+ let max_message_queue_weight = MessageQueueServiceWeight::get();
+ let force_checkpoint =
+ ::WeightInfo::force_checkpoint();
+ let submit_checkpoint =
+ ::WeightInfo::submit();
+ max_message_queue_weight.all_gt(force_checkpoint);
+ max_message_queue_weight.all_gt(submit_checkpoint);
+}