| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- package service
- import (
- "context"
- "encoding/hex"
- "encoding/json"
- "errors"
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/core/types"
- tronaddr "github.com/fbsobreira/gotron-sdk/pkg/address"
- troncommon "github.com/fbsobreira/gotron-sdk/pkg/common"
- "github.com/fbsobreira/gotron-sdk/pkg/proto/api"
- troncore "github.com/fbsobreira/gotron-sdk/pkg/proto/core"
- "google.golang.org/grpc"
- "google.golang.org/protobuf/proto"
- "key-manager/service"
- "math/big"
- "sync"
- "wallet-server/conf"
- "wallet-server/dao"
- )
- const (
- ethNetwork = "eth"
- tronNetwork = "tron"
- ethCoin = "eth"
- trxCoin = "trx"
- usdtCoin = "usdt"
- usdcCoin = "usdc"
- )
- type WalletServer struct {
- UnimplementedWalletServerServer
- lk sync.Mutex
- node *Node
- dao *dao.Dao
- keyManager service.KeyManagerClient
- }
- func NewWalletServer(dao *dao.Dao) (*WalletServer, error) {
- config := conf.GetConfig()
- node, err := NewNode(config.EthRpcAddrs, config.TronRpcAddrs)
- if err != nil {
- return nil, err
- }
- keyManagerClient, _, err := newKeyManagerClient(config.KeyManagerAddr)
- if err != nil {
- return nil, err
- }
- return &WalletServer{
- node: node,
- dao: dao,
- keyManager: keyManagerClient,
- }, nil
- }
- func newKeyManagerClient(keyManagerAddr string) (service.KeyManagerClient, *grpc.ClientConn, error) {
- conn, err := grpc.Dial(keyManagerAddr, grpc.WithInsecure())
- if err != nil {
- return nil, nil, err
- }
- client := service.NewKeyManagerClient(conn)
- return client, conn, nil
- }
- func (w *WalletServer) Transfer(ctx context.Context, req *TransferRequest) (*TransferResponse, error) {
- network := req.Network
- if network != ethNetwork && network != tronNetwork {
- return &TransferResponse{
- Req: req,
- Code: networkErrCode,
- Msg: networkErrMsg,
- TxHash: "",
- }, nil
- }
- coin := req.Coin
- if coin != ethCoin && coin != trxCoin && coin != usdcCoin && coin != usdtCoin {
- return &TransferResponse{
- Req: req,
- Code: coinErrCode,
- Msg: coinErrMsg,
- TxHash: "",
- }, nil
- }
- from, err1 := format(network, req.From)
- to, err2 := format(network, req.To)
- if err1 != nil || err2 != nil {
- return &TransferResponse{
- Req: req,
- Code: addressErrCode,
- Msg: addressErrMsg,
- TxHash: "",
- }, nil
- }
- req.From = from
- req.To = to
- amount, ok := big.NewInt(0).SetString(req.Amount, 10)
- if !ok || amount.Cmp(big.NewInt(0)) <= 0 {
- return &TransferResponse{
- Req: req,
- Code: amountErrCode,
- Msg: amountErrMsg,
- TxHash: "",
- }, nil
- }
- res, err := w.keyManager.GetIndex(ctx, &service.GetIndexRequest{
- Network: network,
- Address: from,
- })
- if err != nil {
- return &TransferResponse{
- Req: req,
- Code: keyManagerErrCode,
- Msg: err.Error(),
- TxHash: "",
- }, nil
- }
- if res.Code != okCode {
- return &TransferResponse{
- Req: req,
- Code: res.Code,
- Msg: res.Msg,
- TxHash: "",
- }, nil
- }
- var txStr string
- var txHash string
- if network == ethNetwork {
- var ethTx *types.Transaction
- code := serverErrCode
- if coin == ethCoin {
- ethTx, err = buildTransferEth(w.node.ethClient, req.From, req.To, amount)
- } else if coin == usdcCoin {
- ethTx, err = buildTransferUsdcOfEth(w.node.ethClient, req.From, req.To, amount)
- } else if coin == usdtCoin {
- ethTx, err = buildTransferUsdtOfEth(w.node.ethClient, req.From, req.To, amount)
- } else {
- code = coinErrCode
- err = errors.New("coin and network do not match")
- }
- if err != nil {
- return &TransferResponse{
- Req: req,
- Code: code,
- Msg: err.Error(),
- TxHash: "",
- }, nil
- }
- txStr, err = marshalJEthTx(ethTx)
- if err != nil {
- return &TransferResponse{
- Req: req,
- Code: serverErrCode,
- Msg: err.Error(),
- TxHash: "",
- }, nil
- }
- } else {
- var tronTx *api.TransactionExtention
- code := serverErrCode
- if coin == trxCoin {
- tronTx, err = buildTransferTrx(w.node.tronClient, req.From, req.To, amount.Int64())
- } else if coin == usdcCoin {
- tronTx, err = buildTransferUsdcOfTron(w.node.tronClient, req.From, req.To, amount)
- } else if coin == usdtCoin {
- tronTx, err = buildTransferUsdtOfTron(w.node.tronClient, req.From, req.To, amount)
- } else {
- code = coinErrCode
- err = errors.New("coin and network do not match")
- }
- if err != nil {
- return &TransferResponse{
- Req: req,
- Code: code,
- Msg: err.Error(),
- TxHash: "",
- }, nil
- }
- txStr, err = marshalJTronTx(tronTx.Transaction)
- if err != nil {
- return &TransferResponse{
- Req: req,
- Code: serverErrCode,
- Msg: err.Error(),
- TxHash: "",
- }, nil
- }
- txHash = troncommon.BytesToHexString(tronTx.GetTxid())
- }
- signRes, err := w.keyManager.Sign(ctx, &service.SignRequest{
- Network: network,
- Sender: from,
- Tx: txStr,
- })
- if err != nil {
- return &TransferResponse{
- Req: req,
- Code: keyManagerErrCode,
- Msg: err.Error(),
- TxHash: "",
- }, nil
- }
- if signRes.Code != okCode {
- return &TransferResponse{
- Req: req,
- Code: signRes.Code,
- Msg: signRes.Msg,
- TxHash: "",
- }, nil
- }
- if network == ethNetwork {
- tx, err := unmarshalJEthTx(signRes.SignedTx)
- if err != nil {
- return &TransferResponse{
- Req: req,
- Code: serverErrCode,
- Msg: err.Error(),
- TxHash: "",
- }, nil
- }
- err = w.node.ethClient.SendTransaction(ctx, tx)
- if err != nil {
- return &TransferResponse{
- Req: req,
- Code: serverErrCode,
- Msg: err.Error(),
- TxHash: "",
- }, nil
- }
- txHash = tx.Hash().String()
- } else {
- tx, err := unmarshalJTronTx(signRes.SignedTx)
- if err != nil {
- return &TransferResponse{
- Req: req,
- Code: serverErrCode,
- Msg: err.Error(),
- TxHash: "",
- }, nil
- }
- result, err := w.node.tronClient.Broadcast(tx)
- if result.Code != 0 || !result.Result {
- d, _ := json.Marshal(result)
- return &TransferResponse{
- Req: req,
- Code: serverErrCode,
- Msg: string(d),
- TxHash: "",
- }, nil
- }
- }
- err = w.dao.CreateTransaction(&dao.Transaction{
- TxId: req.Id,
- Network: req.Network,
- Coin: req.Coin,
- From: req.From,
- To: req.To,
- Amount: req.Amount,
- TxHash: txHash,
- })
- if err != nil {
- 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)
- }
- 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)
- return &TransferResponse{
- Req: req,
- Code: okCode,
- Msg: okMsg,
- TxHash: txHash,
- }, nil
- }
- func format(network, address string) (string, error) {
- if network == ethNetwork {
- if address[:2] != "0x" {
- return "", errors.New("invalid address")
- }
- address = common.HexToAddress(address).String()
- } else {
- if address[:1] != "T" {
- return "", errors.New("invalid address")
- }
- addr, err := tronaddr.Base58ToAddress(address)
- if err != nil {
- return "", err
- }
- address = addr.String()
- }
- return address, nil
- }
- func marshalJEthTx(transaction *types.Transaction) (string, error) {
- b, err := transaction.MarshalJSON()
- if err != nil {
- return "", err
- }
- return hex.EncodeToString(b), nil
- }
- func unmarshalJEthTx(tx string) (*types.Transaction, error) {
- b, err := hex.DecodeString(tx)
- if err != nil {
- return nil, err
- }
- var transaction = &types.Transaction{}
- err = transaction.UnmarshalJSON(b)
- if err != nil {
- return nil, err
- }
- return transaction, err
- }
- func marshalJTronTx(transaction *troncore.Transaction) (string, error) {
- b, err := proto.Marshal(transaction)
- if err != nil {
- return "", err
- }
- return hex.EncodeToString(b), nil
- }
- func unmarshalJTronTx(tx string) (*troncore.Transaction, error) {
- b, err := hex.DecodeString(tx)
- if err != nil {
- return nil, err
- }
- var transaction troncore.Transaction
- err = proto.Unmarshal(b, &transaction)
- if err != nil {
- return nil, err
- }
- return &transaction, nil
- }
|