diff --git a/bridges/snowbridge/pallets/inbound-queue/fixtures/src/lib.rs b/bridges/snowbridge/pallets/inbound-queue/fixtures/src/lib.rs
index 00adcdfa186adc755273b9753d833a6bdbec5b56..cb4232376c6fc98c21485aee7e3f5980cf8f941d 100644
--- a/bridges/snowbridge/pallets/inbound-queue/fixtures/src/lib.rs
+++ b/bridges/snowbridge/pallets/inbound-queue/fixtures/src/lib.rs
@@ -3,5 +3,6 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 
 pub mod register_token;
+pub mod send_native_eth;
 pub mod send_token;
 pub mod send_token_to_penpal;
diff --git a/bridges/snowbridge/pallets/inbound-queue/fixtures/src/send_native_eth.rs b/bridges/snowbridge/pallets/inbound-queue/fixtures/src/send_native_eth.rs
new file mode 100755
index 0000000000000000000000000000000000000000..d3e8d76e6b395081869b85e4b5d1541665a1259c
--- /dev/null
+++ b/bridges/snowbridge/pallets/inbound-queue/fixtures/src/send_native_eth.rs
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
+// Generated, do not edit!
+// See ethereum client README.md for instructions to generate
+
+use hex_literal::hex;
+use snowbridge_beacon_primitives::{
+	types::deneb, AncestryProof, BeaconHeader, ExecutionProof, VersionedExecutionPayloadHeader,
+};
+use snowbridge_core::inbound::{InboundQueueFixture, Log, Message, Proof};
+use sp_core::U256;
+use sp_std::vec;
+
+pub fn make_send_native_eth_message() -> InboundQueueFixture {
+	InboundQueueFixture {
+        message: Message {
+            event_log: 	Log {
+                address: hex!("87d1f7fdfee7f651fabc8bfcb6e086c278b77a7d").into(),
+                topics: vec![
+                    hex!("7153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84f").into(),
+                    hex!("c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539").into(),
+                    hex!("5f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0").into(),
+                ],
+                data: hex!("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005f00a736aa0000000000010000000000000000000000000000000000000000008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48000064a7b3b6e00d000000000000000000e8764817000000000000000000000000").into(),
+            },
+            proof: Proof {
+                receipt_proof: (vec![
+                    hex!("17cd4d05dde30703008a4f213205923630cff8e6bc9d5d95a52716bfb5551fd7").to_vec(),
+                ], vec![
+                    hex!("f903b4822080b903ae02f903aa018301a7fcb9010000000000000000000000000020000000000000000000004000000000000000000400000000000000000000001000000000000000000000000000000000000000000000000000000001080000000000000000000000000000000000000000080000000000020000000000000000000800010100000000000000000000000000000000000200000000000000000000000000001000000040080008000000000000000000040000000021000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000200000000000000f9029ff9015d9487d1f7fdfee7f651fabc8bfcb6e086c278b77a7df884a024c5d2de620c6e25186ae16f6919eba93b6e2c1a33857cc419d9f3a00d6967e9a00000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000090a987b944cb1dcce5564e5fdecd7a54d3de27fea000000000000000000000000000000000000000000000000000000000000003e8b8c000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000208eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48f9013c9487d1f7fdfee7f651fabc8bfcb6e086c278b77a7df863a07153f9357c8ea496bba60bf82e67143e27b64462b49041f8e689e1b05728f84fa0c173fac324158e77fb5840738a1a541f633cbec8884c6a601c567d2b376a0539a05f7060e971b0dc81e63f0aa41831091847d97c1a4693ac450cc128c7214e65e0b8c000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005f00a736aa0000000000010000000000000000000000000000000000000000008eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48000064a7b3b6e00d000000000000000000e8764817000000000000000000000000").to_vec(),
+                ]),
+                execution_proof: ExecutionProof {
+                    header: BeaconHeader {
+                        slot: 246,
+                        proposer_index: 7,
+                        parent_root: hex!("4faaac5d2fa0b8884fe1175c7cac1c92aac9eba5a20b4302edb98a56428c5974").into(),
+                        state_root: hex!("882c13f1d56df781e3444a78cae565bfa1c89822c86cdb0daea71f5351231580").into(),
+                        body_root: hex!("c47eb72204b1ca567396dacef8b0214027eb7f0789330b55166085d1f9cb4c65").into(),
+                    },
+                        ancestry_proof: Some(AncestryProof {
+                        header_branch: vec![
+                            hex!("38e2454bc93c4cfafcea772b8531e4802bbd2561366620699096dd4e591bc488").into(),
+                            hex!("3d7389fb144ccaeca8b8e1667ce1d1538dfceb50bf1e49c4b368a223f051fda3").into(),
+                            hex!("0d49c9c24137ad4d86ebca2f36a159573a68b5d5d60e317776c77cc8b6093034").into(),
+                            hex!("0fadc6735bcdc2793a5039a806fbf39984c39374ed4d272c1147e1c23df88983").into(),
+                            hex!("3a058ad4b169eebb4c754c8488d41e56a7a0e5f8b55b5ec67452a8d326585c69").into(),
+                            hex!("de200426caa9bc03f8e0033b4ef4df1db6501924b5c10fb7867e76db942b903c").into(),
+                            hex!("48b578632bc40eebb517501f179ffdd06d762c03e9383df16fc651eeddd18806").into(),
+                            hex!("98d9d6904b2a6a285db4c4ae59a07100cd38ec4d9fb7a16a10fe83ec99e6ba1d").into(),
+                            hex!("1b2bbae6e684864b714654a60778664e63ba6c3c9bed8074ec1a0380fe5042e6").into(),
+                            hex!("eb907a888eadf5a7e2bd0a3a5a9369e409c7aa688bd4cde758d5b608c6c82785").into(),
+                            hex!("ffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b").into(),
+                            hex!("6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220").into(),
+                            hex!("b7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f").into(),
+                        ],
+                        finalized_block_root: hex!("440615588532ce496a93d189cb0ef1df7cf67d529faee0fd03213ce26ea115e5").into(),
+                        }),
+                    execution_header: VersionedExecutionPayloadHeader::Deneb(deneb::ExecutionPayloadHeader {
+                        parent_hash: hex!("a8c89213b7d7d2ac76462d89e6a7384374db905b657ad803d3c86f88f86c39df").into(),
+                        fee_recipient: hex!("0000000000000000000000000000000000000000").into(),
+                        state_root: hex!("a1e8175213a6a43da17fae65109245867cbc60e3ada16b8ac28c6b208761c772").into(),
+                        receipts_root: hex!("17cd4d05dde30703008a4f213205923630cff8e6bc9d5d95a52716bfb5551fd7").into(),
+                        logs_bloom: hex!("00000000000000000000000020000000000000000000004000000000000000000400000000000000000000001000000000000000000000000000000000000000000000000000000001080000000000000000000000000000000000000000080000000000020000000000000000000800010100000000000000000000000000000000000200000000000000000000000000001000000040080008000000000000000000040000000021000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000200000000000000").into(),
+                        prev_randao: hex!("b9b26dc14ea8c57d069fde0c94ad31c2558365c3986a0c06558470f8c02e62ce").into(),
+                        block_number: 246,
+                        gas_limit: 62908420,
+                        gas_used: 108540,
+                        timestamp: 1734718384,
+                        extra_data: hex!("d983010e08846765746888676f312e32322e358664617277696e").into(),
+                        base_fee_per_gas: U256::from(7u64),
+                        block_hash: hex!("878195e2ea83c74d475363d03d41a7fbfc4026d6e5bcffb713928253984a64a7").into(),
+                        transactions_root: hex!("909139b3137666b4551b629ce6d9fb7e5e6f6def8a48d078448ec6600fe63c7f").into(),
+                        withdrawals_root: hex!("792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535").into(),
+                        blob_gas_used: 0,
+                        excess_blob_gas: 0,
+                    }),
+                    execution_branch: vec![
+                            hex!("5d78e26ea639df17c2194ff925f782b9522009d58cfc60e3d34ba79a19f8faf1").into(),
+                            hex!("b46f0c01805fe212e15907981b757e6c496b0cb06664224655613dcec82505bb").into(),
+                            hex!("db56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71").into(),
+                            hex!("3d84b2809a36450186e5169995a5e3cab55d751aee90fd8456b33d871ccaa463").into(),
+                    ],
+                }
+            },
+        },
+        finalized_header: BeaconHeader {
+            slot: 608,
+            proposer_index: 3,
+            parent_root: hex!("f10c2349530dbd339a72886270e2e304bb68155af68c918c850acd9ab341350f").into(),
+            state_root: hex!("6df0ef4cbb4986a84ff0763727402b88636e6b5535022cd3ad6967b8dd799402").into(),
+            body_root: hex!("f66fc1c022f07f91c777ad5c464625fc0b43d3e7a45650567dce60011210f574").into(),
+        },
+        block_roots_root: hex!("1c0dbf54db070770f5e573b72afe0aac2b0e3cf312107d1cd73bf64d7a2ed90c").into(),
+    }
+}
diff --git a/bridges/snowbridge/primitives/router/src/inbound/mock.rs b/bridges/snowbridge/primitives/router/src/inbound/mock.rs
new file mode 100644
index 0000000000000000000000000000000000000000..91f25cf525520d2614a75478a1f8842c0b5828fd
--- /dev/null
+++ b/bridges/snowbridge/primitives/router/src/inbound/mock.rs
@@ -0,0 +1,48 @@
+use crate::inbound::{MessageToXcm, TokenId};
+use frame_support::parameter_types;
+use sp_runtime::{
+	traits::{IdentifyAccount, MaybeEquivalence, Verify},
+	MultiSignature,
+};
+use xcm::prelude::*;
+
+pub const CHAIN_ID: u64 = 11155111;
+pub const NETWORK: NetworkId = Ethereum { chain_id: CHAIN_ID };
+
+parameter_types! {
+	pub EthereumNetwork: NetworkId = NETWORK;
+
+	pub const CreateAssetCall: [u8;2] = [53, 0];
+	pub const CreateAssetExecutionFee: u128 = 2_000_000_000;
+	pub const CreateAssetDeposit: u128 = 100_000_000_000;
+	pub const SendTokenExecutionFee: u128 = 1_000_000_000;
+	pub const InboundQueuePalletInstance: u8 = 80;
+	pub UniversalLocation: InteriorLocation =
+		[GlobalConsensus(Westend), Parachain(1002)].into();
+	pub AssetHubFromEthereum: Location = Location::new(1,[GlobalConsensus(Westend),Parachain(1000)]);
+}
+
+type Signature = MultiSignature;
+type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
+type Balance = u128;
+
+pub(crate) struct MockTokenIdConvert;
+impl MaybeEquivalence<TokenId, Location> for MockTokenIdConvert {
+	fn convert(_id: &TokenId) -> Option<Location> {
+		Some(Location::parent())
+	}
+	fn convert_back(_loc: &Location) -> Option<TokenId> {
+		None
+	}
+}
+
+pub(crate) type MessageConverter = MessageToXcm<
+	CreateAssetCall,
+	CreateAssetDeposit,
+	InboundQueuePalletInstance,
+	AccountId,
+	Balance,
+	MockTokenIdConvert,
+	UniversalLocation,
+	AssetHubFromEthereum,
+>;
diff --git a/bridges/snowbridge/primitives/router/src/inbound/mod.rs b/bridges/snowbridge/primitives/router/src/inbound/mod.rs
index a10884b455316834774edbca6a69edf6e3f3ec30..7783fb4b4661b4aca01dded39956bb1639bea31d 100644
--- a/bridges/snowbridge/primitives/router/src/inbound/mod.rs
+++ b/bridges/snowbridge/primitives/router/src/inbound/mod.rs
@@ -2,6 +2,8 @@
 // SPDX-FileCopyrightText: 2023 Snowfork <hello@snowfork.com>
 //! Converts messages from Ethereum to XCM messages
 
+#[cfg(test)]
+mod mock;
 #[cfg(test)]
 mod tests;
 
@@ -390,10 +392,16 @@ impl<
 
 	// Convert ERC20 token address to a location that can be understood by Assets Hub.
 	fn convert_token_address(network: NetworkId, token: H160) -> Location {
-		Location::new(
-			2,
-			[GlobalConsensus(network), AccountKey20 { network: None, key: token.into() }],
-		)
+		// If the token is `0x0000000000000000000000000000000000000000` then return the location of
+		// native Ether.
+		if token == H160([0; 20]) {
+			Location::new(2, [GlobalConsensus(network)])
+		} else {
+			Location::new(
+				2,
+				[GlobalConsensus(network), AccountKey20 { network: None, key: token.into() }],
+			)
+		}
 	}
 
 	/// Constructs an XCM message destined for AssetHub that withdraws assets from the sovereign
diff --git a/bridges/snowbridge/primitives/router/src/inbound/tests.rs b/bridges/snowbridge/primitives/router/src/inbound/tests.rs
index e0e90e516be166b0dadd06b158c035e1f12e9d30..5f8c59080d6250df594311d64e7881633a256855 100644
--- a/bridges/snowbridge/primitives/router/src/inbound/tests.rs
+++ b/bridges/snowbridge/primitives/router/src/inbound/tests.rs
@@ -1,21 +1,12 @@
 use super::GlobalConsensusEthereumConvertsFor;
-use crate::inbound::CallIndex;
-use frame_support::{assert_ok, parameter_types};
+use crate::inbound::{
+	mock::*, Command, ConvertMessage, Destination, MessageV1, VersionedMessage, H160,
+};
+use frame_support::assert_ok;
 use hex_literal::hex;
 use xcm::prelude::*;
 use xcm_executor::traits::ConvertLocation;
 
-const NETWORK: NetworkId = Ethereum { chain_id: 11155111 };
-
-parameter_types! {
-	pub EthereumNetwork: NetworkId = NETWORK;
-
-	pub const CreateAssetCall: CallIndex = [1, 1];
-	pub const CreateAssetExecutionFee: u128 = 123;
-	pub const CreateAssetDeposit: u128 = 891;
-	pub const SendTokenExecutionFee: u128 = 592;
-}
-
 #[test]
 fn test_contract_location_with_network_converts_successfully() {
 	let expected_account: [u8; 32] =
@@ -67,3 +58,74 @@ fn test_reanchor_all_assets() {
 		assert_eq!(reanchored_asset_with_ethereum_context, asset.clone());
 	}
 }
+
+#[test]
+fn test_convert_send_token_with_weth() {
+	const WETH: H160 = H160([0xff; 20]);
+	const AMOUNT: u128 = 1_000_000;
+	const FEE: u128 = 1_000;
+	const ACCOUNT_ID: [u8; 32] = [0xBA; 32];
+	const MESSAGE: VersionedMessage = VersionedMessage::V1(MessageV1 {
+		chain_id: CHAIN_ID,
+		command: Command::SendToken {
+			token: WETH,
+			destination: Destination::AccountId32 { id: ACCOUNT_ID },
+			amount: AMOUNT,
+			fee: FEE,
+		},
+	});
+	let result = MessageConverter::convert([1; 32].into(), MESSAGE);
+	assert_ok!(&result);
+	let (xcm, fee) = result.unwrap();
+	assert_eq!(FEE, fee);
+
+	let expected_assets = ReserveAssetDeposited(
+		vec![Asset {
+			id: AssetId(Location {
+				parents: 2,
+				interior: Junctions::X2(
+					[GlobalConsensus(NETWORK), AccountKey20 { network: None, key: WETH.into() }]
+						.into(),
+				),
+			}),
+			fun: Fungible(AMOUNT),
+		}]
+		.into(),
+	);
+	let actual_assets = xcm.into_iter().find(|x| matches!(x, ReserveAssetDeposited(..)));
+	assert_eq!(actual_assets, Some(expected_assets))
+}
+
+#[test]
+fn test_convert_send_token_with_eth() {
+	const ETH: H160 = H160([0x00; 20]);
+	const AMOUNT: u128 = 1_000_000;
+	const FEE: u128 = 1_000;
+	const ACCOUNT_ID: [u8; 32] = [0xBA; 32];
+	const MESSAGE: VersionedMessage = VersionedMessage::V1(MessageV1 {
+		chain_id: CHAIN_ID,
+		command: Command::SendToken {
+			token: ETH,
+			destination: Destination::AccountId32 { id: ACCOUNT_ID },
+			amount: AMOUNT,
+			fee: FEE,
+		},
+	});
+	let result = MessageConverter::convert([1; 32].into(), MESSAGE);
+	assert_ok!(&result);
+	let (xcm, fee) = result.unwrap();
+	assert_eq!(FEE, fee);
+
+	let expected_assets = ReserveAssetDeposited(
+		vec![Asset {
+			id: AssetId(Location {
+				parents: 2,
+				interior: Junctions::X1([GlobalConsensus(NETWORK)].into()),
+			}),
+			fun: Fungible(AMOUNT),
+		}]
+		.into(),
+	);
+	let actual_assets = xcm.into_iter().find(|x| matches!(x, ReserveAssetDeposited(..)));
+	assert_eq!(actual_assets, Some(expected_assets))
+}
diff --git a/bridges/snowbridge/primitives/router/src/outbound/mod.rs b/bridges/snowbridge/primitives/router/src/outbound/mod.rs
index d3b6c116dd7a3420c730f77614de61f355b64319..7ddcc65dd9309150f87e2af4e618d55475784dfd 100644
--- a/bridges/snowbridge/primitives/router/src/outbound/mod.rs
+++ b/bridges/snowbridge/primitives/router/src/outbound/mod.rs
@@ -279,8 +279,13 @@ where
 		let (token, amount) = match reserve_asset {
 			Asset { id: AssetId(inner_location), fun: Fungible(amount) } =>
 				match inner_location.unpack() {
+					// Get the ERC20 contract address of the token.
 					(0, [AccountKey20 { network, key }]) if self.network_matches(network) =>
 						Some((H160(*key), *amount)),
+					// If there is no ERC20 contract address in the location then signal to the
+					// gateway that is a native Ether transfer by using
+					// `0x0000000000000000000000000000000000000000` as the token address.
+					(0, []) => Some((H160([0; 20]), *amount)),
 					_ => None,
 				},
 			_ => None,
diff --git a/bridges/snowbridge/primitives/router/src/outbound/tests.rs b/bridges/snowbridge/primitives/router/src/outbound/tests.rs
index 6e4fd594634039163806c5dda22598461f17d9c0..62f99d276cfdf0740702acf9e1463620fc2d60de 100644
--- a/bridges/snowbridge/primitives/router/src/outbound/tests.rs
+++ b/bridges/snowbridge/primitives/router/src/outbound/tests.rs
@@ -512,6 +512,46 @@ fn xcm_converter_convert_with_wildcard_all_asset_filter_succeeds() {
 	assert_eq!(result, Ok((expected_payload, [0; 32])));
 }
 
+#[test]
+fn xcm_converter_convert_with_native_eth_succeeds() {
+	let network = BridgedNetwork::get();
+
+	let beneficiary_address: [u8; 20] = hex!("2000000000000000000000000000000000000000");
+
+	// The asset is `{ parents: 0, interior: X1(Here) }` relative to ethereum.
+	let assets: Assets = vec![Asset { id: AssetId([].into()), fun: Fungible(1000) }].into();
+	let filter: AssetFilter = Wild(All);
+
+	let message: Xcm<()> = vec![
+		WithdrawAsset(assets.clone()),
+		ClearOrigin,
+		BuyExecution { fees: assets.get(0).unwrap().clone(), weight_limit: Unlimited },
+		DepositAsset {
+			assets: filter,
+			beneficiary: AccountKey20 { network: None, key: beneficiary_address }.into(),
+		},
+		SetTopic([0; 32]),
+	]
+	.into();
+
+	let mut converter =
+		XcmConverter::<MockTokenIdConvert, ()>::new(&message, network, Default::default());
+
+	// The token address that is expected to be sent should be
+	// `0x0000000000000000000000000000000000000000`. The solidity will
+	// interpret this as a transfer of ETH.
+	let expected_payload = Command::AgentExecute {
+		agent_id: Default::default(),
+		command: AgentExecuteCommand::TransferToken {
+			token: H160([0; 20]),
+			recipient: beneficiary_address.into(),
+			amount: 1000,
+		},
+	};
+	let result = converter.convert();
+	assert_eq!(result, Ok((expected_payload, [0; 32])));
+}
+
 #[test]
 fn xcm_converter_convert_with_fees_less_than_reserve_yields_success() {
 	let network = BridgedNetwork::get();
diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs
index 5ef0993f70a1ce33daa68ec23b474716e6bee956..43398eb8bd48095f08eb5fd075f1c9b941b784c1 100644
--- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs
+++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/src/lib.rs
@@ -16,7 +16,8 @@
 pub mod genesis;
 
 pub use bridge_hub_rococo_runtime::{
-	xcm_config::XcmConfig as BridgeHubRococoXcmConfig, EthereumBeaconClient, EthereumInboundQueue,
+	self as bridge_hub_rococo_runtime, xcm_config::XcmConfig as BridgeHubRococoXcmConfig,
+	EthereumBeaconClient, EthereumInboundQueue,
 	ExistentialDeposit as BridgeHubRococoExistentialDeposit,
 	RuntimeOrigin as BridgeHubRococoRuntimeOrigin,
 };
diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs
index a542de16de5fbe68c96f4fecb43db52d6e789f3e..89e5b46d4ddea7c11bd3e7e63ccb99e352eb42ed 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs
@@ -51,6 +51,7 @@ mod imports {
 			genesis::ED as ASSET_HUB_WESTEND_ED, AssetHubWestendParaPallet as AssetHubWestendPallet,
 		},
 		bridge_hub_rococo_emulated_chain::{
+			bridge_hub_rococo_runtime::bridge_to_ethereum_config::EthereumGatewayAddress,
 			genesis::ED as BRIDGE_HUB_ROCOCO_ED, BridgeHubRococoExistentialDeposit,
 			BridgeHubRococoParaPallet as BridgeHubRococoPallet, BridgeHubRococoRuntimeOrigin,
 			BridgeHubRococoXcmConfig, EthereumBeaconClient, EthereumInboundQueue,
diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs
index d91a0c6895f98c377230f48d984d393e9773aeb9..ab4c4aced528257c896140843ff31601e404a39c 100644
--- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs
+++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/snowbridge.rs
@@ -20,8 +20,8 @@ use hex_literal::hex;
 use rococo_westend_system_emulated_network::BridgeHubRococoParaSender as BridgeHubRococoSender;
 use snowbridge_core::{inbound::InboundQueueFixture, outbound::OperatingMode};
 use snowbridge_pallet_inbound_queue_fixtures::{
-	register_token::make_register_token_message, send_token::make_send_token_message,
-	send_token_to_penpal::make_send_token_to_penpal_message,
+	register_token::make_register_token_message, send_native_eth::make_send_native_eth_message,
+	send_token::make_send_token_message, send_token_to_penpal::make_send_token_to_penpal_message,
 };
 use snowbridge_pallet_system;
 use snowbridge_router_primitives::inbound::{
@@ -238,7 +238,7 @@ fn register_weth_token_from_ethereum_to_asset_hub() {
 /// Tests the registering of a token as an asset on AssetHub, and then subsequently sending
 /// a token from Ethereum to AssetHub.
 #[test]
-fn send_token_from_ethereum_to_asset_hub() {
+fn send_weth_token_from_ethereum_to_asset_hub() {
 	BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id().into(), INITIAL_FUND);
 
 	// Fund ethereum sovereign on AssetHub
@@ -278,7 +278,7 @@ fn send_token_from_ethereum_to_asset_hub() {
 /// Tests sending a token to a 3rd party parachain, called PenPal. The token reserve is
 /// still located on AssetHub.
 #[test]
-fn send_token_from_ethereum_to_penpal() {
+fn send_weth_from_ethereum_to_penpal() {
 	let asset_hub_sovereign = BridgeHubRococo::sovereign_account_id_of(Location::new(
 		1,
 		[Parachain(AssetHubRococo::para_id().into())],
@@ -513,6 +513,177 @@ fn send_weth_asset_from_asset_hub_to_ethereum() {
 	});
 }
 
+/// Tests the full cycle of eth transfers:
+/// - sending a token to AssetHub
+/// - returning the token to Ethereum
+#[test]
+fn send_eth_asset_from_asset_hub_to_ethereum_and_back() {
+	let ethereum_network: NetworkId = EthereumNetwork::get().into();
+	let origin_location = (Parent, Parent, ethereum_network).into();
+
+	use ahr_xcm_config::bridging::to_ethereum::DefaultBridgeHubEthereumBaseFee;
+	let assethub_location = BridgeHubRococo::sibling_location_of(AssetHubRococo::para_id());
+	let assethub_sovereign = BridgeHubRococo::sovereign_account_id_of(assethub_location);
+	let ethereum_sovereign: AccountId =
+		GlobalConsensusEthereumConvertsFor::<AccountId>::convert_location(&origin_location)
+			.unwrap();
+
+	AssetHubRococo::force_default_xcm_version(Some(XCM_VERSION));
+	BridgeHubRococo::force_default_xcm_version(Some(XCM_VERSION));
+	AssetHubRococo::force_xcm_version(origin_location.clone(), XCM_VERSION);
+
+	BridgeHubRococo::fund_accounts(vec![(assethub_sovereign.clone(), INITIAL_FUND)]);
+	AssetHubRococo::fund_accounts(vec![
+		(AssetHubRococoReceiver::get(), INITIAL_FUND),
+		(ethereum_sovereign.clone(), INITIAL_FUND),
+	]);
+
+	// Register ETH
+	AssetHubRococo::execute_with(|| {
+		type RuntimeEvent = <AssetHubRococo as Chain>::RuntimeEvent;
+		type RuntimeOrigin = <AssetHubRococo as Chain>::RuntimeOrigin;
+		assert_ok!(<AssetHubRococo as AssetHubRococoPallet>::ForeignAssets::force_create(
+			RuntimeOrigin::root(),
+			origin_location.clone(),
+			ethereum_sovereign.into(),
+			true,
+			1000,
+		));
+
+		assert_expected_events!(
+			AssetHubRococo,
+			vec![
+				RuntimeEvent::ForeignAssets(pallet_assets::Event::ForceCreated { .. }) => {},
+			]
+		);
+	});
+	const ETH_AMOUNT: u128 = 1_000_000_000_000_000_000;
+
+	BridgeHubRococo::execute_with(|| {
+		type RuntimeEvent = <BridgeHubRococo as Chain>::RuntimeEvent;
+		type RuntimeOrigin = <BridgeHubRococo as Chain>::RuntimeOrigin;
+
+		// Set the gateway. This is needed because new fixtures use a different gateway address.
+		assert_ok!(<BridgeHubRococo as Chain>::System::set_storage(
+			RuntimeOrigin::root(),
+			vec![(
+				EthereumGatewayAddress::key().to_vec(),
+				sp_core::H160(hex!("87d1f7fdfEe7f651FaBc8bFCB6E086C278b77A7d")).encode(),
+			)],
+		));
+
+		// Construct SendToken message and sent to inbound queue
+		assert_ok!(send_inbound_message(make_send_native_eth_message()));
+
+		// Check that the send token message was sent using xcm
+		assert_expected_events!(
+			BridgeHubRococo,
+			vec![
+				RuntimeEvent::XcmpQueue(cumulus_pallet_xcmp_queue::Event::XcmpMessageSent { .. }) => {},
+			]
+		);
+	});
+
+	AssetHubRococo::execute_with(|| {
+		type RuntimeEvent = <AssetHubRococo as Chain>::RuntimeEvent;
+		type RuntimeOrigin = <AssetHubRococo as Chain>::RuntimeOrigin;
+
+		let _issued_event = RuntimeEvent::ForeignAssets(pallet_assets::Event::Issued {
+			asset_id: origin_location.clone(),
+			owner: AssetHubRococoReceiver::get().into(),
+			amount: ETH_AMOUNT,
+		});
+		// Check that AssetHub has issued the foreign asset
+		assert_expected_events!(
+			AssetHubRococo,
+			vec![
+				_issued_event => {},
+			]
+		);
+		let assets =
+			vec![Asset { id: AssetId(origin_location.clone()), fun: Fungible(ETH_AMOUNT) }];
+		let multi_assets = VersionedAssets::from(Assets::from(assets));
+
+		let destination = origin_location.clone().into();
+
+		let beneficiary = VersionedLocation::from(Location::new(
+			0,
+			[AccountKey20 { network: None, key: ETHEREUM_DESTINATION_ADDRESS.into() }],
+		));
+
+		let free_balance_before = <AssetHubRococo as AssetHubRococoPallet>::Balances::free_balance(
+			AssetHubRococoReceiver::get(),
+		);
+		// Send the Weth back to Ethereum
+		<AssetHubRococo as AssetHubRococoPallet>::PolkadotXcm::limited_reserve_transfer_assets(
+			RuntimeOrigin::signed(AssetHubRococoReceiver::get()),
+			Box::new(destination),
+			Box::new(beneficiary),
+			Box::new(multi_assets),
+			0,
+			Unlimited,
+		)
+		.unwrap();
+
+		let _burned_event = RuntimeEvent::ForeignAssets(pallet_assets::Event::Burned {
+			asset_id: origin_location.clone(),
+			owner: AssetHubRococoReceiver::get().into(),
+			balance: ETH_AMOUNT,
+		});
+		// Check that AssetHub has issued the foreign asset
+		let _destination = origin_location.clone();
+		assert_expected_events!(
+			AssetHubRococo,
+			vec![
+				_burned_event => {},
+				RuntimeEvent::PolkadotXcm(pallet_xcm::Event::Sent {
+					destination: _destination, ..
+				}) => {},
+			]
+		);
+
+		let free_balance_after = <AssetHubRococo as AssetHubRococoPallet>::Balances::free_balance(
+			AssetHubRococoReceiver::get(),
+		);
+		// Assert at least DefaultBridgeHubEthereumBaseFee charged from the sender
+		let free_balance_diff = free_balance_before - free_balance_after;
+		assert!(free_balance_diff > DefaultBridgeHubEthereumBaseFee::get());
+	});
+
+	BridgeHubRococo::execute_with(|| {
+		type RuntimeEvent = <BridgeHubRococo as Chain>::RuntimeEvent;
+		// Check that the transfer token back to Ethereum message was queue in the Ethereum
+		// Outbound Queue
+		assert_expected_events!(
+			BridgeHubRococo,
+			vec![
+				RuntimeEvent::EthereumOutboundQueue(snowbridge_pallet_outbound_queue::Event::MessageAccepted {..}) => {},
+				RuntimeEvent::EthereumOutboundQueue(snowbridge_pallet_outbound_queue::Event::MessageQueued {..}) => {},
+			]
+		);
+
+		let events = BridgeHubRococo::events();
+		// Check that the local fee was credited to the Snowbridge sovereign account
+		assert!(
+			events.iter().any(|event| matches!(
+				event,
+				RuntimeEvent::Balances(pallet_balances::Event::Minted { who, amount })
+					if *who == TREASURY_ACCOUNT.into() && *amount == 16903333
+			)),
+			"Snowbridge sovereign takes local fee."
+		);
+		// Check that the remote fee was credited to the AssetHub sovereign account
+		assert!(
+			events.iter().any(|event| matches!(
+				event,
+				RuntimeEvent::Balances(pallet_balances::Event::Minted { who, amount })
+					if *who == assethub_sovereign && *amount == 2680000000000,
+			)),
+			"AssetHub sovereign takes remote fee."
+		);
+	});
+}
+
 #[test]
 fn send_token_from_ethereum_to_asset_hub_fail_for_insufficient_fund() {
 	// Insufficient fund
@@ -563,7 +734,7 @@ fn register_weth_token_in_asset_hub_fail_for_insufficient_fee() {
 	});
 }
 
-fn send_token_from_ethereum_to_asset_hub_with_fee(account_id: [u8; 32], fee: u128) {
+fn send_weth_from_ethereum_to_asset_hub_with_fee(account_id: [u8; 32], fee: u128) {
 	let weth_asset_location: Location = Location::new(
 		2,
 		[EthereumNetwork::get().into(), AccountKey20 { network: None, key: WETH }],
@@ -622,8 +793,8 @@ fn send_token_from_ethereum_to_asset_hub_with_fee(account_id: [u8; 32], fee: u12
 }
 
 #[test]
-fn send_token_from_ethereum_to_existent_account_on_asset_hub() {
-	send_token_from_ethereum_to_asset_hub_with_fee(AssetHubRococoSender::get().into(), XCM_FEE);
+fn send_weth_from_ethereum_to_existent_account_on_asset_hub() {
+	send_weth_from_ethereum_to_asset_hub_with_fee(AssetHubRococoSender::get().into(), XCM_FEE);
 
 	AssetHubRococo::execute_with(|| {
 		type RuntimeEvent = <AssetHubRococo as Chain>::RuntimeEvent;
@@ -639,8 +810,8 @@ fn send_token_from_ethereum_to_existent_account_on_asset_hub() {
 }
 
 #[test]
-fn send_token_from_ethereum_to_non_existent_account_on_asset_hub() {
-	send_token_from_ethereum_to_asset_hub_with_fee([1; 32], XCM_FEE);
+fn send_weth_from_ethereum_to_non_existent_account_on_asset_hub() {
+	send_weth_from_ethereum_to_asset_hub_with_fee([1; 32], XCM_FEE);
 
 	AssetHubRococo::execute_with(|| {
 		type RuntimeEvent = <AssetHubRococo as Chain>::RuntimeEvent;
@@ -656,8 +827,8 @@ fn send_token_from_ethereum_to_non_existent_account_on_asset_hub() {
 }
 
 #[test]
-fn send_token_from_ethereum_to_non_existent_account_on_asset_hub_with_insufficient_fee() {
-	send_token_from_ethereum_to_asset_hub_with_fee([1; 32], INSUFFICIENT_XCM_FEE);
+fn send_weth_from_ethereum_to_non_existent_account_on_asset_hub_with_insufficient_fee() {
+	send_weth_from_ethereum_to_asset_hub_with_fee([1; 32], INSUFFICIENT_XCM_FEE);
 
 	AssetHubRococo::execute_with(|| {
 		type RuntimeEvent = <AssetHubRococo as Chain>::RuntimeEvent;
@@ -674,10 +845,10 @@ fn send_token_from_ethereum_to_non_existent_account_on_asset_hub_with_insufficie
 }
 
 #[test]
-fn send_token_from_ethereum_to_non_existent_account_on_asset_hub_with_sufficient_fee_but_do_not_satisfy_ed(
+fn send_weth_from_ethereum_to_non_existent_account_on_asset_hub_with_sufficient_fee_but_do_not_satisfy_ed(
 ) {
 	// On AH the xcm fee is 26_789_690 and the ED is 3_300_000
-	send_token_from_ethereum_to_asset_hub_with_fee([1; 32], 30_000_000);
+	send_weth_from_ethereum_to_asset_hub_with_fee([1; 32], 30_000_000);
 
 	AssetHubRococo::execute_with(|| {
 		type RuntimeEvent = <AssetHubRococo as Chain>::RuntimeEvent;
diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs
index a74a9b6256de2bbe89cb68070a2eb10c927d9e2d..ce3e58c6a66be289e268e6e4def36382438f82fa 100644
--- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs
+++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs
@@ -27,7 +27,8 @@ use asset_hub_rococo_runtime::{
 	AllPalletsWithoutSystem, AssetConversion, AssetDeposit, Assets, Balances, Block,
 	CollatorSelection, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance,
 	MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime, RuntimeCall,
-	RuntimeEvent, RuntimeOrigin, SessionKeys, ToWestendXcmRouterInstance, TrustBackedAssetsInstance, XcmpQueue,
+	RuntimeEvent, RuntimeOrigin, SessionKeys, ToWestendXcmRouterInstance,
+	TrustBackedAssetsInstance, XcmpQueue,
 };
 use asset_test_utils::{
 	test_cases_over_bridge::TestBridgingConfig, CollatorSessionKey, CollatorSessionKeys,
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 faec8bd2f03d1473a3d67996e972b5f2e36c70bf..0968f9ef06f5529c44c047d257aaaa4ed3da845f 100644
--- a/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs
+++ b/cumulus/parachains/runtimes/assets/test-utils/src/test_cases.rs
@@ -1695,8 +1695,10 @@ where
 			0,
 			test_account
 		));
-		let execution_fees =
-			Runtime::query_weight_to_asset_fee(xcm_weight.unwrap(), VersionedAssetId::from(AssetId(asset_not_in_pool)));
+		let execution_fees = Runtime::query_weight_to_asset_fee(
+			xcm_weight.unwrap(),
+			VersionedAssetId::from(AssetId(asset_not_in_pool)),
+		);
 		// Now it works!
 		assert_ok!(execution_fees);
 	});
diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs
index 8fe2efb4fb7b5b2fa40c68faf2addfaec70d7356..040820ed72ffb46d47f86e7822fc4b3351a63bb6 100644
--- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs
+++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/tests/tests.rs
@@ -18,8 +18,9 @@
 
 use bp_polkadot_core::Signature;
 use bridge_hub_rococo_runtime::{
+	bridge_common_config, bridge_to_bulletin_config,
 	bridge_to_ethereum_config::EthereumGatewayAddress,
-	bridge_common_config, bridge_to_bulletin_config, bridge_to_westend_config,
+	bridge_to_westend_config,
 	xcm_config::{LocationToAccountId, RelayNetwork, TokenLocation, XcmConfig},
 	AllPalletsWithoutSystem, Block, BridgeRejectObsoleteHeadersAndMessages, Executive,
 	ExistentialDeposit, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent,
diff --git a/prdoc/pr_7089.prdoc b/prdoc/pr_7089.prdoc
new file mode 100644
index 0000000000000000000000000000000000000000..5e5e92657debad3e478352c141e68b617ea7a879
--- /dev/null
+++ b/prdoc/pr_7089.prdoc
@@ -0,0 +1,16 @@
+# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
+# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
+
+title: [stable2409] Backport Snowbridge - Support bridging native ETH
+
+doc:
+  - audience: Runtime User
+    description: 
+      Support Native ETH as an asset type instead of only supporting WETH. WETH is still supported, but adds
+      support for ETH in the inbound and outbound routers.
+
+crates:
+  - name: snowbridge-router-primitives
+    bump: patch
+  - name: snowbridge-pallet-inbound-queue-fixtures
+    bump: patch