0. 为什么要做自动归集
运营一个多币种充值网关时,USDT 通常散落在成千上万个充值地址里,手动提币既耗时又烧钱;一套稳定的自动归集脚本可把零散余额汇总到冷钱包,大幅节省 BTC 手续费与人力。本文用 Omni Core 原生交易(raw transaction) 的方式,兼顾安全与灵活,并通过 Java 代码实现全自动。
1. 核心关键词
Omni Core 自动归集、USDT 原生交易、omni_createpayload_simplesend、omni_funded_send、比特币手续费估算
2. 前期准备
| 操作 | 说明 |
|---|---|
| 同步区块 | 全节点需要 100 % 同步到最新高度,否则查询不到未确认 UTXO |
| 创建托管钱包 | 每个归集账户准备一条私钥,可以放在 Omni Core 或外部签名校验 |
| 估算矿工费 | https://bitcoinfees.earn.com 的 halfHourFee ≈ 1–3 sat/vByte |
3. 手工演练:先用命令行跑一次
查询 UTXO
./omnicore-cli listunspent 1 99999 '["充值地址1","充值地址2"]'创建 Omni Layer 转账 payload
./omnicore-cli omni_createpayload_simplesend 31 "100.0"组合 BTC 空交易
./omnicore-cli createrawtransaction '[{"txid":"<utxo_txid>","vout":0}]' '{}'插入 payload
./omnicore-cli omni_createrawtx_opreturn <步骤3的结果> <步骤2的payload>指定归集地址
./omnicore-cli omni_createrawtx_reference <步骤4的结果> <归集地址>找零与矿工费
./omnicore-cli omni_createrawtx_change <步骤5的结果> '[{"txid":"<utxo_txid>","vout":0,"scriptPubKey":"<script>","value":金额}]' <找零地址> 0.00001000签名 & 广播
./omnicore-cli signrawtransactionwithwallet <hex> ./omnicore-cli sendrawtransaction <签名后的hex>
一次跑通后,把上述步骤映射到 Java RPC 调用即可。
4. Java 自动归集代码解读
下文代码删减异常处理细节,聚焦 原生交易 拼接流程。
public class UsdtCollector {
private final JsonRpcHttpClient client;
private final String username = "your_rpcuser";
private final String password = "your_rpcpassword";
private final String url = "http://127.0.0.1:18332"; // testnet即可
public String collect(BigDecimal usdtAmount) throws Exception {
String txid = null;
Map<String, Object> inputUtxo = findUtxo(); // 选>0.0001 BTC 的 UTXO
BigDecimal feeSat = calcFee(1); // 148*1+44 ≈ 192 Bytes
// 1. 构造空 BTC 交易
Object rawTx = client.invoke("createrawtransaction",
new Object[]{List.of(inputUtxo), new HashMap<>()}, Object.class);
// 2. 构造 Omni payload
String payload = (String) client.invoke("omni_createpayload_simplesend",
new Object[]{31, usdtAmount.toPlainString()}, String.class);
// 3. 嵌入 payload
String withOpReturn = (String) client.invoke("omni_createrawtx_opreturn",
new Object[]{rawTx, payload}, String.class);
// 4. 绑定收款地址
String withRef = (String) client.invoke("omni_createrawtx_reference",
new Object[]{withOpReturn, "<归集地址>"}, String.class);
// 5. 找零
String finalTx = (String) client.invoke("omni_createrawtx_change",
new Object[]{
withRef,
List.of(inputUtxo),
"<找零地址>",
feeSat.movePointLeft(8).toPlainString()
}, String.class);
// 6. 签名
Map<String, Object> sign = (Map) client.invoke("signrawtransactionwithwallet",
new Object[]{finalTx}, Map.class);
// 7. 广播
return (String) client.invoke("sendrawtransaction",
new Object[]{sign.get("hex")}, String.class);
}
}注意事项
id=31代表泰达币 USDT,以太坊网络 USDT 无此 ID;- 如果是 omni_funded_send(≥0.8.0 版本),可把手续费地址单独传入,归集时不需主地址自带 BTC。
5. 手续费动态估算
调用 bitcoinfees.earn.com/api/v1/fees/recommended 返回 JSON:
{"fastestFee":6,"halfHourFee":3,"hourFee":2}取 halfHourFee,再按公式 size = 148 × 输入数 + 44 × 输出数 + 10,
即可精准控制成本。
6. 常见问题 FAQ
Q1:为什么未确认的 BTC UTXO 也能用作手续费?
A:Omni 协议依附于 Bitcoin UTXO 模型,链上未确认交易里的输出态仍可作为输入,但 需要钱包节点开启零确认接收。
Q2:使用 omni_funded_send 会不会更安全?
A:它只是把“常规交易”帮你封装好了,核心风险仍是私钥泄露,建议专机专网,甚至用硬件钱包离线签名后再广播。
Q3:如何降低手续费到 1 sat/vByte?
A:将 target=144 调用比特币核心的 estimatesmartfee,再预留更长等待时间即可。
Q4:同步区块耗时太长,有没有轻量方案?
A:可接入 Neutrino 轻节点 + Omni RPC 代理,但这会失去全量校验能力,仅适合低金额快速测试。
Q5:测试网与主网参数的区别?
A:URL 端口改成 18332 (testnet) / 8332 (mainnet),USDT 财产 ID 主网同为 31,切勿混用网络。
Q6:.omnilisttransactions 在千亿级记录下慢怎么办?
A:给 addressindex=1、txindex=1,并定期 omni_cleanspent 清理已消费交易,可保持在 5s 内返回。
7. 结语
通过 Omni Core 的原生交易堆栈,你可以把自动归集 USDT做到极致轻量:仅一个 BTC UTXO 做载体,配合精确手续费,既不浪费链上空间,又不耽误资金安全回转。将本文代码微调成定时任务,即可实现“每天零点后一次性归集”的高效运维场景。