server.go 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. package service
  2. import (
  3. "context"
  4. "encoding/hex"
  5. "encoding/json"
  6. "errors"
  7. "github.com/ethereum/go-ethereum/common"
  8. "github.com/ethereum/go-ethereum/core/types"
  9. tronaddr "github.com/fbsobreira/gotron-sdk/pkg/address"
  10. troncommon "github.com/fbsobreira/gotron-sdk/pkg/common"
  11. "github.com/fbsobreira/gotron-sdk/pkg/proto/api"
  12. troncore "github.com/fbsobreira/gotron-sdk/pkg/proto/core"
  13. "google.golang.org/grpc"
  14. "google.golang.org/protobuf/proto"
  15. "key-manager/service"
  16. "math/big"
  17. "sync"
  18. "wallet-server/conf"
  19. "wallet-server/dao"
  20. )
  21. const (
  22. ethNetwork = "eth"
  23. tronNetwork = "tron"
  24. ethCoin = "eth"
  25. trxCoin = "trx"
  26. usdtCoin = "usdt"
  27. usdcCoin = "usdc"
  28. )
  29. type WalletServer struct {
  30. UnimplementedWalletServerServer
  31. lk sync.Mutex
  32. node *Node
  33. dao *dao.Dao
  34. keyManager service.KeyManagerClient
  35. }
  36. func NewWalletServer(dao *dao.Dao) (*WalletServer, error) {
  37. config := conf.GetConfig()
  38. node, err := NewNode(config.EthRpcAddrs, config.TronRpcAddrs)
  39. if err != nil {
  40. return nil, err
  41. }
  42. keyManagerClient, _, err := newKeyManagerClient(config.KeyManagerAddr)
  43. if err != nil {
  44. return nil, err
  45. }
  46. return &WalletServer{
  47. node: node,
  48. dao: dao,
  49. keyManager: keyManagerClient,
  50. }, nil
  51. }
  52. func newKeyManagerClient(keyManagerAddr string) (service.KeyManagerClient, *grpc.ClientConn, error) {
  53. conn, err := grpc.Dial(keyManagerAddr, grpc.WithInsecure())
  54. if err != nil {
  55. return nil, nil, err
  56. }
  57. client := service.NewKeyManagerClient(conn)
  58. return client, conn, nil
  59. }
  60. func (w *WalletServer) Transfer(ctx context.Context, req *TransferRequest) (*TransferResponse, error) {
  61. network := req.Network
  62. if network != ethNetwork && network != tronNetwork {
  63. return &TransferResponse{
  64. Req: req,
  65. Code: networkErrCode,
  66. Msg: networkErrMsg,
  67. TxHash: "",
  68. }, nil
  69. }
  70. coin := req.Coin
  71. if coin != ethCoin && coin != trxCoin && coin != usdcCoin && coin != usdtCoin {
  72. return &TransferResponse{
  73. Req: req,
  74. Code: coinErrCode,
  75. Msg: coinErrMsg,
  76. TxHash: "",
  77. }, nil
  78. }
  79. from, err1 := format(network, req.From)
  80. to, err2 := format(network, req.To)
  81. if err1 != nil || err2 != nil {
  82. return &TransferResponse{
  83. Req: req,
  84. Code: addressErrCode,
  85. Msg: addressErrMsg,
  86. TxHash: "",
  87. }, nil
  88. }
  89. req.From = from
  90. req.To = to
  91. amount, ok := big.NewInt(0).SetString(req.Amount, 10)
  92. if !ok || amount.Cmp(big.NewInt(0)) <= 0 {
  93. return &TransferResponse{
  94. Req: req,
  95. Code: amountErrCode,
  96. Msg: amountErrMsg,
  97. TxHash: "",
  98. }, nil
  99. }
  100. res, err := w.keyManager.GetIndex(ctx, &service.GetIndexRequest{
  101. Network: network,
  102. Address: from,
  103. })
  104. if err != nil {
  105. return &TransferResponse{
  106. Req: req,
  107. Code: keyManagerErrCode,
  108. Msg: err.Error(),
  109. TxHash: "",
  110. }, nil
  111. }
  112. if res.Code != okCode {
  113. return &TransferResponse{
  114. Req: req,
  115. Code: res.Code,
  116. Msg: res.Msg,
  117. TxHash: "",
  118. }, nil
  119. }
  120. var txStr string
  121. var txHash string
  122. if network == ethNetwork {
  123. var ethTx *types.Transaction
  124. code := serverErrCode
  125. if coin == ethCoin {
  126. ethTx, err = buildTransferEth(w.node.ethClient, req.From, req.To, amount)
  127. } else if coin == usdcCoin {
  128. ethTx, err = buildTransferUsdcOfEth(w.node.ethClient, req.From, req.To, amount)
  129. } else if coin == usdtCoin {
  130. ethTx, err = buildTransferUsdtOfEth(w.node.ethClient, req.From, req.To, amount)
  131. } else {
  132. code = coinErrCode
  133. err = errors.New("coin and network do not match")
  134. }
  135. if err != nil {
  136. return &TransferResponse{
  137. Req: req,
  138. Code: code,
  139. Msg: err.Error(),
  140. TxHash: "",
  141. }, nil
  142. }
  143. txStr, err = marshalJEthTx(ethTx)
  144. if err != nil {
  145. return &TransferResponse{
  146. Req: req,
  147. Code: serverErrCode,
  148. Msg: err.Error(),
  149. TxHash: "",
  150. }, nil
  151. }
  152. } else {
  153. var tronTx *api.TransactionExtention
  154. code := serverErrCode
  155. if coin == trxCoin {
  156. tronTx, err = buildTransferTrx(w.node.tronClient, req.From, req.To, amount.Int64())
  157. } else if coin == usdcCoin {
  158. tronTx, err = buildTransferUsdcOfTron(w.node.tronClient, req.From, req.To, amount)
  159. } else if coin == usdtCoin {
  160. tronTx, err = buildTransferUsdtOfTron(w.node.tronClient, req.From, req.To, amount)
  161. } else {
  162. code = coinErrCode
  163. err = errors.New("coin and network do not match")
  164. }
  165. if err != nil {
  166. return &TransferResponse{
  167. Req: req,
  168. Code: code,
  169. Msg: err.Error(),
  170. TxHash: "",
  171. }, nil
  172. }
  173. txStr, err = marshalJTronTx(tronTx.Transaction)
  174. if err != nil {
  175. return &TransferResponse{
  176. Req: req,
  177. Code: serverErrCode,
  178. Msg: err.Error(),
  179. TxHash: "",
  180. }, nil
  181. }
  182. txHash = troncommon.BytesToHexString(tronTx.GetTxid())
  183. }
  184. signRes, err := w.keyManager.Sign(ctx, &service.SignRequest{
  185. Network: network,
  186. Sender: from,
  187. Tx: txStr,
  188. })
  189. if err != nil {
  190. return &TransferResponse{
  191. Req: req,
  192. Code: keyManagerErrCode,
  193. Msg: err.Error(),
  194. TxHash: "",
  195. }, nil
  196. }
  197. if signRes.Code != okCode {
  198. return &TransferResponse{
  199. Req: req,
  200. Code: signRes.Code,
  201. Msg: signRes.Msg,
  202. TxHash: "",
  203. }, nil
  204. }
  205. if network == ethNetwork {
  206. tx, err := unmarshalJEthTx(signRes.SignedTx)
  207. if err != nil {
  208. return &TransferResponse{
  209. Req: req,
  210. Code: serverErrCode,
  211. Msg: err.Error(),
  212. TxHash: "",
  213. }, nil
  214. }
  215. err = w.node.ethClient.SendTransaction(ctx, tx)
  216. if err != nil {
  217. return &TransferResponse{
  218. Req: req,
  219. Code: serverErrCode,
  220. Msg: err.Error(),
  221. TxHash: "",
  222. }, nil
  223. }
  224. txHash = tx.Hash().String()
  225. } else {
  226. tx, err := unmarshalJTronTx(signRes.SignedTx)
  227. if err != nil {
  228. return &TransferResponse{
  229. Req: req,
  230. Code: serverErrCode,
  231. Msg: err.Error(),
  232. TxHash: "",
  233. }, nil
  234. }
  235. result, err := w.node.tronClient.Broadcast(tx)
  236. if result.Code != 0 || !result.Result {
  237. d, _ := json.Marshal(result)
  238. return &TransferResponse{
  239. Req: req,
  240. Code: serverErrCode,
  241. Msg: string(d),
  242. TxHash: "",
  243. }, nil
  244. }
  245. }
  246. err = w.dao.CreateTransaction(&dao.Transaction{
  247. TxId: req.Id,
  248. Network: req.Network,
  249. Coin: req.Coin,
  250. From: req.From,
  251. To: req.To,
  252. Amount: req.Amount,
  253. TxHash: txHash,
  254. })
  255. if err != nil {
  256. log.Warnw("save transaction to mysql failed", "id", req.Id, "network", req.Network, "coin", req.Coin, "from", req.From, "to", req.To, "amount", req.Amount, "txhash", txHash, "err", err)
  257. }
  258. log.Infow("send transaction to chain", "id", req.Id, "network", req.Network, "coin", req.Coin, "from", req.From, "to", req.To, "amount", req.Amount, "txhash", txHash)
  259. return &TransferResponse{
  260. Req: req,
  261. Code: okCode,
  262. Msg: okMsg,
  263. TxHash: txHash,
  264. }, nil
  265. }
  266. func format(network, address string) (string, error) {
  267. if network == ethNetwork {
  268. if address[:2] != "0x" {
  269. return "", errors.New("invalid address")
  270. }
  271. address = common.HexToAddress(address).String()
  272. } else {
  273. if address[:1] != "T" {
  274. return "", errors.New("invalid address")
  275. }
  276. addr, err := tronaddr.Base58ToAddress(address)
  277. if err != nil {
  278. return "", err
  279. }
  280. address = addr.String()
  281. }
  282. return address, nil
  283. }
  284. func marshalJEthTx(transaction *types.Transaction) (string, error) {
  285. b, err := transaction.MarshalJSON()
  286. if err != nil {
  287. return "", err
  288. }
  289. return hex.EncodeToString(b), nil
  290. }
  291. func unmarshalJEthTx(tx string) (*types.Transaction, error) {
  292. b, err := hex.DecodeString(tx)
  293. if err != nil {
  294. return nil, err
  295. }
  296. var transaction = &types.Transaction{}
  297. err = transaction.UnmarshalJSON(b)
  298. if err != nil {
  299. return nil, err
  300. }
  301. return transaction, err
  302. }
  303. func marshalJTronTx(transaction *troncore.Transaction) (string, error) {
  304. b, err := proto.Marshal(transaction)
  305. if err != nil {
  306. return "", err
  307. }
  308. return hex.EncodeToString(b), nil
  309. }
  310. func unmarshalJTronTx(tx string) (*troncore.Transaction, error) {
  311. b, err := hex.DecodeString(tx)
  312. if err != nil {
  313. return nil, err
  314. }
  315. var transaction troncore.Transaction
  316. err = proto.Unmarshal(b, &transaction)
  317. if err != nil {
  318. return nil, err
  319. }
  320. return &transaction, nil
  321. }