diff --git a/Cargo.lock b/Cargo.lock
index a718a46379..20356094bf 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5991,7 +5991,6 @@ dependencies = [
"pallet-assets",
"pallet-aura",
"pallet-balances",
- "pallet-base-fee",
"pallet-block-reward",
"pallet-chain-extension-assets",
"pallet-chain-extension-dapps-staking",
@@ -6001,6 +6000,7 @@ dependencies = [
"pallet-contracts-primitives",
"pallet-dapps-staking",
"pallet-democracy",
+ "pallet-dynamic-evm-base-fee",
"pallet-ethereum",
"pallet-ethereum-checked",
"pallet-evm",
@@ -6033,6 +6033,7 @@ dependencies = [
"pallet-xvm",
"parity-scale-codec",
"scale-info",
+ "smallvec 1.11.0",
"sp-api",
"sp-block-builder",
"sp-consensus-aura",
@@ -7666,6 +7667,24 @@ dependencies = [
"sp-std",
]
+[[package]]
+name = "pallet-dynamic-evm-base-fee"
+version = "0.1.0"
+dependencies = [
+ "fp-evm",
+ "frame-benchmarking",
+ "frame-support",
+ "frame-system",
+ "num-traits",
+ "pallet-balances",
+ "pallet-timestamp",
+ "pallet-transaction-payment",
+ "parity-scale-codec",
+ "scale-info",
+ "sp-core",
+ "sp-runtime",
+]
+
[[package]]
name = "pallet-election-provider-multi-phase"
version = "4.0.0-dev"
@@ -13043,7 +13062,6 @@ dependencies = [
"pallet-aura",
"pallet-authorship",
"pallet-balances",
- "pallet-base-fee",
"pallet-block-reward",
"pallet-chain-extension-assets",
"pallet-chain-extension-dapps-staking",
@@ -13054,6 +13072,7 @@ dependencies = [
"pallet-contracts-primitives",
"pallet-dapps-staking",
"pallet-democracy",
+ "pallet-dynamic-evm-base-fee",
"pallet-ethereum",
"pallet-ethereum-checked",
"pallet-evm",
diff --git a/Cargo.toml b/Cargo.toml
index d63c7c2e35..c5828cc529 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -278,6 +278,7 @@ pallet-xc-asset-config = { path = "./pallets/xc-asset-config", default-features
pallet-xvm = { path = "./pallets/xvm", default-features = false }
pallet-xcm = { path = "./pallets/pallet-xcm", default-features = false }
pallet-ethereum-checked = { path = "./pallets/ethereum-checked", default-features = false }
+pallet-dynamic-evm-base-fee = { path = "./pallets/dynamic-evm-base-fee", default-features = false }
pallet-unified-accounts = { path = "./pallets/unified-accounts", default-features = false }
astar-primitives = { path = "./primitives", default-features = false }
diff --git a/bin/collator/src/local/chain_spec.rs b/bin/collator/src/local/chain_spec.rs
index 8d56c8747c..798370c075 100644
--- a/bin/collator/src/local/chain_spec.rs
+++ b/bin/collator/src/local/chain_spec.rs
@@ -19,10 +19,10 @@
//! Chain specifications.
use local_runtime::{
- wasm_binary_unwrap, AccountId, AuraConfig, AuraId, BalancesConfig, BaseFeeConfig,
- BlockRewardConfig, CouncilConfig, DemocracyConfig, EVMConfig, GenesisConfig, GrandpaConfig,
- GrandpaId, Precompiles, Signature, SudoConfig, SystemConfig, TechnicalCommitteeConfig,
- TreasuryConfig, VestingConfig,
+ wasm_binary_unwrap, AccountId, AuraConfig, AuraId, BalancesConfig, BlockRewardConfig,
+ CouncilConfig, DemocracyConfig, EVMConfig, GenesisConfig, GrandpaConfig, GrandpaId,
+ Precompiles, Signature, SudoConfig, SystemConfig, TechnicalCommitteeConfig, TreasuryConfig,
+ VestingConfig,
};
use sc_service::ChainType;
use sp_core::{crypto::Ss58Codec, sr25519, Pair, Public};
@@ -154,10 +154,6 @@ fn testnet_genesis(
.collect(),
},
ethereum: Default::default(),
- base_fee: BaseFeeConfig::new(
- sp_core::U256::from(1_000_000_000u64),
- sp_runtime::Permill::zero(),
- ),
sudo: SudoConfig {
key: Some(root_key),
},
diff --git a/bin/collator/src/parachain/chain_spec/shibuya.rs b/bin/collator/src/parachain/chain_spec/shibuya.rs
index 843073ab3b..bdd00127c0 100644
--- a/bin/collator/src/parachain/chain_spec/shibuya.rs
+++ b/bin/collator/src/parachain/chain_spec/shibuya.rs
@@ -21,11 +21,10 @@
use cumulus_primitives_core::ParaId;
use sc_service::ChainType;
use shibuya_runtime::{
- wasm_binary_unwrap, AccountId, AuraConfig, AuraId, Balance, BalancesConfig, BaseFeeConfig,
- BlockRewardConfig, CollatorSelectionConfig, CouncilConfig, DemocracyConfig, EVMChainIdConfig,
- EVMConfig, GenesisConfig, ParachainInfoConfig, Precompiles, SessionConfig, SessionKeys,
- Signature, SudoConfig, SystemConfig, TechnicalCommitteeConfig, TreasuryConfig, VestingConfig,
- SBY,
+ wasm_binary_unwrap, AccountId, AuraConfig, AuraId, Balance, BalancesConfig, BlockRewardConfig,
+ CollatorSelectionConfig, CouncilConfig, DemocracyConfig, EVMChainIdConfig, EVMConfig,
+ GenesisConfig, ParachainInfoConfig, Precompiles, SessionConfig, SessionKeys, Signature,
+ SudoConfig, SystemConfig, TechnicalCommitteeConfig, TreasuryConfig, VestingConfig, SBY,
};
use sp_core::{sr25519, Pair, Public};
@@ -158,10 +157,6 @@ fn make_genesis(
})
.collect(),
},
- base_fee: BaseFeeConfig::new(
- sp_core::U256::from(1_000_000_000),
- sp_runtime::Permill::zero(),
- ),
evm_chain_id: EVMChainIdConfig { chain_id: 0x51 },
ethereum: Default::default(),
polkadot_xcm: Default::default(),
diff --git a/pallets/dynamic-evm-base-fee/Cargo.toml b/pallets/dynamic-evm-base-fee/Cargo.toml
new file mode 100644
index 0000000000..e9c2177b6d
--- /dev/null
+++ b/pallets/dynamic-evm-base-fee/Cargo.toml
@@ -0,0 +1,59 @@
+[package]
+name = "pallet-dynamic-evm-base-fee"
+version = "0.1.0"
+license = "GPL-3.0-or-later"
+description = "Handler for dynamic EVM base fee for Astar tokenomics v2."
+authors.workspace = true
+edition.workspace = true
+homepage.workspace = true
+repository.workspace = true
+
+[dependencies]
+parity-scale-codec = { workspace = true }
+scale-info = { workspace = true }
+
+# Substrate
+frame-benchmarking = { workspace = true, optional = true }
+frame-support = { workspace = true }
+frame-system = { workspace = true }
+pallet-transaction-payment = { workspace = true }
+sp-core = { workspace = true }
+sp-runtime = { workspace = true }
+
+# Frontier
+fp-evm = { workspace = true }
+
+[dev-dependencies]
+num-traits = { workspace = true }
+pallet-balances = { workspace = true }
+pallet-timestamp = { workspace = true }
+
+[features]
+default = ["std"]
+std = [
+ "parity-scale-codec/std",
+ "scale-info/std",
+ "num-traits/std",
+ # Substrate
+ "frame-support/std",
+ "frame-system/std",
+ "sp-core/std",
+ "sp-runtime/std",
+ "pallet-transaction-payment/std",
+ "pallet-balances/std",
+ "pallet-timestamp/std",
+ "frame-benchmarking/std",
+ # Frontier
+ "fp-evm/std",
+]
+runtime-benchmarks = [
+ "frame-benchmarking",
+ "frame-support/runtime-benchmarks",
+ "frame-system/runtime-benchmarks",
+ "sp-runtime/runtime-benchmarks",
+]
+try-runtime = [
+ "frame-support/try-runtime",
+ "frame-system/try-runtime",
+ "pallet-transaction-payment/try-runtime",
+]
diff --git a/pallets/dynamic-evm-base-fee/src/benchmarking.rs b/pallets/dynamic-evm-base-fee/src/benchmarking.rs
new file mode 100644
index 0000000000..eb94e5fc67
--- /dev/null
+++ b/pallets/dynamic-evm-base-fee/src/benchmarking.rs
@@ -0,0 +1,99 @@
+// This file is part of Astar.
+
+// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd.
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+// Astar is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Astar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Astar. If not, see .
+
+use super::*;
+
+use fp_evm::FeeCalculator;
+use frame_benchmarking::v2::*;
+use frame_support::traits::Hooks;
+use frame_system::RawOrigin;
+
+#[benchmarks]
+mod benchmarks {
+ use super::*;
+
+ #[benchmark]
+ fn base_fee_per_gas_adjustment() {
+ let (first_block, second_block) = (T::BlockNumber::from(1u32), T::BlockNumber::from(2u32));
+
+ // Setup actions, should ensure some value is written to storage.
+ Pallet::::on_initialize(first_block);
+ Pallet::::on_finalize(first_block);
+ assert!(
+ BaseFeePerGas::::exists(),
+ "Value should exist in storage after first on_finalize call"
+ );
+
+ Pallet::::on_initialize(second_block);
+ let init_bfpg = BaseFeePerGas::::get();
+
+ #[block]
+ {
+ Pallet::::on_finalize(second_block);
+ }
+
+ // Ensure that the value has changed.
+ assert!(BaseFeePerGas::::get() != init_bfpg);
+ }
+
+ #[benchmark]
+ fn set_base_fee_per_gas() {
+ let old_bfpg = BaseFeePerGas::::get();
+ let new_bfpg = old_bfpg + 1;
+
+ #[extrinsic_call]
+ _(RawOrigin::Root, new_bfpg);
+
+ // Ensure that the value has changed.
+ assert_eq!(BaseFeePerGas::::get(), new_bfpg);
+ }
+
+ #[benchmark]
+ fn min_gas_price() {
+ let first_block = T::BlockNumber::from(1u32);
+
+ // Setup actions, should ensure some value is written to storage.
+ Pallet::::on_initialize(first_block);
+ Pallet::::on_finalize(first_block);
+ assert!(
+ BaseFeePerGas::::exists(),
+ "Value should exist in storage after first on_finalize call"
+ );
+
+ #[block]
+ {
+ let _ = Pallet::::min_gas_price();
+ }
+ }
+
+ impl_benchmark_test_suite!(
+ Pallet,
+ crate::benchmarking::tests::new_test_ext(),
+ crate::mock::TestRuntime,
+ );
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::mock;
+ use frame_support::sp_io::TestExternalities;
+
+ pub fn new_test_ext() -> TestExternalities {
+ mock::ExtBuilder::build()
+ }
+}
diff --git a/pallets/dynamic-evm-base-fee/src/lib.rs b/pallets/dynamic-evm-base-fee/src/lib.rs
new file mode 100644
index 0000000000..5574346825
--- /dev/null
+++ b/pallets/dynamic-evm-base-fee/src/lib.rs
@@ -0,0 +1,238 @@
+// This file is part of Astar.
+
+// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd.
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+// Astar is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Astar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Astar. If not, see .
+
+//! Dynamic Evm Base Fee Pallet
+//!
+//! ## Overview
+//!
+//! The pallet is responsible for calculating `Base Fee Per Gas` value, according to the current system parameters.
+//! This is not like `EIP-1559`, instead it's intended for `Astar` and `Astar-like` networks, which allow both
+//! **Substrate native transactions** (which in `Astar` case reuse Polkadot transaction fee approach)
+//! and **EVM transactions** (which use `Base Fee Per Gas`).
+//!
+//! For a more detailed description, reader is advised to refer to Astar Network forum post about [Tokenomics 2.0](https://forum.astar.network/t/astar-tokenomics-2-0-a-dynamically-adjusted-inflation/4924).
+//!
+//! ## Approach
+//!
+//! The core formula this pallet tries to satisfy is:
+//!
+//! base_fee_per_gas = adjustment_factor * weight_factor * 25 / 98974
+//!
+//! Where:
+//! * **adjustment_factor** - is a value that changes in-between the blocks, related to the block fill ratio.
+//! * **weight_factor** - fixed constant, used to convert consumed _weight_ to _fee_.
+//!
+//! The implementation doesn't make any hard requirements on these values, and only requires that a type implementing `Get<_>` provides them.
+//!
+//! ## Implementation
+//!
+//! The core logic is implemented in `on_finalize` hook, which is called at the end of each block.
+//! This pallet's hook should be called AFTER whichever pallet's hook is responsible for updating **adjustment factor**.
+//!
+//! The hook will calculate the ideal new `base_fee_per_gas` value, and then clamp it in between the allowed limits.
+//!
+//! ## Interface
+//!
+//! Pallet provides an implementation of `FeeCalculator` trait. This makes it usable directly in `pallet-evm`.
+//!
+//! A _root-only_ extrinsic is provided to allow setting the `base_fee_per_gas` value manually.
+//!
+//! ## Practical Remarks
+//!
+//! According to the proposed **Tokenomics 2.0**, max amount that adjustment factor will be able to change on live networks in-between blocks is:
+//!
+//! adjustment_new = adjustment_old * (1 + adj + adj^2/2)
+//!
+//! adj = v * (s - s*)
+//! --> recommended _v_ value: 0.000_015
+//! --> largest 's' delta: (1 - 0.25) = **0.75**
+//!
+//! (for variable explanation please check the linked forum post above)
+//! (in short: `v` - variability factor, `s` - current block fill ratio, `s*` - ideal block fill ratio)
+//!
+//! adj = 0.000015 * (1 - 0.25) = **0.000_011_25**
+//! (1 + 0.000_011_25 + 0.000_011_25^2/2) = (1 + 0.000_011_25 + 0.000_000_000_063_281) = **1,000_011_250_063_281**
+//!
+//! Discarding the **1**, and only considering the decimals, this can be expressed as ratio:
+//! Expressed as ratio: 11_250_063_281 / 1_000_000_000_000_000.
+//! This is a much smaller change compared to the max step limit ratio we'll use to limit bfpg alignment.
+//! This means that once equilibrium is reached (fees are aligned), the `StepLimitRatio` will be larger than the max possible adjustment, essentially eliminating its effect.
+
+#![cfg_attr(not(feature = "std"), no_std)]
+
+use frame_support::weights::Weight;
+use sp_core::U256;
+use sp_runtime::{traits::UniqueSaturatedInto, FixedPointNumber, FixedU128, Perquintill};
+
+pub use self::pallet::*;
+
+#[cfg(test)]
+mod mock;
+#[cfg(test)]
+mod tests;
+
+#[cfg(feature = "runtime-benchmarks")]
+mod benchmarking;
+
+pub mod weights;
+pub use weights::WeightInfo;
+
+#[frame_support::pallet]
+pub mod pallet {
+ use frame_support::pallet_prelude::*;
+ use frame_system::pallet_prelude::*;
+
+ use super::*;
+
+ /// The current storage version.
+ const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
+
+ #[pallet::pallet]
+ #[pallet::storage_version(STORAGE_VERSION)]
+ pub struct Pallet(PhantomData);
+
+ #[pallet::config]
+ pub trait Config: frame_system::Config {
+ /// Overarching event type
+ type RuntimeEvent: From + IsType<::RuntimeEvent>;
+ /// Default base fee per gas value. Used in genesis if no other value specified explicitly.
+ type DefaultBaseFeePerGas: Get;
+ /// Minimum value 'base fee per gas' can be adjusted to. This is a defensive measure to prevent the fee from being too low.
+ type MinBaseFeePerGas: Get;
+ /// Maximum value 'base fee per gas' can be adjusted to. This is a defensive measure to prevent the fee from being too high.
+ type MaxBaseFeePerGas: Get;
+ /// Getter for the fee adjustment factor used in 'base fee per gas' formula. This is expected to change in-between the blocks (doesn't have to though).
+ type AdjustmentFactor: Get;
+ /// The so-called `weight_factor` in the 'base fee per gas' formula.
+ type WeightFactor: Get;
+ /// Ratio limit on how much the 'base fee per gas' can change in-between two blocks.
+ /// It's expressed as percentage, and used to calculate the delta between the old and new value.
+ /// E.g. if the current 'base fee per gas' is 100, and the limit is 10%, then the new base fee per gas can be between 90 and 110.
+ type StepLimitRatio: Get;
+ /// Weight information for extrinsics & functions of this pallet.
+ type WeightInfo: WeightInfo;
+ }
+
+ #[pallet::type_value]
+ pub fn DefaultBaseFeePerGas() -> U256 {
+ T::DefaultBaseFeePerGas::get()
+ }
+
+ #[pallet::storage]
+ pub type BaseFeePerGas = StorageValue<_, U256, ValueQuery, DefaultBaseFeePerGas>;
+
+ #[pallet::event]
+ #[pallet::generate_deposit(pub(super) fn deposit_event)]
+ pub enum Event {
+ /// New `base fee per gas` value has been force-set.
+ NewBaseFeePerGas { fee: U256 },
+ }
+
+ #[pallet::error]
+ pub enum Error {
+ /// Specified value is outside of the allowed range.
+ ValueOutOfBounds,
+ }
+
+ #[pallet::hooks]
+ impl Hooks> for Pallet {
+ fn on_initialize(_: T::BlockNumber) -> Weight {
+ T::WeightInfo::base_fee_per_gas_adjustment()
+ }
+
+ fn on_finalize(_n: ::BlockNumber) {
+ BaseFeePerGas::::mutate(|base_fee_per_gas| {
+ let old_bfpg = *base_fee_per_gas;
+
+ // Maximum step we're allowed to move the base fee per gas by.
+ let max_step = {
+ let old_bfpg_u128: u128 = old_bfpg.unique_saturated_into();
+ let step = T::StepLimitRatio::get() * old_bfpg_u128;
+ U256::from(step)
+ };
+
+ // It's possible current base fee per gas is outside of the allowed range.
+ // This can & will happen when this solution is deployed on live networks.
+ //
+ // In such scenario, we will discard the lower & upper bounds configured in the runtime.
+ // Once these bounds are reached ONCE, the runtime logic will prevent them from going out of bounds again.
+ let apply_configured_bounds = old_bfpg >= T::MinBaseFeePerGas::get()
+ && old_bfpg <= T::MaxBaseFeePerGas::get();
+ let (lower_limit, upper_limit) = if apply_configured_bounds {
+ (
+ T::MinBaseFeePerGas::get().max(old_bfpg.saturating_sub(max_step)),
+ T::MaxBaseFeePerGas::get().min(old_bfpg.saturating_add(max_step)),
+ )
+ } else {
+ (
+ old_bfpg.saturating_sub(max_step),
+ old_bfpg.saturating_add(max_step),
+ )
+ };
+
+ // Calculate ideal new 'base_fee_per_gas' according to the formula
+ let ideal_new_bfpg = T::AdjustmentFactor::get()
+ // Weight factor should be multiplied first since it's a larger number, to avoid precision loss.
+ .saturating_mul_int(T::WeightFactor::get())
+ .saturating_mul(25)
+ .saturating_div(98974);
+
+ // Clamp the ideal value in between the allowed limits
+ *base_fee_per_gas = U256::from(ideal_new_bfpg).clamp(lower_limit, upper_limit);
+ })
+ }
+
+ fn integrity_test() {
+ assert!(T::MinBaseFeePerGas::get() <= T::MaxBaseFeePerGas::get(),
+ "Minimum base fee per gas has to be equal or lower than maximum allowed base fee per gas.");
+
+ assert!(T::DefaultBaseFeePerGas::get() >= T::MinBaseFeePerGas::get(),
+ "Default base fee per gas has to be equal or higher than minimum allowed base fee per gas.");
+ assert!(T::DefaultBaseFeePerGas::get() <= T::MaxBaseFeePerGas::get(),
+ "Default base fee per gas has to be equal or lower than maximum allowed base fee per gas.");
+
+ assert!(T::MaxBaseFeePerGas::get() <= U256::from(u128::MAX),
+ "Maximum base fee per gas has to be equal or lower than u128::MAX, otherwise precision loss will occur.");
+ }
+ }
+
+ #[pallet::call]
+ impl Pallet {
+ /// `root-only` extrinsic to set the `base_fee_per_gas` value manually.
+ /// The specified value has to respect min & max limits configured in the runtime.
+ #[pallet::call_index(0)]
+ #[pallet::weight(T::WeightInfo::set_base_fee_per_gas())]
+ pub fn set_base_fee_per_gas(origin: OriginFor, fee: U256) -> DispatchResult {
+ ensure_root(origin)?;
+ ensure!(
+ fee >= T::MinBaseFeePerGas::get() && fee <= T::MaxBaseFeePerGas::get(),
+ Error::::ValueOutOfBounds
+ );
+
+ BaseFeePerGas::::put(fee);
+ Self::deposit_event(Event::NewBaseFeePerGas { fee });
+ Ok(())
+ }
+ }
+}
+
+impl fp_evm::FeeCalculator for Pallet {
+ fn min_gas_price() -> (U256, Weight) {
+ (BaseFeePerGas::::get(), T::WeightInfo::min_gas_price())
+ }
+}
diff --git a/pallets/dynamic-evm-base-fee/src/mock.rs b/pallets/dynamic-evm-base-fee/src/mock.rs
new file mode 100644
index 0000000000..3d7db1e4cb
--- /dev/null
+++ b/pallets/dynamic-evm-base-fee/src/mock.rs
@@ -0,0 +1,182 @@
+// This file is part of Astar.
+
+// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd.
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+// Astar is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Astar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Astar. If not, see .
+
+#![cfg(test)]
+
+use super::*;
+use crate as pallet_dynamic_evm_base_fee;
+
+use frame_support::{
+ construct_runtime, parameter_types,
+ sp_io::TestExternalities,
+ storage,
+ traits::{ConstU128, ConstU32, ConstU64, Get},
+ weights::constants::RocksDbWeight,
+};
+use parity_scale_codec::Encode;
+use sp_core::H256;
+use sp_runtime::{
+ testing::Header,
+ traits::{BlakeTwo256, IdentityLookup, One},
+ FixedU128, Perquintill,
+};
+
+pub(crate) type AccountId = u128;
+pub(crate) type BlockNumber = u64;
+pub(crate) type Balance = u128;
+
+parameter_types! {
+ pub BlockWeights: frame_system::limits::BlockWeights =
+ frame_system::limits::BlockWeights::simple_max(Weight::from_parts(1024, 0));
+}
+
+impl frame_system::Config for TestRuntime {
+ type BaseCallFilter = frame_support::traits::Everything;
+ type BlockWeights = ();
+ type BlockLength = ();
+ type RuntimeOrigin = RuntimeOrigin;
+ type Index = u64;
+ type RuntimeCall = RuntimeCall;
+ type BlockNumber = BlockNumber;
+ type Hash = H256;
+ type Hashing = BlakeTwo256;
+ type AccountId = AccountId;
+ type Lookup = IdentityLookup;
+ type Header = Header;
+ type RuntimeEvent = RuntimeEvent;
+ type BlockHashCount = ConstU64<250>;
+ type DbWeight = RocksDbWeight;
+ type Version = ();
+ type PalletInfo = PalletInfo;
+ type AccountData = pallet_balances::AccountData;
+ type OnNewAccount = ();
+ type OnKilledAccount = ();
+ type SystemWeightInfo = ();
+ type SS58Prefix = ();
+ type OnSetCode = ();
+ type MaxConsumers = frame_support::traits::ConstU32<16>;
+}
+
+impl pallet_balances::Config for TestRuntime {
+ type MaxLocks = ConstU32<4>;
+ type MaxReserves = ();
+ type ReserveIdentifier = [u8; 8];
+ type Balance = Balance;
+ type RuntimeEvent = RuntimeEvent;
+ type DustRemoval = ();
+ type ExistentialDeposit = ConstU128<2>;
+ type AccountStore = System;
+ type WeightInfo = ();
+ type HoldIdentifier = ();
+ type FreezeIdentifier = ();
+ type MaxHolds = ConstU32<0>;
+ type MaxFreezes = ConstU32<0>;
+}
+
+impl pallet_timestamp::Config for TestRuntime {
+ type Moment = u64;
+ type OnTimestampSet = ();
+ type MinimumPeriod = ConstU64<3>;
+ type WeightInfo = ();
+}
+
+parameter_types! {
+ pub DefaultBaseFeePerGas: U256 = U256::from(1_500_000_000_000_u128);
+ pub MinBaseFeePerGas: U256 = U256::from(800_000_000_000_u128);
+ pub MaxBaseFeePerGas: U256 = U256::from(80_000_000_000_000_u128);
+ pub StepLimitRation: Perquintill = Perquintill::from_rational(30_u128, 1_000_000);
+}
+
+impl pallet_dynamic_evm_base_fee::Config for TestRuntime {
+ type RuntimeEvent = RuntimeEvent;
+ type DefaultBaseFeePerGas = DefaultBaseFeePerGas;
+ type MinBaseFeePerGas = MinBaseFeePerGas;
+ type MaxBaseFeePerGas = MaxBaseFeePerGas;
+ type AdjustmentFactor = GetAdjustmentFactor;
+ type WeightFactor = ConstU128<30_000_000_000_000_000>;
+ type StepLimitRatio = StepLimitRation;
+ type WeightInfo = ();
+}
+
+type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic;
+type Block = frame_system::mocking::MockBlock;
+
+construct_runtime!(
+ pub struct TestRuntime
+ where
+ Block = Block,
+ NodeBlock = Block,
+ UncheckedExtrinsic = UncheckedExtrinsic,
+ {
+ System: frame_system,
+ Timestamp: pallet_timestamp,
+ Balances: pallet_balances,
+ DynamicEvmBaseFee: pallet_dynamic_evm_base_fee,
+ }
+);
+
+const ADJUSTMENT_FACTOR: &[u8] = b":adj_factor_evm";
+
+/// Helper method to set the adjustment factor used by the pallet.
+pub fn set_adjustment_factor(factor: FixedU128) {
+ storage::unhashed::put_raw(&ADJUSTMENT_FACTOR, &factor.encode());
+}
+
+pub struct GetAdjustmentFactor;
+impl Get for GetAdjustmentFactor {
+ fn get() -> FixedU128 {
+ storage::unhashed::get::(&ADJUSTMENT_FACTOR).unwrap_or_default()
+ }
+}
+
+pub struct ExtBuilder;
+impl ExtBuilder {
+ pub fn build() -> TestExternalities {
+ let storage = frame_system::GenesisConfig::default()
+ .build_storage::()
+ .unwrap();
+
+ let mut ext = TestExternalities::from(storage);
+ ext.execute_with(|| {
+ set_adjustment_factor(FixedU128::one());
+ System::set_block_number(1);
+ });
+ ext
+ }
+}
+
+/// Ideal `base fee per gas` value according to the fee alignment formula.
+/// It changes dynamically based on `adjustment factor` and `weight factor` parameters.
+pub fn get_ideal_bfpg() -> U256 {
+ U256::from(
+ ::AdjustmentFactor::get()
+ .saturating_mul_int::(
+ ::WeightFactor::get(),
+ )
+ .saturating_mul(25)
+ .saturating_div(98974),
+ )
+}
+
+/// Max step limit describes how much `base fee per gas` can move in any direction during one block.
+pub fn get_max_step_limit() -> U256 {
+ let bfpg: u128 = BaseFeePerGas::::get().unique_saturated_into();
+ let max_allowed_step: u128 = ::StepLimitRatio::get() * bfpg;
+
+ U256::from(max_allowed_step)
+}
diff --git a/pallets/dynamic-evm-base-fee/src/tests.rs b/pallets/dynamic-evm-base-fee/src/tests.rs
new file mode 100644
index 0000000000..dc65f31fe6
--- /dev/null
+++ b/pallets/dynamic-evm-base-fee/src/tests.rs
@@ -0,0 +1,325 @@
+// This file is part of Astar.
+
+// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd.
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+// Astar is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Astar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Astar. If not, see .
+
+#![cfg(test)]
+
+use super::*;
+use mock::*;
+
+use frame_support::{
+ assert_noop, assert_ok,
+ traits::{Get, OnFinalize},
+};
+use num_traits::Bounded;
+use sp_runtime::{
+ traits::{BadOrigin, One, Zero},
+ FixedU128,
+};
+
+use fp_evm::FeeCalculator;
+
+#[test]
+fn default_base_fee_per_gas_works() {
+ ExtBuilder::build().execute_with(|| {
+ // Genesis state check
+ assert_eq!(
+ BaseFeePerGas::::get(),
+ ::DefaultBaseFeePerGas::get(),
+ "Init bfpg should be equal to the specified default one."
+ )
+ });
+}
+
+#[test]
+fn set_base_fee_per_gas_works() {
+ ExtBuilder::build().execute_with(|| {
+ // sanity check
+ assert_eq!(
+ BaseFeePerGas::::get(),
+ ::DefaultBaseFeePerGas::get()
+ );
+
+ // Ensure we can change the bfpg value via root
+ for new_base_fee_per_gas in [
+ ::MinBaseFeePerGas::get(),
+ ::MaxBaseFeePerGas::get(),
+ ] {
+ assert_ok!(DynamicEvmBaseFee::set_base_fee_per_gas(
+ RuntimeOrigin::root(),
+ new_base_fee_per_gas
+ ));
+ System::assert_last_event(mock::RuntimeEvent::DynamicEvmBaseFee(
+ Event::NewBaseFeePerGas {
+ fee: new_base_fee_per_gas,
+ },
+ ));
+ assert_eq!(BaseFeePerGas::::get(), new_base_fee_per_gas);
+ }
+ });
+}
+
+#[test]
+fn set_base_fee_per_gas_value_out_of_bounds_fails() {
+ ExtBuilder::build().execute_with(|| {
+ // Out of bound values
+ let too_small_base_fee_per_gas =
+ ::MinBaseFeePerGas::get() - 1;
+ let too_big_base_fee_per_gas = ::MaxBaseFeePerGas::get() + 1;
+
+ assert_noop!(
+ DynamicEvmBaseFee::set_base_fee_per_gas(
+ RuntimeOrigin::root(),
+ too_small_base_fee_per_gas
+ ),
+ Error::::ValueOutOfBounds
+ );
+ assert_noop!(
+ DynamicEvmBaseFee::set_base_fee_per_gas(
+ RuntimeOrigin::root(),
+ too_big_base_fee_per_gas
+ ),
+ Error::::ValueOutOfBounds
+ );
+ });
+}
+
+#[test]
+fn set_base_fee_per_gas_non_root_fails() {
+ ExtBuilder::build().execute_with(|| {
+ assert_noop!(
+ DynamicEvmBaseFee::set_base_fee_per_gas(
+ RuntimeOrigin::signed(1),
+ ::MinBaseFeePerGas::get()
+ ),
+ BadOrigin
+ );
+ });
+}
+
+#[test]
+fn min_gas_price_works() {
+ ExtBuilder::build().execute_with(|| {
+ let new_base_fee_per_gas =
+ ::MinBaseFeePerGas::get() + 19 * 17;
+ assert_ok!(DynamicEvmBaseFee::set_base_fee_per_gas(
+ RuntimeOrigin::root(),
+ new_base_fee_per_gas
+ ));
+
+ let expected_weight: Weight =
+ <::WeightInfo as weights::WeightInfo>::min_gas_price();
+ assert_eq!(
+ DynamicEvmBaseFee::min_gas_price(),
+ (new_base_fee_per_gas, expected_weight)
+ );
+ });
+}
+
+#[test]
+fn unit_adjustment_factor_no_change() {
+ ExtBuilder::build().execute_with(|| {
+ // Prep init values - ideal bfpg, and unit adjustment factor
+ let init_bfpg = get_ideal_bfpg();
+ BaseFeePerGas::::set(init_bfpg);
+ set_adjustment_factor(FixedU128::one());
+
+ DynamicEvmBaseFee::on_finalize(1);
+ assert_eq!(
+ BaseFeePerGas::::get(),
+ init_bfpg,
+ "bfpg should remain the same"
+ );
+ });
+}
+
+#[test]
+fn bfpg_bounds_are_respected() {
+ ExtBuilder::build().execute_with(|| {
+ // Lower bound
+ let min_bfpg = ::MinBaseFeePerGas::get();
+ BaseFeePerGas::::set(min_bfpg);
+
+ // This should bring the ideal bfpg value to zero
+ set_adjustment_factor(FixedU128::zero());
+ assert!(get_ideal_bfpg().is_zero(), "Sanity check");
+
+ DynamicEvmBaseFee::on_finalize(1);
+ assert_eq!(
+ BaseFeePerGas::::get(),
+ min_bfpg,
+ "bfpg must not go below lower threshold."
+ );
+
+ // Upper limit
+ let upper_bfpg = ::MaxBaseFeePerGas::get();
+ BaseFeePerGas::::set(upper_bfpg);
+
+ // This should bring the ideal bfpg very high, well above max value
+ set_adjustment_factor(FixedU128::max_value());
+ assert!(get_ideal_bfpg() > upper_bfpg, "Sanity check");
+
+ DynamicEvmBaseFee::on_finalize(2);
+ assert_eq!(
+ BaseFeePerGas::::get(),
+ upper_bfpg,
+ "bfpg must not go above threshold"
+ );
+ });
+}
+
+#[test]
+fn step_limit_ratio_is_respected() {
+ ExtBuilder::build().execute_with(|| {
+ // Lower bound, high adjustment factor
+ let min_bfpg = ::MinBaseFeePerGas::get();
+ BaseFeePerGas::::set(min_bfpg);
+ set_adjustment_factor(FixedU128::max_value());
+ let step_limit = get_max_step_limit();
+
+ DynamicEvmBaseFee::on_finalize(1);
+ assert_eq!(
+ BaseFeePerGas::::get(),
+ min_bfpg + step_limit,
+ "Step limit ratio in ascending direction was not respected."
+ );
+
+ // Upper bound, low adjustment factor
+ let max_bfpg = ::MaxBaseFeePerGas::get();
+ BaseFeePerGas::::set(max_bfpg);
+ set_adjustment_factor(FixedU128::zero());
+ let step_limit = get_max_step_limit();
+
+ DynamicEvmBaseFee::on_finalize(2);
+ assert_eq!(
+ BaseFeePerGas::::get(),
+ max_bfpg - step_limit,
+ "Step limit ratio in descending direction was not respected."
+ );
+ });
+}
+
+#[test]
+fn bfpg_full_spectrum_change_works() {
+ ExtBuilder::build().execute_with(|| {
+ // Set bfpg to lowest possible, and adjustment factor to highest possible
+ let min_bfpg = ::MinBaseFeePerGas::get();
+ BaseFeePerGas::::set(min_bfpg);
+ set_adjustment_factor(FixedU128::max_value());
+
+ // Run for limited amount of iterations until upper bound is reached
+ let target_bfpg = ::MaxBaseFeePerGas::get();
+ let mut counter = 1;
+ let iter_limit = 500_000; // safety limit to avoid endless loop
+ while counter <= iter_limit && BaseFeePerGas::::get() < target_bfpg {
+ DynamicEvmBaseFee::on_finalize(counter);
+ counter += 1;
+ }
+
+ assert_eq!(BaseFeePerGas::::get(), target_bfpg,
+ "bfpg upper bound not reached - either it's not enough iterations or some precision loss occurs.");
+ });
+}
+
+#[test]
+fn bfpg_matches_expected_value_for_so_called_average_transaction() {
+ ExtBuilder::build().execute_with(|| {
+ // The new proposed models suggests to use the following formula to calculate the base fee per gas:
+ //
+ // bfpg = (adj_factor * weight_factor * 25_000) / 9_897_4000
+ let init_bfpg = get_ideal_bfpg();
+ BaseFeePerGas::::set(init_bfpg);
+ let init_adj_factor = ::AdjustmentFactor::get();
+
+ // Slighly increase the adjustment factor, and calculate the new base fee per gas
+ //
+ // To keep it closer to reality, let's assume we're using the proposed variability factor of 0.000_015.
+ // Let's also assume that block fullness difference is 0.01 (1%).
+ // This should result in the adjustment factor of 0.000_001_5.
+ //
+ // NOTE: it's important to keep the increase small so that the step doesn't saturate
+ let change = FixedU128::from_rational(1500, 1_000_000_000);
+ let new_adj_factor = init_adj_factor + change;
+ assert!(new_adj_factor > init_adj_factor, "Sanity check");
+ set_adjustment_factor(new_adj_factor);
+
+ // Calculate the new expected base fee per gas
+ let weight_factor: u128 = ::WeightFactor::get();
+ let expected_bfpg =
+ U256::from(new_adj_factor.saturating_mul_int(weight_factor) * 25_000 / 9_897_4000);
+
+ // Calculate the new base fee per gas in the pallet
+ DynamicEvmBaseFee::on_finalize(1);
+
+ // Assert calculated value is as expected
+ let new_bfpg = BaseFeePerGas::::get();
+ assert!(new_bfpg > init_bfpg, "Sanity check");
+ assert_eq!(new_bfpg, expected_bfpg);
+
+ // Also check the opposite direction
+ let new_adj_factor = init_adj_factor - change;
+ set_adjustment_factor(new_adj_factor);
+ let expected_bfpg =
+ U256::from(new_adj_factor.saturating_mul_int(weight_factor) * 25_000 / 9_897_4000);
+
+ // Calculate the new base fee per gas in the pallet
+ DynamicEvmBaseFee::on_finalize(2);
+ // Assert calculated value is as expected
+ let new_bfpg = BaseFeePerGas::::get();
+ assert!(new_bfpg < init_bfpg, "Sanity check");
+ assert_eq!(new_bfpg, expected_bfpg);
+ });
+}
+
+#[test]
+fn lower_upper_bounds_ignored_if_bfpg_is_outside() {
+ ExtBuilder::build().execute_with(|| {
+ // Set the initial bfpg to be outside of the allowed range.
+ // It's important reduction is sufficient so we're still below the minimum limit after the adjustment.
+ let delta = 100_000_000;
+
+ // First test when bfpg is too little
+ let too_small_bfpg = ::MinBaseFeePerGas::get() - delta;
+ BaseFeePerGas::::set(too_small_bfpg);
+ DynamicEvmBaseFee::on_finalize(1);
+
+ assert!(
+ BaseFeePerGas::::get() > too_small_bfpg,
+ "Bfpg should have increased slightly."
+ );
+ assert!(
+ BaseFeePerGas::::get()
+ < ::MinBaseFeePerGas::get(),
+ "For this test, bfpg should still be below the minimum limit."
+ );
+
+ // Repeat the same test but this time bfpg is too big
+ let too_big_bfpg = ::MaxBaseFeePerGas::get() + delta;
+ BaseFeePerGas::::set(too_big_bfpg);
+ DynamicEvmBaseFee::on_finalize(2);
+
+ assert!(
+ BaseFeePerGas::::get() < too_big_bfpg,
+ "Bfpg should have decreased slightly."
+ );
+ assert!(
+ BaseFeePerGas::::get()
+ < ::MaxBaseFeePerGas::get(),
+ "For this test, bfpg should still be above the maximum limit."
+ );
+ });
+}
diff --git a/pallets/dynamic-evm-base-fee/src/weights.rs b/pallets/dynamic-evm-base-fee/src/weights.rs
new file mode 100644
index 0000000000..46c67f3946
--- /dev/null
+++ b/pallets/dynamic-evm-base-fee/src/weights.rs
@@ -0,0 +1,130 @@
+
+// This file is part of Astar.
+
+// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd.
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+// Astar is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Astar is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Astar. If not, see .
+
+//! Autogenerated weights for pallet_dynamic_evm_base_fee
+//!
+//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
+//! DATE: 2023-09-28, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! WORST CASE MAP SIZE: `1000000`
+//! HOSTNAME: `devserver-01`, CPU: `Intel(R) Xeon(R) E-2236 CPU @ 3.40GHz`
+//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("shibuya-dev"), DB CACHE: 1024
+
+// Executed Command:
+// ./target/release/astar-collator
+// benchmark
+// pallet
+// --chain=shibuya-dev
+// --steps=50
+// --repeat=20
+// --pallet=pallet_dynamic_evm_base_fee
+// --extrinsic=*
+// --execution=wasm
+// --wasm-execution=compiled
+// --heap-pages=4096
+// --output=./benchmark-results/dynamic_evm_base_fee_weights.rs
+// --template=./scripts/templates/weight-template.hbs
+
+#![cfg_attr(rustfmt, rustfmt_skip)]
+#![allow(unused_parens)]
+#![allow(unused_imports)]
+
+use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
+use core::marker::PhantomData;
+
+/// Weight functions needed for pallet_dynamic_evm_base_fee.
+pub trait WeightInfo {
+ fn base_fee_per_gas_adjustment() -> Weight;
+ fn set_base_fee_per_gas() -> Weight;
+ fn min_gas_price() -> Weight;
+}
+
+/// Weights for pallet_dynamic_evm_base_fee using the Substrate node and recommended hardware.
+pub struct SubstrateWeight(PhantomData);
+impl WeightInfo for SubstrateWeight {
+ /// Storage: DynamicEvmBaseFee BaseFeePerGas (r:1 w:1)
+ /// Proof: DynamicEvmBaseFee BaseFeePerGas (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen)
+ /// Storage: TransactionPayment NextFeeMultiplier (r:1 w:0)
+ /// Proof: TransactionPayment NextFeeMultiplier (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen)
+ fn base_fee_per_gas_adjustment() -> Weight {
+ // Proof Size summary in bytes:
+ // Measured: `165`
+ // Estimated: `1517`
+ // Minimum execution time: 8_560_000 picoseconds.
+ Weight::from_parts(8_778_000, 1517)
+ .saturating_add(T::DbWeight::get().reads(2_u64))
+ .saturating_add(T::DbWeight::get().writes(1_u64))
+ }
+ /// Storage: DynamicEvmBaseFee BaseFeePerGas (r:0 w:1)
+ /// Proof: DynamicEvmBaseFee BaseFeePerGas (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen)
+ fn set_base_fee_per_gas() -> Weight {
+ // Proof Size summary in bytes:
+ // Measured: `0`
+ // Estimated: `0`
+ // Minimum execution time: 7_883_000 picoseconds.
+ Weight::from_parts(8_060_000, 0)
+ .saturating_add(T::DbWeight::get().writes(1_u64))
+ }
+ /// Storage: DynamicEvmBaseFee BaseFeePerGas (r:1 w:0)
+ /// Proof: DynamicEvmBaseFee BaseFeePerGas (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen)
+ fn min_gas_price() -> Weight {
+ // Proof Size summary in bytes:
+ // Measured: `98`
+ // Estimated: `1517`
+ // Minimum execution time: 4_201_000 picoseconds.
+ Weight::from_parts(4_399_000, 1517)
+ .saturating_add(T::DbWeight::get().reads(1_u64))
+ }
+}
+
+// For backwards compatibility and tests
+impl WeightInfo for () {
+ /// Storage: DynamicEvmBaseFee BaseFeePerGas (r:1 w:1)
+ /// Proof: DynamicEvmBaseFee BaseFeePerGas (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen)
+ /// Storage: TransactionPayment NextFeeMultiplier (r:1 w:0)
+ /// Proof: TransactionPayment NextFeeMultiplier (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen)
+ fn base_fee_per_gas_adjustment() -> Weight {
+ // Proof Size summary in bytes:
+ // Measured: `165`
+ // Estimated: `1517`
+ // Minimum execution time: 8_560_000 picoseconds.
+ Weight::from_parts(8_778_000, 1517)
+ .saturating_add(RocksDbWeight::get().reads(2_u64))
+ .saturating_add(RocksDbWeight::get().writes(1_u64))
+ }
+ /// Storage: DynamicEvmBaseFee BaseFeePerGas (r:0 w:1)
+ /// Proof: DynamicEvmBaseFee BaseFeePerGas (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen)
+ fn set_base_fee_per_gas() -> Weight {
+ // Proof Size summary in bytes:
+ // Measured: `0`
+ // Estimated: `0`
+ // Minimum execution time: 7_883_000 picoseconds.
+ Weight::from_parts(8_060_000, 0)
+ .saturating_add(RocksDbWeight::get().writes(1_u64))
+ }
+ /// Storage: DynamicEvmBaseFee BaseFeePerGas (r:1 w:0)
+ /// Proof: DynamicEvmBaseFee BaseFeePerGas (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen)
+ fn min_gas_price() -> Weight {
+ // Proof Size summary in bytes:
+ // Measured: `98`
+ // Estimated: `1517`
+ // Minimum execution time: 4_201_000 picoseconds.
+ Weight::from_parts(4_399_000, 1517)
+ .saturating_add(RocksDbWeight::get().reads(1_u64))
+ }
+}
diff --git a/runtime/local/Cargo.toml b/runtime/local/Cargo.toml
index 82bddf6272..fd32fdf941 100644
--- a/runtime/local/Cargo.toml
+++ b/runtime/local/Cargo.toml
@@ -11,6 +11,7 @@ repository.workspace = true
log = { workspace = true, optional = true }
parity-scale-codec = { workspace = true }
scale-info = { workspace = true }
+smallvec = { workspace = true }
fp-rpc = { workspace = true }
fp-self-contained = { workspace = true }
@@ -20,7 +21,6 @@ frame-system = { workspace = true }
pallet-assets = { workspace = true }
pallet-aura = { workspace = true }
pallet-balances = { workspace = true }
-pallet-base-fee = { workspace = true }
pallet-collective = { workspace = true }
pallet-contracts = { workspace = true }
pallet-contracts-primitives = { workspace = true }
@@ -70,6 +70,7 @@ pallet-block-reward = { workspace = true }
pallet-chain-extension-dapps-staking = { workspace = true }
pallet-chain-extension-xvm = { workspace = true }
pallet-dapps-staking = { workspace = true }
+pallet-dynamic-evm-base-fee = { workspace = true }
pallet-evm-precompile-assets-erc20 = { workspace = true }
pallet-evm-precompile-dapps-staking = { workspace = true }
pallet-evm-precompile-sr25519 = { workspace = true }
@@ -116,7 +117,7 @@ std = [
"pallet-chain-extension-dapps-staking/std",
"pallet-chain-extension-xvm/std",
"pallet-dapps-staking/std",
- "pallet-base-fee/std",
+ "pallet-dynamic-evm-base-fee/std",
"pallet-ethereum/std",
"pallet-evm/std",
"pallet-evm-precompile-blake2/std",
@@ -186,6 +187,7 @@ runtime-benchmarks = [
"pallet-unified-accounts/runtime-benchmarks",
"astar-primitives/runtime-benchmarks",
"pallet-assets/runtime-benchmarks",
+ "pallet-dynamic-evm-base-fee/runtime-benchmarks",
]
try-runtime = [
"fp-self-contained/try-runtime",
@@ -216,7 +218,7 @@ try-runtime = [
"pallet-proxy/try-runtime",
"pallet-treasury/try-runtime",
"pallet-preimage/try-runtime",
- "pallet-base-fee/try-runtime",
+ "pallet-dynamic-evm-base-fee/try-runtime",
"pallet-evm/try-runtime",
"pallet-ethereum-checked/try-runtime",
]
diff --git a/runtime/local/src/lib.rs b/runtime/local/src/lib.rs
index be79454ca0..b372b6bdbf 100644
--- a/runtime/local/src/lib.rs
+++ b/runtime/local/src/lib.rs
@@ -31,8 +31,9 @@ use frame_support::{
EqualPrivilegeOnly, FindAuthor, Get, InstanceFilter, Nothing, OnFinalize, WithdrawReasons,
},
weights::{
- constants::{RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND},
- ConstantMultiplier, IdentityFee, Weight,
+ constants::{ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND},
+ ConstantMultiplier, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients,
+ WeightToFeePolynomial,
},
ConsensusEngineId, PalletId,
};
@@ -44,6 +45,7 @@ use pallet_ethereum::PostLogContent;
use pallet_evm::{FeeCalculator, GasWeightMapping, Runner};
use pallet_evm_precompile_assets_erc20::AddressToAssetId;
use pallet_grandpa::{fg_primitives, AuthorityList as GrandpaAuthorityList};
+use pallet_transaction_payment::{CurrencyAdapter, Multiplier, TargetedFeeAdjustment};
use parity_scale_codec::{Compact, Decode, Encode, MaxEncodedLen};
use sp_api::impl_runtime_apis;
use sp_core::{crypto::KeyTypeId, ConstBool, OpaqueMetadata, H160, H256, U256};
@@ -54,7 +56,7 @@ use sp_runtime::{
DispatchInfoOf, Dispatchable, NumberFor, PostDispatchInfoOf, UniqueSaturatedInto,
},
transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError},
- ApplyExtrinsicResult, RuntimeDebug,
+ ApplyExtrinsicResult, FixedPointNumber, Perbill, Permill, Perquintill, RuntimeDebug,
};
use sp_std::prelude::*;
@@ -72,12 +74,9 @@ pub use frame_system::Call as SystemCall;
pub use pallet_balances::Call as BalancesCall;
pub use pallet_grandpa::AuthorityId as GrandpaId;
pub use pallet_timestamp::Call as TimestampCall;
-use pallet_transaction_payment::CurrencyAdapter;
pub use sp_consensus_aura::sr25519::AuthorityId as AuraId;
#[cfg(any(feature = "std", test))]
pub use sp_runtime::BuildStorage;
-pub use sp_runtime::{Perbill, Permill};
-
#[cfg(feature = "std")]
/// Wasm binary unwrapped. If built with `BUILD_DUMMY_WASM_BINARY`, the function panics.
pub fn wasm_binary_unwrap() -> &'static [u8] {
@@ -331,18 +330,81 @@ impl pallet_assets::Config for Runtime {
type BenchmarkHelper = astar_primitives::benchmarks::AssetsBenchmarkHelper;
}
+// These values are based on the Astar 2.0 Tokenomics Modeling report.
parameter_types! {
- pub const TransactionByteFee: Balance = 1;
+ pub const TransactionLengthFeeFactor: Balance = 23_500_000_000_000; // 0.000_023_500_000_000_000 SBY per byte
+ pub const WeightFeeFactor: Balance = 30_855_000_000_000_000; // Around 0.03 SBY per unit of ref time.
+ pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(25);
pub const OperationalFeeMultiplier: u8 = 5;
+ pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(1, 666_667); // 0.000_015
+ pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 10); // 0.1
+ pub MaximumMultiplier: Multiplier = Multiplier::saturating_from_integer(10); // 10
+}
+
+/// Handles converting a weight scalar to a fee value, based on the scale and granularity of the
+/// node's balance type.
+///
+/// This should typically create a mapping between the following ranges:
+/// - [0, MAXIMUM_BLOCK_WEIGHT]
+/// - [Balance::min, Balance::max]
+///
+/// Yet, it can be used for any other sort of change to weight-fee. Some examples being:
+/// - Setting it to `0` will essentially disable the weight fee.
+/// - Setting it to `1` will cause the literal `#[weight = x]` values to be charged.
+pub struct WeightToFee;
+impl WeightToFeePolynomial for WeightToFee {
+ type Balance = Balance;
+ fn polynomial() -> WeightToFeeCoefficients {
+ let p = WeightFeeFactor::get();
+ let q = Balance::from(ExtrinsicBaseWeight::get().ref_time());
+ smallvec::smallvec![WeightToFeeCoefficient {
+ degree: 1,
+ negative: false,
+ coeff_frac: Perbill::from_rational(p % q, q),
+ coeff_integer: p / q,
+ }]
+ }
}
impl pallet_transaction_payment::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type OnChargeTransaction = CurrencyAdapter;
- type WeightToFee = IdentityFee;
+ type WeightToFee = WeightToFee;
type OperationalFeeMultiplier = OperationalFeeMultiplier;
- type FeeMultiplierUpdate = ();
- type LengthToFee = ConstantMultiplier;
+ type FeeMultiplierUpdate = TargetedFeeAdjustment<
+ Self,
+ TargetBlockFullness,
+ AdjustmentVariable,
+ MinimumMultiplier,
+ MaximumMultiplier,
+ >;
+ type LengthToFee = ConstantMultiplier;
+}
+
+parameter_types! {
+ pub DefaultBaseFeePerGas: U256 = U256::from(1_470_000_000_000_u128);
+ pub MinBaseFeePerGas: U256 = U256::from(800_000_000_000_u128);
+ pub MaxBaseFeePerGas: U256 = U256::from(80_000_000_000_000_u128);
+ pub StepLimitRatio: Perquintill = Perquintill::from_rational(5_u128, 100_000);
+}
+
+/// Simple wrapper for fetching current native transaction fee weight fee multiplier.
+pub struct AdjustmentFactorGetter;
+impl Get for AdjustmentFactorGetter {
+ fn get() -> Multiplier {
+ pallet_transaction_payment::NextFeeMultiplier::::get()
+ }
+}
+
+impl pallet_dynamic_evm_base_fee::Config for Runtime {
+ type RuntimeEvent = RuntimeEvent;
+ type DefaultBaseFeePerGas = DefaultBaseFeePerGas;
+ type MinBaseFeePerGas = MinBaseFeePerGas;
+ type MaxBaseFeePerGas = MaxBaseFeePerGas;
+ type AdjustmentFactor = AdjustmentFactorGetter;
+ type WeightFactor = WeightFeeFactor;
+ type StepLimitRatio = StepLimitRatio;
+ type WeightInfo = pallet_dynamic_evm_base_fee::weights::SubstrateWeight;
}
parameter_types! {
@@ -477,33 +539,6 @@ impl pallet_xvm::Config for Runtime {
type WeightInfo = pallet_xvm::weights::SubstrateWeight;
}
-parameter_types! {
- // Tells `pallet_base_fee` whether to calculate a new BaseFee `on_finalize` or not.
- pub DefaultBaseFeePerGas: U256 = (MILLIAST / 1_000_000).into();
- // At the moment, we don't use dynamic fee calculation for local chain by default
- pub DefaultElasticity: Permill = Permill::zero();
-}
-
-pub struct BaseFeeThreshold;
-impl pallet_base_fee::BaseFeeThreshold for BaseFeeThreshold {
- fn lower() -> Permill {
- Permill::zero()
- }
- fn ideal() -> Permill {
- Permill::from_parts(500_000)
- }
- fn upper() -> Permill {
- Permill::from_parts(1_000_000)
- }
-}
-
-impl pallet_base_fee::Config for Runtime {
- type RuntimeEvent = RuntimeEvent;
- type Threshold = BaseFeeThreshold;
- type DefaultBaseFeePerGas = DefaultBaseFeePerGas;
- type DefaultElasticity = DefaultElasticity;
-}
-
/// Current approximation of the gas/s consumption considering
/// EVM execution over compiled WASM (on 4.4Ghz CPU).
/// Given the 500ms Weight, from which 75% only are used for transactions,
@@ -552,7 +587,7 @@ parameter_types! {
}
impl pallet_evm::Config for Runtime {
- type FeeCalculator = BaseFee;
+ type FeeCalculator = DynamicEvmBaseFee;
type GasWeightMapping = pallet_evm::FixedGasWeightMapping;
type WeightPerGas = WeightPerGas;
type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping;
@@ -891,7 +926,7 @@ impl InstanceFilter for ProxyType {
| RuntimeCall::DappsStaking(..)
// Skip entire EVM pallet
// Skip entire Ethereum pallet
- | RuntimeCall::BaseFee(..)
+ | RuntimeCall::DynamicEvmBaseFee(..)
// Skip entire Contracts pallet
| RuntimeCall::Democracy(..)
| RuntimeCall::Council(..)
@@ -989,7 +1024,7 @@ construct_runtime!(
TransactionPayment: pallet_transaction_payment,
EVM: pallet_evm,
Ethereum: pallet_ethereum,
- BaseFee: pallet_base_fee,
+ DynamicEvmBaseFee: pallet_dynamic_evm_base_fee,
Contracts: pallet_contracts,
Sudo: pallet_sudo,
Assets: pallet_assets,
@@ -1117,6 +1152,7 @@ mod benches {
[pallet_dapps_staking, DappsStaking]
[pallet_block_reward, BlockReward]
[pallet_ethereum_checked, EthereumChecked]
+ [pallet_dynamic_evm_base_fee, DynamicEvmBaseFee]
);
}
@@ -1509,7 +1545,7 @@ impl_runtime_apis! {
}
fn elasticity() -> Option {
- Some(pallet_base_fee::Elasticity::::get())
+ Some(Permill::zero())
}
fn gas_limit_multiplier_support() {}
diff --git a/runtime/shibuya/Cargo.toml b/runtime/shibuya/Cargo.toml
index eecc607ce7..dae784a038 100644
--- a/runtime/shibuya/Cargo.toml
+++ b/runtime/shibuya/Cargo.toml
@@ -41,7 +41,6 @@ pallet-assets = { workspace = true }
pallet-aura = { workspace = true }
pallet-authorship = { workspace = true }
pallet-balances = { workspace = true }
-pallet-base-fee = { workspace = true }
pallet-collective = { workspace = true }
pallet-contracts = { workspace = true }
pallet-contracts-primitives = { workspace = true }
@@ -101,6 +100,7 @@ pallet-chain-extension-dapps-staking = { workspace = true }
pallet-chain-extension-xvm = { workspace = true }
pallet-collator-selection = { workspace = true }
pallet-dapps-staking = { workspace = true }
+pallet-dynamic-evm-base-fee = { workspace = true }
pallet-ethereum-checked = { workspace = true }
pallet-evm-precompile-assets-erc20 = { workspace = true }
pallet-evm-precompile-batch = { workspace = true }
@@ -166,7 +166,7 @@ std = [
"pallet-contracts-primitives/std",
"pallet-chain-extension-dapps-staking/std",
"pallet-chain-extension-xvm/std",
- "pallet-base-fee/std",
+ "pallet-dynamic-evm-base-fee/std",
"pallet-ethereum/std",
"pallet-preimage/std",
"pallet-evm/std",
@@ -259,6 +259,7 @@ runtime-benchmarks = [
"orml-xtokens/runtime-benchmarks",
"astar-primitives/runtime-benchmarks",
"pallet-assets/runtime-benchmarks",
+ "pallet-dynamic-evm-base-fee/runtime-benchmarks",
]
try-runtime = [
"fp-self-contained/try-runtime",
@@ -301,7 +302,7 @@ try-runtime = [
"parachain-info/try-runtime",
"pallet-xvm/try-runtime",
"pallet-preimage/try-runtime",
- "pallet-base-fee/try-runtime",
+ "pallet-dynamic-evm-base-fee/try-runtime",
"pallet-evm/try-runtime",
"pallet-unified-accounts/try-runtime",
"pallet-ethereum-checked/try-runtime",
diff --git a/runtime/shibuya/src/lib.rs b/runtime/shibuya/src/lib.rs
index be682ea427..a3617a9ac5 100644
--- a/runtime/shibuya/src/lib.rs
+++ b/runtime/shibuya/src/lib.rs
@@ -58,7 +58,7 @@ use sp_inherents::{CheckInherentsResult, InherentData};
use sp_runtime::{
create_runtime_str, generic, impl_opaque_keys,
traits::{
- AccountIdConversion, AccountIdLookup, BlakeTwo256, Block as BlockT, Bounded, ConvertInto,
+ AccountIdConversion, AccountIdLookup, BlakeTwo256, Block as BlockT, ConvertInto,
DispatchInfoOf, Dispatchable, OpaqueKeys, PostDispatchInfoOf, UniqueSaturatedInto,
},
transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError},
@@ -104,7 +104,7 @@ pub const MICROSBY: Balance = 1_000_000_000_000;
pub const MILLISBY: Balance = 1_000 * MICROSBY;
pub const SBY: Balance = 1_000 * MILLISBY;
-pub const STORAGE_BYTE_FEE: Balance = 100 * MICROSBY;
+pub const STORAGE_BYTE_FEE: Balance = MICROSBY;
/// Charge fee for stored bytes and items.
pub const fn deposit(items: u32, bytes: u32) -> Balance {
@@ -115,10 +115,8 @@ pub const fn deposit(items: u32, bytes: u32) -> Balance {
///
/// The slight difference to general `deposit` function is because there is fixed bound on how large the DB
/// key can grow so it doesn't make sense to have as high deposit per item as in the general approach.
-///
-/// TODO: using this requires storage migration (good to test on Shibuya first!)
pub const fn contracts_deposit(items: u32, bytes: u32) -> Balance {
- items as Balance * 4 * MILLISBY + (bytes as Balance) * STORAGE_BYTE_FEE
+ items as Balance * 40 * MICROSBY + (bytes as Balance) * STORAGE_BYTE_FEE
}
/// Change this to adjust the block time.
@@ -639,10 +637,9 @@ impl pallet_vesting::Config for Runtime {
const MAX_VESTING_SCHEDULES: u32 = 28;
}
-// TODO: changing depost per item and per byte to `deposit` function will require storage migration it seems
parameter_types! {
- pub const DepositPerItem: Balance = MILLISBY / 1_000_000;
- pub const DepositPerByte: Balance = MILLISBY / 1_000_000;
+ pub const DepositPerItem: Balance = contracts_deposit(1, 0);
+ pub const DepositPerByte: Balance = contracts_deposit(0, 1);
// Fallback value if storage deposit limit not set by the user
pub const DefaultDepositLimit: Balance = contracts_deposit(16, 16 * 1024);
pub Schedule: pallet_contracts::Schedule = Default::default();
@@ -680,13 +677,15 @@ impl pallet_contracts::Config for Runtime {
type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>;
}
+// These values are based on the Astar 2.0 Tokenomics Modeling report.
parameter_types! {
- pub const TransactionByteFee: Balance = MILLISBY / 100;
+ pub const TransactionLengthFeeFactor: Balance = 23_500_000_000_000; // 0.000_023_500_000_000_000 SBY per byte
+ pub const WeightFeeFactor: Balance = 30_855_000_000_000_000; // Around 0.03 SBY per unit of ref time.
pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(25);
pub const OperationalFeeMultiplier: u8 = 5;
- pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(1, 100_000);
- pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 1_000_000_000u128);
- pub MaximumMultiplier: Multiplier = Bounded::max_value();
+ pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(1, 666_667); // 0.000_015
+ pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 10); // 0.1
+ pub MaximumMultiplier: Multiplier = Multiplier::saturating_from_integer(10); // 10
}
/// Handles converting a weight scalar to a fee value, based on the scale and granularity of the
@@ -703,9 +702,8 @@ pub struct WeightToFee;
impl WeightToFeePolynomial for WeightToFee {
type Balance = Balance;
fn polynomial() -> WeightToFeeCoefficients {
- // in Shibuya, extrinsic base weight (smallest non-zero weight) is mapped to 1/10 mSBY:
- let p = MILLISBY;
- let q = 10 * Balance::from(ExtrinsicBaseWeight::get().ref_time());
+ let p = WeightFeeFactor::get();
+ let q = Balance::from(ExtrinsicBaseWeight::get().ref_time());
smallvec::smallvec![WeightToFeeCoefficient {
degree: 1,
negative: false,
@@ -718,11 +716,12 @@ impl WeightToFeePolynomial for WeightToFee {
pub struct DealWithFees;
impl OnUnbalanced for DealWithFees {
fn on_unbalanceds(mut fees_then_tips: impl Iterator- ) {
- if let Some(mut fees) = fees_then_tips.next() {
+ if let Some(fees) = fees_then_tips.next() {
+ // Burn 80% of fees, rest goes to collators, including 100% of the tips.
+ let (to_burn, mut collators) = fees.ration(80, 20);
if let Some(tips) = fees_then_tips.next() {
- tips.merge_into(&mut fees);
+ tips.merge_into(&mut collators);
}
- let (to_burn, collators) = fees.ration(20, 80);
// burn part of fees
drop(to_burn);
@@ -745,7 +744,33 @@ impl pallet_transaction_payment::Config for Runtime {
MinimumMultiplier,
MaximumMultiplier,
>;
- type LengthToFee = ConstantMultiplier;
+ type LengthToFee = ConstantMultiplier;
+}
+
+parameter_types! {
+ pub DefaultBaseFeePerGas: U256 = U256::from(1_470_000_000_000_u128);
+ pub MinBaseFeePerGas: U256 = U256::from(800_000_000_000_u128);
+ pub MaxBaseFeePerGas: U256 = U256::from(80_000_000_000_000_u128);
+ pub StepLimitRatio: Perquintill = Perquintill::from_rational(5_u128, 100_000);
+}
+
+/// Simple wrapper for fetching current native transaction fee weight fee multiplier.
+pub struct AdjustmentFactorGetter;
+impl Get for AdjustmentFactorGetter {
+ fn get() -> Multiplier {
+ pallet_transaction_payment::NextFeeMultiplier::::get()
+ }
+}
+
+impl pallet_dynamic_evm_base_fee::Config for Runtime {
+ type RuntimeEvent = RuntimeEvent;
+ type DefaultBaseFeePerGas = DefaultBaseFeePerGas;
+ type MinBaseFeePerGas = MinBaseFeePerGas;
+ type MaxBaseFeePerGas = MaxBaseFeePerGas;
+ type AdjustmentFactor = AdjustmentFactorGetter;
+ type WeightFactor = WeightFeeFactor;
+ type StepLimitRatio = StepLimitRatio;
+ type WeightInfo = pallet_dynamic_evm_base_fee::weights::SubstrateWeight;
}
parameter_types! {
@@ -770,33 +795,6 @@ impl pallet_xvm::Config for Runtime {
type WeightInfo = pallet_xvm::weights::SubstrateWeight;
}
-parameter_types! {
- // Tells `pallet_base_fee` whether to calculate a new BaseFee `on_finalize` or not.
- pub DefaultBaseFeePerGas: U256 = (MILLISBY / 1_000_000).into();
- // At the moment, we don't use dynamic fee calculation for Shibuya by default
- pub DefaultElasticity: Permill = Permill::zero();
-}
-
-pub struct BaseFeeThreshold;
-impl pallet_base_fee::BaseFeeThreshold for BaseFeeThreshold {
- fn lower() -> Permill {
- Permill::zero()
- }
- fn ideal() -> Permill {
- Permill::from_parts(500_000)
- }
- fn upper() -> Permill {
- Permill::from_parts(1_000_000)
- }
-}
-
-impl pallet_base_fee::Config for Runtime {
- type RuntimeEvent = RuntimeEvent;
- type Threshold = BaseFeeThreshold;
- type DefaultBaseFeePerGas = DefaultBaseFeePerGas;
- type DefaultElasticity = DefaultElasticity;
-}
-
/// Current approximation of the gas/s consumption considering
/// EVM execution over compiled WASM (on 4.4Ghz CPU).
/// Given the 500ms Weight, from which 75% only are used for transactions,
@@ -839,7 +837,7 @@ parameter_types! {
}
impl pallet_evm::Config for Runtime {
- type FeeCalculator = BaseFee;
+ type FeeCalculator = DynamicEvmBaseFee;
type GasWeightMapping = pallet_evm::FixedGasWeightMapping;
type WeightPerGas = WeightPerGas;
type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping;
@@ -1114,7 +1112,7 @@ impl InstanceFilter for ProxyType {
| RuntimeCall::XcAssetConfig(..)
// Skip entire EVM pallet
// Skip entire Ethereum pallet
- | RuntimeCall::BaseFee(..)
+ | RuntimeCall::DynamicEvmBaseFee(..)
// Skip entire Contracts pallet
| RuntimeCall::Democracy(..)
| RuntimeCall::Council(..)
@@ -1254,7 +1252,7 @@ construct_runtime!(
EVM: pallet_evm = 60,
Ethereum: pallet_ethereum = 61,
- BaseFee: pallet_base_fee = 62,
+ DynamicEvmBaseFee: pallet_dynamic_evm_base_fee = 62,
EVMChainId: pallet_evm_chain_id = 63,
EthereumChecked: pallet_ethereum_checked = 64,
UnifiedAccounts: pallet_unified_accounts = 65,
@@ -1307,17 +1305,40 @@ pub type Executive = frame_executive::Executive<
Migrations,
>;
-// Used to cleanup StateTrieMigration storage - remove once cleanup is done.
+// Used to cleanup BaseFee storage - remove once cleanup is done.
parameter_types! {
- pub const StateTrieMigrationStr: &'static str = "StateTrieMigration";
+ pub const BaseFeeStr: &'static str = "BaseFee";
+}
+
+/// Simple `OnRuntimeUpgrade` logic to prepare Shibuya runtime for `DynamicEvmBaseFee` pallet.
+pub use frame_support::traits::{OnRuntimeUpgrade, StorageVersion};
+pub struct DynamicEvmBaseFeeMigration;
+impl OnRuntimeUpgrade for DynamicEvmBaseFeeMigration {
+ fn on_runtime_upgrade() -> Weight {
+ // Safety check to ensure we don't execute this migration twice
+ if pallet_dynamic_evm_base_fee::BaseFeePerGas::::exists() {
+ return ::DbWeight::get().reads(1);
+ }
+
+ // Set the init value to what was set before on the old `BaseFee` pallet.
+ pallet_dynamic_evm_base_fee::BaseFeePerGas::::put(U256::from(1_000_000_000_u128));
+
+ // Shibuya's multiplier is so low that we have to set it to minimum value directly.
+ pallet_transaction_payment::NextFeeMultiplier::::put(MinimumMultiplier::get());
+
+ // Set init storage version for the pallet
+ StorageVersion::new(1).put::>();
+
+ ::DbWeight::get().reads_writes(1, 3)
+ }
}
/// All migrations that will run on the next runtime upgrade.
///
/// Once done, migrations should be removed from the tuple.
pub type Migrations = (
- frame_support::migrations::RemovePallet,
- pallet_contracts::Migration,
+ frame_support::migrations::RemovePallet,
+ DynamicEvmBaseFeeMigration,
);
type EventRecord = frame_system::EventRecord<
@@ -1402,6 +1423,7 @@ mod benches {
[pallet_xcm, PolkadotXcm]
[pallet_ethereum_checked, EthereumChecked]
[pallet_xvm, Xvm]
+ [pallet_dynamic_evm_base_fee, DynamicEvmBaseFee]
[pallet_unified_accounts, UnifiedAccounts]
);
}
@@ -1765,7 +1787,7 @@ impl_runtime_apis! {
}
fn elasticity() -> Option {
- Some(pallet_base_fee::Elasticity::::get())
+ Some(Permill::zero())
}
fn gas_limit_multiplier_support() {}
diff --git a/tests/integration/src/setup.rs b/tests/integration/src/setup.rs
index aa46e80b12..d0de6fb599 100644
--- a/tests/integration/src/setup.rs
+++ b/tests/integration/src/setup.rs
@@ -211,13 +211,17 @@ pub fn run_to_block(n: u32) {
while System::block_number() < n {
let block_number = System::block_number();
Timestamp::set_timestamp(block_number as u64 * BLOCK_TIME);
+ TransactionPayment::on_finalize(block_number);
DappsStaking::on_finalize(block_number);
Authorship::on_finalize(block_number);
Session::on_finalize(block_number);
AuraExt::on_finalize(block_number);
PolkadotXcm::on_finalize(block_number);
Ethereum::on_finalize(block_number);
+ #[cfg(any(feature = "shiden", features = "astar"))]
BaseFee::on_finalize(block_number);
+ #[cfg(any(feature = "shibuya"))]
+ DynamicEvmBaseFee::on_finalize(block_number);
System::set_block_number(block_number + 1);
@@ -227,7 +231,10 @@ pub fn run_to_block(n: u32) {
Aura::on_initialize(block_number);
AuraExt::on_initialize(block_number);
Ethereum::on_initialize(block_number);
+ #[cfg(any(feature = "shiden", features = "astar"))]
BaseFee::on_initialize(block_number);
+ #[cfg(any(feature = "shibuya"))]
+ DynamicEvmBaseFee::on_initialize(block_number);
#[cfg(any(feature = "shibuya", feature = "shiden", features = "astar"))]
RandomnessCollectiveFlip::on_initialize(block_number);
diff --git a/tests/integration/src/xvm.rs b/tests/integration/src/xvm.rs
index 0ec64a74f7..bf179f5ab5 100644
--- a/tests/integration/src/xvm.rs
+++ b/tests/integration/src/xvm.rs
@@ -762,7 +762,7 @@ fn calling_wasm_from_evm_works_if_sufficient_storage_deposit_limit() {
let wasm_callee_addr = deploy_wasm_contract(WASM_SIMPLE_STORAGE_NAME);
let evm_caller_addr = deploy_evm_contract(CALL_XVM_PAYABLE_WITH_SDL);
- // Fund the EVM caller to pay for storage deposit.
+ // Fund the EVM contract to pay for storage deposit.
let _ = Balances::deposit_creating(&account_id_from(evm_caller_addr.clone()), UNIT);
assert_ok!(EVM::call(
@@ -772,8 +772,8 @@ fn calling_wasm_from_evm_works_if_sufficient_storage_deposit_limit() {
// to: 0x0e0ddb5a5f0b99d7be468a3051a94073ec6b1900178316401a52b93415026999
// input: 0x0000002a (store)
// value: 0
- // storage_deposit_limit: 1_000_000_000_000
- hex::decode("2d9338da000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e8d4a5100000000000000000000000000000000000000000000000000000000000000000200e0ddb5a5f0b99d7be468a3051a94073ec6b1900178316401a52b9341502699900000000000000000000000000000000000000000000000000000000000000040000002a00000000000000000000000000000000000000000000000000000000").expect("invalid call input hex"),
+ // storage_deposit_limit: 1_000_000_000_000_000
+ hex::decode("2d9338da000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000038d7ea4c6800000000000000000000000000000000000000000000000000000000000000000200e0ddb5a5f0b99d7be468a3051a94073ec6b1900178316401a52b9341502699900000000000000000000000000000000000000000000000000000000000000040000002a00000000000000000000000000000000000000000000000000000000").expect("invalid call input hex"),
U256::zero(),
1_000_000,
U256::from(DefaultBaseFeePerGas::get()),