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 }