github.com/status-im/status-go@v1.1.0/multiaccounts/accounts/database_test.go (about)

     1  package accounts
     2  
     3  import (
     4  	"database/sql"
     5  	"encoding/json"
     6  	"fmt"
     7  	"testing"
     8  
     9  	"github.com/stretchr/testify/require"
    10  
    11  	"github.com/status-im/status-go/appdatabase"
    12  	"github.com/status-im/status-go/eth-node/types"
    13  	"github.com/status-im/status-go/multiaccounts/common"
    14  	"github.com/status-im/status-go/multiaccounts/settings"
    15  	"github.com/status-im/status-go/params"
    16  	"github.com/status-im/status-go/t/helpers"
    17  )
    18  
    19  func setupTestDB(t *testing.T) (*Database, func()) {
    20  	db, stop, err := helpers.SetupTestSQLDB(appdatabase.DbInitializer{}, "settings-tests-")
    21  	require.NoError(t, err)
    22  	d, err := NewDB(db)
    23  	require.NoError(t, err)
    24  	return d, func() { require.NoError(t, stop()) }
    25  }
    26  
    27  func TestGetAddresses(t *testing.T) {
    28  	db, stop := setupTestDB(t)
    29  	defer stop()
    30  	accounts := []*Account{
    31  		{Address: types.Address{0x01}, Chat: true, Wallet: true},
    32  		{Address: types.Address{0x02}},
    33  	}
    34  	require.NoError(t, db.SaveOrUpdateAccounts(accounts, false))
    35  	addresses, err := db.GetAddresses()
    36  	require.NoError(t, err)
    37  	require.Equal(t, []types.Address{{0x01}, {0x02}}, addresses)
    38  }
    39  
    40  func TestMoveWalletAccount(t *testing.T) {
    41  	db, stop := setupTestDB(t)
    42  	defer stop()
    43  
    44  	networks := json.RawMessage("{}")
    45  	setting := settings.Settings{
    46  		Networks: &networks,
    47  	}
    48  	config := params.NodeConfig{}
    49  	err := db.CreateSettings(setting, config)
    50  	require.NoError(t, err)
    51  
    52  	accounts := []*Account{
    53  		{Address: types.Address{0x01}, Type: AccountTypeWatch, Position: 0},
    54  		{Address: types.Address{0x02}, Type: AccountTypeWatch, Position: 1},
    55  		{Address: types.Address{0x03}, Type: AccountTypeWatch, Position: 2},
    56  		{Address: types.Address{0x04}, Type: AccountTypeWatch, Position: 3},
    57  		{Address: types.Address{0x05}, Type: AccountTypeWatch, Position: 4},
    58  		{Address: types.Address{0x06}, Type: AccountTypeWatch, Position: 5},
    59  	}
    60  	require.NoError(t, db.SaveOrUpdateAccounts(accounts, false))
    61  	dbAccounts, err := db.GetActiveAccounts()
    62  	require.NoError(t, err)
    63  	require.Len(t, dbAccounts, len(accounts))
    64  	for i := 0; i < len(accounts); i++ {
    65  		require.True(t, SameAccounts(accounts[i], dbAccounts[i]))
    66  	}
    67  
    68  	clock := uint64(1000)
    69  	err = db.MoveWalletAccount(-1, 4, clock)
    70  	require.ErrorIs(t, err, ErrMovingAccountToWrongPosition)
    71  	err = db.MoveWalletAccount(4, -1, clock)
    72  	require.ErrorIs(t, err, ErrMovingAccountToWrongPosition)
    73  	err = db.MoveWalletAccount(4, 4, clock)
    74  	require.ErrorIs(t, err, ErrMovingAccountToWrongPosition)
    75  
    76  	// Move down account from position 1 to position 4
    77  	err = db.MoveWalletAccount(1, 4, clock)
    78  	require.NoError(t, err)
    79  
    80  	// Expected after moving down
    81  	accounts = []*Account{
    82  		{Address: types.Address{0x01}, Type: AccountTypeWatch, Position: 0},
    83  		{Address: types.Address{0x03}, Type: AccountTypeWatch, Position: 1},
    84  		{Address: types.Address{0x04}, Type: AccountTypeWatch, Position: 2},
    85  		{Address: types.Address{0x05}, Type: AccountTypeWatch, Position: 3},
    86  		{Address: types.Address{0x02}, Type: AccountTypeWatch, Position: 4}, // acc with addr 0x02 is at position 4 (moved from position 1)
    87  		{Address: types.Address{0x06}, Type: AccountTypeWatch, Position: 5},
    88  	}
    89  
    90  	dbAccounts, err = db.GetActiveAccounts()
    91  	require.NoError(t, err)
    92  	for i := 0; i < len(accounts); i++ {
    93  		require.True(t, SameAccounts(accounts[i], dbAccounts[i]))
    94  	}
    95  
    96  	// Check clock
    97  	dbClock, err := db.GetClockOfLastAccountsPositionChange()
    98  	require.NoError(t, err)
    99  	require.Equal(t, clock, dbClock)
   100  
   101  	// Move up account from position 5 to position 0
   102  	clock = 2000
   103  	err = db.MoveWalletAccount(5, 0, clock)
   104  	require.NoError(t, err)
   105  
   106  	// Expected after moving up
   107  	accounts = []*Account{
   108  		{Address: types.Address{0x06}, Type: AccountTypeWatch, Position: 0}, // acc with addr 0x06 is at position 0 (moved from position 5)
   109  		{Address: types.Address{0x01}, Type: AccountTypeWatch, Position: 1},
   110  		{Address: types.Address{0x03}, Type: AccountTypeWatch, Position: 2},
   111  		{Address: types.Address{0x04}, Type: AccountTypeWatch, Position: 3},
   112  		{Address: types.Address{0x05}, Type: AccountTypeWatch, Position: 4},
   113  		{Address: types.Address{0x02}, Type: AccountTypeWatch, Position: 5},
   114  	}
   115  
   116  	dbAccounts, err = db.GetActiveAccounts()
   117  	require.NoError(t, err)
   118  	for i := 0; i < len(accounts); i++ {
   119  		require.True(t, SameAccounts(accounts[i], dbAccounts[i]))
   120  	}
   121  
   122  	// Check clock
   123  	dbClock, err = db.GetClockOfLastAccountsPositionChange()
   124  	require.NoError(t, err)
   125  	require.Equal(t, clock, dbClock)
   126  }
   127  
   128  func TestGetWalletAddress(t *testing.T) {
   129  	db, stop := setupTestDB(t)
   130  	defer stop()
   131  	address := types.Address{0x01}
   132  	_, err := db.GetWalletAddress()
   133  	require.Equal(t, err, sql.ErrNoRows)
   134  	require.NoError(t, db.SaveOrUpdateAccounts([]*Account{{Address: address, Wallet: true}}, false))
   135  	wallet, err := db.GetWalletAddress()
   136  	require.NoError(t, err)
   137  	require.Equal(t, address, wallet)
   138  }
   139  
   140  func TestGetChatAddress(t *testing.T) {
   141  	db, stop := setupTestDB(t)
   142  	defer stop()
   143  	address := types.Address{0x01}
   144  	_, err := db.GetChatAddress()
   145  	require.Equal(t, err, sql.ErrNoRows)
   146  	require.NoError(t, db.SaveOrUpdateAccounts([]*Account{{Address: address, Chat: true}}, false))
   147  	chat, err := db.GetChatAddress()
   148  	require.NoError(t, err)
   149  	require.Equal(t, address, chat)
   150  }
   151  
   152  func TestAddressExists(t *testing.T) {
   153  	db, stop := setupTestDB(t)
   154  	defer stop()
   155  
   156  	accounts := []*Account{
   157  		{Address: types.Address{0x01}, Chat: true, Wallet: true},
   158  	}
   159  	require.NoError(t, db.SaveOrUpdateAccounts(accounts, false))
   160  
   161  	exists, err := db.AddressExists(accounts[0].Address)
   162  	require.NoError(t, err)
   163  	require.True(t, exists)
   164  }
   165  
   166  func TestAddressDoesntExist(t *testing.T) {
   167  	db, stop := setupTestDB(t)
   168  	defer stop()
   169  	exists, err := db.AddressExists(types.Address{1, 1, 1})
   170  	require.NoError(t, err)
   171  	require.False(t, exists)
   172  }
   173  
   174  func TestWatchOnlyAccounts(t *testing.T) {
   175  	db, stop := setupTestDB(t)
   176  	defer stop()
   177  
   178  	// check the db
   179  	dbAccounts, err := db.GetActiveAccounts()
   180  	require.NoError(t, err)
   181  	require.Equal(t, 0, len(dbAccounts))
   182  
   183  	woAccounts := GetWatchOnlyAccountsForTest()
   184  
   185  	// try to save keypair with watch only accounts
   186  	kp := &Keypair{}
   187  	kp.Accounts = append(kp.Accounts, woAccounts...)
   188  	err = db.SaveOrUpdateKeypair(kp)
   189  	require.Error(t, err)
   190  
   191  	// check the db after that trying to save keypair with watch only accounts
   192  	dbAccounts, err = db.GetActiveAccounts()
   193  	require.NoError(t, err)
   194  	require.Equal(t, 0, len(dbAccounts))
   195  
   196  	// save watch only accounts
   197  	err = db.SaveOrUpdateAccounts(woAccounts, false)
   198  	require.NoError(t, err)
   199  	_, err = db.GetKeypairByKeyUID(woAccounts[0].KeyUID)
   200  	require.Error(t, err)
   201  	require.True(t, err == ErrDbKeypairNotFound)
   202  	dbAccounts, err = db.GetActiveAccounts()
   203  	require.NoError(t, err)
   204  	require.Equal(t, len(woAccounts), len(dbAccounts))
   205  	require.Equal(t, woAccounts[0].Address, dbAccounts[0].Address)
   206  
   207  	// try to save the same watch only account again
   208  	err = db.SaveOrUpdateAccounts(woAccounts[:1], false)
   209  	require.NoError(t, err)
   210  	dbAccounts, err = db.GetActiveAccounts()
   211  	require.NoError(t, err)
   212  	require.Equal(t, len(woAccounts), len(dbAccounts))
   213  	dbAcc, err := db.GetAccountByAddress(woAccounts[:1][0].Address)
   214  	require.NoError(t, err)
   215  	require.Equal(t, woAccounts[:1][0].Address, dbAcc.Address)
   216  
   217  	// try to save new watch only account
   218  	wo4 := &Account{
   219  		Address: types.Address{0x14},
   220  		Type:    AccountTypeWatch,
   221  		Name:    "WatchOnlyAcc4",
   222  		ColorID: common.CustomizationColorPrimary,
   223  		Emoji:   "emoji-1",
   224  	}
   225  	err = db.SaveOrUpdateAccounts([]*Account{wo4}, false)
   226  	require.NoError(t, err)
   227  	dbAccounts, err = db.GetActiveAccounts()
   228  	require.NoError(t, err)
   229  	require.Equal(t, len(woAccounts)+1, len(dbAccounts))
   230  	dbAcc, err = db.GetAccountByAddress(wo4.Address)
   231  	require.NoError(t, err)
   232  	require.Equal(t, wo4.Address, dbAcc.Address)
   233  
   234  	// updated watch onl to save the same account after it's saved
   235  	wo4.Name = wo4.Name + "updated"
   236  	wo4.ColorID = common.CustomizationColorCamel
   237  	wo4.Emoji = wo4.Emoji + "updated"
   238  	err = db.SaveOrUpdateAccounts([]*Account{wo4}, false)
   239  	require.NoError(t, err)
   240  	dbAccounts, err = db.GetActiveAccounts()
   241  	require.NoError(t, err)
   242  	require.Equal(t, len(woAccounts)+1, len(dbAccounts))
   243  	dbAcc, err = db.GetAccountByAddress(wo4.Address)
   244  	require.NoError(t, err)
   245  	require.Equal(t, wo4.Address, dbAcc.Address)
   246  
   247  	// try to delete keypair for watch only account
   248  	err = db.RemoveKeypair(wo4.KeyUID, 0)
   249  	require.Error(t, err)
   250  	require.True(t, err == ErrDbKeypairNotFound)
   251  
   252  	// try to delete watch only account
   253  	err = db.RemoveAccount(wo4.Address, 0)
   254  	require.NoError(t, err)
   255  	dbAccounts, err = db.GetActiveAccounts()
   256  	require.NoError(t, err)
   257  	require.Equal(t, len(woAccounts), len(dbAccounts))
   258  	_, err = db.GetAccountByAddress(wo4.Address)
   259  	require.Error(t, err)
   260  	require.True(t, err == ErrDbAccountNotFound)
   261  }
   262  
   263  func TestUpdateKeypairName(t *testing.T) {
   264  	db, stop := setupTestDB(t)
   265  	defer stop()
   266  
   267  	kp := GetProfileKeypairForTest(true, false, false)
   268  
   269  	// check the db
   270  	dbAccounts, err := db.GetActiveAccounts()
   271  	require.NoError(t, err)
   272  	require.Equal(t, 0, len(dbAccounts))
   273  
   274  	// save keypair
   275  	err = db.SaveOrUpdateKeypair(kp)
   276  	require.NoError(t, err)
   277  	dbKeypairs, err := db.GetActiveKeypairs()
   278  	require.NoError(t, err)
   279  	require.Equal(t, 1, len(dbKeypairs))
   280  	require.True(t, SameKeypairs(kp, dbKeypairs[0]))
   281  
   282  	// update keypair name
   283  	kp.Name = kp.Name + "updated"
   284  	kp.Accounts[0].Name = kp.Name
   285  	err = db.UpdateKeypairName(kp.KeyUID, kp.Name, kp.Clock, true)
   286  	require.NoError(t, err)
   287  
   288  	// check keypair
   289  	dbKp, err := db.GetKeypairByKeyUID(kp.KeyUID)
   290  	require.NoError(t, err)
   291  	require.Equal(t, len(kp.Accounts), len(dbKp.Accounts))
   292  	require.True(t, SameKeypairs(kp, dbKp))
   293  }
   294  
   295  func TestKeypairs(t *testing.T) {
   296  	keypairs := []*Keypair{
   297  		GetProfileKeypairForTest(true, true, true),
   298  		GetSeedImportedKeypair1ForTest(),
   299  		GetPrivKeyImportedKeypairForTest(), // in this context (when testing db functions) there is not limitations for private key imported keypair
   300  	}
   301  
   302  	for _, kp := range keypairs {
   303  		t.Run("test keypair "+kp.Name, func(t *testing.T) {
   304  			db, stop := setupTestDB(t)
   305  			defer stop()
   306  
   307  			// check the db
   308  			dbKeypairs, err := db.GetActiveKeypairs()
   309  			require.NoError(t, err)
   310  			require.Equal(t, 0, len(dbKeypairs))
   311  			dbAccounts, err := db.GetActiveAccounts()
   312  			require.NoError(t, err)
   313  			require.Equal(t, 0, len(dbAccounts))
   314  
   315  			expectedLastUsedDerivationIndex := uint64(len(kp.Accounts) - 1)
   316  			if kp.Type == KeypairTypeProfile {
   317  				expectedLastUsedDerivationIndex-- // subtract one more in case of profile keypair because of chat account
   318  			}
   319  
   320  			// save keypair
   321  			err = db.SaveOrUpdateKeypair(kp)
   322  			require.NoError(t, err)
   323  			dbKeypairs, err = db.GetActiveKeypairs()
   324  			require.NoError(t, err)
   325  			require.Equal(t, 1, len(dbKeypairs))
   326  			dbKp, err := db.GetKeypairByKeyUID(kp.KeyUID)
   327  			require.NoError(t, err)
   328  			require.Equal(t, len(kp.Accounts), len(dbKp.Accounts))
   329  			kp.LastUsedDerivationIndex = expectedLastUsedDerivationIndex
   330  			require.Equal(t, kp.KeyUID, dbKp.KeyUID)
   331  			dbAccounts, err = db.GetActiveAccounts()
   332  			require.NoError(t, err)
   333  			require.Equal(t, len(kp.Accounts), len(dbAccounts))
   334  
   335  			// delete keypair
   336  			err = db.RemoveKeypair(kp.KeyUID, 0)
   337  			require.NoError(t, err)
   338  			_, err = db.GetKeypairByKeyUID(kp.KeyUID)
   339  			require.Error(t, err)
   340  			require.True(t, err == ErrDbKeypairNotFound)
   341  
   342  			// save keypair again to test the flow below
   343  			err = db.SaveOrUpdateKeypair(kp)
   344  			require.NoError(t, err)
   345  			dbKeypairs, err = db.GetActiveKeypairs()
   346  			require.NoError(t, err)
   347  			require.Equal(t, 1, len(dbKeypairs))
   348  
   349  			ind := len(kp.Accounts) - 1
   350  			accToUpdate := kp.Accounts[ind]
   351  
   352  			// try to save the same account again
   353  			err = db.SaveOrUpdateAccounts([]*Account{accToUpdate}, false)
   354  			require.NoError(t, err)
   355  			dbKp, err = db.GetKeypairByKeyUID(kp.KeyUID)
   356  			require.NoError(t, err)
   357  			require.Equal(t, len(kp.Accounts), len(dbKp.Accounts))
   358  			require.Equal(t, kp.KeyUID, dbKp.KeyUID)
   359  			dbAccounts, err = db.GetActiveAccounts()
   360  			require.NoError(t, err)
   361  			require.Equal(t, len(kp.Accounts), len(dbAccounts))
   362  
   363  			// update an existing account
   364  			accToUpdate.Name = accToUpdate.Name + "updated"
   365  			accToUpdate.ColorID = common.CustomizationColorBrown
   366  			accToUpdate.Emoji = accToUpdate.Emoji + "updated"
   367  
   368  			err = db.SaveOrUpdateAccounts([]*Account{accToUpdate}, false)
   369  			require.NoError(t, err)
   370  			dbKp, err = db.GetKeypairByKeyUID(kp.KeyUID)
   371  			require.NoError(t, err)
   372  			require.Equal(t, len(kp.Accounts), len(dbKp.Accounts))
   373  			dbAccounts, err = db.GetActiveAccounts()
   374  			require.NoError(t, err)
   375  			require.Equal(t, len(kp.Accounts), len(dbAccounts))
   376  			dbAcc, err := db.GetAccountByAddress(accToUpdate.Address)
   377  			require.NoError(t, err)
   378  			require.Equal(t, accToUpdate.Address, dbAcc.Address)
   379  
   380  			// update keypair name
   381  			kpToUpdate := kp
   382  			kpToUpdate.Name = kpToUpdate.Name + "updated"
   383  			err = db.SaveOrUpdateKeypair(kp)
   384  			require.NoError(t, err)
   385  			dbKeypairs, err = db.GetActiveKeypairs()
   386  			require.NoError(t, err)
   387  			require.Equal(t, 1, len(dbKeypairs))
   388  			dbKp, err = db.GetKeypairByKeyUID(kp.KeyUID)
   389  			require.NoError(t, err)
   390  			require.Equal(t, len(kp.Accounts), len(dbKp.Accounts))
   391  			require.Equal(t, kpToUpdate.KeyUID, dbKp.KeyUID)
   392  
   393  			// save new account to an existing keypair which is out of the default Status' derivation root path
   394  			accToAdd := kp.Accounts[ind]
   395  			accToAdd.Address = types.Address{0x08}
   396  			accToAdd.Path = "m/44'/60'/0'/0/10"
   397  			accToAdd.PublicKey = types.Hex2Bytes("0x000000008")
   398  			accToAdd.Name = "Generated Acc 8"
   399  
   400  			err = db.SaveOrUpdateAccounts([]*Account{accToAdd}, false)
   401  			require.NoError(t, err)
   402  			dbKp, err = db.GetKeypairByKeyUID(kp.KeyUID)
   403  			require.NoError(t, err)
   404  			require.Equal(t, len(kp.Accounts)+1, len(dbKp.Accounts))
   405  			require.Equal(t, kp.LastUsedDerivationIndex, dbKp.LastUsedDerivationIndex)
   406  			dbAccounts, err = db.GetActiveAccounts()
   407  			require.NoError(t, err)
   408  			require.Equal(t, len(kp.Accounts)+1, len(dbAccounts))
   409  			dbAcc, err = db.GetAccountByAddress(accToUpdate.Address)
   410  			require.NoError(t, err)
   411  			require.Equal(t, accToAdd.Address, dbAcc.Address)
   412  
   413  			// save new account to an existing keypair which follows Status' default derivation root path
   414  			accToAdd = kp.Accounts[ind]
   415  			accToAdd.Address = types.Address{0x09}
   416  			accToAdd.Path = "m/44'/60'/0'/0/3"
   417  			accToAdd.PublicKey = types.Hex2Bytes("0x000000009")
   418  			accToAdd.Name = "Generated Acc 9"
   419  
   420  			expectedLastUsedDerivationIndex = 3
   421  			if kp.Type == KeypairTypeSeed {
   422  				accToAdd.Path = "m/44'/60'/0'/0/2"
   423  				expectedLastUsedDerivationIndex = 2
   424  			} else if kp.Type == KeypairTypeKey {
   425  				accToAdd.Path = "m/44'/60'/0'/0/1"
   426  				expectedLastUsedDerivationIndex = 1
   427  			}
   428  
   429  			err = db.SaveOrUpdateAccounts([]*Account{accToAdd}, false)
   430  			require.NoError(t, err)
   431  			dbKp, err = db.GetKeypairByKeyUID(kp.KeyUID)
   432  			require.NoError(t, err)
   433  			require.Equal(t, len(kp.Accounts)+2, len(dbKp.Accounts))
   434  			require.Equal(t, expectedLastUsedDerivationIndex, dbKp.LastUsedDerivationIndex)
   435  			dbAccounts, err = db.GetActiveAccounts()
   436  			require.NoError(t, err)
   437  			require.Equal(t, len(kp.Accounts)+2, len(dbAccounts))
   438  			dbAcc, err = db.GetAccountByAddress(accToUpdate.Address)
   439  			require.NoError(t, err)
   440  			require.Equal(t, accToAdd.Address, dbAcc.Address)
   441  
   442  			// delete account
   443  			err = db.RemoveAccount(accToAdd.Address, 0)
   444  			require.NoError(t, err)
   445  			dbAccounts, err = db.GetActiveAccounts()
   446  			require.NoError(t, err)
   447  			require.Equal(t, len(kp.Accounts)+1, len(dbAccounts))
   448  			_, err = db.GetAccountByAddress(accToAdd.Address)
   449  			require.Error(t, err)
   450  			require.True(t, err == ErrDbAccountNotFound)
   451  
   452  			for _, acc := range dbAccounts {
   453  				err = db.RemoveAccount(acc.Address, 0)
   454  				require.NoError(t, err)
   455  			}
   456  
   457  			_, err = db.GetKeypairByKeyUID(kp.KeyUID)
   458  			require.Error(t, err)
   459  			require.True(t, err == ErrDbKeypairNotFound)
   460  		})
   461  	}
   462  }
   463  
   464  func TestResolvingSuggestedDerivationPath(t *testing.T) {
   465  	kp := GetProfileKeypairForTest(true, true, true)
   466  	totalNumOfAccounts := len(kp.Accounts)
   467  
   468  	db, stop := setupTestDB(t)
   469  	defer stop()
   470  
   471  	// check the db
   472  	dbKp, err := db.GetKeypairByKeyUID(kp.KeyUID)
   473  	require.Error(t, err)
   474  	require.True(t, err == ErrDbKeypairNotFound)
   475  	require.Nil(t, dbKp)
   476  
   477  	expectedLastUsedDerivationIndex := uint64(2)
   478  
   479  	// save keypair
   480  	err = db.SaveOrUpdateKeypair(kp)
   481  	require.NoError(t, err)
   482  	dbKp, err = db.GetKeypairByKeyUID(kp.KeyUID)
   483  	require.NoError(t, err)
   484  	require.Equal(t, totalNumOfAccounts, len(dbKp.Accounts))
   485  	require.Equal(t, expectedLastUsedDerivationIndex, dbKp.LastUsedDerivationIndex)
   486  
   487  	// check number of addresses to generate
   488  	numOfAddresses, err := db.GetNumOfAddressesToGenerateForKeypair(kp.KeyUID)
   489  	require.NoError(t, err)
   490  	require.Equal(t, maxNumOfGeneratedAddresses, numOfAddresses)
   491  
   492  	// check suggested path
   493  	suggestedPath, err := db.ResolveSuggestedPathForKeypair(kp.KeyUID)
   494  	require.NoError(t, err)
   495  	require.Equal(t, fmt.Sprintf("%s%d", statusWalletRootPath, expectedLastUsedDerivationIndex+1), suggestedPath)
   496  
   497  	// prepare new account with the next suggested path
   498  	generatedWalletAccountThatWillBeRemovedLater := &Account{
   499  		Address:               types.Address{0x05},
   500  		KeyUID:                kp.KeyUID,
   501  		Wallet:                false,
   502  		Chat:                  false,
   503  		Type:                  AccountTypeGenerated,
   504  		Path:                  suggestedPath,
   505  		PublicKey:             types.Hex2Bytes("0x000000005"),
   506  		Name:                  "Generated Acc 4",
   507  		Emoji:                 "emoji-4",
   508  		ColorID:               common.CustomizationColorPrimary,
   509  		Hidden:                false,
   510  		Clock:                 0,
   511  		Removed:               false,
   512  		Operable:              AccountFullyOperable,
   513  		ProdPreferredChainIDs: "1",
   514  		TestPreferredChainIDs: "5",
   515  	}
   516  
   517  	// add new account with the next suggested path
   518  	err = db.SaveOrUpdateAccounts([]*Account{generatedWalletAccountThatWillBeRemovedLater}, false)
   519  	require.NoError(t, err)
   520  
   521  	totalNumOfAccounts++
   522  	expectedLastUsedDerivationIndex++
   523  
   524  	dbKp, err = db.GetKeypairByKeyUID(kp.KeyUID)
   525  	require.NoError(t, err)
   526  	require.Equal(t, totalNumOfAccounts, len(dbKp.Accounts))
   527  	require.Equal(t, expectedLastUsedDerivationIndex, dbKp.LastUsedDerivationIndex)
   528  
   529  	// check suggested path
   530  	suggestedPath, err = db.ResolveSuggestedPathForKeypair(kp.KeyUID)
   531  	require.NoError(t, err)
   532  	require.Equal(t, fmt.Sprintf("%s%d", statusWalletRootPath, expectedLastUsedDerivationIndex+1), suggestedPath)
   533  
   534  	customSuggestedPath := fmt.Sprintf("%s%d", statusWalletRootPath, expectedLastUsedDerivationIndex+1+1)
   535  
   536  	// prepare new account with the custom suggested path
   537  	generatedWalletAccount := &Account{
   538  		Address:               types.Address{0x07},
   539  		KeyUID:                kp.KeyUID,
   540  		Wallet:                false,
   541  		Chat:                  false,
   542  		Type:                  AccountTypeGenerated,
   543  		Path:                  customSuggestedPath,
   544  		PublicKey:             types.Hex2Bytes("0x000000007"),
   545  		Name:                  "Generated Acc 6",
   546  		Emoji:                 "emoji-6",
   547  		ColorID:               common.CustomizationColorPrimary,
   548  		Hidden:                false,
   549  		Clock:                 0,
   550  		Removed:               false,
   551  		Operable:              AccountFullyOperable,
   552  		ProdPreferredChainIDs: "1",
   553  		TestPreferredChainIDs: "5",
   554  	}
   555  
   556  	// add new account with the next suggested path
   557  	err = db.SaveOrUpdateAccounts([]*Account{generatedWalletAccount}, false)
   558  	require.NoError(t, err)
   559  
   560  	totalNumOfAccounts++
   561  
   562  	dbKp, err = db.GetKeypairByKeyUID(kp.KeyUID)
   563  	require.NoError(t, err)
   564  	require.Equal(t, totalNumOfAccounts, len(dbKp.Accounts))
   565  	require.Equal(t, expectedLastUsedDerivationIndex, dbKp.LastUsedDerivationIndex)
   566  
   567  	// check suggested path
   568  	suggestedPath, err = db.ResolveSuggestedPathForKeypair(kp.KeyUID)
   569  	require.NoError(t, err)
   570  	require.Equal(t, fmt.Sprintf("%s%d", statusWalletRootPath, expectedLastUsedDerivationIndex+1), suggestedPath)
   571  
   572  	// prepare new account with the next suggested path
   573  	generatedWalletAccount = &Account{
   574  		Address:               types.Address{0x06},
   575  		KeyUID:                kp.KeyUID,
   576  		Wallet:                false,
   577  		Chat:                  false,
   578  		Type:                  AccountTypeGenerated,
   579  		Path:                  suggestedPath,
   580  		PublicKey:             types.Hex2Bytes("0x000000006"),
   581  		Name:                  "Generated Acc 5",
   582  		Emoji:                 "emoji-5",
   583  		ColorID:               common.CustomizationColorPrimary,
   584  		Hidden:                false,
   585  		Clock:                 0,
   586  		Removed:               false,
   587  		Operable:              AccountFullyOperable,
   588  		ProdPreferredChainIDs: "1",
   589  		TestPreferredChainIDs: "5",
   590  	}
   591  
   592  	// add new account with the next suggested path
   593  	err = db.SaveOrUpdateAccounts([]*Account{generatedWalletAccount}, false)
   594  	require.NoError(t, err)
   595  
   596  	totalNumOfAccounts++
   597  	expectedLastUsedDerivationIndex++
   598  
   599  	dbKp, err = db.GetKeypairByKeyUID(kp.KeyUID)
   600  	require.NoError(t, err)
   601  	require.Equal(t, totalNumOfAccounts, len(dbKp.Accounts))
   602  	require.Equal(t, expectedLastUsedDerivationIndex, dbKp.LastUsedDerivationIndex)
   603  
   604  	// check suggested path
   605  	suggestedPath, err = db.ResolveSuggestedPathForKeypair(kp.KeyUID)
   606  	require.NoError(t, err)
   607  	require.Equal(t, fmt.Sprintf("%s%d", statusWalletRootPath, expectedLastUsedDerivationIndex+2), suggestedPath)
   608  
   609  	// prepare new account with the next suggested path
   610  	generatedWalletAccount = &Account{
   611  		Address:               types.Address{0x08},
   612  		KeyUID:                kp.KeyUID,
   613  		Wallet:                false,
   614  		Chat:                  false,
   615  		Type:                  AccountTypeGenerated,
   616  		Path:                  suggestedPath,
   617  		PublicKey:             types.Hex2Bytes("0x000000008"),
   618  		Name:                  "Generated Acc 7",
   619  		Emoji:                 "emoji-7",
   620  		ColorID:               common.CustomizationColorPrimary,
   621  		Hidden:                false,
   622  		Clock:                 0,
   623  		Removed:               false,
   624  		Operable:              AccountFullyOperable,
   625  		ProdPreferredChainIDs: "1",
   626  		TestPreferredChainIDs: "5",
   627  	}
   628  
   629  	// add new account with the next suggested path
   630  	err = db.SaveOrUpdateAccounts([]*Account{generatedWalletAccount}, false)
   631  	require.NoError(t, err)
   632  
   633  	totalNumOfAccounts++
   634  	expectedLastUsedDerivationIndex += 2
   635  
   636  	dbKp, err = db.GetKeypairByKeyUID(kp.KeyUID)
   637  	require.NoError(t, err)
   638  	require.Equal(t, totalNumOfAccounts, len(dbKp.Accounts))
   639  	require.Equal(t, expectedLastUsedDerivationIndex, dbKp.LastUsedDerivationIndex)
   640  
   641  	// check suggested path
   642  	suggestedPath, err = db.ResolveSuggestedPathForKeypair(kp.KeyUID)
   643  	require.NoError(t, err)
   644  	require.Equal(t, fmt.Sprintf("%s%d", statusWalletRootPath, expectedLastUsedDerivationIndex+1), suggestedPath)
   645  
   646  	// remove account
   647  	err = db.RemoveAccount(generatedWalletAccountThatWillBeRemovedLater.Address, 0)
   648  	require.NoError(t, err)
   649  
   650  	totalNumOfAccounts--
   651  
   652  	dbKp, err = db.GetKeypairByKeyUID(kp.KeyUID)
   653  	require.NoError(t, err)
   654  	require.Equal(t, totalNumOfAccounts, len(dbKp.Accounts))
   655  	require.Equal(t, expectedLastUsedDerivationIndex, dbKp.LastUsedDerivationIndex)
   656  
   657  	_, err = db.GetAccountByAddress(generatedWalletAccountThatWillBeRemovedLater.Address)
   658  	require.Error(t, err)
   659  	require.True(t, err == ErrDbAccountNotFound)
   660  
   661  	// check suggested path after removing account
   662  	suggestedPath, err = db.ResolveSuggestedPathForKeypair(kp.KeyUID)
   663  	require.NoError(t, err)
   664  	require.Equal(t, fmt.Sprintf("%s%d", statusWalletRootPath, expectedLastUsedDerivationIndex+1), suggestedPath)
   665  }