tron.go 8.9 KB

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