package jobs import ( "fmt" "go-admin/app/admin/service" "go-admin/app/admin/service/dto" "go-admin/config" "go-admin/utils/redishelper" "go-admin/utils/utility" "io" "net/http" "time" "github.com/bytedance/sonic" "github.com/go-admin-team/go-admin-core/logger" "github.com/go-admin-team/go-admin-core/sdk" "github.com/shopspring/decimal" "gorm.io/gorm" ) type TrxPaymentJob struct{} const ( // tronGridURL = "https://api.trongrid.io" // TronGrid API 地址 UsdtContractAddress = "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t" //TRX USDT 合约地址 ) // trx 链上支付定时查询 func (j TrxPaymentJob) Exec(arg interface{}) error { key := fmt.Sprintf("pre_order:%s", "*") keys, err := redishelper.DefaultRedis.ScanKeys(key) if err != nil { logger.Error("查询redis key失败", err) return nil } if len(keys) == 0 { logger.Info("没有待处理订单") return nil } configService := service.SysConfig{} configService.Orm = GetDb() req := dto.SysConfigByKeyReq{} req.ConfigKey = "trx_receive_address" configData := dto.GetSysConfigByKEYForServiceResp{} configService.GetWithKey(&req, &configData) if configData.ConfigValue == "" { logger.Error("查询地址为空") return nil } rechargeService := service.MemberRecharge{} rechargeService.Orm = GetDb() rechargeService.Log = logger.NewHelper(logger.DefaultLogger) startTime := time.Now().UnixMilli() endTime := time.Now().Add(-1 * time.Hour).UnixMilli() transfers, err := GetTRC20Transfers(UsdtContractAddress, configData.ConfigValue, endTime, startTime) if err != nil { logger.Error("查询失败", err) return nil } logs := make([]dto.TmRechargeCallbackReq, 0) item := dto.TmRechargeCallbackReq{} for _, transfer := range transfers { if transfer.TransactionID == "" || transfer.ToAddress != configData.ConfigValue { continue } //实际金额 payableAmount := utility.StringToDecimal(transfer.Value).Div(decimal.NewFromInt(10).Pow(decimal.NewFromInt(int64(transfer.TokenInfo.Decimals)))).Truncate(6) item.TxHash = transfer.TransactionID item.PayableAmount = payableAmount item.FromAddress = transfer.FromAddress item.ToAddress = transfer.ToAddress logs = append(logs, item) } if len(logs) > 0 { err := rechargeService.PayCallBack(&logs) if err != nil { logger.Error("执行完毕,err:", err.Error()) } } return nil } // GetTRC20Transfers 获取指定 TRC20 代币的交易记录 func GetTRC20Transfers(contractAddress, accountAddress string, minTimestamp, maxTimestamp int64) ([]dto.TRC20Transfer, error) { url := fmt.Sprintf("%s/v1/accounts/%s/transactions/trc20?contract_address=%s", config.ExtConfig.TrxGridUrl, accountAddress, contractAddress) if minTimestamp > 0 { url += fmt.Sprintf("&min_timestamp=%d", minTimestamp) } if maxTimestamp > 0 { url += fmt.Sprintf("&max_timestamp=%d", maxTimestamp) } // logger.Info("查询地址:", url) req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, fmt.Errorf("failed to create request: %v", err) } // 设置请求头(包含 TronGrid API Key) req.Header.Set("Accept", "*/*") req.Header.Set("TRON-PRO-API-KEY", config.ExtConfig.TronApiKey) // 从配置读取 API Key client := &http.Client{} resp, err := client.Do(req) if err != nil { return nil, fmt.Errorf("failed to send request: %v", err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("failed to read response body: %v", err) } var result struct { Data []dto.TRC20Transfer `json:"data"` } // logger.Info("查询结果:", string(body)) if err := sonic.Unmarshal(body, &result); err != nil { return nil, fmt.Errorf("failed to unmarshal response: %v", err) } return result.Data, nil } func GetDb() *gorm.DB { dbs := sdk.Runtime.GetDb() for _, db := range dbs { return db } return nil }