Commit 55403625 authored by vicotor's avatar vicotor

add token symbol

parent be092d6b
...@@ -6,6 +6,7 @@ import ( ...@@ -6,6 +6,7 @@ import (
"code.wuban.net.cn/movabridge/bridge-backend/config" "code.wuban.net.cn/movabridge/bridge-backend/config"
"code.wuban.net.cn/movabridge/bridge-backend/dao" "code.wuban.net.cn/movabridge/bridge-backend/dao"
"code.wuban.net.cn/movabridge/bridge-backend/server" "code.wuban.net.cn/movabridge/bridge-backend/server"
"code.wuban.net.cn/movabridge/bridge-backend/tokenrepo"
"os" "os"
"os/signal" "os/signal"
"syscall" "syscall"
...@@ -38,8 +39,9 @@ var rootCmd = &cobra.Command{ ...@@ -38,8 +39,9 @@ var rootCmd = &cobra.Command{
} }
chainRepo := chainlist.New(conf.ChainListFile) chainRepo := chainlist.New(conf.ChainListFile)
tokenRepo := tokenrepo.NewTokenRepo()
d, err := dao.New(conf, chainRepo) d, err := dao.New(conf, chainRepo, tokenRepo)
if err != nil { if err != nil {
panic(err) panic(err)
} }
......
[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_upgradedAddress","type":"address"}],"name":"deprecate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"deprecated","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_evilUser","type":"address"}],"name":"addBlackList","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply2","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"upgradedAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balances","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maximumFee","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_maker","type":"address"}],"name":"getBlackListStatus","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"allowed","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"who","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getOwner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newBasisPoints","type":"uint256"},{"name":"newMaxFee","type":"uint256"}],"name":"setParams","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"amount","type":"uint256"}],"name":"issue","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"amount","type":"uint256"}],"name":"redeem","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"basisPointsRate","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"isBlackListed","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_clearedUser","type":"address"}],"name":"removeBlackList","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MAX_UINT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_blackListedUser","type":"address"}],"name":"destroyBlackFunds","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_initialSupply","type":"uint256"},{"name":"_name","type":"string"},{"name":"_symbol","type":"string"},{"name":"_decimals","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"Issue","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newAddress","type":"address"}],"name":"Deprecate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"feeBasisPoints","type":"uint256"},{"indexed":false,"name":"maxFee","type":"uint256"}],"name":"Params","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_blackListedUser","type":"address"},{"indexed":false,"name":"_balance","type":"uint256"}],"name":"DestroyedBlackFunds","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_user","type":"address"}],"name":"AddedBlackList","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_user","type":"address"}],"name":"RemovedBlackList","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[],"name":"Pause","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpause","type":"event"}]
\ No newline at end of file
This diff is collapsed.
...@@ -3,6 +3,7 @@ package dao ...@@ -3,6 +3,7 @@ package dao
import ( import (
"code.wuban.net.cn/movabridge/bridge-backend/chainlist" "code.wuban.net.cn/movabridge/bridge-backend/chainlist"
"code.wuban.net.cn/movabridge/bridge-backend/config" "code.wuban.net.cn/movabridge/bridge-backend/config"
"code.wuban.net.cn/movabridge/bridge-backend/tokenrepo"
"context" "context"
"crypto/ecdsa" "crypto/ecdsa"
"fmt" "fmt"
...@@ -26,14 +27,16 @@ type Dao struct { ...@@ -26,14 +27,16 @@ type Dao struct {
handleMux sync.Mutex handleMux sync.Mutex
validatorPk *ecdsa.PrivateKey validatorPk *ecdsa.PrivateKey
chainList *chainlist.ChainRepo chainList *chainlist.ChainRepo
tokenRepo *tokenrepo.TokenRepo
} }
func New(_c *config.Config, clist *chainlist.ChainRepo) (dao *Dao, err error) { func New(_c *config.Config, clist *chainlist.ChainRepo, tokenRepo *tokenrepo.TokenRepo) (dao *Dao, err error) {
dao = &Dao{ dao = &Dao{
c: _c, c: _c,
chainGroup: make(map[int64]ChainInfo), chainGroup: make(map[int64]ChainInfo),
syncer: make(map[int64]ChainInterface), syncer: make(map[int64]ChainInterface),
chainList: clist, chainList: clist,
tokenRepo: tokenRepo,
} }
// Connect to all configured chains // Connect to all configured chains
......
...@@ -70,11 +70,25 @@ func (d *Dao) GetBridgeConfig() (config apiModel.BridgeConfig, err error) { ...@@ -70,11 +70,25 @@ func (d *Dao) GetBridgeConfig() (config apiModel.BridgeConfig, err error) {
if !info.Enabled { if !info.Enabled {
continue continue
} }
if info.TokenName == "" {
tokenInfo, err := d.tokenRepo.RetriveTokenInfo(info.ChainId, info.Token)
if err != nil {
log.WithFields(log.Fields{
"chain_id": info.ChainId,
"token": info.Token,
"error": err,
}).Error("not found token info with tokenrepo, skip symbol info")
continue
} else {
info.TokenName = tokenInfo.Symbol
}
}
chainInfo, exist := d.chainList.Get(info.ChainId) chainInfo, exist := d.chainList.Get(info.ChainId)
if !exist { if !exist {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"chain_id": info.ChainId, "chain_id": info.ChainId,
"token": info.Token, "token": info.Token,
"tokenName": info.TokenName,
}).Error("not found chain info with chainlist, skip bridge config") }).Error("not found chain info with chainlist, skip bridge config")
continue continue
} }
...@@ -93,9 +107,19 @@ func (d *Dao) GetBridgeConfig() (config apiModel.BridgeConfig, err error) { ...@@ -93,9 +107,19 @@ func (d *Dao) GetBridgeConfig() (config apiModel.BridgeConfig, err error) {
} else { } else {
chainConfig = _chainConfig chainConfig = _chainConfig
} }
chainConfig.SupportTokens[info.Token] = apiModel.ToToken{ toTokenInfo, err := d.tokenRepo.RetriveTokenInfo(info.ToChainId, info.ToToken)
if err != nil {
log.WithFields(log.Fields{
"chain_id": info.ToChainId,
"token": info.ToToken,
"error": err,
}).Error("not found token info with tokenrepo, skip symbol info")
}
chainConfig.SupportTokens[info.TokenName] = apiModel.ToToken{
TokenContract: info.Token,
ToChainId: info.ToChainId, ToChainId: info.ToChainId,
ToToken: info.ToToken, ToToken: info.ToToken,
ToTokenSymbol: toTokenInfo.Symbol,
} }
config.Chains[chainInfo.Name] = chainConfig config.Chains[chainInfo.Name] = chainConfig
} }
...@@ -129,6 +153,8 @@ func (d *Dao) GetHistoryInfo(user string) (history apiModel.History, err error) ...@@ -129,6 +153,8 @@ func (d *Dao) GetHistoryInfo(user string) (history apiModel.History, err error)
} }
fromChain, _ := d.chainList.Get(event.FromChain) fromChain, _ := d.chainList.Get(event.FromChain)
toChain, _ := d.chainList.Get(event.ToChain) toChain, _ := d.chainList.Get(event.ToChain)
tokenInfo, _ := d.tokenRepo.RetriveTokenInfo(event.FromChain, event.FromToken)
record := &apiModel.HistoryInfo{ record := &apiModel.HistoryInfo{
FromChain: fromChain.Chain, FromChain: fromChain.Chain,
ToChain: toChain.Chain, ToChain: toChain.Chain,
...@@ -136,6 +162,7 @@ func (d *Dao) GetHistoryInfo(user string) (history apiModel.History, err error) ...@@ -136,6 +162,7 @@ func (d *Dao) GetHistoryInfo(user string) (history apiModel.History, err error)
CreateTime: event.OutTimestamp, CreateTime: event.OutTimestamp,
Amount: event.SendAmount, Amount: event.SendAmount,
Token: event.FromToken, Token: event.FromToken,
TokenSymbol: tokenInfo.Symbol,
Status: constant.TransferStatus(event.ToChainStatus).String(), Status: constant.TransferStatus(event.ToChainStatus).String(),
} }
if event.ToChainStatus <= int(constant.TransferChainWaitConfirm) { if event.ToChainStatus <= int(constant.TransferChainWaitConfirm) {
......
...@@ -7,6 +7,7 @@ import ( ...@@ -7,6 +7,7 @@ import (
"go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/mongo/options"
"strings"
"time" "time"
) )
...@@ -140,3 +141,29 @@ func (d *Dao) CreateOrUpdateBridgeTokenInfo(ctx context.Context, info *dbModel.B ...@@ -140,3 +141,29 @@ func (d *Dao) CreateOrUpdateBridgeTokenInfo(ctx context.Context, info *dbModel.B
_, err := collection.UpdateOne(ctx, filter, update, opts) _, err := collection.UpdateOne(ctx, filter, update, opts)
return err return err
} }
func (d *Dao) CreateOrUpdateTokenInfo(ctx context.Context, info *dbModel.TokenInfo) error {
collection := d.db.Collection(info.TableName())
info.Address = strings.ToLower(info.Address)
filter := bson.M{"address": info.Address}
update := bson.D{
{"$set", info},
}
opts := options.Update().SetUpsert(true)
_, err := collection.UpdateOne(ctx, filter, update, opts)
return err
}
func (d *Dao) GetTokenInfo(address string) (info dbModel.TokenInfo, err error) {
collection := d.db.Collection(new(dbModel.TokenInfo).TableName())
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
err = collection.FindOne(ctx, bson.M{"address": strings.ToLower(address)}).Decode(&info)
if err == mongo.ErrNoDocuments {
return info, ErrRecordNotFound
}
return info, err
}
package api package api
type ToToken struct { type ToToken struct {
TokenContract string `bson:"token_contract"`
ToChainId int64 `json:"to_chain_id" bson:"to_chain_id"` ToChainId int64 `json:"to_chain_id" bson:"to_chain_id"`
ToToken string `json:"to_token" bson:"to_token"` ToToken string `json:"to_token" bson:"to_token"`
ToTokenSymbol string `json:"to_token_symbol" bson:"to_token_symbol"`
} }
type ChainConfig struct { type ChainConfig struct {
Chain string `json:"chain" bson:"chain"` Chain string `json:"chain" bson:"chain"`
...@@ -24,6 +26,7 @@ type HistoryInfo struct { ...@@ -24,6 +26,7 @@ type HistoryInfo struct {
CreateTime int64 `json:"create_time" bson:"create_time"` CreateTime int64 `json:"create_time" bson:"create_time"`
Amount string `json:"amount" bson:"amount"` Amount string `json:"amount" bson:"amount"`
Token string `json:"token" bson:"token"` Token string `json:"token" bson:"token"`
TokenSymbol string `json:"token_symbol" bson:"token_symbol"`
Status string `json:"status" bson:"status"` Status string `json:"status" bson:"status"`
} }
......
...@@ -44,6 +44,7 @@ type BridgeTokenInfo struct { ...@@ -44,6 +44,7 @@ type BridgeTokenInfo struct {
ChainId int64 `bson:"chain_id"` ChainId int64 `bson:"chain_id"`
Contract string `bson:"contract"` Contract string `bson:"contract"`
Token string `bson:"token"` Token string `bson:"token"`
TokenName string `bson:"token_name"`
ToChainId int64 `bson:"to_chain_id"` ToChainId int64 `bson:"to_chain_id"`
ToToken string `bson:"to_token"` ToToken string `bson:"to_token"`
Enabled bool `bson:"enabled"` Enabled bool `bson:"enabled"`
...@@ -52,3 +53,15 @@ type BridgeTokenInfo struct { ...@@ -52,3 +53,15 @@ type BridgeTokenInfo struct {
func (b *BridgeTokenInfo) TableName() string { func (b *BridgeTokenInfo) TableName() string {
return "bridge_token_info" return "bridge_token_info"
} }
type TokenInfo struct {
ID primitive.ObjectID `bson:"_id,omitempty"`
Address string `bson:"address"`
Name string `bson:"name"`
Symbol string `bson:"symbol"`
Decimals int64 `bson:"decimals"`
}
func (t *TokenInfo) TableName() string {
return "token_info"
}
package tokenrepo
import (
"code.wuban.net.cn/movabridge/bridge-backend/chainlist"
"code.wuban.net.cn/movabridge/bridge-backend/contract/token"
"context"
"errors"
"fmt"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"strings"
"sync"
)
type TokenInfo struct {
Name string `json:"name" bson:"name"`
Symbol string `json:"symbol" bson:"symbol"`
Decimals int64 `json:"decimals" bson:"decimals"`
Address string `json:"address" bson:"address"`
}
type TokenRepo struct {
repo map[string]TokenInfo
chainRepo *chainlist.ChainRepo
mux sync.RWMutex
}
func NewTokenRepo(chainRepo *chainlist.ChainRepo) *TokenRepo {
return &TokenRepo{
repo: make(map[string]TokenInfo),
}
}
func (tr *TokenRepo) GetTokenInfo(address string) (TokenInfo, bool) {
tr.mux.RLock()
defer tr.mux.RUnlock()
info, ok := tr.repo[strings.ToLower(address)]
return info, ok
}
func (tr *TokenRepo) SetTokenInfo(address string, info TokenInfo) {
tr.mux.Lock()
defer tr.mux.Unlock()
tr.repo[strings.ToLower(address)] = info
}
func (tr *TokenRepo) RetriveTokenInfo(chainId int64, address string) (TokenInfo, error) {
if info, ok := tr.GetTokenInfo(address); ok {
return info, nil
}
chain, ok := tr.chainRepo.Get(chainId)
if !ok {
return TokenInfo{}, errors.New("chain not found")
}
client, err := ethclient.Dial(chain.Rpc)
if err != nil {
return TokenInfo{}, fmt.Errorf("fail to connect chain with url: %v, err: %v", chain.Rpc, err)
}
contract, err := token.NewTokenCaller(common.HexToAddress(address), client)
if err != nil {
return TokenInfo{}, err
}
callOpt := &bind.CallOpts{
BlockNumber: nil,
From: common.Address{},
Context: context.Background(),
}
name, err := contract.Name(callOpt)
if err != nil {
return TokenInfo{}, err
}
symbol, err := contract.Symbol(callOpt)
if err != nil {
return TokenInfo{}, err
}
decimals, err := contract.Decimals(callOpt)
if err != nil {
return TokenInfo{}, err
}
info := TokenInfo{
Name: name,
Symbol: symbol,
Decimals: decimals.Int64(),
Address: address,
}
tr.SetTokenInfo(address, info)
return info, nil
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment