From 922f6df4e8ac93fd526cf014c7bf08798ac85a62 Mon Sep 17 00:00:00 2001
From: TQCasey <494294315@qq.com>
Date: Tue, 3 Feb 2026 13:07:29 +0800
Subject: [PATCH] fix bugs
---
cmd/server/main.go | 11 ++-
index.html | 2 +-
tron_usdt_monitor.go | 184 +++++++++++++++++++++++++++++--------------
3 files changed, 133 insertions(+), 64 deletions(-)
diff --git a/cmd/server/main.go b/cmd/server/main.go
index 3c5a3d8..9884517 100644
--- a/cmd/server/main.go
+++ b/cmd/server/main.go
@@ -56,8 +56,8 @@ func main() {
// 设置收款回调
uman.OnPaymentComplete(func(payment *usdtman.USDTPayment) {
- log.Printf("💰 收到 USDT: %s -> %.6f USDT (确认数: %d, TxID: %s)",
- payment.From, payment.Amount, payment.Confirmations, payment.TxID)
+ log.Printf("💰 收到 USDT: %s -> %s USDT (确认数: %d, TxID: %s)",
+ payment.From, payment.GetAmountString(), payment.Confirmations, payment.TxID)
paymentLock.Lock()
paymentEvents = append(paymentEvents, *payment)
@@ -69,6 +69,10 @@ func main() {
broadcastPayment(payment)
})
+ // test code
+ uman.AddAddress("TWwGSYwpSzT6GTBr4AQw9QF6m4VVui3UGc") // tronlink trc20 gasfree 地址
+ uman.Start()
+
http.HandleFunc("/start", startMonitor)
http.HandleFunc("/stop", stopMonitor)
http.HandleFunc("/add-address", addAddress)
@@ -222,7 +226,8 @@ func broadcastPayment(payment *usdtman.USDTPayment) {
message := map[string]interface{}{
"type": "usdt_payment",
"address": payment.Address,
- "amount": payment.Amount,
+ "amount": payment.GetAmountFloat(),
+ "amountRaw": payment.Amount.String(),
"from": payment.From,
"txId": payment.TxID,
"block": payment.BlockNumber,
diff --git a/index.html b/index.html
index 7fa1a1f..2e7c358 100644
--- a/index.html
+++ b/index.html
@@ -113,7 +113,7 @@
data.data.payments.map(p =>
'
| ' + new Date(p.Timestamp).toLocaleString() + ' | ' +
'' + p.Address.substring(0, 10) + '... | ' +
- '' + p.Amount.toFixed(6) + ' USDT | ' +
+ '' + (p.Amount / 1000000).toFixed(6) + ' USDT | ' +
'' + p.From.substring(0, 10) + '... | ' +
'' + p.Confirmations + ' | ' +
'' +
diff --git a/tron_usdt_monitor.go b/tron_usdt_monitor.go
index 7d0f0f1..58dcc2f 100644
--- a/tron_usdt_monitor.go
+++ b/tron_usdt_monitor.go
@@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"io"
+ "math/big"
"net/http"
"net/url"
"strings"
@@ -43,7 +44,7 @@ type USDTMan struct {
// USDTPayment USDT 收款信息
type USDTPayment struct {
Address string
- Amount float64
+ Amount *big.Int // 原始金额(micro USDT,10^-6),例如 13260000 = 13.26 USDT
TxID string
BlockNumber int64
Timestamp int64
@@ -51,23 +52,57 @@ type USDTPayment struct {
Confirmations int64
}
-// TronGridTransaction 交易信息
+// GetAmountFloat 获取浮点数金额(USDT)
+func (p *USDTPayment) GetAmountFloat() float64 {
+ divisor := new(big.Float).SetInt64(1000000)
+ amount := new(big.Float).SetInt(p.Amount)
+ result := new(big.Float).Quo(amount, divisor)
+ f, _ := result.Float64()
+ return f
+}
+
+// GetAmountString 获取字符串金额(USDT,保留6位小数)
+func (p *USDTPayment) GetAmountString() string {
+ return fmt.Sprintf("%.6f", p.GetAmountFloat())
+}
+
+// MarshalJSON 自定义 JSON 序列化
+func (p *USDTPayment) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Address string `json:"Address"`
+ Amount float64 `json:"Amount"`
+ AmountRaw string `json:"AmountRaw"`
+ TxID string `json:"TxID"`
+ BlockNumber int64 `json:"BlockNumber"`
+ Timestamp int64 `json:"Timestamp"`
+ From string `json:"From"`
+ Confirmations int64 `json:"Confirmations"`
+ }{
+ Address: p.Address,
+ Amount: p.GetAmountFloat(),
+ AmountRaw: p.Amount.String(),
+ TxID: p.TxID,
+ BlockNumber: p.BlockNumber,
+ Timestamp: p.Timestamp,
+ From: p.From,
+ Confirmations: p.Confirmations,
+ })
+}
+
+// TronGridTransaction TRC20 交易信息
type TronGridTransaction struct {
- Ret []map[string]interface{} `json:"ret"`
- TxID string `json:"txID"`
- BlockNumber int64 `json:"blockNumber"`
- BlockTimeStamp int64 `json:"block_timestamp"`
- RawData struct {
- Contract []struct {
- Parameter struct {
- Value struct {
- Amount int64 `json:"amount"`
- To string `json:"to_address"`
- From string `json:"owner_address"`
- } `json:"value"`
- } `json:"parameter"`
- } `json:"contract"`
- } `json:"raw_data"`
+ TransactionID string `json:"transaction_id"`
+ BlockTimestamp int64 `json:"block_timestamp"`
+ From string `json:"from"`
+ To string `json:"to"`
+ Type string `json:"type"`
+ Value string `json:"value"`
+ TokenInfo struct {
+ Symbol string `json:"symbol"`
+ Address string `json:"address"`
+ Decimals int `json:"decimals"`
+ Name string `json:"name"`
+ } `json:"token_info"`
}
// TronGridAccountTransactions 账户交易列表
@@ -75,8 +110,8 @@ type TronGridAccountTransactions struct {
Success bool `json:"success"`
Data []TronGridTransaction `json:"data"`
Meta struct {
- PageSize int `json:"page_size"`
- Fingerprint string `json:"fingerprint"`
+ At int64 `json:"at"`
+ PageSize int `json:"page_size"`
} `json:"meta"`
}
@@ -221,28 +256,51 @@ func (m *USDTMan) checkAddress(address string) {
for _, txn := range transactions {
// 检查是否已处理
m.txnMutex.RLock()
- processed := m.processedTxns[txn.TxID]
+ processed := m.processedTxns[txn.TransactionID]
m.txnMutex.RUnlock()
if processed {
continue
}
+ // 获取交易的区块号(需要通过 transaction_id 查询)
+ blockNumber, err := m.getTransactionBlock(txn.TransactionID)
+ if err != nil {
+ fmt.Printf("Error getting transaction block: %v\n", err)
+ continue
+ }
+
// 计算确认数
- confirmations := currentBlock - txn.BlockNumber
+ confirmations := currentBlock - blockNumber
if confirmations < m.minConfirmations {
continue
}
- // 解析交易数据
- payment := m.parseTransaction(&txn, address, confirmations)
- if payment == nil {
+ // 检查是否是转入该地址
+ if !strings.EqualFold(txn.To, address) {
continue
}
+ // 解析金额(使用 big.Int)
+ amount := new(big.Int)
+ amount, ok := amount.SetString(txn.Value, 10)
+ if !ok || amount.Sign() <= 0 {
+ continue
+ }
+
+ payment := &USDTPayment{
+ Address: address,
+ Amount: amount,
+ TxID: txn.TransactionID,
+ BlockNumber: blockNumber,
+ Timestamp: txn.BlockTimestamp,
+ From: txn.From,
+ Confirmations: confirmations,
+ }
+
// 标记为已处理
m.txnMutex.Lock()
- m.processedTxns[txn.TxID] = true
+ m.processedTxns[txn.TransactionID] = true
m.txnMutex.Unlock()
// 触发回调
@@ -293,6 +351,46 @@ func (m *USDTMan) getUSDTTransactions(address string) ([]TronGridTransaction, er
return result.Data, nil
}
+// getTransactionBlock 获取交易的区块号
+func (m *USDTMan) getTransactionBlock(txID string) (int64, error) {
+ url := fmt.Sprintf("%s/wallet/gettransactioninfobyid?value=%s", TronGridAPI, txID)
+
+ req, err := http.NewRequest("GET", url, nil)
+ if err != nil {
+ return 0, err
+ }
+
+ if m.apiKey != "" {
+ req.Header.Set("TRON-PRO-API-KEY", m.apiKey)
+ }
+
+ resp, err := m.httpClient.Do(req)
+ if err != nil {
+ return 0, err
+ }
+ defer resp.Body.Close()
+
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return 0, err
+ }
+
+ if resp.StatusCode != 200 {
+ return 0, fmt.Errorf("TronGrid API error: %d", resp.StatusCode)
+ }
+
+ var result struct {
+ BlockNumber int64 `json:"blockNumber"`
+ }
+
+ fmt.Println("body", string(body))
+ if err := json.Unmarshal(body, &result); err != nil {
+ return 0, err
+ }
+
+ return result.BlockNumber, nil
+}
+
// getCurrentBlock 获取当前区块高度
func (m *USDTMan) getCurrentBlock() (int64, error) {
url := fmt.Sprintf("%s/wallet/getnowblock", TronGridAPI)
@@ -329,41 +427,7 @@ func (m *USDTMan) getCurrentBlock() (int64, error) {
return blockInfo.BlockHeader.RawData.Number, nil
}
-// parseTransaction 解析交易
-func (m *USDTMan) parseTransaction(txn *TronGridTransaction, targetAddress string, confirmations int64) *USDTPayment {
- if len(txn.Ret) == 0 || txn.Ret[0]["contractRet"] != "SUCCESS" {
- return nil
- }
-
- if len(txn.RawData.Contract) == 0 {
- return nil
- }
-
- contract := txn.RawData.Contract[0]
- value := contract.Parameter.Value
-
- // 转换地址格式
- to := value.To
- from := value.From
-
- // 检查是否是目标地址
- if !strings.EqualFold(to, targetAddress) {
- return nil
- }
-
- // USDT 是 6 位小数
- amount := float64(value.Amount) / 1000000.0
-
- return &USDTPayment{
- Address: targetAddress,
- Amount: amount,
- TxID: txn.TxID,
- BlockNumber: txn.BlockNumber,
- Timestamp: txn.BlockTimeStamp,
- From: from,
- Confirmations: confirmations,
- }
-}
+// parseTransaction 解析交易(已废弃,直接在 checkAddress 中处理)
// GetAddresses 获取所有监听地址
func (m *USDTMan) GetAddresses() []string {
|