Fee Abstraction: Paying Gas With ERC20 Tokens
Table of Contents
Fee Abstraction is a Celo feature that allows users to send transactions without spending any native CELO tokens. Instead, ERC20 tokens are used to pay for the transaction's gas cost.
As a User
Sending Fee Abstraction Transactions
To pay gas via Fee Abstraction, the gas token must be specified in a CIP-64 transaction. This tx type has an additional feeCurrency
field that specifies which token is used for the maxFeePerGas
and maxPriorityFeePerGas
fields. See CIP-64 for details.
Celo will also soon support the CIP-66 tx type in addition to CIP-64.
Client library support is described in docs.celo.org.
JSON-RPC Changes
To make it easier to reliably send Fee Abstraction transactions, the JSON-RPC interface has been extended in two ways:
eth_estimateGas
takes an optionalfeeCurrency
parameter to get Fee Abstraction specific gas estimates (the gas price for the fee token transfers depends on the token)eth_gasPrice
andeth_maxPriorityFeePerGas
take an optionalfeeCurrency
parameter for getting CIP-64 gas prices.
The Fee Currency Directory
Only tokens that have been registered in the FeeCurrencyDirectory
contract using Celo's governance process can be used for Fee Abstraction. The directory entry shows that the token is trustworthy and contains additional information about the token:
- The token address
- An oracle address, conforming to the
IOracle
interface, to get the current exchange rate - The amount of intrinsic gas for Fee Abstraction gas calculation (see "Gas Calculation for Fee Abstraction Transactions")
You can run the getCurrencies()
method on the FeeCurrencyDirectory
contract to get a list of all registered tokens and use getExchangeRate(token address)
to fetch the current exchange rate for a token. The IOracle
interface is only intended for parties providing Fee Abstraction tokens, not for users or client libraries.
Tokens using FeeCurrencyAdapter
Tokens with a low number of decimals
(USDC and USDT) would cause problems during the gas calculation, because the cost per gas can only be accurately given in fractions and not integers. To avoid this issue, the tokens are not directly added to the FeeCurrencyDirectory
. Instead, a FeeCurrencyAdapter
contracts wraps these tokens, calculates the costs per gas in a higher accuracy and only converts it back to the lower accuracy once the total gas costs for a transaction is determined.
This only really impacts the user in a single way: Instead of using the USDC and USDT token addresses, you have to pass their FeeCurrencyAdapter
addresses in the feeCurrency
field for CIP-64 txs.
For Token Authors
Requirements for Registering a Fee Abstraction Token
To become registered as a Fee Abstraction currency, the following requirements have to be met:
- Implement the IFeeCurrency interface
- Ensure exchange rates are kept up to date in the oracle with the
IOracle
interface - Pass a Celo governance vote for the
FeeCurrencyDirectory
addition
The fee-currency-example repository contains the interface description and an example Fee Abstraction token implementation with tests.
Inside the Celo Blockchain
Exchange Rate Handling Inside the Blockchain Client
Before each block, the blockchain client reads the list of all registered Fee Abstraction tokens from the FeeCurrencyDirectory
and fetches the currency exchange rate for each of them. If the Oracle for a token reverts or returns invalid exchange rates (numerator or denominator are zero), the token is treated as if it was not registered. Token registrations and exchange rates stay the same within a block and are only updated before the next block.
Transactions with unregistered feeCurrency
values are not accepted into the tx pool and dropped from the pool if they have been previously accepted. The same is true if the maxFeePerGas
falls below the current base fee.
Gas Calculation for Fee Abstraction Transactions
Ethereum transactions pay a fixed fee of 21000 gas ("intrinsic gas") in addition to the cost for executing the transaction. This is meant to cover the operating expenses during tx processing outside the actual tx execution, like debiting the gas cost from the tx sender's account, refunding the unused gas or transferring the base fee and tip to the respective receivers.
When using Fee Abstraction, the fees are transferred by executing functions on the respective token contract, which is computationally more expensive than native token transfers. The exact costs will vary by token and can change over time. Therefore, a token-specific intrinsic gas value is used for Fee Abstraction txs in addition to Ethereum's intrinsic gas. This value is stored in the FeeCurrencyDirectory
contract and can be changed by Celo governance. It should be set to at least the maximum gas cost of executing all function calls for debiting and crediting fees for a single transaction.
Block Space Limits Per Fee Abstraction Token
As described above, Celo allows users to pay for gas using ERC20 tokens. There is a governable list of accepted tokens. However, the Celo blockchain client starting with version 1.8.1 implements a protective mechanism that allows validators to control the percentage of available block space used by transactions paid with an alternative fee currency (other than CELO) more precisely.
There are two new flags that control this behavior:
-
celo.feecurrency.limits
with a comma-separatedcurrency_address_hash=limit
mappings for currencies listed in theFeeCurrencyWhitelist
contract, wherelimit
represents the maximal fraction of the block gas limit as a float point number available for the given fee currency. The addresses are not expected to be checksummed.For example,
0x765DE816845861e75A25fCA122bb6898B8B1282a=0.1,0xD8763CBa276a3738E6DE85b4b3bF5FDed6D6cA73=0.05,0xEd6961928066D3238134933ee9cDD510Ff157a6e=0
. -
celo.feecurrency.default
- an overridable default value (initially set to0.5
) for currencies not listed in the limits map, meaning that if not specified otherwise, a transaction with a given fee currency can take up to50%
of the block space. CELO token doesn't have a limit.
Based on historical data, the following default configuration is proposed:
--celo.feecurrency.limits.default=0.5
--celo.feecurrency.limits="0x765DE816845861e75A25fCA122bb6898B8B1282a=0.9,0xD8763CBa276a3738E6DE85b4b3bF5FDed6D6cA73=0.5,0xe8537a3d056DA446677B9E9d6c5dB704EaAb4787=0.5"
It imposes the following limits:
- cUSD up to 90%
- cEUR up to 50%
- cREAL up to 50%
- any other token except CELO - 50%
- CELO doesn't have a limit