mirror of
https://github.com/status-im/status-go.git
synced 2025-02-01 17:38:36 +00:00
c67d4030ac
author shashankshampi <shashank.sanket1995@gmail.com> 1729780155 +0530 committer shashankshampi <shashank.sanket1995@gmail.com> 1730274350 +0530 test: Code Migration from status-cli-tests fix_: functional tests (#5979) * fix_: generate on test-functional * chore(test)_: fix functional test assertion --------- Co-authored-by: Siddarth Kumar <siddarthkay@gmail.com> feat(accounts)_: cherry-pick Persist acceptance of Terms of Use & Privacy policy (#5766) (#5977) * feat(accounts)_: Persist acceptance of Terms of Use & Privacy policy (#5766) The original GH issue https://github.com/status-im/status-mobile/issues/21113 came from a request from the Legal team. We must show to Status v1 users the new terms (Terms of Use & Privacy Policy) right after they upgrade to Status v2 from the stores. The solution we use is to create a flag in the accounts table, named hasAcceptedTerms. The flag will be set to true on the first account ever created in v2 and we provide a native call in mobile/status.go#AcceptTerms, which allows the client to persist the user's choice in case they are upgrading (from v1 -> v2, or from a v2 older than this PR). This solution is not the best because we should store the setting in a separate table, not in the accounts table. Related Mobile PR https://github.com/status-im/status-mobile/pull/21124 * fix(test)_: Compare addresses using uppercased strings --------- Co-authored-by: Icaro Motta <icaro.ldm@gmail.com> test_: restore account (#5960) feat_: `LogOnPanic` linter (#5969) * feat_: LogOnPanic linter * fix_: add missing defer LogOnPanic * chore_: make vendor * fix_: tests, address pr comments * fix_: address pr comments fix(ci)_: remove workspace and tmp dir This ensures we do not encounter weird errors like: ``` + ln -s /home/jenkins/workspace/go_prs_linux_x86_64_main_PR-5907 /home/jenkins/workspace/go_prs_linux_x86_64_main_PR-5907@tmp/go/src/github.com/status-im/status-go ln: failed to create symbolic link '/home/jenkins/workspace/go_prs_linux_x86_64_main_PR-5907@tmp/go/src/github.com/status-im/status-go': File exists script returned exit code 1 ``` Signed-off-by: Jakub Sokołowski <jakub@status.im> chore_: enable windows and macos CI build (#5840) - Added support for Windows and macOS in CI pipelines - Added missing dependencies for Windows and x86-64-darwin - Resolved macOS SDK version compatibility for darwin-x86_64 The `mkShell` override was necessary to ensure compatibility with the newer macOS SDK (version 11.0) for x86_64. The default SDK (10.12) was causing build failures because of the missing libs and frameworks. OverrideSDK creates a mapping from the default SDK in all package categories to the requested SDK (11.0). fix(contacts)_: fix trust status not being saved to cache when changed (#5965) Fixes https://github.com/status-im/status-desktop/issues/16392 cleanup added logger and cleanup review comments changes fix_: functional tests (#5979) * fix_: generate on test-functional * chore(test)_: fix functional test assertion --------- Co-authored-by: Siddarth Kumar <siddarthkay@gmail.com> feat(accounts)_: cherry-pick Persist acceptance of Terms of Use & Privacy policy (#5766) (#5977) * feat(accounts)_: Persist acceptance of Terms of Use & Privacy policy (#5766) The original GH issue https://github.com/status-im/status-mobile/issues/21113 came from a request from the Legal team. We must show to Status v1 users the new terms (Terms of Use & Privacy Policy) right after they upgrade to Status v2 from the stores. The solution we use is to create a flag in the accounts table, named hasAcceptedTerms. The flag will be set to true on the first account ever created in v2 and we provide a native call in mobile/status.go#AcceptTerms, which allows the client to persist the user's choice in case they are upgrading (from v1 -> v2, or from a v2 older than this PR). This solution is not the best because we should store the setting in a separate table, not in the accounts table. Related Mobile PR https://github.com/status-im/status-mobile/pull/21124 * fix(test)_: Compare addresses using uppercased strings --------- Co-authored-by: Icaro Motta <icaro.ldm@gmail.com> test_: restore account (#5960) feat_: `LogOnPanic` linter (#5969) * feat_: LogOnPanic linter * fix_: add missing defer LogOnPanic * chore_: make vendor * fix_: tests, address pr comments * fix_: address pr comments chore_: enable windows and macos CI build (#5840) - Added support for Windows and macOS in CI pipelines - Added missing dependencies for Windows and x86-64-darwin - Resolved macOS SDK version compatibility for darwin-x86_64 The `mkShell` override was necessary to ensure compatibility with the newer macOS SDK (version 11.0) for x86_64. The default SDK (10.12) was causing build failures because of the missing libs and frameworks. OverrideSDK creates a mapping from the default SDK in all package categories to the requested SDK (11.0). fix(contacts)_: fix trust status not being saved to cache when changed (#5965) Fixes https://github.com/status-im/status-desktop/issues/16392 test_: remove port bind chore(wallet)_: move route execution code to separate module chore_: replace geth logger with zap logger (#5962) closes: #6002 feat(telemetry)_: add metrics for message reliability (#5899) * feat(telemetry)_: track message reliability Add metrics for dial errors, missed messages, missed relevant messages, and confirmed delivery. * fix_: handle error from json marshal chore_: use zap logger as request logger iterates: status-im/status-desktop#16536 test_: unique project per run test_: use docker compose v2, more concrete project name fix(codecov)_: ignore folders without tests Otherwise Codecov reports incorrect numbers when making changes. https://docs.codecov.com/docs/ignoring-paths Signed-off-by: Jakub Sokołowski <jakub@status.im> test_: verify schema of signals during init; fix schema verification warnings (#5947) fix_: update defaultGorushURL (#6011) fix(tests)_: use non-standard port to avoid conflicts We have observed `nimbus-eth2` build failures reporting this port: ```json { "lvl": "NTC", "ts": "2024-10-28 13:51:32.308+00:00", "msg": "REST HTTP server could not be started", "topics": "beacnde", "address": "127.0.0.1:5432", "reason": "(98) Address already in use" } ``` https://ci.status.im/job/nimbus-eth2/job/platforms/job/linux/job/x86_64/job/main/job/PR-6683/3/ Signed-off-by: Jakub Sokołowski <jakub@status.im> fix_: create request logger ad-hoc in tests Fixes `TestCall` failing when run concurrently. chore_: configure codecov (#6005) * chore_: configure codecov * fix_: after_n_builds
235 lines
6.8 KiB
Go
235 lines
6.8 KiB
Go
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
|
|
}
|