1
// Copyright (C) Moondance Labs Ltd.
2
// This file is part of Tanssi.
3

            
4
// Tanssi is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8

            
9
// Tanssi is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13

            
14
// You should have received a copy of the GNU General Public License
15
// along with Tanssi.  If not, see <http://www.gnu.org/licenses/>.
16

            
17
#![cfg_attr(not(feature = "std"), no_std)]
18
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
19
#![recursion_limit = "256"]
20

            
21
// Make the WASM binary available.
22
#[cfg(feature = "std")]
23
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
24

            
25
extern crate alloc;
26

            
27
use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases;
28
#[cfg(feature = "std")]
29
use sp_version::NativeVersion;
30

            
31
#[cfg(any(feature = "std", test))]
32
pub use sp_runtime::BuildStorage;
33

            
34
pub mod genesis_config_presets;
35
pub mod migrations;
36
mod precompiles;
37
pub mod weights;
38
pub mod xcm_config;
39

            
40
use {
41
    crate::precompiles::TemplatePrecompiles,
42
    alloc::{vec, vec::Vec},
43
    cumulus_primitives_core::AggregateMessageOrigin,
44
    cumulus_primitives_core::ParaId,
45
    dp_impl_tanssi_pallets_config::impl_tanssi_pallets_config,
46
    ethereum::AuthorizationList,
47
    fp_account::EthereumSignature,
48
    fp_rpc::TransactionStatus,
49
    frame_support::{
50
        construct_runtime,
51
        dispatch::{DispatchClass, GetDispatchInfo},
52
        dynamic_params::{dynamic_pallet_params, dynamic_params},
53
        genesis_builder_helper::{build_state, get_preset},
54
        pallet_prelude::DispatchResult,
55
        parameter_types,
56
        traits::{
57
            fungible::{Balanced, Credit, Inspect},
58
            tokens::ConversionToAssetBalance,
59
            ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, Contains, FindAuthor, InsideBoth,
60
            InstanceFilter, OnFinalize, OnUnbalanced,
61
        },
62
        weights::{
63
            constants::{
64
                BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight,
65
                WEIGHT_REF_TIME_PER_SECOND,
66
            },
67
            ConstantMultiplier, FeePolynomial, Weight, WeightToFee as _, WeightToFeeCoefficient,
68
            WeightToFeeCoefficients, WeightToFeePolynomial,
69
        },
70
    },
71
    frame_system::{
72
        limits::{BlockLength, BlockWeights},
73
        EnsureRoot,
74
    },
75
    hex_literal::hex,
76
    nimbus_primitives::{NimbusId, SlotBeacon},
77
    pallet_ethereum::{Call::transact, PostLogContent, Transaction as EthereumTransaction},
78
    pallet_evm::{
79
        Account as EVMAccount, EVMFungibleAdapter, EnsureAddressNever, EnsureAddressRoot,
80
        EnsureCreateOrigin, FeeCalculator, FrameSystemAccountProvider, GasWeightMapping,
81
        IdentityAddressMapping, OnChargeEVMTransaction as OnChargeEVMTransactionT, Runner,
82
    },
83
    pallet_transaction_payment::FungibleAdapter,
84
    parity_scale_codec::{Decode, DecodeWithMemTracking, Encode},
85
    polkadot_runtime_common::SlowAdjustingFeeUpdate,
86
    scale_info::TypeInfo,
87
    smallvec::smallvec,
88
    sp_api::impl_runtime_apis,
89
    sp_consensus_slots::{Slot, SlotDuration},
90
    sp_core::{Get, MaxEncodedLen, OpaqueMetadata, H160, H256, U256},
91
    sp_runtime::{
92
        generic, impl_opaque_keys,
93
        traits::{
94
            BlakeTwo256, Block as BlockT, DispatchInfoOf, Dispatchable, IdentifyAccount,
95
            IdentityLookup, PostDispatchInfoOf, UniqueSaturatedInto, Verify,
96
        },
97
        transaction_validity::{
98
            InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError,
99
        },
100
        ApplyExtrinsicResult, BoundedVec, Cow,
101
    },
102
    sp_version::RuntimeVersion,
103
    xcm::prelude::Location,
104
    xcm::v5::NetworkId,
105
    xcm::Version as XcmVersion,
106
    xcm::{IntoVersion, VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm},
107
    xcm_runtime_apis::{
108
        dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects},
109
        fees::Error as XcmPaymentApiError,
110
    },
111
};
112
pub use {
113
    sp_consensus_aura::sr25519::AuthorityId as AuraId,
114
    sp_runtime::{MultiAddress, Perbill, Permill},
115
};
116

            
117
// Polkadot imports
118
use polkadot_runtime_common::BlockHashCount;
119

            
120
pub type Precompiles = TemplatePrecompiles<Runtime>;
121

            
122
/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
123
pub type Signature = EthereumSignature;
124

            
125
/// Some way of identifying an account on the chain. We intentionally make it equivalent
126
/// to the public key of our transaction signing scheme.
127
pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
128

            
129
/// Balance of an account.
130
pub type Balance = u128;
131

            
132
/// Index of a transaction in the chain.
133
pub type Index = u32;
134

            
135
/// A hash of some data used by the chain.
136
pub type Hash = sp_core::H256;
137

            
138
/// An index to a block.
139
pub type BlockNumber = u32;
140

            
141
/// The address format for describing accounts.
142
pub type Address = AccountId;
143

            
144
/// Block header type as expected by this runtime.
145
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
146

            
147
/// Block type as expected by this runtime.
148
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
149

            
150
/// A Block signed with a Justification
151
pub type SignedBlock = generic::SignedBlock<Block>;
152

            
153
/// BlockId type as expected by this runtime.
154
pub type BlockId = generic::BlockId<Block>;
155

            
156
pub type TxExtension = cumulus_pallet_weight_reclaim::StorageWeightReclaim<
157
    Runtime,
158
    (
159
        frame_system::CheckNonZeroSender<Runtime>,
160
        frame_system::CheckSpecVersion<Runtime>,
161
        frame_system::CheckTxVersion<Runtime>,
162
        frame_system::CheckGenesis<Runtime>,
163
        frame_system::CheckEra<Runtime>,
164
        frame_system::CheckNonce<Runtime>,
165
        frame_system::CheckWeight<Runtime>,
166
        pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
167
    ),
168
>;
169
/// Unchecked extrinsic type as expected by this runtime.
170
pub type UncheckedExtrinsic =
171
    fp_self_contained::UncheckedExtrinsic<Address, RuntimeCall, Signature, TxExtension>;
172
/// Extrinsic type that has already been checked.
173
pub type CheckedExtrinsic =
174
    fp_self_contained::CheckedExtrinsic<AccountId, RuntimeCall, TxExtension, H160>;
175
/// The payload being signed in transactions.
176
pub type SignedPayload = generic::SignedPayload<RuntimeCall, TxExtension>;
177

            
178
/// Executive: handles dispatch to the various modules.
179
pub type Executive = frame_executive::Executive<
180
    Runtime,
181
    Block,
182
    frame_system::ChainContext<Runtime>,
183
    Runtime,
184
    AllPalletsWithSystem,
185
>;
186

            
187
pub mod currency {
188
    use super::Balance;
189

            
190
    pub const MICROUNIT: Balance = 1_000_000_000_000;
191
    pub const MILLIUNIT: Balance = 1_000_000_000_000_000;
192
    pub const UNIT: Balance = 1_000_000_000_000_000_000;
193
    pub const KILOUNIT: Balance = 1_000_000_000_000_000_000_000;
194

            
195
    pub const STORAGE_BYTE_FEE: Balance = 100 * MICROUNIT;
196

            
197
    pub const fn deposit(items: u32, bytes: u32) -> Balance {
198
        items as Balance * 100 * MILLIUNIT + (bytes as Balance) * STORAGE_BYTE_FEE
199
    }
200
}
201

            
202
impl fp_self_contained::SelfContainedCall for RuntimeCall {
203
    type SignedInfo = H160;
204

            
205
    fn is_self_contained(&self) -> bool {
206
        match self {
207
            RuntimeCall::Ethereum(call) => call.is_self_contained(),
208
            _ => false,
209
        }
210
    }
211

            
212
    fn check_self_contained(&self) -> Option<Result<Self::SignedInfo, TransactionValidityError>> {
213
        match self {
214
            RuntimeCall::Ethereum(call) => call.check_self_contained(),
215
            _ => None,
216
        }
217
    }
218

            
219
    fn validate_self_contained(
220
        &self,
221
        info: &Self::SignedInfo,
222
        dispatch_info: &DispatchInfoOf<RuntimeCall>,
223
        len: usize,
224
    ) -> Option<TransactionValidity> {
225
        match self {
226
            RuntimeCall::Ethereum(call) => call.validate_self_contained(info, dispatch_info, len),
227
            _ => None,
228
        }
229
    }
230

            
231
    fn pre_dispatch_self_contained(
232
        &self,
233
        info: &Self::SignedInfo,
234
        dispatch_info: &DispatchInfoOf<RuntimeCall>,
235
        len: usize,
236
    ) -> Option<Result<(), TransactionValidityError>> {
237
        match self {
238
            RuntimeCall::Ethereum(call) => {
239
                call.pre_dispatch_self_contained(info, dispatch_info, len)
240
            }
241
            _ => None,
242
        }
243
    }
244

            
245
    fn apply_self_contained(
246
        self,
247
        info: Self::SignedInfo,
248
    ) -> Option<sp_runtime::DispatchResultWithInfo<PostDispatchInfoOf<Self>>> {
249
        match self {
250
            call @ RuntimeCall::Ethereum(pallet_ethereum::Call::transact { .. }) => {
251
                Some(call.dispatch(RuntimeOrigin::from(
252
                    pallet_ethereum::RawOrigin::EthereumTransaction(info),
253
                )))
254
            }
255
            _ => None,
256
        }
257
    }
258
}
259

            
260
#[derive(Clone)]
261
pub struct TransactionConverter;
262

            
263
impl fp_rpc::ConvertTransaction<UncheckedExtrinsic> for TransactionConverter {
264
    fn convert_transaction(&self, transaction: pallet_ethereum::Transaction) -> UncheckedExtrinsic {
265
        UncheckedExtrinsic::new_bare(
266
            pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
267
        )
268
    }
269
}
270

            
271
impl fp_rpc::ConvertTransaction<opaque::UncheckedExtrinsic> for TransactionConverter {
272
    fn convert_transaction(
273
        &self,
274
        transaction: pallet_ethereum::Transaction,
275
    ) -> opaque::UncheckedExtrinsic {
276
        let extrinsic = UncheckedExtrinsic::new_bare(
277
            pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
278
        );
279
        let encoded = extrinsic.encode();
280
        opaque::UncheckedExtrinsic::decode(&mut &encoded[..])
281
            .expect("Encoded extrinsic is always valid")
282
    }
283
}
284

            
285
/// Handles converting a weight scalar to a fee value, based on the scale and granularity of the
286
/// node's balance type.
287
///
288
/// This should typically create a mapping between the following ranges:
289
///   - `[0, MAXIMUM_BLOCK_WEIGHT]`
290
///   - `[Balance::min, Balance::max]`
291
///
292
/// Yet, it can be used for any other sort of change to weight-fee. Some examples being:
293
///   - Setting it to `0` will essentially disable the weight fee.
294
///   - Setting it to `1` will cause the literal `#[weight = x]` values to be charged.
295
pub struct WeightToFee;
296
impl frame_support::weights::WeightToFee for WeightToFee {
297
    type Balance = Balance;
298

            
299
253
    fn weight_to_fee(weight: &Weight) -> Self::Balance {
300
253
        let time_poly: FeePolynomial<Balance> = RefTimeToFee::polynomial().into();
301
253
        let proof_poly: FeePolynomial<Balance> = ProofSizeToFee::polynomial().into();
302

            
303
        // Take the maximum instead of the sum to charge by the more scarce resource.
304
253
        time_poly
305
253
            .eval(weight.ref_time())
306
253
            .max(proof_poly.eval(weight.proof_size()))
307
253
    }
308
}
309
pub struct RefTimeToFee;
310
impl WeightToFeePolynomial for RefTimeToFee {
311
    type Balance = Balance;
312
253
    fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {
313
        // in Rococo, extrinsic base weight (smallest non-zero weight) is mapped to 1 MILLIUNIT:
314
        // in our template, we map to 1/10 of that, or 1/10 MILLIUNIT
315
        // for benchmarks, we simply put a value to get a coefficeint of 1
316
        #[cfg(not(feature = "runtime-benchmarks"))]
317
253
        let p = currency::MILLIUNIT / 10;
318
        #[cfg(feature = "runtime-benchmarks")]
319
        let p = 100 * Balance::from(ExtrinsicBaseWeight::get().ref_time());
320

            
321
253
        let q = 100 * Balance::from(ExtrinsicBaseWeight::get().ref_time());
322
253
        smallvec![WeightToFeeCoefficient {
323
            degree: 1,
324
            negative: false,
325
            coeff_frac: Perbill::from_rational(p % q, q),
326
            coeff_integer: p / q,
327
        }]
328
253
    }
329
}
330

            
331
/// Maps the proof size component of `Weight` to a fee.
332
pub struct ProofSizeToFee;
333
impl WeightToFeePolynomial for ProofSizeToFee {
334
    type Balance = Balance;
335
253
    fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {
336
        // Map 10kb proof to 1 CENT.
337
        #[cfg(not(feature = "runtime-benchmarks"))]
338
253
        let p = currency::MILLIUNIT / 10;
339
        #[cfg(feature = "runtime-benchmarks")]
340
        let p = 100 * Balance::from(ExtrinsicBaseWeight::get().proof_size());
341
253
        let q = 10_000;
342

            
343
253
        smallvec![WeightToFeeCoefficient {
344
            degree: 1,
345
            negative: false,
346
            coeff_frac: Perbill::from_rational(p % q, q),
347
            coeff_integer: p / q,
348
        }]
349
253
    }
350
}
351

            
352
parameter_types! {
353
        /// Network and location for the Ethereum chain. On Starlight, the Ethereum chain bridged
354
        /// to is the Ethereum mainnet, with chain ID 1.
355
        /// <https://chainlist.org/chain/1>
356
        /// <https://ethereum.org/en/developers/docs/apis/json-rpc/#net_version>
357
        pub EthereumNetwork: NetworkId = {
358
            use crate::dynamic_params::xcm_config::RelayNetwork;
359
            use crate::dynamic_params::EthereumNetworkChainId;
360

            
361
            // derive chain_id from RelayNetwork
362
            let chain_id = EthereumNetworkChainId::from_relay_network(&RelayNetwork::get())
363
                .expect("Unsupported relay network")
364
                .as_u64();
365

            
366
            NetworkId::Ethereum { chain_id }
367
        };
368
        pub EthereumLocation: Location = Location::new(2, EthereumNetwork::get());
369
}
370

            
371
/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
372
/// the specifics of the runtime. They can then be made to be agnostic over specific formats
373
/// of data like extrinsics, allowing for them to continue syncing the network through upgrades
374
/// to even the core data structures.
375
pub mod opaque {
376
    use {
377
        super::*,
378
        sp_runtime::{generic, traits::BlakeTwo256},
379
    };
380

            
381
    pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic;
382
    /// Opaque block header type.
383
    pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
384
    /// Opaque block type.
385
    pub type Block = generic::Block<Header, UncheckedExtrinsic>;
386
    /// Opaque block identifier type.
387
    pub type BlockId = generic::BlockId<Block>;
388
}
389

            
390
mod impl_on_charge_evm_transaction;
391

            
392
impl_opaque_keys! {
393
    pub struct SessionKeys { }
394
}
395

            
396
#[sp_version::runtime_version]
397
pub const VERSION: RuntimeVersion = RuntimeVersion {
398
    spec_name: Cow::Borrowed("frontier-template"),
399
    impl_name: Cow::Borrowed("frontier-template"),
400
    authoring_version: 1,
401
    spec_version: 1700,
402
    impl_version: 0,
403
    apis: RUNTIME_API_VERSIONS,
404
    transaction_version: 1,
405
    system_version: 1,
406
};
407

            
408
/// This determines the average expected block time that we are targeting.
409
/// Blocks will be produced at a minimum duration defined by `SLOT_DURATION`.
410
/// `SLOT_DURATION` is picked up by `pallet_timestamp` which is in turn picked
411
/// up by `pallet_aura` to implement `fn slot_duration()`.
412
///
413
/// Change this to adjust the block time.
414
pub const MILLISECS_PER_BLOCK: u64 = 6000;
415

            
416
// NOTE: Currently it is not possible to change the slot duration after the chain has started.
417
//       Attempting to do so will brick block production.
418
pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
419

            
420
// Time is measured by number of blocks.
421
pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
422
pub const HOURS: BlockNumber = MINUTES * 60;
423
pub const DAYS: BlockNumber = HOURS * 24;
424

            
425
pub const EXISTENTIAL_DEPOSIT: Balance = 0;
426

            
427
/// We assume that ~5% of the block weight is consumed by `on_initialize` handlers. This is
428
/// used to limit the maximal weight of a single extrinsic.
429
const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(5);
430

            
431
/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used by
432
/// `Operational` extrinsics.
433
const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
434

            
435
/// We allow for 2 seconds of compute with a 6 second average block time
436
const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts(
437
    WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2),
438
    cumulus_primitives_core::relay_chain::MAX_POV_SIZE as u64,
439
);
440

            
441
/// We allow for 2 seconds of compute with a 6 second average block time
442
pub const WEIGHT_MILLISECS_PER_BLOCK: u64 = 2000;
443

            
444
/// The version information used to identify this runtime when compiled natively.
445
#[cfg(feature = "std")]
446
pub fn native_version() -> NativeVersion {
447
    NativeVersion {
448
        runtime_version: VERSION,
449
        can_author_with: Default::default(),
450
    }
451
}
452

            
453
parameter_types! {
454
    pub const Version: RuntimeVersion = VERSION;
455

            
456
    // This part is copied from Substrate's `bin/node/runtime/src/lib.rs`.
457
    //  The `RuntimeBlockLength` and `RuntimeBlockWeights` exist here because the
458
    // `DeletionWeightLimit` and `DeletionQueueDepth` depend on those to parameterize
459
    // the lazy contract deletion.
460
    pub RuntimeBlockLength: BlockLength =
461
        BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO);
462
    pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder()
463
        .base_block(BlockExecutionWeight::get())
464
38763
        .for_class(DispatchClass::all(), |weights| {
465
38763
            weights.base_extrinsic = ExtrinsicBaseWeight::get();
466
38763
        })
467
12921
        .for_class(DispatchClass::Normal, |weights| {
468
12921
            weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT);
469
12921
        })
470
12921
        .for_class(DispatchClass::Operational, |weights| {
471
12921
            weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT);
472
            // Operational transactions have some extra reserved space, so that they
473
            // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`.
474
12921
            weights.reserved = Some(
475
12921
                MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT
476
12921
            );
477
12921
        })
478
        .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO)
479
        .build_or_panic();
480
    pub const SS58Prefix: u16 = 42;
481
}
482

            
483
// Configure FRAME pallets to include in runtime.
484
impl frame_system::Config for Runtime {
485
    /// The identifier used to distinguish between accounts.
486
    type AccountId = AccountId;
487
    /// The aggregated dispatch type that is available for extrinsics.
488
    type RuntimeCall = RuntimeCall;
489
    /// The lookup mechanism to get account ID from whatever is passed in dispatchers.
490
    type Lookup = IdentityLookup<AccountId>;
491
    /// The index type for storing how many extrinsics an account has signed.
492
    type Nonce = Index;
493
    /// The index type for blocks.
494
    type Block = Block;
495
    /// The type for hashing blocks and tries.
496
    type Hash = Hash;
497
    /// The hashing algorithm used.
498
    type Hashing = BlakeTwo256;
499
    /// The ubiquitous event type.
500
    type RuntimeEvent = RuntimeEvent;
501
    /// The ubiquitous origin type.
502
    type RuntimeOrigin = RuntimeOrigin;
503
    /// Maximum number of block number to block hash mappings to keep (oldest pruned first).
504
    type BlockHashCount = BlockHashCount;
505
    /// Runtime version.
506
    type Version = Version;
507
    /// Converts a module to an index of this module in the runtime.
508
    type PalletInfo = PalletInfo;
509
    /// The data to be stored in an account.
510
    type AccountData = pallet_balances::AccountData<Balance>;
511
    /// What to do if a new account is created.
512
    type OnNewAccount = ();
513
    /// What to do if an account is fully reaped from the system.
514
    type OnKilledAccount = ();
515
    /// The weight of database operations that the runtime can invoke.
516
    type DbWeight = RocksDbWeight;
517
    /// The basic call filter to use in dispatchable.
518
    type BaseCallFilter = InsideBoth<MaintenanceMode, TxPause>;
519
    /// Weight information for the extrinsics of this pallet.
520
    type SystemWeightInfo = weights::frame_system::SubstrateWeight<Runtime>;
521
    /// Block & extrinsics weights: base values and limits.
522
    type BlockWeights = RuntimeBlockWeights;
523
    /// The maximum length of a block (in bytes).
524
    type BlockLength = RuntimeBlockLength;
525
    /// This is used as an identifier of the chain. 42 is the generic substrate prefix.
526
    type SS58Prefix = SS58Prefix;
527
    /// The action to take on a Runtime Upgrade
528
    type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode<Self>;
529
    type MaxConsumers = frame_support::traits::ConstU32<16>;
530
    type RuntimeTask = RuntimeTask;
531
    type SingleBlockMigrations = ();
532
    type MultiBlockMigrator = MultiBlockMigrations;
533
    type PreInherents = ();
534
    type PostInherents = ();
535
    type PostTransactions = ();
536
    type ExtensionsWeightInfo = weights::frame_system_extensions::SubstrateWeight<Runtime>;
537
}
538

            
539
parameter_types! {
540
    pub const TransactionByteFee: Balance = 1;
541
}
542

            
543
impl pallet_transaction_payment::Config for Runtime {
544
    type RuntimeEvent = RuntimeEvent;
545
    // This will burn the fees
546
    type OnChargeTransaction = FungibleAdapter<Balances, ()>;
547
    type OperationalFeeMultiplier = ConstU8<5>;
548
    type WeightToFee = WeightToFee;
549
    type LengthToFee = ConstantMultiplier<Balance, TransactionByteFee>;
550
    type FeeMultiplierUpdate = SlowAdjustingFeeUpdate<Self>;
551
    type WeightInfo = weights::pallet_transaction_payment::SubstrateWeight<Runtime>;
552
}
553

            
554
parameter_types! {
555
    pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT;
556
}
557

            
558
impl pallet_balances::Config for Runtime {
559
    type MaxLocks = ConstU32<50>;
560
    /// The type for recording an account's balance.
561
    type Balance = Balance;
562
    /// The ubiquitous event type.
563
    type RuntimeEvent = RuntimeEvent;
564
    type DustRemoval = ();
565
    type ExistentialDeposit = ExistentialDeposit;
566
    type AccountStore = System;
567
    type MaxReserves = ConstU32<50>;
568
    type ReserveIdentifier = [u8; 8];
569
    type FreezeIdentifier = RuntimeFreezeReason;
570
    type MaxFreezes = ConstU32<0>;
571
    type RuntimeHoldReason = RuntimeHoldReason;
572
    type RuntimeFreezeReason = RuntimeFreezeReason;
573
    type DoneSlashHandler = ();
574
    type WeightInfo = weights::pallet_balances::SubstrateWeight<Runtime>;
575
}
576

            
577
parameter_types! {
578
    pub ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4;
579
    pub ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT / 4;
580
    pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent;
581
}
582

            
583
pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000;
584
pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 3;
585
pub const BLOCK_PROCESSING_VELOCITY: u32 = 1;
586

            
587
type ConsensusHook = pallet_async_backing::consensus_hook::FixedVelocityConsensusHook<
588
    Runtime,
589
    BLOCK_PROCESSING_VELOCITY,
590
    UNINCLUDED_SEGMENT_CAPACITY,
591
>;
592

            
593
impl cumulus_pallet_parachain_system::Config for Runtime {
594
    type WeightInfo = weights::cumulus_pallet_parachain_system::SubstrateWeight<Runtime>;
595
    type RuntimeEvent = RuntimeEvent;
596
    type OnSystemEvent = ();
597
    type SelfParaId = parachain_info::Pallet<Runtime>;
598
    type OutboundXcmpMessageSource = XcmpQueue;
599
    type DmpQueue = frame_support::traits::EnqueueWithOrigin<MessageQueue, RelayOrigin>;
600
    type ReservedDmpWeight = ReservedDmpWeight;
601
    type XcmpMessageHandler = XcmpQueue;
602
    type ReservedXcmpWeight = ReservedXcmpWeight;
603
    type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases;
604
    type ConsensusHook = ConsensusHook;
605
    type SelectCore = cumulus_pallet_parachain_system::DefaultCoreSelector<Runtime>;
606
    type RelayParentOffset = ConstU32<0>;
607
}
608

            
609
pub struct ParaSlotProvider;
610
impl Get<(Slot, SlotDuration)> for ParaSlotProvider {
611
1408
    fn get() -> (Slot, SlotDuration) {
612
1408
        let slot = u64::from(<Runtime as pallet_author_inherent::Config>::SlotBeacon::slot());
613
1408
        (Slot::from(slot), SlotDuration::from_millis(SLOT_DURATION))
614
1408
    }
615
}
616

            
617
parameter_types! {
618
    pub const ExpectedBlockTime: u64 = MILLISECS_PER_BLOCK;
619
}
620

            
621
impl pallet_async_backing::Config for Runtime {
622
    type AllowMultipleBlocksPerSlot = ConstBool<true>;
623
    type GetAndVerifySlot =
624
        pallet_async_backing::ParaSlot<RELAY_CHAIN_SLOT_DURATION_MILLIS, ParaSlotProvider>;
625
    type ExpectedBlockTime = ExpectedBlockTime;
626
}
627

            
628
impl parachain_info::Config for Runtime {}
629

            
630
parameter_types! {
631
    pub const Period: u32 = 6 * HOURS;
632
    pub const Offset: u32 = 0;
633
}
634

            
635
impl pallet_sudo::Config for Runtime {
636
    type RuntimeCall = RuntimeCall;
637
    type RuntimeEvent = RuntimeEvent;
638
    type WeightInfo = weights::pallet_sudo::SubstrateWeight<Runtime>;
639
}
640

            
641
impl pallet_utility::Config for Runtime {
642
    type RuntimeEvent = RuntimeEvent;
643
    type RuntimeCall = RuntimeCall;
644
    type PalletsOrigin = OriginCaller;
645
    type WeightInfo = weights::pallet_utility::SubstrateWeight<Runtime>;
646
}
647

            
648
/// The type used to represent the kinds of proxying allowed.
649
#[derive(
650
    Copy,
651
    Clone,
652
    Eq,
653
    PartialEq,
654
    Ord,
655
    PartialOrd,
656
    Encode,
657
    Decode,
658
    DecodeWithMemTracking,
659
    Debug,
660
    MaxEncodedLen,
661
    TypeInfo,
662
)]
663
#[allow(clippy::unnecessary_cast)]
664
pub enum ProxyType {
665
    /// All calls can be proxied. This is the trivial/most permissive filter.
666
    Any = 0,
667
    /// Only extrinsics that do not transfer funds.
668
    NonTransfer = 1,
669
    /// Only extrinsics related to governance (democracy and collectives).
670
    Governance = 2,
671
    /// Allow to veto an announced proxy call.
672
    CancelProxy = 3,
673
    /// Allow extrinsic related to Balances.
674
    Balances = 4,
675
}
676

            
677
impl Default for ProxyType {
678
    fn default() -> Self {
679
        Self::Any
680
    }
681
}
682

            
683
// Be careful: Each time this filter is modified, the substrate filter must also be modified
684
// consistently.
685
impl pallet_evm_precompile_proxy::EvmProxyCallFilter for ProxyType {
686
    fn is_evm_proxy_call_allowed(
687
        &self,
688
        call: &pallet_evm_precompile_proxy::EvmSubCall,
689
        recipient_has_code: bool,
690
        gas: u64,
691
    ) -> precompile_utils::EvmResult<bool> {
692
        Ok(match self {
693
            ProxyType::Any => true,
694
            ProxyType::NonTransfer => false,
695
            ProxyType::Governance => false,
696
            // The proxy precompile does not contain method cancel_proxy
697
            ProxyType::CancelProxy => false,
698
            ProxyType::Balances => {
699
                // Allow only "simple" accounts as recipient (no code nor precompile).
700
                // Note: Checking the presence of the code is not enough because some precompiles
701
                // have no code.
702
                !recipient_has_code
703
                    && !precompile_utils::precompile_set::is_precompile_or_fail::<Runtime>(
704
                        call.to.0, gas,
705
                    )?
706
            }
707
        })
708
    }
709
}
710

            
711
impl InstanceFilter<RuntimeCall> for ProxyType {
712
    fn filter(&self, c: &RuntimeCall) -> bool {
713
        // Since proxy filters are respected in all dispatches of the Utility
714
        // pallet, it should never need to be filtered by any proxy.
715
        if let RuntimeCall::Utility(..) = c {
716
            return true;
717
        }
718

            
719
        match self {
720
            ProxyType::Any => true,
721
            ProxyType::NonTransfer => {
722
                matches!(
723
                    c,
724
                    RuntimeCall::System(..)
725
                        | RuntimeCall::ParachainSystem(..)
726
                        | RuntimeCall::Timestamp(..)
727
                        | RuntimeCall::Proxy(..)
728
                )
729
            }
730
            // We don't have governance yet
731
            ProxyType::Governance => false,
732
            ProxyType::CancelProxy => matches!(
733
                c,
734
                RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. })
735
            ),
736
            ProxyType::Balances => {
737
                matches!(c, RuntimeCall::Balances(..))
738
            }
739
        }
740
    }
741

            
742
    fn is_superset(&self, o: &Self) -> bool {
743
        match (self, o) {
744
            (x, y) if x == y => true,
745
            (ProxyType::Any, _) => true,
746
            (_, ProxyType::Any) => false,
747
            _ => false,
748
        }
749
    }
750
}
751

            
752
impl pallet_proxy::Config for Runtime {
753
    type RuntimeEvent = RuntimeEvent;
754
    type RuntimeCall = RuntimeCall;
755
    type Currency = Balances;
756
    type ProxyType = ProxyType;
757
    // One storage item; key size 32, value size 8
758
    type ProxyDepositBase = ConstU128<{ currency::deposit(1, 8) }>;
759
    // Additional storage item size of 21 bytes (20 bytes AccountId + 1 byte sizeof(ProxyType)).
760
    type ProxyDepositFactor = ConstU128<{ currency::deposit(0, 21) }>;
761
    type MaxProxies = ConstU32<32>;
762
    type MaxPending = ConstU32<32>;
763
    type CallHasher = BlakeTwo256;
764
    type AnnouncementDepositBase = ConstU128<{ currency::deposit(1, 8) }>;
765
    // Additional storage item size of 56 bytes:
766
    // - 20 bytes AccountId
767
    // - 32 bytes Hasher (Blake2256)
768
    // - 4 bytes BlockNumber (u32)
769
    type AnnouncementDepositFactor = ConstU128<{ currency::deposit(0, 56) }>;
770
    type WeightInfo = weights::pallet_proxy::SubstrateWeight<Runtime>;
771
    type BlockNumberProvider = System;
772
}
773

            
774
pub struct XcmExecutionManager;
775
impl xcm_primitives::PauseXcmExecution for XcmExecutionManager {
776
    fn suspend_xcm_execution() -> DispatchResult {
777
        XcmpQueue::suspend_xcm_execution(RuntimeOrigin::root())
778
    }
779
    fn resume_xcm_execution() -> DispatchResult {
780
        XcmpQueue::resume_xcm_execution(RuntimeOrigin::root())
781
    }
782
}
783

            
784
impl cumulus_pallet_weight_reclaim::Config for Runtime {
785
    type WeightInfo = weights::cumulus_pallet_weight_reclaim::SubstrateWeight<Runtime>;
786
}
787

            
788
impl pallet_migrations::Config for Runtime {
789
    type MigrationsList = (migrations::TemplateMigrations<Runtime, XcmpQueue, PolkadotXcm>,);
790
    type XcmExecutionManager = XcmExecutionManager;
791
}
792

            
793
parameter_types! {
794
    pub MbmServiceWeight: Weight = Perbill::from_percent(80) * RuntimeBlockWeights::get().max_block;
795
}
796

            
797
impl pallet_multiblock_migrations::Config for Runtime {
798
    type RuntimeEvent = RuntimeEvent;
799
    #[cfg(not(feature = "runtime-benchmarks"))]
800
    type Migrations = ();
801
    // Benchmarks need mocked migrations to guarantee that they succeed.
802
    #[cfg(feature = "runtime-benchmarks")]
803
    type Migrations = pallet_multiblock_migrations::mock_helpers::MockedMigrations;
804
    type CursorMaxLen = ConstU32<65_536>;
805
    type IdentifierMaxLen = ConstU32<256>;
806
    type MigrationStatusHandler = ();
807
    type FailedMigrationHandler = MaintenanceMode;
808
    type MaxServiceWeight = MbmServiceWeight;
809
    type WeightInfo = weights::pallet_multiblock_migrations::SubstrateWeight<Runtime>;
810
}
811

            
812
/// Maintenance mode Call filter
813
pub struct MaintenanceFilter;
814
impl Contains<RuntimeCall> for MaintenanceFilter {
815
    fn contains(c: &RuntimeCall) -> bool {
816
        !matches!(
817
            c,
818
            RuntimeCall::Balances(_)
819
                | RuntimeCall::Ethereum(_)
820
                | RuntimeCall::EVM(_)
821
                | RuntimeCall::PolkadotXcm(_)
822
        )
823
    }
824
}
825

            
826
/// Normal Call Filter
827
/// We dont allow to create nor mint assets, this for now is disabled
828
/// We only allow transfers. For now creation of assets will go through
829
/// asset-manager, while minting/burning only happens through xcm messages
830
/// This can change in the future
831
pub struct NormalFilter;
832
impl Contains<RuntimeCall> for NormalFilter {
833
2816
    fn contains(c: &RuntimeCall) -> bool {
834
2816
        !matches!(
835
2816
            c,
836
            // Filtering the EVM prevents possible re-entrancy from the precompiles which could
837
            // lead to unexpected scenarios.
838
            // See https://github.com/PureStake/sr-moonbeam/issues/30
839
            // Note: It is also assumed that EVM calls are only allowed through `Origin::Root` so
840
            // this can be seen as an additional security
841
            RuntimeCall::EVM(_)
842
        )
843
2816
    }
844
}
845

            
846
impl pallet_maintenance_mode::Config for Runtime {
847
    type NormalCallFilter = NormalFilter;
848
    type MaintenanceCallFilter = InsideBoth<MaintenanceFilter, NormalFilter>;
849
    type MaintenanceOrigin = EnsureRoot<AccountId>;
850
    type XcmExecutionManager = XcmExecutionManager;
851
}
852

            
853
#[dynamic_params(RuntimeParameters, pallet_parameters::Parameters::<Runtime>)]
854
pub mod dynamic_params {
855
    use super::*;
856

            
857
    #[dynamic_pallet_params]
858
    #[codec(index = 3)]
859
    pub mod contract_deploy_filter {
860
        #[codec(index = 0)]
861
        pub static AllowedAddressesToCreate: DeployFilter = DeployFilter::All;
862
        #[codec(index = 1)]
863
        pub static AllowedAddressesToCreateInner: DeployFilter = DeployFilter::All;
864
    }
865

            
866
    /// The Dancelight genesis hash used as the default relay network identifier.
867
    pub const DANCELIGHT_GENESIS_HASH: [u8; 32] =
868
        hex_literal::hex!["983a1a72503d6cc3636776747ec627172b51272bf45e50a355348facb67a820a"];
869

            
870
    /// The Starlight genesis hash.
871
    pub const TANSSI_GENESIS_HASH: [u8; 32] =
872
        hex_literal::hex!["dd6d086f75ec041b66e20c4186d327b23c8af244c534a2418de6574e8c041a60"];
873

            
874
    pub enum EthereumNetworkChainId {
875
        EthereumTestnet,
876
        EthereumMainnet,
877
    }
878

            
879
    pub const SEPOLIA_ETH_TESTNET_CHAIN_ID: u64 = 11155111;
880
    pub const ETH_MAINNET_CHAIN_ID: u64 = 1;
881

            
882
    impl EthereumNetworkChainId {
883
420
        pub fn as_u64(&self) -> u64 {
884
420
            match self {
885
144
                EthereumNetworkChainId::EthereumTestnet => SEPOLIA_ETH_TESTNET_CHAIN_ID,
886
276
                EthereumNetworkChainId::EthereumMainnet => ETH_MAINNET_CHAIN_ID,
887
            }
888
420
        }
889

            
890
        /// Derive chain_id from relay network
891
420
        pub fn from_relay_network(network: &NetworkId) -> Option<Self> {
892
276
            match network {
893
420
                NetworkId::ByGenesis(hash) if hash == &DANCELIGHT_GENESIS_HASH => {
894
144
                    Some(Self::EthereumTestnet)
895
                }
896
276
                NetworkId::ByGenesis(hash) if hash == &TANSSI_GENESIS_HASH => {
897
276
                    Some(Self::EthereumMainnet)
898
                }
899
                _ => None,
900
            }
901
420
        }
902
    }
903

            
904
    #[dynamic_pallet_params]
905
    #[codec(index = 4)]
906
    pub mod xcm_config {
907
        use super::*;
908

            
909
        /// The relay network identifier for this container chain.
910
        /// Using Dancelight genesis hash as default.
911
        #[codec(index = 0)]
912
        pub static RelayNetwork: xcm::latest::NetworkId =
913
            xcm::latest::NetworkId::ByGenesis(DANCELIGHT_GENESIS_HASH);
914
    }
915
}
916

            
917
impl pallet_parameters::Config for Runtime {
918
    type AdminOrigin = EnsureRoot<AccountId>;
919
    type RuntimeEvent = RuntimeEvent;
920
    type RuntimeParameters = RuntimeParameters;
921
    type WeightInfo = weights::pallet_parameters::SubstrateWeight<Runtime>;
922
}
923

            
924
#[cfg(feature = "runtime-benchmarks")]
925
impl Default for RuntimeParameters {
926
    fn default() -> Self {
927
        RuntimeParameters::ContractDeployFilter(
928
            dynamic_params::contract_deploy_filter::Parameters::AllowedAddressesToCreate(
929
                dynamic_params::contract_deploy_filter::AllowedAddressesToCreate,
930
                Some(DeployFilter::All),
931
            ),
932
        )
933
    }
934
}
935

            
936
#[derive(
937
    Clone, PartialEq, Encode, Decode, DecodeWithMemTracking, TypeInfo, Eq, MaxEncodedLen, Debug,
938
)]
939
pub enum DeployFilter {
940
    All,
941
    Whitelisted(BoundedVec<H160, ConstU32<100>>),
942
}
943

            
944
pub struct AddressFilter<Runtime, AddressList>(core::marker::PhantomData<(Runtime, AddressList)>);
945
impl<Runtime, AddressList> EnsureCreateOrigin<Runtime> for AddressFilter<Runtime, AddressList>
946
where
947
    Runtime: pallet_evm::Config,
948
    AddressList: Get<DeployFilter>,
949
{
950
    fn check_create_origin(address: &H160) -> Result<(), pallet_evm::Error<Runtime>> {
951
        let deploy_filter: DeployFilter = AddressList::get();
952

            
953
        match deploy_filter {
954
            DeployFilter::All => Ok(()),
955
            DeployFilter::Whitelisted(addresses_vec) => {
956
                if !addresses_vec.contains(address) {
957
                    Err(pallet_evm::Error::<Runtime>::CreateOriginNotAllowed)
958
                } else {
959
                    Ok(())
960
                }
961
            }
962
        }
963
    }
964
}
965

            
966
impl pallet_evm_chain_id::Config for Runtime {}
967

            
968
pub struct FindAuthorAdapter;
969
impl FindAuthor<H160> for FindAuthorAdapter {
970
1741
    fn find_author<'a, I>(digests: I) -> Option<H160>
971
1741
    where
972
1741
        I: 'a + IntoIterator<Item = (sp_runtime::ConsensusEngineId, &'a [u8])>,
973
    {
974
1741
        if let Some(author) = AuthorInherent::find_author(digests) {
975
            return Some(H160::from_slice(&author.encode()[0..20]));
976
1741
        }
977
1741
        None
978
1741
    }
979
}
980

            
981
/// Current approximation of the gas/s consumption considering
982
/// EVM execution over compiled WASM (on 4.4Ghz CPU).
983
/// Given the 1000ms Weight, from which 75% only are used for transactions,
984
/// the total EVM execution gas limit is: GAS_PER_SECOND * 1 * 0.75 ~= 30_000_000.
985
pub const GAS_PER_SECOND: u64 = 40_000_000;
986

            
987
/// Approximate ratio of the amount of Weight per Gas.
988
/// u64 works for approximations because Weight is a very small unit compared to gas.
989
pub const WEIGHT_PER_GAS: u64 = WEIGHT_REF_TIME_PER_SECOND / GAS_PER_SECOND;
990

            
991
parameter_types! {
992
    pub BlockGasLimit: U256
993
        = U256::from(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT.ref_time() / WEIGHT_PER_GAS);
994
    pub PrecompilesValue: TemplatePrecompiles<Runtime> = TemplatePrecompiles::<_>::new();
995
    pub WeightPerGas: Weight = Weight::from_parts(WEIGHT_PER_GAS, 0);
996
    pub SuicideQuickClearLimit: u32 = 0;
997
    pub GasLimitPovSizeRatio: u32 = 16;
998
    /// Hardcoding the value, since it is computed on block execution. Check calculations in the tests
999
    pub GasLimitStorageGrowthRatio: u64 = 1464;
}
impl_on_charge_evm_transaction!();
impl pallet_evm::Config for Runtime {
    type AccountProvider = FrameSystemAccountProvider<Runtime>;
    type FeeCalculator = BaseFee;
    type GasWeightMapping = pallet_evm::FixedGasWeightMapping<Self>;
    type WeightPerGas = WeightPerGas;
    type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping<Self>;
    type CallOrigin = EnsureAddressRoot<AccountId>;
    type WithdrawOrigin = EnsureAddressNever<AccountId>;
    type AddressMapping = IdentityAddressMapping;
    type CreateOriginFilter =
        AddressFilter<Runtime, dynamic_params::contract_deploy_filter::AllowedAddressesToCreate>;
    type CreateInnerOriginFilter = AddressFilter<
        Runtime,
        dynamic_params::contract_deploy_filter::AllowedAddressesToCreateInner,
    >;
    type Currency = Balances;
    type PrecompilesType = TemplatePrecompiles<Self>;
    type PrecompilesValue = PrecompilesValue;
    type ChainId = EVMChainId;
    type BlockGasLimit = BlockGasLimit;
    type Runner = pallet_evm::runner::stack::Runner<Self>;
    type OnChargeTransaction = OnChargeEVMTransaction<()>;
    type OnCreate = ();
    type FindAuthor = FindAuthorAdapter;
    type GasLimitPovSizeRatio = GasLimitPovSizeRatio;
    type GasLimitStorageGrowthRatio = GasLimitStorageGrowthRatio;
    type Timestamp = Timestamp;
    type WeightInfo = ();
}
parameter_types! {
    pub const PostBlockAndTxnHashes: PostLogContent = PostLogContent::BlockAndTxnHashes;
}
impl pallet_ethereum::Config for Runtime {
    type StateRoot = pallet_ethereum::IntermediateStateRoot<Self::Version>;
    type PostLogContent = PostBlockAndTxnHashes;
    type ExtraDataLength = ConstU32<30>;
}
parameter_types! {
    pub BoundDivision: U256 = U256::from(1024);
}
parameter_types! {
    pub DefaultBaseFeePerGas: U256 = U256::from(2_000_000_000);
    pub DefaultElasticity: Permill = Permill::from_parts(125_000);
}
pub struct BaseFeeThreshold;
impl pallet_base_fee::BaseFeeThreshold for BaseFeeThreshold {
1408
    fn lower() -> Permill {
1408
        Permill::zero()
1408
    }
2816
    fn ideal() -> Permill {
2816
        Permill::from_parts(500_000)
2816
    }
1408
    fn upper() -> Permill {
1408
        Permill::from_parts(1_000_000)
1408
    }
}
impl pallet_base_fee::Config for Runtime {
    type Threshold = BaseFeeThreshold;
    type DefaultBaseFeePerGas = DefaultBaseFeePerGas;
    type DefaultElasticity = DefaultElasticity;
}
impl pallet_root_testing::Config for Runtime {
    type RuntimeEvent = RuntimeEvent;
}
impl pallet_tx_pause::Config for Runtime {
    type RuntimeEvent = RuntimeEvent;
    type RuntimeCall = RuntimeCall;
    type PauseOrigin = EnsureRoot<AccountId>;
    type UnpauseOrigin = EnsureRoot<AccountId>;
    type WhitelistedCalls = ();
    type MaxNameLen = ConstU32<256>;
    type WeightInfo = weights::pallet_tx_pause::SubstrateWeight<Runtime>;
}
impl dp_impl_tanssi_pallets_config::Config for Runtime {
    const SLOT_DURATION: u64 = SLOT_DURATION;
    type TimestampWeights = weights::pallet_timestamp::SubstrateWeight<Runtime>;
    type AuthorInherentWeights = weights::pallet_author_inherent::SubstrateWeight<Runtime>;
    type AuthoritiesNotingWeights = weights::pallet_cc_authorities_noting::SubstrateWeight<Runtime>;
}
parameter_types! {
    // One storage item; key size 32 + 20; value is size 4+4+16+20. Total = 1 * (52 + 44)
    pub const DepositBase: Balance = currency::deposit(1, 96);
    // Additional storage item size of 20 bytes.
    pub const DepositFactor: Balance = currency::deposit(0, 20);
    pub const MaxSignatories: u32 = 100;
}
impl pallet_multisig::Config for Runtime {
    type RuntimeEvent = RuntimeEvent;
    type RuntimeCall = RuntimeCall;
    type Currency = Balances;
    type DepositBase = DepositBase;
    type DepositFactor = DepositFactor;
    type MaxSignatories = MaxSignatories;
    type WeightInfo = weights::pallet_multisig::SubstrateWeight<Runtime>;
    type BlockNumberProvider = System;
}
impl_tanssi_pallets_config!(Runtime);
// Create the runtime by composing the FRAME pallets that were previously configured.
construct_runtime!(
    pub enum Runtime
    {
        // System support stuff.
        System: frame_system = 0,
        ParachainSystem: cumulus_pallet_parachain_system = 1,
        Timestamp: pallet_timestamp = 2,
        ParachainInfo: parachain_info = 3,
        Sudo: pallet_sudo = 4,
        Utility: pallet_utility = 5,
        Proxy: pallet_proxy = 6,
        Migrations: pallet_migrations = 7,
        MultiBlockMigrations: pallet_multiblock_migrations = 121,
        MaintenanceMode: pallet_maintenance_mode = 8,
        TxPause: pallet_tx_pause = 9,
        // Monetary stuff.
        Balances: pallet_balances = 10,
        // Other utilities
        Multisig: pallet_multisig = 16,
        Parameters: pallet_parameters = 17,
        // ContainerChain
        AuthoritiesNoting: pallet_cc_authorities_noting = 50,
        AuthorInherent: pallet_author_inherent = 51,
        // Frontier
        Ethereum: pallet_ethereum = 60,
        EVM: pallet_evm = 61,
        EVMChainId: pallet_evm_chain_id = 62,
        BaseFee: pallet_base_fee = 64,
        TransactionPayment: pallet_transaction_payment = 66,
        // XCM
        XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Storage, Event<T>} = 70,
        CumulusXcm: cumulus_pallet_xcm::{Pallet, Event<T>, Origin} = 71,
        PolkadotXcm: pallet_xcm::{Pallet, Call, Storage, Event<T>, Origin, Config<T>} = 73,
        MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event<T>} = 74,
        ForeignAssets: pallet_assets::<Instance1>::{Pallet, Call, Storage, Event<T>} = 75,
        ForeignAssetsCreator: pallet_foreign_asset_creator::{Pallet, Call, Storage, Event<T>} = 76,
        AssetRate: pallet_asset_rate::{Pallet, Call, Storage, Event<T>} = 77,
        XcmExecutorUtils: pallet_xcm_executor_utils::{Pallet, Call, Storage, Event<T>} = 78,
        WeightReclaim: cumulus_pallet_weight_reclaim = 80,
        RootTesting: pallet_root_testing = 100,
        AsyncBacking: pallet_async_backing::{Pallet, Storage} = 110,
    }
);
#[cfg(feature = "runtime-benchmarks")]
mod benches {
    frame_benchmarking::define_benchmarks!(
        [frame_system, frame_system_benchmarking::Pallet::<Runtime>]
        [frame_system_extensions, frame_system_benchmarking::extensions::Pallet::<Runtime>]
        [cumulus_pallet_parachain_system, ParachainSystem]
        [pallet_timestamp, Timestamp]
        [pallet_sudo, Sudo]
        [pallet_utility, Utility]
        [pallet_proxy, Proxy]
        [pallet_transaction_payment, TransactionPayment]
        [pallet_tx_pause, TxPause]
        [pallet_balances, Balances]
        [pallet_multiblock_migrations, MultiBlockMigrations]
        [pallet_multisig, Multisig]
        [pallet_parameters, Parameters]
        [pallet_cc_authorities_noting, AuthoritiesNoting]
        [pallet_author_inherent, AuthorInherent]
        [cumulus_pallet_xcmp_queue, XcmpQueue]
        [pallet_xcm, PalletXcmExtrinsicsBenchmark::<Runtime>]
        [pallet_xcm_benchmarks::generic, pallet_xcm_benchmarks::generic::Pallet::<Runtime>]
        [pallet_message_queue, MessageQueue]
        [pallet_assets, ForeignAssets]
        [pallet_foreign_asset_creator, ForeignAssetsCreator]
        [pallet_asset_rate, AssetRate]
        [pallet_xcm_executor_utils, XcmExecutorUtils]
        [cumulus_pallet_weight_reclaim, WeightReclaim]
        [pallet_evm_precompile_sha3fips, EVMPrecompileSha3FIPSBench::<Runtime>]
    );
}
impl_runtime_apis! {
    impl sp_api::Core<Block> for Runtime {
        fn version() -> RuntimeVersion {
            VERSION
        }
        fn execute_block(block: Block) {
            Executive::execute_block(block)
        }
        fn initialize_block(header: &<Block as BlockT>::Header) -> sp_runtime::ExtrinsicInclusionMode {
            Executive::initialize_block(header)
        }
    }
    impl sp_api::Metadata<Block> for Runtime {
        fn metadata() -> OpaqueMetadata {
            OpaqueMetadata::new(Runtime::metadata().into())
        }
        fn metadata_at_version(version: u32) -> Option<OpaqueMetadata> {
            Runtime::metadata_at_version(version)
        }
        fn metadata_versions() -> Vec<u32> {
            Runtime::metadata_versions()
        }
    }
    impl sp_block_builder::BlockBuilder<Block> for Runtime {
        fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult {
            Executive::apply_extrinsic(extrinsic)
        }
        fn finalize_block() -> <Block as BlockT>::Header {
            Executive::finalize_block()
        }
        fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
            data.create_extrinsics()
        }
        fn check_inherents(
            block: Block,
            data: sp_inherents::InherentData,
        ) -> sp_inherents::CheckInherentsResult {
            data.check_extrinsics(&block)
        }
    }
    impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
        fn validate_transaction(
            source: TransactionSource,
            xt: <Block as BlockT>::Extrinsic,
            block_hash: <Block as BlockT>::Hash,
        ) -> TransactionValidity {
            // Filtered calls should not enter the tx pool as they'll fail if inserted.
            // If this call is not allowed, we return early.
            if !<Runtime as frame_system::Config>::BaseCallFilter::contains(&xt.0.function) {
                return InvalidTransaction::Call.into();
            }
            // This runtime uses Substrate's pallet transaction payment. This
            // makes the chain feel like a standard Substrate chain when submitting
            // frame transactions and using Substrate ecosystem tools. It has the downside that
            // transaction are not prioritized by gas_price. The following code reprioritizes
            // transactions to overcome this.
            //
            // A more elegant, ethereum-first solution is
            // a pallet that replaces pallet transaction payment, and allows users
            // to directly specify a gas price rather than computing an effective one.
            // #HopefullySomeday
            // First we pass the transactions to the standard FRAME executive. This calculates all the
            // necessary tags, longevity and other properties that we will leave unchanged.
            // This also assigns some priority that we don't care about and will overwrite next.
            let mut intermediate_valid = Executive::validate_transaction(source, xt.clone(), block_hash)?;
            let dispatch_info = xt.get_dispatch_info();
            // If this is a pallet ethereum transaction, then its priority is already set
            // according to effective priority fee from pallet ethereum. If it is any other kind of
            // transaction, we modify its priority. The goal is to arrive at a similar metric used
            // by pallet ethereum, which means we derive a fee-per-gas from the txn's tip and
            // weight.
            Ok(match &xt.0.function {
                RuntimeCall::Ethereum(transact { .. }) => intermediate_valid,
                _ if dispatch_info.class != DispatchClass::Normal => intermediate_valid,
                _ => {
                    let tip = match xt.0.preamble.to_signed() {
                        None => 0,
                        Some((_, _, ref signed_extra)) => {
                            // Yuck, this depends on the index of charge transaction in Signed Extra
                            let charge_transaction = &signed_extra.0.7;
                            charge_transaction.tip()
                        }
                    };
                    let effective_gas =
                        <Runtime as pallet_evm::Config>::GasWeightMapping::weight_to_gas(
                            dispatch_info.total_weight()
                        );
                    let tip_per_gas = tip.checked_div(u128::from(effective_gas)).unwrap_or(0);
                    // Overwrite the original prioritization with this ethereum one
                    intermediate_valid.priority = tip_per_gas as u64;
                    intermediate_valid
                }
            })
        }
    }
    impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
        fn offchain_worker(header: &<Block as BlockT>::Header) {
            Executive::offchain_worker(header)
        }
    }
    impl sp_session::SessionKeys<Block> for Runtime {
        fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
            SessionKeys::generate(seed)
        }
        fn decode_session_keys(
            encoded: Vec<u8>,
        ) -> Option<Vec<(Vec<u8>, sp_core::crypto::KeyTypeId)>> {
            SessionKeys::decode_into_raw_public_keys(&encoded)
        }
    }
    impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Index> for Runtime {
        fn account_nonce(account: AccountId) -> Index {
            System::account_nonce(account)
        }
    }
    impl cumulus_primitives_core::CollectCollationInfo<Block> for Runtime {
        fn collect_collation_info(header: &<Block as BlockT>::Header) -> cumulus_primitives_core::CollationInfo {
            ParachainSystem::collect_collation_info(header)
        }
    }
    impl async_backing_primitives::UnincludedSegmentApi<Block> for Runtime {
        fn can_build_upon(
            included_hash: <Block as BlockT>::Hash,
            slot: async_backing_primitives::Slot,
        ) -> bool {
            ConsensusHook::can_build_upon(included_hash, slot)
        }
    }
    impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
        fn build_state(config: Vec<u8>) -> sp_genesis_builder::Result {
            build_state::<RuntimeGenesisConfig>(config)
        }
        fn get_preset(id: &Option<sp_genesis_builder::PresetId>) -> Option<Vec<u8>> {
            get_preset::<RuntimeGenesisConfig>(id, |id: &sp_genesis_builder::PresetId| {
                let mut default_funded_accounts = genesis_config_presets::pre_funded_accounts();
                default_funded_accounts.sort();
                default_funded_accounts.dedup();
                let para_id: ParaId = 2000.into();
                let patch = match id.as_ref() {
                    "development" => genesis_config_presets::development(
                        default_funded_accounts.clone(),
                        para_id,
                        AccountId::from(hex!("f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac")),
                    ),
                    _ => return None,
                };
                Some(
                    serde_json::to_string(&patch)
                        .expect("serialization to json is expected to work. qed.")
                        .into_bytes(),
                )
            })
        }
        fn preset_names() -> Vec<sp_genesis_builder::PresetId> {
            vec!["development".into()]
        }
    }
    #[cfg(feature = "runtime-benchmarks")]
    impl frame_benchmarking::Benchmark<Block> for Runtime {
        fn benchmark_metadata(
            extra: bool,
        ) -> (
            Vec<frame_benchmarking::BenchmarkList>,
            Vec<frame_support::traits::StorageInfo>,
        ) {
            use frame_benchmarking::{BenchmarkList};
            use frame_support::traits::StorageInfoTrait;
            use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark;
            use pallet_evm_precompile_sha3fips_benchmarking::Pallet as EVMPrecompileSha3FIPSBench;
            let mut list = Vec::<BenchmarkList>::new();
            list_benchmarks!(list, extra);
            let storage_info = AllPalletsWithSystem::storage_info();
            (list, storage_info)
        }
        #[allow(non_local_definitions)]
        fn dispatch_benchmark(
            config: frame_benchmarking::BenchmarkConfig,
        ) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, alloc::string::String> {
            use frame_benchmarking::{BenchmarkBatch, BenchmarkError};
            use sp_core::storage::TrackedStorageKey;
            use xcm::latest::prelude::*;
            use alloc::boxed::Box;
            use pallet_evm_precompile_sha3fips_benchmarking::Pallet as EVMPrecompileSha3FIPSBench;
            impl pallet_evm_precompile_sha3fips_benchmarking::Config for Runtime {}
            impl frame_system_benchmarking::Config for Runtime {
                fn setup_set_code_requirements(code: &alloc::vec::Vec<u8>) -> Result<(), BenchmarkError> {
                    ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32);
                    Ok(())
                }
                fn verify_set_code() {
                    System::assert_last_event(cumulus_pallet_parachain_system::Event::<Runtime>::ValidationFunctionStored.into());
                }
            }
            use xcm_config::SelfReserve;
            parameter_types! {
                pub ExistentialDepositAsset: Option<Asset> = Some((
                    SelfReserve::get(),
                    ExistentialDeposit::get()
                ).into());
            }
            impl pallet_xcm_benchmarks::Config for Runtime {
                type XcmConfig = xcm_config::XcmConfig;
                type AccountIdConverter = xcm_config::LocationToAccountId;
                type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper<
                    xcm_config::XcmConfig,
                    ExistentialDepositAsset,
                    xcm_config::PriceForParentDelivery,
                >;
                fn valid_destination() -> Result<Location, BenchmarkError> {
                    Ok(Location::parent())
                }
                fn worst_case_holding(_depositable_count: u32) -> Assets {
                    // We only care for native asset until we support others
                    // TODO: refactor this case once other assets are supported
                    vec![Asset{
                        id: AssetId(SelfReserve::get()),
                        fun: Fungible(u128::MAX),
                    }].into()
                }
            }
            impl pallet_xcm_benchmarks::generic::Config for Runtime {
                type TransactAsset = Balances;
                type RuntimeCall = RuntimeCall;
                fn worst_case_response() -> (u64, Response) {
                    (0u64, Response::Version(Default::default()))
                }
                fn worst_case_asset_exchange() -> Result<(Assets, Assets), BenchmarkError> {
                    Err(BenchmarkError::Skip)
                }
                fn universal_alias() -> Result<(Location, Junction), BenchmarkError> {
                    tanssi_runtime_common::universal_aliases::AliasingBenchmarksHelper::prepare_universal_alias()
                    .ok_or(BenchmarkError::Skip)
                }
                fn transact_origin_and_runtime_call() -> Result<(Location, RuntimeCall), BenchmarkError> {
                    Ok((Location::parent(), frame_system::Call::remark_with_event { remark: vec![] }.into()))
                }
                fn subscribe_origin() -> Result<Location, BenchmarkError> {
                    Ok(Location::parent())
                }
                fn worst_case_for_trader() -> Result<(Asset, WeightLimit), BenchmarkError> {
                    Ok((Asset {
                        id: AssetId(SelfReserve::get()),
                        fun: Fungible(crate::currency::MICROUNIT*100),
                    }, WeightLimit::Unlimited))
                }
                fn claimable_asset() -> Result<(Location, Location, Assets), BenchmarkError> {
                    let origin = Location::parent();
                    let assets: Assets = (Location::parent(), 1_000u128).into();
                    let ticket = Location { parents: 0, interior: Here };
                    Ok((origin, ticket, assets))
                }
                fn unlockable_asset() -> Result<(Location, Location, Asset), BenchmarkError> {
                    Err(BenchmarkError::Skip)
                }
                fn export_message_origin_and_destination(
                ) -> Result<(Location, NetworkId, InteriorLocation), BenchmarkError> {
                    Err(BenchmarkError::Skip)
                }
                fn alias_origin() -> Result<(Location, Location), BenchmarkError> {
                    Err(BenchmarkError::Skip)
                }
            }
            use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark;
            impl pallet_xcm::benchmarking::Config for Runtime {
                type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper<
                    xcm_config::XcmConfig,
                    ExistentialDepositAsset,
                    xcm_config::PriceForParentDelivery,
                >;
                fn get_asset() -> Asset {
                    Asset {
                        id: AssetId(SelfReserve::get()),
                        fun: Fungible(crate::currency::MICROUNIT),
                    }
                }
                fn reachable_dest() -> Option<Location> {
                    Some(Parent.into())
                }
                fn teleportable_asset_and_dest() -> Option<(Asset, Location)> {
                    let teleportable = crate::currency::MICROUNIT;
                    // Relay/native token can be teleported between AH and Relay.
                    Some((
                        Asset {
                            fun: Fungible(teleportable),
                            id: Parent.into()
                        },
                        Parent.into(),
                    ))
                }
                fn reserve_transferable_asset_and_dest() -> Option<(Asset, Location)> {
                    use xcm_config::SelfReserve;
                    // AH can reserve transfer native token to some random parachain.
                    let random_para_id = 43211234;
                    ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(
                        random_para_id.into()
                    );
                    let who = frame_benchmarking::whitelisted_caller();
                    // Give some multiple of the existential deposit
                    let balance = crate::currency::MICROUNIT* 1000;
                    let _ = <Balances as frame_support::traits::Currency<_>>::make_free_balance_be(
                        &who, balance,
                    );
                    Some((
                        Asset {
                            fun: Fungible(balance),
                            id: SelfReserve::get().into()
                        },
                        ParentThen(Parachain(random_para_id).into()).into(),
                    ))
                }
                fn set_up_complex_asset_transfer(
                ) -> Option<(Assets, u32, Location, Box<dyn FnOnce()>)> {
                    use xcm_config::SelfReserve;
                    // Transfer to Relay some local AH asset (local-reserve-transfer) while paying
                    // fees using teleported native token.
                    // (We don't care that Relay doesn't accept incoming unknown AH local asset)
                    let dest = Parent.into();
                    let fee_amount = crate::currency::MICROUNIT;
                    let fee_asset: Asset = (SelfReserve::get(), fee_amount).into();
                    let who = frame_benchmarking::whitelisted_caller();
                    // Give some multiple of the existential deposit
                    let balance = fee_amount + crate::currency::MICROUNIT * 1000;
                    let _ = <Balances as frame_support::traits::Currency<_>>::make_free_balance_be(
                        &who, balance,
                    );
                    // verify initial balance
                    assert_eq!(Balances::free_balance(who), balance);
                    // set up local asset
                    let asset_amount = 10u128;
                    let initial_asset_amount = asset_amount * 10;
                    let (asset_id, asset_location) = pallet_foreign_asset_creator::benchmarks::create_minted_asset::<Runtime>(
                        initial_asset_amount,
                        who,
                        None,
                    );
                    let transfer_asset: Asset = (asset_location, asset_amount).into();
                    let assets: Assets = vec![fee_asset.clone(), transfer_asset].into();
                    let fee_index = if assets.get(0).unwrap().eq(&fee_asset) { 0 } else { 1 };
                    // verify transferred successfully
                    let verify = Box::new(move || {
                        // verify native balance after transfer, decreased by transferred fee amount
                        // (plus transport fees)
                        assert!(Balances::free_balance(who) <= balance - fee_amount);
                        // verify asset balance decreased by exactly transferred amount
                        assert_eq!(
                            ForeignAssets::balance(asset_id, who),
                            initial_asset_amount - asset_amount,
                        );
                    });
                    Some((assets, fee_index, dest, verify))
                }
            }
            let whitelist: Vec<TrackedStorageKey> = vec![
                // Block Number
                hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac")
                    .to_vec()
                    .into(),
                // Total Issuance
                hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80")
                    .to_vec()
                    .into(),
                // Execution Phase
                hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a")
                    .to_vec()
                    .into(),
                // Event Count
                hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850")
                    .to_vec()
                    .into(),
                // System Events
                hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7")
                    .to_vec()
                    .into(),
                // The transactional storage limit.
                hex_literal::hex!("3a7472616e73616374696f6e5f6c6576656c3a")
                    .to_vec()
                    .into(),
                // ParachainInfo ParachainId
                hex_literal::hex!(  "0d715f2646c8f85767b5d2764bb2782604a74d81251e398fd8a0a4d55023bb3f")
                    .to_vec()
                    .into(),
            ];
            let mut batches = Vec::<BenchmarkBatch>::new();
            let params = (&config, &whitelist);
            add_benchmarks!(params, batches);
            Ok(batches)
        }
    }
    #[cfg(feature = "try-runtime")]
    impl frame_try_runtime::TryRuntime<Block> for Runtime {
        fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) {
            let weight = Executive::try_runtime_upgrade(checks).unwrap();
            (weight, RuntimeBlockWeights::get().max_block)
        }
        fn execute_block(
            block: Block,
            state_root_check: bool,
            signature_check: bool,
            select: frame_try_runtime::TryStateSelect,
        ) -> Weight {
            // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to
            // have a backtrace here.
            Executive::try_execute_block(block, state_root_check, signature_check, select).unwrap()
        }
    }
    impl fp_rpc::EthereumRuntimeRPCApi<Block> for Runtime {
        fn chain_id() -> u64 {
            <Runtime as pallet_evm::Config>::ChainId::get()
        }
        fn account_basic(address: H160) -> EVMAccount {
            let (account, _) = pallet_evm::Pallet::<Runtime>::account_basic(&address);
            account
        }
        fn gas_price() -> U256 {
            let (gas_price, _) = <Runtime as pallet_evm::Config>::FeeCalculator::min_gas_price();
            gas_price
        }
        fn account_code_at(address: H160) -> Vec<u8> {
            pallet_evm::AccountCodes::<Runtime>::get(address)
        }
        fn author() -> H160 {
            <pallet_evm::Pallet<Runtime>>::find_author()
        }
        fn storage_at(address: H160, index: U256) -> H256 {
            let tmp = index.to_big_endian();
            pallet_evm::AccountStorages::<Runtime>::get(address, H256::from_slice(&tmp[..]))
        }
        fn call(
            from: H160,
            to: H160,
            data: Vec<u8>,
            value: U256,
            gas_limit: U256,
            max_fee_per_gas: Option<U256>,
            max_priority_fee_per_gas: Option<U256>,
            nonce: Option<U256>,
            estimate: bool,
            access_list: Option<Vec<(H160, Vec<H256>)>>,
            authorization_list: Option<AuthorizationList>,
        ) -> Result<pallet_evm::CallInfo, sp_runtime::DispatchError> {
            let config = if estimate {
                let mut config = <Runtime as pallet_evm::Config>::config().clone();
                config.estimate = true;
                Some(config)
            } else {
                None
            };
            let is_transactional = false;
            let validate = true;
            let transaction_data = pallet_ethereum::TransactionData::new(
                pallet_ethereum::TransactionAction::Call(to),
                data.clone(),
                nonce.unwrap_or_default(),
                gas_limit,
                None,
                max_fee_per_gas.or(Some(U256::default())),
                max_priority_fee_per_gas.or(Some(U256::default())),
                value,
                Some(<Runtime as pallet_evm::Config>::ChainId::get()),
                access_list.clone().unwrap_or_default(),
                authorization_list.clone().unwrap_or_default(),
            );
            let gas_limit = gas_limit.min(u64::MAX.into()).low_u64();
            let (weight_limit, proof_size_base_cost) = pallet_ethereum::Pallet::<Runtime>::transaction_weight(&transaction_data);
            <Runtime as pallet_evm::Config>::Runner::call(
                from,
                to,
                data,
                value,
                gas_limit,
                max_fee_per_gas,
                max_priority_fee_per_gas,
                nonce,
                access_list.unwrap_or_default(),
                authorization_list.unwrap_or_default(),
                is_transactional,
                validate,
                weight_limit,
                proof_size_base_cost,
                config.as_ref().unwrap_or(<Runtime as pallet_evm::Config>::config()),
            ).map_err(|err| err.error.into())
        }
        fn create(
            from: H160,
            data: Vec<u8>,
            value: U256,
            gas_limit: U256,
            max_fee_per_gas: Option<U256>,
            max_priority_fee_per_gas: Option<U256>,
            nonce: Option<U256>,
            estimate: bool,
            access_list: Option<Vec<(H160, Vec<H256>)>>,
            authorization_list: Option<AuthorizationList>,
        ) -> Result<pallet_evm::CreateInfo, sp_runtime::DispatchError> {
            let config = if estimate {
                let mut config = <Runtime as pallet_evm::Config>::config().clone();
                config.estimate = true;
                Some(config)
            } else {
                None
            };
            let is_transactional = false;
            let validate = true;
            let transaction_data = pallet_ethereum::TransactionData::new(
                pallet_ethereum::TransactionAction::Create,
                data.clone(),
                nonce.unwrap_or_default(),
                gas_limit,
                None,
                max_fee_per_gas.or(Some(U256::default())),
                max_priority_fee_per_gas.or(Some(U256::default())),
                value,
                Some(<Runtime as pallet_evm::Config>::ChainId::get()),
                access_list.clone().unwrap_or_default(),
                authorization_list.clone().unwrap_or_default(),
            );
            let gas_limit = gas_limit.min(u64::MAX.into()).low_u64();
            let (weight_limit, proof_size_base_cost) = pallet_ethereum::Pallet::<Runtime>::transaction_weight(&transaction_data);
            <Runtime as pallet_evm::Config>::Runner::create(
                from,
                data,
                value,
                gas_limit,
                max_fee_per_gas,
                max_priority_fee_per_gas,
                nonce,
                access_list.unwrap_or_default(),
                authorization_list.unwrap_or_default(),
                is_transactional,
                validate,
                weight_limit,
                proof_size_base_cost,
                config.as_ref().unwrap_or(<Runtime as pallet_evm::Config>::config()),
            ).map_err(|err| err.error.into())
        }
        fn current_transaction_statuses() -> Option<Vec<TransactionStatus>> {
            pallet_ethereum::CurrentTransactionStatuses::<Runtime>::get()
        }
        fn current_block() -> Option<pallet_ethereum::Block> {
            pallet_ethereum::CurrentBlock::<Runtime>::get()
        }
        fn current_receipts() -> Option<Vec<pallet_ethereum::Receipt>> {
            pallet_ethereum::CurrentReceipts::<Runtime>::get()
        }
        fn current_all() -> (
            Option<pallet_ethereum::Block>,
            Option<Vec<pallet_ethereum::Receipt>>,
            Option<Vec<TransactionStatus>>,
        ) {
            (
                pallet_ethereum::CurrentBlock::<Runtime>::get(),
                pallet_ethereum::CurrentReceipts::<Runtime>::get(),
                pallet_ethereum::CurrentTransactionStatuses::<Runtime>::get()
            )
        }
        fn extrinsic_filter(
            xts: Vec<<Block as BlockT>::Extrinsic>,
        ) -> Vec<EthereumTransaction> {
            xts.into_iter().filter_map(|xt| match xt.0.function {
                RuntimeCall::Ethereum(transact { transaction }) => Some(transaction),
                _ => None
            }).collect::<Vec<EthereumTransaction>>()
        }
        fn elasticity() -> Option<Permill> {
            Some(pallet_base_fee::Elasticity::<Runtime>::get())
        }
        fn gas_limit_multiplier_support() {}
        fn pending_block(xts: Vec<<Block as BlockT>::Extrinsic>) -> (Option<pallet_ethereum::Block>, Option<alloc::vec::Vec<TransactionStatus>>) {
            for ext in xts.into_iter() {
                let _ = Executive::apply_extrinsic(ext);
            }
            Ethereum::on_finalize(System::block_number() + 1);
            (
                pallet_ethereum::CurrentBlock::<Runtime>::get(),
                pallet_ethereum::CurrentTransactionStatuses::<Runtime>::get()
            )
        }
        fn initialize_pending_block(header: &<Block as BlockT>::Header) {
            Executive::initialize_block(header);
        }
    }
    impl fp_rpc::ConvertTransactionRuntimeApi<Block> for Runtime {
        fn convert_transaction(
            transaction: pallet_ethereum::Transaction
        ) -> <Block as BlockT>::Extrinsic {
            UncheckedExtrinsic::new_bare(
                pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
            )
        }
    }
    impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>
    for Runtime {
        fn query_info(
            uxt: <Block as BlockT>::Extrinsic,
            len: u32,
        ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo<Balance> {
            TransactionPayment::query_info(uxt, len)
        }
        fn query_fee_details(
            uxt: <Block as BlockT>::Extrinsic,
            len: u32,
        ) -> pallet_transaction_payment::FeeDetails<Balance> {
            TransactionPayment::query_fee_details(uxt, len)
        }
        fn query_weight_to_fee(weight: Weight) -> Balance {
            TransactionPayment::weight_to_fee(weight)
        }
        fn query_length_to_fee(length: u32) -> Balance {
            TransactionPayment::length_to_fee(length)
        }
    }
    impl dp_slot_duration_runtime_api::TanssiSlotDurationApi<Block> for Runtime {
        fn slot_duration() -> u64 {
            SLOT_DURATION
        }
    }
    impl xcm_runtime_apis::fees::XcmPaymentApi<Block> for Runtime {
        fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result<Vec<VersionedAssetId>, XcmPaymentApiError> {
            if !matches!(xcm_version, 3..=5) {
                return Err(XcmPaymentApiError::UnhandledXcmVersion);
            }
            Ok([VersionedAssetId::V5(xcm_config::SelfReserve::get().into())]
                .into_iter()
                .chain(
                    pallet_asset_rate::ConversionRateToNative::<Runtime>::iter_keys().filter_map(|asset_id_u16| {
                        pallet_foreign_asset_creator::AssetIdToForeignAsset::<Runtime>::get(asset_id_u16).map(|location| {
                            VersionedAssetId::V5(location.into())
                        }).or_else(|| {
                            log::warn!("Asset `{}` is present in pallet_asset_rate but not in pallet_foreign_asset_creator", asset_id_u16);
                            None
                        })
                    })
                )
                .filter_map(|asset| asset.into_version(xcm_version).map_err(|e| {
                    log::warn!("Failed to convert asset to version {}: {:?}", xcm_version, e);
                }).ok())
                .collect())
        }
        fn query_weight_to_asset_fee(weight: Weight, asset: VersionedAssetId) -> Result<u128, XcmPaymentApiError> {
            let local_asset = VersionedAssetId::V5(xcm_config::SelfReserve::get().into());
            let asset = asset
                .into_version(5)
                .map_err(|_| XcmPaymentApiError::VersionedConversionFailed)?;
            if asset == local_asset {
                Ok(WeightToFee::weight_to_fee(&weight))
            } else {
                let native_fee = WeightToFee::weight_to_fee(&weight);
                let asset_v5: xcm::latest::AssetId = asset.try_into().map_err(|_| XcmPaymentApiError::VersionedConversionFailed)?;
                let location: xcm::latest::Location = asset_v5.0;
                let asset_id = pallet_foreign_asset_creator::ForeignAssetToAssetId::<Runtime>::get(location).ok_or(XcmPaymentApiError::AssetNotFound)?;
                let asset_rate = AssetRate::to_asset_balance(native_fee, asset_id);
                match asset_rate {
                    Ok(x) => Ok(x),
                    Err(pallet_asset_rate::Error::UnknownAssetKind) => Err(XcmPaymentApiError::AssetNotFound),
                    // Error when converting native balance to asset balance, probably overflow
                    Err(_e) => Err(XcmPaymentApiError::WeightNotComputable),
                }
            }
        }
        fn query_xcm_weight(message: VersionedXcm<()>) -> Result<Weight, XcmPaymentApiError> {
            PolkadotXcm::query_xcm_weight(message)
        }
        fn query_delivery_fees(destination: VersionedLocation, message: VersionedXcm<()>) -> Result<VersionedAssets, XcmPaymentApiError> {
            PolkadotXcm::query_delivery_fees(destination, message)
        }
    }
    impl xcm_runtime_apis::dry_run::DryRunApi<Block, RuntimeCall, RuntimeEvent, OriginCaller> for Runtime {
        fn dry_run_call(origin: OriginCaller, call: RuntimeCall, result_xcms_version: XcmVersion) -> Result<CallDryRunEffects<RuntimeEvent>, XcmDryRunApiError> {
            PolkadotXcm::dry_run_call::<Runtime, xcm_config::XcmRouter, OriginCaller, RuntimeCall>(origin, call, result_xcms_version)
        }
        fn dry_run_xcm(origin_location: VersionedLocation, xcm: VersionedXcm<RuntimeCall>) -> Result<XcmDryRunEffects<RuntimeEvent>, XcmDryRunApiError> {
            PolkadotXcm::dry_run_xcm::<Runtime, xcm_config::XcmRouter, RuntimeCall, xcm_config::XcmConfig>(origin_location, xcm)
        }
    }
    impl xcm_runtime_apis::conversions::LocationToAccountApi<Block, AccountId> for Runtime {
        fn convert_location(location: VersionedLocation) -> Result<
            AccountId,
            xcm_runtime_apis::conversions::Error
        > {
            xcm_runtime_apis::conversions::LocationToAccountHelper::<
                AccountId,
                xcm_config::LocationToAccountId,
            >::convert_location(location)
        }
    }
66174
}
#[allow(dead_code)]
struct CheckInherents;
// TODO: this should be removed but currently if we remove it the relay does not check anything
// related to other inherents that are not parachain-system
#[allow(deprecated)]
impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
    fn check_inherents(
        block: &Block,
        relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof,
    ) -> sp_inherents::CheckInherentsResult {
        let relay_chain_slot = relay_state_proof
            .read_slot()
            .expect("Could not read the relay chain slot from the proof");
        let inherent_data =
            cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration(
                relay_chain_slot,
                core::time::Duration::from_secs(6),
            )
            .create_inherent_data()
            .expect("Could not create the timestamp inherent data");
        inherent_data.check_extrinsics(block)
    }
}
cumulus_pallet_parachain_system::register_validate_block! {
    Runtime = Runtime,
    CheckInherents = CheckInherents,
    BlockExecutor = pallet_author_inherent::BlockExecutor::<Runtime, Executive>,
}
#[cfg(test)]
mod tests {
    use super::*;
    /// Block storage limit in bytes. Set to 40 KB.
    const BLOCK_STORAGE_LIMIT: u64 = 40 * 1024;
    #[test]
1
    fn check_ratio_constant() {
1
        assert_eq!(
1
            BlockGasLimit::get().min(u64::MAX.into()).low_u64() / BLOCK_STORAGE_LIMIT,
1
            GasLimitStorageGrowthRatio::get()
        );
1
    }
    #[test]
1
    fn test_chain_id_derivation_dancelight() {
1
        let chain_id = dynamic_params::EthereumNetworkChainId::from_relay_network(
1
            &NetworkId::ByGenesis(dynamic_params::DANCELIGHT_GENESIS_HASH),
1
        )
1
        .unwrap()
1
        .as_u64();
1
        assert_eq!(chain_id, dynamic_params::SEPOLIA_ETH_TESTNET_CHAIN_ID);
1
    }
    #[test]
1
    fn test_chain_id_derivation_starlight() {
1
        let chain_id = dynamic_params::EthereumNetworkChainId::from_relay_network(
1
            &NetworkId::ByGenesis(dynamic_params::TANSSI_GENESIS_HASH),
1
        )
1
        .unwrap()
1
        .as_u64();
1
        assert_eq!(chain_id, dynamic_params::ETH_MAINNET_CHAIN_ID);
1
    }
}