diff --git a/multiaccounts/accounts/database.go b/multiaccounts/accounts/database.go index 6b94fce65..3c2ffb82c 100644 --- a/multiaccounts/accounts/database.go +++ b/multiaccounts/accounts/database.go @@ -1266,8 +1266,38 @@ func (db *Database) GetNodeConfig() (*params.NodeConfig, error) { return nodecfg.GetNodeConfigFromDB(db.db) } -// This function should not update the clock, cause it marks accounts locally. -func (db *Database) SetAccountOperability(address types.Address, operable AccountOperable) (err error) { +// This function should not update the clock, cause it marks keypair/accounts locally. +func (db *Database) MarkKeypairFullyOperable(keyUID string) (err error) { + tx, err := db.db.Begin() + if err != nil { + return err + } + defer func() { + if err == nil { + err = tx.Commit() + return + } + _ = tx.Rollback() + }() + + kp, err := db.getKeypairByKeyUID(tx, keyUID, false) + if err != nil { + return err + } + + for _, acc := range kp.Accounts { + _, err = tx.Exec(`UPDATE keypairs_accounts SET operable = ? WHERE address = ?`, AccountFullyOperable, acc.Address) + if err != nil { + return err + } + } + + _, err = tx.Exec(`UPDATE keypairs SET synced_from = "" WHERE key_uid = ?`, keyUID) + return err +} + +// This function should not update the clock, cause it marks a keypair locally. +func (db *Database) SetKeypairSyncedFrom(address types.Address, operable AccountOperable) (err error) { tx, err := db.db.Begin() if err != nil { return err diff --git a/services/accounts/accounts.go b/services/accounts/accounts.go index c7751b790..4d9518392 100644 --- a/services/accounts/accounts.go +++ b/services/accounts/accounts.go @@ -71,6 +71,10 @@ func (api *API) SaveKeypair(ctx context.Context, keypair *accounts.Keypair) erro return nil } +func (api *API) HasPairedDevices(ctx context.Context) bool { + return (*api.messenger).HasPairedDevices() +} + // Setting `Keypair` without `Accounts` will update keypair only. func (api *API) UpdateKeypairName(ctx context.Context, keyUID string, name string) error { return (*api.messenger).UpdateKeypairName(keyUID, name) @@ -312,6 +316,30 @@ func (api *API) ImportPrivateKey(ctx context.Context, privateKey string, passwor return err } +// Creates all keystore files for a keypair and mark it in db as fully operable. +func (api *API) MakePrivateKeyKeypairFullyOperable(ctx context.Context, privateKey string, password string) error { + info, err := api.manager.AccountsGenerator().ImportPrivateKey(privateKey) + if err != nil { + return err + } + + kp, err := api.db.GetKeypairByKeyUID(info.KeyUID) + if err != nil { + return err + } + + if kp == nil { + return errors.New("keypair for the provided private key is not known") + } + + _, err = api.manager.AccountsGenerator().StoreAccount(info.ID, password) + if err != nil { + return err + } + + return api.db.MarkKeypairFullyOperable(info.KeyUID) +} + // Imports a new mnemonic and creates local keystore file. func (api *API) ImportMnemonic(ctx context.Context, mnemonic string, password string) error { mnemonicNoExtraSpaces := strings.Join(strings.Fields(mnemonic), " ") @@ -334,6 +362,42 @@ func (api *API) ImportMnemonic(ctx context.Context, mnemonic string, password st return err } +// Creates all keystore files for a keypair and mark it in db as fully operable. +func (api *API) MakeSeedPhraseKeypairFullyOperable(ctx context.Context, mnemonic string, password string) error { + mnemonicNoExtraSpaces := strings.Join(strings.Fields(mnemonic), " ") + + generatedAccountInfo, err := api.manager.AccountsGenerator().ImportMnemonic(mnemonicNoExtraSpaces, "") + if err != nil { + return err + } + + kp, err := api.db.GetKeypairByKeyUID(generatedAccountInfo.KeyUID) + if err != nil { + return err + } + + if kp == nil { + return errors.New("keypair for the provided seed phrase is not known") + } + + _, err = api.manager.AccountsGenerator().StoreAccount(generatedAccountInfo.ID, password) + if err != nil { + return err + } + + var paths []string + for _, acc := range kp.Accounts { + paths = append(paths, acc.Path) + } + + _, err = api.manager.AccountsGenerator().StoreDerivedAccounts(generatedAccountInfo.ID, password, paths) + if err != nil { + return err + } + + return api.db.MarkKeypairFullyOperable(generatedAccountInfo.KeyUID) +} + // Creates a random new mnemonic. func (api *API) GetRandomMnemonic(ctx context.Context) (string, error) { return api.manager.GetRandomMnemonic()