diff --git a/Makefile b/Makefile index 10da5430196..243931c88b3 100644 --- a/Makefile +++ b/Makefile @@ -499,3 +499,6 @@ run-integration-tests: run-anvil: SHELL := /bin/sh run-anvil: docker-compose -f integration-tests/docker-compose.anvil.yml up --remove-orphans + +run-integration-anvil: + docker-compose -f integration-tests-anvil/docker-compose.yml up --remove-orphans diff --git a/_assets/scripts/run_unit_tests.sh b/_assets/scripts/run_unit_tests.sh index fd0c13980c1..213d0195ffa 100755 --- a/_assets/scripts/run_unit_tests.sh +++ b/_assets/scripts/run_unit_tests.sh @@ -47,6 +47,9 @@ run_test_for_packages() { local exit_code_file="exit_code_${iteration}.txt" local timeout="$(( single_timeout * count))m" + # exclude integration-tests-anvil package + packages=$(echo "${packages}" | tr ' ' '\n' | grep -v '/integration-tests-anvil$' | tr '\n' ' ') + if [[ "${UNIT_TEST_DRY_RUN}" == 'true' ]]; then echo -e "${GRN}Dry run ${iteration}. message:${RST} ${log_message}\n"\ "${YLW}Dry run ${iteration}. packages:${RST} ${packages}\n"\ diff --git a/api/backend_test.go b/api/backend_test.go index 88d92faea92..5f27e89aebf 100644 --- a/api/backend_test.go +++ b/api/backend_test.go @@ -35,7 +35,7 @@ import ( "github.com/status-im/status-go/rpc" "github.com/status-im/status-go/services/typeddata" "github.com/status-im/status-go/services/wallet" - walletservice "github.com/status-im/status-go/services/wallet" + "github.com/status-im/status-go/services/wallet/common" "github.com/status-im/status-go/signal" "github.com/status-im/status-go/sqlite" "github.com/status-im/status-go/t/helpers" @@ -90,51 +90,39 @@ func setupTestMultiDB() (*multiaccounts.Database, func() error, error) { }, nil } -func setupGethStatusBackend() (*GethStatusBackend, func() error, func() error, func() error, error) { +func setupGethStatusBackend(t *testing.T) (*GethStatusBackend, error) { db, stop1, err := setupTestDB() if err != nil { - return nil, nil, nil, nil, err + return nil, err } backend := NewGethStatusBackend() backend.StatusNode().SetAppDB(db) ma, stop2, err := setupTestMultiDB() if err != nil { - return nil, nil, nil, nil, err + return nil, err } backend.StatusNode().SetMultiaccountsDB(ma) walletDb, stop3, err := setupTestWalletDB() if err != nil { - return nil, nil, nil, nil, err + return nil, err } backend.StatusNode().SetWalletDB(walletDb) - return backend, stop1, stop2, stop3, err + t.Cleanup(func() { + require.NoError(t, stop1()) + require.NoError(t, stop2()) + require.NoError(t, stop3()) + require.NoError(t, backend.StopNode()) + }) + return backend, err } func TestBackendStartNodeConcurrently(t *testing.T) { utils.Init() - backend, stop1, stop2, stop3, err := setupGethStatusBackend() - defer func() { - err := stop1() - if err != nil { - require.NoError(t, backend.StopNode()) - } - }() - defer func() { - err := stop2() - if err != nil { - require.NoError(t, backend.StopNode()) - } - }() - defer func() { - err := stop3() - if err != nil { - require.NoError(t, backend.StopNode()) - } - }() + backend, err := setupGethStatusBackend(t) require.NoError(t, err) config, err := utils.MakeTestNodeConfig(params.StatusChainNetworkID) @@ -171,25 +159,7 @@ func TestBackendStartNodeConcurrently(t *testing.T) { func TestBackendRestartNodeConcurrently(t *testing.T) { utils.Init() - backend, stop1, stop2, stopWallet, err := setupGethStatusBackend() - defer func() { - err := stop1() - if err != nil { - require.NoError(t, backend.StopNode()) - } - }() - defer func() { - err := stop2() - if err != nil { - require.NoError(t, backend.StopNode()) - } - }() - defer func() { - err := stopWallet() - if err != nil { - require.NoError(t, backend.StopNode()) - } - }() + backend, err := setupGethStatusBackend(t) require.NoError(t, err) config, err := utils.MakeTestNodeConfig(params.StatusChainNetworkID) @@ -219,25 +189,7 @@ func TestBackendRestartNodeConcurrently(t *testing.T) { func TestBackendGettersConcurrently(t *testing.T) { utils.Init() - backend, stop1, stop2, stopWallet, err := setupGethStatusBackend() - defer func() { - err := stop1() - if err != nil { - require.NoError(t, backend.StopNode()) - } - }() - defer func() { - err := stop2() - if err != nil { - require.NoError(t, backend.StopNode()) - } - }() - defer func() { - err := stopWallet() - if err != nil { - require.NoError(t, backend.StopNode()) - } - }() + backend, err := setupGethStatusBackend(t) require.NoError(t, err) config, err := utils.MakeTestNodeConfig(params.StatusChainNetworkID) @@ -324,25 +276,7 @@ func TestBackendConnectionChangesToOffline(t *testing.T) { func TestBackendCallRPCConcurrently(t *testing.T) { utils.Init() - backend, stop1, stop2, stopWallet, err := setupGethStatusBackend() - defer func() { - err := stop1() - if err != nil { - require.NoError(t, backend.StopNode()) - } - }() - defer func() { - err := stop2() - if err != nil { - require.NoError(t, backend.StopNode()) - } - }() - defer func() { - err := stopWallet() - if err != nil { - require.NoError(t, backend.StopNode()) - } - }() + backend, err := setupGethStatusBackend(t) require.NoError(t, err) config, err := utils.MakeTestNodeConfig(params.StatusChainNetworkID) @@ -420,25 +354,7 @@ func TestAppStateChange(t *testing.T) { func TestBlockedRPCMethods(t *testing.T) { utils.Init() - backend, stop1, stop2, stopWallet, err := setupGethStatusBackend() - defer func() { - err := stop1() - if err != nil { - require.NoError(t, backend.StopNode()) - } - }() - defer func() { - err := stop2() - if err != nil { - require.NoError(t, backend.StopNode()) - } - }() - defer func() { - err := stopWallet() - if err != nil { - require.NoError(t, backend.StopNode()) - } - }() + backend, err := setupGethStatusBackend(t) require.NoError(t, err) config, err := utils.MakeTestNodeConfig(params.StatusChainNetworkID) @@ -480,25 +396,7 @@ func TestCallRPCWithStoppedNode(t *testing.T) { func TestStartStopMultipleTimes(t *testing.T) { utils.Init() - backend, stop1, stop2, stopWallet, err := setupGethStatusBackend() - defer func() { - err := stop1() - if err != nil { - require.NoError(t, backend.StopNode()) - } - }() - defer func() { - err := stop2() - if err != nil { - require.NoError(t, backend.StopNode()) - } - }() - defer func() { - err := stopWallet() - if err != nil { - require.NoError(t, backend.StopNode()) - } - }() + backend, err := setupGethStatusBackend(t) require.NoError(t, err) config, err := utils.MakeTestNodeConfig(params.StatusChainNetworkID) @@ -519,25 +417,7 @@ func TestStartStopMultipleTimes(t *testing.T) { func TestHashTypedData(t *testing.T) { utils.Init() - backend, stop1, stop2, stopWallet, err := setupGethStatusBackend() - defer func() { - err := stop1() - if err != nil { - require.NoError(t, backend.StopNode()) - } - }() - defer func() { - err := stop2() - if err != nil { - require.NoError(t, backend.StopNode()) - } - }() - defer func() { - err := stopWallet() - if err != nil { - require.NoError(t, backend.StopNode()) - } - }() + backend, err := setupGethStatusBackend(t) require.NoError(t, err) config, err := utils.MakeTestNodeConfig(params.StatusChainNetworkID) @@ -950,7 +830,7 @@ func TestDeleteMultiaccount(t *testing.T) { KeyUID: generateAccount.KeyUID, } - err = backend.ensureAppDBOpened(account, "123123") + err = backend.EnsureAppDBOpened(account, "123123") require.NoError(t, err) s := settings.Settings{ @@ -1031,25 +911,7 @@ func TestConvertAccount(t *testing.T) { utils.Init() - backend, stop1, stop2, stopWallet, err := setupGethStatusBackend() - defer func() { - err := stop1() - if err != nil { - require.NoError(t, backend.StopNode()) - } - }() - defer func() { - err := stop2() - if err != nil { - require.NoError(t, backend.StopNode()) - } - }() - defer func() { - err := stopWallet() - if err != nil { - require.NoError(t, backend.StopNode()) - } - }() + backend, err := setupGethStatusBackend(t) require.NoError(t, err) backend.rootDataDir = rootDataDir @@ -1076,7 +938,7 @@ func TestConvertAccount(t *testing.T) { found = keystoreContainsFileForAccount(keyStoreDir, chatAddress) require.True(t, found) - defaultSettings, err := defaultSettings(genAccInfo.KeyUID, genAccInfo.Address, derivedAccounts) + defaultSettings, err := DefaultSettings(genAccInfo.KeyUID, genAccInfo.Address, derivedAccounts) require.NoError(t, err) nodeConfig, err := DefaultNodeConfig(defaultSettings.InstallationID, &requests.CreateAccount{ LogLevel: defaultSettings.LogLevel, @@ -1135,7 +997,7 @@ func TestConvertAccount(t *testing.T) { KeyUID: profileKeypair.KeyUID, } - err = backend.ensureAppDBOpened(account, password) + err = backend.EnsureAppDBOpened(account, password) require.NoError(t, err) err = backend.StartNodeWithAccountAndInitialConfig(account, password, *defaultSettings, nodeConfig, profileKeypair.Accounts, nil) @@ -1160,7 +1022,7 @@ func TestConvertAccount(t *testing.T) { } // Ensure we're able to open the DB - err = backend.ensureAppDBOpened(keycardAccount, keycardPassword) + err = backend.EnsureAppDBOpened(keycardAccount, keycardPassword) require.NoError(t, err) // db creation @@ -1199,7 +1061,7 @@ func TestConvertAccount(t *testing.T) { }() // Ensure we're able to open the DB - err = backend.ensureAppDBOpened(keycardAccount, keycardPassword) + err = backend.EnsureAppDBOpened(keycardAccount, keycardPassword) require.NoError(t, err) // db creation after re-encryption @@ -1229,7 +1091,7 @@ func TestConvertAccount(t *testing.T) { require.True(t, found) // Ensure we're able to open the DB - err = backend.ensureAppDBOpened(keycardAccount, password) + err = backend.EnsureAppDBOpened(keycardAccount, password) require.NoError(t, err) // db creation after re-encryption @@ -1412,7 +1274,7 @@ func TestCreateWallet(t *testing.T) { walletService := statusNode.WalletService() require.NotNil(t, walletService) - walletAPI := walletservice.NewAPI(walletService) + walletAPI := wallet.NewAPI(walletService) paths := []string{"m/44'/60'/0'/0/1"} @@ -1568,12 +1430,12 @@ func TestWalletConfigOnLoginAccount(t *testing.T) { } require.Equal(t, b.config.WalletConfig.InfuraAPIKey, infuraToken) - require.Equal(t, b.config.WalletConfig.AlchemyAPIKeys[mainnetChainID], alchemyEthereumMainnetToken) - require.Equal(t, b.config.WalletConfig.AlchemyAPIKeys[sepoliaChainID], alchemyEthereumSepoliaToken) - require.Equal(t, b.config.WalletConfig.AlchemyAPIKeys[arbitrumChainID], alchemyArbitrumMainnetToken) - require.Equal(t, b.config.WalletConfig.AlchemyAPIKeys[arbitrumSepoliaChainID], alchemyArbitrumSepoliaToken) - require.Equal(t, b.config.WalletConfig.AlchemyAPIKeys[optimismChainID], alchemyOptimismMainnetToken) - require.Equal(t, b.config.WalletConfig.AlchemyAPIKeys[optimismSepoliaChainID], alchemyOptimismSepoliaToken) + require.Equal(t, b.config.WalletConfig.AlchemyAPIKeys[common.EthereumMainnet], alchemyEthereumMainnetToken) + require.Equal(t, b.config.WalletConfig.AlchemyAPIKeys[common.EthereumSepolia], alchemyEthereumSepoliaToken) + require.Equal(t, b.config.WalletConfig.AlchemyAPIKeys[common.ArbitrumMainnet], alchemyArbitrumMainnetToken) + require.Equal(t, b.config.WalletConfig.AlchemyAPIKeys[common.ArbitrumSepolia], alchemyArbitrumSepoliaToken) + require.Equal(t, b.config.WalletConfig.AlchemyAPIKeys[common.OptimismMainnet], alchemyOptimismMainnetToken) + require.Equal(t, b.config.WalletConfig.AlchemyAPIKeys[common.OptimismSepolia], alchemyOptimismSepoliaToken) require.Equal(t, b.config.WalletConfig.RaribleMainnetAPIKey, raribleMainnetAPIKey) require.Equal(t, b.config.WalletConfig.RaribleTestnetAPIKey, raribleTestnetAPIKey) diff --git a/api/defaults.go b/api/defaults.go index bbcc0c239d8..ab3cfcfed6a 100644 --- a/api/defaults.go +++ b/api/defaults.go @@ -49,7 +49,7 @@ var ( overrideApiConfig = overrideApiConfigProd ) -func defaultSettings(keyUID string, address string, derivedAddresses map[string]generator.AccountInfo) (*settings.Settings, error) { +func DefaultSettings(keyUID string, address string, derivedAddresses map[string]generator.AccountInfo) (*settings.Settings, error) { chatKeyString := derivedAddresses[pathDefaultChat].PublicKey s := &settings.Settings{} diff --git a/api/geth_backend.go b/api/geth_backend.go index 52f88cfea04..166ed11d385 100644 --- a/api/geth_backend.go +++ b/api/geth_backend.go @@ -384,14 +384,14 @@ func (b *GethStatusBackend) ensureDBsOpened(account multiaccounts.Account, passw return err } - if err = b.ensureAppDBOpened(account, password); err != nil { + if err = b.EnsureAppDBOpened(account, password); err != nil { return err } return nil } -func (b *GethStatusBackend) ensureAppDBOpened(account multiaccounts.Account, password string) (err error) { +func (b *GethStatusBackend) EnsureAppDBOpened(account multiaccounts.Account, password string) (err error) { b.mu.Lock() defer b.mu.Unlock() if b.appDB != nil { @@ -1601,7 +1601,7 @@ func (b *GethStatusBackend) buildAccount(request *requests.CreateAccount, input } func (b *GethStatusBackend) prepareSettings(request *requests.CreateAccount, input *prepareAccountInput) (*settings.Settings, error) { - settings, err := defaultSettings(input.keyUID, input.address, input.derivedAddresses) + settings, err := DefaultSettings(input.keyUID, input.address, input.derivedAddresses) if err != nil { return nil, err } diff --git a/api/utils_test.go b/api/utils_test.go index c7d3bc9f4a7..438691102f4 100644 --- a/api/utils_test.go +++ b/api/utils_test.go @@ -16,25 +16,7 @@ import ( func TestHashMessage(t *testing.T) { utils.Init() - backend, stop1, stop2, stopWallet, err := setupGethStatusBackend() - defer func() { - err := stop1() - if err != nil { - require.NoError(t, backend.StopNode()) - } - }() - defer func() { - err := stop2() - if err != nil { - require.NoError(t, backend.StopNode()) - } - }() - defer func() { - err := stopWallet() - if err != nil { - require.NoError(t, backend.StopNode()) - } - }() + backend, err := setupGethStatusBackend(t) require.NoError(t, err) config, err := utils.MakeTestNodeConfig(params.StatusChainNetworkID) diff --git a/integration-tests-anvil/docker-compose.yml b/integration-tests-anvil/docker-compose.yml new file mode 100644 index 00000000000..e3ae60692ed --- /dev/null +++ b/integration-tests-anvil/docker-compose.yml @@ -0,0 +1,17 @@ +services: + anvil: + image: ghcr.io/foundry-rs/foundry:latest + platform: linux/amd64 + command: + - anvil --host 0.0.0.0 --block-time 2 + + go-test: + image: golang:1.21.4 + depends_on: + - anvil + privileged: true + volumes: + - ../:/go/src/github.com/status-im/status-go/ + working_dir: /go/src/github.com/status-im/status-go/api + command: | + go test -tags gowaku_skip_migrations -run ^TestRouterFeesUpdate github.com/status-im/status-go/api/... -v -- -anvil-host=http://anvil:8545 diff --git a/integration-tests-anvil/wallet_router_integration_test.go b/integration-tests-anvil/wallet_router_integration_test.go new file mode 100644 index 00000000000..2083cf5bada --- /dev/null +++ b/integration-tests-anvil/wallet_router_integration_test.go @@ -0,0 +1,391 @@ +package anviltests + +import ( + "database/sql" + "encoding/json" + "io/ioutil" + "math/big" + + "os" + "path/filepath" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/google/uuid" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/status-im/status-go/api" + "github.com/status-im/status-go/appdatabase" + "github.com/status-im/status-go/eth-node/types" + "github.com/status-im/status-go/multiaccounts" + "github.com/status-im/status-go/multiaccounts/accounts" + "github.com/status-im/status-go/params" + "github.com/status-im/status-go/protocol/requests" + walletCommon "github.com/status-im/status-go/services/wallet/common" + walletRequests "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/router" + "github.com/status-im/status-go/services/wallet/router/pathprocessor" + "github.com/status-im/status-go/services/wallet/router/sendtype" + "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" +) + +const testAmount0Point1ETHInWei = 100000000000000000 + +var anvilHost string + +type routerSuggestedRoutesEnvelope struct { + Type string `json:"type"` + Routes responses.RouterSuggestedRoutes `json:"event"` +} + +func initAnvil() { + for _, arg := range os.Args { + if strings.Contains(arg, "anvil-host") { + anvilHost = strings.Split(arg, "=")[1] + break + } + } +} + +func setupSignalHandler(t *testing.T) chan responses.RouterSuggestedRoutes { + suggestedRoutesCh := make(chan responses.RouterSuggestedRoutes) + signalHandler := signal.MobileSignalHandler(func(data []byte) { + var envelope signal.Envelope + err := json.Unmarshal(data, &envelope) + assert.NoError(t, err) + if envelope.Type == string(signal.SuggestedRoutes) { + var response routerSuggestedRoutesEnvelope + err := json.Unmarshal(data, &response) + assert.NoError(t, err) + + suggestedRoutesCh <- response.Routes + } + }) + signal.SetMobileSignalHandler(signalHandler) + + t.Cleanup(func() { + close(suggestedRoutesCh) + signal.ResetMobileSignalHandler() + }) + + return suggestedRoutesCh +} + +func setupTestDB() (*sql.DB, func() error, error) { + return helpers.SetupTestSQLDB(appdatabase.DbInitializer{}, "tests") +} + +func setupTestWalletDB() (*sql.DB, func() error, error) { + return helpers.SetupTestSQLDB(walletdatabase.DbInitializer{}, "tests") +} + +func setupTestMultiDB() (*multiaccounts.Database, func() error, error) { + tmpfile, err := ioutil.TempFile("", "tests") + if err != nil { + return nil, nil, err + } + db, err := multiaccounts.InitializeDB(tmpfile.Name()) + if err != nil { + return nil, nil, err + } + return db, func() error { + err := db.Close() + if err != nil { + return err + } + return os.Remove(tmpfile.Name()) + }, nil +} + +func setupGethStatusBackend(t *testing.T) (*api.GethStatusBackend, error) { + db, stop1, err := setupTestDB() + if err != nil { + return nil, err + } + backend := api.NewGethStatusBackend() + backend.StatusNode().SetAppDB(db) + + ma, stop2, err := setupTestMultiDB() + if err != nil { + return nil, err + } + backend.StatusNode().SetMultiaccountsDB(ma) + + walletDb, stop3, err := setupTestWalletDB() + if err != nil { + return nil, err + } + backend.StatusNode().SetWalletDB(walletDb) + + t.Cleanup(func() { + require.NoError(t, stop1()) + require.NoError(t, stop2()) + require.NoError(t, stop3()) + require.NoError(t, backend.StopNode()) + }) + return backend, err +} + +func setupWalletWithAnvil(t *testing.T, mnemonic string, password string, rootDataDir string) (*api.GethStatusBackend, error) { + initAnvil() + const pathEIP1581Root = "m/43'/60'/1581'" + const pathEIP1581Chat = pathEIP1581Root + "/0'/0" + const pathWalletRoot = "m/44'/60'/0'/0" + const pathDefaultWalletAccount = pathWalletRoot + "/0" + allGeneratedPaths := []string{pathEIP1581Root, pathEIP1581Chat, pathWalletRoot, pathDefaultWalletAccount} + + var err error + + keystoreContainsFileForAccount := func(keyStoreDir string, hexAddress string) bool { + addrWithoutPrefix := strings.ToLower(hexAddress[2:]) + found := false + err = filepath.Walk(keyStoreDir, func(path string, fileInfo os.FileInfo, err error) error { + if err != nil { + return err + } + if !fileInfo.IsDir() && strings.Contains(strings.ToUpper(path), strings.ToUpper(addrWithoutPrefix)) { + found = true + } + return nil + }) + return found + } + + keyStoreDir := filepath.Join(rootDataDir, "keystore") + + utils.Init() + + backend, err := setupGethStatusBackend(t) + require.NoError(t, err) + + backend.UpdateRootDataDir(rootDataDir) + require.NoError(t, backend.AccountManager().InitKeystore(keyStoreDir)) + err = backend.OpenAccounts() + require.NoError(t, err) + + genAccInfo, err := backend.AccountManager().AccountsGenerator().ImportMnemonic(mnemonic, "") + assert.NoError(t, err) + + masterAddress := genAccInfo.Address + + accountInfo, err := backend.AccountManager().AccountsGenerator().StoreAccount(genAccInfo.ID, password) + assert.NoError(t, err) + + found := keystoreContainsFileForAccount(keyStoreDir, accountInfo.Address) + require.True(t, found) + + derivedAccounts, err := backend.AccountManager().AccountsGenerator().StoreDerivedAccounts(genAccInfo.ID, password, allGeneratedPaths) + assert.NoError(t, err) + + chatAddress := derivedAccounts[pathEIP1581Chat].Address + found = keystoreContainsFileForAccount(keyStoreDir, chatAddress) + require.True(t, found) + + defaultSettings, err := api.DefaultSettings(genAccInfo.KeyUID, genAccInfo.Address, derivedAccounts) + require.NoError(t, err) + nodeConfig, err := api.DefaultNodeConfig(defaultSettings.InstallationID, &requests.CreateAccount{ + LogLevel: defaultSettings.LogLevel, + }) + require.NoError(t, err) + nodeConfig.DataDir = rootDataDir + nodeConfig.KeyStoreDir = keyStoreDir + + nodeConfig.NetworkID = 1 + nodeConfig.HTTPEnabled = true + nodeConfig.WalletConfig = params.WalletConfig{ + Enabled: true, + } + nodeConfig.UpstreamConfig = params.UpstreamRPCConfig{ + URL: anvilHost, + Enabled: true, + } + nodeConfig.Networks = []params.Network{ + params.Network{ + ChainID: uint64(31337), + ChainName: "Anvil", + DefaultRPCURL: anvilHost, + RPCURL: anvilHost, + ShortName: "eth", + NativeCurrencyName: "Ether", + NativeCurrencySymbol: "ETH", + NativeCurrencyDecimals: 18, + IsTest: false, + Layer: 1, + Enabled: true, + // RelatedChainID: goerliChainID, + }, + } + + profileKeypair := &accounts.Keypair{ + KeyUID: genAccInfo.KeyUID, + Name: "Profile Name", + Type: accounts.KeypairTypeProfile, + DerivedFrom: masterAddress, + } + + profileKeypair.Accounts = append(profileKeypair.Accounts, &accounts.Account{ + Address: types.HexToAddress(chatAddress), + KeyUID: profileKeypair.KeyUID, + Type: accounts.AccountTypeGenerated, + PublicKey: types.Hex2Bytes(accountInfo.PublicKey), + Path: pathEIP1581Chat, + Wallet: false, + Chat: true, + Name: "GeneratedAccount", + }) + + for p, dAccInfo := range derivedAccounts { + found = keystoreContainsFileForAccount(keyStoreDir, dAccInfo.Address) + require.NoError(t, err) + require.True(t, found) + + if p == pathDefaultWalletAccount { + wAcc := &accounts.Account{ + Address: types.HexToAddress(dAccInfo.Address), + KeyUID: genAccInfo.KeyUID, + Wallet: false, + Chat: false, + Type: accounts.AccountTypeGenerated, + Path: p, + Name: "derivacc" + p, + Hidden: false, + Removed: false, + } + if p == pathDefaultWalletAccount { + wAcc.Wallet = true + } + profileKeypair.Accounts = append(profileKeypair.Accounts, wAcc) + } + } + + account := multiaccounts.Account{ + Name: profileKeypair.Name, + Timestamp: 1, + KeyUID: profileKeypair.KeyUID, + } + + err = backend.EnsureAppDBOpened(account, password) + require.NoError(t, err) + + err = backend.StartNodeWithAccountAndInitialConfig(account, password, *defaultSettings, nodeConfig, profileKeypair.Accounts, nil) + require.NoError(t, err) + + return backend, nil +} + +func TestRouterFeesUpdate(t *testing.T) { + const mnemonic = "test test test test test test test test test test test junk" + const password = "111111" + rootDataDir := t.TempDir() + + backend, err := setupWalletWithAnvil(t, mnemonic, password, rootDataDir) + require.NoError(t, err) + + statusNode := backend.StatusNode() + require.NotNil(t, statusNode) + + walletService := statusNode.WalletService() + require.NotNil(t, walletService) + + rpcClient := walletService.GetRPCClient() + transactor := walletService.GetTransactor() + tokenManager := walletService.GetTokenManager() + ensService := walletService.GetEnsService() + stickersService := walletService.GetStickersService() + + walletRouter := router.NewRouter(rpcClient, transactor, tokenManager, walletService.GetMarketManager(), walletService.GetCollectiblesService(), + walletService.GetCollectiblesManager(), ensService, stickersService) + require.NotNil(t, walletRouter) + defer walletRouter.StopSuggestedRoutesAsyncCalculation() + + transfer := pathprocessor.NewTransferProcessor(rpcClient, transactor) + walletRouter.AddPathProcessor(transfer) + + erc721Transfer := pathprocessor.NewERC721Processor(rpcClient, transactor) + walletRouter.AddPathProcessor(erc721Transfer) + + erc1155Transfer := pathprocessor.NewERC1155Processor(rpcClient, transactor) + walletRouter.AddPathProcessor(erc1155Transfer) + + hop := pathprocessor.NewHopBridgeProcessor(rpcClient, transactor, tokenManager, rpcClient.NetworkManager) + walletRouter.AddPathProcessor(hop) + + paraswap := pathprocessor.NewSwapParaswapProcessor(rpcClient, transactor, tokenManager) + walletRouter.AddPathProcessor(paraswap) + + ensRegister := pathprocessor.NewENSReleaseProcessor(rpcClient, transactor, ensService) + walletRouter.AddPathProcessor(ensRegister) + + ensRelease := pathprocessor.NewENSReleaseProcessor(rpcClient, transactor, ensService) + walletRouter.AddPathProcessor(ensRelease) + + ensPublicKey := pathprocessor.NewENSPublicKeyProcessor(rpcClient, transactor, ensService) + walletRouter.AddPathProcessor(ensPublicKey) + + buyStickers := pathprocessor.NewStickersBuyProcessor(rpcClient, transactor, stickersService) + walletRouter.AddPathProcessor(buyStickers) + + suggestedRoutesCh := setupSignalHandler(t) + + input := &walletRequests.RouteInputParams{ + TestnetMode: false, + Uuid: uuid.NewString(), + SendType: sendtype.Transfer, + AddrFrom: common.HexToAddress("0xa0Ee7A142d267C1f36714E4a8F75612F20a79720"), + AddrTo: common.HexToAddress("0x1"), + AmountIn: (*hexutil.Big)(big.NewInt(testAmount0Point1ETHInWei)), + TokenID: pathprocessor.EthSymbol, + DisabledFromChainIDs: []uint64{walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, + DisabledToChainIDs: []uint64{walletCommon.OptimismMainnet, walletCommon.ArbitrumMainnet}, + + TestsMode: false, + } + + // run the suggested routes calculation and cancel it after initial results are received + receivedResultsCounter := 0 + quitTimer := time.NewTimer(5 * time.Second) + walletRouter.SuggestedRoutesAsync(input) + +loop1: + for { + select { + case asyncRoutes := <-suggestedRoutesCh: + receivedResultsCounter++ + walletRouter.StopSuggestedRoutesAsyncCalculation() + t.Log("canceled, async route uuid", asyncRoutes.Uuid) + case <-quitTimer.C: + break loop1 + } + } + + require.False(t, quitTimer.Stop()) + require.Equal(t, 1, receivedResultsCounter) + + // run the suggested routes calculation and let it finish and check if updates are received + receivedResultsCounter = 0 + quitTimer = time.NewTimer(5 * time.Second) + walletRouter.SuggestedRoutesAsync(input) + +loop2: + for { + select { + case asyncRoutes := <-suggestedRoutesCh: + t.Log("received, async route uuid", asyncRoutes.Uuid) + receivedResultsCounter++ + case <-quitTimer.C: + break loop2 + } + } + + require.False(t, quitTimer.Stop()) + require.Greater(t, receivedResultsCounter, 1) +} diff --git a/integration-tests/docker-compose.anvil.yml b/integration-tests/docker-compose.anvil.yml index 61dc6a1583a..141d8eda175 100644 --- a/integration-tests/docker-compose.anvil.yml +++ b/integration-tests/docker-compose.anvil.yml @@ -3,7 +3,7 @@ services: image: ghcr.io/foundry-rs/foundry:latest platform: linux/amd64 command: - - anvil --host 0.0.0.0 + - anvil --host 0.0.0.0 --block-time 2 deploy-sntv2: platform: linux/amd64 diff --git a/services/wallet/common/const.go b/services/wallet/common/const.go index a3021dc83e8..95341c8a4fe 100644 --- a/services/wallet/common/const.go +++ b/services/wallet/common/const.go @@ -29,6 +29,7 @@ const ( ArbitrumSepolia uint64 = 421614 BinanceChainID uint64 = 56 // obsolete? BinanceTestChainID uint64 = 97 // obsolete? + AnvilMainnet uint64 = 31337 ) var ( diff --git a/services/wallet/router/router_updates.go b/services/wallet/router/router_updates.go index f916c041cc3..e18161e4875 100644 --- a/services/wallet/router/router_updates.go +++ b/services/wallet/router/router_updates.go @@ -10,11 +10,13 @@ import ( ) var ( - newBlockCheckIntervalMainnet = 3 * time.Second - newBlockCheckIntervalOptimism = 1 * time.Second - newBlockCheckIntervalArbitrum = 200 * time.Millisecond + newBlockCheckIntervalMainnet = 3 * time.Second + newBlockCheckIntervalOptimism = 1 * time.Second + newBlockCheckIntervalArbitrum = 200 * time.Millisecond + newBlockCheckIntervalAnvilMainnet = 2 * time.Second - feeRecalculationTimeout = 5 * time.Minute + feeRecalculationTimeout = 5 * time.Minute + feeRecalculationAnvilTimeout = 5 * time.Second ) type fetchingLastBlock struct { @@ -41,7 +43,11 @@ func (r *Router) subscribeForUdates(chainID uint64) error { } r.clientsForUpdatesPerChains.Store(chainID, flb) - r.startTimeoutForUpdates(flb.closeCh) + timeout := feeRecalculationTimeout + if chainID == walletCommon.AnvilMainnet { + timeout = feeRecalculationAnvilTimeout + } + r.startTimeoutForUpdates(flb.closeCh, timeout) var ticker *time.Ticker switch chainID { @@ -51,6 +57,8 @@ func (r *Router) subscribeForUdates(chainID uint64) error { ticker = time.NewTicker(newBlockCheckIntervalOptimism) case walletCommon.ArbitrumMainnet: ticker = time.NewTicker(newBlockCheckIntervalArbitrum) + case walletCommon.AnvilMainnet: + ticker = time.NewTicker(newBlockCheckIntervalAnvilMainnet) } ctx, cancelCtx := context.WithCancel(context.Background()) @@ -118,8 +126,8 @@ func (r *Router) subscribeForUdates(chainID uint64) error { return nil } -func (r *Router) startTimeoutForUpdates(closeCh chan struct{}) { - dedlineTicker := time.NewTicker(feeRecalculationTimeout) +func (r *Router) startTimeoutForUpdates(closeCh chan struct{}, timeout time.Duration) { + dedlineTicker := time.NewTicker(timeout) go func() { for { select {