Allowlisted fee currencies
The protocol maintains a governable allowlist of smart contract addresses that can be used as fee currencies. These contracts implement an extension of the ERC20 interface with additional functions for debiting and crediting transaction fees (see Adding Fee Currencies). To fetch the current allowlist, callgetCurrencies() on the FeeCurrencyDirectory contract, or use celocli:
Adapters for non-18-decimal tokens
Allowlisted addresses may be adapters rather than full ERC20 tokens. Adapters are used when a token has decimals other than 18 (e.g., USDC and USDT use 6 decimals). The Celo blockchain calculates gas pricing in 18 decimals, so adapters normalize the value.- For transfers: use the token address as usual.
- For
feeCurrency: use the adapter address. - For
balanceOf: querying via the adapter returns the balance as if the token had 18 decimals — useful for checking whether an account can cover gas without converting units.
adaptedToken() on the adapter contract. Newer adapters — including the USDT and USA₮ ones — expose this as getAdaptedToken() instead, so try both if the first call reverts.
For more on gas pricing, see Transaction Fees.
Adapter addresses
The current adapter and token addresses for each network are listed on the Fee currency contracts page, which is generated from the on-chainFeeCurrencyDirectory allowlist.
Using fee abstraction with Celo CLI
Transfer 1 USDC using USDC as the fee currency viacelocli:
--gasCurrency. All three tokens use 6 decimals, so pass --value in units of 10^6 (e.g. 1000000 = 1 USDT/USDC/USAâ‚®).
Transfer 1 USDT using USDT as the fee currency:
--privateKey stays in your shell history, and other users on the machine can see it in the process list while the command runs. Use a dedicated account that holds only what you plan to send.
Using fee abstraction with viem
We recommend viem, which serializes CIP-64 natively when you pass a Celo chain fromviem/chains. Ethers.js and web3.js do not support the field on their own; use the Celo Ethers.js wrapper or the web3 transaction-types plugin. Whichever library you use, the wallet that signs the transaction must also support CIP-64; see wallet support.
To run the scripts below, install viem with npm install viem, save each script as an .mjs file (they use import and top-level await), and run it with node. They target Celo mainnet and use USDC. For USDT or USA₮, replace the token and adapter addresses with that token’s pair from Fee currency contracts; both tokens have 6 decimals, so the math stays the same.
Estimate the gas fee
Before sending, estimate the transaction fee so the UI can reserve that amount and prevent users from trying to transfer more than their available balance.The gas price returned from the RPC is always expressed in 18 decimals, regardless of the fee currency.
feeCurrency value when estimating.
Prepare the transaction
SetfeeCurrency to the adapter address (USDC/USDT/USAâ‚®) or token address (USDm, EURm, BRLm). Use transaction type 123 (0x7b), which is CIP-64 compliant.
Send the transaction
The script below sends 1 USDC in total, fee included: it estimates the fee as in Estimate the gas fee, converts it from 18 to 6 decimals, and transfers 1 USDC minus the fee. The network takes the fee from the sender’s USDC balance before it runs the transfer, so the balance must cover the transferred amount plus the fee at the time of inclusion. That fee can rise above the estimate if the base fee goes up in between, so keep a small margin above 1 USDC. The network also checks that the balance covers the gas limit times the maximum fee per gas, which is higher than the estimate. SetPRIVATE_KEY to the sender’s private key, a 0x-prefixed hex string.
Troubleshooting
Where to set the fee currency:
Resources
Related
- Fee abstraction guide — Background, why it matters and which wallets support it
- Fee currency contracts — Token and adapter addresses for each network
- Fee abstraction specification — Protocol rules, JSON-RPC changes and node flags
- Adding fee currencies — Register a new fee currency