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

     1  package wallet
     2  
     3  import (
     4  	"database/sql"
     5  	"encoding/json"
     6  	"fmt"
     7  	"sync"
     8  	"time"
     9  
    10  	"github.com/ethereum/go-ethereum/common"
    11  	"github.com/ethereum/go-ethereum/event"
    12  	"github.com/ethereum/go-ethereum/log"
    13  	"github.com/ethereum/go-ethereum/p2p"
    14  	gethrpc "github.com/ethereum/go-ethereum/rpc"
    15  
    16  	"github.com/status-im/status-go/account"
    17  	"github.com/status-im/status-go/multiaccounts/accounts"
    18  	"github.com/status-im/status-go/params"
    19  	protocolCommon "github.com/status-im/status-go/protocol/common"
    20  	"github.com/status-im/status-go/rpc"
    21  	"github.com/status-im/status-go/server"
    22  	"github.com/status-im/status-go/services/ens"
    23  	"github.com/status-im/status-go/services/stickers"
    24  	"github.com/status-im/status-go/services/wallet/activity"
    25  	"github.com/status-im/status-go/services/wallet/balance"
    26  	"github.com/status-im/status-go/services/wallet/blockchainstate"
    27  	"github.com/status-im/status-go/services/wallet/collectibles"
    28  	"github.com/status-im/status-go/services/wallet/community"
    29  	"github.com/status-im/status-go/services/wallet/currency"
    30  	"github.com/status-im/status-go/services/wallet/history"
    31  	"github.com/status-im/status-go/services/wallet/market"
    32  	"github.com/status-im/status-go/services/wallet/onramp"
    33  	"github.com/status-im/status-go/services/wallet/thirdparty"
    34  	"github.com/status-im/status-go/services/wallet/thirdparty/alchemy"
    35  	"github.com/status-im/status-go/services/wallet/thirdparty/coingecko"
    36  	"github.com/status-im/status-go/services/wallet/thirdparty/cryptocompare"
    37  	"github.com/status-im/status-go/services/wallet/thirdparty/opensea"
    38  	"github.com/status-im/status-go/services/wallet/thirdparty/rarible"
    39  	"github.com/status-im/status-go/services/wallet/token"
    40  	"github.com/status-im/status-go/services/wallet/transfer"
    41  	"github.com/status-im/status-go/services/wallet/walletevent"
    42  	"github.com/status-im/status-go/transactions"
    43  )
    44  
    45  const (
    46  	EventBlockchainStatusChanged walletevent.EventType = "wallet-blockchain-status-changed"
    47  )
    48  
    49  // NewService initializes service instance.
    50  func NewService(
    51  	db *sql.DB,
    52  	accountsDB *accounts.Database,
    53  	appDB *sql.DB,
    54  	rpcClient *rpc.Client,
    55  	accountFeed *event.Feed,
    56  	settingsFeed *event.Feed,
    57  	gethManager *account.GethManager,
    58  	transactor *transactions.Transactor,
    59  	config *params.NodeConfig,
    60  	ens *ens.Service,
    61  	stickers *stickers.Service,
    62  	pendingTxManager *transactions.PendingTxTracker,
    63  	feed *event.Feed,
    64  	mediaServer *server.MediaServer,
    65  	statusProxyStageName string,
    66  ) *Service {
    67  	signals := &walletevent.SignalsTransmitter{
    68  		Publisher: feed,
    69  	}
    70  	blockchainStatus := make(map[uint64]string)
    71  	mutex := sync.Mutex{}
    72  	rpcClient.SetWalletNotifier(func(chainID uint64, message string) {
    73  		mutex.Lock()
    74  		defer mutex.Unlock()
    75  
    76  		if len(blockchainStatus) == 0 {
    77  			networks, err := rpcClient.NetworkManager.Get(false)
    78  			if err != nil {
    79  				return
    80  			}
    81  
    82  			for _, network := range networks {
    83  				blockchainStatus[network.ChainID] = "up"
    84  			}
    85  		}
    86  
    87  		blockchainStatus[chainID] = message
    88  		encodedmessage, err := json.Marshal(blockchainStatus)
    89  		if err != nil {
    90  			return
    91  		}
    92  
    93  		feed.Send(walletevent.Event{
    94  			Type:     EventBlockchainStatusChanged,
    95  			Accounts: []common.Address{},
    96  			Message:  string(encodedmessage),
    97  			At:       time.Now().Unix(),
    98  			ChainID:  chainID,
    99  		})
   100  	})
   101  
   102  	communityManager := community.NewManager(db, mediaServer, feed)
   103  	balanceCacher := balance.NewCacherWithTTL(5 * time.Minute)
   104  	tokenManager := token.NewTokenManager(db, rpcClient, communityManager, rpcClient.NetworkManager, appDB, mediaServer, feed, accountFeed, accountsDB, token.NewPersistence(db))
   105  	tokenManager.Start()
   106  
   107  	cryptoOnRampProviders := []onramp.Provider{
   108  		onramp.NewMercuryoProvider(tokenManager),
   109  		onramp.NewRampProvider(),
   110  		onramp.NewMoonPayProvider(),
   111  	}
   112  	cryptoOnRampManager := onramp.NewManager(cryptoOnRampProviders)
   113  
   114  	savedAddressesManager := &SavedAddressesManager{db: db}
   115  	transactionManager := transfer.NewTransactionManager(transfer.NewMultiTransactionDB(db), gethManager, transactor, config, accountsDB, pendingTxManager, feed)
   116  	blockChainState := blockchainstate.NewBlockChainState()
   117  	transferController := transfer.NewTransferController(db, accountsDB, rpcClient, accountFeed, feed, transactionManager, pendingTxManager,
   118  		tokenManager, balanceCacher, blockChainState)
   119  	transferController.Start()
   120  	cryptoCompare := cryptocompare.NewClient()
   121  	coingecko := coingecko.NewClient()
   122  	cryptoCompareProxy := cryptocompare.NewClientWithParams(cryptocompare.Params{
   123  		ID:       fmt.Sprintf("%s-proxy", cryptoCompare.ID()),
   124  		URL:      fmt.Sprintf("https://%s.api.status.im/cryptocompare/", statusProxyStageName),
   125  		User:     config.WalletConfig.StatusProxyMarketUser,
   126  		Password: config.WalletConfig.StatusProxyMarketPassword,
   127  	})
   128  	marketManager := market.NewManager([]thirdparty.MarketDataProvider{cryptoCompare, coingecko, cryptoCompareProxy}, feed)
   129  	reader := NewReader(tokenManager, marketManager, token.NewPersistence(db), feed)
   130  	history := history.NewService(db, accountsDB, accountFeed, feed, rpcClient, tokenManager, marketManager, balanceCacher.Cache())
   131  	currency := currency.NewService(db, feed, tokenManager, marketManager)
   132  
   133  	openseaHTTPClient := opensea.NewHTTPClient()
   134  	openseaV2Client := opensea.NewClientV2(config.WalletConfig.OpenseaAPIKey, openseaHTTPClient)
   135  	raribleClient := rarible.NewClient(config.WalletConfig.RaribleMainnetAPIKey, config.WalletConfig.RaribleTestnetAPIKey)
   136  	alchemyClient := alchemy.NewClient(config.WalletConfig.AlchemyAPIKeys)
   137  
   138  	// Collectible providers in priority order (i.e. provider N+1 will be tried only if provider N fails)
   139  	contractOwnershipProviders := []thirdparty.CollectibleContractOwnershipProvider{
   140  		raribleClient,
   141  		alchemyClient,
   142  	}
   143  
   144  	accountOwnershipProviders := []thirdparty.CollectibleAccountOwnershipProvider{
   145  		raribleClient,
   146  		alchemyClient,
   147  		openseaV2Client,
   148  	}
   149  
   150  	collectibleDataProviders := []thirdparty.CollectibleDataProvider{
   151  		raribleClient,
   152  		alchemyClient,
   153  		openseaV2Client,
   154  	}
   155  
   156  	collectionDataProviders := []thirdparty.CollectionDataProvider{
   157  		raribleClient,
   158  		alchemyClient,
   159  		openseaV2Client,
   160  	}
   161  
   162  	collectibleSearchProviders := []thirdparty.CollectibleSearchProvider{
   163  		raribleClient,
   164  	}
   165  
   166  	collectibleProviders := thirdparty.CollectibleProviders{
   167  		ContractOwnershipProviders: contractOwnershipProviders,
   168  		AccountOwnershipProviders:  accountOwnershipProviders,
   169  		CollectibleDataProviders:   collectibleDataProviders,
   170  		CollectionDataProviders:    collectionDataProviders,
   171  		SearchProviders:            collectibleSearchProviders,
   172  	}
   173  
   174  	collectiblesManager := collectibles.NewManager(
   175  		db,
   176  		rpcClient,
   177  		communityManager,
   178  		collectibleProviders,
   179  		mediaServer,
   180  		feed,
   181  	)
   182  	collectibles := collectibles.NewService(db, feed, accountsDB, accountFeed, settingsFeed, communityManager, rpcClient.NetworkManager, collectiblesManager)
   183  
   184  	activity := activity.NewService(db, accountsDB, tokenManager, collectiblesManager, feed, pendingTxManager)
   185  
   186  	featureFlags := &protocolCommon.FeatureFlags{}
   187  	if config.WalletConfig.EnableCelerBridge {
   188  		featureFlags.EnableCelerBridge = true
   189  	}
   190  
   191  	return &Service{
   192  		db:                    db,
   193  		accountsDB:            accountsDB,
   194  		rpcClient:             rpcClient,
   195  		tokenManager:          tokenManager,
   196  		communityManager:      communityManager,
   197  		savedAddressesManager: savedAddressesManager,
   198  		transactionManager:    transactionManager,
   199  		pendingTxManager:      pendingTxManager,
   200  		transferController:    transferController,
   201  		cryptoOnRampManager:   cryptoOnRampManager,
   202  		collectiblesManager:   collectiblesManager,
   203  		collectibles:          collectibles,
   204  		gethManager:           gethManager,
   205  		marketManager:         marketManager,
   206  		transactor:            transactor,
   207  		ens:                   ens,
   208  		stickers:              stickers,
   209  		feed:                  feed,
   210  		signals:               signals,
   211  		reader:                reader,
   212  		history:               history,
   213  		currency:              currency,
   214  		activity:              activity,
   215  		decoder:               NewDecoder(),
   216  		blockChainState:       blockChainState,
   217  		keycardPairings:       NewKeycardPairings(),
   218  		config:                config,
   219  		featureFlags:          featureFlags,
   220  	}
   221  }
   222  
   223  // Service is a wallet service.
   224  type Service struct {
   225  	db                    *sql.DB
   226  	accountsDB            *accounts.Database
   227  	rpcClient             *rpc.Client
   228  	savedAddressesManager *SavedAddressesManager
   229  	tokenManager          *token.Manager
   230  	communityManager      *community.Manager
   231  	transactionManager    *transfer.TransactionManager
   232  	pendingTxManager      *transactions.PendingTxTracker
   233  	cryptoOnRampManager   *onramp.Manager
   234  	transferController    *transfer.Controller
   235  	marketManager         *market.Manager
   236  	started               bool
   237  	collectiblesManager   *collectibles.Manager
   238  	collectibles          *collectibles.Service
   239  	gethManager           *account.GethManager
   240  	transactor            *transactions.Transactor
   241  	ens                   *ens.Service
   242  	stickers              *stickers.Service
   243  	feed                  *event.Feed
   244  	signals               *walletevent.SignalsTransmitter
   245  	reader                *Reader
   246  	history               *history.Service
   247  	currency              *currency.Service
   248  	activity              *activity.Service
   249  	decoder               *Decoder
   250  	blockChainState       *blockchainstate.BlockChainState
   251  	keycardPairings       *KeycardPairings
   252  	config                *params.NodeConfig
   253  	featureFlags          *protocolCommon.FeatureFlags
   254  }
   255  
   256  // Start signals transmitter.
   257  func (s *Service) Start() error {
   258  	s.transferController.Start()
   259  	s.currency.Start()
   260  	err := s.signals.Start()
   261  	s.history.Start()
   262  	s.collectibles.Start()
   263  	s.started = true
   264  	return err
   265  }
   266  
   267  // Set external Collectibles community info provider
   268  func (s *Service) SetWalletCommunityInfoProvider(provider thirdparty.CommunityInfoProvider) {
   269  	s.communityManager.SetCommunityInfoProvider(provider)
   270  }
   271  
   272  // Stop reactor and close db.
   273  func (s *Service) Stop() error {
   274  	log.Info("wallet will be stopped")
   275  	s.signals.Stop()
   276  	s.transferController.Stop()
   277  	s.currency.Stop()
   278  	s.reader.Stop()
   279  	s.history.Stop()
   280  	s.activity.Stop()
   281  	s.collectibles.Stop()
   282  	s.tokenManager.Stop()
   283  	s.started = false
   284  	log.Info("wallet stopped")
   285  	return nil
   286  }
   287  
   288  // APIs returns list of available RPC APIs.
   289  func (s *Service) APIs() []gethrpc.API {
   290  	return []gethrpc.API{
   291  		{
   292  			Namespace: "wallet",
   293  			Version:   "0.1.0",
   294  			Service:   NewAPI(s),
   295  			Public:    true,
   296  		},
   297  	}
   298  }
   299  
   300  // Protocols returns list of p2p protocols.
   301  func (s *Service) Protocols() []p2p.Protocol {
   302  	return nil
   303  }
   304  
   305  func (s *Service) IsStarted() bool {
   306  	return s.started
   307  }
   308  
   309  func (s *Service) KeycardPairings() *KeycardPairings {
   310  	return s.keycardPairings
   311  }
   312  
   313  func (s *Service) Config() *params.NodeConfig {
   314  	return s.config
   315  }
   316  
   317  func (s *Service) FeatureFlags() *protocolCommon.FeatureFlags {
   318  	return s.featureFlags
   319  }
   320  
   321  func (s *Service) GetRPCClient() *rpc.Client {
   322  	return s.rpcClient
   323  }
   324  
   325  func (s *Service) GetTransactor() *transactions.Transactor {
   326  	return s.transactor
   327  }
   328  
   329  func (s *Service) GetTokenManager() *token.Manager {
   330  	return s.tokenManager
   331  }
   332  
   333  func (s *Service) GetMarketManager() *market.Manager {
   334  	return s.marketManager
   335  }
   336  
   337  func (s *Service) GetCollectiblesService() *collectibles.Service {
   338  	return s.collectibles
   339  }
   340  
   341  func (s *Service) GetCollectiblesManager() *collectibles.Manager {
   342  	return s.collectiblesManager
   343  }
   344  
   345  func (s *Service) GetEnsService() *ens.Service {
   346  	return s.ens
   347  }
   348  
   349  func (s *Service) GetStickersService() *stickers.Service {
   350  	return s.stickers
   351  }