tron.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. package tron2
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "io/ioutil"
  7. "math/big"
  8. "net/http"
  9. "strconv"
  10. "strings"
  11. "time"
  12. "github.com/JFJun/trx-sign-go/grpcs"
  13. "github.com/JFJun/trx-sign-go/sign"
  14. "github.com/btcsuite/btcd/btcec"
  15. addr "github.com/fbsobreira/gotron-sdk/pkg/address"
  16. "github.com/fbsobreira/gotron-sdk/pkg/client"
  17. "github.com/fbsobreira/gotron-sdk/pkg/common"
  18. "github.com/fbsobreira/gotron-sdk/pkg/proto/core"
  19. "github.com/google/uuid"
  20. "github.com/sirupsen/logrus"
  21. "github.com/spf13/viper"
  22. "google.golang.org/grpc"
  23. )
  24. type GenAddressInfo struct {
  25. Seed string
  26. Addr string
  27. PrvKey string
  28. }
  29. func GenAddressBySeed() (*GenAddressInfo, error) {
  30. uuid := uuid.New()
  31. seed := uuid.String()
  32. seed = strings.Replace(seed, "-", "", -1)
  33. if len(seed) != 32 {
  34. return nil, fmt.Errorf("seed len=[%d] is not equal 32", len(seed))
  35. }
  36. priv, _ := btcec.PrivKeyFromBytes(btcec.S256(), []byte(seed))
  37. if priv == nil {
  38. return nil, errors.New("priv is nil ptr")
  39. }
  40. a := addr.PubkeyToAddress(priv.ToECDSA().PublicKey)
  41. addrInfo := GenAddressInfo{
  42. Seed: seed,
  43. Addr: a.String(),
  44. PrvKey: priv.D.Text(16),
  45. }
  46. return &addrInfo, nil
  47. }
  48. type txInfoItem struct {
  49. TransactionID string `json:"transaction_id"`
  50. BlockTimestamp int64 `json:"block_timestamp"`
  51. From string `json:"from"`
  52. To string `json:"to"`
  53. Type string `json:"type"`
  54. Value string `json:"value"`
  55. }
  56. var rpcClient *grpcs.Client
  57. func getClient() (*grpcs.Client, error) {
  58. if rpcClient != nil {
  59. return rpcClient, nil
  60. }
  61. grpcHost := viper.GetString("tron.grpcHost")
  62. if grpcHost == "" {
  63. grpcHost = "grpc.trongrid.io:50051"
  64. }
  65. c := new(grpcs.Client)
  66. //c.node = node
  67. c.GRPC = client.NewGrpcClient(grpcHost)
  68. err := c.GRPC.Start(grpc.WithInsecure())
  69. if err != nil {
  70. return nil, fmt.Errorf("grpc client start error: %v", err)
  71. }
  72. // c, err := grpcs.NewClient(grpcHost)
  73. // if err != nil {
  74. // logrus.Error(err)
  75. // return nil, err
  76. // }
  77. rpcClient = c
  78. return c, err
  79. }
  80. func TransferTrx(from string, to string, amount int64, key string) (bool, string) {
  81. c, err := getClient()
  82. if err != nil {
  83. fmt.Println(err)
  84. }
  85. tx, err := c.Transfer(from, to, amount)
  86. if err != nil {
  87. fmt.Println(err)
  88. return false, ""
  89. }
  90. signTx, err := sign.SignTransaction(tx.Transaction, key)
  91. if err != nil {
  92. fmt.Println(err)
  93. return false, ""
  94. }
  95. err = c.BroadcastTransaction(signTx)
  96. if err != nil {
  97. fmt.Println(err)
  98. return false, ""
  99. }
  100. return true, common.BytesToHexString(tx.GetTxid())
  101. }
  102. func TransferTrc20(contractAddress string, from string, to string, amount int64, key string) (bool, string, *core.Transaction) {
  103. if len(key) != 64 {
  104. logrus.Error("key not valid:", len(key), "!=64")
  105. return false, "", nil
  106. }
  107. // grpcHost := viper.GetString("tron.grpcHost")
  108. c, err := getClient()
  109. if err != nil {
  110. logrus.Error(err)
  111. return false, "", nil
  112. }
  113. amountBig := big.NewInt(amount)
  114. tx, err := c.TransferTrc20(from, to, contractAddress, amountBig, 10000000)
  115. if err != nil {
  116. logrus.Error(err)
  117. return false, "", nil
  118. }
  119. signTx, err := sign.SignTransaction(tx.Transaction, key)
  120. if err != nil {
  121. logrus.Error(err)
  122. return false, "", nil
  123. }
  124. // err = c.BroadcastTransaction(signTx)
  125. // if err != nil {
  126. // fmt.Println(err)
  127. // return false, nil
  128. // }
  129. return true, common.BytesToHexString(tx.GetTxid()), signTx
  130. }
  131. func BroadcastTransaction(signTx *core.Transaction) error {
  132. c, err := getClient()
  133. if err != nil {
  134. logrus.Error(err)
  135. return err
  136. }
  137. return c.BroadcastTransaction(signTx)
  138. }
  139. func GetBalance(addr string) (int64, error) {
  140. c, err := getClient()
  141. if err != nil {
  142. return 0, err
  143. }
  144. acc, err := c.GetTrxBalance(addr)
  145. if err != nil {
  146. return 0, err
  147. }
  148. // d, _ := json.Marshal(acc)
  149. // fmt.Println(string(d))
  150. return acc.GetBalance(), nil
  151. }
  152. func GetTrc20BalanceByHash(hash string) (int64, error) {
  153. type HashInfoResp struct {
  154. Block int64 `json:"block"`
  155. Confirmed bool `json:"confirmed"`
  156. Revert bool `json:"revert"`
  157. ContractRet string `json:"contractRet"`
  158. ContractData struct {
  159. Amount int `json:"amount"`
  160. OwnerAddress string `json:"owner_address"`
  161. ToAddress string `json:"to_address"`
  162. } `json:"contractData"`
  163. Trc20TransferInfo []struct {
  164. IconURL string `json:"icon_url"`
  165. Symbol string `json:"symbol"`
  166. Level string `json:"level"`
  167. Decimals int `json:"decimals"`
  168. Name string `json:"name"`
  169. ToAddress string `json:"to_address"`
  170. ContractAddress string `json:"contract_address"`
  171. Type string `json:"type"`
  172. Vip bool `json:"vip"`
  173. TokenType string `json:"tokenType"`
  174. FromAddress string `json:"from_address"`
  175. AmountStr string `json:"amount_str"`
  176. } `json:"trc20TransferInfo"`
  177. }
  178. reqUrl := "https://apilist.tronscan.org/api/transaction-info?hash=" + hash + "&t=" + fmt.Sprintf("%d", time.Now().Unix())
  179. logrus.Info("req url:", reqUrl)
  180. res, err := http.Get(reqUrl)
  181. if err != nil {
  182. logrus.Error(err)
  183. return 0, err
  184. }
  185. body, err := ioutil.ReadAll(res.Body)
  186. if err != nil {
  187. logrus.Error(err)
  188. return 0, err
  189. }
  190. defer res.Body.Close()
  191. hashResp := HashInfoResp{}
  192. err = json.Unmarshal(body, &hashResp)
  193. if err != nil {
  194. logrus.Error(err, string(body))
  195. return 0, err
  196. }
  197. if hashResp.Block == 0 {
  198. logrus.Error("block id未生效:", string(body))
  199. return 0, errors.New("not valid")
  200. }
  201. if hashResp.ContractRet != "SUCCESS" {
  202. return 0, errors.New("transfer failed")
  203. }
  204. if !hashResp.Confirmed {
  205. return 0, errors.New("not confirm")
  206. }
  207. if len(hashResp.Trc20TransferInfo) != 1 {
  208. return 0, errors.New("data not valid")
  209. }
  210. val, err := strconv.ParseInt(hashResp.Trc20TransferInfo[0].AmountStr, 10, 64)
  211. if err != nil {
  212. return 0, err
  213. }
  214. return val, nil
  215. }
  216. func GetTrc20Balance(addr string, contractAddress string) (int64, error) {
  217. c, err := getClient()
  218. if err != nil {
  219. return 0, err
  220. }
  221. amount, err := c.GetTrc20Balance(addr, contractAddress)
  222. if err != nil {
  223. return 0, err
  224. }
  225. val, err := strconv.ParseInt(amount.String(), 10, 64)
  226. if err != nil {
  227. return 0, err
  228. }
  229. return val, nil
  230. }
  231. func IsTransactionSucc_(txid string) (bool, error) {
  232. c, err := getClient()
  233. if err != nil {
  234. logrus.Error(err)
  235. return false, err
  236. }
  237. txInfo, err := c.GRPC.GetTransactionByID(txid)
  238. if err != nil {
  239. logrus.Error(err)
  240. return false, err
  241. }
  242. if len(txInfo.Ret) == 0 {
  243. //半小时也没有,认为失败
  244. if txInfo.GetRawData().Timestamp-time.Now().Unix() > 30*60 {
  245. return false, nil
  246. }
  247. logrus.Error("len(txInfo.Ret) == 0")
  248. return false, errors.New("no result")
  249. }
  250. if txInfo.Ret[0].ContractRet == core.Transaction_Result_DEFAULT {
  251. return false, errors.New("wait contract result")
  252. }
  253. return txInfo.Ret[0].Ret == core.Transaction_Result_SUCESS && txInfo.Ret[0].ContractRet == core.Transaction_Result_SUCCESS,
  254. nil
  255. }
  256. func IsTransactionSucc(hash string) (bool, error) {
  257. c, err := getClient()
  258. if err != nil {
  259. logrus.Error(err)
  260. return false, err
  261. }
  262. body, err := c.GRPC.GetTransactionInfoByID(hash)
  263. if err != nil {
  264. logrus.Error(err)
  265. return false, err
  266. }
  267. switch body.Receipt.GetResult().String() {
  268. case "SUCCESS":
  269. return true, nil
  270. case "REVERT":
  271. return false, nil
  272. default:
  273. return false, errors.New("no result")
  274. }
  275. }
  276. func CheckToComtainSince(addr string, val int64, since int64) (bool, string, error) {
  277. fp := ""
  278. for {
  279. his, retfp, err := GetTxHistoryByAddr(addr, fp, 20)
  280. if err != nil {
  281. fmt.Println(err)
  282. return false, "", err
  283. }
  284. if len(his) == 0 {
  285. break
  286. }
  287. for _, info := range his {
  288. if info.BlockTimestamp < since {
  289. continue
  290. }
  291. value, err := strconv.ParseInt(info.Value, 10, 64)
  292. if err != nil {
  293. fmt.Println(err)
  294. continue
  295. }
  296. if value != val {
  297. continue
  298. }
  299. return true, info.From, nil
  300. }
  301. if retfp == "" {
  302. break
  303. }
  304. fp = retfp
  305. }
  306. return false, "", nil
  307. }
  308. func GetTxHistoryByAddr(addr string, fingerprint string, limit int) ([]txInfoItem, string, error) {
  309. apiHost := viper.GetString("tron.apiHost")
  310. contractAddr := viper.GetString("contractaddr")
  311. if contractAddr == "" {
  312. logrus.Fatal("contractaddr is empty")
  313. return nil, "", errors.New("contractaddr is empty")
  314. }
  315. reqUrl := fmt.Sprintf(`https://%s/v1/accounts/%s/transactions/trc20?limit=%d&contract_address=%s&only_confirmed=true&only_to=true&order_by=block_timestamp,desc`,
  316. apiHost, addr, limit, contractAddr)
  317. logrus.Info("reqUrl:", reqUrl)
  318. if fingerprint != "" {
  319. reqUrl = reqUrl + "&fingerprint=" + fingerprint
  320. }
  321. resp, err := http.Get(reqUrl)
  322. if err != nil {
  323. logrus.Error(err, " ", reqUrl)
  324. return nil, "", err
  325. }
  326. type Meta struct {
  327. Fingerprint string `json:"fingerprint"`
  328. }
  329. type DataInfo struct {
  330. Data []txInfoItem `json:"data"`
  331. Meta Meta `json:"meta"`
  332. }
  333. dataInfo := DataInfo{}
  334. body, err := ioutil.ReadAll(resp.Body)
  335. if err != nil {
  336. logrus.Error(err, " ", reqUrl)
  337. return nil, "", err
  338. }
  339. defer resp.Body.Close()
  340. err = json.Unmarshal(body, &dataInfo)
  341. if err != nil {
  342. logrus.Error(err, " ", reqUrl)
  343. return nil, "", err
  344. }
  345. if dataInfo.Data == nil {
  346. return nil, "", errors.New(string(body))
  347. }
  348. resultList := make([]txInfoItem, 0)
  349. for _, item := range dataInfo.Data {
  350. if item.Type != "Transfer" {
  351. continue
  352. }
  353. resultList = append(resultList, item)
  354. }
  355. return resultList, dataInfo.Meta.Fingerprint, nil
  356. }