code.vegaprotocol.io/vega@v0.79.0/core/nodewallets/eth/keystore/wallet.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 keystore 17 18 import ( 19 "fmt" 20 "os" 21 "path/filepath" 22 "sync" 23 24 "code.vegaprotocol.io/vega/core/nodewallets/registry" 25 "code.vegaprotocol.io/vega/libs/crypto" 26 vgrand "code.vegaprotocol.io/vega/libs/rand" 27 28 "github.com/ethereum/go-ethereum/accounts" 29 "github.com/ethereum/go-ethereum/accounts/keystore" 30 ) 31 32 const KeyStoreAlgoType = "eth" 33 34 type loader interface { 35 Load(walletName, passphrase string) (*Wallet, error) 36 } 37 38 type Wallet struct { 39 loader loader 40 name string 41 acc accounts.Account 42 ks *keystore.KeyStore 43 passphrase string 44 address crypto.PublicKey 45 mut sync.Mutex 46 } 47 48 func newWallet(loader loader, walletName, passphrase string, data []byte) (*Wallet, error) { 49 // NewKeyStore always create a new wallet key store file 50 // we create this in tmp as we do not want to impact the original one. 51 tempFile := filepath.Join(os.TempDir(), vgrand.RandomStr(10)) 52 ks := keystore.NewKeyStore(tempFile, keystore.StandardScryptN, keystore.StandardScryptP) 53 54 acc, err := ks.Import(data, passphrase, passphrase) 55 if err != nil { 56 return nil, fmt.Errorf("couldn't import Ethereum wallet in keystore: %w", err) 57 } 58 59 if err := ks.Unlock(acc, passphrase); err != nil { 60 return nil, fmt.Errorf("couldn't unlock Ethereum wallet: %w", err) 61 } 62 63 address := crypto.NewPublicKey(acc.Address.Hex(), acc.Address.Bytes()) 64 65 return &Wallet{ 66 loader: loader, 67 name: walletName, 68 acc: acc, 69 ks: ks, 70 passphrase: passphrase, 71 address: address, 72 }, nil 73 } 74 75 func (w *Wallet) Cleanup() error { 76 // just remove the wallet from the tmp file 77 return w.ks.Delete(w.acc, w.passphrase) 78 } 79 80 func (w *Wallet) Name() string { 81 return w.name 82 } 83 84 func (w *Wallet) Chain() string { 85 return "ethereum" 86 } 87 88 func (w *Wallet) Sign(data []byte) ([]byte, error) { 89 return w.ks.SignHash(w.acc, data) 90 } 91 92 func (w *Wallet) Algo() string { 93 return KeyStoreAlgoType 94 } 95 96 func (w *Wallet) Version() (string, error) { 97 return "0", nil 98 } 99 100 func (w *Wallet) PubKey() crypto.PublicKey { 101 return w.address 102 } 103 104 func (w *Wallet) Reload(details registry.EthereumWalletDetails) error { 105 d, ok := details.(registry.EthereumKeyStoreWallet) 106 if !ok { 107 // this would mean an implementation error 108 panic(fmt.Errorf("failed to get EthereumKeyStoreWallet")) 109 } 110 111 nW, err := w.loader.Load(d.Name, d.Passphrase) 112 if err != nil { 113 return fmt.Errorf("failed to load new wallet: %w", err) 114 } 115 116 w.mut.Lock() 117 defer w.mut.Unlock() 118 119 w.name = nW.name 120 w.acc = nW.acc 121 w.ks = nW.ks 122 w.passphrase = nW.passphrase 123 w.address = nW.address 124 125 return nil 126 }