-
Notifications
You must be signed in to change notification settings - Fork 244
/
onboarding.go
114 lines (91 loc) · 3.02 KB
/
onboarding.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package account
import (
"fmt"
"github.com/pborman/uuid"
"github.com/status-im/status-go/account/generator"
"github.com/status-im/status-go/eth-node/crypto"
"github.com/status-im/status-go/eth-node/types"
"github.com/status-im/status-go/extkeys"
)
// OnboardingAccount is returned during onboarding and contains its ID and the mnemonic to re-generate the same account Info keys.
type OnboardingAccount struct {
ID string `json:"id"`
mnemonic string
Info Info `json:"info"`
}
// Onboarding is a struct contains a slice of OnboardingAccount.
type Onboarding struct {
accounts map[string]*OnboardingAccount
}
// NewOnboarding returns a new onboarding struct generating n accounts.
func NewOnboarding(n, mnemonicPhraseLength int) (*Onboarding, error) {
onboarding := &Onboarding{
accounts: make(map[string]*OnboardingAccount),
}
for i := 0; i < n; i++ {
account, err := onboarding.generateAccount(mnemonicPhraseLength)
if err != nil {
return nil, err
}
onboarding.accounts[account.ID] = account
}
return onboarding, nil
}
// Accounts return the list of OnboardingAccount generated.
func (o *Onboarding) Accounts() []*OnboardingAccount {
accounts := make([]*OnboardingAccount, 0)
for _, a := range o.accounts {
accounts = append(accounts, a)
}
return accounts
}
// Account returns an OnboardingAccount by id.
func (o *Onboarding) Account(id string) (*OnboardingAccount, error) {
account, ok := o.accounts[id]
if !ok {
return nil, ErrOnboardingAccountNotFound
}
return account, nil
}
func (o *Onboarding) generateAccount(mnemonicPhraseLength int) (*OnboardingAccount, error) {
entropyStrength, err := generator.MnemonicPhraseLengthToEntropyStrength(mnemonicPhraseLength)
if err != nil {
return nil, err
}
mnemonic := extkeys.NewMnemonic()
mnemonicPhrase, err := mnemonic.MnemonicPhrase(entropyStrength, extkeys.EnglishLanguage)
if err != nil {
return nil, fmt.Errorf("can not create mnemonic seed: %v", err)
}
masterExtendedKey, err := extkeys.NewMaster(mnemonic.MnemonicSeed(mnemonicPhrase, ""))
if err != nil {
return nil, fmt.Errorf("can not create master extended key: %v", err)
}
walletAddress, walletPubKey, err := o.deriveAccount(masterExtendedKey, extkeys.KeyPurposeWallet, 0)
if err != nil {
return nil, err
}
info := Info{
WalletAddress: walletAddress,
WalletPubKey: walletPubKey,
ChatAddress: walletAddress,
ChatPubKey: walletPubKey,
}
uuid := uuid.NewRandom().String()
account := &OnboardingAccount{
ID: uuid,
mnemonic: mnemonicPhrase,
Info: info,
}
return account, nil
}
func (o *Onboarding) deriveAccount(masterExtendedKey *extkeys.ExtendedKey, purpose extkeys.KeyPurpose, index uint32) (string, string, error) {
extendedKey, err := masterExtendedKey.ChildForPurpose(purpose, index)
if err != nil {
return "", "", err
}
privateKeyECDSA := extendedKey.ToECDSA()
address := crypto.PubkeyToAddress(privateKeyECDSA.PublicKey)
publicKeyHex := types.EncodeHex(crypto.FromECDSAPub(&privateKeyECDSA.PublicKey))
return address.Hex(), publicKeyHex, nil
}