通过API在TRON查询TRC-20代币余额
读取 TRC-20 余额是 TRON 上支付仪表板、交易集成和钱包应用程序的基础。与TRX(原生)不同,代币余额存在于每个代币的智能合约中——您可以在合约上查询balanceOf(address)。
本指南展示了 TronWeb、TronGrid REST,以及 USDT 和任意 TRC-20 代币的生产注意事项。
USDT 合约参考
主网官方USDT:
TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t
小数:6(1 USDT = 1_000_000 基本单位)。
方法一:TronWeb
const TronWeb = require('tronweb');
const tronWeb = new TronWeb({
fullHost: 'https://api.trongrid.io',
headers: { 'TRON-PRO-API-KEY': process.env.TRONGRID_KEY },
});
const USDT = 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t';
async function getTrc20Balance(holderAddress, contractAddress = USDT) {
if (!tronWeb.isAddress(holderAddress)) throw new Error('Invalid address');
const contract = await tronWeb.contract().at(contractAddress);
const raw = await contract.balanceOf(holderAddress).call();
const decimals = await contract.decimals().call();
const divisor = Math.pow(10, Number(decimals));
return Number(raw) / divisor;
}
注意:.call() 行为可能会返回类似 BigNumber 的对象——在生产中仔细规范化。
方法二:TronGrid 账户端点
GET https://api.trongrid.io/v1/accounts/{address}
响应包括 trc20 数组,其中包含由合约地址键入的代币余额。
解析示例(结构可能有所不同):
async function getUsdtFromAccountApi(address) {
const res = await fetch(
`https://api.trongrid.io/v1/accounts/${address}`,
{ headers: { 'TRON-PRO-API-KEY': process.env.TRONGRID_KEY } }
);
const json = await res.json();
const trc20 = json.data?.[0]?.trc20 || [];
for (const entry of trc20) {
const [[contract, balance]] = Object.entries(entry);
if (contract === USDT) return Number(balance) / 1e6;
}
return 0;
}
适合一次列出所有代币;对于实时支付边缘情况不太精确。
方法三:triggerconstantcontract
每个触发智能合约的低级HTTP:
function_selector:balanceOf(address)parameter:ABI编码的持有者地址contract_address:代币合约
当 TronWeb 不可用时使用(非 JS 堆栈)。
小数处理
永远不要假设 18 位小数。始终调用 decimals() 或使用已知常量:
| 代币 | 小数 |
|---|---|
| USDT | 6 |
| 许多自定义令牌 | 18 |
使用整数数学 (BigInt) 来确保财务准确性 — 避免大额余额上的 JavaScript 浮动错误。
TRX 余额与代币{#trx}
const balanceSun = await tronWeb.trx.getBalance(address); const balanceTrx = tronWeb.fromSun(balanceSun);
用户即使只持有USDT,也需要TRX来支付费用。
生产模式{#生产}
付款轮询
对于接受USDT付款:
- 为每个用户生成唯一的存款地址 或 按金额+备注模式跟踪
- 预期付款窗口后投票
balanceOf - 更好:USDT
Transfer事件的事件监听器
缓存
- UI 的缓存余额具有短 TTL(10-30 秒)
- 检测到传入的
Transfer事件时无效
速率限制
尊重 TronGrid 限制 — 非高峰期批量地址查询。
多令牌支持
抽象助手:
async function getTokenBalance(holder, tokenContract) {
const c = await tronWeb.contract().at(tokenContract);
const [raw, decimals] = await Promise.all([
c.balanceOf(holder).call(),
c.decimals().call(),
]);
return { raw: raw.toString(), decimals: Number(decimals) };
}
批量余额查询
对于许多地址,避免 N+1 常量调用。使用 TronGrid v1 帐户令牌端点或与速率限制感知并行。对数据库中的存款地址进行索引,并仅轮询活动发票以减少 API 负载。
小数处理陷阱
USDT 使用 6 位小数;许多 TRC-20 代币使用 18。切勿在未除以 10**decimals 的情况下显示原始 balanceOf。在 JavaScript 中将金额存储为字符串或 BigInt 以避免浮点错误。小数点后一位的错误已导致支付系统在其他链上的生产事件中记入预期金额的 1e12 倍——同样的风险也适用于TRON。
相关指南 {#相关}
常见问题解答
TRON主网上的USDT合约地址是什么?
TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t — 在生产使用之前始终验证TronScan。
BalanceOf 需要私钥吗?
不。balanceOf是一个只读合约调用,任何全节点或TronGrid都可以执行。
为什么API余额与TronLink不同?
时间安排、未确认的交易或错误的合约地址。确认最新区块和合约。
可以查询历史余额吗?
需要存档节点/索引器 - 非标准 TronGrid 帐户端点。自行使用 TronScan API 或索引 Transfer 事件。
转账后余额更新的速度有多快?
交易确认后(约 3 秒)。轮询getTransaction直到SUCCESS,然后读取余额。
感谢你的反馈——帮助我们改进文档。