HIP-1259: Fee Collection Account
| Author | Richard Bair |
|---|---|
| Working Group | Richard Bair, Jasper Potts, Atul Mahamuni, Leemon Baird |
| Requested By | Hashgraph |
| Discussions-To | https://github.com/hiero-ledger/hiero-improvement-proposals/pull/1259 |
| Status | Approved ⓘ |
| Last Call Period Ends ⓘ | Tue, 12 Aug 2025 00:00:00 +0000 |
| Type | Standards Track ⓘ |
| Category | Core ⓘ |
| Created | 2025-07-11 |
Table of Contents
Abstract
This proposal introduces a new network-controlled account, known as the fee collection account (default address 0.0.802), into which all fees are paid. Instead of distributing fees immediately across multiple accounts, the system accumulates them here and performs a single daily transfer at the start of each staking period. This transfer sends the appropriate portions to the admin fee account (0.0.98), staking reward account (0.0.800), node reward account (0.0.801), and individual node accounts. The change simplifies transaction records, reduces block stream size, and improves overall network performance.
Motivation
Every transaction on the network incurs a fee, some of which is paid to the node that submitted the transaction, and the rest to the network as a whole. Currently, these fees are distributed right after each transaction: the node fee goes directly to the submitting node’s account, while the remainder is split among accounts 0.0.98 (typically 80%), 0.0.800 ( typically 10%), and 0.0.801 (typically 10%).
This immediate distribution creates challenges. For a simple crypto transfer between two accounts, the system must read and update up to six accounts: the sender, receiver, submitting node, 0.0.98, 0.0.800, and 0.0.801. This increases processing overhead and slows performance. In the block stream, every transaction must record balance changes for all these accounts, inflating data size and storage costs. Users viewing transactions on explorers like HashScan see a complex web of transfers, which can be confusing even with visualizations.
By collecting all fees in one account and distributing them daily, this HIP reduces account interactions per transaction, shrinks block stream records, and presents users with a single, straightforward fee payment.
Rationale
The core idea is to use a dedicated fee collection account that mirrors the security of accounts 0.0.800 and 0.0.801—no keys, fully code-controlled, and resistant to unauthorized changes. Unlike those accounts, the fee collection account will not be open to HBAR deposits. All fee components flow into this account via a single transfer, minimizing per-transaction work.
To track node fees without immediate payouts, a singleton state in the Merkle tree accumulates amounts owed to each node. This singleton updates once per block, not per transaction, keeping block stream costs low.
Distributions occur once per staking period, before reward calculations, ensuring accurate balances for staking. In special cases where fees route entirely to 0.0.801 (e.g., low balance), the system handles this during payout. If staking rewards apply during a transaction, only 0.0.800 updates—still lightweight due to its simple structure.
This design builds on basic principles: batch operations for efficiency, single-point collection for simplicity, and delayed distributions to align with existing staking cycles.
User Stories
- As a user, I want transaction records to show a simple fee payment, without a tangle of transfers to multiple system accounts.
- As a block node or mirror node operator, I want smaller block streams to lower my data ingestion and storage costs.
- As a network administrator, I want fee handling that maintains incentives for nodes while improving overall throughput.
Specification
Overview
Create a new special account at address 0.0.802 (the actual number is configurable, like 0.0.800 and 0.0.801). This account has no keys, does not accept HBAR transfers, and is controlled solely by network code—preventing token associations or updates of any kind.
Add a singleton state in the Merkle tree called NodePayments. This is a map where each key is a node AccountID
number, and each value is a node receiving node fees.
During transaction handling:
- Calculate fees as usual.
- Add the node fee to the corresponding entry in the
NodePaymentsmap. - Transfer all fees into 0.0.802 via a single entry in the transaction’s transfer list.

The singleton updates the Merkle tree per transaction, but records in the block stream only once per block. Since 0.0.802 has no keys, its block stream record is minimal.
At the end of each staking period, prior to any other transactions or operations:
- Create a synthetic transaction to distribute all hbars from 0.0.802. This single transaction can have a large transfer list accommodating the transfers to all nodes and the special accounts
- Pay node fees from the
NodePaymentsmap to each node’s account.- If for any reason the node’s account cannot accept the fees (i.e. it is deleted or doesn’t exist), then they are forfeit. They will remain in 0.0.802 until step 3
receiverSigRequiredis ignored for payments to node accounts- Hooks are not executed when fees are paid to node accounts
- Split the remaining balance among 0.0.98, 0.0.800, and 0.0.801 per current rules
- Reset
NodePaymentsto an empty map.
This synthetic transaction is recorded in the block stream like any other.
Protobuf Changes
The singleton state is defined in a new protobuf file: services/state/node_payments.proto.
// A singleton state object that accumulates node fees for distribution.
message NodePayments {
// A map from account_number to NodePayment
map<uint64, NodePayment> payments = 1;
}
message NodePayment {
// The node account ID number. This is the last part of the shard.realm.num triplet.
uint64 account_number = 1;
// The total amount in fees due the node, in tinybars
uint64 fees = 2;
}
This message is stored as a singleton leaf in the Merkle tree. As transactions are handled, the payments map is populated and the fees accumulated. Once per staking period, the payments are disbursed and the map is cleared.
Implementation Details
- Fee Calculation: Unchanged.
- Singleton Management: Clear map after disbursement; accumulate during handling.
- Distribution Timing: Trigger at start of staking period.
- Edge Cases: When distributing fees on roster change, If 0.0.801 is low, route fees fully there until it reaches the configured minimum (1M HBARs on Hedera Mainnet), and then distribute as per normal.
- Deposit Rejection: Reject any transaction that would send any hbar to the fee account (crypto transfers, smart contracts, etc). The only item in the transfer list that sends hbars to account 0.0.802 will be the line inserted by the code as a result of fee collection.
Backward Compatibility
Clients see simpler transfers (one to 0.0.802). Explorers like HashScan can update visualizations. Networks upgrade seamlessly, with the new account created on migration/upgrade.
Security Implications
Since account 0.0.802 has no keys, it is free from tampering, even by the elevated permissions of the 0.0.2 account
keys. Since it doesn’t accept HBAR transfers, users cannot accidentally submit it tokens. Since it does not have
automatic associations enabled, no associations or token transfers can complete. While a frictionless airdrop can queue
a transfer for the account, it will never succeed. The account can never be deleted, and is not subject to rent.
No new attack vectors; reduces complexity in per-transaction accounting.
How to Teach This
- For Users: Transactions now show one fee to 0.0.802, simplifying views in explorers. Rewards and penalties still work as before.
- For Developers: No API changes; monitor block streams for the new account and daily synthetic transactions.
- Examples: Compare before/after transaction records; explain daily payout in staking docs.
Rejected Ideas
Allow HBAR transfers into the fee collection account (0.0.802)
There are two reasons for rejecting this:
- It was requested by the mirror node team that we not allow HBAR transfers into this account. “It would make it easier to separate fee transfers from non-fee transfers like Coinbase requires.”
- Avoid accidental credits into this account by users. There’s no way to get the money back out. 0.0.800 requires user donations. But 0.0.801 and 0.0.802 do not, so we shouldn’t allow either of them to get donations. This might require fixing 0.0.801.
Citation
Please cite this document as: