add multi-account LoadAccount, ImportMnemonic, and Reset functions (#1542)
* add multi-account LoadAccount and Reset functions * add MultiAccountImportMnemonic * rename StoreDerived to StoreDerivedAccounts * add docs
This commit is contained in:
parent
dcb0fa5262
commit
2b96aa5456
|
@ -0,0 +1,43 @@
|
||||||
|
# Account Generator
|
||||||
|
|
||||||
|
The Account Generator is used to generate, import, derive child keys, and store accounts.
|
||||||
|
It is instantiated in the `account.Manager` struct and it's accessible from the `lib` and `mobile`
|
||||||
|
package through functions with the `MultiAccount` prefix:
|
||||||
|
|
||||||
|
* MultiAccountGenerate
|
||||||
|
* MultiAccountGenerateAndDeriveAddresses
|
||||||
|
* MultiAccountImportMnemonic
|
||||||
|
* MultiAccountDeriveAddresses
|
||||||
|
* MultiAccountStoreDerivedAccounts
|
||||||
|
* MultiAccountImportPrivateKey
|
||||||
|
* MultiAccountStoreAccount
|
||||||
|
* MultiAccountLoadAccount
|
||||||
|
* MultiAccountReset
|
||||||
|
|
||||||
|
|
||||||
|
Using `Generate` and `ImportMnemonic`, a master key is loaded in memory and a random temporarily id is returned.
|
||||||
|
Bare in mind these accounts are not saved. They are in memory until `StoreAccount` or `StoreDerivedAccounts` are called.
|
||||||
|
Calling `Reset` or restarting the application will remove everything from memory.
|
||||||
|
Logging-in and Logging-out will do the same.
|
||||||
|
|
||||||
|
Since `Generate` and `ImportMnemonic` create extended keys, we can use those keys to derive new child keys.
|
||||||
|
`MultiAccountDeriveAddresses(id, paths)` returns a list of addresses/pubKey, one for each path.
|
||||||
|
This can be used to check balances on those addresses and show them to the user.
|
||||||
|
|
||||||
|
Once the user is happy with some specific derivation paths, we can store them using `StoreDerivedAccounts(id, passwordToEncryptKey, paths)`.
|
||||||
|
`StoreDerivedAccounts` returns an address/pubKey for each path. The address can be use in the future to load them in memory again.
|
||||||
|
Calling `StoreDerivedAccounts` will encrypt and store the keys, each one in a keystore json file, and remove all the keys from memory.
|
||||||
|
Since they are derived from an extended key, they are extended keys too, so they can be used in the future to derive more child keys.
|
||||||
|
`StoreAccount` stores the key identified by its ID, so in case the key comes from `Generate` or `ImportPrivateKey`, it will store the master key.
|
||||||
|
In general we want to avoid saving master keys, so we should only use `StoreDerivedAccounts` for extended keys, and `StoreAccount` for normal keys.
|
||||||
|
|
||||||
|
Calling `Load(address, password)` will unlock the key specified by addresses using password, and load it in memory.
|
||||||
|
`Load` returns a new id that can be used again with DeriveAddresses, `StoreAccount`, and `StoreDerivedAccounts`.
|
||||||
|
|
||||||
|
`ImportPrivateKey` imports a raw private key specified by its hex form.
|
||||||
|
It's not an extended key, so it can't be used to derive child addresses.
|
||||||
|
You can call `DeriveAddresses` to derive the address/pubKey of a normal key passing an empty string as derivation path.
|
||||||
|
`StoreAccount` will save the key without deriving a child key.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,9 +17,27 @@ import (
|
||||||
"github.com/status-im/status-go/account/generator"
|
"github.com/status-im/status-go/account/generator"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func checkMultiAccountErrorResponse(t *testing.T, respJSON *C.char, expectedError string) {
|
||||||
|
var e struct {
|
||||||
|
Error *string `json:"error,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal([]byte(C.GoString(respJSON)), &e); err != nil {
|
||||||
|
t.Fatalf("error unmarshaling error response")
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.Error == nil {
|
||||||
|
t.Fatalf("unexpected empty error. expected %s, got nil", expectedError)
|
||||||
|
}
|
||||||
|
|
||||||
|
if *e.Error != expectedError {
|
||||||
|
t.Fatalf("unexpected error. expected %s, got %+v", expectedError, *e.Error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func checkMultiAccountResponse(t *testing.T, respJSON *C.char, resp interface{}) {
|
func checkMultiAccountResponse(t *testing.T, respJSON *C.char, resp interface{}) {
|
||||||
var e struct {
|
var e struct {
|
||||||
Error *string `json:"error"`
|
Error *string `json:"error,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
json.Unmarshal([]byte(C.GoString(respJSON)), &e)
|
json.Unmarshal([]byte(C.GoString(respJSON)), &e)
|
||||||
|
@ -32,7 +50,7 @@ func checkMultiAccountResponse(t *testing.T, respJSON *C.char, resp interface{})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testMultiAccountGenerateDeriveAndStore(t *testing.T) bool { //nolint: gocyclo
|
func testMultiAccountGenerateDeriveStoreLoadReset(t *testing.T) bool { //nolint: gocyclo
|
||||||
// to make sure that we start with empty account (which might have gotten populated during previous tests)
|
// to make sure that we start with empty account (which might have gotten populated during previous tests)
|
||||||
if err := statusBackend.Logout(); err != nil {
|
if err := statusBackend.Logout(); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -68,21 +86,91 @@ func testMultiAccountGenerateDeriveAndStore(t *testing.T) bool { //nolint: gocyc
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if ok := testMultiAccountDeriveAddresses(t, info.ID, paths); !ok {
|
if _, ok := testMultiAccountDeriveAddresses(t, info.ID, paths, false); !ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
password := "multi-account-test-password"
|
||||||
|
|
||||||
// store 2 derived child accounts from the first account.
|
// store 2 derived child accounts from the first account.
|
||||||
// after that all the generated account should be remove from memory.
|
// after that all the generated account should be remove from memory.
|
||||||
if ok := testMultiAccountStoreDerived(t, generateResp[0].ID, paths); !ok {
|
addresses, ok := testMultiAccountStoreDerived(t, generateResp[0].ID, password, paths)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
loadedIDs := make([]string, 0)
|
||||||
|
|
||||||
|
// unlock and load all stored accounts.
|
||||||
|
for _, address := range addresses {
|
||||||
|
loadedID, ok := testMultiAccountLoadAccount(t, address, password)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
loadedIDs = append(loadedIDs, loadedID)
|
||||||
|
|
||||||
|
if _, ok := testMultiAccountDeriveAddresses(t, loadedID, paths, false); !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rawResp = MultiAccountReset()
|
||||||
|
|
||||||
|
// try again deriving addresses.
|
||||||
|
// it should fail because reset should remove all the accounts from memory.
|
||||||
|
for _, loadedID := range loadedIDs {
|
||||||
|
if _, ok := testMultiAccountDeriveAddresses(t, loadedID, paths, true); !ok {
|
||||||
|
t.Errorf("account is still in memory, expected Reset to remove all accounts")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func testMultiAccountImportMnemonicAndDerive(t *testing.T) bool { //nolint: gocyclo
|
||||||
|
// to make sure that we start with empty account (which might have gotten populated during previous tests)
|
||||||
|
if err := statusBackend.Logout(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mnemonicPhrase := "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
|
||||||
|
bip39Passphrase := "TREZOR"
|
||||||
|
params := mobile.MultiAccountImportMnemonicParams{
|
||||||
|
MnemonicPhrase: mnemonicPhrase,
|
||||||
|
Bip39Passphrase: bip39Passphrase,
|
||||||
|
}
|
||||||
|
|
||||||
|
paramsJSON, err := json.Marshal(¶ms)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error encoding MultiAccountImportMnemonicParams")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// import mnemonic
|
||||||
|
rawResp := MultiAccountImportMnemonic(C.CString(string(paramsJSON)))
|
||||||
|
var importResp generator.IdentifiedAccountInfo
|
||||||
|
// check the response doesn't have errors
|
||||||
|
checkMultiAccountResponse(t, rawResp, &importResp)
|
||||||
|
|
||||||
|
bip44DerivationPath := "m/44'/60'/0'/0/0"
|
||||||
|
expectedBip44Address := "0x9c32F71D4DB8Fb9e1A58B0a80dF79935e7256FA6"
|
||||||
|
addresses, ok := testMultiAccountDeriveAddresses(t, importResp.ID, []string{bip44DerivationPath}, false)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if addresses[bip44DerivationPath] != expectedBip44Address {
|
||||||
|
t.Errorf("unexpected address; expected %s, got %s", expectedBip44Address, addresses[bip44DerivationPath])
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func testMultiAccountDeriveAddresses(t *testing.T, accountID string, paths []string) bool { //nolint: gocyclo
|
func testMultiAccountDeriveAddresses(t *testing.T, accountID string, paths []string, expectAccountNotFoundError bool) (map[string]string, bool) { //nolint: gocyclo
|
||||||
params := mobile.MultiAccountDeriveAddressesParams{
|
params := mobile.MultiAccountDeriveAddressesParams{
|
||||||
AccountID: accountID,
|
AccountID: accountID,
|
||||||
Paths: paths,
|
Paths: paths,
|
||||||
|
@ -91,34 +179,44 @@ func testMultiAccountDeriveAddresses(t *testing.T, accountID string, paths []str
|
||||||
paramsJSON, err := json.Marshal(¶ms)
|
paramsJSON, err := json.Marshal(¶ms)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("error encoding MultiAccountDeriveAddressesParams")
|
t.Errorf("error encoding MultiAccountDeriveAddressesParams")
|
||||||
return false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// derive addresses from account accountID
|
// derive addresses from account accountID
|
||||||
rawResp := MultiAccountDeriveAddresses(C.CString(string(paramsJSON)))
|
rawResp := MultiAccountDeriveAddresses(C.CString(string(paramsJSON)))
|
||||||
|
|
||||||
|
if expectAccountNotFoundError {
|
||||||
|
checkMultiAccountErrorResponse(t, rawResp, "account not found")
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
|
||||||
var deriveResp map[string]generator.AccountInfo
|
var deriveResp map[string]generator.AccountInfo
|
||||||
// check the response doesn't have errors
|
// check the response doesn't have errors
|
||||||
checkMultiAccountResponse(t, rawResp, &deriveResp)
|
checkMultiAccountResponse(t, rawResp, &deriveResp)
|
||||||
if len(deriveResp) != 2 {
|
if len(deriveResp) != len(paths) {
|
||||||
t.Errorf("expected 2 derived accounts info, got %d", len(deriveResp))
|
t.Errorf("expected %d derived accounts info, got %d", len(paths), len(deriveResp))
|
||||||
return false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addresses := make(map[string]string)
|
||||||
|
|
||||||
// check that we have an address for each derivation path we used.
|
// check that we have an address for each derivation path we used.
|
||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
if _, ok := deriveResp[path]; !ok {
|
info, ok := deriveResp[path]
|
||||||
|
if !ok {
|
||||||
t.Errorf("results doesn't contain account info for path %s", path)
|
t.Errorf("results doesn't contain account info for path %s", path)
|
||||||
return false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addresses[path] = info.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return addresses, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func testMultiAccountStoreDerived(t *testing.T, accountID string, paths []string) bool { //nolint: gocyclo
|
func testMultiAccountStoreDerived(t *testing.T, accountID string, password string, paths []string) ([]string, bool) { //nolint: gocyclo
|
||||||
password := "test-multiaccount-password"
|
|
||||||
|
|
||||||
params := mobile.MultiAccountStoreDerivedParams{
|
params := mobile.MultiAccountStoreDerivedAccountsParams{
|
||||||
MultiAccountDeriveAddressesParams: mobile.MultiAccountDeriveAddressesParams{
|
MultiAccountDeriveAddressesParams: mobile.MultiAccountDeriveAddressesParams{
|
||||||
AccountID: accountID,
|
AccountID: accountID,
|
||||||
Paths: paths,
|
Paths: paths,
|
||||||
|
@ -129,11 +227,11 @@ func testMultiAccountStoreDerived(t *testing.T, accountID string, paths []string
|
||||||
paramsJSON, err := json.Marshal(params)
|
paramsJSON, err := json.Marshal(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("error encoding MultiAccountStoreDerivedParams")
|
t.Errorf("error encoding MultiAccountStoreDerivedParams")
|
||||||
return false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// store one child account for each derivation path.
|
// store one child account for each derivation path.
|
||||||
rawResp := MultiAccountStoreDerived(C.CString(string(paramsJSON)))
|
rawResp := MultiAccountStoreDerivedAccounts(C.CString(string(paramsJSON)))
|
||||||
var storeResp map[string]generator.AccountInfo
|
var storeResp map[string]generator.AccountInfo
|
||||||
|
|
||||||
// check that we don't have errors in the response
|
// check that we don't have errors in the response
|
||||||
|
@ -145,7 +243,7 @@ func testMultiAccountStoreDerived(t *testing.T, accountID string, paths []string
|
||||||
|
|
||||||
if len(addresses) != 2 {
|
if len(addresses) != 2 {
|
||||||
t.Errorf("expected 2 addresses, got %d", len(addresses))
|
t.Errorf("expected 2 addresses, got %d", len(addresses))
|
||||||
return false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// for each stored account, check that we can decrypt it with the password we used.
|
// for each stored account, check that we can decrypt it with the password we used.
|
||||||
|
@ -154,10 +252,11 @@ func testMultiAccountStoreDerived(t *testing.T, accountID string, paths []string
|
||||||
_, err = statusBackend.AccountManager().VerifyAccountPassword(dir, address, password)
|
_, err = statusBackend.AccountManager().VerifyAccountPassword(dir, address, password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("failed to verify password on stored derived account")
|
t.Errorf("failed to verify password on stored derived account")
|
||||||
|
return nil, false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return addresses, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func testMultiAccountGenerateAndDerive(t *testing.T) bool { //nolint: gocyclo
|
func testMultiAccountGenerateAndDerive(t *testing.T) bool { //nolint: gocyclo
|
||||||
|
@ -259,3 +358,26 @@ func testMultiAccountImportStore(t *testing.T) bool { //nolint: gocyclo
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testMultiAccountLoadAccount(t *testing.T, address string, password string) (string, bool) { //nolint: gocyclo
|
||||||
|
t.Log("loading account")
|
||||||
|
params := mobile.MultiAccountLoadAccountParams{
|
||||||
|
Address: address,
|
||||||
|
Password: password,
|
||||||
|
}
|
||||||
|
|
||||||
|
paramsJSON, err := json.Marshal(params)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error encoding MultiAccountLoadAccountParams")
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
// load the account in memory
|
||||||
|
rawResp := MultiAccountLoadAccount(C.CString(string(paramsJSON)))
|
||||||
|
var loadResp generator.IdentifiedAccountInfo
|
||||||
|
|
||||||
|
// check that we don't have errors in the response
|
||||||
|
checkMultiAccountResponse(t, rawResp, &loadResp)
|
||||||
|
|
||||||
|
return loadResp.ID, true
|
||||||
|
}
|
||||||
|
|
|
@ -147,8 +147,12 @@ func testExportedAPI(t *testing.T, done chan struct{}) {
|
||||||
testFailedTransaction,
|
testFailedTransaction,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"MultiAccount - Generate/Derive/StoreDerived",
|
"MultiAccount - Generate/Derive/StoreDerived/Load/Reset",
|
||||||
testMultiAccountGenerateDeriveAndStore,
|
testMultiAccountGenerateDeriveStoreLoadReset,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"MultiAccount - ImportMnemonic/Derive",
|
||||||
|
testMultiAccountImportMnemonicAndDerive,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"MultiAccount - GenerateAndDerive",
|
"MultiAccount - GenerateAndDerive",
|
||||||
|
|
|
@ -74,10 +74,10 @@ func MultiAccountDeriveAddresses(paramsJSON *C.char) *C.char {
|
||||||
return C.CString(string(out))
|
return C.CString(string(out))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MultiAccountStoreDerived derive accounts from the specified key and store them encrypted with the specified password.
|
// MultiAccountStoreDerivedAccounts derive accounts from the specified key and store them encrypted with the specified password.
|
||||||
//export MultiAccountStoreDerived
|
//export MultiAccountStoreDerivedAccounts
|
||||||
func MultiAccountStoreDerived(paramsJSON *C.char) *C.char {
|
func MultiAccountStoreDerivedAccounts(paramsJSON *C.char) *C.char {
|
||||||
var p mobile.MultiAccountStoreDerivedParams
|
var p mobile.MultiAccountStoreDerivedAccountsParams
|
||||||
|
|
||||||
if err := json.Unmarshal([]byte(C.GoString(paramsJSON)), &p); err != nil {
|
if err := json.Unmarshal([]byte(C.GoString(paramsJSON)), &p); err != nil {
|
||||||
return makeJSONResponse(err)
|
return makeJSONResponse(err)
|
||||||
|
@ -118,6 +118,28 @@ func MultiAccountImportPrivateKey(paramsJSON *C.char) *C.char {
|
||||||
return C.CString(string(out))
|
return C.CString(string(out))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MultiAccountImportMnemonic imports an account derived from the mnemonic phrase and the Bip39Passphrase storing it.
|
||||||
|
//export MultiAccountImportMnemonic
|
||||||
|
func MultiAccountImportMnemonic(paramsJSON *C.char) *C.char {
|
||||||
|
var p mobile.MultiAccountImportMnemonicParams
|
||||||
|
|
||||||
|
if err := json.Unmarshal([]byte(C.GoString(paramsJSON)), &p); err != nil {
|
||||||
|
return makeJSONResponse(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := statusBackend.AccountManager().AccountsGenerator().ImportMnemonic(p.MnemonicPhrase, p.Bip39Passphrase)
|
||||||
|
if err != nil {
|
||||||
|
return makeJSONResponse(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := json.Marshal(resp)
|
||||||
|
if err != nil {
|
||||||
|
return makeJSONResponse(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return C.CString(string(out))
|
||||||
|
}
|
||||||
|
|
||||||
// MultiAccountStoreAccount stores the select account.
|
// MultiAccountStoreAccount stores the select account.
|
||||||
//export MultiAccountStoreAccount
|
//export MultiAccountStoreAccount
|
||||||
func MultiAccountStoreAccount(paramsJSON *C.char) *C.char {
|
func MultiAccountStoreAccount(paramsJSON *C.char) *C.char {
|
||||||
|
@ -139,3 +161,32 @@ func MultiAccountStoreAccount(paramsJSON *C.char) *C.char {
|
||||||
|
|
||||||
return C.CString(string(out))
|
return C.CString(string(out))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MultiAccountLoadAccount loads in memory the account specified by address unlocking it with password.
|
||||||
|
//export MultiAccountLoadAccount
|
||||||
|
func MultiAccountLoadAccount(paramsJSON *C.char) *C.char {
|
||||||
|
var p mobile.MultiAccountLoadAccountParams
|
||||||
|
|
||||||
|
if err := json.Unmarshal([]byte(C.GoString(paramsJSON)), &p); err != nil {
|
||||||
|
return makeJSONResponse(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := statusBackend.AccountManager().AccountsGenerator().LoadAccount(p.Address, p.Password)
|
||||||
|
if err != nil {
|
||||||
|
return makeJSONResponse(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := json.Marshal(resp)
|
||||||
|
if err != nil {
|
||||||
|
return makeJSONResponse(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return C.CString(string(out))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MultiAccountReset remove all the multi-account keys from memory.
|
||||||
|
//export MultiAccountReset
|
||||||
|
func MultiAccountReset() *C.char {
|
||||||
|
statusBackend.AccountManager().AccountsGenerator().Reset()
|
||||||
|
return makeJSONResponse(nil)
|
||||||
|
}
|
||||||
|
|
|
@ -23,8 +23,8 @@ type MultiAccountDeriveAddressesParams struct {
|
||||||
Paths []string `json:"paths"`
|
Paths []string `json:"paths"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MultiAccountStoreDerivedParams are the params sent to MultiAccountStoreDerived.
|
// MultiAccountStoreDerivedAccountsParams are the params sent to MultiAccountStoreDerivedAccounts.
|
||||||
type MultiAccountStoreDerivedParams struct {
|
type MultiAccountStoreDerivedAccountsParams struct {
|
||||||
MultiAccountDeriveAddressesParams
|
MultiAccountDeriveAddressesParams
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,18 @@ type MultiAccountImportPrivateKeyParams struct {
|
||||||
PrivateKey string `json:"privateKey"`
|
PrivateKey string `json:"privateKey"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MultiAccountLoadAccountParams are the params sent to MultiAccountLoadAccount.
|
||||||
|
type MultiAccountLoadAccountParams struct {
|
||||||
|
Address string `json:"address"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MultiAccountImportMnemonicParams are the params sent to MultiAccountImportMnemonic.
|
||||||
|
type MultiAccountImportMnemonicParams struct {
|
||||||
|
MnemonicPhrase string `json:"mnemonicPhrase"`
|
||||||
|
Bip39Passphrase string `json:"Bip39Passphrase"`
|
||||||
|
}
|
||||||
|
|
||||||
// MultiAccountGenerate generates account in memory without storing them.
|
// MultiAccountGenerate generates account in memory without storing them.
|
||||||
func MultiAccountGenerate(paramsJSON string) string {
|
func MultiAccountGenerate(paramsJSON string) string {
|
||||||
var p MultiAccountGenerateParams
|
var p MultiAccountGenerateParams
|
||||||
|
@ -103,9 +115,9 @@ func MultiAccountDeriveAddresses(paramsJSON string) string {
|
||||||
return string(out)
|
return string(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MultiAccountStoreDerived derive accounts from the specified key and store them encrypted with the specified password.
|
// MultiAccountStoreDerivedAccounts derive accounts from the specified key and store them encrypted with the specified password.
|
||||||
func MultiAccountStoreDerived(paramsJSON string) string {
|
func MultiAccountStoreDerivedAccounts(paramsJSON string) string {
|
||||||
var p MultiAccountStoreDerivedParams
|
var p MultiAccountStoreDerivedAccountsParams
|
||||||
|
|
||||||
if err := json.Unmarshal([]byte(paramsJSON), &p); err != nil {
|
if err := json.Unmarshal([]byte(paramsJSON), &p); err != nil {
|
||||||
return makeJSONResponse(err)
|
return makeJSONResponse(err)
|
||||||
|
@ -145,6 +157,27 @@ func MultiAccountImportPrivateKey(paramsJSON string) string {
|
||||||
return string(out)
|
return string(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MultiAccountImportMnemonic imports an account derived from the mnemonic phrase and the Bip39Passphrase storing it.
|
||||||
|
func MultiAccountImportMnemonic(paramsJSON string) string {
|
||||||
|
var p MultiAccountImportMnemonicParams
|
||||||
|
|
||||||
|
if err := json.Unmarshal([]byte(paramsJSON), &p); err != nil {
|
||||||
|
return makeJSONResponse(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := statusBackend.AccountManager().AccountsGenerator().ImportMnemonic(p.MnemonicPhrase, p.Bip39Passphrase)
|
||||||
|
if err != nil {
|
||||||
|
return makeJSONResponse(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := json.Marshal(resp)
|
||||||
|
if err != nil {
|
||||||
|
return makeJSONResponse(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(out)
|
||||||
|
}
|
||||||
|
|
||||||
// MultiAccountStoreAccount stores the select account.
|
// MultiAccountStoreAccount stores the select account.
|
||||||
func MultiAccountStoreAccount(paramsJSON string) string {
|
func MultiAccountStoreAccount(paramsJSON string) string {
|
||||||
var p MultiAccountStoreAccountParams
|
var p MultiAccountStoreAccountParams
|
||||||
|
@ -165,3 +198,30 @@ func MultiAccountStoreAccount(paramsJSON string) string {
|
||||||
|
|
||||||
return string(out)
|
return string(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MultiAccountLoadAccount loads in memory the account specified by address unlocking it with password.
|
||||||
|
func MultiAccountLoadAccount(paramsJSON string) string {
|
||||||
|
var p MultiAccountLoadAccountParams
|
||||||
|
|
||||||
|
if err := json.Unmarshal([]byte(paramsJSON), &p); err != nil {
|
||||||
|
return makeJSONResponse(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := statusBackend.AccountManager().AccountsGenerator().LoadAccount(p.Address, p.Password)
|
||||||
|
if err != nil {
|
||||||
|
return makeJSONResponse(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := json.Marshal(resp)
|
||||||
|
if err != nil {
|
||||||
|
return makeJSONResponse(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MultiAccountReset remove all the multi-account keys from memory.
|
||||||
|
func MultiAccountReset() string {
|
||||||
|
statusBackend.AccountManager().AccountsGenerator().Reset()
|
||||||
|
return makeJSONResponse(nil)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue