fix update

This commit is contained in:
2026-02-03 00:10:43 +08:00
parent 79c1c710a2
commit 8965b96f0e
3 changed files with 102 additions and 15 deletions

View File

@@ -12,8 +12,25 @@ TRON USDT TRC20 收款监听服务 - 基于交易记录扫描 + 区块确认数
## API 使用方式 ## API 使用方式
```go ```go
// 创建监听器 // 创建监听器(配置对象方式)
uman := usdtman.NewUSDTMan([]string{"地址1", "地址2"}, "API_KEY") uman := usdtman.NewUSDTMan(usdtman.Config{
Addresses: []string{"地址1", "地址2"},
APIKey: "YOUR_API_KEY",
QueryInterval: 5 * time.Second, // 查询间隔(可选,默认 5 秒)
MinConfirmations: 6, // 最小确认数(可选,默认 6
MaxHistoryTxns: 20, // 查询历史交易数(可选,默认 20
ProxyURL: "http://127.0.0.1:7890", // HTTP/SOCKS5 代理(可选)
})
// 或者使用自定义 Transport
uman := usdtman.NewUSDTMan(usdtman.Config{
Addresses: []string{"地址1"},
APIKey: "YOUR_API_KEY",
Transport: &http.Transport{
Proxy: http.ProxyURL(proxyURL),
// 其他自定义配置...
},
})
// 设置收款回调 // 设置收款回调
uman.OnPaymentComplete(func(payment *usdtman.USDTPayment) { uman.OnPaymentComplete(func(payment *usdtman.USDTPayment) {
@@ -25,6 +42,10 @@ uman.Start()
// 停止监听 // 停止监听
uman.Stop() uman.Stop()
// 动态添加/移除地址
uman.AddAddress("新地址")
uman.RemoveAddress("旧地址")
``` ```
## 运行 ## 运行

View File

@@ -7,6 +7,7 @@ import (
"net/http" "net/http"
"os" "os"
"sync" "sync"
"time"
"usdtman" "usdtman"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
@@ -34,8 +35,24 @@ func main() {
apiKey = "da1e77dc-b35b-4458-846a-5a551b9df4b2" apiKey = "da1e77dc-b35b-4458-846a-5a551b9df4b2"
} }
// 初始化 USDTMan (无初始地址) // 初始化 USDTMan
uman = usdtman.NewUSDTMan([]string{}, apiKey) proxyURL := os.Getenv("PROXY_URL") // 例如: http://127.0.0.1:7890
config := usdtman.Config{
Addresses: []string{}, // 初始无地址,可通过 API 添加
APIKey: apiKey,
QueryInterval: 5 * time.Second, // 每 5 秒查询一次
MinConfirmations: 6, // 6 个确认
MaxHistoryTxns: 20, // 每次查询最多 20 条历史交易
}
// 如果设置了代理
if proxyURL != "" {
config.ProxyURL = proxyURL
log.Printf("✅ 使用代理: %s", proxyURL)
}
uman = usdtman.NewUSDTMan(config)
// 设置收款回调 // 设置收款回调
uman.OnPaymentComplete(func(payment *usdtman.USDTPayment) { uman.OnPaymentComplete(func(payment *usdtman.USDTPayment) {

View File

@@ -6,23 +6,38 @@ import (
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"net/url"
"strings" "strings"
"sync" "sync"
"time" "time"
) )
// Config USDTMan 配置
type Config struct {
Addresses []string // 监听地址列表
APIKey string // TronGrid API Key
QueryInterval time.Duration // 查询间隔(秒),默认 5 秒
MinConfirmations int64 // 最小确认数,默认 6
MaxHistoryTxns int // 每次查询的最大历史交易数,默认 20
ProxyURL string // HTTP/SOCKS5 代理地址,例如 "http://127.0.0.1:7890" 或 "socks5://127.0.0.1:1080"
Transport http.RoundTripper // 自定义 Transport优先级高于 ProxyURL
}
// USDTMan USDT 监听管理器 // USDTMan USDT 监听管理器
type USDTMan struct { type USDTMan struct {
mu sync.RWMutex mu sync.RWMutex
addresses []string addresses []string
apiKey string apiKey string
queryInterval time.Duration
running bool running bool
ctx context.Context ctx context.Context
cancel context.CancelFunc cancel context.CancelFunc
onPaymentComplete func(*USDTPayment) onPaymentComplete func(*USDTPayment)
minConfirmations int64 minConfirmations int64
maxHistoryTxns int
processedTxns map[string]bool // 已处理的交易 processedTxns map[string]bool // 已处理的交易
txnMutex sync.RWMutex txnMutex sync.RWMutex
httpClient *http.Client // HTTP 客户端
} }
// USDTPayment USDT 收款信息 // USDTPayment USDT 收款信息
@@ -80,14 +95,50 @@ const (
) )
// NewUSDTMan 创建监听管理器 // NewUSDTMan 创建监听管理器
func NewUSDTMan(addresses []string, apiKey string) *USDTMan { func NewUSDTMan(config Config) *USDTMan {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
// 设置默认值
if config.QueryInterval == 0 {
config.QueryInterval = 5 * time.Second
}
if config.MinConfirmations == 0 {
config.MinConfirmations = 6
}
if config.MaxHistoryTxns == 0 {
config.MaxHistoryTxns = 20
}
// 创建 HTTP 客户端
httpClient := &http.Client{
Timeout: 10 * time.Second,
}
// 配置代理
if config.Transport != nil {
// 使用自定义 Transport
httpClient.Transport = config.Transport
} else if config.ProxyURL != "" {
// 使用代理 URL
proxyURL, err := url.Parse(config.ProxyURL)
if err == nil {
httpClient.Transport = &http.Transport{
Proxy: http.ProxyURL(proxyURL),
}
} else {
fmt.Printf("⚠️ 代理 URL 解析失败: %v使用直连\n", err)
}
}
return &USDTMan{ return &USDTMan{
addresses: addresses, addresses: config.Addresses,
apiKey: apiKey, apiKey: config.APIKey,
queryInterval: config.QueryInterval,
minConfirmations: config.MinConfirmations,
maxHistoryTxns: config.MaxHistoryTxns,
httpClient: httpClient,
ctx: ctx, ctx: ctx,
cancel: cancel, cancel: cancel,
minConfirmations: 6,
processedTxns: make(map[string]bool), processedTxns: make(map[string]bool),
} }
} }
@@ -128,7 +179,7 @@ func (m *USDTMan) Stop() {
// monitorLoop 监听循环 // monitorLoop 监听循环
func (m *USDTMan) monitorLoop() { func (m *USDTMan) monitorLoop() {
ticker := time.NewTicker(5 * time.Second) ticker := time.NewTicker(m.queryInterval)
defer ticker.Stop() defer ticker.Stop()
for { for {
@@ -207,8 +258,8 @@ func (m *USDTMan) checkAddress(address string) {
// getUSDTTransactions 获取地址的 USDT 交易 // getUSDTTransactions 获取地址的 USDT 交易
func (m *USDTMan) getUSDTTransactions(address string) ([]TronGridTransaction, error) { func (m *USDTMan) getUSDTTransactions(address string) ([]TronGridTransaction, error) {
url := fmt.Sprintf("%s/v1/accounts/%s/transactions/trc20?limit=20&contract_address=%s&only_to=true", url := fmt.Sprintf("%s/v1/accounts/%s/transactions/trc20?limit=%d&contract_address=%s&only_to=true",
TronGridAPI, address, USDTContractAddress) TronGridAPI, address, m.maxHistoryTxns, USDTContractAddress)
req, err := http.NewRequest("GET", url, nil) req, err := http.NewRequest("GET", url, nil)
if err != nil { if err != nil {
@@ -219,8 +270,7 @@ func (m *USDTMan) getUSDTTransactions(address string) ([]TronGridTransaction, er
req.Header.Set("TRON-PRO-API-KEY", m.apiKey) req.Header.Set("TRON-PRO-API-KEY", m.apiKey)
} }
client := &http.Client{Timeout: 10 * time.Second} resp, err := m.httpClient.Do(req)
resp, err := client.Do(req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -256,8 +306,7 @@ func (m *USDTMan) getCurrentBlock() (int64, error) {
req.Header.Set("TRON-PRO-API-KEY", m.apiKey) req.Header.Set("TRON-PRO-API-KEY", m.apiKey)
} }
client := &http.Client{Timeout: 10 * time.Second} resp, err := m.httpClient.Do(req)
resp, err := client.Do(req)
if err != nil { if err != nil {
return 0, err return 0, err
} }