referrerpolicy=no-referrer-when-downgrade

bridge_hub_westend_runtime/
bridge_to_ethereum_config.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Cumulus.
3// SPDX-License-Identifier: Apache-2.0
4
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// 	http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17use crate::{
18	bridge_common_config::BridgeReward,
19	xcm_config,
20	xcm_config::{RelayNetwork, RootLocation, TreasuryAccount, UniversalLocation, XcmConfig},
21	Balances, BridgeRelayers, EthereumBeaconClient, EthereumInboundQueue, EthereumInboundQueueV2,
22	EthereumOutboundQueue, EthereumOutboundQueueV2, EthereumSystem, EthereumSystemV2, MessageQueue,
23	Runtime, RuntimeEvent, TransactionByteFee,
24};
25use bp_asset_hub_westend::CreateForeignAssetDeposit;
26use frame_support::{parameter_types, traits::Contains, weights::ConstantMultiplier};
27use frame_system::EnsureRootWithSuccess;
28use hex_literal::hex;
29use pallet_xcm::EnsureXcm;
30use parachains_common::{AccountId, Balance};
31use snowbridge_beacon_primitives::{Fork, ForkVersions};
32use snowbridge_core::{gwei, meth, AllowSiblingsOnly, PricingParameters, Rewards};
33use snowbridge_outbound_queue_primitives::{
34	v1::{ConstantGasMeter, EthereumBlobExporter},
35	v2::{ConstantGasMeter as ConstantGasMeterV2, EthereumBlobExporter as EthereumBlobExporterV2},
36};
37use sp_core::H160;
38use sp_runtime::{
39	traits::{ConstU32, ConstU8, Keccak256},
40	FixedU128,
41};
42use testnet_parachains_constants::westend::{
43	currency::*,
44	fee::WeightToFee,
45	snowbridge::{
46		AssetHubParaId, EthereumLocation, EthereumNetwork, FRONTEND_PALLET_INDEX,
47		INBOUND_QUEUE_PALLET_INDEX_V1, INBOUND_QUEUE_PALLET_INDEX_V2,
48	},
49};
50use westend_runtime_constants::system_parachain::ASSET_HUB_ID;
51use xcm::prelude::{GlobalConsensus, InteriorLocation, Location, PalletInstance, Parachain};
52use xcm_executor::XcmExecutor;
53
54pub const SLOTS_PER_EPOCH: u32 = snowbridge_pallet_ethereum_client::config::SLOTS_PER_EPOCH as u32;
55
56/// Exports message to the Ethereum Gateway contract.
57pub type SnowbridgeExporter = EthereumBlobExporter<
58	UniversalLocation,
59	EthereumNetwork,
60	snowbridge_pallet_outbound_queue::Pallet<Runtime>,
61	snowbridge_core::AgentIdOf,
62	EthereumSystem,
63>;
64
65pub type SnowbridgeExporterV2 = EthereumBlobExporterV2<
66	UniversalLocation,
67	EthereumNetwork,
68	EthereumOutboundQueueV2,
69	EthereumSystemV2,
70	AssetHubParaId,
71>;
72
73// Ethereum Bridge
74parameter_types! {
75	pub storage EthereumGatewayAddress: H160 = H160(hex!("b1185ede04202fe62d38f5db72f71e38ff3e8305"));
76}
77
78parameter_types! {
79	pub const CreateAssetCall: [u8;2] = [53, 0];
80	pub Parameters: PricingParameters<u128> = PricingParameters {
81		exchange_rate: FixedU128::from_rational(1, 400),
82		fee_per_gas: gwei(20),
83		rewards: Rewards { local: 1 * UNITS, remote: meth(1) },
84		multiplier: FixedU128::from_rational(1, 1),
85	};
86	pub AssetHubFromEthereum: Location = Location::new(1, [GlobalConsensus(RelayNetwork::get()), Parachain(ASSET_HUB_ID)]);
87	pub EthereumUniversalLocation: InteriorLocation = [GlobalConsensus(EthereumNetwork::get())].into();
88	pub AssetHubUniversalLocation: InteriorLocation = [GlobalConsensus(RelayNetwork::get()), Parachain(ASSET_HUB_ID)].into();
89	pub InboundQueueV2Location: InteriorLocation = [PalletInstance(INBOUND_QUEUE_PALLET_INDEX_V2)].into();
90	pub const SnowbridgeReward: BridgeReward = BridgeReward::Snowbridge;
91	pub SnowbridgeFrontendLocation: Location = Location::new(1, [Parachain(ASSET_HUB_ID), PalletInstance(FRONTEND_PALLET_INDEX)]);
92}
93
94impl snowbridge_pallet_inbound_queue::Config for Runtime {
95	type RuntimeEvent = RuntimeEvent;
96	type Verifier = snowbridge_pallet_ethereum_client::Pallet<Runtime>;
97	type Token = Balances;
98	#[cfg(not(feature = "runtime-benchmarks"))]
99	type XcmSender = crate::XcmRouter;
100	#[cfg(feature = "runtime-benchmarks")]
101	type XcmSender = benchmark_helpers::DoNothingRouter;
102	type ChannelLookup = EthereumSystem;
103	type GatewayAddress = EthereumGatewayAddress;
104	#[cfg(feature = "runtime-benchmarks")]
105	type Helper = Runtime;
106	type MessageConverter = snowbridge_inbound_queue_primitives::v1::MessageToXcm<
107		CreateAssetCall,
108		CreateForeignAssetDeposit,
109		ConstU8<INBOUND_QUEUE_PALLET_INDEX_V1>,
110		AccountId,
111		Balance,
112		EthereumSystem,
113		EthereumUniversalLocation,
114		AssetHubFromEthereum,
115	>;
116	type WeightToFee = WeightToFee;
117	type LengthToFee = ConstantMultiplier<Balance, TransactionByteFee>;
118	type MaxMessageSize = ConstU32<2048>;
119	type WeightInfo = crate::weights::snowbridge_pallet_inbound_queue::WeightInfo<Runtime>;
120	type PricingParameters = EthereumSystem;
121	type AssetTransactor = <xcm_config::XcmConfig as xcm_executor::Config>::AssetTransactor;
122}
123
124impl snowbridge_pallet_inbound_queue_v2::Config for Runtime {
125	type RuntimeEvent = RuntimeEvent;
126	type Verifier = EthereumBeaconClient;
127	#[cfg(not(feature = "runtime-benchmarks"))]
128	type XcmSender = crate::XcmRouter;
129	#[cfg(feature = "runtime-benchmarks")]
130	type XcmSender = benchmark_helpers::DoNothingRouter;
131	type GatewayAddress = EthereumGatewayAddress;
132	#[cfg(feature = "runtime-benchmarks")]
133	type Helper = Runtime;
134	type WeightInfo = crate::weights::snowbridge_pallet_inbound_queue_v2::WeightInfo<Runtime>;
135	type AssetHubParaId = AssetHubParaId;
136	type XcmExecutor = XcmExecutor<XcmConfig>;
137	type MessageConverter = snowbridge_inbound_queue_primitives::v2::MessageToXcm<
138		CreateAssetCall,
139		CreateForeignAssetDeposit,
140		EthereumNetwork,
141		InboundQueueV2Location,
142		EthereumSystem,
143		EthereumGatewayAddress,
144		EthereumUniversalLocation,
145		AssetHubFromEthereum,
146		AssetHubUniversalLocation,
147		AccountId,
148	>;
149	type AccountToLocation = xcm_builder::AliasesIntoAccountId32<
150		xcm_config::RelayNetwork,
151		<Runtime as frame_system::Config>::AccountId,
152	>;
153	type RewardKind = BridgeReward;
154	type DefaultRewardKind = SnowbridgeReward;
155	type RewardPayment = BridgeRelayers;
156}
157
158impl snowbridge_pallet_outbound_queue::Config for Runtime {
159	type RuntimeEvent = RuntimeEvent;
160	type Hashing = Keccak256;
161	type MessageQueue = MessageQueue;
162	type Decimals = ConstU8<12>;
163	type MaxMessagePayloadSize = ConstU32<2048>;
164	type MaxMessagesPerBlock = ConstU32<32>;
165	type GasMeter = ConstantGasMeter;
166	type Balance = Balance;
167	type WeightToFee = WeightToFee;
168	type WeightInfo = crate::weights::snowbridge_pallet_outbound_queue::WeightInfo<Runtime>;
169	type PricingParameters = EthereumSystem;
170	type Channels = EthereumSystem;
171}
172
173impl snowbridge_pallet_outbound_queue_v2::Config for Runtime {
174	type RuntimeEvent = RuntimeEvent;
175	type Hashing = Keccak256;
176	type MessageQueue = MessageQueue;
177	// Maximum payload size for outbound messages.
178	type MaxMessagePayloadSize = ConstU32<2048>;
179	// Maximum number of outbound messages that can be committed per block.
180	// It's benchmarked, including the entire process flow(initialize,submit,commit) in the
181	// worst-case, Benchmark results in `../weights/snowbridge_pallet_outbound_queue_v2.
182	// rs` show that the `process` function consumes less than 1% of the block capacity, which is
183	// safe enough.
184	type MaxMessagesPerBlock = ConstU32<32>;
185	type GasMeter = ConstantGasMeterV2;
186	type Balance = Balance;
187	type WeightToFee = WeightToFee;
188	type Verifier = EthereumBeaconClient;
189	type GatewayAddress = EthereumGatewayAddress;
190	type WeightInfo = crate::weights::snowbridge_pallet_outbound_queue_v2::WeightInfo<Runtime>;
191	type EthereumNetwork = EthereumNetwork;
192	type RewardKind = BridgeReward;
193	type DefaultRewardKind = SnowbridgeReward;
194	type RewardPayment = BridgeRelayers;
195	// No consumers of this notifier on Bridge Hub.
196	type OnNewCommitment = ();
197	#[cfg(feature = "runtime-benchmarks")]
198	type Helper = Runtime;
199}
200
201#[cfg(not(any(feature = "std", feature = "fast-runtime", feature = "runtime-benchmarks", test)))]
202parameter_types! {
203	pub const ChainForkVersions: ForkVersions = ForkVersions {
204		genesis: Fork {
205			version: hex!("90000069"),
206			epoch: 0,
207		},
208		altair: Fork {
209			version: hex!("90000070"),
210			epoch: 50,
211		},
212		bellatrix: Fork {
213			version: hex!("90000071"),
214			epoch: 100,
215		},
216		capella: Fork {
217			version: hex!("90000072"),
218			epoch: 56832,
219		},
220		deneb: Fork {
221			version: hex!("90000073"),
222			epoch: 132608,
223		},
224		electra: Fork {
225			version: hex!("90000074"),
226			epoch: 222464, // https://github.com/ethereum/EIPs/pull/9322/files
227		},
228	};
229}
230
231#[cfg(any(feature = "std", feature = "fast-runtime", feature = "runtime-benchmarks", test))]
232parameter_types! {
233	pub const ChainForkVersions: ForkVersions = ForkVersions {
234		genesis: Fork {
235			version: hex!("00000000"),
236			epoch: 0,
237		},
238		altair: Fork {
239			version: hex!("01000000"),
240			epoch: 0,
241		},
242		bellatrix: Fork {
243			version: hex!("02000000"),
244			epoch: 0,
245		},
246		capella: Fork {
247			version: hex!("03000000"),
248			epoch: 0,
249		},
250		deneb: Fork {
251			version: hex!("04000000"),
252			epoch: 0,
253		},
254		electra: Fork {
255			version: hex!("05000000"),
256			epoch: 0,
257		},
258	};
259}
260
261impl snowbridge_pallet_ethereum_client::Config for Runtime {
262	type RuntimeEvent = RuntimeEvent;
263	type ForkVersions = ChainForkVersions;
264	type FreeHeadersInterval = ConstU32<SLOTS_PER_EPOCH>;
265	type WeightInfo = crate::weights::snowbridge_pallet_ethereum_client::WeightInfo<Runtime>;
266}
267
268impl snowbridge_pallet_system::Config for Runtime {
269	type RuntimeEvent = RuntimeEvent;
270	type OutboundQueue = EthereumOutboundQueue;
271	type SiblingOrigin = EnsureXcm<AllowSiblingsOnly>;
272	type AgentIdOf = snowbridge_core::AgentIdOf;
273	type TreasuryAccount = TreasuryAccount;
274	type Token = Balances;
275	type WeightInfo = crate::weights::snowbridge_pallet_system::WeightInfo<Runtime>;
276	#[cfg(feature = "runtime-benchmarks")]
277	type Helper = ();
278	type DefaultPricingParameters = Parameters;
279	type InboundDeliveryCost = EthereumInboundQueue;
280	type UniversalLocation = UniversalLocation;
281	type EthereumLocation = EthereumLocation;
282}
283
284pub struct AllowFromEthereumFrontend;
285impl Contains<Location> for AllowFromEthereumFrontend {
286	fn contains(location: &Location) -> bool {
287		match location.unpack() {
288			(1, [Parachain(para_id), PalletInstance(index)]) =>
289				return *para_id == ASSET_HUB_ID && *index == FRONTEND_PALLET_INDEX,
290			_ => false,
291		}
292	}
293}
294
295impl snowbridge_pallet_system_v2::Config for Runtime {
296	type RuntimeEvent = RuntimeEvent;
297	type OutboundQueue = EthereumOutboundQueueV2;
298	type InboundQueue = EthereumInboundQueueV2;
299	type FrontendOrigin = EnsureXcm<AllowFromEthereumFrontend>;
300	type WeightInfo = crate::weights::snowbridge_pallet_system_v2::WeightInfo<Runtime>;
301	type GovernanceOrigin = EnsureRootWithSuccess<crate::AccountId, RootLocation>;
302	#[cfg(feature = "runtime-benchmarks")]
303	type Helper = ();
304}
305
306#[cfg(feature = "runtime-benchmarks")]
307pub mod benchmark_helpers {
308	use crate::{
309		bridge_to_ethereum_config::EthereumGatewayAddress, vec, EthereumBeaconClient, Runtime,
310		RuntimeOrigin, System,
311	};
312	use codec::Encode;
313	use frame_support::assert_ok;
314	use hex_literal::hex;
315	use snowbridge_beacon_primitives::BeaconHeader;
316	use snowbridge_inbound_queue_primitives::EventFixture;
317	use snowbridge_pallet_inbound_queue::BenchmarkHelper;
318	use snowbridge_pallet_inbound_queue_fixtures::register_token::make_register_token_message;
319	use snowbridge_pallet_inbound_queue_v2::BenchmarkHelper as InboundQueueBenchmarkHelperV2;
320	use snowbridge_pallet_inbound_queue_v2_fixtures::register_token::make_register_token_message as make_register_token_message_v2;
321	use snowbridge_pallet_outbound_queue_v2::BenchmarkHelper as OutboundQueueBenchmarkHelperV2;
322	use sp_core::H256;
323	use xcm::latest::{Assets, Location, SendError, SendResult, SendXcm, Xcm, XcmHash};
324
325	impl<T: snowbridge_pallet_ethereum_client::Config> BenchmarkHelper<T> for Runtime {
326		fn initialize_storage() -> EventFixture {
327			let message = make_register_token_message();
328			EthereumBeaconClient::store_finalized_header(
329				message.finalized_header,
330				message.block_roots_root,
331			)
332			.unwrap();
333			System::set_storage(
334				RuntimeOrigin::root(),
335				vec![(
336					EthereumGatewayAddress::key().to_vec(),
337					hex!("EDa338E4dC46038493b885327842fD3E301CaB39").to_vec(),
338				)],
339			)
340			.unwrap();
341			message
342		}
343	}
344
345	impl<T: snowbridge_pallet_inbound_queue_v2::Config> InboundQueueBenchmarkHelperV2<T> for Runtime {
346		fn initialize_storage() -> EventFixture {
347			let message = make_register_token_message_v2();
348
349			assert_ok!(EthereumBeaconClient::store_finalized_header(
350				message.finalized_header,
351				message.block_roots_root,
352			));
353
354			message
355		}
356	}
357
358	impl<T: snowbridge_pallet_outbound_queue_v2::Config> OutboundQueueBenchmarkHelperV2<T> for Runtime {
359		fn initialize_storage(beacon_header: BeaconHeader, block_roots_root: H256) {
360			EthereumBeaconClient::store_finalized_header(beacon_header, block_roots_root).unwrap();
361		}
362	}
363
364	pub struct DoNothingRouter;
365	impl SendXcm for DoNothingRouter {
366		type Ticket = Xcm<()>;
367
368		fn validate(
369			_dest: &mut Option<Location>,
370			xcm: &mut Option<Xcm<()>>,
371		) -> SendResult<Self::Ticket> {
372			Ok((xcm.clone().unwrap(), Assets::new()))
373		}
374		fn deliver(xcm: Xcm<()>) -> Result<XcmHash, SendError> {
375			let hash = xcm.using_encoded(sp_io::hashing::blake2_256);
376			Ok(hash)
377		}
378	}
379
380	impl snowbridge_pallet_system::BenchmarkHelper<RuntimeOrigin> for () {
381		fn make_xcm_origin(location: Location) -> RuntimeOrigin {
382			RuntimeOrigin::from(pallet_xcm::Origin::Xcm(location))
383		}
384	}
385
386	impl snowbridge_pallet_system_v2::BenchmarkHelper<RuntimeOrigin> for () {
387		fn make_xcm_origin(location: Location) -> RuntimeOrigin {
388			RuntimeOrigin::from(pallet_xcm::Origin::Xcm(location))
389		}
390	}
391}
392
393#[cfg(test)]
394mod tests {
395	use super::*;
396
397	#[test]
398	fn bridge_hub_inbound_queue_pallet_index_is_correct() {
399		assert_eq!(
400			INBOUND_QUEUE_PALLET_INDEX_V1,
401			<EthereumInboundQueue as frame_support::traits::PalletInfoAccess>::index() as u8
402		);
403	}
404
405	#[test]
406	fn bridge_hub_inbound_v2_queue_pallet_index_is_correct() {
407		assert_eq!(
408			INBOUND_QUEUE_PALLET_INDEX_V2,
409			<EthereumInboundQueueV2 as frame_support::traits::PalletInfoAccess>::index() as u8
410		);
411	}
412}
413
414pub(crate) mod migrations {
415	use frame_support::pallet_prelude::*;
416	use snowbridge_core::TokenId;
417
418	#[frame_support::storage_alias]
419	pub type OldNativeToForeignId<T: snowbridge_pallet_system::Config> = StorageMap<
420		snowbridge_pallet_system::Pallet<T>,
421		Blake2_128Concat,
422		xcm::v4::Location,
423		TokenId,
424		OptionQuery,
425	>;
426
427	/// One shot migration for NetworkId::Westend to NetworkId::ByGenesis(WESTEND_GENESIS_HASH)
428	pub struct MigrationForXcmV5<T: snowbridge_pallet_system::Config>(core::marker::PhantomData<T>);
429	impl<T: snowbridge_pallet_system::Config> frame_support::traits::OnRuntimeUpgrade
430		for MigrationForXcmV5<T>
431	{
432		fn on_runtime_upgrade() -> Weight {
433			let mut weight = T::DbWeight::get().reads(1);
434
435			let translate_westend = |pre: xcm::v4::Location| -> Option<xcm::v5::Location> {
436				weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
437				Some(xcm::v5::Location::try_from(pre).expect("valid location"))
438			};
439			snowbridge_pallet_system::ForeignToNativeId::<T>::translate_values(translate_westend);
440
441			weight
442		}
443	}
444}