diff --git a/node/status_node_services.go b/node/status_node_services.go index cbd527ad0cd..71ad5e796ad 100644 --- a/node/status_node_services.go +++ b/node/status_node_services.go @@ -60,7 +60,6 @@ import ( "github.com/status-im/status-go/services/wakuv2ext" "github.com/status-im/status-go/services/wallet" "github.com/status-im/status-go/services/wallet/thirdparty" - "github.com/status-im/status-go/services/wallet/transfer" "github.com/status-im/status-go/services/web3provider" "github.com/status-im/status-go/timesource" "github.com/status-im/status-go/waku" @@ -606,7 +605,7 @@ func (b *StatusNode) walletService(accountsDB *accounts.Database, appDB *sql.DB, func (b *StatusNode) localNotificationsService(network uint64) (*localnotifications.Service, error) { var err error if b.localNotificationsSrvc == nil { - b.localNotificationsSrvc, err = localnotifications.NewService(b.appDB, transfer.NewDB(b.walletDB), network) + b.localNotificationsSrvc, err = localnotifications.NewService(b.appDB) if err != nil { return nil, err } @@ -684,13 +683,6 @@ func (b *StatusNode) StartLocalNotifications() error { } } - err := b.localNotificationsSrvc.SubscribeWallet(&b.walletFeed) - - if err != nil { - b.logger.Error("LocalNotifications service could not subscribe to wallet on StartLocalNotifications", zap.Error(err)) - return nil - } - return nil } diff --git a/services/local-notifications/api.go b/services/local-notifications/api.go index 632ef499934..c3b82ecd693 100644 --- a/services/local-notifications/api.go +++ b/services/local-notifications/api.go @@ -2,8 +2,6 @@ package localnotifications import ( "context" - - "github.com/status-im/status-go/logutils" ) func NewAPI(s *Service) *API { @@ -17,15 +15,3 @@ type API struct { func (api *API) NotificationPreferences(ctx context.Context) ([]NotificationPreference, error) { return api.s.db.GetPreferences() } - -func (api *API) SwitchWalletNotifications(ctx context.Context, preference bool) error { - logutils.ZapLogger().Debug("Switch Transaction Notification") - err := api.s.db.ChangeWalletPreference(preference) - if err != nil { - return err - } - - api.s.WatchingEnabled = preference - - return nil -} diff --git a/services/local-notifications/core.go b/services/local-notifications/core.go index 71f229e7fed..2c650cd69d4 100644 --- a/services/local-notifications/core.go +++ b/services/local-notifications/core.go @@ -3,18 +3,11 @@ package localnotifications import ( "database/sql" "encoding/json" - "sync" - - "go.uber.org/zap" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/rpc" - gocommon "github.com/status-im/status-go/common" "github.com/status-im/status-go/logutils" - "github.com/status-im/status-go/multiaccounts/accounts" - "github.com/status-im/status-go/services/wallet/transfer" "github.com/status-im/status-go/signal" ) @@ -79,41 +72,17 @@ type MessageEvent struct{} // CustomEvent - structure used to pass custom user set messages to bus type CustomEvent struct{} -type transmitter struct { - publisher *event.Feed - - wg sync.WaitGroup - quit chan struct{} -} - // Service keeps the state of message bus type Service struct { - started bool - WatchingEnabled bool - chainID uint64 - transmitter *transmitter - walletTransmitter *transmitter - db *Database - walletDB *transfer.Database - accountsDB *accounts.Database + started bool + db *Database } -func NewService(appDB *sql.DB, walletDB *transfer.Database, chainID uint64) (*Service, error) { - db := NewDB(appDB, chainID) - accountsDB, err := accounts.NewDB(appDB) - if err != nil { - return nil, err - } - trans := &transmitter{} - walletTrans := &transmitter{} +func NewService(appDB *sql.DB) (*Service, error) { + db := NewDB(appDB) return &Service{ - db: db, - chainID: chainID, - walletDB: walletDB, - accountsDB: accountsDB, - transmitter: trans, - walletTransmitter: walletTrans, + db: db, }, nil } @@ -165,54 +134,13 @@ func pushMessage(notification *Notification) { // Start Worker which processes all incoming messages func (s *Service) Start() error { s.started = true - - s.transmitter.quit = make(chan struct{}) - s.transmitter.publisher = &event.Feed{} - - events := make(chan TransactionEvent, 10) - sub := s.transmitter.publisher.Subscribe(events) - - s.transmitter.wg.Add(1) - go func() { - defer gocommon.LogOnPanic() - defer s.transmitter.wg.Done() - for { - select { - case <-s.transmitter.quit: - sub.Unsubscribe() - return - case err := <-sub.Err(): - if err != nil { - logutils.ZapLogger().Error("Local notifications transmitter failed with", zap.Error(err)) - } - return - case event := <-events: - s.transactionsHandler(event) - } - } - }() - logutils.ZapLogger().Info("Successful start") - return nil } // Stop worker func (s *Service) Stop() error { s.started = false - - if s.transmitter.quit != nil { - close(s.transmitter.quit) - s.transmitter.wg.Wait() - s.transmitter.quit = nil - } - - if s.walletTransmitter.quit != nil { - close(s.walletTransmitter.quit) - s.walletTransmitter.wg.Wait() - s.walletTransmitter.quit = nil - } - return nil } diff --git a/services/local-notifications/core_test.go b/services/local-notifications/core_test.go index baaeddf9a0c..f6a335188bd 100644 --- a/services/local-notifications/core_test.go +++ b/services/local-notifications/core_test.go @@ -1,43 +1,16 @@ package localnotifications import ( - "fmt" - "math/big" - "strings" "testing" - "time" "github.com/stretchr/testify/require" - - w_common "github.com/status-im/status-go/services/wallet/common" - "github.com/status-im/status-go/services/wallet/transfer" - "github.com/status-im/status-go/services/wallet/walletevent" - "github.com/status-im/status-go/signal" - "github.com/status-im/status-go/t/helpers" - "github.com/status-im/status-go/t/utils" - "github.com/status-im/status-go/walletdatabase" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/event" ) -func createWalletDb(t *testing.T) (*transfer.Database, func()) { - db, cleanup, err := helpers.SetupTestSQLDB(walletdatabase.DbInitializer{}, "local-notifications-tests-wallet-") - require.NoError(t, err) - return transfer.NewDB(db), func() { - require.NoError(t, cleanup()) - } -} - func TestServiceStartStop(t *testing.T) { db, stop := setupAppTestDb(t) defer stop() - walletDb, walletStop := createWalletDb(t) - defer walletStop() - - s, err := NewService(db, walletDb, 1777) + s, err := NewService(db) require.NoError(t, err) require.NoError(t, s.Start()) require.Equal(t, true, s.IsStarted()) @@ -45,101 +18,3 @@ func TestServiceStartStop(t *testing.T) { require.NoError(t, s.Stop()) require.Equal(t, false, s.IsStarted()) } - -func TestWalletSubscription(t *testing.T) { - db, stop := setupAppTestDb(t) - defer stop() - - walletDb, walletStop := createWalletDb(t) - defer walletStop() - - feed := &event.Feed{} - s, err := NewService(db, walletDb, 1777) - require.NoError(t, err) - require.NoError(t, s.Start()) - require.Equal(t, true, s.IsStarted()) - - require.NoError(t, s.SubscribeWallet(feed)) - require.Equal(t, true, s.IsWatchingWallet()) - - s.StartWalletWatcher() - require.Equal(t, true, s.IsWatchingWallet()) - - s.StopWalletWatcher() - require.Equal(t, false, s.IsWatchingWallet()) - - require.NoError(t, s.Stop()) - require.Equal(t, false, s.IsStarted()) -} - -func TestTransactionNotification(t *testing.T) { - db, stop := setupAppTestDb(t) - defer stop() - - walletDb, walletStop := createWalletDb(t) - defer walletStop() - - s, err := NewService(db, walletDb, 1777) - require.NoError(t, err) - require.NoError(t, s.Start()) - require.Equal(t, true, s.IsStarted()) - - var signalEvent []byte - - signalHandler := signal.MobileSignalHandler(func(s []byte) { - signalEvent = s - }) - - signal.SetMobileSignalHandler(signalHandler) - t.Cleanup(signal.ResetMobileSignalHandler) - - feed := &event.Feed{} - require.NoError(t, s.SubscribeWallet(feed)) - s.WatchingEnabled = true - - s.StartWalletWatcher() - - header := &transfer.DBHeader{ - Number: big.NewInt(1), - Hash: common.Hash{1}, - Address: common.Address{1}, - } - tx := types.NewTransaction(1, common.Address{1}, nil, 10, big.NewInt(10), nil) - receipt := types.NewReceipt(nil, false, 100) - receipt.Logs = []*types.Log{} - transfers := []transfer.Transfer{ - { - ID: common.Hash{1}, - Type: w_common.Type("eth"), - BlockHash: header.Hash, - BlockNumber: header.Number, - Transaction: tx, - Receipt: receipt, - Address: header.Address, - }, - } - require.NoError(t, walletDb.SaveBlocks(1777, []*transfer.DBHeader{header})) - require.NoError(t, transfer.SaveTransfersMarkBlocksLoaded(walletDb, 1777, header.Address, transfers, []*big.Int{header.Number})) - - feed.Send(walletevent.Event{ - Type: transfer.EventRecentHistoryReady, - Accounts: []common.Address{header.Address}, - }) - - feed.Send(walletevent.Event{ - Type: transfer.EventNewTransfers, - BlockNumber: header.Number, - Accounts: []common.Address{header.Address}, - }) - - require.NoError(t, utils.Eventually(func() error { - if signalEvent == nil { - return fmt.Errorf("signal was not handled") - } - require.True(t, strings.Contains(string(signalEvent), `"type":"local-notifications"`)) - require.True(t, strings.Contains(string(signalEvent), `"to":"`+header.Address.Hex())) - return nil - }, 2*time.Second, 100*time.Millisecond)) - - require.NoError(t, s.Stop()) -} diff --git a/services/local-notifications/database.go b/services/local-notifications/database.go index 4e06a750ab7..1ba3fe27614 100644 --- a/services/local-notifications/database.go +++ b/services/local-notifications/database.go @@ -5,8 +5,7 @@ import ( ) type Database struct { - db *sql.DB - network uint64 + db *sql.DB } type NotificationPreference struct { @@ -16,8 +15,8 @@ type NotificationPreference struct { Identifier string `json:"identifier,omitempty"` } -func NewDB(db *sql.DB, network uint64) *Database { - return &Database{db: db, network: network} +func NewDB(db *sql.DB) *Database { + return &Database{db: db} } func (db *Database) GetPreferences() (rst []NotificationPreference, err error) { @@ -37,17 +36,7 @@ func (db *Database) GetPreferences() (rst []NotificationPreference, err error) { return rst, nil } -func (db *Database) GetWalletPreference() (rst NotificationPreference, err error) { - pref := db.db.QueryRow("SELECT service, event, identifier, enabled FROM local_notifications_preferences WHERE service = 'wallet' AND event = 'transaction' AND identifier = 'all'") - - err = pref.Scan(&rst.Service, &rst.Event, &rst.Identifier, &rst.Enabled) - if err == sql.ErrNoRows { - return rst, nil - } - return -} - -func (db *Database) ChangeWalletPreference(preference bool) error { - _, err := db.db.Exec("INSERT OR REPLACE INTO local_notifications_preferences (service, event, identifier, enabled) VALUES ('wallet', 'transaction', 'all', ?)", preference) +func (db *Database) ChangePreference(p NotificationPreference) error { + _, err := db.db.Exec("INSERT OR REPLACE INTO local_notifications_preferences (enabled, service, event, identifier) VALUES (?, ?, ?, ?)", p.Enabled, p.Service, p.Event, p.Identifier) return err } diff --git a/services/local-notifications/database_test.go b/services/local-notifications/database_test.go index 367bc3a0499..69c1eea3302 100644 --- a/services/local-notifications/database_test.go +++ b/services/local-notifications/database_test.go @@ -17,32 +17,11 @@ func setupAppTestDb(t *testing.T) (*sql.DB, func()) { } func setupTestDB(t *testing.T, db *sql.DB) (*Database, func()) { - return NewDB(db, 1777), func() { + return NewDB(db), func() { require.NoError(t, db.Close()) } } -func TestWalletPreferences(t *testing.T) { - appDB, appStop := setupAppTestDb(t) - defer appStop() - - db, stop := setupTestDB(t, appDB) - defer stop() - - enabled := true - require.NoError(t, db.ChangeWalletPreference(enabled)) - rst, err := db.GetWalletPreference() - require.NoError(t, err) - require.Equal(t, enabled, rst.Enabled) - - enabled = false - require.NoError(t, db.ChangeWalletPreference(enabled)) - rst, err = db.GetWalletPreference() - require.Equal(t, enabled, rst.Enabled) - - require.NoError(t, err) -} - func TestPreferences(t *testing.T) { appDB, appStop := setupAppTestDb(t) defer appStop() @@ -52,7 +31,14 @@ func TestPreferences(t *testing.T) { enabled := true - require.NoError(t, db.ChangeWalletPreference(enabled)) + require.NoError(t, db.ChangePreference( + NotificationPreference{ + Enabled: enabled, + Service: "service", + Event: "event", + Identifier: "identifier", + }, + )) rst, err := db.GetPreferences() require.Equal(t, 1, len(rst)) diff --git a/services/local-notifications/transaction.go b/services/local-notifications/transaction.go deleted file mode 100644 index 7b5b49a6b2b..00000000000 --- a/services/local-notifications/transaction.go +++ /dev/null @@ -1,234 +0,0 @@ -package localnotifications - -import ( - "encoding/json" - "math/big" - - "go.uber.org/zap" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/event" - - gocommon "github.com/status-im/status-go/common" - "github.com/status-im/status-go/eth-node/types" - "github.com/status-im/status-go/logutils" - "github.com/status-im/status-go/multiaccounts/accounts" - "github.com/status-im/status-go/services/wallet/transfer" - "github.com/status-im/status-go/services/wallet/walletevent" -) - -type transactionState string - -const ( - walletDeeplinkPrefix = "status-app://wallet/" - - failed transactionState = "failed" - inbound transactionState = "inbound" - outbound transactionState = "outbound" -) - -// TransactionEvent - structure used to pass messages from wallet to bus -type TransactionEvent struct { - Type string `json:"type"` - BlockNumber *big.Int `json:"block-number"` - Accounts []common.Address `json:"accounts"` - MaxKnownBlocks map[common.Address]*big.Int `json:"max-known-blocks"` -} - -type transactionBody struct { - State transactionState `json:"state"` - From common.Address `json:"from"` - To common.Address `json:"to"` - FromAccount *accounts.Account `json:"fromAccount,omitempty"` - ToAccount *accounts.Account `json:"toAccount,omitempty"` - Value *hexutil.Big `json:"value"` - ERC20 bool `json:"erc20"` - Contract common.Address `json:"contract"` - Network uint64 `json:"network"` -} - -func (t transactionBody) MarshalJSON() ([]byte, error) { - type Alias transactionBody - item := struct{ *Alias }{Alias: (*Alias)(&t)} - return json.Marshal(item) -} - -func (s *Service) buildTransactionNotification(rawTransfer transfer.Transfer) *Notification { - logutils.ZapLogger().Debug("Handled a new transfer in buildTransactionNotification", zap.Any("info", rawTransfer)) - - var deeplink string - var state transactionState - transfer := transfer.CastToTransferView(rawTransfer) - - switch { - case transfer.TxStatus == hexutil.Uint64(0): - state = failed - case transfer.Address == transfer.To: - state = inbound - default: - state = outbound - } - - from, err := s.accountsDB.GetAccountByAddress(types.Address(transfer.From)) - - if err != nil { - logutils.ZapLogger().Debug("Could not select From account by address", zap.Error(err)) - } - - to, err := s.accountsDB.GetAccountByAddress(types.Address(transfer.To)) - - if err != nil { - logutils.ZapLogger().Debug("Could not select To account by address", zap.Error(err)) - } - - if from != nil { - deeplink = walletDeeplinkPrefix + from.Address.String() - } else if to != nil { - deeplink = walletDeeplinkPrefix + to.Address.String() - } - - body := transactionBody{ - State: state, - From: transfer.From, - To: transfer.Address, - FromAccount: from, - ToAccount: to, - Value: transfer.Value, - ERC20: string(transfer.Type) == "erc20", - Contract: transfer.Contract, - Network: transfer.NetworkID, - } - - return &Notification{ - BodyType: TypeTransaction, - ID: transfer.ID, - Body: body, - Deeplink: deeplink, - Category: CategoryTransaction, - } -} - -func (s *Service) transactionsHandler(payload TransactionEvent) { - logutils.ZapLogger().Info("Handled a new transaction", zap.Any("info", payload)) - - limit := 20 - if payload.BlockNumber != nil { - for _, address := range payload.Accounts { - if payload.BlockNumber.Cmp(payload.MaxKnownBlocks[address]) >= 0 { - logutils.ZapLogger().Info("Handled transfer for address", zap.Stringer("info", address)) - transfers, err := s.walletDB.GetTransfersByAddressAndBlock(s.chainID, address, payload.BlockNumber, int64(limit)) - if err != nil { - logutils.ZapLogger().Error("Could not fetch transfers", zap.Error(err)) - } - - for _, transaction := range transfers { - n := s.buildTransactionNotification(transaction) - pushMessage(n) - } - } - } - } -} - -// SubscribeWallet - Subscribes to wallet signals -func (s *Service) SubscribeWallet(publisher *event.Feed) error { - s.walletTransmitter.publisher = publisher - - preference, err := s.db.GetWalletPreference() - - if err != nil { - logutils.ZapLogger().Error("Failed to get wallet preference", zap.Error(err)) - s.WatchingEnabled = false - } else { - s.WatchingEnabled = preference.Enabled - } - - s.StartWalletWatcher() - - return err -} - -// StartWalletWatcher - Forward wallet events to notifications -func (s *Service) StartWalletWatcher() { - if s.walletTransmitter.quit != nil { - // already running, nothing to do - return - } - - if s.walletTransmitter.publisher == nil { - logutils.ZapLogger().Error("wallet publisher was not initialized") - return - } - - s.walletTransmitter.quit = make(chan struct{}) - events := make(chan walletevent.Event, 10) - sub := s.walletTransmitter.publisher.Subscribe(events) - - s.walletTransmitter.wg.Add(1) - - maxKnownBlocks := map[common.Address]*big.Int{} - go func() { - defer gocommon.LogOnPanic() - defer s.walletTransmitter.wg.Done() - historyReady := false - for { - select { - case <-s.walletTransmitter.quit: - sub.Unsubscribe() - return - case err := <-sub.Err(): - // technically event.Feed cannot send an error to subscription.Err channel. - // the only time we will get an event is when that channel is closed. - if err != nil { - logutils.ZapLogger().Error("wallet signals transmitter failed with", zap.Error(err)) - } - return - case event := <-events: - if event.Type == transfer.EventNewTransfers && historyReady && event.BlockNumber != nil { - newBlocks := false - for _, address := range event.Accounts { - if _, ok := maxKnownBlocks[address]; !ok { - newBlocks = true - maxKnownBlocks[address] = event.BlockNumber - } else if event.BlockNumber.Cmp(maxKnownBlocks[address]) == 1 { - maxKnownBlocks[address] = event.BlockNumber - newBlocks = true - } - } - if newBlocks && s.WatchingEnabled { - s.transmitter.publisher.Send(TransactionEvent{ - Type: string(event.Type), - BlockNumber: event.BlockNumber, - Accounts: event.Accounts, - MaxKnownBlocks: maxKnownBlocks, - }) - } - } else if event.Type == transfer.EventRecentHistoryReady { - historyReady = true - if event.BlockNumber != nil { - for _, address := range event.Accounts { - if _, ok := maxKnownBlocks[address]; !ok { - maxKnownBlocks[address] = event.BlockNumber - } - } - } - } - } - } - }() -} - -// StopWalletWatcher - stops watching for new wallet events -func (s *Service) StopWalletWatcher() { - if s.walletTransmitter.quit != nil { - close(s.walletTransmitter.quit) - s.walletTransmitter.wg.Wait() - s.walletTransmitter.quit = nil - } -} - -// IsWatchingWallet - check if local-notifications are subscribed to wallet updates -func (s *Service) IsWatchingWallet() bool { - return s.walletTransmitter.quit != nil -} diff --git a/services/local-notifications/types.go b/services/local-notifications/types.go index efc2af1a1b2..cc47eecbc5c 100644 --- a/services/local-notifications/types.go +++ b/services/local-notifications/types.go @@ -1,12 +1,10 @@ package localnotifications const ( - CategoryTransaction PushCategory = "transaction" CategoryMessage PushCategory = "newMessage" CategoryGroupInvite PushCategory = "groupInvite" CategoryCommunityRequestToJoin = "communityRequestToJoin" CategoryCommunityJoined = "communityJoined" - TypeTransaction NotificationType = "transaction" - TypeMessage NotificationType = "message" + TypeMessage NotificationType = "message" ) diff --git a/services/wallet/activity/activity_test.go b/services/wallet/activity/activity_test.go index a4011841aaf..0b47a04f3df 100644 --- a/services/wallet/activity/activity_test.go +++ b/services/wallet/activity/activity_test.go @@ -1396,56 +1396,6 @@ func TestGetActivityEntries_ErrorIfNoAddress(t *testing.T) { require.EqualError(t, err, "no addresses provided") } -func TestGetTxDetails(t *testing.T) { - deps, close := setupTestActivityDB(t) - defer close() - - // Adds 4 extractable transactions 2 transactions (ETH/Sepolia, ETH/Optimism), one MT USDC to DAI and another MT USDC to SNT - td, _, _ := fillTestData(t, deps.db) - - _, err := getTxDetails(context.Background(), deps.db, "") - require.EqualError(t, err, "invalid tx id") - - details, err := getTxDetails(context.Background(), deps.db, td.tr1.Hash.String()) - require.NoError(t, err) - - require.Equal(t, td.tr1.Hash.String(), details.ID) - require.Equal(t, 0, details.MultiTxID) - require.Equal(t, td.tr1.Nonce, details.Nonce) - require.Equal(t, len(details.ChainDetails), 1) - require.Equal(t, td.tr1.ChainID, common.ChainID(details.ChainDetails[0].ChainID)) - require.Equal(t, td.tr1.BlkNumber, details.ChainDetails[0].BlockNumber) - require.Equal(t, td.tr1.Hash, details.ChainDetails[0].Hash) - require.Equal(t, td.tr1.Contract, *details.ChainDetails[0].Contract) -} - -func TestGetMultiTxDetails(t *testing.T) { - deps, close := setupTestActivityDB(t) - defer close() - - // Adds 4 extractable transactions 2 transactions (ETH/Sepolia, ETH/Optimism), one MT USDC to DAI and another MT USDC to SNT - td, _, _ := fillTestData(t, deps.db) - - _, err := getMultiTxDetails(context.Background(), deps.db, 0) - require.EqualError(t, err, "invalid tx id") - - details, err := getMultiTxDetails(context.Background(), deps.db, int(td.multiTx1.ID)) - require.NoError(t, err) - - require.Equal(t, "", details.ID) - require.Equal(t, int(td.multiTx1.ID), details.MultiTxID) - require.Equal(t, td.multiTx1Tr2.Nonce, details.Nonce) - require.Equal(t, 2, len(details.ChainDetails)) - require.Equal(t, td.multiTx1Tr1.ChainID, common.ChainID(details.ChainDetails[0].ChainID)) - require.Equal(t, td.multiTx1Tr1.BlkNumber, details.ChainDetails[0].BlockNumber) - require.Equal(t, td.multiTx1Tr1.Hash, details.ChainDetails[0].Hash) - require.Equal(t, td.multiTx1Tr1.Contract, *details.ChainDetails[0].Contract) - require.Equal(t, td.multiTx1Tr2.ChainID, common.ChainID(details.ChainDetails[1].ChainID)) - require.Equal(t, td.multiTx1Tr2.BlkNumber, details.ChainDetails[1].BlockNumber) - require.Equal(t, td.multiTx1Tr2.Hash, details.ChainDetails[1].Hash) - require.Equal(t, td.multiTx1Tr2.Contract, *details.ChainDetails[1].Contract) -} - func TestGetActivityEntriesSkipEthGasFeeOnlyTransfers(t *testing.T) { deps, close := setupTestActivityDB(t) defer close() diff --git a/services/wallet/activity/details.go b/services/wallet/activity/details.go deleted file mode 100644 index 88588319371..00000000000 --- a/services/wallet/activity/details.go +++ /dev/null @@ -1,259 +0,0 @@ -package activity - -import ( - "context" - "database/sql" - "encoding/hex" - "errors" - "math/big" - - // used for embedding the sql query in the binary - _ "embed" - - eth "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/types" - "github.com/status-im/status-go/services/wallet/common" - "github.com/status-im/status-go/sqlite" -) - -type ProtocolType = int - -const ( - ProtocolHop ProtocolType = iota + 1 - ProtocolUniswap -) - -type EntryChainDetails struct { - ChainID int64 `json:"chainId"` - BlockNumber int64 `json:"blockNumber"` - Hash eth.Hash `json:"hash"` - Contract *eth.Address `json:"contractAddress,omitempty"` -} - -type EntryDetails struct { - ID string `json:"id"` - MultiTxID int `json:"multiTxId"` - Nonce uint64 `json:"nonce"` - ChainDetails []EntryChainDetails `json:"chainDetails"` - Input string `json:"input"` - ProtocolType *ProtocolType `json:"protocolType,omitempty"` - MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"` - GasLimit uint64 `json:"gasLimit"` - TotalFees *hexutil.Big `json:"totalFees,omitempty"` -} - -//go:embed multiTxDetails.sql -var queryMultiTxDetailsString string - -//go:embed txDetails.sql -var queryTxDetailsString string - -func protocolTypeFromDBType(dbType string) (protocolType *ProtocolType) { - protocolType = new(ProtocolType) - switch common.Type(dbType) { - case common.UniswapV2Swap: - fallthrough - case common.UniswapV3Swap: - *protocolType = ProtocolUniswap - case common.HopBridgeFrom: - fallthrough - case common.HopBridgeTo: - *protocolType = ProtocolHop - default: - return nil - } - return protocolType -} - -func getMultiTxDetails(ctx context.Context, db *sql.DB, multiTxID int) (*EntryDetails, error) { - if multiTxID <= 0 { - return nil, errors.New("invalid tx id") - } - - rows, err := db.QueryContext(ctx, queryMultiTxDetailsString, multiTxID, multiTxID) - if err != nil { - return nil, err - } - defer rows.Close() - - var maxFeePerGas *hexutil.Big - var input string - var protocolType *ProtocolType - var nonce, gasLimit uint64 - var totalFees *hexutil.Big - var chainDetailsList []EntryChainDetails - for rows.Next() { - var contractTypeDB sql.NullString - var chainIDDB, nonceDB, blockNumber sql.NullInt64 - var transferHashDB, contractAddressDB sql.RawBytes - var baseGasFees *string - var baseGasFeesDB sql.NullString - tx := &types.Transaction{} - nullableTx := sqlite.JSONBlob{Data: tx} - err := rows.Scan(&transferHashDB, &blockNumber, &chainIDDB, &contractTypeDB, &nonceDB, &contractAddressDB, &nullableTx, &baseGasFeesDB) - if err != nil { - return nil, err - } - - var chainID int64 - if chainIDDB.Valid { - chainID = chainIDDB.Int64 - } - chainDetails := getChainDetails(chainID, &chainDetailsList) - - if baseGasFeesDB.Valid { - baseGasFees = common.NewAndSet(baseGasFeesDB.String) - } - - if len(transferHashDB) > 0 { - chainDetails.Hash = eth.BytesToHash(transferHashDB) - } - if contractTypeDB.Valid && protocolType == nil { - protocolType = protocolTypeFromDBType(contractTypeDB.String) - } - - if blockNumber.Valid { - chainDetails.BlockNumber = blockNumber.Int64 - } - if nonceDB.Valid { - nonce = uint64(nonceDB.Int64) - } - - if len(contractAddressDB) > 0 && chainDetails.Contract == nil { - chainDetails.Contract = new(eth.Address) - *chainDetails.Contract = eth.BytesToAddress(contractAddressDB) - } - - if nullableTx.Valid { - input = "0x" + hex.EncodeToString(tx.Data()) - maxFeePerGas = (*hexutil.Big)(tx.GasFeeCap()) - gasLimit = tx.Gas() - if baseGasFees != nil { - baseGasFees, _ := new(big.Int).SetString(*baseGasFees, 0) - totalFees = (*hexutil.Big)(getTotalFees(tx, baseGasFees)) - } - } - } - if err = rows.Err(); err != nil { - return nil, err - } - - if maxFeePerGas == nil { - maxFeePerGas = (*hexutil.Big)(big.NewInt(0)) - } - - if len(input) == 0 { - input = "0x" - } - - return &EntryDetails{ - MultiTxID: multiTxID, - Nonce: nonce, - ProtocolType: protocolType, - Input: input, - MaxFeePerGas: maxFeePerGas, - GasLimit: gasLimit, - ChainDetails: chainDetailsList, - TotalFees: totalFees, - }, nil -} - -func getTxDetails(ctx context.Context, db *sql.DB, id string) (*EntryDetails, error) { - if len(id) == 0 { - return nil, errors.New("invalid tx id") - } - rows, err := db.QueryContext(ctx, queryTxDetailsString, eth.HexToHash(id)) - if err != nil { - return nil, err - } - defer rows.Close() - - if !rows.Next() { - return nil, errors.New("Entry not found") - } - - tx := &types.Transaction{} - nullableTx := sqlite.JSONBlob{Data: tx} - var transferHashDB, contractAddressDB sql.RawBytes - var chainIDDB, nonceDB, blockNumberDB sql.NullInt64 - var baseGasFees string - err = rows.Scan(&transferHashDB, &blockNumberDB, &chainIDDB, &nonceDB, &nullableTx, &contractAddressDB, &baseGasFees) - if err != nil { - return nil, err - } - - details := &EntryDetails{ - ID: id, - } - - var chainID int64 - if chainIDDB.Valid { - chainID = chainIDDB.Int64 - } - chainDetails := getChainDetails(chainID, &details.ChainDetails) - - if blockNumberDB.Valid { - chainDetails.BlockNumber = blockNumberDB.Int64 - } - - if nonceDB.Valid { - details.Nonce = uint64(nonceDB.Int64) - } - - if len(transferHashDB) > 0 { - chainDetails.Hash = eth.BytesToHash(transferHashDB) - } - - if len(contractAddressDB) > 0 { - chainDetails.Contract = new(eth.Address) - *chainDetails.Contract = eth.BytesToAddress(contractAddressDB) - } - - if nullableTx.Valid { - details.Input = "0x" + hex.EncodeToString(tx.Data()) - details.MaxFeePerGas = (*hexutil.Big)(tx.GasFeeCap()) - details.GasLimit = tx.Gas() - baseGasFees, _ := new(big.Int).SetString(baseGasFees, 0) - details.TotalFees = (*hexutil.Big)(getTotalFees(tx, baseGasFees)) - } - - return details, nil -} - -func getTotalFees(tx *types.Transaction, baseFee *big.Int) *big.Int { - if tx.Type() == types.DynamicFeeTxType { - // EIP-1559 transaction - if baseFee == nil { - return nil - } - tip := tx.GasTipCap() - maxFee := tx.GasFeeCap() - gasUsed := big.NewInt(int64(tx.Gas())) - - totalGasUsed := new(big.Int).Add(tip, baseFee) - if totalGasUsed.Cmp(maxFee) > 0 { - totalGasUsed.Set(maxFee) - } - - return new(big.Int).Mul(totalGasUsed, gasUsed) - } - - // Legacy transaction - gasPrice := tx.GasPrice() - gasUsed := big.NewInt(int64(tx.Gas())) - - return new(big.Int).Mul(gasPrice, gasUsed) -} - -func getChainDetails(chainID int64, data *[]EntryChainDetails) *EntryChainDetails { - for i, entry := range *data { - if entry.ChainID == chainID { - return &(*data)[i] - } - } - *data = append(*data, EntryChainDetails{ - ChainID: chainID, - }) - return &(*data)[len(*data)-1] -} diff --git a/services/wallet/activity/service.go b/services/wallet/activity/service.go index 4148a5bdc80..7fc79d1d076 100644 --- a/services/wallet/activity/service.go +++ b/services/wallet/activity/service.go @@ -117,38 +117,6 @@ type FilterResponse struct { ErrorCode ErrorCode `json:"errorCode"` } -// FilterActivityAsync allows only one filter task to run at a time -// it cancels the current one if a new one is started -// and should not expect other owners to have data in one of the queried tables -// -// All calls will trigger an EventActivityFilteringDone event with the result of the filtering -// TODO #12120: replace with session based APIs -func (s *Service) FilterActivityAsync(requestID int32, addresses []common.Address, chainIDs []w_common.ChainID, filter Filter, offset int, limit int) { - s.scheduler.Enqueue(requestID, filterTask, func(ctx context.Context) (interface{}, error) { - allAddresses := s.areAllAddresses(addresses) - activities, err := getActivityEntries(ctx, s.getDeps(), addresses, allAddresses, chainIDs, filter, offset, limit) - return activities, err - }, func(result interface{}, taskType async.TaskType, err error) { - res := FilterResponse{ - ErrorCode: ErrorCodeFailed, - } - - if errors.Is(err, context.Canceled) || errors.Is(err, async.ErrTaskOverwritten) { - res.ErrorCode = ErrorCodeTaskCanceled - } else if err == nil { - activities := result.([]Entry) - res.Activities = activities - res.Offset = offset - res.HasMore = len(activities) == limit - res.ErrorCode = ErrorCodeSuccess - } - - sendResponseEvent(s.eventFeed, &requestID, EventActivityFilteringDone, res, err) - - s.getActivityDetailsAsync(requestID, res.Activities) - }) -} - type CollectibleHeader struct { ID thirdparty.CollectibleUniqueID `json:"id"` Name string `json:"name"` @@ -207,14 +175,6 @@ func (s *Service) GetActivityCollectiblesAsync(requestID int32, chainIDs []w_com }) } -func (s *Service) GetMultiTxDetails(ctx context.Context, multiTxID int) (*EntryDetails, error) { - return getMultiTxDetails(ctx, s.db, multiTxID) -} - -func (s *Service) GetTxDetails(ctx context.Context, id string) (*EntryDetails, error) { - return getTxDetails(ctx, s.db, id) -} - // getActivityDetails check if any of the entries have details that are not loaded then fetch and emit result func (s *Service) getActivityDetails(ctx context.Context, entries []Entry) ([]*EntryData, error) { res := make([]*EntryData, 0) diff --git a/services/wallet/activity/service_test.go b/services/wallet/activity/service_test.go index 05d72408661..65d5357526a 100644 --- a/services/wallet/activity/service_test.go +++ b/services/wallet/activity/service_test.go @@ -2,8 +2,6 @@ package activity import ( "context" - "database/sql" - "math/big" "testing" "time" @@ -16,7 +14,6 @@ import ( "github.com/status-im/status-go/multiaccounts/accounts" ethclient "github.com/status-im/status-go/rpc/chain/ethclient" mock_rpcclient "github.com/status-im/status-go/rpc/mock/client" - "github.com/status-im/status-go/services/wallet/bigint" "github.com/status-im/status-go/services/wallet/common" "github.com/status-im/status-go/services/wallet/thirdparty" "github.com/status-im/status-go/services/wallet/token" @@ -102,198 +99,6 @@ func setupTestService(tb testing.TB) (state testState) { return state } -type arg struct { - chainID common.ChainID - tokenAddressStr string - tokenIDStr string - tokenID *big.Int - tokenAddress *eth.Address -} - -// insertStubTransfersWithCollectibles will insert nil if tokenIDStr is empty -func insertStubTransfersWithCollectibles(t *testing.T, db *sql.DB, args []arg) (fromAddresses, toAddresses []eth.Address) { - trs, fromAddresses, toAddresses := transfer.GenerateTestTransfers(t, db, 0, len(args)) - for i := range args { - trs[i].ChainID = args[i].chainID - if args[i].tokenIDStr == "" { - args[i].tokenID = nil - } else { - args[i].tokenID = new(big.Int) - args[i].tokenID.SetString(args[i].tokenIDStr, 0) - } - args[i].tokenAddress = new(eth.Address) - *args[i].tokenAddress = eth.HexToAddress(args[i].tokenAddressStr) - transfer.InsertTestTransferWithOptions(t, db, trs[i].To, &trs[i], &transfer.TestTransferOptions{ - TokenAddress: *args[i].tokenAddress, - TokenID: args[i].tokenID, - }) - } - return fromAddresses, toAddresses -} - -func TestService_UpdateCollectibleInfo(t *testing.T) { - state := setupTestService(t) - defer state.close() - - args := []arg{ - {5, "0xA2838FDA19EB6EED3F8B9EFF411D4CD7D2DE0313", "0x0D", nil, nil}, - {5, "0xA2838FDA19EB6EED3F8B9EFF411D4CD7D2DE0313", "0x762AD3E4934E687F8701F24C7274E5209213FD6208FF952ACEB325D028866949", nil, nil}, - {5, "0xA2838FDA19EB6EED3F8B9EFF411D4CD7D2DE0313", "0x762AD3E4934E687F8701F24C7274E5209213FD6208FF952ACEB325D028866949", nil, nil}, - {5, "0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a", "", nil, nil}, - {5, "0xA2838FDA19EB6EED3F8B9EFF411D4CD7D2DE0313", "0x0F", nil, nil}, - } - fromAddresses, toAddresses := insertStubTransfersWithCollectibles(t, state.service.db, args) - - ch := make(chan walletevent.Event) - sub := state.eventFeed.Subscribe(ch) - - // Expect one call for the fungible token - state.tokenMock.EXPECT().LookupTokenIdentity(uint64(5), eth.HexToAddress("0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a"), false).Return( - &token.Token{ - ChainID: 5, - Address: eth.HexToAddress("0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a"), - Symbol: "STT", - }, - ).Times(1) - state.collectiblesMock.On("FetchAssetsByCollectibleUniqueID", []thirdparty.CollectibleUniqueID{ - { - ContractID: thirdparty.ContractID{ - ChainID: args[4].chainID, - Address: *args[4].tokenAddress}, - TokenID: &bigint.BigInt{Int: args[4].tokenID}, - }, { - ContractID: thirdparty.ContractID{ - ChainID: args[1].chainID, - Address: *args[1].tokenAddress}, - TokenID: &bigint.BigInt{Int: args[1].tokenID}, - }, { - ContractID: thirdparty.ContractID{ - ChainID: args[0].chainID, - Address: *args[0].tokenAddress}, - TokenID: &bigint.BigInt{Int: args[0].tokenID}, - }, - }).Return([]thirdparty.FullCollectibleData{ - { - CollectibleData: thirdparty.CollectibleData{ - ID: thirdparty.CollectibleUniqueID{ - ContractID: thirdparty.ContractID{ - ChainID: args[4].chainID, - Address: *args[4].tokenAddress}, - TokenID: &bigint.BigInt{Int: args[4].tokenID}, - }, - Name: "Test 4", - ImageURL: "test://url/4"}, - CollectionData: nil, - }, { - CollectibleData: thirdparty.CollectibleData{ - ID: thirdparty.CollectibleUniqueID{ - ContractID: thirdparty.ContractID{ - ChainID: args[1].chainID, - Address: *args[1].tokenAddress}, - TokenID: &bigint.BigInt{Int: args[1].tokenID}, - }, - Name: "Test 1", - ImageURL: "test://url/1"}, - CollectionData: nil, - }, - { - CollectibleData: thirdparty.CollectibleData{ - ID: thirdparty.CollectibleUniqueID{ - ContractID: thirdparty.ContractID{ - ChainID: args[0].chainID, - Address: *args[0].tokenAddress}, - TokenID: &bigint.BigInt{Int: args[0].tokenID}, - }, - Name: "Test 0", - ImageURL: "test://url/0"}, - CollectionData: nil, - }, - }, nil).Once() - - state.service.FilterActivityAsync(0, append(fromAddresses, toAddresses...), allNetworksFilter(), Filter{}, 0, 10) - - filterResponseCount := 0 - var updates []EntryData - - for i := 0; i < 2; i++ { - select { - case res := <-ch: - switch res.Type { - case EventActivityFilteringDone: - payload, err := walletevent.GetPayload[FilterResponse](res) - require.NoError(t, err) - require.Equal(t, ErrorCodeSuccess, payload.ErrorCode) - require.Equal(t, 5, len(payload.Activities)) - filterResponseCount++ - case EventActivityFilteringUpdate: - err := walletevent.ExtractPayload(res, &updates) - require.NoError(t, err) - } - case <-time.NewTimer(shouldNotWaitTimeout).C: - require.Fail(t, "timeout while waiting for event") - } - } - - // FetchAssetsByCollectibleUniqueID will receive only unique ids, while number of entries can be bigger - require.Equal(t, 1, filterResponseCount) - require.Equal(t, 4, len(updates)) - require.Equal(t, "Test 4", *updates[0].NftName) - require.Equal(t, "test://url/4", *updates[0].NftURL) - require.Equal(t, "Test 1", *updates[1].NftName) - require.Equal(t, "test://url/1", *updates[1].NftURL) - require.Equal(t, "Test 1", *updates[2].NftName) - require.Equal(t, "test://url/1", *updates[2].NftURL) - require.Equal(t, "Test 0", *updates[3].NftName) - require.Equal(t, "test://url/0", *updates[3].NftURL) - - sub.Unsubscribe() -} - -func TestService_UpdateCollectibleInfo_Error(t *testing.T) { - state := setupTestService(t) - defer state.close() - - args := []arg{ - {5, "0xA2838FDA19EB6EED3F8B9EFF411D4CD7D2DE0313", "0x762AD3E4934E687F8701F24C7274E5209213FD6208FF952ACEB325D028866949", nil, nil}, - {5, "0xA2838FDA19EB6EED3F8B9EFF411D4CD7D2DE0313", "0x0D", nil, nil}, - } - - ch := make(chan walletevent.Event, 4) - sub := state.eventFeed.Subscribe(ch) - - fromAddresses, toAddresses := insertStubTransfersWithCollectibles(t, state.service.db, args) - - state.collectiblesMock.On("FetchAssetsByCollectibleUniqueID", mock.Anything).Return(nil, thirdparty.ErrChainIDNotSupported).Once() - - state.service.FilterActivityAsync(0, append(fromAddresses, toAddresses...), allNetworksFilter(), Filter{}, 0, 5) - - filterResponseCount := 0 - updatesCount := 0 - - for i := 0; i < 2; i++ { - select { - case res := <-ch: - switch res.Type { - case EventActivityFilteringDone: - payload, err := walletevent.GetPayload[FilterResponse](res) - require.NoError(t, err) - require.Equal(t, ErrorCodeSuccess, payload.ErrorCode) - require.Equal(t, 2, len(payload.Activities)) - filterResponseCount++ - case EventActivityFilteringUpdate: - updatesCount++ - } - case <-time.NewTimer(20 * time.Millisecond).C: - // We wait to ensure the EventActivityFilteringUpdate is never sent - } - } - - require.Equal(t, 1, filterResponseCount) - require.Equal(t, 0, updatesCount) - - sub.Unsubscribe() -} - func setupTransactions(t *testing.T, state testState, txCount int, testTxs []transactions.TestTxSummary) (allAddresses []eth.Address, pendings []transactions.PendingTransaction, ch chan walletevent.Event, cleanup func()) { ch = make(chan walletevent.Event, 4) sub := state.eventFeed.Subscribe(ch) diff --git a/services/wallet/activity/session_service.go b/services/wallet/activity/session_service.go index 2d61dcf9616..08be5e2f2e2 100644 --- a/services/wallet/activity/session_service.go +++ b/services/wallet/activity/session_service.go @@ -27,7 +27,6 @@ import ( type Version string const ( - V1 Version = "v1" V2 Version = "v2" ) @@ -61,10 +60,10 @@ type fullFilterParams struct { } func (s *Service) getActivityEntries(ctx context.Context, f fullFilterParams, offset int, count int) ([]Entry, error) { - allAddresses := s.areAllAddresses(f.addresses) - if f.version == V1 { - return getActivityEntries(ctx, s.getDeps(), f.addresses, allAddresses, f.chainIDs, f.filter, offset, count) + if f.version != V2 { + return nil, errors.New("unsupported version") } + allAddresses := s.areAllAddresses(f.addresses) return getActivityEntriesV2(ctx, s.getDeps(), f.addresses, allAddresses, f.chainIDs, f.filter, offset, count) } @@ -364,18 +363,13 @@ func (s *Service) processChangesForSession(session *Session, eventCount int, cha f := session.getFullFilterParams() limit := NoLimit - if session.version == V1 { - limit = len(session.model) + eventCount - } activities, err := s.getActivityEntries(context.Background(), f, 0, limit) if err != nil { logutils.ZapLogger().Error("Error getting activity entries", zap.Error(err)) return } - if session.version != V1 { - s.processEntryDataUpdates(session.id, activities, changedTxs) - } + s.processEntryDataUpdates(session.id, activities, changedTxs) allData := append(session.new, session.model...) new, _ /*removed*/ := findUpdates(allData, activities) diff --git a/services/wallet/activity/session_service_test.go b/services/wallet/activity/session_service_test.go index bc44e9a3649..4530750103e 100644 --- a/services/wallet/activity/session_service_test.go +++ b/services/wallet/activity/session_service_test.go @@ -21,7 +21,7 @@ func TestService_IncrementalUpdateOnTop(t *testing.T) { allAddresses, pendings, ch, cleanup := setupTransactions(t, state, transactionCount, []transactions.TestTxSummary{{DontConfirm: true, Timestamp: transactionCount + 1}}) defer cleanup() - sessionID := state.service.StartFilterSession(allAddresses, allNetworksFilter(), Filter{}, 5, V1) + sessionID := state.service.StartFilterSession(allAddresses, allNetworksFilter(), Filter{}, 5, V2) require.Greater(t, sessionID, SessionID(0)) defer state.service.StopFilterSession(sessionID) @@ -96,7 +96,7 @@ func TestService_IncrementalUpdateMixed(t *testing.T) { ) defer cleanup() - sessionID := state.service.StartFilterSession(allAddresses, allNetworksFilter(), Filter{}, 5, V1) + sessionID := state.service.StartFilterSession(allAddresses, allNetworksFilter(), Filter{}, 5, V2) require.Greater(t, sessionID, SessionID(0)) defer state.service.StopFilterSession(sessionID) @@ -143,7 +143,7 @@ func TestService_IncrementalUpdateFetchWindow(t *testing.T) { allAddresses, pendings, ch, cleanup := setupTransactions(t, state, transactionCount, []transactions.TestTxSummary{{DontConfirm: true, Timestamp: transactionCount + 1}}) defer cleanup() - sessionID := state.service.StartFilterSession(allAddresses, allNetworksFilter(), Filter{}, 2, V1) + sessionID := state.service.StartFilterSession(allAddresses, allNetworksFilter(), Filter{}, 2, V2) require.Greater(t, sessionID, SessionID(0)) defer state.service.StopFilterSession(sessionID) @@ -192,7 +192,7 @@ func TestService_IncrementalUpdateFetchWindowNoReset(t *testing.T) { allAddresses, pendings, ch, cleanup := setupTransactions(t, state, transactionCount, []transactions.TestTxSummary{{DontConfirm: true, Timestamp: transactionCount + 1}}) defer cleanup() - sessionID := state.service.StartFilterSession(allAddresses, allNetworksFilter(), Filter{}, 2, V1) + sessionID := state.service.StartFilterSession(allAddresses, allNetworksFilter(), Filter{}, 2, V2) require.Greater(t, sessionID, SessionID(0)) defer state.service.StopFilterSession(sessionID) @@ -239,7 +239,7 @@ func TestService_FilteredIncrementalUpdateResetAndClear(t *testing.T) { allAddresses = append(append(allAddresses, newFromTrs...), newToTrs...) // 1. User visualizes transactions for the first time - sessionID := state.service.StartFilterSession(allAddresses, allNetworksFilter(), Filter{}, 4, V1) + sessionID := state.service.StartFilterSession(allAddresses, allNetworksFilter(), Filter{}, 4, V2) require.Greater(t, sessionID, SessionID(0)) defer state.service.StopFilterSession(sessionID) diff --git a/services/wallet/api.go b/services/wallet/api.go index 0ee72bd3639..238ed6495c0 100644 --- a/services/wallet/api.go +++ b/services/wallet/api.go @@ -34,7 +34,6 @@ import ( "github.com/status-im/status-go/services/wallet/requests" "github.com/status-im/status-go/services/wallet/router" "github.com/status-im/status-go/services/wallet/router/fees" - "github.com/status-im/status-go/services/wallet/router/pathprocessor" "github.com/status-im/status-go/services/wallet/thirdparty" "github.com/status-im/status-go/services/wallet/token" "github.com/status-im/status-go/services/wallet/transfer" @@ -107,56 +106,6 @@ type DerivedAddress struct { AlreadyCreated bool `json:"alreadyCreated"` } -// @deprecated -func (api *API) CheckRecentHistory(ctx context.Context, addresses []common.Address) error { - return api.s.transferController.CheckRecentHistory([]uint64{api.s.rpcClient.UpstreamChainID}, addresses) -} - -// @deprecated -func (api *API) CheckRecentHistoryForChainIDs(ctx context.Context, chainIDs []uint64, addresses []common.Address) error { - return api.s.transferController.CheckRecentHistory(chainIDs, addresses) -} - -func hexBigToBN(hexBig *hexutil.Big) *big.Int { - var bN *big.Int - if hexBig != nil { - bN = hexBig.ToInt() - } - return bN -} - -// @deprecated -// GetTransfersByAddress returns transfers for a single address -func (api *API) GetTransfersByAddress(ctx context.Context, address common.Address, toBlock, limit *hexutil.Big, fetchMore bool) ([]transfer.View, error) { - logutils.ZapLogger().Debug("[WalletAPI:: GetTransfersByAddress] get transfers for an address", zap.Stringer("address", address)) - var intLimit = int64(1) - if limit != nil { - intLimit = limit.ToInt().Int64() - } - return api.s.transferController.GetTransfersByAddress(ctx, api.s.rpcClient.UpstreamChainID, address, hexBigToBN(toBlock), intLimit, fetchMore) -} - -// @deprecated -// LoadTransferByHash loads transfer to the database -// Only used by status-mobile -func (api *API) LoadTransferByHash(ctx context.Context, address common.Address, hash common.Hash) error { - logutils.ZapLogger().Debug("[WalletAPI:: LoadTransferByHash] get transfer by hash", zap.Stringer("address", address), zap.Stringer("hash", hash)) - return api.s.transferController.LoadTransferByHash(ctx, api.s.rpcClient, address, hash) -} - -// @deprecated -func (api *API) GetTransfersByAddressAndChainID(ctx context.Context, chainID uint64, address common.Address, toBlock, limit *hexutil.Big, fetchMore bool) ([]transfer.View, error) { - logutils.ZapLogger().Debug("[WalletAPI:: GetTransfersByAddressAndChainIDs] get transfers for an address", zap.Stringer("address", address)) - return api.s.transferController.GetTransfersByAddress(ctx, chainID, address, hexBigToBN(toBlock), limit.ToInt().Int64(), fetchMore) -} - -// @deprecated -func (api *API) GetTransfersForIdentities(ctx context.Context, identities []transfer.TransactionIdentity) ([]transfer.View, error) { - logutils.ZapLogger().Debug("wallet.api.GetTransfersForIdentities", zap.Int("identities.len", len(identities))) - - return api.s.transferController.GetTransfersForIdentities(ctx, identities) -} - func (api *API) FetchDecodedTxData(ctx context.Context, data string) (*thirdparty.DataParsed, error) { logutils.ZapLogger().Debug("[Wallet: FetchDecodedTxData]") @@ -269,24 +218,6 @@ func (api *API) GetPendingTransactions(ctx context.Context) ([]*transactions.Pen return rst, err } -// @deprecated -// Not used by status-desktop anymore -func (api *API) GetPendingTransactionsForIdentities(ctx context.Context, identities []transfer.TransactionIdentity) ( - result []*transactions.PendingTransaction, err error) { - - logutils.ZapLogger().Debug("wallet.api.GetPendingTransactionsForIdentities") - - result = make([]*transactions.PendingTransaction, 0, len(identities)) - var pt *transactions.PendingTransaction - for _, identity := range identities { - pt, err = api.s.pendingTxManager.GetPendingEntry(identity.ChainID, identity.Hash) - result = append(result, pt) - } - - logutils.ZapLogger().Debug("wallet.api.GetPendingTransactionsForIdentities RES", zap.Int("len", len(result))) - return -} - // @deprecated // TODO - #11861: Remove this and replace with EventPendingTransactionStatusChanged event and Delete to confirm the transaction where it is needed func (api *API) WatchTransactionByChainID(ctx context.Context, chainID uint64, transactionHash common.Hash) (err error) { @@ -690,45 +621,6 @@ func (api *API) SendTransactionWithSignature(ctx context.Context, chainID uint64 return api.s.transactionManager.SendTransactionWithSignature(chainID, params, sig) } -// Deprecated: `CreateMultiTransaction` is the old way of sending transactions and should not be used anymore. -// -// The flow that should be used instead: -// - call `BuildTransactionsFromRoute` -// - wait for the `wallet.router.sign-transactions` signal -// - sign received hashes using `SignMessage` call or sign on keycard -// - call `SendRouterTransactionsWithSignatures` with the signatures of signed hashes from the previous step -// -// TODO: remove this struct once mobile switches to the new approach -func (api *API) CreateMultiTransaction(ctx context.Context, multiTransactionCommand *transfer.MultiTransactionCommand, data []*pathprocessor.MultipathProcessorTxArgs, password string) (*transfer.MultiTransactionCommandResult, error) { - logutils.ZapLogger().Debug("[WalletAPI:: CreateMultiTransaction] create multi transaction") - - cmd, err := api.s.transactionManager.CreateMultiTransactionFromCommand(multiTransactionCommand, data) - if err != nil { - return nil, err - } - - if password != "" { - selectedAccount, err := api.getVerifiedWalletAccount(multiTransactionCommand.FromAddress.Hex(), password) - if err != nil { - return nil, err - } - - cmdRes, err := api.s.transactionManager.SendTransactions(ctx, cmd, data, api.s.router.GetPathProcessors(), selectedAccount) - if err != nil { - return nil, err - } - - _, err = api.s.transactionManager.InsertMultiTransaction(cmd) - if err != nil { - logutils.ZapLogger().Error("Failed to save multi transaction", zap.Error(err)) // not critical - } - - return cmdRes, nil - } - - return nil, api.s.transactionManager.SendTransactionForSigningToKeycard(ctx, cmd, data, api.s.router.GetPathProcessors()) -} - func (api *API) BuildTransactionsFromRoute(ctx context.Context, buildInputParams *requests.RouterBuildTransactionsParams) { logutils.ZapLogger().Debug("[WalletAPI::BuildTransactionsFromRoute] builds transactions from the generated best route", zap.String("uuid", buildInputParams.Uuid)) api.s.routeExecutionManager.BuildTransactionsFromRoute(ctx, buildInputParams) @@ -768,38 +660,6 @@ func (api *API) FetchAllCurrencyFormats() (currency.FormatPerSymbol, error) { return api.s.currency.FetchAllCurrencyFormats() } -// @deprecated replaced by session APIs; see #12120 -func (api *API) FilterActivityAsync(requestID int32, addresses []common.Address, chainIDs []wcommon.ChainID, filter activity.Filter, offset int, limit int) error { - logutils.ZapLogger().Debug("wallet.api.FilterActivityAsync", - zap.Int32("requestID", requestID), - zap.Int("addr.count", len(addresses)), - zap.Int("chainIDs.count", len(chainIDs)), - zap.Int("offset", offset), - zap.Int("limit", limit), - ) - - api.s.activity.FilterActivityAsync(requestID, addresses, chainIDs, filter, offset, limit) - return nil -} - -// @deprecated replaced by session APIs; see #12120 -func (api *API) CancelActivityFilterTask(requestID int32) error { - logutils.ZapLogger().Debug("wallet.api.CancelActivityFilterTask", zap.Int32("requestID", requestID)) - - api.s.activity.CancelFilterTask(requestID) - return nil -} - -func (api *API) StartActivityFilterSession(addresses []common.Address, chainIDs []wcommon.ChainID, filter activity.Filter, firstPageCount int) (activity.SessionID, error) { - logutils.ZapLogger().Debug("wallet.api.StartActivityFilterSession", - zap.Int("addr.count", len(addresses)), - zap.Int("chainIDs.count", len(chainIDs)), - zap.Int("firstPageCount", firstPageCount), - ) - - return api.s.activity.StartFilterSession(addresses, chainIDs, filter, firstPageCount, activity.V1), nil -} - func (api *API) StartActivityFilterSessionV2(addresses []common.Address, chainIDs []wcommon.ChainID, filter activity.Filter, firstPageCount int) (activity.SessionID, error) { logutils.ZapLogger().Debug("wallet.api.StartActivityFilterSessionV2", zap.Int("addr.count", len(addresses)), @@ -843,18 +703,6 @@ func (api *API) StopActivityFilterSession(id activity.SessionID) { api.s.activity.StopFilterSession(id) } -func (api *API) GetMultiTxDetails(ctx context.Context, multiTxID int) (*activity.EntryDetails, error) { - logutils.ZapLogger().Debug("wallet.api.GetMultiTxDetails", zap.Int("multiTxID", multiTxID)) - - return api.s.activity.GetMultiTxDetails(ctx, multiTxID) -} - -func (api *API) GetTxDetails(ctx context.Context, id string) (*activity.EntryDetails, error) { - logutils.ZapLogger().Debug("wallet.api.GetTxDetails", zap.String("id", id)) - - return api.s.activity.GetTxDetails(ctx, id) -} - func (api *API) GetRecipientsAsync(requestID int32, chainIDs []wcommon.ChainID, addresses []common.Address, offset int, limit int) (ignored bool, err error) { logutils.ZapLogger().Debug("wallet.api.GetRecipientsAsync", zap.Int("addresses.len", len(addresses)), diff --git a/services/wallet/routeexecution/manager.go b/services/wallet/routeexecution/manager.go index fab5684c1b5..32f4c2677b6 100644 --- a/services/wallet/routeexecution/manager.go +++ b/services/wallet/routeexecution/manager.go @@ -9,12 +9,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/event" - "github.com/ethereum/go-ethereum/log" - - "github.com/status-im/status-go/logutils" status_common "github.com/status-im/status-go/common" statusErrors "github.com/status-im/status-go/errors" + "github.com/status-im/status-go/logutils" "github.com/status-im/status-go/services/wallet/requests" "github.com/status-im/status-go/services/wallet/responses" "github.com/status-im/status-go/services/wallet/routeexecution/storage" @@ -196,7 +194,7 @@ func (m *Manager) SendRouterTransactionsWithSignatures(ctx context.Context, send response.SentTransactions, err = m.transactionManager.SendRouterTransactions(ctx, multiTx) if err != nil { - log.Error("Error sending router transactions", "error", err) + logutils.ZapLogger().Error("Error sending router transactions", zap.Error(err)) // TODO #16556: Handle partially successful Tx sends? // Don't return, store whichever transactions were successfully sent } @@ -207,28 +205,7 @@ func (m *Manager) SendRouterTransactionsWithSignatures(ctx context.Context, send routeData := wallettypes.NewRouteData(&routeInputParams, m.buildInputParams, routerTransactions) tmpErr = m.db.PutRouteData(routeData) if tmpErr != nil { - log.Error("Error storing route data", "error", tmpErr) - } - - var ( - chainIDs []uint64 - addresses []common.Address - ) - for _, tx := range response.SentTransactions { - chainIDs = append(chainIDs, tx.FromChain) - addresses = append(addresses, common.Address(tx.FromAddress)) - go func(chainId uint64, txHash common.Hash) { - defer status_common.LogOnPanic() - tmpErr = m.transactionManager.WatchTransaction(context.Background(), chainId, txHash) - if tmpErr != nil { - logutils.ZapLogger().Error("Error watching transaction", zap.Error(tmpErr)) - return - } - }(tx.FromChain, common.Hash(tx.Hash)) - } - tmpErr = m.transferController.CheckRecentHistory(chainIDs, addresses) - if tmpErr != nil { - logutils.ZapLogger().Error("Error checking recent history", zap.Error(tmpErr)) + logutils.ZapLogger().Error("Error storing route data", zap.Error(tmpErr)) } }() } diff --git a/services/wallet/transfer/block_dao.go b/services/wallet/transfer/block_dao.go index 3c21746de21..692808b576e 100644 --- a/services/wallet/transfer/block_dao.go +++ b/services/wallet/transfer/block_dao.go @@ -22,97 +22,10 @@ type Block struct { Nonce *int64 } -type BlockView struct { - Address common.Address `json:"address"` - Number *big.Int `json:"blockNumber"` - Balance bigint.BigInt `json:"balance"` - Nonce *int64 `json:"nonce"` -} - -func blocksToViews(blocks map[common.Address]*Block) []BlockView { - blocksViews := []BlockView{} - for address, block := range blocks { - view := BlockView{ - Address: address, - Number: block.Number, - Balance: bigint.BigInt{Int: block.Balance}, - Nonce: block.Nonce, - } - blocksViews = append(blocksViews, view) - } - - return blocksViews -} - type BlockDAO struct { db *sql.DB } -// MergeBlocksRanges merge old blocks ranges if possible -func (b *BlockDAO) mergeBlocksRanges(chainIDs []uint64, accounts []common.Address) error { - for _, chainID := range chainIDs { - for _, account := range accounts { - err := b.mergeRanges(chainID, account) - if err != nil { - return err - } - } - } - return nil -} - -func (b *BlockDAO) mergeRanges(chainID uint64, account common.Address) (err error) { - var ( - tx *sql.Tx - ) - - ranges, err := b.getOldRanges(chainID, account) - if err != nil { - return err - } - - logutils.ZapLogger().Info("merge old ranges", - zap.Stringer("account", account), - zap.Uint64("network", chainID), - zap.Int("ranges", len(ranges)), - ) - - if len(ranges) <= 1 { - return nil - } - - tx, err = b.db.Begin() - if err != nil { - return err - } - - defer func() { - if err == nil { - err = tx.Commit() - return - } - _ = tx.Rollback() - }() - - newRanges, deletedRanges := getNewRanges(ranges) - - for _, rangeToDelete := range deletedRanges { - err = deleteRange(chainID, tx, account, rangeToDelete.from, rangeToDelete.to) - if err != nil { - return err - } - } - - for _, newRange := range newRanges { - err = insertRange(chainID, tx, account, newRange.from, newRange.to) - if err != nil { - return err - } - } - - return nil -} - func (b *BlockDAO) insertRange(chainID uint64, account common.Address, from, to, balance *big.Int, nonce uint64) error { logutils.ZapLogger().Debug( "insert blocks range", @@ -131,35 +44,6 @@ func (b *BlockDAO) insertRange(chainID uint64, account common.Address, from, to, return err } -func (b *BlockDAO) getOldRanges(chainID uint64, account common.Address) ([]*BlocksRange, error) { - query := `select blk_from, blk_to from blocks_ranges - where address = ? - and network_id = ? - order by blk_from` - - rows, err := b.db.Query(query, account, chainID) - if err != nil { - return nil, err - } - defer rows.Close() - ranges := []*BlocksRange{} - for rows.Next() { - from := &big.Int{} - to := &big.Int{} - err = rows.Scan((*bigint.SQLBigInt)(from), (*bigint.SQLBigInt)(to)) - if err != nil { - return nil, err - } - - ranges = append(ranges, &BlocksRange{ - from: from, - to: to, - }) - } - - return ranges, nil -} - // GetBlocksToLoadByAddress gets unloaded blocks for a given address. func (b *BlockDAO) GetBlocksToLoadByAddress(chainID uint64, address common.Address, limit int) (rst []*big.Int, err error) { query := `SELECT blk_number FROM blocks @@ -205,56 +89,6 @@ func (b *BlockDAO) GetLastBlockByAddress(chainID uint64, address common.Address, return nil, nil } -func (b *BlockDAO) GetFirstSavedBlock(chainID uint64, address common.Address) (rst *DBHeader, err error) { - query := `SELECT blk_number, blk_hash, loaded - FROM blocks - WHERE network_id = ? AND address = ? - ORDER BY blk_number LIMIT 1` - rows, err := b.db.Query(query, chainID, address) - if err != nil { - return - } - defer rows.Close() - - if rows.Next() { - header := &DBHeader{Hash: common.Hash{}, Number: new(big.Int)} - err = rows.Scan((*bigint.SQLBigInt)(header.Number), &header.Hash, &header.Loaded) - if err != nil { - return nil, err - } - - return header, nil - } - - return nil, nil -} - -func (b *BlockDAO) GetFirstKnownBlock(chainID uint64, address common.Address) (rst *big.Int, err error) { - query := `SELECT blk_from FROM blocks_ranges - WHERE address = ? - AND network_id = ? - ORDER BY blk_from - LIMIT 1` - - rows, err := b.db.Query(query, address, chainID) - if err != nil { - return - } - defer rows.Close() - - if rows.Next() { - block := &big.Int{} - err = rows.Scan((*bigint.SQLBigInt)(block)) - if err != nil { - return nil, err - } - - return block, nil - } - - return nil, nil -} - func (b *BlockDAO) GetLastKnownBlockByAddress(chainID uint64, address common.Address) (block *Block, err error) { query := `SELECT blk_to, balance, nonce FROM blocks_ranges WHERE address = ? @@ -285,43 +119,6 @@ func (b *BlockDAO) GetLastKnownBlockByAddress(chainID uint64, address common.Add return nil, nil } -func (b *BlockDAO) getLastKnownBlocks(chainID uint64, addresses []common.Address) (map[common.Address]*Block, error) { - result := map[common.Address]*Block{} - for _, address := range addresses { - block, error := b.GetLastKnownBlockByAddress(chainID, address) - if error != nil { - return nil, error - } - - if block != nil { - result[address] = block - } - } - - return result, nil -} - -// TODO Remove the method below, it is used in one place and duplicates getLastKnownBlocks method with slight unneeded change -func (b *BlockDAO) GetLastKnownBlockByAddresses(chainID uint64, addresses []common.Address) (map[common.Address]*Block, []common.Address, error) { - res := map[common.Address]*Block{} - accountsWithoutHistory := []common.Address{} - for _, address := range addresses { - block, err := b.GetLastKnownBlockByAddress(chainID, address) - if err != nil { - logutils.ZapLogger().Info("Can't get last block", zap.Error(err)) - return nil, nil, err - } - - if block != nil { - res[address] = block - } else { - accountsWithoutHistory = append(accountsWithoutHistory, address) - } - } - - return res, accountsWithoutHistory, nil -} - func getNewRanges(ranges []*BlocksRange) ([]*BlocksRange, []*BlocksRange) { initValue := big.NewInt(-1) prevFrom := big.NewInt(-1) @@ -369,27 +166,6 @@ func getNewRanges(ranges []*BlocksRange) ([]*BlocksRange, []*BlocksRange) { return newRanges, deletedRanges } -func deleteRange(chainID uint64, creator statementCreator, account common.Address, from *big.Int, to *big.Int) error { - logutils.ZapLogger().Info("delete blocks range", - zap.Stringer("account", account), - zap.Uint64("network", chainID), - zap.Stringer("from", from), - zap.Stringer("to", to), - ) - delete, err := creator.Prepare(`DELETE FROM blocks_ranges - WHERE address = ? - AND network_id = ? - AND blk_from = ? - AND blk_to = ?`) - if err != nil { - logutils.ZapLogger().Info("some error", zap.Error(err)) - return err - } - - _, err = delete.Exec(account, chainID, (*bigint.SQLBigInt)(from), (*bigint.SQLBigInt)(to)) - return err -} - func deleteAllRanges(creator statementCreator, account common.Address) error { delete, err := creator.Prepare(`DELETE FROM blocks_ranges WHERE address = ?`) if err != nil { @@ -399,19 +175,3 @@ func deleteAllRanges(creator statementCreator, account common.Address) error { _, err = delete.Exec(account) return err } - -func insertRange(chainID uint64, creator statementCreator, account common.Address, from *big.Int, to *big.Int) error { - logutils.ZapLogger().Info("insert blocks range", - zap.Stringer("account", account), - zap.Uint64("network", chainID), - zap.Stringer("from", from), - zap.Stringer("to", to), - ) - insert, err := creator.Prepare("INSERT INTO blocks_ranges (network_id, address, blk_from, blk_to) VALUES (?, ?, ?, ?)") - if err != nil { - return err - } - - _, err = insert.Exec(chainID, account, (*bigint.SQLBigInt)(from), (*bigint.SQLBigInt)(to)) - return err -} diff --git a/services/wallet/transfer/commands_sequential.go b/services/wallet/transfer/commands_sequential.go index 19961aa74a8..c6b128e0a44 100644 --- a/services/wallet/transfer/commands_sequential.go +++ b/services/wallet/transfer/commands_sequential.go @@ -1484,7 +1484,7 @@ func (c *loadBlocksAndTransfersCommand) areAllTransfersLoaded(account common.Add if allBlocksLoaded { headers, err := c.blockDAO.GetBlocksToLoadByAddress(c.chainClient.NetworkID(), account, 1) if err != nil { - logutils.ZapLogger().Error("loadBlocksAndTransfersCommand GetFirstSavedBlock", zap.Error(err)) + logutils.ZapLogger().Error("loadBlocksAndTransfersCommand GetBlocksToLoadByAddress", zap.Error(err)) return false, err } diff --git a/services/wallet/transfer/controller.go b/services/wallet/transfer/controller.go index f07f16706a2..4041ea178cd 100644 --- a/services/wallet/transfer/controller.go +++ b/services/wallet/transfer/controller.go @@ -1,16 +1,12 @@ package transfer import ( - "context" "database/sql" - "fmt" - "math/big" "go.uber.org/zap" "golang.org/x/exp/slices" // since 1.21, this is in the standard library "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/event" gocommon "github.com/status-im/status-go/common" "github.com/status-im/status-go/logutils" @@ -80,64 +76,6 @@ func (c *Controller) Stop() { } } -func sameChains(chainIDs1 []uint64, chainIDs2 []uint64) bool { - if len(chainIDs1) != len(chainIDs2) { - return false - } - - for _, chainID := range chainIDs1 { - if !slices.Contains(chainIDs2, chainID) { - return false - } - } - - return true -} - -func (c *Controller) CheckRecentHistory(chainIDs []uint64, accounts []common.Address) error { - if len(accounts) == 0 { - return nil - } - - if len(chainIDs) == 0 { - return nil - } - - err := c.blockDAO.mergeBlocksRanges(chainIDs, accounts) - if err != nil { - return err - } - - chainClients, err := c.rpcClient.EthClients(chainIDs) - if err != nil { - return err - } - - if c.reactor != nil { - if !sameChains(chainIDs, c.reactor.chainIDs) { - err := c.reactor.restart(chainClients, accounts) - if err != nil { - return err - } - } - - return nil - } - - const omitHistory = true - c.reactor = NewReactor(c.db, c.blockDAO, c.blockRangesSeqDAO, c.accountsDB, c.TransferFeed, c.transactionManager, - c.pendingTxManager, c.tokenManager, c.balanceCacher, omitHistory, c.blockChainState) - - err = c.reactor.start(chainClients, accounts) - if err != nil { - return err - } - - c.startAccountWatcher(chainIDs) - - return nil -} - func (c *Controller) startAccountWatcher(chainIDs []uint64) { if c.accWatcher == nil { c.accWatcher = accountsevent.NewWatcher(c.accountsDB, c.accountFeed, func(changedAddresses []common.Address, eventType accountsevent.EventType, currentAddresses []common.Address) { @@ -174,76 +112,6 @@ func (c *Controller) onAccountsChanged(changedAddresses []common.Address, eventT } } -// Only used by status-mobile -func (c *Controller) LoadTransferByHash(ctx context.Context, rpcClient *rpc.Client, address common.Address, hash common.Hash) error { - chainClient, err := rpcClient.EthClient(rpcClient.UpstreamChainID) - if err != nil { - return err - } - - signer := types.LatestSignerForChainID(chainClient.ToBigInt()) - - transfer, err := getTransferByHash(ctx, chainClient, signer, address, hash) - if err != nil { - return err - } - - transfers := []Transfer{*transfer} - - err = c.db.InsertBlock(rpcClient.UpstreamChainID, address, transfer.BlockNumber, transfer.BlockHash) - if err != nil { - return err - } - - tx, err := c.db.client.BeginTx(ctx, nil) - if err != nil { - return err - } - - blocks := []*big.Int{transfer.BlockNumber} - err = saveTransfersMarkBlocksLoaded(tx, rpcClient.UpstreamChainID, address, transfers, blocks) - if err != nil { - rollErr := tx.Rollback() - if rollErr != nil { - return fmt.Errorf("failed to rollback transaction due to error: %v", err) - } - return err - } - - return nil -} - -func (c *Controller) GetTransfersByAddress(ctx context.Context, chainID uint64, address common.Address, toBlock *big.Int, - limit int64, fetchMore bool) ([]View, error) { - - rst, err := c.reactor.getTransfersByAddress(ctx, chainID, address, toBlock, limit) - if err != nil { - logutils.ZapLogger().Error("[WalletAPI:: GetTransfersByAddress] can't fetch transfers", zap.Error(err)) - return nil, err - } - - return castToTransferViews(rst), nil -} - -func (c *Controller) GetTransfersForIdentities(ctx context.Context, identities []TransactionIdentity) ([]View, error) { - rst, err := c.db.GetTransfersForIdentities(ctx, identities) - if err != nil { - logutils.ZapLogger().Error("[transfer.Controller.GetTransfersForIdentities] DB err", zap.Error(err)) - return nil, err - } - - return castToTransferViews(rst), nil -} - -func (c *Controller) GetCachedBalances(ctx context.Context, chainID uint64, addresses []common.Address) ([]BlockView, error) { - result, error := c.blockDAO.getLastKnownBlocks(chainID, addresses) - if error != nil { - return nil, error - } - - return blocksToViews(result), nil -} - func (c *Controller) cleanUpRemovedAccount(address common.Address) { // Transfers will be deleted by foreign key constraint by cascade err := deleteBlocks(c.db.client, address) diff --git a/services/wallet/transfer/database.go b/services/wallet/transfer/database.go index e6518e3b235..455038fa9d5 100644 --- a/services/wallet/transfer/database.go +++ b/services/wallet/transfer/database.go @@ -228,49 +228,6 @@ type statementCreator interface { Prepare(query string) (*sql.Stmt, error) } -// Only used by status-mobile -func (db *Database) InsertBlock(chainID uint64, account common.Address, blockNumber *big.Int, blockHash common.Hash) error { - var ( - tx *sql.Tx - ) - tx, err := db.client.Begin() - if err != nil { - return err - } - defer func() { - if err == nil { - err = tx.Commit() - return - } - _ = tx.Rollback() - }() - - blockDB := blockDBFields{ - chainID: chainID, - account: account, - blockNumber: blockNumber, - blockHash: blockHash, - } - return insertBlockDBFields(tx, blockDB) -} - -type blockDBFields struct { - chainID uint64 - account common.Address - blockNumber *big.Int - blockHash common.Hash -} - -func insertBlockDBFields(creator statementCreator, block blockDBFields) error { - insert, err := creator.Prepare("INSERT OR IGNORE INTO blocks(network_id, address, blk_number, blk_hash, loaded) VALUES (?, ?, ?, ?, ?)") - if err != nil { - return err - } - - _, err = insert.Exec(block.chainID, block.account, (*bigint.SQLBigInt)(block.blockNumber), block.blockHash, true) - return err -} - func insertBlocksWithTransactions(chainID uint64, creator statementCreator, headers []*DBHeader) error { insert, err := creator.Prepare("INSERT OR IGNORE INTO blocks(network_id, address, blk_number, blk_hash, loaded) VALUES (?, ?, ?, ?, ?)") if err != nil { diff --git a/services/wallet/transfer/downloader.go b/services/wallet/transfer/downloader.go index 71fd37dc11c..8bc8756c974 100644 --- a/services/wallet/transfer/downloader.go +++ b/services/wallet/transfer/downloader.go @@ -89,49 +89,6 @@ func (d *ETHDownloader) GetTransfersByNumber(ctx context.Context, number *big.In return rst, err } -// Only used by status-mobile -func getTransferByHash(ctx context.Context, client chain.ClientInterface, signer types.Signer, address common.Address, hash common.Hash) (*Transfer, error) { - transaction, _, err := client.TransactionByHash(ctx, hash) - if err != nil { - return nil, err - } - - receipt, err := client.TransactionReceipt(ctx, hash) - if err != nil { - return nil, err - } - - eventType, transactionLog := w_common.GetFirstEvent(receipt.Logs) - transactionType := w_common.EventTypeToSubtransactionType(eventType) - - from, err := types.Sender(signer, transaction) - - if err != nil { - return nil, err - } - - baseGasFee, err := client.GetBaseFeeFromBlock(ctx, big.NewInt(int64(transactionLog.BlockNumber))) - if err != nil { - return nil, err - } - - transfer := &Transfer{ - Type: transactionType, - ID: hash, - Address: address, - BlockNumber: receipt.BlockNumber, - BlockHash: receipt.BlockHash, - Timestamp: uint64(time.Now().Unix()), - Transaction: transaction, - From: from, - Receipt: receipt, - Log: transactionLog, - BaseGasFees: baseGasFee, - } - - return transfer, nil -} - func (d *ETHDownloader) getTransfersInBlock(ctx context.Context, blk *types.Block, accounts []common.Address) ([]Transfer, error) { startTs := time.Now() diff --git a/services/wallet/transfer/helpers.go b/services/wallet/transfer/helpers.go index 96c2c7d5e84..5991cdecd7d 100644 --- a/services/wallet/transfer/helpers.go +++ b/services/wallet/transfer/helpers.go @@ -104,30 +104,6 @@ func addSignaturesToTransactions(transactions map[common.Hash]*TransactionDescri return nil } -func multiTransactionFromCommand(command *MultiTransactionCommand) *MultiTransaction { - toAmount := new(hexutil.Big) - if command.ToAmount != nil { - toAmount = command.ToAmount - } - multiTransaction := NewMultiTransaction( - /* Timestamp: */ uint64(time.Now().Unix()), - /* FromNetworkID: */ 0, - /* ToNetworkID: */ 0, - /* FromTxHash: */ common.Hash{}, - /* ToTxHash: */ common.Hash{}, - /* FromAddress: */ command.FromAddress, - /* ToAddress: */ command.ToAddress, - /* FromAsset: */ command.FromAsset, - /* ToAsset: */ command.ToAsset, - /* FromAmount: */ command.FromAmount, - /* ToAmount: */ toAmount, - /* Type: */ command.Type, - /* CrossTxID: */ "", - ) - - return multiTransaction -} - func updateDataFromMultiTx(data []*pathprocessor.MultipathProcessorTxArgs, multiTransaction *MultiTransaction) { for _, tx := range data { if tx.TransferTx != nil { diff --git a/services/wallet/transfer/reactor.go b/services/wallet/transfer/reactor.go index f058df0cfef..70102f7255b 100644 --- a/services/wallet/transfer/reactor.go +++ b/services/wallet/transfer/reactor.go @@ -121,13 +121,3 @@ func (r *Reactor) createFetchStrategy(chainClients map[uint64]chain.ClientInterf r.blockChainState, ) } - -func (r *Reactor) getTransfersByAddress(ctx context.Context, chainID uint64, address common.Address, toBlock *big.Int, - limit int64) ([]Transfer, error) { - - if r.strategy != nil { - return r.strategy.getTransfersByAddress(ctx, chainID, address, toBlock, limit) - } - - return nil, errors.New(ReactorNotStarted) -} diff --git a/services/wallet/transfer/testutils.go b/services/wallet/transfer/testutils.go index 06b5916c5f9..b4a308ba503 100644 --- a/services/wallet/transfer/testutils.go +++ b/services/wallet/transfer/testutils.go @@ -326,17 +326,6 @@ func InsertTestTransferWithOptions(tb testing.TB, db *sql.DB, address eth_common blkHash := eth_common.HexToHash("4") - block := blockDBFields{ - chainID: uint64(tr.ChainID), - account: address, - blockNumber: big.NewInt(tr.BlkNumber), - blockHash: blkHash, - } - - // Respect `FOREIGN KEY(network_id,address,blk_hash)` of `transfers` table - err = insertBlockDBFields(tx, block) - require.NoError(tb, err) - receiptStatus := uint64(0) if tr.Success { receiptStatus = 1 diff --git a/services/wallet/transfer/transaction_manager_multitransaction.go b/services/wallet/transfer/transaction_manager_multitransaction.go index 35b3ac900e7..5157604ea12 100644 --- a/services/wallet/transfer/transaction_manager_multitransaction.go +++ b/services/wallet/transfer/transaction_manager_multitransaction.go @@ -36,33 +36,6 @@ func (tm *TransactionManager) UpdateMultiTransaction(multiTransaction *MultiTran return tm.storage.UpdateMultiTransaction(multiTransaction) } -func (tm *TransactionManager) CreateMultiTransactionFromCommand(command *MultiTransactionCommand, - data []*pathprocessor.MultipathProcessorTxArgs) (*MultiTransaction, error) { - - multiTransaction := multiTransactionFromCommand(command) - - // Extract network from args - switch multiTransaction.Type { - case MultiTransactionSend, MultiTransactionApprove, MultiTransactionSwap: - if multiTransaction.FromNetworkID == wallet_common.UnknownChainID && len(data) == 1 { - multiTransaction.FromNetworkID = data[0].ChainID - } - case MultiTransactionBridge: - if len(data) == 1 && data[0].HopTx != nil { - if multiTransaction.FromNetworkID == wallet_common.UnknownChainID { - multiTransaction.FromNetworkID = data[0].HopTx.ChainID - } - if multiTransaction.ToNetworkID == wallet_common.UnknownChainID { - multiTransaction.ToNetworkID = data[0].HopTx.ChainIDTo - } - } - default: - return nil, fmt.Errorf("unsupported multi transaction type: %v", multiTransaction.Type) - } - - return multiTransaction, nil -} - func (tm *TransactionManager) SendTransactionForSigningToKeycard(ctx context.Context, multiTransaction *MultiTransaction, data []*pathprocessor.MultipathProcessorTxArgs, pathProcessors map[string]pathprocessor.PathProcessor) error { acc, err := tm.accountsDB.GetAccountByAddress(types.Address(multiTransaction.FromAddress)) if err != nil { diff --git a/services/wallet/transfer/transaction_manager_multitransaction_test.go b/services/wallet/transfer/transaction_manager_multitransaction_test.go index 72d365529eb..08d0e7076fe 100644 --- a/services/wallet/transfer/transaction_manager_multitransaction_test.go +++ b/services/wallet/transfer/transaction_manager_multitransaction_test.go @@ -313,55 +313,3 @@ func TestWatchTransaction_Timeout(t *testing.T) { err = tm.WatchTransaction(ctx, chainID, transactionHash) require.ErrorIs(t, err, ErrWatchPendingTxTimeout) } - -func TestCreateMultiTransactionFromCommand(t *testing.T) { - tm, _, _ := setupTransactionManager(t) - - var command *MultiTransactionCommand - - // Test types that should get chainID from the data - mtTypes := []MultiTransactionType{MultiTransactionSend, MultiTransactionApprove, MultiTransactionSwap, MultiTransactionBridge, MultiTransactionType(7)} - - for _, mtType := range mtTypes { - fromAmount := hexutil.Big(*big.NewInt(1000000000000000000)) - toAmount := hexutil.Big(*big.NewInt(123)) - command = &MultiTransactionCommand{ - Type: mtType, - FromAddress: common.HexToAddress("0x1234567890abcdef1234567890abcdef12345678"), - ToAddress: common.HexToAddress("0xabcdef1234567890abcdef1234567890abcdef12"), - FromAsset: "DAI", - ToAsset: "USDT", - FromAmount: &fromAmount, - ToAmount: &toAmount, - } - - data := make([]*pathprocessor.MultipathProcessorTxArgs, 0) - data = append(data, &pathprocessor.MultipathProcessorTxArgs{ - ChainID: 1, - }) - - if mtType == MultiTransactionBridge { - data[0].HopTx = &pathprocessor.HopBridgeTxArgs{ - ChainID: 1, - ChainIDTo: 2, - } - } - - multiTransaction, err := tm.CreateMultiTransactionFromCommand(command, data) - if mtType > MultiTransactionApprove { - // Unsupported type - require.Error(t, err) - break - } - require.NoError(t, err) - require.NotNil(t, multiTransaction) - require.Equal(t, command.FromAddress, multiTransaction.FromAddress) - require.Equal(t, command.ToAddress, multiTransaction.ToAddress) - require.Equal(t, command.FromAsset, multiTransaction.FromAsset) - require.Equal(t, command.ToAsset, multiTransaction.ToAsset) - require.Equal(t, command.FromAmount, multiTransaction.FromAmount) - require.Equal(t, command.ToAmount, multiTransaction.ToAmount) - require.Equal(t, command.Type, multiTransaction.Type) - require.Equal(t, data[0].ChainID, multiTransaction.FromNetworkID) - } -} diff --git a/services/wallet/transfer/view.go b/services/wallet/transfer/view.go deleted file mode 100644 index f6419b5b7cd..00000000000 --- a/services/wallet/transfer/view.go +++ /dev/null @@ -1,118 +0,0 @@ -package transfer - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" - w_common "github.com/status-im/status-go/services/wallet/common" -) - -// View stores only fields used by a client and ensures that all relevant fields are -// encoded in hex. -type View struct { - ID common.Hash `json:"id"` - Type w_common.Type `json:"type"` - Address common.Address `json:"address"` - BlockNumber *hexutil.Big `json:"blockNumber"` - BlockHash common.Hash `json:"blockhash"` - Timestamp hexutil.Uint64 `json:"timestamp"` - GasPrice *hexutil.Big `json:"gasPrice"` - MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"` - MaxPriorityFeePerGas *hexutil.Big `json:"maxPriorityFeePerGas"` - EffectiveTip *hexutil.Big `json:"effectiveTip"` - EffectiveGasPrice *hexutil.Big `json:"effectiveGasPrice"` - GasLimit hexutil.Uint64 `json:"gasLimit"` - GasUsed hexutil.Uint64 `json:"gasUsed"` - Nonce hexutil.Uint64 `json:"nonce"` - TxStatus hexutil.Uint64 `json:"txStatus"` - Input hexutil.Bytes `json:"input"` - TxHash common.Hash `json:"txHash"` - Value *hexutil.Big `json:"value"` // Only used for Type EthTransfer and Erc20Transfer - TokenID *hexutil.Big `json:"tokenId"` // Only used for Type Erc721Transfer - From common.Address `json:"from"` - To common.Address `json:"to"` - Contract common.Address `json:"contract"` - NetworkID uint64 `json:"networkId"` - MultiTransactionID int64 `json:"multiTransactionID"` - BaseGasFees string `json:"base_gas_fee"` -} - -func castToTransferViews(transfers []Transfer) []View { - views := make([]View, 0, len(transfers)) - for _, tx := range transfers { - switch tx.Type { - case w_common.EthTransfer, w_common.Erc20Transfer, w_common.Erc721Transfer: - view := CastToTransferView(tx) - views = append(views, view) - } - } - return views -} - -func CastToTransferView(t Transfer) View { - view := View{} - view.ID = t.ID - view.Type = getFixedTransferType(t) - view.Address = t.Address - view.BlockNumber = (*hexutil.Big)(t.BlockNumber) - view.BlockHash = t.BlockHash - view.Timestamp = hexutil.Uint64(t.Timestamp) - view.GasPrice = (*hexutil.Big)(t.Transaction.GasPrice()) - if t.BaseGasFees != "" { - baseFee := new(big.Int) - baseFee.SetString(t.BaseGasFees[2:], 16) - tip := t.Transaction.EffectiveGasTipValue(baseFee) - - view.EffectiveTip = (*hexutil.Big)(tip) - price := new(big.Int).Add(baseFee, tip) - view.EffectiveGasPrice = (*hexutil.Big)(price) - } - view.MaxFeePerGas = (*hexutil.Big)(t.Transaction.GasFeeCap()) - view.MaxPriorityFeePerGas = (*hexutil.Big)(t.Transaction.GasTipCap()) - view.GasLimit = hexutil.Uint64(t.Transaction.Gas()) - view.GasUsed = hexutil.Uint64(t.Receipt.GasUsed) - view.BaseGasFees = t.BaseGasFees - view.Nonce = hexutil.Uint64(t.Transaction.Nonce()) - view.TxStatus = hexutil.Uint64(t.Receipt.Status) - view.Input = hexutil.Bytes(t.Transaction.Data()) - view.TxHash = t.Transaction.Hash() - view.NetworkID = t.NetworkID - - value := new(hexutil.Big) - tokenID := new(hexutil.Big) - - switch view.Type { - case w_common.EthTransfer: - view.From = t.From - if t.Transaction.To() != nil { - view.To = *t.Transaction.To() - } - value = (*hexutil.Big)(t.Transaction.Value()) - view.Contract = t.Receipt.ContractAddress - case w_common.Erc20Transfer: - view.Contract = t.Log.Address - from, to, valueInt := w_common.ParseErc20TransferLog(t.Log) - view.From, view.To, value = from, to, (*hexutil.Big)(valueInt) - case w_common.Erc721Transfer: - view.Contract = t.Log.Address - from, to, tokenIDInt := w_common.ParseErc721TransferLog(t.Log) - view.From, view.To, tokenID = from, to, (*hexutil.Big)(tokenIDInt) - } - - view.MultiTransactionID = int64(t.MultiTransactionID) - view.Value = value - view.TokenID = tokenID - - return view -} - -func getFixedTransferType(tx Transfer) w_common.Type { - // erc721 transfers share signature with erc20 ones, so they both used to be categorized as erc20 - // by the Downloader. We fix this here since they might be mis-categorized in the db. - if tx.Type == w_common.Erc20Transfer { - eventType := w_common.GetEventType(tx.Log) - return w_common.EventTypeToSubtransactionType(eventType) - } - return tx.Type -} diff --git a/tests-functional/tests/test_cases.py b/tests-functional/tests/test_cases.py index 9e0a3e79405..2446952f4e1 100644 --- a/tests-functional/tests/test_cases.py +++ b/tests-functional/tests/test_cases.py @@ -13,6 +13,8 @@ from conftest import option from constants import user_1, user_2, DEFAULT_DISPLAY_NAME +import wallet_utils + class StatusDTestCase: network_id = 31337 @@ -39,72 +41,31 @@ def setup_class(self): self.rpc_client.restore_account_and_login() self.rpc_client.wait_for_login() +class SignalTestCase(StatusDTestCase): + await_signals = [] -class WalletTestCase(StatusBackendTestCase): - - def wallet_create_multi_transaction(self, **kwargs): - method = "wallet_createMultiTransaction" - transfer_tx_data = { - "data": "", - "from": user_1.address, - "gas": "0x5BBF", - "input": "", - "maxFeePerGas": "0xbcc0f04fd", - "maxPriorityFeePerGas": "0xbcc0f04fd", - "to": user_2.address, - "type": "0x02", - "value": "0x5af3107a4000", - } - for key, new_value in kwargs.items(): - if key in transfer_tx_data: - transfer_tx_data[key] = new_value - else: - logging.info( - f"Warning: The key '{key}' does not exist in the transferTx parameters and will be ignored.") - params = [ - { - "fromAddress": user_1.address, - "fromAmount": "0x5af3107a4000", - "fromAsset": "ETH", - "type": 0, # MultiTransactionSend - "toAddress": user_2.address, - "toAsset": "ETH", - }, - [ - { - "bridgeName": "Transfer", - "chainID": 31337, - "transferTx": transfer_tx_data - } - ], - f"{option.password}", - ] - return self.rpc_client.rpc_request(method, params) - - def send_valid_multi_transaction(self, **kwargs): - response = self.wallet_create_multi_transaction(**kwargs) - - tx_hash = None - self.rpc_client.verify_is_valid_json_rpc_response(response) - try: - tx_hash = response.json( - )["result"]["hashes"][str(self.network_id)][0] - except (KeyError, json.JSONDecodeError): - raise Exception(response.content) - return tx_hash + def setup_method(self): + super().setup_method() + self.signal_client = SignalClient(option.ws_url_statusd, self.await_signals) + + websocket_thread = threading.Thread(target=self.signal_client._connect) + websocket_thread.daemon = True + websocket_thread.start() -class TransactionTestCase(WalletTestCase): +class TransactionTestCase(SignalTestCase): def setup_method(self): - self.tx_hash = self.send_valid_multi_transaction() + tx_data = wallet_utils.send_router_transaction(self.rpc_client, self.signal_client) + self.tx_hash = tx_data["tx_status"]["hash"] -class EthRpcTestCase(WalletTestCase): +class EthRpcTestCase(SignalTestCase): @pytest.fixture(autouse=True, scope='class') def tx_data(self): - tx_hash = self.send_valid_multi_transaction() + tx_data = wallet_utils.send_router_transaction(self.rpc_client, self.signal_client) + tx_hash = tx_data["tx_status"]["hash"] self.wait_until_tx_not_pending(tx_hash) receipt = self.get_transaction_receipt(tx_hash) @@ -143,17 +104,6 @@ def wait_until_tx_not_pending(self, tx_hash, timeout=10): return response.json()["result"]["tx"] -class SignalTestCase(StatusDTestCase): - await_signals = [] - - def setup_method(self): - super().setup_method() - self.signal_client = SignalClient(option.ws_url_statusd, self.await_signals) - - websocket_thread = threading.Thread(target=self.signal_client._connect) - websocket_thread.daemon = True - websocket_thread.start() - class NetworkConditionTestCase: diff --git a/tests-functional/tests/test_wallet_rpc.py b/tests-functional/tests/test_wallet_rpc.py index 39cbbed7732..f3da1c5340b 100644 --- a/tests-functional/tests/test_wallet_rpc.py +++ b/tests-functional/tests/test_wallet_rpc.py @@ -8,73 +8,6 @@ from constants import user_1 from test_cases import StatusBackendTestCase, TransactionTestCase, StatusDTestCase - -@pytest.mark.wallet -@pytest.mark.tx -@pytest.mark.rpc -class TestTransactionRpc(TransactionTestCase): - - @pytest.mark.parametrize( - "method, params", - [ - ( - "wallet_checkRecentHistoryForChainIDs", - [[31337], ["0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"]], - ), - ( - "wallet_getPendingTransactionsForIdentities", - [[{"chainId": None, "hash": None}]], - ), - ], - ) - def test_tx_(self, method, params): - _id = str(random.randint(1, 9999)) - - if method in ["wallet_getPendingTransactionsForIdentities"]: - params[0][0]["chainId"] = self.network_id - params[0][0]["hash"] = self.tx_hash - - response = self.rpc_client.rpc_valid_request(method, params, _id) - self.rpc_client.verify_json_schema(response.json(), method) - - def test_create_multi_transaction(self): - response = self.wallet_create_multi_transaction() - self.rpc_client.verify_is_valid_json_rpc_response(response) - - # how to create schema: - # from schema_builder import CustomSchemaBuilder - # CustomSchemaBuilder(method).create_schema(response.json()) - - with open(f"{option.base_dir}/schemas/wallet_createMultiTransaction/transferTx_positive", "r") as schema: - jsonschema.validate(instance=response.json(), schema=json.load(schema)) - - @pytest.mark.parametrize( - "method, changed_values, expected_error_code, expected_error_text", - [ - ( - "transferTx_value_not_enough_balance", - {'value': '0x21e438ea8139cd35004'}, -32000, "Insufficient funds for gas", - ), - ( - "transferTx_from_from_invalid_string", - {'from': 'some_invalid_address'}, -32602, "cannot unmarshal hex string without 0x prefix", - ), - ], - ) - def test_create_multi_transaction_validation(self, method, - changed_values, - expected_error_code, expected_error_text): - response = self.wallet_create_multi_transaction(**changed_values) - self.rpc_client.verify_is_json_rpc_error(response) - actual_error_code, actual_error_text = response.json()['error']['code'], response.json()['error']['message'] - assert expected_error_code == actual_error_code, \ - f"got code: {actual_error_code} instead of expected: {expected_error_code}" - assert expected_error_text in actual_error_text, \ - f"got error: {actual_error_text} that does not include: {expected_error_text}" - - self.rpc_client.verify_json_schema(response.json(), "wallet_createMultiTransaction/transferTx_error") - - @pytest.mark.wallet @pytest.mark.rpc class TestRpc(StatusBackendTestCase): @@ -96,7 +29,6 @@ class TestRpc(StatusBackendTestCase): "usd"]), ("wallet_fetchTokenDetails", [["WETH9", "USDC", "ZEENUS", "EUROC", "WEENUS", "XEENUS", "WETH", "ETH", "STT", "UNI", "YEENUS", "DAI"]]), - ("wallet_checkRecentHistoryForChainIDs", [[31337], [user_1.address]]), ("wallet_getWalletConnectActiveSessions", [1728995277]), ("wallet_stopSuggestedRoutesAsyncCalculation", []), ]