code.vegaprotocol.io/vega@v0.79.0/core/nodewallets/vega/loader.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package vega 17 18 import ( 19 "context" 20 "encoding/hex" 21 "fmt" 22 "path/filepath" 23 "time" 24 25 "code.vegaprotocol.io/vega/libs/crypto" 26 "code.vegaprotocol.io/vega/paths" 27 "code.vegaprotocol.io/vega/wallet/wallet" 28 storev1 "code.vegaprotocol.io/vega/wallet/wallet/store/v1" 29 "code.vegaprotocol.io/vega/wallet/wallets" 30 ) 31 32 type WalletLoader struct { 33 walletHome string 34 } 35 36 func InitialiseWalletLoader(vegaPaths paths.Paths) (*WalletLoader, error) { 37 walletHome, err := vegaPaths.CreateDataDirFor(paths.VegaNodeWalletsDataHome) 38 if err != nil { 39 return nil, fmt.Errorf("couldn't get the directory path for %s: %w", paths.VegaNodeWalletsDataHome, err) 40 } 41 42 return &WalletLoader{ 43 walletHome: walletHome, 44 }, nil 45 } 46 47 func (l *WalletLoader) Generate(passphrase string) (*Wallet, map[string]string, error) { 48 data := map[string]string{} 49 store, err := storev1.InitialiseStore(l.walletHome, false) 50 if err != nil { 51 return nil, nil, err 52 } 53 defer store.Close() 54 55 handler := wallets.NewHandler(store) 56 57 walletName := fmt.Sprintf("vega.%v", time.Now().UnixNano()) 58 mnemonic, err := handler.CreateWallet(walletName, passphrase) 59 if err != nil { 60 return nil, nil, err 61 } 62 data["mnemonic"] = mnemonic 63 data["walletFilePath"] = store.GetWalletPath(walletName) 64 65 _, err = handler.GenerateKeyPair(walletName, passphrase, []wallet.Metadata{}) 66 if err != nil { 67 return nil, nil, err 68 } 69 70 w, err := newWallet(l, store, walletName, passphrase) 71 if err != nil { 72 return nil, nil, fmt.Errorf("couldn't create wallet: %w", err) 73 } 74 return w, data, nil 75 } 76 77 func (l *WalletLoader) Load(walletName, passphrase string) (*Wallet, error) { 78 store, err := storev1.InitialiseStore(l.walletHome, false) 79 if err != nil { 80 return nil, err 81 } 82 defer store.Close() 83 84 return newWallet(l, store, walletName, passphrase) 85 } 86 87 func (l *WalletLoader) Import(sourceFilePath string, passphrase string) (*Wallet, map[string]string, error) { 88 ctx := context.Background() 89 90 sourcePath, sourceWalletName := filepath.Split(sourceFilePath) 91 92 w, err := importSourceWallet(ctx, sourcePath, sourceWalletName, passphrase) 93 if err != nil { 94 return nil, nil, err 95 } 96 97 destStore, err := storev1.InitialiseStore(l.walletHome, false) 98 if err != nil { 99 return nil, nil, fmt.Errorf("couldn't initialise destination wallet store: %w", err) 100 } 101 defer destStore.Close() 102 103 destWalletName := fmt.Sprintf("vega.%v", time.Now().UnixNano()) 104 w.SetName(destWalletName) 105 err = destStore.CreateWallet(ctx, w, passphrase) 106 if err != nil { 107 return nil, nil, fmt.Errorf("couldn't save the wallet %s: %w", destWalletName, err) 108 } 109 110 destWallet, err := newWallet(l, destStore, destWalletName, passphrase) 111 if err != nil { 112 return nil, nil, fmt.Errorf("couldn't create wallet: %w", err) 113 } 114 115 data := map[string]string{ 116 "walletFilePath": destStore.GetWalletPath(destWalletName), 117 } 118 119 return destWallet, data, nil 120 } 121 122 func importSourceWallet(ctx context.Context, sourcePath string, sourceWalletName string, passphrase string) (wallet.Wallet, error) { 123 sourceStore, err := storev1.InitialiseStore(sourcePath, false) 124 if err != nil { 125 return nil, fmt.Errorf("couldn't initialise source wallet store: %w", err) 126 } 127 defer sourceStore.Close() 128 129 if err := sourceStore.UnlockWallet(ctx, sourceWalletName, passphrase); err != nil { 130 return nil, fmt.Errorf("couldn't unlock the source wallet: %w", err) 131 } 132 133 w, err := sourceStore.GetWallet(ctx, sourceWalletName) 134 if err != nil { 135 return nil, fmt.Errorf("couldn't get source wallet %s: %w", sourceWalletName, err) 136 } 137 return w, nil 138 } 139 140 func newWallet(loader loader, store *storev1.FileStore, walletName, passphrase string) (*Wallet, error) { 141 ctx := context.Background() 142 if err := store.UnlockWallet(ctx, walletName, passphrase); err != nil { 143 return nil, fmt.Errorf("could not unlock the wallet %q: %w", walletName, err) 144 } 145 146 w, err := store.GetWallet(ctx, walletName) 147 if err != nil { 148 return nil, fmt.Errorf("could not get wallet %q: %w", walletName, err) 149 } 150 151 keyPairs := w.ListKeyPairs() 152 153 if keyPairCount := len(keyPairs); keyPairCount == 0 { 154 return nil, fmt.Errorf("vega wallet for node requires to have 1 key pair, none found") 155 } else if keyPairCount != 1 { 156 return nil, fmt.Errorf("vega wallet for node requires to have max 1 key pair, found %v", keyPairCount) 157 } 158 159 keyPair := keyPairs[0] 160 161 pubKey, err := getPubKey(keyPair) 162 if err != nil { 163 return nil, fmt.Errorf("couldn't get public key: %w", err) 164 } 165 166 walletID, err := getID(w) 167 if err != nil { 168 return nil, fmt.Errorf("couldn't get wallet ID: %w", err) 169 } 170 171 return &Wallet{ 172 loader: loader, 173 name: walletName, 174 keyPair: keyPair, 175 pubKey: pubKey, 176 walletID: walletID, 177 }, nil 178 } 179 180 func getPubKey(keyPair wallet.KeyPair) (crypto.PublicKey, error) { 181 decodedPubKey, err := hex.DecodeString(keyPair.PublicKey()) 182 if err != nil { 183 return crypto.PublicKey{}, fmt.Errorf("couldn't decode public key as hexadecimal: %w", err) 184 } 185 186 return crypto.NewPublicKey(keyPair.PublicKey(), decodedPubKey), nil 187 } 188 189 func getID(w wallet.Wallet) (crypto.PublicKey, error) { 190 decodedID, err := hex.DecodeString(w.ID()) 191 if err != nil { 192 return crypto.PublicKey{}, fmt.Errorf("couldn't decode wallet ID as hexadecimal: %w", err) 193 } 194 195 return crypto.NewPublicKey(w.ID(), decodedID), nil 196 }