github.com/0chain/gosdk@v1.17.11/znft/keystore.go (about)

     1  package znft
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path"
     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  	"gopkg.in/yaml.v2"
    14  )
    15  
    16  // ListStorageAccounts List available accounts
    17  func ListStorageAccounts(homedir string) []common.Address {
    18  	am := getAccountManager(homedir)
    19  	addresses := am.Accounts()
    20  
    21  	return addresses
    22  }
    23  
    24  // DeleteAccount deletes account from wallet
    25  func DeleteAccount(homedir, address string) bool {
    26  	am := getAccountManager(homedir)
    27  
    28  	wallet, err := am.Find(accounts.Account{
    29  		Address: common.HexToAddress(address),
    30  	})
    31  
    32  	if err != nil && wallet == nil {
    33  		fmt.Printf("failed to find account %s, error: %s", address, err)
    34  		return false
    35  	}
    36  
    37  	return true
    38  }
    39  
    40  func getAccountManager(homedir string) *accounts.Manager {
    41  	keyDir := path.Join(homedir, WalletDir)
    42  	ks := keystore.NewKeyStore(keyDir, keystore.StandardScryptN, keystore.StandardScryptP)
    43  	config := &accounts.Config{InsecureUnlockAllowed: false}
    44  	am := accounts.NewManager(config, ks)
    45  	return am
    46  }
    47  
    48  // AccountExists checks if account exists
    49  func AccountExists(homedir, address string) bool {
    50  	am := getAccountManager(homedir)
    51  
    52  	wallet, err := am.Find(accounts.Account{
    53  		Address: common.HexToAddress(address),
    54  	})
    55  
    56  	if err != nil && wallet == nil {
    57  		fmt.Printf("failed to find account %s, error: %s\n", address, err)
    58  		return false
    59  	}
    60  
    61  	status, _ := wallet.Status()
    62  	url := wallet.URL()
    63  
    64  	fmt.Printf("Account exists. Status: %s, Path: %s\n", status, url)
    65  
    66  	return true
    67  }
    68  
    69  // CreateKeyStorage create, restore or unlock key storage
    70  func CreateKeyStorage(homedir, password string) error {
    71  	keyDir := path.Join(homedir, WalletDir)
    72  	ks := keystore.NewKeyStore(keyDir, keystore.StandardScryptN, keystore.StandardScryptP)
    73  	account, err := ks.NewAccount(password)
    74  	if err != nil {
    75  		return errors.Wrap(err, "failed to create keystore")
    76  	}
    77  	fmt.Printf("Created account: %s", account.Address.Hex())
    78  
    79  	return nil
    80  }
    81  
    82  // UpdateClientEthereumAddress updates Ethereum address
    83  func UpdateClientEthereumAddress(homedir, address string) (err error) {
    84  	configFile := path.Join(homedir, ConfigFile)
    85  	buf, err := os.ReadFile(configFile)
    86  	if err != nil {
    87  		return err
    88  	}
    89  	cfg := &Configuration{}
    90  	err = yaml.Unmarshal(buf, cfg)
    91  	if err != nil {
    92  		return err
    93  	}
    94  
    95  	cfg.WalletAddress = address
    96  
    97  	text, err := yaml.Marshal(cfg)
    98  	if err != nil {
    99  		return err
   100  	}
   101  
   102  	err = os.WriteFile(configFile, text, 0644)
   103  
   104  	return err
   105  }
   106  
   107  // ImportAccount imports account using mnemonic
   108  // password is used to lock and unlock keystorage before signing transaction
   109  func ImportAccount(homedir, mnemonic, password string) (string, error) {
   110  	// 1. Create storage and account if it doesn't exist and add account to it
   111  	keyDir := path.Join(homedir, WalletDir)
   112  	ks := keystore.NewKeyStore(keyDir, keystore.StandardScryptN, keystore.StandardScryptP)
   113  
   114  	// 2. Init wallet
   115  	wallet, err := hdw.NewFromMnemonic(mnemonic)
   116  	if err != nil {
   117  		return "", errors.Wrap(err, "failed to import from mnemonic")
   118  	}
   119  
   120  	// DefaultBaseDerivationPath is the base path from which custom derivation endpoints
   121  	// are incremented. As such, the first account will be at m/44'/60'/0'/0, the second
   122  	// at m/44'/60'/0'/1, etc
   123  	// from basic library:
   124  	// var DefaultBaseDerivationPath = accounts.DefaultBaseDerivationPath
   125  	// from the BIP44 specification, the HD derivation path is defined as
   126  	// m / purpose' / coin_type' / account' / change / address_index
   127  	// https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
   128  
   129  	pathD := hdw.MustParseDerivationPath("m/44'/60'/0'/0/0")
   130  	account, err := wallet.Derive(pathD, true)
   131  	if err != nil {
   132  		return "", errors.Wrap(err, "failed parse derivation path")
   133  	}
   134  
   135  	key, err := wallet.PrivateKey(account)
   136  	if err != nil {
   137  		return "", errors.Wrap(err, "failed to get private key")
   138  	}
   139  
   140  	// 3. Find key
   141  	acc, err := ks.Find(account)
   142  	if err == nil {
   143  		fmt.Printf("Account already exists: %s\nPath: %s\n\n", acc.Address.Hex(), acc.URL.Path)
   144  		return acc.Address.Hex(), nil
   145  	}
   146  
   147  	// 4. Import the key if it doesn't exist
   148  	acc, err = ks.ImportECDSA(key, password)
   149  	if err != nil {
   150  		return "", errors.Wrap(err, "failed to get import private key")
   151  	}
   152  
   153  	fmt.Printf("Imported account %s to path: %s\n", acc.Address.Hex(), acc.URL.Path)
   154  
   155  	return acc.Address.Hex(), nil
   156  }