Lire un reçu de transaction TRON : énergie utilisée, frais d'énergie, bande passante et résultat
La page d'une transaction sur un explorateur de blocs montre un transfert USDT comme un mot, des frais et quelques chiffres de ressources. Un nœud renvoie le reçu de la même transaction par gettransactioninfobyid, avec un nom sur chaque chiffre : energy_usage, energy_usage_total, origin_energy_usage, energy_penalty_total, energy_fee, net_usage, net_fee et result. energy_fee est le TRX brûlé pour l'énergie que le compte n'avait pas, à 100 sun l'unité, net_fee est le TRX brûlé pour les octets, et sur chaque reçu de cet article le fee de premier niveau est la somme des deux. Nous gardons des reçus du réseau principal pour chaque cas qui vaut d'être lu : un transfert sur de l'énergie louée, un payé en TRX, des appels où le contrat a payé une part de l'énergie, et des transferts arrêtés à OUT_OF_ENERGY ou REVERT.
Un champ absent veut dire zéro
Un reçu omet tout champ dont la valeur est zéro. Un transfert qui n'a brûlé aucun TRX pour l'énergie n'a pas d'energy_fee, et un dont les octets n'ont rien coûté n'a pas de net_fee. Les montants, energy_fee, net_fee et le fee de premier niveau, sont en sun, un millionième de TRX.
Un transfert sur de l'énergie louée, un payé en TRX
Les deux transferts ci-dessous ont consommé 130,285 unités, le chiffre pour un destinataire sans solde USDT. Le premier est à nous : le 2 septembre 2026, nous avons loué de l'énergie auprès de JustLend DAO au profit d'un second portefeuille et envoyé un USDT depuis celui-ci (ce que cette commande a coûté). Le second est celui d'un autre expéditeur, du 6 octobre 2026, sans énergie sur le compte. Nous l'avons lu dans la liste des transactions de l'expéditeur, qui écrit les mêmes champs à plat à côté de la transaction, zéros compris, et omet energy_penalty_total.
| Champ | Énergie louée, 2 septembre 2026 | Sans énergie, 6 octobre 2026 |
|---|---|---|
Résultat : receipt.result, ou contractRet dans la liste | 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 | pas dans la liste |
net_usage, octets | absent | 0 |
net_fee, sun | 345,000 | 345,000 |
fee, sun | 345,000 | 13,373,500 |
| Les frais en TRX | 0.345 TRX | 13.3735 TRX |
energy_usage_total est ce que l'appel a consommé. energy_usage est la part que l'expéditeur a payée avec l'énergie qu'il avait déjà, gelée ou déléguée, et energy_fee est le reste, acheté en brûlant des TRX à 100 sun l'unité. Sur notre transfert, les deux premiers sont égaux et le troisième est absent : la délégation a donc payé chaque unité. L'autre expéditeur n'avait pas d'énergie, et 13,028,500 sun sont partis sur 130,285 unités, exactement 100 sun chacune.
Les lignes de bande passante concordent. Aucun des deux comptes n'a couvert les octets avec une bande passante à lui, donc chacun a payé 345,000 sun : 345 octets à 1,000 sun l'octet, le tarif des paramètres de la chaîne que nous avons lus le 2 septembre 2026.
Quand le contrat paie une part de l'énergie
Le déployeur d'un contrat peut prendre à sa charge une part de l'énergie de chaque appel qui y entre. Le reçu porte alors origin_energy_usage, la part du déployeur. L'appelant paie le reste comme se paie un transfert, d'abord avec sa propre énergie puis en brûlant. Le marché d'énergie de JustLend DAO fixe la part de l'appelant à un dixième (consume_user_resource_percent vaut 10), et sur la totalité de ses 83 reçus de notre échantillon, la part de l'appelant égale energy_usage plus un centième d'energy_fee.
| Champ, 2 septembre 2026 | Notre appel de location | L'appel de restitution d'un autre locataire |
|---|---|---|
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 |
| Part de l'appelant, total moins origine | 8,429 | 7,414 |
net_usage, octets | 383 | absent |
net_fee, sun | absent | 378,000 |
fee, sun | absent | 1,117,000 |
Le second appelant avait 24 unités à lui et a brûlé 739,000 sun pour les 7,390 autres. Notre appel de location n'a pas de fee, bien qu'il ait envoyé un prépaiement au contrat : cet argent voyage comme valeur de l'appel, et fee ne compte que ce que le réseau a pris (où est allé le prépaiement). Aucun des reçus USDT de cet article ne porte d'origin_energy_usage : sur chacun, l'énergie propre de l'expéditeur et sa combustion font tout le total.
Un origin_energy_usage absent veut dire que le déployeur n'a rien payé et que l'appelant a payé tout l'appel. C'est le cas le plus cher, et il ressemble exactement à un champ que personne n'a rempli. La part du déployeur sort de l'énergie propre du déployeur, et seulement tant qu'il en reste. Le même après-midi, moins de trois heures avant notre location, l'appel de location d'un autre locataire sur le même marché ne portait aucun origin_energy_usage et a payé lui-même les 52,672 unités, dont 51,492 brûlées.
Bande passante : net_usage face à net_fee
La bande passante se mesure en octets de la transaction signée (énergie et bande passante côte à côte). net_usage compte les octets qu'un compte a couverts avec sa propre bande passante, l'allocation quotidienne gratuite ou un gel de bande passante. net_fee est ce qu'il a payé en TRX pour les octets qu'il n'a pas pu couvrir. Dans chaque reçu que nous détenons, c'est l'un ou l'autre.
Notre commande JustLend montre les deux. L'appel de location ci-dessus a un net_usage de 383 et pas de net_fee : la bande passante gratuite du portefeuille l'a couvert. Notre propre appel de restitution, depuis le même portefeuille 144 secondes plus tard et absent du tableau ci-dessus, n'a pas de net_usage et un net_fee de 378,000 sun. L'allocation gratuite est de 600 par jour d'après le getFreeNetLimit de la chaîne, et ce que la location en avait laissé n'a pas couvert la restitution. Sur les 83 reçus JustLend de notre échantillon, 29 ont payé leurs octets, chacun à 1,000 sun l'octet.
Ce que décide le mot de résultat
Le mot apparaît deux fois dans un reçu. Un reçu en échec porte un result de premier niveau à FAILED quelle que soit la cause, avec un resMessage en hexadécimal. La cause est un niveau plus bas, dans receipt.result : SUCCESS, OUT_OF_ENERGY ou REVERT. Un reçu réussi n'a aucun result de premier niveau : un script qui ne lit que le champ extérieur range donc tous les échecs sous un seul nom.
Trois enregistrements d'un même portefeuille le 6 octobre 2026 montrent comment arrive OUT_OF_ENERGY. Ce sont un seul transfert signé trois fois, lus dans la liste des transactions parce que fee_limit appartient à la transaction signée. Le troisième est le transfert payé en TRX du premier tableau.
| 6 octobre 2026 | 15:49 UTC | 16:24 UTC | 16:26 UTC |
|---|---|---|---|
fee_limit, sun | 1,100,000 | non défini | 13,046,000 |
Résultat, 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, octets | 344 | 0 | 0 |
net_fee, sun | 0 | 339,000 | 345,000 |
| Les frais en TRX | 1.1 TRX | 0.339 TRX | 13.3735 TRX |
La première tentative s'est arrêtée à exactement 11,000 unités, son fee_limit divisé par 100 sun : un nœud plafonne l'énergie d'un appel à fee_limit sur le prix de l'énergie, quoi que détienne le compte. La deuxième ne portait aucun fee_limit, ce qui compte pour zéro : elle ne pouvait donc dépenser aucune énergie. Son reçu n'a aucun champ d'énergie, et son resMessage se décode en « Not enough energy for 'PUSH1' operation executing: curInvokeEnergyLimit[0], … ». Trois minutes plus tard, le même compte a payé la troisième tentative : il n'était donc pas vide. L'énergie déléguée tombe sous le même plafond, ce qui explique pourquoi notre API refuse un transfert en mode B signé sans fee_limit suffisant, avec fee_limit_too_low, avant que nous achetions la moindre énergie.
Deux autres transferts USDT des mêmes quelques minutes montrent les deux mots d'échec, chacun FAILED au premier niveau.
| Champ, 6 octobre 2026 | À court d'énergie | Refusé par le contrat |
|---|---|---|
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 |
| Les frais en TRX | 1.7284 TRX | 0.345 TRX |
Le premier expéditeur avait 44,165 unités à lui, a brûlé des TRX pour 13,834 de plus, et s'est arrêté à 57,999, tout ce que son énergie et ses TRX ensemble pouvaient acheter. Son fee_limit signé autorisait 350,000 unités : cette fois, la limite était le compte. Dans le second, le contrat a refusé le transfert : le resMessage dit « REVERT opcode executed », et l'USDT ne donne aucune raison quand il fait un revert. Notre référence d'API donne deux causes : un expéditeur qui ne détient plus le montant, et un expéditeur gelé par l'émetteur du jeton (les échecs que rencontrent les équipes de paiement).
Seul un reçu SUCCESS consigne le déplacement de jetons : son log contient l'événement Transfer du jeton, comme celui de notre transfert loué. Les reçus OUT_OF_ENERGY et REVERT ne portent aucun log, car aucun jeton n'a bougé. Leurs frais sont dépensés quand même, puisque tout ce que l'appel a consommé avant de s'arrêter reste payé (pourquoi les TRX sont partis après OUT_OF_ENERGY).
Quand nous diffusons le transfert signé d'un client en mode B, le reçu tranche aussi la question de qui paie l'énergie. Un reçu OUT_OF_ENERGY qui a dépensé moins que l'exigence du transfert, 64,285 unités vers une adresse détenant des USDT ou 130,285 vers une adresse qui n'en détient pas, veut dire que notre énergie n'était pas sur l'adresse quand l'appel s'est exécuté. L'élément se ferme en expired et nous le facturons, sauf si nos enregistrements montrent que le vendeur a repris la délégation avant le bloc du transfert, ou qu'un autre de vos transferts depuis la même adresse l'a dépensée. Le manque est alors à nous, comme lorsqu'un reçu a dépensé au moins l'exigence et s'est tout de même arrêté parce que notre estimation était trop courte : l'élément se ferme en failed et nous rendons la réservation. Un reçu que nous détenons a consommé 108,047 unités et s'est pourtant arrêté : sur un transfert que nous avions dimensionné pour un destinataire détenant des USDT, ce manque serait à nous. Nous facturons aussi un REVERT.
La pénalité fait partie du total
Sur notre transfert loué, le total est de 130,285 unités, le portefeuille a tiré exactement 130,285 de sa délégation, et 100,635 de ces unités portent l'étiquette de pénalité. Les transferts en échec concordent : l'énergie du compte plus l'énergie brûlée fait le total, pénalité comprise.
Les valeurs que nous détenons sont 100,635 sur un transfert abouti vers une adresse sans USDT, 25,905 sur deux transferts qui ont manqué d'énergie et 6,640 sur celui que le contrat a refusé. L'exécution à blanc d'un transfert par un nœud rapporte un energy_penalty concordant : 100,635 à côté de 130,285 pour un destinataire sans USDT, et 49,635 à côté de 64,285 pour un qui en détient. Les paramètres de la chaîne que nous avons lus le 2 septembre 2026 ont l'énergie dynamique activée (getAllowDynamicEnergy vaut 1), et le nom s'accorde avec une pénalité qui grandit avec le destinataire le plus coûteux. Nous n'avons pas vérifié l'arithmétique du nœud contre ces paramètres : ce pour quoi la pénalité facture reste donc ici non mesuré.
Vérifier une location sur son reçu
Après avoir loué de l'énergie, deux champs du reçu du transfert disent si la location a fait son travail : energy_fee est absent, et energy_usage, plus tout origin_energy_usage, égale energy_usage_total. Un energy_fee sur un transfert pour lequel vous avez loué veut dire qu'une partie de son énergie a tout de même été achetée avec des TRX. La délégation était plus petite que l'appel, n'était pas arrivée quand l'appel s'est exécuté, avait déjà été reprise, ou a été dépensée d'abord par un autre transfert du même portefeuille (comment une délégation commence et finit). Le compte lui-même peut être lu avant l'envoi (comment louer de l'énergie en toute sécurité).
Remettez-nous le transfert signé en mode B et c'est à nous de lire le reçu, élément par élément : toutes les raisons pour lesquelles un élément peut se fermer, dans la référence de l'API →