Files
evm/core/fee_split.go
T
zeekayandHanzo Dev 1abb712fe8 core: C-Chain tx-fee disbursement seam — creditTxFee (50/50 split dormant)
Single fee-disbursement seam in state_transition.go delegates to creditTxFee
(core/fee_split.go): full-fee-to-coinbase legacy path by default, or a
deterministic 50%-true-burn + 50%-to-FeeRewardVault (0x0100..0002) split once
the standalone FeeSplitTimestamp fork is active. Gated OFF everywhere
(FeeSplitTimestamp nil) so the LIVE path stays RewardManager -> DAO Gov Safe;
this is the ready in-protocol-split option the DAO can enable later.

Proven (CGO off): fee_split_test (split math, conservation, odd-wei, determinism,
legacy), fee_split_block_test (end-to-end burn on accepted blocks),
reward_manager_routing_test (100% -> DAO Safe + live on-chain setRewardAddress
redirect). params/extras suite green incl. the 3 mainnet boot-compat guards.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-17 17:12:55 -07:00

49 lines
2.4 KiB
Go

// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package core
import (
"github.com/holiman/uint256"
"github.com/luxfi/evm/params"
"github.com/luxfi/evm/params/extras"
"github.com/luxfi/geth/common"
"github.com/luxfi/geth/core/tracing"
"github.com/luxfi/geth/core/vm"
ethparams "github.com/luxfi/geth/params"
)
// creditTxFee disburses the fee paid by a single transaction.
//
// Legacy behavior (FeeSplit inactive) — the full fee is credited to the coinbase
// (the blackhole 0x0100..00 on the C-Chain), matching historical Subnet-EVM.
//
// FeeSplit active — the fee is divided 50/50, deterministically:
//
// - rewardShare = fee / 2 (floor) -> credited to extras.FeeRewardVault.
// This half stays in circulation, parked in a protocol-owned account, to be
// atomically exported to the P-Chain staking-reward pool where it is paid out
// through the native staking-reward path (see the "Tx-fee 50/50 split" design
// in LLM.md). It is NOT minted; it is moved, so it can never double-mint.
//
// - burnShare = fee - rewardShare (ceil) -> credited to NO account.
// Never re-crediting it removes it from the account trie, i.e. the sum of all
// balances (the supply) decreases by exactly burnShare every transaction. This
// is a TRUE burn — identical in mechanism to the EIP-1559 base-fee burn — not a
// transfer to a dead address (which would leave supply unchanged).
//
// Determinism: fee is a consensus value (gasUsed * effectiveGasPrice); the split
// is pure uint256 integer arithmetic (a single right shift) to a fixed address, so
// every validator computes an identical post-state and the split cannot fork the
// chain. The odd wei on an odd fee is assigned to the burn (conservative: it never
// over-credits the reward side, and it keeps burn >= reward exactly).
func creditTxFee(stateDB vm.StateDB, config *ethparams.ChainConfig, coinbase common.Address, blockTime uint64, fee *uint256.Int) {
if cfg := params.GetExtra(config); cfg != nil && cfg.IsFeeSplit(blockTime) {
rewardShare := new(uint256.Int).Rsh(fee, 1) // floor(fee/2)
stateDB.AddBalance(extras.FeeRewardVault, rewardShare, tracing.BalanceIncreaseRewardTransactionFee)
// burnShare = fee - rewardShare is intentionally left uncredited (true burn).
return
}
stateDB.AddBalance(coinbase, fee, tracing.BalanceIncreaseRewardTransactionFee)
}