136 lines
3.2 KiB
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
|
|
}
|