cip43
titleFee address module
descriptionForward TIA tokens to protocol revenue via a dedicated fee address
authorManav Aggarwal (@Manav-Aggarwal)
discussions-tohttps://forum.celestia.org/t/cip-add-burn-module/2216
statusIn Review
typeStandards Track
categoryCore
created2026-01-14

Abstract

This proposal introduces a fee address that allows users to send TIA tokens to a dedicated module account, which are then automatically forwarded to the fee collector as transaction fees via protocol-injected transactions. These fees are distributed to delegators through the existing distribution module.

Motivation

External networks using Celestia for data availability may want to contribute fee revenue to Celestia. However, they face fundamental operational constraints.

Networks typically don’t maintain a funded account on Celestia with signing keys. Setting up a custodian or multisig on Celestia adds significant operational overhead. Their only access to Celestia is through cross-chain bridges like IBC or Hyperlane. However, these bridges can only deliver tokens to a recipient address—they cannot submit transactions with custom fee amounts.

This creates a gap: networks can bridge TIA to Celestia, but cannot convert those tokens into protocol revenue without maintaining Celestia-side infrastructure.

The fee address solves this by providing a dedicated address where:

  • Networks send TIA via any bridge (IBC, Hyperlane, etc.)
  • Tokens are automatically converted to protocol revenue via protocol-injected transactions
  • Contributions appear in dashboard revenue calculations (e.g., Blockworks, Celenium) without requiring integration changes from dashboard providers

Dashboard Compatibility Constraint

Blockchain analytics dashboards calculate protocol revenue by aggregating the tx.AuthInfo.Fee field across all transactions. A simpler design using direct bank transfers would not appear in these revenue calculations. The protocol-injected transaction approach ensures contributions appear as real transaction fees without requiring dashboard providers to add special-case logic.

Non-Goals

This CIP intentionally does not address:

  • Fee distribution mechanism: How collected fees are allocated (delegators, community pool, burn) is a broader tokenomics decision affecting all protocol revenue, not just external contributions
  • Minimum contribution threshold: Small amounts (even 1 utia) trigger forwarding immediately; batching adds complexity for marginal benefit
  • Multi-denom support: Only utia is accepted; foreign tokens would become permanently stuck
  • Burning tokens: This CIP forwards to revenue; a separate CIP could propose burning collected fees

Specification

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119 and RFC 8174.

Architecture

The fee address functionality is intentionally minimal with no dedicated module:

  • Types: pkg/feeaddress/ contains MsgPayProtocolFee and validation logic
  • Ante handlers: app/ante/ contains FeeAddressDecorator (denom validation) and ProtocolFeeTerminatorDecorator (protocol fee handling)
  • Module account: Registered in maccPerms for token operations

Fee Address

Tokens MUST be sent to the following module account:

celestia18sjk23yldd9dg7j33sk24elwz2f06zt7ahx39y

This address is derived from the module name “feeaddress” using standard Cosmos SDK module account derivation.

Message Types

MsgPayProtocolFee

This message is protocol-injected and MUST NOT be submitted by users directly.

message MsgPayProtocolFee {
  string from_address = 1;
}

The from_address field is always set to the fee address module account. The message includes a signer annotation for SDK compatibility, but signature verification is skipped by the ProtocolFeeTerminatorDecorator. Validation happens via ProcessProposal checking that tx fee == fee address balance.

Validation Rules

The FeeAddressDecorator ante handler enforces token restrictions for direct sends:

  • Only utia (the native staking token) MAY be sent to the fee address via MsgSend or MsgMultiSend
  • Attempts to send other denoms via direct sends MUST be rejected

Note: Inbound IBC and Hyperlane transfers of non-utia tokens cannot be rejected at the protocol level and will become permanently stuck at the fee address. Transfers of utia via these bridges are accepted.

Protocol-Injected Fee Forward Transaction

PrepareProposal

When preparing a block proposal, the block proposer:

  1. Queries the fee address utia balance
  2. If balance is non-zero:
    • Creates a MsgPayProtocolFee transaction with from_address set to the fee address
    • Sets the transaction fee to the entire fee address balance
    • Sets gas limit to 40,000 (minimal, no computation)
    • Does NOT sign the transaction (unsigned)
    • Prepends the transaction to the block

Note: The protocol fee tx is minimal (~100 bytes). If a block cannot accommodate it (practically impossible), tokens remain in the fee address until the next block.

ProcessProposal (Strict Validation)

PrepareProposal is proposer-controlled, so ProcessProposal MUST independently verify protocol fee forwarding to prevent malicious proposers from withholding funds.

All validators MUST enforce strict validation:

  1. If fee address has a non-zero balance:
    • Block MUST contain a valid MsgPayProtocolFee tx as the first transaction
    • Tx fee MUST equal the fee address balance
    • Block is REJECTED if any of these conditions fail
  2. If fee address has zero balance:
    • Block MUST NOT contain a MsgPayProtocolFee tx
    • Block is REJECTED if a protocol fee tx is present

Ante Handler: ProtocolFeeTerminatorDecorator

The ProtocolFeeTerminatorDecorator processes MsgPayProtocolFee transactions:

  1. Rejects user-submitted MsgPayProtocolFee transactions (only protocol-injected allowed)
  2. Deducts the transaction fee from the fee address (not from a signer)
  3. Sends the fee to the fee collector module
  4. Terminates the ante chain early, bypassing signature and sequence checks

The protocol fee transaction skips standard ante decorators for fee deduction, min gas price validation, signature verification, and sequence increment. See the reference implementation for the complete bypass list.

Distribution

Forwarded fees are sent to the fee collector module account. The distribution module allocates fee collector funds to delegators proportionally at BeginBlock. Validators receive their share through their self-delegation. This distribution mechanism may be modified in future protocol upgrades.

CLI Usage

# Send tokens to the fee address (forwarded to protocol revenue in next block)
celestia-appd tx bank send mykey celestia18sjk23yldd9dg7j33sk24elwz2f06zt7ahx39y 1000000utia

# Query fee address balance
celestia-appd query bank balances celestia18sjk23yldd9dg7j33sk24elwz2f06zt7ahx39y

# Query fee address via auth module
celestia-appd query auth module-account feeaddress

Parameters

This module introduces no new parameters.

Rationale

Why Not Direct Transfer to Fee Collector?

A simpler design would transfer tokens directly in EndBlocker:

bankKeeper.SendCoins(ctx, feeAddress, feeCollectorModule, balance)

This doesn’t work because dashboards calculate revenue by aggregating tx.AuthInfo.Fee fields. Direct bank transfers don’t create transactions, so contributions would be invisible to analytics without requiring every dashboard provider to add special-case logic for this module.

Why Forward to Revenue Instead of Burn?

Both approaches achieve the goal of “contributing” to Celestia but have different outcomes:

ApproachEconomic EffectDashboard Visibility
Fee ForwardingRedistributed to delegators via distribution moduleAppears as tx fees
BurningDeflationary, benefits all TIA holdersNot counted as revenue

This CIP focuses narrowly on the contribution mechanism. What Celestia does with collected fees (redistribute, burn, partial burn) is a broader tokenomics decision that affects all protocol revenue and should be addressed in a separate CIP.

Strict Enforcement

ProcessProposal strictly enforces fee forwarding to ensure:

  • No block proposer can “skip” forwarding to keep funds in the fee address
  • Consensus on when/how funds are forwarded
  • Predictable behavior for applications sending to the fee address

Other Design Decisions

  1. No minimum balance threshold: Forward any non-zero balance to minimize complexity. Very small amounts (e.g., 1 utia) trigger a protocol fee tx with effective gas price ~0.000025 utia/gas (1 / 40,000). This is acceptable because protocol-injected txs skip min gas price validation, the contributor is still adding to protocol revenue, and block overhead is minimal (~100 bytes). Adding a threshold would delay forwarding and increase complexity.
  2. One protocol fee tx per block: All contributions in the fee address are batched into a single MsgPayProtocolFee tx (~100 bytes overhead)
  3. Unsigned transaction: Validated via ProcessProposal fee balance check, not signature
  4. Gas limit: 40,000 (minimal - message handler performs bank transfer only)
  5. Module account over vanity address: Using standard Cosmos SDK module account derivation ensures compatibility with existing tooling and avoids the need to maintain a custom vanity address.

Backwards Compatibility

This is a consensus-breaking change that requires a network upgrade. However, it is purely additive (new functionality) and does not affect existing functionality.

Test Cases

Test cases are available in the reference implementation:

  • Ante decorator tests: app/ante/fee_address_test.go, app/ante/protocol_fee_test.go
  • Integration tests: app/feeaddress_test.go, app/protocol_fee_test.go
  • Validation tests: pkg/feeaddress/validation_test.go

Tests cover successful forwarding, wrong denom rejection, user submission rejection, and ProcessProposal validation.

Security Considerations

  1. Denom Restriction: Only utia can be sent to the fee address via direct sends (MsgSend/MsgMultiSend), enforced by the FeeAddressDecorator ante handler. While utia sent via IBC and Hyperlane is accepted, inbound transfers of non-utia tokens cannot be rejected at the protocol level and will become permanently stuck at the fee address with no way to recover them. Users and applications should ensure they only send utia to the fee address.

  2. No Direct Access: Users cannot withdraw from the fee address. Tokens are automatically forwarded as transaction fees.

  3. Strict Enforcement: Blocks that fail to forward non-zero balances are rejected, preventing proposers from withholding funds.

  4. Spam Resistance: The protocol fee transaction is created by the block proposer in PrepareProposal, not sourced from the mempool. Users cannot prevent its inclusion by filling blocks with spam. A malicious proposer could omit it, but ProcessProposal would reject their block—tokens remain in the fee address until the next honest proposer.

  5. Low-Value Contributions: Sending very small amounts (e.g., 1 utia per block) is not an attack vector. Each contribution still adds to protocol revenue, the protocol fee tx is minimal (~100 bytes), and gas price validation is intentionally skipped. The only observable effect is inflated transaction counts on dashboards, though revenue attribution remains accurate.

  6. User Submission Rejection: The ProtocolFeeTerminatorDecorator explicitly rejects any MsgPayProtocolFee transactions submitted by users, ensuring only protocol-injected transactions are processed.

Reference Implementation

The implementation is available at: https://github.com/celestiaorg/celestia-app/pull/6441

Copyright and related rights waived via CC0.