status-go/services/wallet/router.go

136 lines
3.2 KiB
Go

package wallet
import (
"context"
"math"
"math/big"
"sync"
"github.com/ethereum/go-ethereum/common"
"github.com/status-im/status-go/params"
"github.com/status-im/status-go/services/wallet/async"
"github.com/status-im/status-go/services/wallet/chain"
)
type SuggestedRoutes struct {
Networks []params.Network `json:"networks"`
}
func NewRouter(s *Service) *Router {
return &Router{s}
}
type Router struct {
s *Service
}
func (r *Router) suitableTokenExists(ctx context.Context, network *params.Network, tokens []*Token, account common.Address, amount float64, tokenSymbol string) (bool, error) {
for _, token := range tokens {
if token.Symbol != tokenSymbol {
continue
}
clients, err := chain.NewClients(r.s.rpcClient, []uint64{network.ChainID})
if err != nil {
return false, err
}
balance, err := r.s.tokenManager.getBalance(ctx, clients[0], account, token.Address)
if err != nil {
return false, err
}
amountForToken, _ := new(big.Float).Mul(big.NewFloat(amount), big.NewFloat(math.Pow10(int(token.Decimals)))).Int(nil)
if balance.Cmp(amountForToken) >= 0 {
return true, nil
}
}
return false, nil
}
func (r *Router) suggestedRoutes(ctx context.Context, account common.Address, amount float64, tokenSymbol string, disabledChainIDs []uint64) (*SuggestedRoutes, error) {
areTestNetworksEnabled, err := r.s.accountsDB.GetTestNetworksEnabled()
if err != nil {
return nil, err
}
networks, err := r.s.rpcClient.NetworkManager.Get(false)
if err != nil {
return nil, err
}
var (
group = async.NewAtomicGroup(ctx)
mu sync.Mutex
candidates = make([]params.Network, 0)
)
for networkIdx := range networks {
network := networks[networkIdx]
if network.IsTest != areTestNetworksEnabled {
continue
}
networkFound := false
for _, chainID := range disabledChainIDs {
networkFound = false
if chainID == network.ChainID {
networkFound = true
break
}
}
// This is network cannot be used as a suggestedRoute as the user has disabled it
if networkFound {
continue
}
group.Add(func(c context.Context) error {
if tokenSymbol == network.NativeCurrencySymbol {
tokens := []*Token{&Token{
Address: common.HexToAddress("0x"),
Symbol: network.NativeCurrencySymbol,
Decimals: uint(network.NativeCurrencyDecimals),
Name: network.NativeCurrencyName,
}}
ok, _ := r.suitableTokenExists(c, network, tokens, account, amount, tokenSymbol)
if ok {
mu.Lock()
candidates = append(candidates, *network)
mu.Unlock()
return nil
}
}
tokens, err := r.s.tokenManager.getTokens(network.ChainID)
if err == nil {
ok, _ := r.suitableTokenExists(c, network, tokens, account, amount, tokenSymbol)
if ok {
mu.Lock()
candidates = append(candidates, *network)
mu.Unlock()
return nil
}
}
customTokens, err := r.s.tokenManager.getCustomsByChainID(network.ChainID)
if err == nil {
ok, _ := r.suitableTokenExists(c, network, customTokens, account, amount, tokenSymbol)
if ok {
mu.Lock()
candidates = append(candidates, *network)
mu.Unlock()
}
}
return nil
})
}
group.Wait()
return &SuggestedRoutes{
Networks: candidates,
}, nil
}