| cip | 43 |
|---|---|
| title | Fee address module |
| description | Forward TIA tokens to protocol revenue via a dedicated fee address |
| author | Manav Aggarwal (@Manav-Aggarwal) |
| discussions-to | https://forum.celestia.org/t/cip-add-burn-module/2216 |
| status | In Review |
| type | Standards Track |
| category | Core |
| created | 2026-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
utiais 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/containsMsgPayProtocolFeeand validation logic - Ante handlers:
app/ante/containsFeeAddressDecorator(denom validation) andProtocolFeeTerminatorDecorator(protocol fee handling) - Module account: Registered in
maccPermsfor 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 viaMsgSendorMsgMultiSend - 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:
- Queries the fee address
utiabalance - If balance is non-zero:
- Creates a
MsgPayProtocolFeetransaction withfrom_addressset 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
- Creates a
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:
- If fee address has a non-zero balance:
- Block MUST contain a valid
MsgPayProtocolFeetx as the first transaction - Tx fee MUST equal the fee address balance
- Block is REJECTED if any of these conditions fail
- Block MUST contain a valid
- If fee address has zero balance:
- Block MUST NOT contain a
MsgPayProtocolFeetx - Block is REJECTED if a protocol fee tx is present
- Block MUST NOT contain a
Ante Handler: ProtocolFeeTerminatorDecorator
The ProtocolFeeTerminatorDecorator processes MsgPayProtocolFee transactions:
- Rejects user-submitted
MsgPayProtocolFeetransactions (only protocol-injected allowed) - Deducts the transaction fee from the fee address (not from a signer)
- Sends the fee to the fee collector module
- 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:
| Approach | Economic Effect | Dashboard Visibility |
|---|---|---|
| Fee Forwarding | Redistributed to delegators via distribution module | Appears as tx fees |
| Burning | Deflationary, benefits all TIA holders | Not 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
- 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.
- One protocol fee tx per block: All contributions in the fee address are batched into a single
MsgPayProtocolFeetx (~100 bytes overhead) - Unsigned transaction: Validated via ProcessProposal fee balance check, not signature
- Gas limit: 40,000 (minimal - message handler performs bank transfer only)
- 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
-
Denom Restriction: Only
utiacan be sent to the fee address via direct sends (MsgSend/MsgMultiSend), enforced by theFeeAddressDecoratorante handler. Whileutiasent via IBC and Hyperlane is accepted, inbound transfers of non-utiatokens 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 sendutiato the fee address. -
No Direct Access: Users cannot withdraw from the fee address. Tokens are automatically forwarded as transaction fees.
-
Strict Enforcement: Blocks that fail to forward non-zero balances are rejected, preventing proposers from withholding funds.
-
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.
-
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.
-
User Submission Rejection: The
ProtocolFeeTerminatorDecoratorexplicitly rejects anyMsgPayProtocolFeetransactions 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
Copyright and related rights waived via CC0.