mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2025-01-16 23:08:45 +00:00
60558b7970
* keymanagers no longer use cli ctx * rename important values to keymanageropts * further refactor accounts methods to reduce cli dependency * separating cli vs non cli methods for various accounts functions * recover wallet cli vs non-cli mode * ensure half of tests build * accounts v2 package now builds * full revamp wallet creation or opening wallets * everything builds * tests pass finally * Merge branch 'master' into no-cli-keymanagers * ensure commands work as expected * Merge branch 'no-cli-keymanagers' of github.com:prysmaticlabs/prysm into no-cli-keymanagers * further fix build * account creation comments * fix imports and comments * fix up failing test * fix build * Update derived.go * Update direct.go * Update remote.go * Fixed variable * fix up red tests * use Cli instead of CLI, fix tests, and address Radek's feedback * Merge refs/heads/master into no-cli-keymanagers * Merge refs/heads/master into no-cli-keymanagers * Merge refs/heads/master into no-cli-keymanagers * Merge refs/heads/master into no-cli-keymanagers * Merge refs/heads/master into no-cli-keymanagers * Merge refs/heads/master into no-cli-keymanagers * Merge refs/heads/master into no-cli-keymanagers * Merge refs/heads/master into no-cli-keymanagers
193 lines
6.6 KiB
Go
193 lines
6.6 KiB
Go
package v2
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/manifoldco/promptui"
|
|
"github.com/pkg/errors"
|
|
"github.com/prysmaticlabs/prysm/shared/bls"
|
|
"github.com/prysmaticlabs/prysm/shared/fileutil"
|
|
"github.com/prysmaticlabs/prysm/shared/params"
|
|
"github.com/prysmaticlabs/prysm/shared/promptutil"
|
|
"github.com/prysmaticlabs/prysm/validator/flags"
|
|
v2keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v2"
|
|
"github.com/prysmaticlabs/prysm/validator/keymanager/v2/derived"
|
|
"github.com/urfave/cli/v2"
|
|
)
|
|
|
|
// SendDepositCli transaction for user specified accounts via an interactive
|
|
// CLI process or via command-line flags.
|
|
func SendDepositCli(cliCtx *cli.Context) error {
|
|
wallet, err := OpenWalletOrElseCli(cliCtx, func(cliCtx *cli.Context) (*Wallet, error) {
|
|
return nil, errors.New(
|
|
"no wallet found, nothing to deposit",
|
|
)
|
|
})
|
|
if err != nil {
|
|
return errors.Wrap(err, "could not open wallet")
|
|
}
|
|
keymanager, err := wallet.InitializeKeymanager(
|
|
cliCtx.Context,
|
|
true, /* skip mnemonic confirm */
|
|
)
|
|
if err != nil && strings.Contains(err.Error(), "invalid checksum") {
|
|
return errors.New("wrong wallet password entered")
|
|
}
|
|
if err != nil {
|
|
return errors.Wrap(err, "could not initialize keymanager")
|
|
}
|
|
switch wallet.KeymanagerKind() {
|
|
case v2keymanager.Derived:
|
|
km, ok := keymanager.(*derived.Keymanager)
|
|
if !ok {
|
|
return errors.New("could not assert keymanager interface to concrete type")
|
|
}
|
|
depositConfig, err := createDepositConfig(cliCtx, km)
|
|
if err != nil {
|
|
return errors.Wrap(err, "could not initialize deposit config")
|
|
}
|
|
if err := km.SendDepositTx(depositConfig); err != nil {
|
|
return err
|
|
}
|
|
default:
|
|
return errors.New("only Prysm HD wallets support sending deposits at the moment")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func createDepositConfig(cliCtx *cli.Context, km *derived.Keymanager) (*derived.SendDepositConfig, error) {
|
|
pubKeysBytes, err := km.FetchValidatingPublicKeys(context.Background())
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "could not fetch validating public keys")
|
|
}
|
|
pubKeys := make([]bls.PublicKey, len(pubKeysBytes))
|
|
for i, pk := range pubKeysBytes {
|
|
pubKeys[i], err = bls.PublicKeyFromBytes(pk[:])
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "could not parse BLS public key")
|
|
}
|
|
}
|
|
// Allow the user to interactively select the accounts to backup or optionally
|
|
// provide them via cli flags as a string of comma-separated, hex strings. If the user has
|
|
// selected to deposit all accounts, we skip this part.
|
|
if !cliCtx.IsSet(flags.DepositPublicKeysFlag.Name) {
|
|
pubKeys, err = filterPublicKeysFromUserInput(
|
|
cliCtx,
|
|
flags.DepositPublicKeysFlag,
|
|
pubKeysBytes,
|
|
selectAccountsDepositPromptText,
|
|
)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "could not filter validating public keys for deposit")
|
|
}
|
|
}
|
|
|
|
web3Provider := cliCtx.String(flags.HTTPWeb3ProviderFlag.Name)
|
|
// Enter the web3provider information.
|
|
if web3Provider == "" {
|
|
web3Provider, err = promptutil.DefaultAndValidatePrompt(
|
|
"Enter the HTTP address of your eth1 endpoint for the Goerli testnet",
|
|
cliCtx.String(flags.HTTPWeb3ProviderFlag.Name),
|
|
func(input string) error {
|
|
return nil
|
|
},
|
|
)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "could not validate web3 provider endpoint")
|
|
}
|
|
}
|
|
depositDelaySeconds := cliCtx.Int(flags.DepositDelaySecondsFlag.Name)
|
|
config := &derived.SendDepositConfig{
|
|
DepositContractAddress: cliCtx.String(flags.DepositContractAddressFlag.Name),
|
|
DepositDelaySeconds: time.Duration(depositDelaySeconds) * time.Second,
|
|
DepositPublicKeys: pubKeys,
|
|
Web3Provider: web3Provider,
|
|
}
|
|
|
|
if !cliCtx.Bool(flags.SkipDepositConfirmationFlag.Name) {
|
|
confirmDepositPrompt := "You are about to send %d ETH into contract address %s for %d eth2 validator accounts. " +
|
|
"Are you sure you want to do this? Enter the words 'yes I do' to continue"
|
|
gweiPerEth := params.BeaconConfig().GweiPerEth
|
|
ethDepositTotal := uint64(len(pubKeys)) * params.BeaconConfig().MaxEffectiveBalance / gweiPerEth
|
|
if _, err := promptutil.ValidatePrompt(
|
|
os.Stdin,
|
|
fmt.Sprintf(confirmDepositPrompt, ethDepositTotal, config.DepositContractAddress, len(pubKeys)),
|
|
func(input string) error {
|
|
if input != "yes I do" {
|
|
return errors.New("please enter 'yes I do' or exit")
|
|
}
|
|
return nil
|
|
},
|
|
); err != nil {
|
|
return nil, errors.Wrap(err, "could not confirm deposit acknowledgement")
|
|
}
|
|
}
|
|
|
|
// If the user passes any of the specified flags, we read them and return the
|
|
// config struct directly, bypassing any CLI input.
|
|
hasPrivateKey := cliCtx.IsSet(flags.Eth1PrivateKeyFileFlag.Name)
|
|
hasEth1Keystore := cliCtx.IsSet(flags.Eth1KeystoreUTCPathFlag.Name)
|
|
if hasPrivateKey || hasEth1Keystore {
|
|
if hasPrivateKey {
|
|
fileBytes, err := fileutil.ReadFileAsBytes(cliCtx.String(flags.Eth1PrivateKeyFileFlag.Name))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
config.Eth1PrivateKey = strings.TrimRight(string(fileBytes), "\r\n")
|
|
}
|
|
return config, nil
|
|
}
|
|
|
|
usePrivateKeyPrompt := "Inputting an eth1 private key hex string directly"
|
|
useEth1KeystorePrompt := "Using an encrypted eth1 keystore UTC file"
|
|
eth1Prompt := promptui.Select{
|
|
Label: "Select how you wish to sign your eth1 transaction",
|
|
Items: []string{
|
|
usePrivateKeyPrompt,
|
|
useEth1KeystorePrompt,
|
|
},
|
|
}
|
|
_, selection, err := eth1Prompt.Run()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// If the user wants to proceed by inputting their private key directly, ask for it securely.
|
|
if selection == usePrivateKeyPrompt {
|
|
eth1PrivateKeyString, err := promptutil.PasswordPrompt(
|
|
"Enter the hex string value of your eth1 private key",
|
|
promptutil.NotEmpty,
|
|
)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "could not read eth1 private key string")
|
|
}
|
|
config.Eth1PrivateKey = strings.TrimRight(eth1PrivateKeyString, "\r\n")
|
|
} else if selection == useEth1KeystorePrompt {
|
|
// Otherwise, ask the user for paths to their keystore UTC file and its password.
|
|
eth1KeystoreUTCFile, err := promptutil.DefaultAndValidatePrompt(
|
|
"Enter the file path for your encrypted, eth1 keystore-utc file",
|
|
cliCtx.String(flags.Eth1KeystoreUTCPathFlag.Name),
|
|
func(input string) error {
|
|
return nil
|
|
},
|
|
)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "could not read eth1 keystore UTC path")
|
|
}
|
|
eth1KeystorePasswordFile, err := inputWeakPassword(
|
|
cliCtx,
|
|
flags.Eth1KeystorePasswordFileFlag,
|
|
"Enter the file path a .txt file containing your eth1 keystore password",
|
|
)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "could not read eth1 keystore password file path")
|
|
}
|
|
config.Eth1KeystoreUTCFile = eth1KeystoreUTCFile
|
|
config.Eth1KeystorePasswordFile = eth1KeystorePasswordFile
|
|
}
|
|
return config, nil
|
|
}
|