github.com/status-im/status-go@v1.1.0/services/wallet/currency/service.go (about)

     1  package currency
     2  
     3  import (
     4  	"context"
     5  	"database/sql"
     6  	"time"
     7  
     8  	"github.com/ethereum/go-ethereum/event"
     9  	"github.com/status-im/status-go/services/wallet/market"
    10  	"github.com/status-im/status-go/services/wallet/token"
    11  	"github.com/status-im/status-go/services/wallet/walletevent"
    12  )
    13  
    14  const (
    15  	EventCurrencyTickUpdateFormat walletevent.EventType = "wallet-currency-tick-update-format"
    16  
    17  	currencyFormatUpdateInterval = 1 * time.Hour
    18  )
    19  
    20  type Service struct {
    21  	currency *Currency
    22  	db       *DB
    23  
    24  	tokenManager *token.Manager
    25  	walletFeed   *event.Feed
    26  	cancelFn     context.CancelFunc
    27  }
    28  
    29  func NewService(db *sql.DB, walletFeed *event.Feed, tokenManager *token.Manager, marketManager *market.Manager) *Service {
    30  	return &Service{
    31  		currency:     NewCurrency(marketManager),
    32  		db:           NewCurrencyDB(db),
    33  		tokenManager: tokenManager,
    34  		walletFeed:   walletFeed,
    35  	}
    36  }
    37  
    38  func (s *Service) Start() {
    39  	// Update all fiat currency formats in cache
    40  	fiatFormats, err := s.getAllFiatCurrencyFormats()
    41  
    42  	if err == nil {
    43  		_ = s.db.UpdateCachedFormats(fiatFormats)
    44  	}
    45  
    46  	ctx, cancel := context.WithCancel(context.Background())
    47  	s.cancelFn = cancel
    48  
    49  	go func() {
    50  		ticker := time.NewTicker(currencyFormatUpdateInterval)
    51  		defer ticker.Stop()
    52  		for {
    53  			select {
    54  			case <-ctx.Done():
    55  				return
    56  			case <-ticker.C:
    57  				s.walletFeed.Send(walletevent.Event{
    58  					Type: EventCurrencyTickUpdateFormat,
    59  				})
    60  			}
    61  		}
    62  	}()
    63  }
    64  
    65  func (s *Service) Stop() {
    66  	if s.cancelFn != nil {
    67  		s.cancelFn()
    68  	}
    69  }
    70  
    71  func (s *Service) GetCachedCurrencyFormats() (FormatPerSymbol, error) {
    72  	return s.db.GetCachedFormats()
    73  }
    74  
    75  func (s *Service) FetchAllCurrencyFormats() (FormatPerSymbol, error) {
    76  	// Only token prices can change, so we fetch those
    77  	tokenFormats, err := s.fetchAllTokenCurrencyFormats()
    78  
    79  	if err != nil {
    80  		return nil, err
    81  	}
    82  
    83  	err = s.db.UpdateCachedFormats(tokenFormats)
    84  
    85  	if err != nil {
    86  		return nil, err
    87  	}
    88  
    89  	return s.GetCachedCurrencyFormats()
    90  }
    91  
    92  func (s *Service) getAllFiatCurrencyFormats() (FormatPerSymbol, error) {
    93  	return GetFiatCurrencyFormats(GetAllFiatCurrencySymbols())
    94  }
    95  
    96  func (s *Service) fetchAllTokenCurrencyFormats() (FormatPerSymbol, error) {
    97  	tokens, err := s.tokenManager.GetAllTokens()
    98  	if err != nil {
    99  		return nil, err
   100  	}
   101  
   102  	tokenPerSymbolMap := make(map[string]bool)
   103  	tokenSymbols := make([]string, 0)
   104  	for _, t := range tokens {
   105  		symbol := t.Symbol
   106  		if !tokenPerSymbolMap[symbol] {
   107  			tokenPerSymbolMap[symbol] = true
   108  			tokenSymbols = append(tokenSymbols, symbol)
   109  		}
   110  	}
   111  
   112  	tokenFormats, err := s.currency.FetchTokenCurrencyFormats(tokenSymbols)
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  	gweiSymbol := "Gwei"
   117  	tokenFormats[gweiSymbol] = Format{
   118  		Symbol:              gweiSymbol,
   119  		DisplayDecimals:     9,
   120  		StripTrailingZeroes: true,
   121  	}
   122  	return tokenFormats, err
   123  }