Skip to main content
On TRON, every transaction costs gas, and users normally pay it in TRX. This recipe shows how your app can cover that gas instead, so users can send tokens like USDT from a wallet that holds no TRX. Dynamic doesn’t sponsor TRON gas the way it does for Solana and EVM. Instead, your backend uses a sponsor wallet to stake TRX and lend the resulting gas to your users’ wallets. TRON calls this gas Energy and Bandwidth, and calls lending it delegating. This recipe uses two wallets:
  • A sponsor wallet: a TRON server wallet that your backend controls with the Node SDK. It stakes TRX and lends gas to users.
  • A user wallet: the user’s TRON embedded wallet, which signs TRC-20 transfers in the browser without holding TRX.

Prerequisites

Dynamic environment
  • TRON enabled in two places in the Dynamic Console: Chains & Networks, with the same network active as your backend (for example, Nile), and Embedded Wallets.
  • A frontend using the JavaScript SDK (@dynamic-labs-sdk/*) with the TRON extension. The legacy React SDK’s @dynamic-labs/tron supports only external wallets.
Sponsor wallet (backend)
  • A TRON server wallet from Create a TRON wallet. Save the full walletMetadata that createWalletAccount returns, and the wallet’s password.
  • A Dynamic API token and your environment ID.
  • Enough TRX in the sponsor wallet to stake. Step 3 shows how much.
TRON network
  • A TRON full node, such as TronGrid (https://api.trongrid.io on mainnet, https://nile.trongrid.io on Nile). Use a TronGrid API key in production, because TronGrid rate-limits requests without one.

How it works

  1. The sponsor wallet stakes TRX for Energy, which contract calls such as TRC-20 transfers consume.
  2. Your frontend sends the user’s address to your backend, which activates the address if it’s new and delegates Energy to it.
  3. Once the delegation confirms, the user’s wallet sends transfers as usual, and TRON spends the delegated Energy instead of TRX. Free Bandwidth covers about one transfer a day, and the sponsor can send a small amount of TRX to cover more.
  4. When the user no longer needs coverage, the sponsor reclaims the Energy and can unstake the TRX.

1. Set up the sponsor client (backend)

Install @dynamic-labs-wallet/node-tron. The examples read these environment variables:
  • DYNAMIC_ENVIRONMENT_ID and DYNAMIC_AUTH_TOKEN
  • SPONSOR_WALLET_METADATA (the saved walletMetadata as JSON) and SPONSOR_WALLET_PASSWORD
  • TRON_NODE, and optionally TRONGRID_API_KEY
Only delegate to wallets of authenticated users, or anyone can drain the sponsor. Verify the user’s Dynamic JWT, check that its environment_id matches yours, and check that userAddress is one of the user’s wallets. If the token omits verified_credentials, look up the user (the token’s sub) with Get a user by ID and your API token.
In production:
  • Keep DYNAMIC_AUTH_TOKEN, SPONSOR_WALLET_PASSWORD, and the wallet metadata in a secrets manager.
  • A long-lived client’s session expires, and signTransaction then fails with HTTP 403. Call authenticateApiToken again and retry, or create the client per request.
  • Load @dynamic-labs-wallet/node-tron as an ES module (the CommonJS build fails wallet creation with bs58.encode is not a function). In Next.js, also add @dynamic-labs-wallet/node and @dynamic-labs-wallet/node-tron to serverExternalPackages, because Turbopack can’t bundle their native addon.

2. Add full-node helpers

The full node builds the sponsor’s transactions, and your backend signs and broadcasts them as in Sign TRON Transactions. The node reports invalid requests as HTTP 200 with an Error field, so the helper checks for it before signing.

3. Stake TRX on the sponsor wallet

Staked TRX earns a share of the network’s daily Energy, and spent Energy recovers over 24 hours. Size the stake as the Energy your users need per day divided by the Energy per TRX, which is TotalEnergyLimit / TotalEnergyWeight from /wallet/getaccountresource. Estimate a transfer’s Energy with /wallet/triggerconstantcontract (energy_used); transfers to an address that doesn’t hold the token yet cost more.
Recent mainnet USDT transfers used about 65,000 Energy to an existing holder and 130,000 to a new one.1 At 10 Energy per TRX, one 65,000-Energy transfer a day needs 6,500 TRX of stake.

4. Lend gas to the user’s wallet

A new embedded wallet doesn’t exist on-chain, and receiving TRC-20 tokens doesn’t activate it. Delegating to it fails with Account[…] not exists, so the sponsor activates it first, for a one-time fee of about 1.1 TRX.2
delegateresource takes staked TRX in SUN, not Energy, so convert with the Energy per TRX. Stake whose Energy is still recovering can’t be delegated, so check /wallet/getcandelegatedmaxsize first and stake more or reclaim when it runs low.
Delegate, and wait for confirmation before responding to the frontend. A transfer sent before the delegation confirms doesn’t get the Energy.
Repeated delegations to one address add up. Before delegating, call /wallet/getaccountresource for the user’s address, and skip the delegation when EnergyLimit minus EnergyUsed already covers ENERGY_PER_TRANSFER.
A delegation with lock: true can’t be reclaimed until its lock period expires.

Cover more than one transfer a day

Every transaction also uses Bandwidth, which delegated Energy doesn’t cover. An activated account gets 600 free Bandwidth a day and a TRC-20 transfer uses about 345, so a user with no TRX can send about one transfer a day.3 Another transfer that day fails with BANDWITH_ERROR (TRON’s spelling). A transaction takes all of its Bandwidth from one source, so a user with 255 free Bandwidth left can’t spend it on a 345-Bandwidth transfer. To cover more transfers, send the user the TRX that burning the missing Bandwidth costs: the transfer’s Bandwidth times getTransactionFee from /wallet/getchainparameters, which is about 0.35 TRX per transfer.4 Send only the shortfall, because the user can spend that TRX on anything. topUpBandwidth in Charge a fee on TRON transfers shows the calculation. Delegating Bandwidth works the same way as Energy (resource: 'BANDWIDTH', type: 0 for getcandelegatedmaxsize), but it costs the sponsor more than it lends. A staked TRX earns only about 0.63 Bandwidth a day,5 so one transfer needs about 550 TRX of stake. The sponsor’s own delegate and undelegate transactions also use its staked Bandwidth before its free Bandwidth, which leaves less to lend.6

5. Send a transfer without TRX (frontend)

Steps 1 to 4 run in a backend endpoint you define, here /api/sponsor. Call it with the user’s Dynamic JWT before each transfer. The backend activates the address once and delegates only when the user’s remaining Energy is too low:
sendGaslessTransfer calls requestSponsorship first, then sends the transfer with the embedded wallet’s TronWeb instance. TronWeb uses the active Dynamic network’s RPC, not your TRON_NODE, so both must be on the same network. This example sends USDT on mainnet:
feeLimit is in SUN. It caps the TRX the call can burn, and TRON also uses it to cap the Energy the call can use, including delegated Energy. Set it to at least the Energy the transfer needs times the network’s Energy fee (getEnergyFee from /wallet/getchainparameters), with headroom. The limit isn’t a charge: when delegated Energy covers the call, 100 TRX costs nothing. TronWeb rejects 0, and the network’s maximum is getMaxFeeLimit. If the delegated Energy runs out and the user holds no TRX, the transfer fails rather than burning TRX.
On Nile, test with a token whose sender pays the Energy, such as BTT (TNuoKL1ni8aoshfFL1ASca1Gou9RXwAzfn, 18 decimals). Nile’s USDT pays its senders’ Energy itself, so it succeeds even without delegation. A covered transfer’s receipt (/wallet/gettransactioninfobyid) has energy_usage and no energy_fee, net_fee, or origin_energy_usage.

6. Reclaim unused gas

When the user no longer needs coverage, undelegate the full amount lent to them, read from /wallet/getdelegatedresourcev2:
To recover the TRX, call /wallet/unfreezebalancev2 on undelegated stake, wait out Stake 2.0’s unstaking period (14 days on mainnet), then call /wallet/withdrawexpireunfreeze.

Charge a fee

Gas sponsorship and fees are separate: this recipe covers your users’ gas, and a fee is what users pay your app. To charge users a fee on their transfers, with or without sponsoring their gas, see Charge a fee on TRON transfers.

Next steps

Footnotes

  1. energy_usage_total of 64,285 and 130,285 in the five most recent mainnet USDT (TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t) transfers checked on October 28, 2026. TRON’s dynamic Energy pricing changes these values, so estimate your own. ↩
  2. The fee of 1,100,000 SUN on a Nile AccountCreateContract in October 2026 (28714d8d…): TRON’s 1 TRX account creation fee (getCreateNewAccountFeeInSystemContract) plus 0.1 TRX of Bandwidth. ↩
  3. Free Bandwidth of 600 a day on mainnet and Nile. The 345 is the net_usage of BTT transfers on Nile on October 29, 2026; the exact value depends on the transaction’s size. ↩
  4. 345 Bandwidth × a getTransactionFee of 1,000 SUN = 345,000 SUN (0.345 TRX), the net_fee of each BTT transfer that burned TRX for Bandwidth on Nile on November 4, 2026, for example 8e105c25…. ↩
  5. TotalNetLimit / TotalNetWeight from /wallet/getaccountresource on Nile on November 4, 2026: 43,200,000,000 / 68,453,725,176 = 0.631. 345 Bandwidth / 0.631 = 547 TRX. ↩
  6. On Nile on November 4, 2026, a sponsor with 4,000 TRX staked for Bandwidth (2,524 Bandwidth a day) could delegate only 18 TRX of it after its own staking, delegation, and undelegation transactions that day, measured with getcandelegatedmaxsize (type: 0). ↩
Last modified on November 5, 2026