1use 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
56pub 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
73parameter_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 type MaxMessagePayloadSize = ConstU32<2048>;
179 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 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, },
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 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}