diff --git a/test/go/test-wallet_connect/combined/index.html b/test/go/test-wallet_connect/combined/index.html
deleted file mode 100644
index 5a90510263..0000000000
--- a/test/go/test-wallet_connect/combined/index.html
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
- App and Integration
-
-
-
- App Page
-
- Wallet Page
-
-
-
diff --git a/test/go/test-wallet_connect/modal/modal.go b/test/go/test-wallet_connect/modal/modal.go
index 47c17ef40d..db32e2a76c 100644
--- a/test/go/test-wallet_connect/modal/modal.go
+++ b/test/go/test-wallet_connect/modal/modal.go
@@ -11,6 +11,9 @@ import (
webview "github.com/webview/webview_go"
)
+// main simulates a wallet connect client session with status registered as a wallet connect provider
+// this is used as an alternative for testing the deep link integration until the status desktop app goes in production
+// and we can register it as a wallet connect provider
func main() {
// Serve files from the ./generated directory
fileServer := http.FileServer(http.Dir("./generated"))
diff --git a/test/go/test-wallet_connect/sdk/helpers.go b/test/go/test-wallet_connect/sdk/helpers.go
deleted file mode 100644
index d6e5a9be49..0000000000
--- a/test/go/test-wallet_connect/sdk/helpers.go
+++ /dev/null
@@ -1,207 +0,0 @@
-package main
-
-import (
- "encoding/json"
- "flag"
- "fmt"
- "io"
- "os"
- "path/filepath"
- "reflect"
-
- statusgo "github.com/status-im/status-go/mobile"
- "github.com/status-im/status-go/multiaccounts"
-)
-
-func loginToAccount(hashedPassword, userFolder, nodeConfigJson string) error {
- absUserFolder, err := filepath.Abs(userFolder)
- if err != nil {
- return err
- }
- accountsJson := statusgo.OpenAccounts(absUserFolder)
- accounts := make([]multiaccounts.Account, 0)
- err = getCAPIResponse(accountsJson, &accounts)
- if err != nil {
- return err
- }
-
- if len(accounts) == 0 {
- return fmt.Errorf("no accounts found")
- }
-
- account := accounts[0]
- keystorePath := filepath.Join(filepath.Join(absUserFolder, "keystore/"), account.KeyUID)
- initKeystoreJson := statusgo.InitKeystore(keystorePath)
- apiResponse := statusgo.APIResponse{}
- err = getCAPIResponse(initKeystoreJson, &apiResponse)
- if err != nil {
- return err
- }
-
- //serialize account of type multiaccounts.Account
- accountJson, err := json.Marshal(account)
- if err != nil {
- return err
- }
- loginJson := statusgo.LoginWithConfig(string(accountJson), hashedPassword, nodeConfigJson)
- err = getCAPIResponse(loginJson, &apiResponse)
- if err != nil {
- return err
- }
-
- return nil
-}
-
-type jsonrpcMessage struct {
- Version string `json:"jsonrpc"`
- ID json.RawMessage `json:"id"`
-}
-
-type jsonrpcRequest struct {
- jsonrpcMessage
- ChainID uint64 `json:"chainId"`
- Method string `json:"method"`
- Params json.RawMessage `json:"params,omitempty"`
-}
-
-func callPrivateMethod(method string, params []interface{}) string {
- var paramsJson json.RawMessage
- var err error
- if params != nil {
- paramsJson, err = json.Marshal(params)
- if err != nil {
- return ""
- }
- }
-
- msg := jsonrpcRequest{
- jsonrpcMessage: jsonrpcMessage{
- Version: "2.0",
- },
- Method: method,
- Params: paramsJson,
- }
-
- msgJson, err := json.Marshal(msg)
- if err != nil {
- return ""
- }
-
- return statusgo.CallPrivateRPC(string(msgJson))
-}
-
-type Config struct {
- HashedPassword string `json:"hashedPassword"`
- NodeConfigFile string `json:"nodeConfigFile"`
- DataDir *string `json:"dataDir,omitempty"`
-}
-
-func processConfigArgs() (config *Config, nodeConfigJson string, userFolder string, err error) {
- var configFilePath string
- flag.StringVar(&configFilePath, "config", "", "path to json config file")
- flag.StringVar(&userFolder, "dataDir", "../../../Status/data", "path to json config file")
- flag.Parse()
-
- if configFilePath == "" {
- flag.Usage()
- return
- }
-
- config = &Config{}
- // parse config file
- configFile, err := os.Open(configFilePath)
- if err != nil {
- panic(err)
- }
- defer configFile.Close()
- jsonParser := json.NewDecoder(configFile)
- if err = jsonParser.Decode(&config); err != nil {
- panic(err)
- }
-
- // Read config.NodeConfigFile json file and store it as string
- nodeConfigFile, err := os.Open(config.NodeConfigFile)
- if err != nil {
- panic(err)
- }
- defer nodeConfigFile.Close()
- nodeConfigData, err := io.ReadAll(nodeConfigFile)
- if err == nil {
- nodeConfigJson = string(nodeConfigData)
- }
-
- if config.DataDir != nil {
- userFolder = *config.DataDir
- }
-
- return
-}
-
-func getCAPIResponse[T any](responseJson string, res T) error {
- apiResponse := statusgo.APIResponse{}
- err := json.Unmarshal([]byte(responseJson), &apiResponse)
- if err == nil {
- if apiResponse.Error != "" {
- return fmt.Errorf("API error: %s", apiResponse.Error)
- }
- }
-
- typeOfT := reflect.TypeOf(res)
- kindOfT := typeOfT.Kind()
-
- // Check for valid types: pointer, slice, map
- if kindOfT != reflect.Ptr && kindOfT != reflect.Slice && kindOfT != reflect.Map {
- return fmt.Errorf("type T must be a pointer, slice, or map")
- }
-
- if err := json.Unmarshal([]byte(responseJson), &res); err != nil {
- return fmt.Errorf("failed to unmarshal data: %w", err)
- }
-
- return nil
-}
-
-type jsonrpcSuccessfulResponse struct {
- jsonrpcMessage
- Result json.RawMessage `json:"result"`
-}
-
-type jsonrpcErrorResponse struct {
- jsonrpcMessage
- Error jsonError `json:"error"`
-}
-
-// jsonError represents Error message for JSON-RPC responses.
-type jsonError struct {
- Code int `json:"code"`
- Message string `json:"message"`
- Data interface{} `json:"data,omitempty"`
-}
-
-func getRPCAPIResponse[T any](responseJson string, res T) error {
- errApiResponse := jsonrpcErrorResponse{}
- err := json.Unmarshal([]byte(responseJson), &errApiResponse)
- if err == nil && errApiResponse.Error.Code != 0 {
- return fmt.Errorf("API error: %#v", errApiResponse.Error)
- }
-
- apiResponse := jsonrpcSuccessfulResponse{}
- err = json.Unmarshal([]byte(responseJson), &apiResponse)
- if err != nil {
- return fmt.Errorf("failed to unmarshal jsonrpcSuccessfulResponse: %w", err)
- }
-
- typeOfT := reflect.TypeOf(res)
- kindOfT := typeOfT.Kind()
-
- // Check for valid types: pointer, slice, map
- if kindOfT != reflect.Ptr && kindOfT != reflect.Slice && kindOfT != reflect.Map {
- return fmt.Errorf("type T must be a pointer, slice, or map")
- }
-
- if err := json.Unmarshal(apiResponse.Result, &res); err != nil {
- return fmt.Errorf("failed to unmarshal data: %w", err)
- }
-
- return nil
-}
diff --git a/test/go/test-wallet_connect/sdk/index.html b/test/go/test-wallet_connect/sdk/index.html
deleted file mode 100644
index 83b96b0188..0000000000
--- a/test/go/test-wallet_connect/sdk/index.html
+++ /dev/null
@@ -1,383 +0,0 @@
-
-
-
-
- Wallet Connect status-go test
-
-
-
-
-
-
-
-
-
diff --git a/test/go/test-wallet_connect/sdk/main.go b/test/go/test-wallet_connect/sdk/main.go
deleted file mode 100644
index 892b4ebe48..0000000000
--- a/test/go/test-wallet_connect/sdk/main.go
+++ /dev/null
@@ -1,229 +0,0 @@
-package main
-
-import (
- "encoding/json"
- "fmt"
- "net/http"
- "os"
-
- "github.com/ethereum/go-ethereum/log"
- webview "github.com/webview/webview_go"
-
- statusgo "github.com/status-im/status-go/mobile"
- wc "github.com/status-im/status-go/services/wallet/walletconnect"
- "github.com/status-im/status-go/services/wallet/walletevent"
- "github.com/status-im/status-go/signal"
-)
-
-// l is used for local logging
-var l log.Logger
-
-func init() {
- l = log.New()
- l.SetHandler(log.CallerFileHandler(log.StreamHandler(os.Stdout, log.TerminalFormat(false))))
-}
-
-type PairResult struct {
- SessionProposal string `json:"sessionProposal"`
-}
-
-type Configuration struct {
- ProjectId string `json:"projectId"`
-}
-
-type GoEvent struct {
- Name string `json:"name"`
- Payload interface{} `json:"payload"`
-}
-
-var eventQueue chan GoEvent = make(chan GoEvent, 10000)
-
-func signalHandler(jsonEvent string) {
- // parse signal.Envelope from jsonEvent
- envelope := signal.Envelope{}
- err := json.Unmarshal([]byte(jsonEvent), &envelope)
- if err != nil {
- // check for error in json
- apiResponse := statusgo.APIResponse{}
- err = json.Unmarshal([]byte(jsonEvent), &apiResponse)
- if err != nil {
- log.Error("Error parsing the signal event: ", err)
- return
- }
- }
-
- if envelope.Type == signal.EventNodeReady {
- eventQueue <- GoEvent{Name: "nodeReady", Payload: ""}
- } else if envelope.Type == "wallet" {
- // parse envelope.Event to json
- walletEvent := walletevent.Event{}
- err := json.Unmarshal([]byte(jsonEvent), &walletEvent)
- if err != nil {
- log.Error("Error parsing the wallet event: ", err)
- return
- }
- // TODO: continue from here
- // if walletEvent.Type == "WalletConnectProposeUserPair" {
- // eventQueue <- GoEvent{Name: "proposeUserPair", Payload: walletEvent.Message}
- // }
- }
-}
-
-func main() {
- // Setup status-go logger
- log.Root().SetHandler(log.CallerFileHandler(log.StdoutHandler))
-
- signal.SetDefaultNodeNotificationHandler(signalHandler)
- config, nodeConfigJson, userFolder, err := processConfigArgs()
- if err != nil {
- panic(err)
- }
-
- // Login to first account
- err = loginToAccount(config.HashedPassword, userFolder, nodeConfigJson)
- if err != nil {
- panic(err)
- }
-
- // Start WebView
- w := webview.New(true)
- defer w.Destroy()
- w.SetTitle("WC status-go test")
- w.SetSize(1280, 1024, webview.HintNone)
-
- w.Bind("sessionRequest", func(sessionRequestJson, hashedPassword string) bool {
- fmt.Println("sessionRequestJson:", sessionRequestJson)
- sessionReqRes := callPrivateMethod("wallet_wCSessionRequest", []interface{}{sessionRequestJson})
- fmt.Println("sessionReqRes:", sessionReqRes)
- var apiResponse wc.SessionRequestResponse
- err = getRPCAPIResponse(sessionReqRes, &apiResponse)
- if err != nil {
- l.Error("Error parsing wallet_wCSessionRequest response", "error", err)
- return false
- }
- if apiResponse.SignOnKeycard {
- l.Error("SignOnKeycard is not supported in this test")
- return false
- }
-
- sessionReqRes = callPrivateMethod("wallet_wCSignMessage", []interface{}{apiResponse.MessageToSign, apiResponse.Address, hashedPassword})
- fmt.Println("sessionReqRes:", sessionReqRes)
- var signature string
- err = getRPCAPIResponse(sessionReqRes, &signature)
- if err != nil {
- l.Error("Error parsing wallet_wCSignMessage response", "error", err)
- return false
- }
-
- // TODO: process the request type ...
-
- go func() {
- eventQueue <- GoEvent{Name: "sessionRequestResult", Payload: apiResponse}
- }()
-
- return true
- })
-
- w.Bind("getConfiguration", func() Configuration {
- projectID := os.Getenv("STATUS_BUILD_WALLET_CONNECT_PROJECT_ID")
- if projectID == "" {
- projectID = "87815d72a81d739d2a7ce15c2cfdefb3"
- }
- return Configuration{ProjectId: projectID}
- })
-
- w.Bind("echo", func(message string) bool {
- fmt.Println(" WebView:", message)
- return true
- })
-
- // Setup go to webview event queue
- w.Bind("popNextEvent", func() GoEvent {
- select {
- case event := <-eventQueue:
- return event
- default:
- return GoEvent{Name: "", Payload: ""}
- }
- })
-
- mockStatusObject(w)
- mockController(w)
-
- // Start a local server to serve the files
- http.HandleFunc("/bundle.js", func(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate, post-check=0, pre-check=0")
- http.ServeFile(w, r, "../../../../ui/app/AppLayouts/Wallet/views/walletconnect/sdk/generated/bundle.js")
- })
-
- http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate, post-check=0, pre-check=0")
- http.ServeFile(w, r, "./index.html")
- })
-
- go http.ListenAndServe(":8081", nil)
-
- w.Navigate("http://localhost:8081")
- w.Run()
-}
-
-func mockController(w webview.WebView) {
- w.Bind("controller_recordSuccessfulPairing", func(sessionProposalJson string) {
- fmt.Println("controller_recordSuccessfulPairing:", sessionProposalJson)
- sessionProposalRes := callPrivateMethod("wallet_wCRecordSuccessfulPairing", []interface{}{sessionProposalJson})
- var apiResponse wc.PairSessionResponse
- err := getRPCAPIResponse(sessionProposalRes, &apiResponse)
- if err != nil {
- l.Error("Error parsing the API response", "error", err)
- }
- })
-
- w.Bind("controller_changePairingState", func(topic string, active bool) {
- sessionProposalRes := callPrivateMethod("wallet_wCChangePairingState", []interface{}{topic, active})
- var apiResponse wc.PairSessionResponse
- err := getRPCAPIResponse(sessionProposalRes, &apiResponse)
- if err != nil {
- l.Error("Error parsing the API response", "error", err)
- }
- })
-}
-
-func mockStatusObject(w webview.WebView) {
- w.Bind("statusObject_sdkInitialized", func(error string) {
- // All OK here
- })
- w.Bind("statusObject_onSessionProposal", func(sessionProposalJson string) bool {
- sessionProposalRes := callPrivateMethod("wallet_wCPairSessionProposal", []interface{}{sessionProposalJson})
- var apiResponse wc.PairSessionResponse
- err := getRPCAPIResponse(sessionProposalRes, &apiResponse)
- if err != nil {
- l.Error("Error parsing the API response", "error", err)
- return false
- }
-
- go func() {
- eventQueue <- GoEvent{Name: "proposeUserPair", Payload: apiResponse}
- }()
-
- return true
- })
- w.Bind("statusObject_onSessionRequest", func(sessionRequestJson string) bool {
- sessionReqRes := callPrivateMethod("wallet_wCSessionRequest", []interface{}{sessionRequestJson})
- var apiResponse wc.SessionRequestResponse
- err := getRPCAPIResponse(sessionReqRes, &apiResponse)
- if err != nil {
- l.Error("Error parsing the API response", "error", err)
- return false
- }
- return true
- })
-
- // function onSessionUpdate(details)
- // function onSessionExtend(details)
- // function onSessionPing(details)
- // function onSessionDelete(details)
- // function onSessionExpire(details)
- // function onSessionRequestSent(details)
- // function onSessionEvent(details)
- // function onProposalExpire(details)
-}
diff --git a/test/status-go/integration/.gitignore b/test/status-go/integration/.gitignore
new file mode 100644
index 0000000000..1300e1343d
--- /dev/null
+++ b/test/status-go/integration/.gitignore
@@ -0,0 +1 @@
+.integration_tests_config.json
\ No newline at end of file
diff --git a/test/status-go/integration/README.md b/test/status-go/integration/README.md
new file mode 100644
index 0000000000..1a8a50a5c9
--- /dev/null
+++ b/test/status-go/integration/README.md
@@ -0,0 +1,30 @@
+# Development integration tests for status-go
+
+These integration tests are an experiment. They rely on an existing developer environment (working user folder, blockchain access tokens) and internet connection.
+
+If it proves its usefulness we might consider automating them and make it independent of internet services
+
+## How to run tests
+
+Setup steps
+
+- Dump the node config passed to `Login` status-go call as `.node_config.json` and use its path later on in as `nodeConfigFile` in `.integration_tests_config.json`
+ - Ensure the blockchain access tokens are configured when dumping the configuration file
+- Copy [integration_tests_config-template.json](./integration_tests_config-template.json) to tests sub-folders and rename it as `.integration_tests_config.json`, then update it with your own values.
+ - Update `nodeConfigFile` with the previously extracted node config path
+ - The `hashedPassword` should be the "0x" + `keccak256(clearPassword)`
+ - For `dataDir` it is expected an working status-go user folder (e.g. the usual `status-desktop/Second/data` used with `make run` command)
+
+Run wallet tests
+
+- once
+
+ ```sh
+ (cd test/status-go/integration && go test -v ./wallet/... --tags=gowaku_no_rln,gowaku_skip_migrations)
+ ```
+
+- continuously on code changes
+
+ ```sh
+ (cd test/status-go/integration && nodemon --watch ../../../vendor/status-go/ --watch . --ext "*.go,*.sql" --exec 'go test -v ./wallet/... --tags=gowaku_no_rln,gowaku_skip_migrations 2>&1 | tee ~/proj/tmp/status-go-tests.log || exit 1')
+ ```
diff --git a/test/go/test-wallet_connect/sdk/go.mod b/test/status-go/integration/go.mod
similarity index 94%
rename from test/go/test-wallet_connect/sdk/go.mod
rename to test/status-go/integration/go.mod
index e46d35dd22..a7b9445939 100644
--- a/test/go/test-wallet_connect/sdk/go.mod
+++ b/test/status-go/integration/go.mod
@@ -1,8 +1,10 @@
-module main
+module github.com/status-im/status-desktop/test/status-go/integration
go 1.20
-replace github.com/status-im/status-go => ../../../../vendor/status-go
+replace github.com/status-im/status-desktop/test/status-go/integration => ./
+
+replace github.com/status-im/status-go => ../../../vendor/status-go
// Keep these in sync with status-go/go.mod aliases
replace github.com/ethereum/go-ethereum v1.10.26 => github.com/status-im/go-ethereum v1.10.25-status.11
@@ -18,14 +20,13 @@ replace github.com/mutecomm/go-sqlcipher/v4 v4.4.2 => github.com/status-im/go-sq
require (
github.com/ethereum/go-ethereum v1.10.26
github.com/status-im/status-go v0.171.7
- github.com/webview/webview_go v0.0.0-20230901181450-5a14030a9070
+ github.com/stretchr/testify v1.8.4
)
require (
github.com/BurntSushi/toml v1.2.1 // indirect
github.com/PuerkitoBio/goquery v1.6.1 // indirect
github.com/RoaringBitmap/roaring v0.9.4 // indirect
- github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 // indirect
github.com/VictoriaMetrics/fastcache v1.6.0 // indirect
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 // indirect
github.com/anacrolix/chansync v0.3.0 // indirect
@@ -46,6 +47,7 @@ require (
github.com/anacrolix/utp v0.1.0 // indirect
github.com/andybalholm/brotli v1.0.5 // indirect
github.com/andybalholm/cascadia v1.2.0 // indirect
+ github.com/avast/retry-go/v4 v4.5.1 // indirect
github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/beevik/ntp v0.3.0 // indirect
github.com/benbjohnson/clock v1.3.5 // indirect
@@ -70,7 +72,7 @@ require (
github.com/deckarep/golang-set v1.8.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
- github.com/dustin/go-humanize v1.0.0 // indirect
+ github.com/dustin/go-humanize v1.0.1 // indirect
github.com/edsrzf/mmap-go v1.0.0 // indirect
github.com/elastic/gosigar v0.14.2 // indirect
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 // indirect
@@ -79,7 +81,7 @@ require (
github.com/forPelevin/gomoji v1.1.2 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect
- github.com/go-ole/go-ole v1.2.5 // indirect
+ github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-stack/stack v1.8.1 // indirect
@@ -211,7 +213,7 @@ require (
github.com/russolsen/transit v0.0.0-20180705123435-0794b4c4505a // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/schollz/peerdiscovery v1.7.0 // indirect
- github.com/shirou/gopsutil v3.21.5+incompatible // indirect
+ github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/shopspring/decimal v1.2.0 // indirect
github.com/siphiuel/lc-proxy-wrapper v0.0.0-20230516150924-246507cee8c7 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
@@ -222,9 +224,9 @@ require (
github.com/status-im/migrate/v4 v4.6.2-status.3 // indirect
github.com/status-im/rendezvous v1.3.7 // indirect
github.com/status-im/status-go/extkeys v1.1.2 // indirect
- github.com/status-im/tcp-shaker v0.0.0-20191114194237-215893130501 // indirect
+ github.com/status-im/tcp-shaker v1.1.1-status // indirect
github.com/status-im/zxcvbn-go v0.0.0-20220311183720-5e8676676857 // indirect
- github.com/stretchr/testify v1.8.4 // indirect
+ github.com/stretchr/objx v0.5.0 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect
github.com/tklauser/go-sysconf v0.3.6 // indirect
github.com/tklauser/numcpus v0.2.2 // indirect
@@ -234,8 +236,8 @@ require (
github.com/vacp2p/mvds v0.0.24-0.20201124060106-26d8e94130d8 // indirect
github.com/waku-org/go-discover v0.0.0-20221209174356-61c833f34d98 // indirect
github.com/waku-org/go-libp2p-rendezvous v0.0.0-20230628220917-7b4e5ae4c0e7 // indirect
- github.com/waku-org/go-waku v0.8.1-0.20231103161423-351dd55a1498 // indirect
- github.com/waku-org/go-zerokit-rln v0.1.14-0.20230916173259-d284a3d8f2fd // indirect
+ github.com/waku-org/go-waku v0.8.1-0.20240104144340-585648c4eefe // indirect
+ github.com/waku-org/go-zerokit-rln v0.1.14-0.20240102145250-fa738c0bdf59 // indirect
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20230916172309-ee0ee61dde2b // indirect
github.com/waku-org/go-zerokit-rln-arm v0.0.0-20230916171929-1dd9494ff065 // indirect
github.com/waku-org/go-zerokit-rln-x86_64 v0.0.0-20230916171518-2a77c3734dd1 // indirect
@@ -250,6 +252,7 @@ require (
github.com/yeqown/go-qrcode/v2 v2.2.1 // indirect
github.com/yeqown/go-qrcode/writer/standard v1.2.1 // indirect
github.com/yeqown/reedsolomon v1.0.0 // indirect
+ github.com/yusufpapurcu/wmi v1.2.3 // indirect
github.com/zenthangplus/goccm v0.0.0-20211005163543-2f2e522aca15 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
go.uber.org/atomic v1.11.0 // indirect
diff --git a/test/go/test-wallet_connect/sdk/go.sum b/test/status-go/integration/go.sum
similarity index 99%
rename from test/go/test-wallet_connect/sdk/go.sum
rename to test/status-go/integration/go.sum
index ad57ef40ec..c96385c8e4 100644
--- a/test/go/test-wallet_connect/sdk/go.sum
+++ b/test/status-go/integration/go.sum
@@ -158,7 +158,6 @@ github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:H
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
-github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 h1:5sXbqlSomvdjlRbWyNqkPsJ3Fg+tQZCbgeX1VGljbQY=
github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o=
github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw=
@@ -346,6 +345,8 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
+github.com/avast/retry-go/v4 v4.5.1 h1:AxIx0HGi4VZ3I02jr78j5lZ3M6x1E0Ivxa6b0pUUh7o=
+github.com/avast/retry-go/v4 v4.5.1/go.mod h1:/sipNsvNB3RRuT5iNcb6h73nw3IBmXJ/H3XrCQYSOpc=
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
@@ -711,8 +712,9 @@ github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48/go.mod h1:R9ET47fwRVRP
github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
+github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/dvyukov/go-fuzz v0.0.0-20200318091601-be3528f3a813/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
@@ -828,8 +830,9 @@ github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/stdr v1.2.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jTKKwI=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
-github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY=
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
+github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
+github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
@@ -1900,8 +1903,9 @@ github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfP
github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
-github.com/shirou/gopsutil v3.21.5+incompatible h1:OloQyEerMi7JUrXiNzy8wQ5XN+baemxSl12QgIzt0jc=
github.com/shirou/gopsutil v3.21.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
+github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
+github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
@@ -1999,8 +2003,8 @@ github.com/status-im/resize v0.0.0-20201215164250-7c6d9f0d3088 h1:ClCAP2FPCvl8hG
github.com/status-im/resize v0.0.0-20201215164250-7c6d9f0d3088/go.mod h1:+92j1tN27DypDeBFxkg0uzkqfh1bNHTZe3Bv2PjvxpM=
github.com/status-im/status-go/extkeys v1.1.2 h1:FSjARgDathJ3rIapJt851LsIXP9Oyuu2M2jPJKuzloU=
github.com/status-im/status-go/extkeys v1.1.2/go.mod h1:hCmFzb2jiiVF2voZKYbzuhOQiHHCmyLJsZJXrFFg7BY=
-github.com/status-im/tcp-shaker v0.0.0-20191114194237-215893130501 h1:oa0KU5jJRNtXaM/P465MhvSFo/HM2O8qi2DDuPcd7ro=
-github.com/status-im/tcp-shaker v0.0.0-20191114194237-215893130501/go.mod h1:RYo/itke1oU5k/6sj9DNM3QAwtE5rZSgg5JnkOv83hk=
+github.com/status-im/tcp-shaker v1.1.1-status h1:TnVeeWlq2SKCWotHc4Vi6qZQfY8TTe3VLmu1xpEFYhg=
+github.com/status-im/tcp-shaker v1.1.1-status/go.mod h1:RYo/itke1oU5k/6sj9DNM3QAwtE5rZSgg5JnkOv83hk=
github.com/status-im/zxcvbn-go v0.0.0-20220311183720-5e8676676857 h1:sPkzT7Z7uLmejOsBRlZ0kwDWpqjpHJsp834o5nbhqho=
github.com/status-im/zxcvbn-go v0.0.0-20220311183720-5e8676676857/go.mod h1:lq9I5ROto5tcua65GmCE6SIW7VE0ucdEBs1fn4z7uWU=
github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8=
@@ -2013,7 +2017,9 @@ github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
@@ -2025,7 +2031,9 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
@@ -2088,10 +2096,10 @@ github.com/waku-org/go-discover v0.0.0-20221209174356-61c833f34d98 h1:xwY0kW5XZF
github.com/waku-org/go-discover v0.0.0-20221209174356-61c833f34d98/go.mod h1:eBHgM6T4EG0RZzxpxKy+rGz/6Dw2Nd8DWxS0lm9ESDw=
github.com/waku-org/go-libp2p-rendezvous v0.0.0-20230628220917-7b4e5ae4c0e7 h1:0e1h+p84yBp0IN7AqgbZlV7lgFBjm214lgSOE7CeJmE=
github.com/waku-org/go-libp2p-rendezvous v0.0.0-20230628220917-7b4e5ae4c0e7/go.mod h1:pFvOZ9YTFsW0o5zJW7a0B5tr1owAijRWJctXJ2toL04=
-github.com/waku-org/go-waku v0.8.1-0.20231103161423-351dd55a1498 h1:2Y06Ni3tBj2LQA0ys1o1PspZxZPM9GOKwNEGolbueQ4=
-github.com/waku-org/go-waku v0.8.1-0.20231103161423-351dd55a1498/go.mod h1:hem2hnXK5BdabxwJULszM0Rh1Yj+gD9IxjwLCGPPaxs=
-github.com/waku-org/go-zerokit-rln v0.1.14-0.20230916173259-d284a3d8f2fd h1:cu7CsUo7BK6ac/v193RIaqAzUcmpa6MNY4xYW9AenQI=
-github.com/waku-org/go-zerokit-rln v0.1.14-0.20230916173259-d284a3d8f2fd/go.mod h1:1PdBdPzyTaKt3VnpAHk3zj+r9dXPFOr3IHZP9nFle6E=
+github.com/waku-org/go-waku v0.8.1-0.20240104144340-585648c4eefe h1:2D97fbaKlIQRjWMz/iTjnYcxi2z6ekKvspTGtcuPHgU=
+github.com/waku-org/go-waku v0.8.1-0.20240104144340-585648c4eefe/go.mod h1:+b5fPPJ4YUIAPJtPOtwB7bTrOQ9lF15I2LnQjV6NMIA=
+github.com/waku-org/go-zerokit-rln v0.1.14-0.20240102145250-fa738c0bdf59 h1:jisj+OCI6QydLtFq3Pyhu49wl9ytPN7oAHjMfepHDrA=
+github.com/waku-org/go-zerokit-rln v0.1.14-0.20240102145250-fa738c0bdf59/go.mod h1:1PdBdPzyTaKt3VnpAHk3zj+r9dXPFOr3IHZP9nFle6E=
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20230916172309-ee0ee61dde2b h1:KgZVhsLkxsj5gb/FfndSCQu6VYwALrCOgYI3poR95yE=
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20230916172309-ee0ee61dde2b/go.mod h1:KYykqtdApHVYZ3G0spwMnoxc5jH5eI3jyO9SwsSfi48=
github.com/waku-org/go-zerokit-rln-arm v0.0.0-20230916171929-1dd9494ff065 h1:Sd7QD/1Yo2o2M1MY49F8Zr4KNBPUEK5cz5HoXQVJbrs=
@@ -2104,8 +2112,6 @@ github.com/wealdtech/go-multicodec v1.4.0 h1:iq5PgxwssxnXGGPTIK1srvt6U5bJwIp7k6k
github.com/wealdtech/go-multicodec v1.4.0/go.mod h1:aedGMaTeYkIqi/KCPre1ho5rTb3hGpu/snBOS3GQLw4=
github.com/wealdtech/go-string2eth v1.1.0 h1:USJQmysUrBYYmZs7d45pMb90hRSyEwizP7lZaOZLDAw=
github.com/wealdtech/go-string2eth v1.1.0/go.mod h1:RUzsLjJtbZaJ/3UKn9kY19a/vCCUHtEWoUW3uiK6yGU=
-github.com/webview/webview_go v0.0.0-20230901181450-5a14030a9070 h1:imZLWyo1ondeQjqfb/eHuYgFiOAYg6ugSMCnGfPTPmg=
-github.com/webview/webview_go v0.0.0-20230901181450-5a14030a9070/go.mod h1:yE65LFCeWf4kyWD5re+h4XNvOHJEXOCOuJZ4v8l5sgk=
github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
@@ -2148,6 +2154,8 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
+github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
diff --git a/test/status-go/integration/helpers/accounts.go b/test/status-go/integration/helpers/accounts.go
new file mode 100644
index 0000000000..2cd44cb396
--- /dev/null
+++ b/test/status-go/integration/helpers/accounts.go
@@ -0,0 +1,47 @@
+package helpers
+
+import (
+ "github.com/status-im/status-go/multiaccounts/accounts"
+)
+
+func GetAllAccounts() (res []accounts.Account, err error) {
+ jsonRes, err := CallPrivateMethod("accounts_getAccounts", []interface{}{})
+ if err != nil {
+ return nil, err
+ }
+
+ var allAccounts []accounts.Account
+ err = GetRPCAPIResponse(jsonRes, &allAccounts)
+ if err != nil {
+ return nil, err
+ }
+ return allAccounts, nil
+}
+
+func GetWalletWatchOnlyAccounts() (res []accounts.Account, err error) {
+ accounts, err := GetAllAccounts()
+ if err != nil {
+ return nil, err
+ }
+
+ for _, acc := range accounts {
+ if !acc.IsWalletNonWatchOnlyAccount() {
+ res = append(res, acc)
+ }
+ }
+ return res, nil
+}
+
+func GetWalletOperableAccounts() (res []accounts.Account, err error) {
+ accounts, err := GetAllAccounts()
+ if err != nil {
+ return nil, err
+ }
+
+ for _, acc := range accounts {
+ if acc.IsWalletAccountReadyForTransaction() {
+ res = append(res, acc)
+ }
+ }
+ return res, nil
+}
diff --git a/test/status-go/integration/helpers/helpers.go b/test/status-go/integration/helpers/helpers.go
new file mode 100644
index 0000000000..d8c0cfd842
--- /dev/null
+++ b/test/status-go/integration/helpers/helpers.go
@@ -0,0 +1,314 @@
+package helpers
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "reflect"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/log"
+ statusgo "github.com/status-im/status-go/mobile"
+ "github.com/status-im/status-go/multiaccounts"
+ "github.com/status-im/status-go/services/wallet/walletevent"
+ "github.com/status-im/status-go/signal"
+)
+
+type StatusGoEventName string
+
+const NodeReadyEvent StatusGoEventName = "nodeReady"
+const WalletEvent StatusGoEventName = "wallet"
+
+type GoEvent struct {
+ Name StatusGoEventName `json:"name"`
+ Payload interface{} `json:"payload"`
+}
+
+type envelope struct {
+ Type string `json:"type"`
+ Event json.RawMessage `json:"event"` // Use json.RawMessage to delay parsing
+}
+
+func signalHandler(eventQueue chan GoEvent, jsonEvent string) {
+ envelope := envelope{}
+ err := json.Unmarshal([]byte(jsonEvent), &envelope)
+ if err != nil {
+ apiResponse := statusgo.APIResponse{}
+ err = json.Unmarshal([]byte(jsonEvent), &apiResponse)
+ if err != nil {
+ log.Error("Error parsing the signal event: ", err)
+ } else if apiResponse.Error != "" {
+ log.Error("Error from status-go: ", apiResponse.Error)
+ } else {
+ log.Error("Unknown JSON content for event", jsonEvent)
+ }
+ return
+ }
+
+ if envelope.Type == signal.EventNodeReady {
+ eventQueue <- GoEvent{Name: NodeReadyEvent, Payload: string(envelope.Event)}
+ } else if envelope.Type == string(WalletEvent) {
+ walletEvent := walletevent.Event{}
+ err := json.Unmarshal(envelope.Event, &walletEvent)
+ if err != nil {
+ log.Error("Error parsing the wallet event: ", err)
+ return
+ }
+ eventQueue <- GoEvent{Name: WalletEvent, Payload: walletEvent}
+ }
+}
+
+func LoginToTestAccount(t *testing.T) (eventQueue chan GoEvent, config *Config, l log.Logger) {
+ l = log.New()
+ l.SetHandler(log.CallerFileHandler(log.StreamHandler(os.Stdout, log.TerminalFormat(false))))
+
+ // Setup status-go logger
+ log.Root().SetHandler(log.CallerFileHandler(log.StdoutHandler))
+
+ eventQueue = make(chan GoEvent, 10000)
+ signal.SetDefaultNodeNotificationHandler(func(jsonEvent string) {
+ signalHandler(eventQueue, jsonEvent)
+ })
+
+ conf, nodeConfigJson, userFolder, err := processConfigArgs("./.integration_tests_config.json")
+ if err != nil {
+ t.Fatal(err)
+ }
+ config = conf
+
+ // Login to first account
+ err = loginToAccount(config.HashedPassword, userFolder, nodeConfigJson)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return
+}
+
+func WaitForEvent(eventQueue chan GoEvent, eventName StatusGoEventName, timeout time.Duration) (event *GoEvent, err error) {
+ for {
+ select {
+ case event := <-eventQueue:
+ if event.Name == eventName {
+ return &event, nil
+ }
+ case <-time.After(timeout):
+ return nil, fmt.Errorf("timeout waiting for event %s", eventName)
+ }
+ }
+}
+
+func WaitForWalletEvent[T any](eventQueue chan GoEvent, eventName walletevent.EventType, timeout time.Duration) (payload *T, err error) {
+ var event *GoEvent
+ for {
+ event, err = WaitForEvent(eventQueue, WalletEvent, timeout)
+ if err != nil {
+ return nil, err
+ }
+
+ walletEvent, ok := event.Payload.(walletevent.Event)
+ if !ok {
+ return nil, errors.New("event payload is not a wallet event")
+ }
+
+ var newPayload T
+ if walletEvent.Type == eventName {
+ if walletEvent.Message != "" {
+ err = json.Unmarshal([]byte(walletEvent.Message), &newPayload)
+ if err != nil {
+ return nil, err
+ }
+ return &newPayload, nil
+ }
+ return nil, nil
+ }
+ }
+}
+
+func loginToAccount(hashedPassword, userFolder, nodeConfigJson string) error {
+ absUserFolder, err := filepath.Abs(userFolder)
+ if err != nil {
+ return err
+ }
+ accountsJson := statusgo.OpenAccounts(absUserFolder)
+ accounts := make([]multiaccounts.Account, 0)
+ err = GetCAPIResponse(accountsJson, &accounts)
+ if err != nil {
+ return err
+ }
+
+ if len(accounts) == 0 {
+ return fmt.Errorf("no accounts found")
+ }
+
+ account := accounts[0]
+ keystorePath := filepath.Join(filepath.Join(absUserFolder, "keystore/"), account.KeyUID)
+ initKeystoreJson := statusgo.InitKeystore(keystorePath)
+ apiResponse := statusgo.APIResponse{}
+ err = GetCAPIResponse(initKeystoreJson, &apiResponse)
+ if err != nil {
+ return err
+ }
+
+ //serialize account of type multiaccounts.Account
+ accountJson, err := json.Marshal(account)
+ if err != nil {
+ return err
+ }
+ loginJson := statusgo.LoginWithConfig(string(accountJson), hashedPassword, nodeConfigJson)
+ err = GetCAPIResponse(loginJson, &apiResponse)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+type jsonrpcMessage struct {
+ Version string `json:"jsonrpc"`
+ ID json.RawMessage `json:"id"`
+}
+
+type jsonrpcRequest struct {
+ jsonrpcMessage
+ ChainID uint64 `json:"chainId"`
+ Method string `json:"method"`
+ Params json.RawMessage `json:"params,omitempty"`
+}
+
+func CallPrivateMethod(method string, params []interface{}) (string, error) {
+ var paramsJson json.RawMessage
+ var err error
+ if params != nil {
+ paramsJson, err = json.Marshal(params)
+ if err != nil {
+ return "", err
+ }
+ }
+
+ msg := jsonrpcRequest{
+ jsonrpcMessage: jsonrpcMessage{
+ Version: "2.0",
+ },
+ Method: method,
+ Params: paramsJson,
+ }
+
+ msgJson, err := json.Marshal(msg)
+ if err != nil {
+ return "", err
+ }
+
+ return statusgo.CallPrivateRPC(string(msgJson)), nil
+}
+
+type Config struct {
+ HashedPassword string `json:"hashedPassword"`
+ NodeConfigFile string `json:"nodeConfigFile"`
+ DataDir string `json:"dataDir"`
+}
+
+// processConfigArgs expects that configFilePath points to a JSON file that contains a Config struct
+// For now this are for developer to manually run them using an existing user folder.
+// TODO: ideally we would generate a temporary user folder to be used in the entire suite.
+func processConfigArgs(configFilePath string) (config *Config, nodeConfigJson string, userFolder string, err error) {
+ config = &Config{}
+ // parse config file
+ configFile, err := os.Open(configFilePath)
+ if err != nil {
+ return nil, "", "", err
+ }
+ defer configFile.Close()
+
+ jsonParser := json.NewDecoder(configFile)
+ if err = jsonParser.Decode(&config); err != nil {
+ panic(err)
+ }
+
+ nodeConfigFile, err := os.Open(config.NodeConfigFile)
+ if err != nil {
+ panic(err)
+ }
+ defer nodeConfigFile.Close()
+
+ nodeConfigData, err := io.ReadAll(nodeConfigFile)
+ if err == nil {
+ nodeConfigJson = string(nodeConfigData)
+ }
+
+ userFolder = config.DataDir
+
+ return
+}
+
+func GetCAPIResponse[T any](responseJson string, res T) error {
+ apiResponse := statusgo.APIResponse{}
+ err := json.Unmarshal([]byte(responseJson), &apiResponse)
+ if err == nil {
+ if apiResponse.Error != "" {
+ return fmt.Errorf("API error: %s", apiResponse.Error)
+ }
+ }
+
+ typeOfT := reflect.TypeOf(res)
+ kindOfT := typeOfT.Kind()
+
+ // Check for valid types: pointer, slice, map
+ if kindOfT != reflect.Ptr && kindOfT != reflect.Slice && kindOfT != reflect.Map {
+ return fmt.Errorf("type T must be a pointer, slice, or map")
+ }
+
+ if err := json.Unmarshal([]byte(responseJson), &res); err != nil {
+ return fmt.Errorf("failed to unmarshal data: %w", err)
+ }
+
+ return nil
+}
+
+type jsonrpcSuccessfulResponse struct {
+ jsonrpcMessage
+ Result json.RawMessage `json:"result"`
+}
+
+type jsonrpcErrorResponse struct {
+ jsonrpcMessage
+ Error jsonError `json:"error"`
+}
+
+// jsonError represents Error message for JSON-RPC responses.
+type jsonError struct {
+ Code int `json:"code"`
+ Message string `json:"message"`
+ Data interface{} `json:"data,omitempty"`
+}
+
+func GetRPCAPIResponse[T any](responseJson string, res T) error {
+ errApiResponse := jsonrpcErrorResponse{}
+ err := json.Unmarshal([]byte(responseJson), &errApiResponse)
+ if err == nil && errApiResponse.Error.Code != 0 {
+ return fmt.Errorf("API error: %#v", errApiResponse.Error)
+ }
+
+ apiResponse := jsonrpcSuccessfulResponse{}
+ err = json.Unmarshal([]byte(responseJson), &apiResponse)
+ if err != nil {
+ return fmt.Errorf("failed to unmarshal jsonrpcSuccessfulResponse: %w", err)
+ }
+
+ typeOfT := reflect.TypeOf(res)
+ kindOfT := typeOfT.Kind()
+
+ // Check for valid types: pointer, slice, map
+ if kindOfT != reflect.Ptr && kindOfT != reflect.Slice && kindOfT != reflect.Map {
+ return fmt.Errorf("type T must be a pointer, slice, or map")
+ }
+
+ if err := json.Unmarshal(apiResponse.Result, &res); err != nil {
+ return fmt.Errorf("failed to unmarshal data: %w", err)
+ }
+
+ return nil
+}
diff --git a/test/status-go/integration/integration_tests_config-template.json b/test/status-go/integration/integration_tests_config-template.json
new file mode 100644
index 0000000000..577bfc1915
--- /dev/null
+++ b/test/status-go/integration/integration_tests_config-template.json
@@ -0,0 +1,5 @@
+{
+ "hashedPassword": "0x",
+ "nodeConfigFile": "",
+ "dataDir": ""
+}
\ No newline at end of file
diff --git a/test/status-go/integration/wallet/pendingtransactions_test.go b/test/status-go/integration/wallet/pendingtransactions_test.go
new file mode 100644
index 0000000000..ea032a1ed2
--- /dev/null
+++ b/test/status-go/integration/wallet/pendingtransactions_test.go
@@ -0,0 +1,85 @@
+// These tests are for development only to be run manually
+// There is more work needed to automate them not to depend on an existing account and internet connection
+
+package wallet
+
+import (
+ "math/big"
+ "testing"
+ "time"
+
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/stretchr/testify/require"
+
+ "github.com/ethereum/go-ethereum/common"
+
+ "github.com/status-im/status-desktop/test/status-go/integration/helpers"
+
+ "github.com/status-im/status-go/eth-node/types"
+ "github.com/status-im/status-go/services/wallet/bridge"
+ "github.com/status-im/status-go/services/wallet/transfer"
+ "github.com/status-im/status-go/transactions"
+)
+
+// TestPendingTx_NotificationStatus tests that a pending transaction is created, then updated and finally deleted.
+func TestPendingTx_NotificationStatus(t *testing.T) {
+ eventQueue, conf, _ := helpers.LoginToTestAccount(t)
+
+ _, err := helpers.WaitForEvent(eventQueue, helpers.NodeReadyEvent, 60*time.Second)
+ require.NoError(t, err)
+
+ opAccounts, err := helpers.GetWalletOperableAccounts()
+ require.NoError(t, err)
+ require.Greater(t, len(opAccounts), 0)
+ sender := opAccounts[0]
+
+ watchAccounts, err := helpers.GetWalletWatchOnlyAccounts()
+ require.NoError(t, err)
+ require.Greater(t, len(watchAccounts), 0)
+ recipient := watchAccounts[0]
+
+ mTCommand := transfer.MultiTransactionCommand{
+ FromAddress: common.Address(sender.Address),
+ ToAddress: common.Address(recipient.Address),
+ FromAsset: "ETH",
+ ToAsset: "ETH",
+ FromAmount: (*hexutil.Big)(new(big.Int).SetUint64(100000)),
+ Type: transfer.MultiTransactionSend,
+ }
+ data := []*bridge.TransactionBridge{
+ {
+ BridgeName: "Transfer",
+ ChainID: 5,
+ TransferTx: &transactions.SendTxArgs{
+ From: sender.Address,
+ To: &recipient.Address,
+ Value: (*hexutil.Big)(new(big.Int).Set(mTCommand.FromAmount.ToInt())),
+ },
+ },
+ }
+
+ password := conf.HashedPassword
+
+ // Step 1: send a transaction that will generate a pending entry
+ sessionReqRes, err := helpers.CallPrivateMethod("wallet_createMultiTransaction", []interface{}{mTCommand, data, password})
+ require.NoError(t, err)
+
+ var apiResponse *transfer.MultiTransactionCommandResult
+ err = helpers.GetRPCAPIResponse(sessionReqRes, &apiResponse)
+ require.NoError(t, err)
+ require.Equal(t, 1, len(apiResponse.Hashes))
+
+ // Step 2: wait for the pending entry to be confirmed
+ statusPayload, err := helpers.WaitForWalletEvent[transactions.StatusChangedPayload](eventQueue, transactions.EventPendingTransactionStatusChanged, 60*time.Second)
+ require.NoError(t, err)
+ require.Equal(t, statusPayload.Status, transactions.Success)
+
+ // Step 3: Trigger downloading of the new transaction ...
+ _, err = helpers.CallPrivateMethod("wallet_checkRecentHistoryForChainIDs", []interface{}{[]uint64{5}, []types.Address{sender.Address, recipient.Address}})
+ require.NoError(t, err)
+
+ // ... and wait for the new transaction download to trigger deletion from pending_transactions
+ updatePayload, err := helpers.WaitForWalletEvent[transactions.PendingTxUpdatePayload](eventQueue, transactions.EventPendingTransactionUpdate, 60*time.Second)
+ require.NoError(t, err)
+ require.True(t, updatePayload.Deleted)
+}