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 #[cfg(feature = "runtime-benchmarks")]
196 type Helper = Runtime;
197}
198
199#[cfg(not(any(feature = "std", feature = "fast-runtime", feature = "runtime-benchmarks", test)))]
200parameter_types! {
201 pub const ChainForkVersions: ForkVersions = ForkVersions {
202 genesis: Fork {
203 version: hex!("90000069"),
204 epoch: 0,
205 },
206 altair: Fork {
207 version: hex!("90000070"),
208 epoch: 50,
209 },
210 bellatrix: Fork {
211 version: hex!("90000071"),
212 epoch: 100,
213 },
214 capella: Fork {
215 version: hex!("90000072"),
216 epoch: 56832,
217 },
218 deneb: Fork {
219 version: hex!("90000073"),
220 epoch: 132608,
221 },
222 electra: Fork {
223 version: hex!("90000074"),
224 epoch: 222464, },
226 };
227}
228
229#[cfg(any(feature = "std", feature = "fast-runtime", feature = "runtime-benchmarks", test))]
230parameter_types! {
231 pub const ChainForkVersions: ForkVersions = ForkVersions {
232 genesis: Fork {
233 version: hex!("00000000"),
234 epoch: 0,
235 },
236 altair: Fork {
237 version: hex!("01000000"),
238 epoch: 0,
239 },
240 bellatrix: Fork {
241 version: hex!("02000000"),
242 epoch: 0,
243 },
244 capella: Fork {
245 version: hex!("03000000"),
246 epoch: 0,
247 },
248 deneb: Fork {
249 version: hex!("04000000"),
250 epoch: 0,
251 },
252 electra: Fork {
253 version: hex!("05000000"),
254 epoch: 0,
255 },
256 };
257}
258
259impl snowbridge_pallet_ethereum_client::Config for Runtime {
260 type RuntimeEvent = RuntimeEvent;
261 type ForkVersions = ChainForkVersions;
262 type FreeHeadersInterval = ConstU32<SLOTS_PER_EPOCH>;
263 type WeightInfo = crate::weights::snowbridge_pallet_ethereum_client::WeightInfo<Runtime>;
264}
265
266impl snowbridge_pallet_system::Config for Runtime {
267 type RuntimeEvent = RuntimeEvent;
268 type OutboundQueue = EthereumOutboundQueue;
269 type SiblingOrigin = EnsureXcm<AllowSiblingsOnly>;
270 type AgentIdOf = snowbridge_core::AgentIdOf;
271 type TreasuryAccount = TreasuryAccount;
272 type Token = Balances;
273 type WeightInfo = crate::weights::snowbridge_pallet_system::WeightInfo<Runtime>;
274 #[cfg(feature = "runtime-benchmarks")]
275 type Helper = ();
276 type DefaultPricingParameters = Parameters;
277 type InboundDeliveryCost = EthereumInboundQueue;
278 type UniversalLocation = UniversalLocation;
279 type EthereumLocation = EthereumLocation;
280}
281
282pub struct AllowFromEthereumFrontend;
283impl Contains<Location> for AllowFromEthereumFrontend {
284 fn contains(location: &Location) -> bool {
285 match location.unpack() {
286 (1, [Parachain(para_id), PalletInstance(index)]) =>
287 return *para_id == ASSET_HUB_ID && *index == FRONTEND_PALLET_INDEX,
288 _ => false,
289 }
290 }
291}
292
293impl snowbridge_pallet_system_v2::Config for Runtime {
294 type RuntimeEvent = RuntimeEvent;
295 type OutboundQueue = EthereumOutboundQueueV2;
296 type InboundQueue = EthereumInboundQueueV2;
297 type FrontendOrigin = EnsureXcm<AllowFromEthereumFrontend>;
298 type WeightInfo = crate::weights::snowbridge_pallet_system_v2::WeightInfo<Runtime>;
299 type GovernanceOrigin = EnsureRootWithSuccess<crate::AccountId, RootLocation>;
300 #[cfg(feature = "runtime-benchmarks")]
301 type Helper = ();
302}
303
304#[cfg(feature = "runtime-benchmarks")]
305pub mod benchmark_helpers {
306 use crate::{
307 bridge_to_ethereum_config::EthereumGatewayAddress, vec, EthereumBeaconClient, Runtime,
308 RuntimeOrigin, System,
309 };
310 use codec::Encode;
311 use hex_literal::hex;
312 use snowbridge_beacon_primitives::BeaconHeader;
313 use snowbridge_pallet_inbound_queue::BenchmarkHelper;
314 use snowbridge_pallet_inbound_queue_v2::BenchmarkHelper as InboundQueueBenchmarkHelperV2;
315 use snowbridge_pallet_outbound_queue_v2::BenchmarkHelper as OutboundQueueBenchmarkHelperV2;
316 use sp_core::H256;
317 use xcm::latest::{Assets, Location, SendError, SendResult, SendXcm, Xcm, XcmHash};
318
319 impl<T: snowbridge_pallet_ethereum_client::Config> BenchmarkHelper<T> for Runtime {
320 fn initialize_storage(beacon_header: BeaconHeader, block_roots_root: H256) {
321 EthereumBeaconClient::store_finalized_header(beacon_header, block_roots_root).unwrap();
322 System::set_storage(
323 RuntimeOrigin::root(),
324 vec![(
325 EthereumGatewayAddress::key().to_vec(),
326 hex!("EDa338E4dC46038493b885327842fD3E301CaB39").to_vec(),
327 )],
328 )
329 .unwrap();
330 }
331 }
332
333 impl<T: snowbridge_pallet_inbound_queue_v2::Config> InboundQueueBenchmarkHelperV2<T> for Runtime {
334 fn initialize_storage(beacon_header: BeaconHeader, block_roots_root: H256) {
335 EthereumBeaconClient::store_finalized_header(beacon_header, block_roots_root).unwrap();
336 }
337 }
338
339 impl<T: snowbridge_pallet_outbound_queue_v2::Config> OutboundQueueBenchmarkHelperV2<T> for Runtime {
340 fn initialize_storage(beacon_header: BeaconHeader, block_roots_root: H256) {
341 EthereumBeaconClient::store_finalized_header(beacon_header, block_roots_root).unwrap();
342 }
343 }
344
345 pub struct DoNothingRouter;
346 impl SendXcm for DoNothingRouter {
347 type Ticket = Xcm<()>;
348
349 fn validate(
350 _dest: &mut Option<Location>,
351 xcm: &mut Option<Xcm<()>>,
352 ) -> SendResult<Self::Ticket> {
353 Ok((xcm.clone().unwrap(), Assets::new()))
354 }
355 fn deliver(xcm: Xcm<()>) -> Result<XcmHash, SendError> {
356 let hash = xcm.using_encoded(sp_io::hashing::blake2_256);
357 Ok(hash)
358 }
359 }
360
361 impl snowbridge_pallet_system::BenchmarkHelper<RuntimeOrigin> for () {
362 fn make_xcm_origin(location: Location) -> RuntimeOrigin {
363 RuntimeOrigin::from(pallet_xcm::Origin::Xcm(location))
364 }
365 }
366
367 impl snowbridge_pallet_system_v2::BenchmarkHelper<RuntimeOrigin> for () {
368 fn make_xcm_origin(location: Location) -> RuntimeOrigin {
369 RuntimeOrigin::from(pallet_xcm::Origin::Xcm(location))
370 }
371 }
372}
373
374#[cfg(test)]
375mod tests {
376 use super::*;
377
378 #[test]
379 fn bridge_hub_inbound_queue_pallet_index_is_correct() {
380 assert_eq!(
381 INBOUND_QUEUE_PALLET_INDEX_V1,
382 <EthereumInboundQueue as frame_support::traits::PalletInfoAccess>::index() as u8
383 );
384 }
385
386 #[test]
387 fn bridge_hub_inbound_v2_queue_pallet_index_is_correct() {
388 assert_eq!(
389 INBOUND_QUEUE_PALLET_INDEX_V2,
390 <EthereumInboundQueueV2 as frame_support::traits::PalletInfoAccess>::index() as u8
391 );
392 }
393}
394
395pub(crate) mod migrations {
396 use frame_support::pallet_prelude::*;
397 use snowbridge_core::TokenId;
398
399 #[frame_support::storage_alias]
400 pub type OldNativeToForeignId<T: snowbridge_pallet_system::Config> = StorageMap<
401 snowbridge_pallet_system::Pallet<T>,
402 Blake2_128Concat,
403 xcm::v4::Location,
404 TokenId,
405 OptionQuery,
406 >;
407
408 pub struct MigrationForXcmV5<T: snowbridge_pallet_system::Config>(core::marker::PhantomData<T>);
410 impl<T: snowbridge_pallet_system::Config> frame_support::traits::OnRuntimeUpgrade
411 for MigrationForXcmV5<T>
412 {
413 fn on_runtime_upgrade() -> Weight {
414 let mut weight = T::DbWeight::get().reads(1);
415
416 let translate_westend = |pre: xcm::v4::Location| -> Option<xcm::v5::Location> {
417 weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
418 Some(xcm::v5::Location::try_from(pre).expect("valid location"))
419 };
420 snowbridge_pallet_system::ForeignToNativeId::<T>::translate_values(translate_westend);
421
422 weight
423 }
424 }
425}