diff --git a/template/runtime/RUNTIME_VERSIONS.md b/template/runtime/RUNTIME_VERSIONS.md index 50481d40..1ed193cf 100644 --- a/template/runtime/RUNTIME_VERSIONS.md +++ b/template/runtime/RUNTIME_VERSIONS.md @@ -32,7 +32,8 @@ sign through the new `Ed25519Text` (`0x03`) and `Ed25519WrappedText` (`0x04`). Circuit keys: unsound ones are recorded on chain and never verify again, a removed version keeps its key, and a key without phase 2 is refused. Shielded pool: a replaced root stays spendable for a full window, and spends -creating the same note are exclusive in the pool. +creating the same note are exclusive in the pool. Substrate fees price weight +and bytes like EVM gas. `transaction_version` is unchanged. Ships with `pallet-evm-precompile-balances` 0.2.0, `pallet-zk-verifier` 0.19.0, `orbinum-zk-verifier` 3.4.0 and `pallet-shielded-pool` 0.25.2. @@ -140,6 +141,17 @@ creating the same note are exclusive in the pool. change note each `provide` a pool tag, besides the spent nullifiers: two spends creating the same note can no longer both sit in the pool and propagate when only one can execute. +- **Substrate fees aligned with EVM gas.** `WeightToFee` was `IdentityFee`, + 1 wei per unit of `ref_time`, so a transfer cost about 3e-10 ORB: a million + new accounts cost 0.0003 ORB and filling every block for a day about 0.03 ORB. + A unit of `ref_time` now costs the default base fee over `WeightPerGas` + (1 gwei / 20_000 = 50_000 wei) and a byte 16 gas (16 gwei), so an extrinsic + costs what the same weight costs as EVM gas: a transfer about 1.6e-5 ORB, as + over EVM. `ExistentialDeposit` stays 0: above it, an EVM account emptied by a + Substrate transfer is reaped, its nonce returns to 0 and its earlier signed + transactions can be replayed, and the shielded pool's account could burn the + remainder backing pending fees. Unsigned spends (`MinSpendFee`) and Root calls + are unchanged. ### spec 19 — tx 7 — 2026-10-13 (`v0.5.0`) diff --git a/template/runtime/src/configs/system.rs b/template/runtime/src/configs/system.rs index c51d3e30..34aa1931 100644 --- a/template/runtime/src/configs/system.rs +++ b/template/runtime/src/configs/system.rs @@ -81,11 +81,22 @@ impl pallet_balances::Config for Runtime { type DoneSlashHandler = (); } +parameter_types! { + /// Fee per unit of `ref_time`: what the same weight costs as EVM gas at the + /// default base fee (1 gwei / 20_000 weight per gas = 50_000 wei). A + /// Substrate extrinsic costs what the equivalent EVM transaction does, + /// instead of 1 wei per unit, which made accounts and blocks nearly free. + pub WeightFee: Balance = (DefaultBaseFeePerGas::get() + / U256::from(WeightPerGas::get().ref_time())).low_u128(); + /// Fee per encoded byte: EVM calldata's 16 gas per non-zero byte. + pub LengthFee: Balance = (DefaultBaseFeePerGas::get() * U256::from(16)).low_u128(); +} + impl pallet_transaction_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; type OnChargeTransaction = FungibleAdapter; - type WeightToFee = IdentityFee; - type LengthToFee = IdentityFee; + type WeightToFee = ConstantMultiplier; + type LengthToFee = ConstantMultiplier; /// Parameterized slow adjusting fee updated based on /// type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; diff --git a/template/runtime/src/lib.rs b/template/runtime/src/lib.rs index dd6f75be..5061c63d 100644 --- a/template/runtime/src/lib.rs +++ b/template/runtime/src/lib.rs @@ -38,7 +38,7 @@ use frame_support::{ genesis_builder_helper::build_state, parameter_types, traits::{ConstBool, ConstU32, ConstU64, ConstU8, OnFinalize, OnTimestampSet}, - weights::{constants::WEIGHT_REF_TIME_PER_MILLIS, IdentityFee, Weight}, + weights::{constants::WEIGHT_REF_TIME_PER_MILLIS, ConstantMultiplier, Weight}, PalletId, }; use pallet_ethereum::{Call::transact, PostLogContent, Transaction as EthereumTransaction}; diff --git a/template/runtime/src/runtime_tests/weights.rs b/template/runtime/src/runtime_tests/weights.rs index 2326c80c..301f68d2 100644 --- a/template/runtime/src/runtime_tests/weights.rs +++ b/template/runtime/src/runtime_tests/weights.rs @@ -8,3 +8,20 @@ fn configured_base_extrinsic_weight_is_evm_compatible() { .base_extrinsic; assert!(base_extrinsic.ref_time() <= min_ethereum_transaction_weight.ref_time()); } + +/// Substrate fees price weight and bytes like EVM gas at the default base fee: +/// the weight of 21_000 gas costs what 21_000 gas does. +#[test] +fn substrate_fees_match_evm_gas() { + use frame_support::weights::WeightToFee as _; + + let base_fee = crate::DefaultBaseFeePerGas::get().low_u128(); + assert_eq!(crate::WeightFee::get(), 50_000); + assert_eq!(crate::LengthFee::get(), 16 * base_fee); + + let transfer = WeightPerGas::get() * 21_000; + assert_eq!( + ::WeightToFee::weight_to_fee(&transfer), + 21_000 * base_fee + ); +}