TIP-1007: Fee Token Introspection
Abstract
TIP-1007 adds a getFeeToken() view function to the FeeManager precompile that returns the fee token address being used for the current transaction. This enables smart contracts to introspect which TIP-20 token is paying for gas fees during execution, allowing for dynamic logic based on the fee token choice.
Motivation
Tempo transactions support paying gas fees in any USD-denominated TIP-20 token via the fee token preference system. However, prior to this TIP, there was no way for a smart contract to determine which fee token is being used for the current transaction during execution.
This capability was requested by a partner. It could be useful for contracts that want to:
- Adjust their internal logic based on which fee token is being used
- Provide fee token-aware pricing or routing decisions
- Emit events or logs that include the fee token for off-chain indexing
- Implement fee token-specific behavior in cross-chain messaging
Specification
New Function
The following function is added to the IFeeManager interface:
interface IFeeManager {
// ... existing functions ...
/// @notice Returns the fee token being used for the current transaction
/// @return The address of the TIP-20 token paying for gas fees
/// @dev This value is set by the protocol before transaction execution begins.
/// Returns address(0) if no fee token has been set (e.g., in eth_call
/// simulations where the transaction handler does not run).
function getFeeToken() external view returns (address);
}Behavior
Fee Token Resolution
The fee token returned by getFeeToken() is the same token that was resolved by the protocol during transaction validation, following the fee token preference rules.
Storage
The fee token is stored in transient storage (EIP-1153) within the FeeManager precompile. This means:
- The value is automatically cleared at the end of each transaction
- No persistent storage writes occur, minimizing gas costs
- The value is consistent across all calls within a transaction (including internal calls and subcalls)
Timing
The fee token is set by the protocol in the validate_against_state_and_deduct_caller handler phase, before any user code executes. This ensures the value is available throughout the entire transaction execution.
Gas Cost
Reading the fee token costs the standard warm transient storage read cost (100 gas for TLOAD). This is the cost of calling getFeeToken() itself; callers should account for additional gas used by the CALL opcode to invoke the precompile.
Edge Cases
| Scenario | Return Value |
|---|---|
| Normal transaction | The resolved fee token address |
| Free transaction (zero gas price) | The resolved fee token (may still be set) |
eth_call simulation | address(0) (no transaction context) |
The only case where address(0) is returned is in simulation contexts (e.g., eth_call) where the protocol handler does not execute.
Example Usage
import { IFeeManager } from "./interfaces/IFeeManager.sol";
contract FeeTokenAware {
IFeeManager constant FEE_MANAGER = IFeeManager(0xfeeC000000000000000000000000000000000000);
address constant PATH_USD = 0x20C0000000000000000000000000000000000000;
function doSomething() external {
address feeToken = FEE_MANAGER.getFeeToken();
if (feeToken == PATH_USD) {
// User is paying fees in pathUSD
} else if (feeToken != address(0)) {
// User is paying fees in a different USD stablecoin
} else {
// No fee token context (e.g., eth_call simulation)
}
}
}Interface Addition
The following function is added to IFeeManager:
/// @notice Returns the fee token being used for the current transaction
/// @return The address of the TIP-20 token paying for gas fees
function getFeeToken() external view returns (address);Invariants
getFeeToken()must return a consistent value across all calls within the same transactiongetFeeToken()must returnaddress(0)in simulation contexts (e.g.,eth_call) where no transaction handler runsgetFeeToken()must be callable fromstaticcallcontexts without reverting- The fee token returned must match the token used for actual fee deduction in
collectFeePreTxandcollectFeePostTx - Reading the fee token must not modify any state (view function)
Test Cases
The test suite must cover:
- Basic functionality:
getFeeToken()returns the correct fee token address - Zero when unset: Returns
address(0)when no fee token is set - Consistency: Same value returned from nested calls within a transaction
- Static call safety: Works correctly when called via
staticcall - Transient storage: Value is cleared between transactions
- Different fee tokens: Works with various TIP-20 fee tokens (pathUSD, USDC, etc.)
- Dispatch coverage: Function selector is correctly dispatched by the precompile