diff --git a/Cargo.lock b/Cargo.lock index 28f586a9b3..e82eced0c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7146,6 +7146,20 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-dynamic-evm-base-fee" +version = "0.1.0" +dependencies = [ + "fp-evm", + "frame-support", + "frame-system", + "pallet-transaction-payment", + "parity-scale-codec", + "scale-info", + "sp-core", + "sp-runtime", +] + [[package]] name = "pallet-election-provider-multi-phase" version = "4.0.0-dev" diff --git a/pallets/dynamic-evm-base-fee/Cargo.toml b/pallets/dynamic-evm-base-fee/Cargo.toml new file mode 100644 index 0000000000..6ba0e41c13 --- /dev/null +++ b/pallets/dynamic-evm-base-fee/Cargo.toml @@ -0,0 +1,43 @@ +[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-support = { workspace = true } +frame-system = { workspace = true } +sp-core = { workspace = true } +sp-runtime = { workspace = true } +pallet-transaction-payment = { workspace = true } + +# Frontier +fp-evm = { workspace = true } + +[features] +default = ["std"] +std = [ + "parity-scale-codec/std", + "scale-info/std", + # Substrate + "frame-support/std", + "frame-system/std", + "sp-core/std", + "sp-runtime/std", + "pallet-transaction-payment/std", + # Frontier + "fp-evm/std", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", + "pallet-transaction-payment/try-runtime", +] 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..7ed9c2cebc --- /dev/null +++ b/pallets/dynamic-evm-base-fee/src/lib.rs @@ -0,0 +1,118 @@ +// 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_attr(not(feature = "std"), no_std)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_core::U256; +use sp_runtime::{traits::Convert, traits::UniqueSaturatedInto}; + +pub use self::pallet::*; + +#[frame_support::pallet] +pub mod pallet { + use frame_support::pallet_prelude::*; + use frame_system::pallet_prelude::*; + + use super::*; + + #[pallet::pallet] + pub struct Pallet(PhantomData); + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: From + IsType<::RuntimeEvent>; + type DefaultBaseFeePerGas: Get; + type MinBaseFeePerGas: Get; + type MaxBaseFeePerGas: Get; + type AdjustmentLogic: Convert; + } + + #[pallet::genesis_config] + pub struct GenesisConfig { + pub base_fee_per_gas: U256, + _marker: PhantomData, + } + + impl Default for GenesisConfig { + fn default() -> Self { + Self { + base_fee_per_gas: T::DefaultBaseFeePerGas::get(), + _marker: PhantomData, + } + } + } + + #[pallet::genesis_build] + impl GenesisBuild for GenesisConfig { + fn build(&self) { + BaseFeePerGas::::put(self.base_fee_per_gas); + } + } + + #[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 { + NewBaseFeePerGas { fee: U256 }, + } + + #[pallet::hooks] + impl Hooks> for Pallet { + fn on_initialize(_: T::BlockNumber) -> Weight { + // TODO: benchmark this! + let db_weight = ::DbWeight::get(); + db_weight.reads_writes(2, 1) + } + + fn on_finalize(_n: ::BlockNumber) { + BaseFeePerGas::::mutate(|base_fee_per_gas| { + let new_base_fee_per_gas = + T::AdjustmentLogic::convert(base_fee_per_gas.clone().unique_saturated_into()); + + *base_fee_per_gas = U256::from(new_base_fee_per_gas) + .clamp(T::MinBaseFeePerGas::get(), T::MaxBaseFeePerGas::get()); + }) + } + } + + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + #[pallet::weight(10_000 + T::DbWeight::get().writes(1).ref_time())] + pub fn set_base_fee_per_gas(origin: OriginFor, fee: U256) -> DispatchResult { + ensure_root(origin)?; + 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::DbWeight::get().reads(1)) + } +} diff --git a/runtime/shibuya/src/lib.rs b/runtime/shibuya/src/lib.rs index 24c352cc60..2ffdf7848f 100644 --- a/runtime/shibuya/src/lib.rs +++ b/runtime/shibuya/src/lib.rs @@ -103,7 +103,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 { @@ -117,7 +117,7 @@ pub const fn deposit(items: u32, bytes: u32) -> Balance { /// /// 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. @@ -735,11 +735,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);