微单位、字符串字段,以及为什么 USDT 的小数位数不止一种。
本 API 中的每个金额都是以微单位表示的整数:精确到小数点后 6 位。
25000000 == 25.000000 USDT
100 == 0.000100 USDT
之所以用整数,是因为用浮点数表示金钱,就是一个迟早会发作的错误。之所以是 6 位,是因为在 USDT 小数位数最少的那条链上,它自身的精度就是 6 位。
每个金额字段都会出现两次:
{ "amount": 25000000, "amount_decimal": "25.000000" }
amount_decimal 之所以存在,是因为 JavaScript 在 JSON 中没有整数。JSON.parse 给你的是双精度浮点数,而 25000000 / 1e6 不一定等于 25。超过 2^53 微单位——约 90 亿 USDT——整数本身就不再精确。
能帮你避坑的规则:
amount_decimal,并使用十进制运算库进行计算,或者先自行解析成整数单位再计算。amount 是安全的。直接使用它即可。在请求中传入金额也是一样。传入 amount 或 amount_decimal,不要两者都传:
{ "amount_decimal": "25.00" }
{ "amount": 25000000 }
Tron 上是 6 位。BSC 上是 18 位。这是代币合约的属性,而不是链的属性,也是转账金额相差一万亿倍这类错误最常见的根源。
你完全不必操心:API 的每个字段都使用微单位。链上原始值会以 amount_raw 按付款路由公布,并附带 token_contract,供需要关心这一点的钱包使用。
amount_raw 是字符串,原因正如上文所述——25 × 10^18 无法放进双精度浮点数,而在 BSC 上每个金额都是这个数量级。
在默认的共享地址策略下,同一个地址上可能同时有多笔付款在等待到账。区分它们的是精确金额:系统会把金额调整几个微单位,确保同一地址上不会有两笔未完成的付款要求相同的数额。
这带来两个结果:
underpaid 或 overpaid,这两种状态都会触发事件,也都由你决定如何处理。不需要做任何取整。按你实际收取的精确数额创建付款即可;网关不会取整,低于配置最低金额的金额会以 amount_too_small 被拒绝,而不会被向上取整成客户没有同意的数额。