I've implemented a POA EVM-Compatible chain using the Frontier node template on branch polkadot-v0.9.22.
I've Implemented a DealWithFees struct and let some part of fees be added to a treasury i've implemented. I'm running all the defaults which came with Frontier's node template having made no changes to pallet evm, ethereum, baseFee or dynamic_fee's configs.
Ive set pallet EVM's OnChargeTransaction to EVMCurrencyAdapter<Balances, DealWithFees>.
But after executing an EVM transaction, no change is observed in the treasury.
NOTE I have fixed the fee for every transaction at 250,000,000,000 balance.
pub struct ToAuthor<R>(sp_std::marker::PhantomData<R>);
impl<R> OnUnbalanced<NegativeImbalance<R>> for ToAuthor<R>
where
R: pallet_balances::Config + pallet_authorship::Config,
<R as frame_system::Config>::AccountId: From<AccountId>,
<R as frame_system::Config>::AccountId: Into<AccountId>,
<R as frame_system::Config>::Event: From<pallet_balances::Event<R>>,
{
fn on_nonzero_unbalanced(amount: NegativeImbalance<R>) {
if let Some(author) = <pallet_authorship::Pallet<R>>::author() {
<pallet_balances::Pallet<R>>::resolve_creating(&author, amount);
}
}
}
pub struct DealWithFees<R>(sp_std::marker::PhantomData<R>);
impl<R> OnUnbalanced<NegativeImbalance<R>> for DealWithFees<R>
where
R: pallet_balances::Config + pallet_treasury::Config + pallet_authorship::Config,
pallet_treasury::Pallet<R>: OnUnbalanced<NegativeImbalance<R>>,
<R as frame_system::Config>::AccountId: From<AccountId>,
<R as frame_system::Config>::AccountId: Into<AccountId>,
<R as frame_system::Config>::Event: From<pallet_balances::Event<R>>,
{
fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item = NegativeImbalance<R>>) {
if let Some(fees) = fees_then_tips.next() {
// for fees, 75% to treasury, 25% to author
let mut split = fees.ration(75, 25);
if let Some(tips) = fees_then_tips.next() {
// for tips, if any, 100% to author
tips.merge_into(&mut split.1);
}
use pallet_treasury::Pallet as Treasury;
<Treasury<R> as OnUnbalanced<_>>::on_unbalanced(split.0);
<ToAuthor<R> as OnUnbalanced<_>>::on_unbalanced(split.1);
}
}
}
const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
/// We allow for 2 seconds of compute with a 6 second average block time.
pub const MAXIMUM_BLOCK_WEIGHT: Weight = 2 * WEIGHT_PER_SECOND;
const WEIGHT_PER_GAS: u64 = 20_000;
pub struct ConstantFee<T>(sp_std::marker::PhantomData<T>);
impl<T> WeightToFeePolynomial for ConstantFee<T>
where
T: BaseArithmetic + From<u32> + Copy + Unsigned + From<u64>,
{
type Balance = T;
fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {
let fee: u64 = (DOLLARS * 25).try_into().unwrap();
smallvec!(WeightToFeeCoefficient {
coeff_integer: fee.into(),
coeff_frac: Perbill::zero(),
negative: false,
degree: 0,
})
}
fn calc(_weight: &Weight) -> Self::Balance {
let fee: u64 = (DOLLARS * 25).try_into().unwrap();
return fee.into();
}
}
parameter_types! {
pub const TransactionByteFee: Balance = 1;
}
impl pallet_transaction_payment::Config for Runtime {
type OnChargeTransaction = CurrencyAdapter<Balances, DealWithFees<Runtime>>;
type OperationalFeeMultiplier = ConstU8<5>;
type WeightToFee = ConstantFee<Balance>;
type LengthToFee = ConstantMultiplier<Balance, TransactionByteFee>;
parameter_types! {
pub const SpendPeriod: BlockNumber = 6 * DAYS;
pub const TreasuryPalletId: PalletId = PalletId(*b"py/trsry");
/// 5% of proposal value should be reserved from proposer balance,
/// but not less than ProposalBondMinimum.
/// This value would be slashed if proposal rejected.
pub const ProposalBond: Permill = Permill::from_percent(0);
}
impl pallet_treasury::Config for Runtime {
type Currency = Balances;
// Only root for now, governance later.
type ApproveOrigin = EnsureRoot<AccountId>;
// Only root for now, governance later.
type RejectOrigin = EnsureRoot<AccountId>;
type Event = Event;
// If proposal rejected - send deposit to treasury.
type OnSlash = Treasury;
type ProposalBond = ProposalBond;
type ProposalBondMinimum = ();
type ProposalBondMaximum = ();
type SpendPeriod = SpendPeriod;
// Not burning.
type Burn = ();
type PalletId = TreasuryPalletId;
type BurnDestination = ();
type WeightInfo = ();
type SpendFunds = ();
type MaxApprovals = ConstU32<100>;
}
parameter_types! {
pub const UncleGenerations: BlockNumber = 5;
}
impl pallet_authorship::Config for Runtime {
type FindAuthor = pallet_session::FindAccountFromAuthorIndex<Self, Aura>;
type UncleGenerations = UncleGenerations;
type FilterUncle = ();
type EventHandler = ();
}
pub struct FindAuthorTruncated<F>(PhantomData<F>);
impl<F: FindAuthor<u32>> FindAuthor<H160> for FindAuthorTruncated<F> {
fn find_author<'a, I>(digests: I) -> Option<H160>
where
I: 'a + IntoIterator<Item = (ConsensusEngineId, &'a [u8])>,
{
if let Some(author_index) = F::find_author(digests) {
let authority_id = Aura::authorities()[author_index as usize].clone();
return Some(H160::from_slice(&authority_id.to_raw_vec()[4..24]));
}
None
}
}
pub struct FixedGasWeightMapping;
impl GasWeightMapping for FixedGasWeightMapping {
fn gas_to_weight(gas: u64) -> Weight {
gas.saturating_mul(WEIGHT_PER_GAS)
}
fn weight_to_gas(weight: Weight) -> u64 {
weight.wrapping_div(WEIGHT_PER_GAS)
}
}
parameter_types! {
pub const ChainId: u64 = 421;
pub BlockGasLimit: U256 = U256::from(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT / WEIGHT_PER_GAS);
pub PrecompilesValue: FrontierPrecompiles<Runtime> = FrontierPrecompiles::<_>::new();
}
impl pallet_evm::Config for Runtime {
type FeeCalculator = BaseFee;
type GasWeightMapping = FixedGasWeightMapping;
type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping<Self>;
type CallOrigin = EnsureAddressTruncated;
type WithdrawOrigin = EnsureAddressTruncated;
type AddressMapping = HashedAddressMapping<BlakeTwo256>;
type Currency = Balances;
type Event = Event;
type Runner = pallet_evm::runner::stack::Runner<Self>;
type PrecompilesType = FrontierPrecompiles<Self>;
type PrecompilesValue = PrecompilesValue;
type ChainId = ChainId;
type BlockGasLimit = BlockGasLimit;
type OnChargeTransaction = EVMCurrencyAdapter<Balances, DealWithFees<Runtime>>;
type FindAuthor = FindAuthorTruncated<Aura>;
}
impl pallet_ethereum::Config for Runtime {
type Event = Event;
type StateRoot = pallet_ethereum::IntermediateStateRoot<Self>;
}
frame_support::parameter_types! {
pub BoundDivision: U256 = U256::from(1024);
}
impl pallet_dynamic_fee::Config for Runtime {
type MinGasPriceBoundDivisor = BoundDivision;
}
frame_support::parameter_types! {
pub IsActive: bool = false;
pub DefaultBaseFeePerGas: U256 = U256::from(1_000_000_000);
}
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 Event = Event;
type Threshold = BaseFeeThreshold;
type IsActive = IsActive;
type DefaultBaseFeePerGas = DefaultBaseFeePerGas;
}
impl pallet_hotfix_sufficients::Config for Runtime {
type AddressMapping = HashedAddressMapping<BlakeTwo256>;
type WeightInfo = ();
}