Skip to main content

Understand network revenue routing on your Arbitrum chain

Every transaction on an Arbitrum chain pays a single fee, but under the hood that fee is split into components that travel very different paths before reaching their final destination. Some components are credited to a collector address in the same transaction that paid them, while others are routed through a system pool and paid out after batches are posted.

This page traces the complete life of a transaction fee: which address collects each component, when funds actually move, why block explorers estimate, and how and when to retrieve funds.

To change the fee parameters and collector addresses described here, follow the step by step instructions in How to manage the fee parameters of your Arbitrum chain.

Main fee components

Transaction fees on an Arbitrum chain split into four components, each with its own collector:

Fee componentWhat it coversCollected byPaid out
Arbitrum chain base feeExecution, up to the configured minimum base feeinfraFeeAccountImmediately, per transaction
Arbitrum chain surplus feeExecution paid above the minimum base fee (congestion), plus any priority feesnetworkFeeAccountImmediately, per transaction
Parent chain base feeEstimated cost of posting the transaction's data to the parent chainL1PricerFundsPoolAddress (system pool), then the batch poster's fee collectorAfter each batch posting report
Parent chain surplus feeOptional per data unit reward configured by the chain ownerL1RewardRecipientAfter each batch posting report
Fallback behavior

If infraFeeAccount is not set (the zero address), the entire execution fee (base and surplus) goes to networkFeeAccount. At chain deployment, networkFeeAccount is initialized to the initial chain owner and infraFeeAccount starts unset, so a freshly deployed chain sends all execution fees to the chain owner's address.

The first two components are straightforward: ArbOS credits them to their collector addresses during transaction execution in the same block. The rest of this page focuses on the parent chain base fee and the parent chain surplus fee.

Fee lifecycle

A user pays one gas fee on the child chain. ArbOS splits that fee into two paths. ArbOS credits the execution fee in the same transaction: the Arbitrum chain base fee to infraFeeAccount, and the surplus fee plus priority fees to networkFeeAccount. ArbOS credits the parent chain fee to the L1PricerFundsPoolAddress system pool (0xA4B0…00f6), where it accumulates. Separately, the batch poster posts a batch to SequencerInbox on the parent chain and pays that gas out of pocket. SequencerInbox then sends a batch posting report into the delayed inbox. When ArbOS processes that report, it pays out from the pool: first the parent chain surplus fee to L1RewardRecipient, then the amount due to the batch poster's fee collector.
  1. A user pays the transaction fee. ArbOS estimates the transaction's parent chain footprint by compressing it and multiplying the size by the current price per data unit (its running estimate of parent chain costs). This amount is charged as part of the transaction's gas.

  2. The fee is split at the end of execution. The execution components go directly to infraFeeAccount and networkFeeAccount. The parent chain component is credited to L1PricerFundsPoolAddress (0xA4B00000000000000000000000000000000000f6), a system owned pool with no private key. The pool exists to reimburse whoever ends up paying for batch posting.

  3. The batch poster posts a batch. The batch poster submits your chain's transaction data to the SequencerInbox contract on the parent chain, paying parent chain gas from its own parent chain balance. This is the cost the pool will cover later on.

  4. The parent chain reports the spending. In the same transaction that records the batch, the SequencerInbox contract sends a batch posting report message into your chain's delayed inbox, containing who posted the batch and the parent chain base fee at the time.

  5. ArbOS processes the report and pays out. When the report arrives on the child chain, ArbOS computes what the batch actually cost (reported base fee × the batch's data gas, plus a fixed per batch overhead) and records it as funds due to that batch poster. It then pays, from the pool's balance:

    • First, any parent chain surplus fee owed to the configured reward recipient (reward rate × data units processed).
    • Then, the accumulated amount due to the batch poster, sent to that poster's fee collector address.

    If the pool doesn't hold enough to cover everything owed, the remainder stays on the books as funds due and is paid from future collections.

  6. The price adjusts. ArbOS compares the pool's balance against the total funds due and nudges the price per data unit up or down, so that over time, collections converge on actual costs. The full algorithm is described in Gas and fees.

When do funds move?

Payouts to the fee collector and reward recipient are triggered by batch posting reports. In practice this means:

  • Funds move shortly after each batch is posted once the report has transited the delayed inbox and been processed on the child chain.
  • Batch posting frequency depends on your chain's traffic and batch poster configuration (size, frequency), so payout frequency varies with it. Information about the batch poster configuration is described in Batch Poster.
  • Every report will cover as much of the funds as it can,

Estimated versus actual fees

Block explorers such as Blockscout display a per transaction "Gas used for L1" value (and a corresponding L1 fee). A common question is whether this is the actual cost of posting that transaction to the parent chain. It is an estimate, and it is never retroactively corrected. Here is why:

  • When a transaction executes, its batch doesn't exist yet, meaning the transaction has yet to be posted to the parent chain. Therefore ArbOS estimates the parent chain costs by using the price per data unit from the previously posted batch as an estimate.
  • The charged amount is recorded in the transaction receipt as gasUsedForL1: the parent chain fee re-expressed in child chain gas units at the transaction's gas price. This receipt field is what explorers display.
  • The transaction's actual share of batch posting costs is only knowable later, when the batch containing it is posted and reported. That actual cost is never attributed back to individual transactions. Instead, the difference between what was collected and what batches actually cost accumulates as a surplus or deficit in L1PricerFundsPoolAddress, and the adaptive pricing algorithm adjusts future charges to drive that difference toward zero.
Gas estimation pads the fee

eth_estimateGas responses include an additional ~10% padding on the parent chain component to protect users against parent chain gas price increases between estimation and execution. The amount actually charged at execution time uses the unpadded current price, so estimates typically exceed final charges.

You can read the parent chain fee charged to the current transaction from within a contract, or inspect a live chain's pricing state, using the ArbGasInfo precompile (getCurrentTxL1GasFees(), getL1BaseFeeEstimate()).

Funds are stagnant unless moved

All four collector addresses are addresses on your chain, and every payout described above is a native token transfer on your chain. The protocol never bridges revenue to the parent chain on your behalf. Two balances that operators sometimes conflate are entirely separate:

  • The batch poster's parent chain balance: the wallet that pays for posting batches. It spends the parent chain's gas token and depletes over time. You must keep it funded. If you hold that key in a KMS or a remote signer rather than locally, see Batch poster: External signing (KMS).
  • The fee collector's child chain balance: where reimbursement and revenue accumulate, denominated in your chain's gas token.

The protocol's pricing loop makes the second balance grow in proportion to what the first one spends, but moving value between them is the chain operator's job.

There are two options to move revenue from the child chain to the parent chain:

  1. Withdraw manually through the bridge. If a collector is an EOA or multisig you control, initiate a standard child to parent withdrawal and execute it on the parent chain after the challenge period.
  2. Use the AEP fee router contracts. Set your collector addresses to ChildToParentRouter contracts, which route received funds to a configurable parent chain address and can be triggered permissionlessly. This is the recommended setup for chains with Arbitrum Expansion Program obligations (see AEP fee router contracts).
Custom gas token chains

On chains with a custom gas token, fee collection is denominated in your gas token while the batch poster spends the parent chain's native token, so the reimbursement stream and the actual cost are in different assets. Such chains typically disable the parent chain base fee (set the price per unit to zero) and handle batch posting costs off-protocol. See How to use a custom gas token and the custom gas token scenario in AEP fee reporting.

Monitoring the fee pool

A few useful read calls for reporting on the parent chain fee stream (all against your chain's RPC):

# Balance sitting in the fee pool, waiting to be paid out
cast balance 0xA4B00000000000000000000000000000000000f6 --rpc-url $CHAIN_RPC

# Pool funds recognized by the pricer as available for payouts
cast call --rpc-url $CHAIN_RPC 0x000000000000000000000000000000000000006C "getL1FeesAvailable() (uint256)"

# Surplus (positive) or deficit (negative): available funds minus everything owed
cast call --rpc-url $CHAIN_RPC 0x000000000000000000000000000000000000006C "getL1PricingSurplus() (int256)"

# Amount accrued to the reward recipient but not yet paid
cast call --rpc-url $CHAIN_RPC 0x000000000000000000000000000000000000006C "getL1PricingFundsDueForRewards() (uint256)"

# Batch posters known to the chain, and a poster's fee collector
cast call --rpc-url $CHAIN_RPC 0x000000000000000000000000000000000000006D "getBatchPosters() (address[])"
cast call --rpc-url $CHAIN_RPC 0x000000000000000000000000000000000000006D "getFeeCollector(address) (address)" $BATCH_POSTER_ADDRESS

A negative surplus is normal after periods of high parent chain gas prices since recent batches cost more than what was collected. Therefore the adaptive pricing algorithm is raising the per unit price to recover. A persistently large positive surplus means users are being overcharged relative to costs; a chain owner can correct the price directly (ArbOwner.setL1PricePerUnit) or leave the algorithm to converge.

Funds sent directly to the pool address

The pricer only pays out funds it has accounted for. If tokens are transferred directly to L1PricerFundsPoolAddress outside of fee collection, a chain owner can make them available for payouts using ArbOwner.releaseL1PricerSurplusFunds(uint256).

For structured daily reporting across all fee streams, see AEP fee reporting, which includes a ready made RPC reporting script.

See also