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 }