github.com/0chain/gosdk@v1.17.11/zcnbridge/keystore.go (about) 1 package zcnbridge 2 3 import ( 4 "fmt" 5 "path" 6 "time" 7 8 hdw "github.com/0chain/gosdk/zcncore/ethhdwallet" 9 "github.com/ethereum/go-ethereum/accounts" 10 "github.com/ethereum/go-ethereum/accounts/keystore" 11 "github.com/ethereum/go-ethereum/common" 12 "github.com/pkg/errors" 13 ) 14 15 // DetailedAccount describes detailed account 16 type DetailedAccount struct { 17 EthereumAddress, 18 PublicKey, 19 PrivateKey accounts.Account 20 } 21 22 // KeyStore is a wrapper, which exposes Ethereum KeyStore methods used by DEX bridge. 23 type KeyStore interface { 24 Find(accounts.Account) (accounts.Account, error) 25 TimedUnlock(accounts.Account, string, time.Duration) error 26 SignHash(account accounts.Account, hash []byte) ([]byte, error) 27 GetEthereumKeyStore() *keystore.KeyStore 28 } 29 30 type keyStore struct { 31 ks *keystore.KeyStore 32 } 33 34 // NewKeyStore creates new KeyStore wrapper instance 35 func NewKeyStore(path string) KeyStore { 36 return &keyStore{ 37 ks: keystore.NewKeyStore(path, keystore.StandardScryptN, keystore.StandardScryptP), 38 } 39 } 40 41 // Find forwards request to Ethereum KeyStore Find method 42 func (k *keyStore) Find(account accounts.Account) (accounts.Account, error) { 43 return k.ks.Find(account) 44 } 45 46 // TimedUnlock forwards request to Ethereum KeyStore TimedUnlock method 47 func (k *keyStore) TimedUnlock(account accounts.Account, passPhrase string, timeout time.Duration) error { 48 return k.ks.TimedUnlock(account, passPhrase, timeout) 49 } 50 51 // SignHash forwards request to Ethereum KeyStore SignHash method 52 func (k *keyStore) SignHash(account accounts.Account, hash []byte) ([]byte, error) { 53 return k.ks.SignHash(account, hash) 54 } 55 56 // GetEthereumKeyStore returns Ethereum KeyStore instance 57 func (k *keyStore) GetEthereumKeyStore() *keystore.KeyStore { 58 return k.ks 59 } 60 61 // ListStorageAccounts List available accounts 62 // - homedir is the home directory 63 func ListStorageAccounts(homedir string) []common.Address { 64 keyDir := path.Join(homedir, EthereumWalletStorageDir) 65 ks := keystore.NewKeyStore(keyDir, keystore.StandardScryptN, keystore.StandardScryptP) 66 config := &accounts.Config{InsecureUnlockAllowed: false} 67 am := accounts.NewManager(config, ks) 68 addresses := am.Accounts() 69 70 return addresses 71 } 72 73 // DeleteAccount deletes account from wallet 74 // - homedir is the home directory 75 // - address is the account address 76 func DeleteAccount(homedir, address string) bool { 77 keyDir := path.Join(homedir, EthereumWalletStorageDir) 78 ks := keystore.NewKeyStore(keyDir, keystore.StandardScryptN, keystore.StandardScryptP) 79 config := &accounts.Config{InsecureUnlockAllowed: false} 80 am := accounts.NewManager(config, ks) 81 82 wallet, err := am.Find(accounts.Account{ 83 Address: common.HexToAddress(address), 84 }) 85 86 if err != nil && wallet == nil { 87 fmt.Printf("failed to find account %s, error: %s", address, err) 88 return false 89 } 90 91 return true 92 } 93 94 // AccountExists checks if account exists 95 // - homedir is the home directory 96 // - address is the account address 97 func AccountExists(homedir, address string) bool { 98 keyDir := path.Join(homedir, EthereumWalletStorageDir) 99 ks := keystore.NewKeyStore(keyDir, keystore.StandardScryptN, keystore.StandardScryptP) 100 config := &accounts.Config{InsecureUnlockAllowed: false} 101 am := accounts.NewManager(config, ks) 102 103 wallet, err := am.Find(accounts.Account{ 104 Address: common.HexToAddress(address), 105 }) 106 107 if err != nil && wallet == nil { 108 fmt.Printf("failed to find account %s, error: %s\n", address, err) 109 return false 110 } 111 112 status, _ := wallet.Status() 113 url := wallet.URL() 114 115 fmt.Printf("Account exists. Status: %s, Path: %s\n", status, url) 116 117 return true 118 } 119 120 // CreateKeyStorage create, restore or unlock key storage 121 // - homedir is the home directory 122 // - password is the password 123 func CreateKeyStorage(homedir, password string) error { 124 keyDir := path.Join(homedir, EthereumWalletStorageDir) 125 ks := keystore.NewKeyStore(keyDir, keystore.StandardScryptN, keystore.StandardScryptP) 126 account, err := ks.NewAccount(password) 127 if err != nil { 128 return errors.Wrap(err, "failed to create keystore") 129 } 130 fmt.Printf("Created account: %s", account.Address.Hex()) 131 132 return nil 133 } 134 135 // AccountAddressIndex represents client account and address indexes for multi-key wallet. Used to derive ethereum account. 136 type AccountAddressIndex struct { 137 AccountIndex int 138 AddressIndex int 139 140 // Bip32 flag indicates if the account is derived using BIP32 derivation path. 141 Bip32 bool 142 } 143 144 // ImportAccount imports account using mnemonic 145 // - homedir is the home directory 146 // - mnemonic is the mnemonic phrase 147 // - password is the password 148 // - accountAddrIndex is the account and address indexes used for the derivation of the ethereum account 149 func ImportAccount(homedir, mnemonic, password string, accountAddrIndex ...AccountAddressIndex) (string, error) { 150 // 1. Create storage and account if it doesn't exist and add account to it 151 152 keyDir := path.Join(homedir, EthereumWalletStorageDir) 153 ks := keystore.NewKeyStore(keyDir, keystore.StandardScryptN, keystore.StandardScryptP) 154 155 // 2. Init wallet 156 157 wallet, err := hdw.NewFromMnemonic(mnemonic) 158 if err != nil { 159 return "", errors.Wrap(err, "failed to import from mnemonic") 160 } 161 162 var aai AccountAddressIndex 163 if len(accountAddrIndex) > 0 { 164 aai = accountAddrIndex[0] 165 } 166 167 var pathD accounts.DerivationPath 168 if aai.Bip32 { 169 pathD = hdw.MustParseDerivationPath(fmt.Sprintf("m/44'/60'/0'/%d", aai.AddressIndex)) 170 } else { 171 pathD = hdw.MustParseDerivationPath(fmt.Sprintf("m/44'/60'/%d'/0/%d", aai.AccountIndex, aai.AddressIndex)) 172 } 173 174 account, err := wallet.Derive(pathD, true) 175 if err != nil { 176 return "", errors.Wrap(err, "failed parse derivation path") 177 } 178 179 key, err := wallet.PrivateKey(account) 180 if err != nil { 181 return "", errors.Wrap(err, "failed to get private key") 182 } 183 184 // 3. Find key 185 186 acc, err := ks.Find(account) 187 if err == nil { 188 fmt.Printf("Account already exists: %s\nPath: %s\n\n", acc.Address.Hex(), acc.URL.Path) 189 return acc.Address.Hex(), nil 190 } 191 192 // 4. Import the key if it doesn't exist 193 194 acc, err = ks.ImportECDSA(key, password) 195 if err != nil { 196 return "", errors.Wrap(err, "failed to get import private key") 197 } 198 199 fmt.Printf("Imported account %s to path: %s\n", acc.Address.Hex(), acc.URL.Path) 200 201 return acc.Address.Hex(), nil 202 }