在 TRON 上从充值地址归集 USDT:每次归集的激活、能量与带宽
给每位客户一个专属充值地址的支付网关或交易所,必须先把这些地址上的 TRC-20 USDT 归集到一个主钱包,也就是热钱包,才能把其中任何一部分付出去。在 TRON 上,每一次这样的归集都是一笔普通的 USDT 转账,由充值地址签名。它需要链上有账户,需要为合约调用准备的能量,以及为字节准备的带宽,而一个只收过 USDT 的充值地址,这三样都没有。
收到 USDT 并不会创建账户
USDT 余额是代币合约自己存储里的一个条目。转入一笔只会写这个条目,不会创建账户,所以一个地址可以持有 USDT,而网络里根本没有它的账户。我们 2026 年 9 月 7 日的测量在主网上找到了两个这样的地址:每个都持有 USDT,而我们读取的节点在被问到它背后的账户时,不管是在我们的测试调用之前还是之后,返回的都是一个空对象。到 10 月 27 日,两者持有的余额与 9 月 7 日时分毫不差。
能量是代理给账户的,我们不会把它交付给没有账户的地址:在 mode A 或 mode C 里,把这样一个地址写成 from 的订单,会返回 422 invalid_address,details.reason 为 inactive_wallet。链本身会不会接受往这样一个地址的代理,我们没有测过,因为我们的拒绝在前面。我们的运维笔记里还记着节点对一个从未收到过任何东西的钱包发起发送时的答复,no OwnerAccount。那条记录说的是从我们自己的热钱包发出的 TRX;我们没有试过从处于这个状态的地址发出一笔 USDT 转账。这个状态更完整的来龙去脉,见讲未激活账户的那一篇。
激活一个地址只需要一笔 TRX 转账,由发送方付费
任何一笔转入的 TRX,不管多小,都会创建账户,从那以后这个地址就和别的账户一样了。那次测量的第一次尝试恰恰栽在这一点上,我们把它作废了:一个地址读出来没有账户,22 秒之后有人往它转了一个 sun,账户就这样被创建了。它自己的创建时间说明了这一点。
创建它的费用由发送 TRX 的一方承担:在归集的架构里,就是出资激活的那个钱包。有两个链上参数决定这笔费用。我们是在 2026 年 9 月 3 日读的,网络可以修改它们,所以在用它们做预算之前请重新读一遍。
| 链上参数 | 值,读于 2026 年 9 月 3 日 |
|---|---|
getCreateAccountFee | 0.1 TRX |
getCreateNewAccountFeeInSystemContract | 1 TRX |
这两项在一笔普通的 TRX 转账上怎么叠加,我们没有用自己发出的转账量过:那需要往一个全新的地址发一笔真实转账,而我们一笔也没发过。不管怎样,这笔费用每个地址只付一次。在每个地址生成时就激活它的团队,会在可能永远收不到充值的地址上付这笔钱;在第一笔充值到账时才激活的团队,只在有东西可归集的地方付。
每一次归集都按较低的那个能量数
一笔 USDT 转账花多少能量,取决于收款方。收款方已经持有 USDT 时,这笔转账大约要 65,000 单位;它的 USDT 余额为零时,大约要 131,000。收款方有没有账户,不在其中起作用。找到那两个地址的测量把四种组合并排摆了出来,每一次都是余额说了算(为什么有两个数)。
归集付给的总是同一个收款方,即热钱包,而热钱包持有 USDT。所以每一次归集都是较便宜的那一种,single,不管充值地址处在什么状态。9 月 7 日的那几次调用,是从一个留下其余余额的钱包里挪出一个单位,而归集挪走的是全部,把充值地址留在零。10 月 27 日,我们让节点在同样那两个地址上对两种情形各做了模拟,收款方是一个持有 USDT 的钱包。
| 转给持有 USDT 的钱包的模拟转账,2026 年 10 月 27 日 | 使用的能量 |
|---|---|
| 第一个地址,一个单位 | 64,285 |
| 第一个地址,它的全部余额 | 64,285 |
| 第二个地址,一个单位 | 64,285 |
| 第二个地址,它的全部余额 | 64,285 |
把充值地址清空没有带来任何变化,这个数就是那次测量对每笔转给持有者的转账所给出的那个。这些是节点的模拟,没有一个是已广播归集的回执;9 月 7 日的数字也带着同样的保留。这两个地址今天有没有账户,我们没有重新读。
丢掉较便宜那一种的唯一办法,是把热钱包清空。收款方上只要有一个单位的 USDT,就够按较低的那个数计,但到了零,下一次归集进去要大约 131,000 单位,烧的话就是 13.1 TRX。烧的话,一次正常的归集按每单位 100 sun 的协议价花 6.5 TRX,而租用同样的能量要花多少跟着市场走。
免费带宽每个地址每天大约够一次归集
带宽计量的是交易的字节,而能量计量的是它的计算(两只表放在一起看)。每个账户每天都有一份免费的带宽额度。我们 2026 年 9 月 2 日在主网上发出并量过的那笔 USDT 转账,是用 TRX 付的带宽费,由此可以精确算出它被计了多少带宽。
| 一笔 USDT 转账的带宽 | 值 | 读取日期 |
|---|---|---|
为字节烧掉的(net_fee) | 0.345 TRX | 2026 年 9 月 2 日 |
一个字节的燃烧价(getTransactionFee) | 1,000 sun | 2026 年 9 月 3 日 |
| 被计的带宽,由除法算出 | 345 字节 | 算出 |
每个账户每天的免费额度(getFreeNetLimit) | 600 | 2026 年 9 月 3 日 |
对着每天 600 的额度,按这个数计费的一次归集装得下,背靠背的两次就装不下了。超出额度后,网络为字节烧发送方的 TRX。所以一个地址一天里的第一次归集,在带宽上不花任何钱,而一个同时通过代理拿到能量的充值地址,发送它不需要自己的任何 TRX。紧跟着第一次之后的第二次归集,要用充值地址里的 TRX 来付它的字节。额度在这两次之间恢复得多快,我们没有量过;我们自己的归集按每个地址每天大约一笔、用免费额度来规划。如果一个地址被归集得比这更频繁,激活用的那笔转账可以同时给它留下付这些字节的 TRX。
为一轮归集订购能量
mode A 写明每笔转账的两端,充值地址作 from,热钱包作 to,而类型由我们自己从热钱包上读出。mode C 只写明要充能的那个钱包,类型由您给出,这适合按自己的节奏签名归集、并希望能量先到位的托管系统(mode C 详解)。对归集来说,只要热钱包持有 USDT,这个类型始终是 single。两种模式一个订单都最多收 500 笔转账,与一轮付款是同一个上限。租期是五分钟或一小时,send_before 比它的结束早三秒。
只要有一个充值地址没有账户,整个订单都会被拒绝。422 在 details.index 和 details.address 里指出是哪一个,什么也不会买。所以先筛一遍这一轮。POST /v1/estimate 同样接受 500 笔转账,不预留任何东西,并且会在订单会被拒绝的地方发出警告:给每个条目带上 from,每个没有账户的充值地址都会被标上 inactive_sender 返回。把这些地址激活,等激活确认,再下订单。这个拒绝不会消耗 Idempotency-Key,而且我们在因此拒绝订单之前,会绕过缓存重读激活状态,所以一旦激活转账确认,同一个键、同一个请求体就能用了。
从我们自己的归集里值得带走的规则
我们自己也跑着一套归集。客户把钱付到我们替他们持有的充值地址,后台的一轮任务把这些币挪到那个用来支付采购的热钱包。它挪的是 TRX,所以花的是带宽而不是能量,它的记录对 USDT 归集的能量一侧什么也没说。
我们的归集在决定的那一刻从链上读金额。我们自己的记录不知道被烧掉的费用,也不知道哪一笔归集的数据库行没能在进程崩溃中保住,而链知道。同一条规则也让重试变得安全:币如果已经离开,就没有东西可发。
对一笔已广播的归集,我们让它一直保持打开,直到它的交易出现在某个区块里,而且只有在经过一个不短于我们的签名服务给交易设的最长过期时间的窗口之后,才把它记为失败。关得早了,一笔仍有可能落地的转账会被当成丢失,下一轮就可能对同一份余额再签一笔转账。归集尚未确认期间,它的地址不参加下一轮。
我们的 TRX 归集最多发出余额减去一笔手续费预留,而且只在地址的免费带宽已经用完时才留这笔预留。USDT 归集用另一种币付费,不是它所挪的那种,所以每次都是整笔 USDT 余额全部发出,而这笔预留就变成了充值地址为一天里第二次归集的字节所需的 TRX。
在给归集定价之前,找出每一个仍需激活的充值地址,一次请求五百个:每个条目都带 from 的 POST /v1/estimate →