If you've worked on a stablecoin wallet, you've probably seen this support ticket. A user has 500 USDT on TRON, presses Send, and gets an error. The balance is right there on the screen. What's missing is TRX, a coin they never bought and didn't know they needed.
Every chain that carries stablecoins charges its fees in its own native token. So "send 50 USDT" is quietly a two-asset operation, and the second asset is the one users forget. My last post looked at why a swap screen shows the wrong number. This one is about the coin that never shows up on the send screen at all, until it blocks the transfer.
Key takeaways
- On TRON, Solana, Stellar, TON and Ethereum, a USDT or USDC transfer costs something in the chain's native token, and each chain charges it differently.
- The cost often depends on the recipient. Sending USDT on TRON to an address that has never held USDT needs about twice the Energy. On Solana, a missing token account adds rent.
- Fee sponsorship exists on every one of these chains: TRON Energy delegation, Solana fee payers, Stellar fee-bump transactions, TON gasless transfers, Ethereum paymasters.
- Gasless doesn't mean free. Someone still pays the network, and the cost usually comes out of the stablecoin.
- A wallet should check the native balance before the user types an amount, not after they press Send.
Five chains, five billing models
A comparison of the best blockchains for crypto payments published this week scores TRON, Solana, TON, Stellar and Ethereum on cost per transfer, finality, stablecoin liquidity, real payment use and access. Its definition of access includes how hard it is to get the gas token. I think that criterion deserves more attention than it usually gets, because it's where first-time users get stuck.
Here is what each chain actually charges for a stablecoin transfer, checked against the networks' own documentation:
| Chain | Native token | What a stablecoin transfer costs | What depends on the recipient |
|---|---|---|---|
| TRON | TRX | About 65,000 Energy, or 6.5 TRX if burned at 100 sun per Energy | About 131,000 Energy if the recipient has never held USDT |
| Solana | SOL | 5,000 lamports per signature, plus an optional priority fee | About 0.00204 SOL rent if the recipient has no token account |
| Stellar | XLM | 100 stroops per operation (0.00001 XLM) | The recipient needs a trustline, which locks 0.5 XLM of their reserve |
| TON | Gram (formerly Toncoin) | A small fee in Gram, or in USDT through gasless transfers | Depends on the wallet, see below |
| Ethereum and L2s | ETH | Gas units times gas price, paid in ETH on mainnet, Base and Arbitrum alike | More gas if the recipient holds none of the token yet, since a new storage slot is written |
The rows don't line up, so a wallet that supports all five needs five different answers to "can this user send right now?"
TRON: Energy, Bandwidth and the first-time recipient
TRON doesn't charge a gas price in the usual sense. A USDT transfer consumes two resources. Energy pays for running the token contract, and Bandwidth pays for the bytes of the transaction (GetBlock docs).
A transfer to an address that already holds USDT takes about 65,000 Energy, because it updates an existing storage slot. A transfer to an address that has never held USDT takes about 131,000, because the contract has to create one. If the sender has no Energy, the network burns TRX instead, at 100 sun per Energy. That works out to about 6.5 TRX for the first case and 13.1 TRX for the second.
Bandwidth is easier on the user. Every account gets 600 free Bandwidth points a day, and a USDT transfer uses about 345, so one transfer a day is covered.
There are cheaper routes, but none of them helps a user who has zero TRX:
- Staking TRX gives Energy in proportion to the stake. Unstaking takes 14 days.
- Energy rental markets delegate Energy from large stakers, typically at 30 to 50 sun per unit.
- In February 2025 Justin Sun announced a gas-free option for sending USDT on TRON without holding TRX. Whether you can use it depends on the wallet.
The doubled cost for new recipients catches people out. The amount the wallet quoted yesterday for sending to a friend can be half of what it charges today for paying someone new.
Solana: cheap fees, plus rent
Solana's base fee is 5,000 lamports per signature, or 0.000005 SOL. A priority fee on top is optional (Solana docs).
The surprise is rent. USDC and USDT on Solana live in token accounts, one per owner per token. If the recipient doesn't have one yet, the sender's transaction usually creates it, and every account must hold a minimum balance proportional to its size. The formula in Solana's docs is (account_size + 128) * 3,480 lamports * 2 years. A token account is 165 bytes, so that comes to 2,039,280 lamports, about 0.00204 SOL (Solana docs). The balance is returned when the account is closed.
That is a small number, but it is about 400 times the base fee. A wallet that shows "fee: 0.000005 SOL" and then takes 0.002 more has a trust problem, even if the amount is tiny.
Solana also lets a different account pay the fee for a transaction, which is how many apps sponsor their users' transfers.
Stellar: reserves and trustlines
Stellar's fees are close to nothing: the network minimum is 100 stroops per operation, which is 0.00001 XLM, and it only rises when the network is congested (Stellar docs).
The catch is the minimum balance. Every account must keep two base reserves, currently 1 XLM, plus 0.5 XLM for each subentry (Stellar docs). To hold USDC, an account needs a trustline to the issuer, and that trustline is a subentry. So a wallet holding only USDC still has to keep 1.5 XLM locked.
The recipient side matters even more. An account without a USDC trustline can't receive USDC at all. On TRON or Ethereum a payment to a fresh address just works. On Stellar it fails until the recipient opts in.
Stellar has two built-in ways around this. Fee-bump transactions let another account pay the fee, and sponsored reserves let an app cover a user's reserves.
TON: gasless, with a fee in USDT
On TON, fees are paid in the native token, which was renamed from Toncoin to Gram in June 2026. Tonkeeper's gasless mode lets a W5 wallet send USDT with no Gram in it. The user signs a message, a relayer wraps it in a transaction and pays the network, and the fee is taken from the USDT being sent (Tonkeeper).
Tonkeeper's own explainer is honest about this: gas doesn't disappear, it just gets paid in a different token. Its example, at a price of $7 per token, puts a gasless USDT transfer at about $0.14, against about $0.10 through its prepaid Battery. Users get convenience and pay a small premium for it.
Ethereum and L2s: paymasters
On Ethereum mainnet, Base and Arbitrum, gas is paid in ETH. L2s made transfers cheap, but they didn't remove the need to hold ETH on that specific network. Someone with USDC on Base and ETH only on mainnet still can't send.
Two standards changed this. ERC-4337 introduced paymasters, contracts that pay gas on a user's behalf. EIP-7702, activated with the Pectra upgrade in May 2025, lets regular wallets delegate to smart contract code, so they can use paymasters too. Circle's Paymaster, for example, checks that the sender has enough USDC and pays the gas, charging the user in USDC instead of ETH (Circle).
A different approach is a chain built around one stablecoin. Plasma launched in September 2025 with zero-fee USDT transfers during its initial rollout. That removes the problem for USDT on that chain, but users still have to get there.
Check before the user types an amount
Every chain above has a fix, but the user only benefits if the wallet checks first. Here is a preflight check that returns how much of the native token a stablecoin transfer needs. It ignores some edge cases on purpose, such as TRON Bandwidth beyond the free daily allowance:
type SendCheck =
| { chain: 'tron'; recipientHasUsdt: boolean; availableEnergy: bigint }
| { chain: 'solana'; recipientHasTokenAccount: boolean; priorityFeeLamports: bigint }
| { chain: 'stellar'; recipientHasTrustline: boolean; senderSubentries: number }
| { chain: 'evm'; gasLimit: bigint; maxFeePerGasWei: bigint }
const SUN_PER_ENERGY = 100n
const TOKEN_ACCOUNT_RENT_LAMPORTS = 2_039_280n // 165-byte token account
const BASE_RESERVE_STROOPS = 5_000_000n // 0.5 XLM
// Native amount the sender must hold, in the chain's smallest unit
export function nativeNeeded(c: SendCheck): bigint {
switch (c.chain) {
case 'tron': {
const energy = c.recipientHasUsdt ? 65_000n : 131_000n
const missing = energy > c.availableEnergy ? energy - c.availableEnergy : 0n
return missing * SUN_PER_ENERGY
}
case 'solana': {
const rent = c.recipientHasTokenAccount ? 0n : TOKEN_ACCOUNT_RENT_LAMPORTS
return 5_000n + c.priorityFeeLamports + rent
}
case 'stellar': {
if (!c.recipientHasTrustline) {
throw new Error('Recipient has no trustline for this asset')
}
const minBalance = BigInt(2 + c.senderSubentries) * BASE_RESERVE_STROOPS
return minBalance + 100n
}
case 'evm':
return c.gasLimit * c.maxFeePerGasWei
}
}
A few outputs to sanity-check against the table: a TRON transfer to a new recipient with no Energy returns 13,100,000 sun, or 13.1 TRX. A Solana transfer that creates a token account returns 2,044,280 lamports. A Stellar sender with one USDC trustline needs 15,000,100 stroops, about 1.5 XLM, most of which stays locked as reserve.
The real work is in the inputs. recipientHasUsdt and recipientHasTokenAccount need a lookup on the recipient before the quote, which is easy to skip and expensive to get wrong.
A checklist for the send screen
- [ ] Show the native balance next to the stablecoin balance, with the network name.
- [ ] Run the preflight check as soon as the recipient is known, before the amount.
- [ ] Look up the recipient: USDT history on TRON, a token account on Solana, a trustline on Stellar.
- [ ] Show the total fee, including rent or reserves, in both the native token and dollars.
- [ ] If the user has no native token, offer the fix in place: sponsored fee, gasless mode or a small top-up.
- [ ] When the fee is paid in the stablecoin, say so before signing and show the amount the recipient will get.
FAQ
Why can't I send USDT if I have enough USDT?
Because the network fee is charged in the chain's native token, not in USDT. On TRON you need TRX or Energy, on Solana SOL, on Ethereum and its L2s ETH, on Stellar XLM and on TON Gram. Your USDT balance can cover the amount but not the fee. Some wallets now offer gasless sending, where a relayer or paymaster pays the network and takes the fee from your USDT, so check whether yours supports it. Otherwise, buying a small amount of the native token on the same network solves the problem for many future transfers.
Why did my USDT transfer on TRON cost twice as much this time?
Most likely the recipient had never held USDT before. Sending to such an address takes about 131,000 Energy instead of about 65,000, because the token contract has to create a new storage entry for the recipient. If you have no staked or rented Energy, the network burns TRX to cover it, so the cost roughly doubles. Later transfers to the same address go back to the normal amount. Staking TRX or renting Energy lowers the cost for both cases.
Is a gasless transfer free?
No. The network still charges a fee, and someone pays it. In gasless setups a relayer or paymaster pays the network in the native token and recovers the cost from you, usually in the stablecoin you're sending, sometimes with a small markup. Some apps cover the fee themselves as a feature and make the money back elsewhere. Gasless removes the need to hold a second coin. It doesn't remove the cost, so check the final amount the recipient gets before signing.
Closing thoughts
Sending a stablecoin still means managing two balances, and most of the confusion comes from wallets that show only one of them. All the tools for hiding the second coin already exist on these five chains. What's left is wiring the check into the moment the user picks a recipient.
If you've shipped gasless sending or fee sponsorship, which part took the most work: the relayer, the pricing, or explaining it to users? I'd like to compare notes in the comments.
Top comments (0)