Reading a TRON transaction receipt: energy used, energy fee, bandwidth and the result
The transaction page of a block explorer shows a USDT transfer as a word, a fee and a few resource figures. A node returns the same transaction's receipt from gettransactioninfobyid, with a name on every figure: energy_usage, energy_usage_total, origin_energy_usage, energy_penalty_total, energy_fee, net_usage, net_fee and result. energy_fee is the TRX burned for energy the account did not have, at 100 sun a unit, net_fee is the TRX burned for bytes, and on every receipt in this post the top-level fee is the two added together. We keep mainnet receipts for each case worth reading: a transfer on rented energy, one paid in TRX, calls where the contract paid part of the energy, and transfers that stopped at OUT_OF_ENERGY or REVERT.
A missing field means zero
A receipt leaves out every field whose value is zero. A transfer that burned no TRX for energy has no energy_fee, and one whose bytes cost nothing has no net_fee. The amounts, energy_fee, net_fee and the top-level fee, are in sun, a millionth of a TRX.
One transfer on rented energy, one paid in TRX
Both transfers below consumed 130,285 units, the figure for a recipient with no USDT balance. The first is ours: on 2 September 2026 we rented energy from JustLend DAO to a second wallet and sent one USDT from it (what that order cost). The second is another sender's, from 6 October 2026, with no energy on the account. We read it from the sender's transaction list, which writes the same fields out flat beside the transaction, zeros included, and leaves energy_penalty_total out.
| Field | Rented energy, 2 September 2026 | No energy, 6 October 2026 |
|---|---|---|
Result: receipt.result, or contractRet in the list | SUCCESS | SUCCESS |
energy_usage | 130,285 | 0 |
energy_fee, sun | absent | 13,028,500 |
energy_usage_total | 130,285 | 130,285 |
energy_penalty_total | 100,635 | not in the list |
net_usage, bytes | absent | 0 |
net_fee, sun | 345,000 | 345,000 |
fee, sun | 345,000 | 13,373,500 |
| The fee in TRX | 0.345 TRX | 13.3735 TRX |
energy_usage_total is what the call consumed. energy_usage is the part the sender paid from energy it already had, staked or delegated, and energy_fee is the rest, bought by burning TRX at 100 sun a unit. On our transfer the first two are equal and the third is absent, so the delegation paid for every unit. The other sender had no energy, and 13,028,500 sun went on 130,285 units, exactly 100 sun each.
The bandwidth rows match. Neither account covered the bytes from bandwidth of its own, so each paid 345,000 sun: 345 bytes at 1,000 sun a byte, the rate in the chain parameters we read on 2 September 2026.
When the contract pays part of the energy
A contract's deployer can take on part of the energy of every call into it. The receipt then carries origin_energy_usage, the deployer's part. The caller pays the rest the way a transfer is paid, from its own energy first and by burning. JustLend DAO's energy market sets the caller's share at a tenth (consume_user_resource_percent is 10), and on all 83 of its receipts in our sample the caller's part equals energy_usage plus a hundredth of energy_fee.
| Field, 2 September 2026 | Our rent call | Another renter's return call |
|---|---|---|
energy_usage | 8,429 | 24 |
energy_fee, sun | absent | 739,000 |
origin_energy_usage | 75,861 | 66,721 |
energy_usage_total | 84,290 | 74,135 |
| Caller's part, total minus origin | 8,429 | 7,414 |
net_usage, bytes | 383 | absent |
net_fee, sun | absent | 378,000 |
fee, sun | absent | 1,117,000 |
The second caller had 24 units of its own and burned 739,000 sun for the other 7,390. Our rent call has no fee, although it sent the contract a prepayment: that money travels as the call's value, and fee counts only what the network took (where the prepayment went). None of the USDT receipts in this post carries an origin_energy_usage: on each one, the sender's own energy and its burn add up to the whole total.
An absent origin_energy_usage means the deployer paid nothing and the caller paid for the whole call. That is the most expensive case, and it looks exactly like a field nobody filled in. The deployer's share comes out of the deployer's own energy, and only while some is left. The same afternoon, under three hours before our rent, another renter's rent call on the same market carried no origin_energy_usage and paid all 52,672 units itself, 51,492 of them burned.
Bandwidth: net_usage against net_fee
Bandwidth is metered in bytes of the signed transaction (energy and bandwidth side by side). net_usage counts the bytes an account covered from its own bandwidth, the free daily allowance or a bandwidth stake. net_fee is what it paid in TRX for bytes it could not cover. In every receipt we hold it is one or the other.
Our JustLend order shows both. The rent call above has net_usage 383 and no net_fee: the wallet's free bandwidth covered it. Our own return call, from the same wallet 144 seconds later and not in the table above, has no net_usage and a net_fee of 378,000 sun. The free allowance is 600 a day by the chain's getFreeNetLimit, and what the rent left of it did not cover the return. Of the 83 JustLend receipts in our sample, 29 paid for their bytes, each at 1,000 sun a byte.
What the result word decides
The word appears twice in a receipt. A failed receipt carries a top-level result of FAILED whatever went wrong, with a resMessage in hex. The cause is one level down, in receipt.result: SUCCESS, OUT_OF_ENERGY or REVERT. A successful receipt has no top-level result at all, so a script that reads only the outer field files every failure under one name.
Three records from one wallet on 6 October 2026 show how OUT_OF_ENERGY comes about. They are one transfer signed three times, read from the transaction list because fee_limit belongs to the signed transaction. The third is the paid-in-TRX transfer from the first table.
| 6 October 2026 | 15:49 UTC | 16:24 UTC | 16:26 UTC |
|---|---|---|---|
fee_limit, sun | 1,100,000 | not set | 13,046,000 |
Result, contractRet | OUT_OF_ENERGY | OUT_OF_ENERGY | SUCCESS |
energy_usage_total | 11,000 | 0 | 130,285 |
energy_fee, sun | 1,100,000 | 0 | 13,028,500 |
net_usage, bytes | 344 | 0 | 0 |
net_fee, sun | 0 | 339,000 | 345,000 |
| The fee in TRX | 1.1 TRX | 0.339 TRX | 13.3735 TRX |
The first attempt stopped at exactly 11,000 units, its fee_limit divided by 100 sun: a node caps a call's energy at fee_limit over the energy price, whatever the account holds. The second carried no fee_limit, which counts as zero, so it could spend no energy at all. Its receipt has no energy fields, and its resMessage decodes to "Not enough energy for 'PUSH1' operation executing: curInvokeEnergyLimit[0], …". Three minutes later the same account paid for the third attempt, so it was not empty. Delegated energy falls under the same cap, which is why our API refuses a mode B transfer signed without enough fee_limit, with fee_limit_too_low, before we buy any energy.
Two other USDT transfers from the same few minutes show both failure words, each FAILED at the top level.
| Field, 6 October 2026 | Ran out of energy | Refused by the contract |
|---|---|---|
receipt.result | OUT_OF_ENERGY | REVERT |
energy_usage | 44,165 | 8,624 |
energy_fee, sun | 1,383,400 | absent |
energy_usage_total | 57,999 | 8,624 |
energy_penalty_total | 25,905 | 6,640 |
net_fee, sun | 345,000 | 345,000 |
| The fee in TRX | 1.7284 TRX | 0.345 TRX |
The first sender had 44,165 units of its own, burned TRX for 13,834 more, and ran out at 57,999, all that its energy and TRX together could buy. Its signed fee_limit allowed 350,000 units, so this time the account was the limit. In the second the contract refused the transfer: the resMessage reads "REVERT opcode executed", and USDT gives no reason when it reverts. Our API reference gives two causes: a sender that no longer holds the amount, and one frozen by the token's issuer (the failures payout desks meet).
Only a SUCCESS receipt records tokens moving: its log holds the token's Transfer event, as our rented transfer's does. The OUT_OF_ENERGY and REVERT receipts carry no log, because no tokens moved. Their fee is spent all the same, since whatever the call consumed before it stopped stays paid (why the TRX is gone after OUT_OF_ENERGY).
When we broadcast a client's signed transfer in mode B, the receipt also settles who pays for the energy. An OUT_OF_ENERGY receipt that spent less than the transfer's requirement, 64,285 units to an address holding USDT or 130,285 to one without, means our energy was not on the address when the call ran. The item closes expired and we charge for it, unless our records show the seller took the delegation back before the transfer's block, or that another of your transfers from the same address spent it. Then the shortfall is ours, as it is when a receipt spent at least the requirement and still ran out because our estimate was short: the item closes failed and we return the hold. One receipt we hold consumed 108,047 units and still stopped: on a transfer we had sized for a recipient holding USDT, that shortfall would be ours. We charge for a REVERT too.
The penalty is part of the total
On our rented transfer the total is 130,285 units, the wallet drew exactly 130,285 from its delegation, and 100,635 of those units carry the penalty label. The failed transfers agree: energy from the account plus energy burned comes to the total, penalty included.
The values we hold are 100,635 on a completed transfer to an address with no USDT, 25,905 on two transfers that ran out of energy and 6,640 on the one the contract refused. A node's dry run of a transfer reports a matching energy_penalty: 100,635 beside 130,285 for a recipient with no USDT, and 49,635 beside 64,285 for one that holds some. The chain parameters we read on 2 September 2026 have dynamic energy switched on (getAllowDynamicEnergy is 1), and the name fits a penalty that grows with the costlier recipient. We have not checked the node's arithmetic against those parameters, so what the penalty charges for is still unmeasured here.
Checking a rental against its receipt
After renting energy, two fields of the transfer's receipt say whether the rental did its job: energy_fee is absent, and energy_usage, plus any origin_energy_usage, equals energy_usage_total. An energy_fee on a transfer you rented for means some of its energy was bought with TRX after all. The delegation was smaller than the call, had not landed when the call ran, had already been taken back, or was spent first by another transfer from the same wallet (how a delegation starts and ends). The account itself can be read before sending (how to rent energy safely).
Hand us the signed transfer in mode B and the receipt becomes ours to read, item by item: every reason an item can close with, in the API reference →