为什么一笔 USDT 转账需要 65,000 能量,空地址需要 131,000
问一笔 TRON 上的 USDT 转账要多少能量,所有来源给的都是同样两个答案:大约 65,000 单位;收款方没有 USDT 时,大约 131,000 单位。按网络每单位 100 sun 的燃烧费率,这就是钱包里显示成手续费的 6.5 TRX 和 13.1 TRX。几乎没有人说这两个数从哪里来。我们去问了节点,它自己的记账把每一个数都拆成了两部分:能量里有四分之三以上是网络动态能量模型下的附加费,而 USDT 按网络允许的最高系数交这笔附加费。收款地址没有 USDT 时多出来的 66,000,是 15,000 单位的额外工作量,再加上同一个系数的附加费。
节点对一笔转账报告了什么
节点可以不发送、只把一次合约调用跑一遍。它对着自己手里那份链的副本执行这次调用,答完就把结果丢掉,所以没有签名,也没有付费。2026 年 9 月 7 日,我们跑了四次这样的调用,每次都是最小额的一笔转账——一个单位,也就是百万分之一个 USDT——从一个余额有数千的钱包转出,转给四种收款方:有或没有 USDT,链上有或没有账户。几分钟后,我们换了几个地址把这一组又跑了一遍,一共八次调用。
每个答复里都带着人人引用的那个数字 energy_used,旁边还有第二个数字 energy_penalty。两次运行对每一种收款方给出的是同一对数字:
| 收款方,2026 年 9 月 7 日 | energy_used | energy_penalty | 差值 |
|---|---|---|---|
| 持有 USDT,账户已激活 | 64,285 | 49,635 | 14,650 |
| 持有 USDT,从未激活 | 64,285 | 49,635 | 14,650 |
| 没有 USDT,账户已激活 | 130,285 | 100,635 | 29,650 |
| 没有 USDT,从未激活 | 130,285 | 100,635 | 29,650 |
收款方有没有账户,并不造成差别:一个网络从没听说过的地址,和余额相同的老地址花的一样多。起决定作用的是余额,而分界线就划在零。第二次运行里,一个只持有一个单位 USDT(即百万分之一个代币)的收款方,拿到的是较低的那个数。这对一个订单意味着什么,见讲账户未激活的那一篇。
2026 年 10 月 27 日,我们把其中两次调用又跑了一遍,还是从同一个钱包转出,转给同样的两个地址,一个持有 USDT,一个是空的。两次返回的 energy_used 和 energy_penalty 都和 9 月一样,一个单位不差。
附加费及其参数
链上有一个开关,管的是它所谓的动态能量,而每个合约都带着自己的 energy_factor。随它而来的还有三个网络参数,按名字看,它们分别是一个使用量阈值、系数每次上调的步长,以及一个上限:被大量使用的合约,每次调用要多付能量。我们在 2026 年 9 月 3 日读了这些参数,10 月 27 日又读了一次,那一次也读了 USDT 自己的系数。两次读到的参数没有变。
| 从链上读到的 | 值 |
|---|---|
动态能量已开启,getAllowDynamicEnergy | 1 |
阈值,getDynamicEnergyThreshold | 5,000,000,000 |
步长,getDynamicEnergyIncreaseFactor | 2,000 |
上限,getDynamicEnergyMaxFactor | 34,000 |
USDT 的 energy_factor,2026 年 10 月 27 日 | 34,000 |
燃烧费率,每单位多少 sun,getEnergyFee | 100 |
USDT 就停在上限上。我们读到这个系数的同一个晚上,转给持有者的那次转账报出的 energy_penalty 与 9 月相同,所以 9 月的数字同样符合 34,000 这个系数。
拆开 65,000 和 131,000
把 energy_penalty 读作附加费,其余读作调用本身的工作量,也就是它的基础成本。这样,两种转账就相差 15,000 单位的工作量和 51,000 单位的附加费:
| 每笔转账的能量 | 持有 USDT | 没有 USDT | 差值 |
|---|---|---|---|
| 基础成本 | 14,650 | 29,650 | 15,000 |
| 附加费 | 49,635 | 100,635 | 51,000 |
| 合计 | 64,285 | 130,285 | 66,000 |
差值那一列的算术是精确的:多出来的 15,000 单位工作量带着 51,000 单位附加费,每五份对应十七份,这正是把系数 34,000 按万分之几来数的结果。所以把那两个常被引用的数字隔开的 66,000,就是一整块额外工作量,按 USDT 的系数加收了附加费。
调用的其余部分和这个比率差了一点。14,650 的五分之十七倍是 49,810,而节点报出的是 49,635,低了 175 单位。余额为零的那种情形同样低了 175 单位,所以这个缺口出在两种转账共有的那部分工作里。49,635 不是任何整数的五分之十七倍,所以这个缺口不可能是调用中逃过了附加费的某一段;而在同一次调用报出同样附加费的那个晚上,读到的系数就是 34,000。这个规律看起来像舍入:附加费是对调用的许多小步骤逐个算出来的。我们没有拿节点的代码核对这一点,所以表里印的是节点报出的数字,那 175 单位就不作解释。
多出来的 15,000 单位工作量是什么
USDT 余额是代币合约自己存储里的一个条目,和 TRON 账户是分开放的,所以没有账户的地址也能持有 USDT。转给一个有余额的地址,是在一个已经存着数字的条目上覆写。转给零余额的地址,是往一个空条目里写入。对这个差距通常的解释是:往空条目里写,比覆写花得多,而 15,000 与此相符。我们的探测量到了这笔开销,却没有检验这个原因,所以请把它当作数字与之吻合的一种解释。
如果这个解释成立,一个曾经持有过 USDT、后来把它全部转走的地址,应该按较高的那个数计费,因为它的条目已经回到了零。搜索结果里至少有一个页面说,这样的地址可能仍然按较低的那个数计。我们没有为这种情况专门设计探测,但已记录的探测里恰好有一次覆盖了它。第一次运行里有一个零余额的收款方,是我们从 USDT 转账流水里作为发送方挑出来的:就在探测的整整一周前,它转出了略多于 44 USDT。所以它持有过 USDT,后来被转空了,而转给它的那一笔是 130,285,和为这次运行生成的那个地址一样。这是一个地址,只读了一次。
从 64,285 到 65,000
整数的数字略高于量到的数字。我们的服务也是这样向上取整的:这里的订单按两种转账分别定为 65,000 或 131,000 单位,而实测需要的是 64,285 和 130,285。无论哪一种,都留出 715 单位的余量。向上取整是安全的一侧,因为能量不够的转账,要么为不足的部分烧掉发送方的 TRX,要么在不允许烧的时候失败,而且能量已经花出去了(这种失败是什么样子)。改成烧、不去租,实测的数字比整数略少一点:
| 收款方 | 实测能量 | 按每单位 100 sun 烧掉 |
|---|---|---|
| 持有 USDT | 64,285 单位 | 6.4285 TRX |
| 没有 USDT | 130,285 单位 | 13.0285 TRX |
这两个数字只算能量。一笔转账还会消耗带宽,那是另一只表,账单小得多(能量和带宽放在一起看)。
什么会让这些数字动起来
第一个杠杆是系数。它属于合约,而按参数的名字看,它随合约的使用量分档上调,直到上限。USDT 现在就在上限上,所以从这里起,系数只能维持或下降,除非上限本身被改动。阈值、步长和上限都是网络参数,网络的治理可以修改它们。在上限处,附加费占一笔 USDT 转账所花能量的四分之三以上。按这些数字算,没有它,同样转给持有者的这笔转账只需要它的基础成本,即 14,650 单位。
第二个是燃烧费率 getEnergyFee,我们读它的那两天都是每单位 100 sun。它决定烧掉这些能量要花多少 TRX,而无论它是多少,能量的数量都不变。网络以前改过它,那篇讲手续费的指南按今天的费率把算术摆了出来。我们两组探测相隔的七周里,能量这一侧没有动:两次都是 64,285 和 130,285。
在任何东西被签名之前,先查清一个收款方会花哪一个数:API 参考文档里的 GET /v1/address-check →