Energy for a TRC-20 approve and other TRON contract calls
Energy is what TRON charges for running contract code, and a USDT transfer is one contract call among many. An approve spends it too, and so does the transferFrom that later moves the approved funds. On 28 October 2026 we dry-ran both on the USDT contract: an approve took 99,764 units of energy when the allowance stood at zero and 33,764 when one was already set, and a transferFrom took 65,123 against an unlimited allowance and 89,325 against a limited one. Calls into other contracts have figures of their own, and rented energy pays for any of them the way it pays for a transfer.
A delegation raises the energy limit of the account it lands on, and every contract call that account signs spends from that limit before any TRX is burned (what TRON energy is). Nothing in a delegation names the contract or the function it is meant for. A call other than a transfer differs in how much it spends, which depends on the contract and function it calls and on the state it finds there, and on some contracts in how much of that the signer pays.
What the USDT calls spent in a dry run
A dry run is a constant call: a node executes the call against its own copy of the chain, reports the energy it used and discards the result. Nothing is signed or broadcast, and it costs nothing. We made ours through a public full node between 08:29 and 08:34 UTC on 28 October 2026. The owners were real accounts, picked out of the newest blocks just after each had approved a spender, and the pulls were dry-run from those spenders. The approve from zero went to an address we generated for our September measurement, which no owner had approved. We read each allowance and balance moments before the call. Every figure below came back from a call that would have succeeded. The transfer and both pulls moved one unit, a millionth of a USDT, to the same address, which holds USDT.
| USDT call, 28 October 2026 | Energy used | Of it, reported as energy_penalty | Burned at 100 sun a unit |
|---|---|---|---|
transfer to an address that holds USDT | 64,285 | 49,635 | 6.4285 TRX |
approve, allowance at zero | 99,764 | 77,076 | 9.9764 TRX |
approve, allowance already set | 33,764 | 26,076 | 3.3764 TRX |
transferFrom by the spender, against an unlimited allowance | 65,123 | 50,281 | 6.5123 TRX |
transferFrom by another spender, against a limited allowance | 89,325 | 68,976 | 8.9325 TRX |
The two kinds of approve came from the same owner for the same new amount. One spender had no allowance yet and the other had one standing, and the call for the first cost 66,000 units more. That is the same gap as between a transfer to an address with no USDT and one to a holder, which we measured in September at 130,285 and 64,285 (the two transfer figures). In both pairs the cheaper call overwrote a number that was already there and the dearer one wrote over a zero.
Unless the contract's deployer has agreed to carry part of it, as JustLend DAO's has (below), whoever signs a call pays its energy. In a flow where a customer approves a merchant's contract and the merchant later pulls the funds, the customer pays for each approve, and whoever signs the pulling call pays for it: the transferFrom in the table, plus the merchant contract's own code when the pull runs inside it. The two pulls we could dry-run differed in their allowance. With an unlimited one, the spender's transferFrom came to 838 units more than a plain transfer of the same amount to the same address, and with a limited one it cost 24,202 above that. That is one pair of each, and the pairs had different owners and spenders too.
A little over three quarters of every figure sits in a field the node calls energy_penalty, and the share is the same for all five calls, an approve as much as a transfer.
A lending contract: JustLend DAO's two calls
Renting energy from JustLend DAO is itself a pair of contract calls, one that opens the position and one that returns it (what that rental costs). We paired 30 rents with their returns from the contract's public record for the 24 hours that ended on the evening of 2 September 2026, and read what each call used, in total, from its receipt.
| JustLend DAO call, 2 September 2026 | Fewest | Median | Most |
|---|---|---|---|
Rent, rentResource | 52,672 | 69,306 | 84,290 |
Return, returnResource | 67,195 | 74,135 | 74,135 |
The table gives totals because the signer does not always pay all of it. The contract is set to charge its callers a tenth of the energy and to cover the rest from its deployer's own energy, up to 90,000 units a call, for as long as that energy lasts. Our own rent that evening used 84,290 units and its signer paid 8,429 of them. Under three hours earlier a third party's rent paid all 52,672 itself, because the deployer's energy had run out, and its return twelve seconds later paid 62,200 of 74,135. A dry run reports what a call uses, while the signer pays anything from the tenth the contract charges its callers up to all of it, depending on the deployer's energy at that second, so size the call for all of it.
Sizing a call nobody has measured for you
No table covers every contract, and the figures above move with the state a call finds. The number to trust is a dry run of that exact call, from the account that will sign it, made shortly before it is sent. Any full node answers it:
POST /wallet/triggerconstantcontract
{"owner_address": "T… (the account that will sign)",
"contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"function_selector": "approve(address,uint256)",
"parameter": "… (the arguments, ABI-encoded)",
"visible": true}
Check the answer before you take the number, because a call that would revert still reports energy. Two of our first transferFrom attempts went to pairs that could no longer pay: one allowance had been drawn in the seconds before we asked, and one owner held no USDT at all. They came back with 5,947 and 4,845 units for work that ends in failure. Their result.result still read true. What told them apart was FAILED in transaction.ret, where a call that succeeds leaves an empty entry.
Leave room above the figure, since an allowance can be spent and a recipient emptied between the dry run and the block. We leave room on our side too: our standard transfer figures, 65,000 and 131,000, sit 715 units above what the two transfers measure, and when a signed USDT transfer handed to us in mode B dry-runs above what a transfer to an empty address measures, we buy the measurement plus a margin and judge delivery against the measurement itself.
Set the transaction's fee_limit to cover the whole figure at the network's price of 100 sun a unit, even when the energy is rented. A node caps a call at its fee_limit divided by the energy price and counts delegated energy inside that cap, so a low limit stops a call that has every unit it needs on the account. Bandwidth is a separate meter: every call also pays for its bytes, and energy does not cover them (energy and bandwidth).
A swap through an exchange contract is the same arithmetic with one more contract in it: an approve that lets the exchange move the tokens, then the call into the exchange. We did not dry-run one.
Renting energy for a call by the unit
Our modes A and B are built around a USDT transfer, and mode B accepts a signed USDT transfer and nothing else. In mode A, when a transfer's recipient turns out to be a contract, we run the dry run for you: the item comes back as kind: custom, its energy_units are the measurement, and a contract_recipient warning says why (custom items, before anything is signed).
For every other call there is mode C. You name the wallet and the volume, and we delegate the energy to that wallet with no recipient involved (mode C in the API walk-through). The volume can be energy_units, any whole number from 65,000 to 50,000,000 per wallet, and the item comes back as kind: bulk. Mode C takes no custom, because there is no recipient for us to dry-run, so the measurement is yours. The wallet has to be activated on chain, and an order for one that is not comes back refused with inactive_wallet.
The five-minute lease takes volumes up to 131,000. Anything larger has to go on the one-hour lease, and we refuse it on the shorter one with bulk_needs_longer_lease: a large volume is assembled from several sources and lands in pieces seconds apart. An approve from zero fits under that line on its own, with room for a margin. Follow it with a transfer to a holder and the pair passes the line, so it goes on the hour. The smallest volume we sell covers an approve on a standing allowance with nearly as much again left over.
POST /v1/estimate with the same energy_units answers what that volume would be charged at this moment and, in coverage, whether the market has it now. Once delivered, the item stays ready until send_before and then reads expired, which here means the lease ran out: the normal end. The charge is for the delivery, and energy the wallet leaves unspent goes back with the delegation.
What we did not measure: a swap, a call into any contract other than USDT and JustLend DAO, a transferFrom to an address with no USDT, and whether these figures hold over weeks. Every USDT figure here is one constant call answered by one node; we sent no transaction, so none of them has been checked against a receipt.
Dry-run the call, then put that volume on the wallet that will sign it: mode c and energy_units on POST /v1/orders →