Compare commits

...

8 Commits

Author SHA1 Message Date
Jim McDonald
8078359eab Show account info for dynamically generated HD accounts 2020-07-28 20:16:41 +01:00
Jim McDonald
7de8dc7424 Show account info for dynamically generated HD accounts 2020-07-28 20:14:43 +01:00
Jim McDonald
987dbd26c6 Provide deposit info prior to chain-based info 2020-07-24 13:56:53 +01:00
Jim McDonald
1f0aeac9b4 Bump version 2020-07-24 13:34:33 +01:00
Jim McDonald
37cab43242 Add deposit data to validator info. 2020-07-24 13:30:52 +01:00
Jim McDonald
6f94e599ac Update dependencies. 2020-07-24 12:40:19 +01:00
Jim McDonald
86bc3d5418 Allow creation of HD wallets with seed extension. 2020-07-24 12:25:06 +01:00
Jim McDonald
8cc45f0b4b Sort accounts by path (if available) or name (if not). 2020-07-24 12:24:16 +01:00
14 changed files with 382 additions and 171 deletions

View File

@@ -61,6 +61,7 @@ In quiet mode this will return 0 if the account is created successfully, otherwi
defer cancel()
account, err = distributedCreator.CreateDistributedAccount(ctx, accountName, viper.GetUint32("participants"), viper.GetUint32("signing-threshold"), []byte(getPassphrase()))
} else {
// Want a standard account.
creator, isCreator := wallet.(e2wtypes.WalletAccountCreator)
assert(isCreator, "Wallet does not support account creation")
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))

View File

@@ -17,6 +17,7 @@ import (
"context"
"fmt"
"os"
"strings"
"github.com/spf13/cobra"
"github.com/spf13/viper"
@@ -39,10 +40,21 @@ In quiet mode this will return 0 if the account exists, otherwise 1.`,
wallet, err := openWallet()
errCheck(err, "Failed to access wallet")
outputIf(debug, fmt.Sprintf("Opened wallet %q of type %s", wallet.Name(), wallet.Type()))
_, accountName, err := e2wallet.WalletAndAccountNames(viper.GetString("account"))
errCheck(err, "Failed to obtain account name")
if wallet.Type() == "hierarchical deterministic" && strings.HasPrefix(accountName, "m/") {
assert(getWalletPassphrase() != "", "walletpassphrase is required to show information about dynamically generated hierarchical deterministic accounts")
locker, isLocker := wallet.(e2wtypes.WalletLocker)
if isLocker {
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
errCheck(locker.Unlock(ctx, []byte(getWalletPassphrase())), "Failed to unlock wallet")
}
}
accountByNameProvider, isAccountByNameProvider := wallet.(e2wtypes.WalletAccountByNameProvider)
assert(isAccountByNameProvider, "wallet cannot obtain accounts by name")
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))

View File

@@ -57,10 +57,10 @@ func assert(condition bool, msg string) {
// die prints an error and quits
func die(msg string) {
if !quiet {
if msg != "" && !quiet {
fmt.Fprintf(os.Stderr, "%s\n", msg)
}
os.Exit(1)
os.Exit(_exitFailure)
}
// warnCheck checks for an error and warns if it is present

47
cmd/networks.go Normal file
View File

@@ -0,0 +1,47 @@
// Copyright © 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"fmt"
"github.com/wealdtech/ethdo/grpc"
)
// networks is a map of deposit contract addresses to networks.
var networks = map[string]string{
"16e82d77882a663454ef92806b7deca1d394810f": "Altona",
"0f0f0fc0530007361933eab5db97d09acdd6c1c8": "Onyx",
"07b39f4fde4a38bace212b546dac87c58dfe3fdc": "Medalla",
}
// network returns the name of the network, if known.
func network() string {
if err := connect(); err != nil {
return "Unknown"
}
depositContractAddress, err := grpc.FetchDepositContractAddress(eth2GRPCConn)
if err != nil {
return "Unknown"
}
outputIf(debug, fmt.Sprintf("Deposit contract is %x", depositContractAddress))
depositContract := fmt.Sprintf("%x", depositContractAddress)
if network, exists := networks[depositContract]; exists {
return network
} else {
return "Unknown"
}
}

View File

@@ -310,6 +310,11 @@ func accountsFromPath(ctx context.Context, wallet e2wtypes.Wallet, accountSpec s
// connect connects to an Ethereum 2 endpoint.
func connect() error {
if eth2GRPCConn != nil {
// Already connected.
return nil
}
connection := ""
if viper.GetString("connection") != "" {
connection = viper.GetString("connection")

View File

@@ -14,13 +14,19 @@
package cmd
import (
"bytes"
"context"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"strconv"
"strings"
"time"
"github.com/pkg/errors"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/spf13/cobra"
"github.com/spf13/viper"
@@ -42,74 +48,76 @@ var validatorInfoCmd = &cobra.Command{
In quiet mode this will return 0 if the validator information can be obtained, otherwise 1.`,
Run: func(cmd *cobra.Command, args []string) {
// Sanity checking and setup.
assert(viper.GetString("account") != "" || validatorInfoPubKey != "", "--account or --pubkey is required")
err := connect()
errCheck(err, "Failed to obtain connection to Ethereum 2 beacon chain node")
var account e2wtypes.Account
if viper.GetString("account") != "" {
wallet, err := openWallet()
errCheck(err, "Failed to access wallet")
_, accountName, err := e2wallet.WalletAndAccountNames(viper.GetString("account"))
errCheck(err, "Failed to obtain account name")
accountByNameProvider, isAccountByNameProvider := wallet.(e2wtypes.WalletAccountByNameProvider)
assert(isAccountByNameProvider, "wallet cannot obtain accounts by name")
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
account, err = accountByNameProvider.AccountByName(ctx, accountName)
errCheck(err, "Failed to obtain account")
} else {
pubKeyBytes, err := hex.DecodeString(strings.TrimPrefix(validatorInfoPubKey, "0x"))
errCheck(err, fmt.Sprintf("Failed to decode public key %s", validatorInfoPubKey))
account, err = util.NewScratchAccount(nil, pubKeyBytes)
errCheck(err, fmt.Sprintf("Invalid public key %s", validatorInfoPubKey))
account, err := validatorInfoAccount()
errCheck(err, "Failed to obtain validator account")
if verbose {
network := network()
outputIf(debug, fmt.Sprintf("Network is %s", network))
pubKey, err := bestPublicKey(account)
if err == nil {
deposits, totalDeposited, err := graphData(network, pubKey.Marshal())
if err == nil {
fmt.Printf("Number of deposits: %d\n", deposits)
fmt.Printf("Total deposited: %s\n", string2eth.GWeiToString(totalDeposited, true))
}
}
}
validatorInfo, err := grpc.FetchValidatorInfo(eth2GRPCConn, account)
errCheck(err, "Failed to obtain validator information")
validatorDef, err := grpc.FetchValidator(eth2GRPCConn, account)
validator, err := grpc.FetchValidator(eth2GRPCConn, account)
if err != nil {
// We can live with this.
validator = nil
}
if validatorInfo.Status != ethpb.ValidatorStatus_DEPOSITED &&
validatorInfo.Status != ethpb.ValidatorStatus_UNKNOWN_STATUS {
errCheck(err, "Failed to obtain validator definition")
}
assert(validatorInfo.Status != ethpb.ValidatorStatus_UNKNOWN_STATUS, "Not known as a validator")
if quiet {
os.Exit(_exitSuccess)
}
outputIf(verbose, fmt.Sprintf("Epoch of data:\t\t%v", validatorInfo.Epoch))
outputIf(verbose && validatorInfo.Status != ethpb.ValidatorStatus_DEPOSITED, fmt.Sprintf("Index:\t\t\t%v", validatorInfo.Index))
outputIf(verbose, fmt.Sprintf("Public key:\t\t%#x", validatorInfo.PublicKey))
fmt.Printf("Status:\t\t\t%s\n", strings.Title(strings.ToLower(validatorInfo.Status.String())))
fmt.Printf("Balance:\t\t%s\n", string2eth.GWeiToString(validatorInfo.Balance, true))
outputIf(verbose, fmt.Sprintf("Epoch of data: %v", validatorInfo.Epoch))
outputIf(verbose && validatorInfo.Status != ethpb.ValidatorStatus_DEPOSITED, fmt.Sprintf("Index: %v", validatorInfo.Index))
outputIf(verbose, fmt.Sprintf("Public key: %#x", validatorInfo.PublicKey))
fmt.Printf("Status: %s\n", strings.Title(strings.ToLower(validatorInfo.Status.String())))
fmt.Printf("Balance: %s\n", string2eth.GWeiToString(validatorInfo.Balance, true))
if validatorInfo.Status == ethpb.ValidatorStatus_ACTIVE ||
validatorInfo.Status == ethpb.ValidatorStatus_EXITING ||
validatorInfo.Status == ethpb.ValidatorStatus_SLASHING {
fmt.Printf("Effective balance:\t%s\n", string2eth.GWeiToString(validatorInfo.EffectiveBalance, true))
fmt.Printf("Effective balance: %s\n", string2eth.GWeiToString(validatorInfo.EffectiveBalance, true))
}
if validatorDef != nil {
outputIf(verbose, fmt.Sprintf("Withdrawal credentials:\t%#x", validatorDef.WithdrawalCredentials))
if validator != nil {
outputIf(verbose, fmt.Sprintf("Withdrawal credentials: %#x", validator.WithdrawalCredentials))
}
transition := time.Unix(int64(validatorInfo.TransitionTimestamp), 0)
transitionPassed := int64(validatorInfo.TransitionTimestamp) <= time.Now().Unix()
switch validatorInfo.Status {
case ethpb.ValidatorStatus_DEPOSITED:
if validatorInfo.TransitionTimestamp != 0 {
fmt.Printf("Inclusion in chain:\t%s\n", transition)
fmt.Printf("Inclusion in chain: %s\n", transition)
}
case ethpb.ValidatorStatus_PENDING:
fmt.Printf("Activation:\t\t%s\n", transition)
fmt.Printf("Activation: %s\n", transition)
case ethpb.ValidatorStatus_EXITING, ethpb.ValidatorStatus_SLASHING:
fmt.Printf("Attesting finishes:\t%s\n", transition)
fmt.Printf("Attesting finishes: %s\n", transition)
case ethpb.ValidatorStatus_EXITED:
if transitionPassed {
fmt.Printf("Funds withdrawable:\tNow\n")
fmt.Printf("Funds withdrawable: Now\n")
} else {
fmt.Printf("Funds withdrawable:\t%s\n", transition)
fmt.Printf("Funds withdrawable: %s\n", transition)
}
}
@@ -117,6 +125,98 @@ In quiet mode this will return 0 if the validator information can be obtained, o
},
}
// validatorInfoAccount obtains the account for the validator info command.
func validatorInfoAccount() (e2wtypes.Account, error) {
var account e2wtypes.Account
if viper.GetString("account") != "" {
wallet, err := openWallet()
if err != nil {
return nil, errors.Wrap(err, "failed to open wallet")
}
_, accountName, err := e2wallet.WalletAndAccountNames(viper.GetString("account"))
if err != nil {
return nil, errors.Wrap(err, "failed to obtain account name")
}
if wallet.Type() == "hierarchical deterministic" && strings.HasPrefix(accountName, "m/") {
assert(getWalletPassphrase() != "", "walletpassphrase is required to obtain information about validators with dynamically generated hierarchical deterministic accounts")
locker, isLocker := wallet.(e2wtypes.WalletLocker)
if isLocker {
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
errCheck(locker.Unlock(ctx, []byte(getWalletPassphrase())), "Failed to unlock wallet")
}
}
accountByNameProvider, isProvider := wallet.(e2wtypes.WalletAccountByNameProvider)
if !isProvider {
return nil, errors.New("failed to ask wallet for account by name")
}
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
account, err = accountByNameProvider.AccountByName(ctx, accountName)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain account")
}
} else {
pubKeyBytes, err := hex.DecodeString(strings.TrimPrefix(validatorInfoPubKey, "0x"))
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("failed to decode public key %s", validatorInfoPubKey))
}
account, err = util.NewScratchAccount(nil, pubKeyBytes)
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("invalid public key %s", validatorInfoPubKey))
}
}
return account, nil
}
// graphData returns data from the graph about number and amount of deposits
func graphData(network string, validatorPubKey []byte) (uint64, uint64, error) {
subgraph := fmt.Sprintf("attestantio/eth2deposits-%s", strings.ToLower(network))
query := fmt.Sprintf(`{"query": "{deposits(where: {validatorPubKey:\"%#x\"}) { id amount withdrawalCredentials }}"}`, validatorPubKey)
url := fmt.Sprintf("https://api.thegraph.com/subgraphs/name/%s", subgraph)
graphResp, err := http.Post(url, "application/json", bytes.NewBufferString(query))
if err != nil {
return 0, 0, errors.Wrap(err, "failed to check if there is already a deposit for this validator")
}
defer graphResp.Body.Close()
body, err := ioutil.ReadAll(graphResp.Body)
if err != nil {
return 0, 0, errors.Wrap(err, "bad information returned from existing deposit check")
}
type graphDeposit struct {
Index string `json:"index"`
Amount string `json:"amount"`
WithdrawalCredentials string `json:"withdrawalCredentials"`
}
type graphData struct {
Deposits []*graphDeposit `json:"deposits,omitempty"`
}
type graphResponse struct {
Data *graphData `json:"data,omitempty"`
}
var response graphResponse
if err := json.Unmarshal(body, &response); err != nil {
return 0, 0, errors.Wrap(err, "invalid data returned from existing deposit check")
}
deposits := uint64(0)
totalDeposited := uint64(0)
if response.Data != nil && len(response.Data.Deposits) > 0 {
for _, deposit := range response.Data.Deposits {
deposits++
depositAmount, err := strconv.ParseUint(deposit.Amount, 10, 64)
if err != nil {
return 0, 0, errors.Wrap(err, fmt.Sprintf("invalid deposit amount from pre-existing deposit %s", deposit.Amount))
}
totalDeposited += depositAmount
}
}
return deposits, totalDeposited, nil
}
func init() {
validatorCmd.AddCommand(validatorInfoCmd)
validatorInfoCmd.Flags().StringVar(&validatorInfoPubKey, "pubkey", "", "Public key for which to obtain status")

View File

@@ -22,7 +22,7 @@ import (
"github.com/spf13/viper"
)
var ReleaseVersion = "local build"
var ReleaseVersion = "local build from v1.5.2"
// versionCmd represents the version command
var versionCmd = &cobra.Command{

View File

@@ -17,6 +17,9 @@ import (
"context"
"fmt"
"os"
"sort"
"strconv"
"strings"
"github.com/spf13/cobra"
"github.com/spf13/viper"
@@ -40,27 +43,66 @@ In quiet mode this will return 0 if the wallet holds any addresses, otherwise 1.
wallet, err := openWallet()
errCheck(err, "Failed to access wallet")
hasAccounts := false
accounts := make([]e2wtypes.Account, 0, 128)
for account := range wallet.Accounts(ctx) {
hasAccounts = true
accounts = append(accounts, account)
}
assert(len(accounts) > 0, "")
if _, isPathProvider := accounts[0].(e2wtypes.AccountPathProvider); isPathProvider {
// Order accounts by their path components.
sort.Slice(accounts, func(i int, j int) bool {
iBits := strings.Split(accounts[i].(e2wtypes.AccountPathProvider).Path(), "/")
jBits := strings.Split(accounts[j].(e2wtypes.AccountPathProvider).Path(), "/")
for index := range iBits {
if iBits[index] == "m" && jBits[index] == "m" {
continue
}
if len(jBits) <= index {
return false
}
iBit, err := strconv.ParseUint(iBits[index], 10, 64)
if err != nil {
return true
}
jBit, err := strconv.ParseUint(jBits[index], 10, 64)
if err != nil {
return false
}
if iBit < jBit {
return true
}
if iBit > jBit {
return false
}
}
return len(jBits) > len(iBits)
})
} else {
// Order accounts by their name.
sort.Slice(accounts, func(i int, j int) bool {
return strings.Compare(accounts[i].Name(), accounts[j].Name()) < 0
})
}
for _, account := range accounts {
outputIf(!quiet, account.Name())
if verbose {
fmt.Printf(" UUID: %v\n", account.ID())
pubKeyProvider, isProvider := account.(e2wtypes.AccountPublicKeyProvider)
if isProvider {
if pathProvider, isProvider := account.(e2wtypes.AccountPathProvider); isProvider {
if pathProvider.Path() != "" {
fmt.Printf("Path: %s\n", pathProvider.Path())
}
}
if pubKeyProvider, isProvider := account.(e2wtypes.AccountPublicKeyProvider); isProvider {
fmt.Printf(" Public key: %#x\n", pubKeyProvider.PublicKey().Marshal())
}
compositePubKeyProvider, isProvider := account.(e2wtypes.AccountCompositePublicKeyProvider)
if isProvider {
if compositePubKeyProvider, isProvider := account.(e2wtypes.AccountCompositePublicKeyProvider); isProvider {
fmt.Printf(" Composite public key: %#x\n", compositePubKeyProvider.CompositePublicKey().Marshal())
}
}
}
if hasAccounts {
os.Exit(_exitSuccess)
}
os.Exit(_exitFailure)
os.Exit(_exitSuccess)
},
}

View File

@@ -15,8 +15,12 @@ package cmd
import (
"context"
"crypto/rand"
"fmt"
"os"
"strings"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
bip39 "github.com/tyler-smith/go-bip39"
@@ -26,9 +30,6 @@ import (
nd "github.com/wealdtech/go-eth2-wallet-nd/v2"
)
var walletCreateType string
var walletCreateSeed string
var walletCreateCmd = &cobra.Command{
Use: "create",
Short: "Create a wallet",
@@ -43,18 +44,22 @@ In quiet mode this will return 0 if the wallet is created successfully, otherwis
assert(viper.GetString("remote") == "", "wallet create not available with remote wallets")
assert(viper.GetString("wallet") != "", "--wallet is required")
assert(walletCreateType != "", "--type is required")
assert(viper.GetString("type") != "", "--type is required")
var err error
switch strings.ToLower(walletCreateType) {
switch strings.ToLower(viper.GetString("type")) {
case "non-deterministic", "nd":
assert(walletCreateSeed == "", "--seed is not allowed with non-deterministic wallets")
assert(viper.GetString("mnemonic") == "", "--mnemonic is not allowed with non-deterministic wallets")
err = walletCreateND(ctx, viper.GetString("wallet"))
case "hierarchical deterministic", "hd":
if quiet {
fmt.Printf("Creation of hierarchical deterministic wallets prints its mnemonic, so cannot be run with the --quiet flag")
os.Exit(_exitFailure)
}
assert(getWalletPassphrase() != "", "--walletpassphrase is required for hierarchical deterministic wallets")
err = walletCreateHD(ctx, viper.GetString("wallet"), getWalletPassphrase(), walletCreateSeed)
err = walletCreateHD(ctx, viper.GetString("wallet"), getWalletPassphrase(), viper.GetString("mnemonic"))
case "distributed":
assert(walletCreateSeed == "", "--seed is not allowed with distributed wallets")
assert(viper.GetString("mnemonic") == "", "--mnemonic is not allowed with distributed wallets")
err = walletCreateDistributed(ctx, viper.GetString("wallet"))
default:
die("unknown wallet type")
@@ -75,28 +80,66 @@ func walletCreateDistributed(ctx context.Context, name string) error {
return err
}
// walletCreateND creates a hierarchical-deterministic wallet.
func walletCreateHD(ctx context.Context, name string, passphrase string, seedPhrase string) error {
// walletCreateHD creates a hierarchical-deterministic wallet.
func walletCreateHD(ctx context.Context, name string, passphrase string, mnemonic string) error {
encryptor := keystorev4.New()
if seedPhrase != "" {
// Create wallet from a user-supplied seed.
var seed []byte
seed, err := bip39.MnemonicToByteArray(seedPhrase)
errCheck(err, "Failed to decode seed")
// Strip checksum; last byte.
seed = seed[:len(seed)-1]
assert(len(seed) == 32, "Seed must have 24 words")
_, err = hd.CreateWalletFromSeed(ctx, name, []byte(passphrase), store, encryptor, seed)
return err
printMnemonic := mnemonic == ""
mnemonicPassphrase := ""
if mnemonic == "" {
// Create a new random mnemonic.
entropy := make([]byte, 32)
_, err := rand.Read(entropy)
if err != nil {
return errors.Wrap(err, "failed to generate entropy for wallet mnemonic")
}
mnemonic, err = bip39.NewMnemonic(entropy)
if err != nil {
return errors.Wrap(err, "failed to generate wallet mnemonic")
}
} else {
// We have an existing mnemonic. If there are more than 24 words we treat the additional characters as the passphrase.
mnemonicParts := strings.Split(mnemonic, " ")
if len(mnemonicParts) > 24 {
mnemonic = strings.Join(mnemonicParts[:24], " ")
mnemonicPassphrase = strings.Join(mnemonicParts[24:], " ")
}
}
// Create wallet with a random seed.
_, err := hd.CreateWallet(ctx, name, []byte(passphrase), store, encryptor)
// Ensure the mnemonic is valid
if !bip39.IsMnemonicValid(mnemonic) {
return errors.New("mnemonic is not valid")
}
// Create seed from mnemonic and passphrase.
seed := bip39.NewSeed(mnemonic, mnemonicPassphrase)
_, err := hd.CreateWallet(ctx, name, []byte(passphrase), store, encryptor, seed)
if printMnemonic {
fmt.Printf(`The following phrase is your mnemonic for this wallet:
%s
Anyone with access to this mnemonic can recreate the accounts in this wallet, so please store this mnemonic safely. More information about mnemonics can be found at https://support.mycrypto.com/general-knowledge/cryptography/how-do-mnemonic-phrases-work
Please note this mnemonic is not stored within the wallet, so cannot be retrieved or displayed again. As such, this mnemonic should be written down or otherwise protected before proceeding.
`, mnemonic)
}
return err
}
func init() {
walletCmd.AddCommand(walletCreateCmd)
walletFlags(walletCreateCmd)
walletCreateCmd.Flags().StringVar(&walletCreateType, "type", "non-deterministic", "Type of wallet to create (non-deterministic or hierarchical deterministic)")
walletCreateCmd.Flags().StringVar(&walletCreateSeed, "seed", "", "The 24-word seed phrase for a hierarchical deterministic wallet")
walletCreateCmd.Flags().String("type", "non-deterministic", "Type of wallet to create (non-deterministic or hierarchical deterministic)")
if err := viper.BindPFlag("type", walletCreateCmd.Flags().Lookup("type")); err != nil {
panic(err)
}
walletCreateCmd.Flags().String("mnemonic", "", "The 24-word mnemonic for a hierarchical deterministic wallet")
if err := viper.BindPFlag("mnemonic", walletCreateCmd.Flags().Lookup("mnemonic")); err != nil {
panic(err)
}
}

View File

@@ -1,77 +0,0 @@
// Copyright © 2019, 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"bytes"
"context"
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/spf13/viper"
bip39 "github.com/tyler-smith/go-bip39"
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)
var walletSeedCmd = &cobra.Command{
Use: "seed",
Short: "Display the seed of a wallet",
Long: `Display the seed for an hierarchical deterministic wallet. For example:
ethdo wallet seed --wallet=primary
In quiet mode this will return 0 if the wallet is a hierarchical deterministic wallet, otherwise 1.`,
Run: func(cmd *cobra.Command, args []string) {
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
assert(viper.GetString("remote") == "", "wallet seed not available with remote wallets")
assert(viper.GetString("wallet") != "", "--wallet is required")
assert(getWalletPassphrase() != "", "--walletpassphrase is required")
wallet, err := walletFromPath(viper.GetString("wallet"))
errCheck(err, "Failed to access wallet")
_, ok := wallet.(e2wtypes.WalletKeyProvider)
assert(ok, fmt.Sprintf("wallets of type %q do not have a seed", wallet.Type()))
locker, isLocker := wallet.(e2wtypes.WalletLocker)
if isLocker {
errCheck(locker.Unlock(ctx, []byte(getWalletPassphrase())), "Failed to unlock wallet")
}
keyProvider, isKeyProvider := wallet.(e2wtypes.WalletKeyProvider)
assert(isKeyProvider, "Wallet does not provide key")
seed, err := keyProvider.Key(ctx)
errCheck(err, "Failed to obtain wallet key")
outputIf(debug, fmt.Sprintf("Seed is %#x", seed))
seedStr, err := bip39.NewMnemonic(seed)
errCheck(err, "Failed to generate seed mnemonic")
// Re-read mnemonimc to ensure correctness.
recalcSeed, err := bip39.MnemonicToByteArray(seedStr)
// Drop checksum (last byte).
errCheck(err, "Failed to recalculate seed")
recalcSeed = recalcSeed[:len(recalcSeed)-1]
outputIf(debug, fmt.Sprintf("Recalc seed is %#x", recalcSeed))
errCheck(err, "Failed to recalculate seed mnemonic")
assert(bytes.Equal(recalcSeed, seed), "Generated invalid mnemonic")
outputIf(!quiet, seedStr)
os.Exit(_exitSuccess)
},
}
func init() {
walletCmd.AddCommand(walletSeedCmd)
walletFlags(walletSeedCmd)
}

View File

@@ -31,7 +31,7 @@ Spending: 0x85dfc6dcee4c9da36f6473ec02fda283d6c920c641fc8e3a76113c5c227d4aeeb100
- `wallet`: the name of the wallet to create
- `type`: the type of wallet to create. This can be either "nd" for a non-deterministic wallet, where private keys are generated randomly, or "hd" for a hierarchical deterministic wallet, where private keys are generated from a seed and path as per [ERC-2333](https://github.com/CarlBeek/EIPs/blob/bls_path/EIPS/eip-2334.md) (defaults to "nd")
- `walletpassphrase`: the passphrase for of the wallet. This is required for hierarchical deterministic wallets, to protect the seed
- `seed`: for hierarchical deterministic wallets only, use a pre-defined 24-word [BIP-39 seed phrase](https://en.bitcoin.it/wiki/Seed_phrase) to create the wallet. **Warning** The same seed can be imported in to multiple wallets, in which case they will generate the same keys. Please ensure that only a single wallet is active with any single seed phrase
- `mnemonic`: for hierarchical deterministic wallets only, use a pre-defined 24-word [BIP-39 seed phrase](https://en.bitcoin.it/wiki/Seed_phrase) to create the wallet, along with an additional "seed extension" phrase if required. **Warning** The same mnemonic can be used to create multiple wallets, in which case they will generate the same keys.
```sh
$ ethdo wallet create --wallet="Personal wallet" --type="hd" --walletpassphrase="my wallet secret"
@@ -103,17 +103,6 @@ Personal wallet
**N.B.** encrypted wallets will not show up in this list unless the correct passphrase for the store is supplied.
#### `seed`
`ethdo wallet seed` provides the seed for hierarchical deterministic wallets. Options include:
- `wallet`: the name of the wallet
- `walletpassphrase`: the passphrase for the wallet
```sh
$ ethdo wallet seed --wallet="Personal wallet" --walletpassphrase="my wallet secret"
decorate false mail domain gain later motion chair tank muffin smoke involve witness bean shell urge team solve share truly shadow decorate jeans hen
```
### `account` commands
Account commands focus on information about local accounts, generally those used by Geth and Parity but also those from hardware devices.

25
go.mod
View File

@@ -4,20 +4,21 @@ go 1.13
require (
github.com/OneOfOne/xxhash v1.2.5 // indirect
github.com/aws/aws-sdk-go v1.33.11 // indirect
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/gogo/protobuf v1.3.1
github.com/google/uuid v1.1.1
github.com/grpc-ecosystem/grpc-gateway v1.14.6 // indirect
github.com/herumi/bls-eth-go-binary v0.0.0-20200719025738-3e30d132e8f6
github.com/herumi/bls-eth-go-binary v0.0.0-20200722032157-41fc56eba7b4
github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/mapstructure v1.3.2 // indirect
github.com/mitchellh/mapstructure v1.3.3 // indirect
github.com/pelletier/go-toml v1.8.0 // indirect
github.com/pkg/errors v0.9.1
github.com/prysmaticlabs/ethereumapis v0.0.0-20200619200018-174e3b90d786
github.com/prysmaticlabs/ethereumapis v0.0.0-20200709024211-e8095222f77b
github.com/prysmaticlabs/go-bitfield v0.0.0-20200618145306-2ae0807bef65
github.com/prysmaticlabs/go-ssz v0.0.0-20200612203617-6d5c9aa213ae
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/spf13/afero v1.3.0 // indirect
github.com/spf13/afero v1.3.2 // indirect
github.com/spf13/cast v1.3.1 // indirect
github.com/spf13/cobra v1.0.0
github.com/spf13/jwalterweatherman v1.1.0 // indirect
@@ -29,17 +30,19 @@ require (
github.com/wealdtech/go-ecodec v1.1.0
github.com/wealdtech/go-eth2-types/v2 v2.5.0
github.com/wealdtech/go-eth2-util v1.5.0
github.com/wealdtech/go-eth2-wallet v1.11.0
github.com/wealdtech/go-eth2-wallet-dirk v1.0.0
github.com/wealdtech/go-eth2-wallet-distributed v1.0.1
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.0.0
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.2.0
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.2.0
github.com/wealdtech/go-eth2-wallet v1.12.0
github.com/wealdtech/go-eth2-wallet-dirk v1.0.1
github.com/wealdtech/go-eth2-wallet-distributed v1.1.0
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.0
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.3.0
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.3.0
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.16.1
github.com/wealdtech/go-eth2-wallet-store-s3 v1.8.0
github.com/wealdtech/go-eth2-wallet-types/v2 v2.5.0
github.com/wealdtech/go-eth2-wallet-types/v2 v2.6.0
github.com/wealdtech/go-string2eth v1.1.0
golang.org/x/sys v0.0.0-20200722175500-76b94024e4b6 // indirect
golang.org/x/text v0.3.3 // indirect
google.golang.org/genproto v0.0.0-20200722002428-88e341933a54 // indirect
google.golang.org/grpc v1.30.0
gopkg.in/ini.v1 v1.57.0 // indirect
)

31
go.sum
View File

@@ -29,6 +29,8 @@ github.com/aws/aws-sdk-go v1.32.6 h1:HoswAabUWgnrUF7X/9dr4WRgrr8DyscxXvTDm7Qw/5c
github.com/aws/aws-sdk-go v1.32.6/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go v1.33.5 h1:p2fr1ryvNTU6avUWLI+/H7FGv0TBIjzVM5WDgXBBv4U=
github.com/aws/aws-sdk-go v1.33.5/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go v1.33.11 h1:A7b3mNKbh/0zrhnNN/KxWD0YZJw2RImnjFXWOquYKB4=
github.com/aws/aws-sdk-go v1.33.11/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
@@ -155,6 +157,10 @@ github.com/herumi/bls-eth-go-binary v0.0.0-20200706085701-832d8c2c0f7d h1:P8yaFm
github.com/herumi/bls-eth-go-binary v0.0.0-20200706085701-832d8c2c0f7d/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U=
github.com/herumi/bls-eth-go-binary v0.0.0-20200719025738-3e30d132e8f6 h1:xOOHoKwCj0WXm60FqRxQ0u8cLr+kq5DJUlPspEPsu/s=
github.com/herumi/bls-eth-go-binary v0.0.0-20200719025738-3e30d132e8f6/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U=
github.com/herumi/bls-eth-go-binary v0.0.0-20200721081051-e31ced8c0204 h1:owpf19DI+vvpSOetnfE1NsLykSxZt8dSag7SDsJd8F0=
github.com/herumi/bls-eth-go-binary v0.0.0-20200721081051-e31ced8c0204/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U=
github.com/herumi/bls-eth-go-binary v0.0.0-20200722032157-41fc56eba7b4 h1:TfBVK1MJ9vhrMXWVHu5p/MlVHZTeCGgDAEu5RykVZeI=
github.com/herumi/bls-eth-go-binary v0.0.0-20200722032157-41fc56eba7b4/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jackc/puddle v1.1.1 h1:PJAw7H/9hoWC4Kf3J8iNmL1SwA6E8vfsLqBiL+F6CtI=
@@ -200,6 +206,8 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg=
github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8=
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
@@ -233,6 +241,8 @@ github.com/protolambda/zssz v0.1.5 h1:7fjJjissZIIaa2QcvmhS/pZISMX21zVITt49sW1oue
github.com/protolambda/zssz v0.1.5/go.mod h1:a4iwOX5FE7/JkKA+J/PH0Mjo9oXftN6P8NZyL28gpag=
github.com/prysmaticlabs/ethereumapis v0.0.0-20200619200018-174e3b90d786 h1:bJiOTV2sYykacsxViyRltztQY0DyjT/uFoVRZkEaxsY=
github.com/prysmaticlabs/ethereumapis v0.0.0-20200619200018-174e3b90d786/go.mod h1:rs05kpTfWKl0KflsBWzBQFstoyPFMTWQTbxSAyGHe78=
github.com/prysmaticlabs/ethereumapis v0.0.0-20200709024211-e8095222f77b h1:GjYix8Y4VpQhlsjA2ickr3HxjIns4bI36zOmC+lwaNw=
github.com/prysmaticlabs/ethereumapis v0.0.0-20200709024211-e8095222f77b/go.mod h1:rs05kpTfWKl0KflsBWzBQFstoyPFMTWQTbxSAyGHe78=
github.com/prysmaticlabs/go-bitfield v0.0.0-20191017011753-53b773adde52/go.mod h1:hCwmef+4qXWjv0jLDbQdWnL0Ol7cS7/lCSS26WR+u6s=
github.com/prysmaticlabs/go-bitfield v0.0.0-20200322041314-62c2aee71669/go.mod h1:hCwmef+4qXWjv0jLDbQdWnL0Ol7cS7/lCSS26WR+u6s=
github.com/prysmaticlabs/go-bitfield v0.0.0-20200618145306-2ae0807bef65 h1:hJfAWrlxx7SKpn4S/h2JGl2HHwA1a2wSS3HAzzZ0F+U=
@@ -263,6 +273,8 @@ github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.3.0 h1:Ysnmjh1Di8EaWaBv40CYR4IdaIsBc5996Gh1oZzCBKk=
github.com/spf13/afero v1.3.0/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
github.com/spf13/afero v1.3.2 h1:GDarE4TJQI52kYSbSAmLiId1Elfj+xgSDqrUZxFhxlU=
github.com/spf13/afero v1.3.2/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
@@ -320,18 +332,30 @@ github.com/wealdtech/go-eth2-wallet v1.10.2 h1:oUgi6Ih5fA9thhIipzXMSaLkiwDQXwT8q
github.com/wealdtech/go-eth2-wallet v1.10.2/go.mod h1:8H9pgp5K7X1kU1cJMS/B3DrMZF74ZlwBThownrcRYgk=
github.com/wealdtech/go-eth2-wallet v1.11.0 h1:2KfrWDqF4sWGgk4N5+DaYmh0hOnqiCl0P4vCz5mx17U=
github.com/wealdtech/go-eth2-wallet v1.11.0/go.mod h1:E9ZRNO4JNdi27ys7oc+xWWucXu4IGfV5q1vWC9X3oqg=
github.com/wealdtech/go-eth2-wallet v1.12.0 h1:nrwI3jPhehUhJGlBtNv/UmIo/57llvuVZZavLnfdQHI=
github.com/wealdtech/go-eth2-wallet v1.12.0/go.mod h1:ouV+YSMbzk2dyecmofm8jhaMKdSigdIPMSnSqmWEfW8=
github.com/wealdtech/go-eth2-wallet-dirk v1.0.0 h1:1QUcWILF3h4OLCgTPpWklvRSuPu0fqrt15jwSm7CSC4=
github.com/wealdtech/go-eth2-wallet-dirk v1.0.0/go.mod h1:VTzjJ51dedvYPr4huI7g7KXZVTpGR6ZrCDQwBxJpLck=
github.com/wealdtech/go-eth2-wallet-dirk v1.0.1 h1:YUE1QlJPun8b+xbz0JM71/3t1i9zp9KjcZdJvtJQL+E=
github.com/wealdtech/go-eth2-wallet-dirk v1.0.1/go.mod h1:5jK/aEAjYAVRBKKjYAvJWSmOWxiECs4asYXHwloNI+w=
github.com/wealdtech/go-eth2-wallet-distributed v1.0.1 h1:3BxMII8T6t16g6lWcYWXjfdvaw8rXuwMQx9h0TG5wRg=
github.com/wealdtech/go-eth2-wallet-distributed v1.0.1/go.mod h1:Ha/8S+SCLEuSfXHdvhTLwnKaEF47o6gzQ+FURKwftvU=
github.com/wealdtech/go-eth2-wallet-distributed v1.1.0 h1:OZjjuxcIYo+EhAfph7lYP1z+VeNs9ruOI32kqtYe1Jg=
github.com/wealdtech/go-eth2-wallet-distributed v1.1.0/go.mod h1:8r06Vpg/315/7Hl9CXq0ShQP8/cgUrBGzKKo6ywA4yQ=
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.0.0 h1:IcpS4VpXhYz+TVupB5n6C6IQzaKwG+Rc8nvgCa/da4c=
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.0.0/go.mod h1:X8WRO5hEwbjx8ZOqoRmtS1ngyflKs25GkP7qGv7yOqE=
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.0 h1:CWb82xeNaZQt1Z829RyDALUy7UZbc6VOfTS+82jRdEQ=
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.0/go.mod h1:JelKMM10UzDJNXdIcojMj6SCIsHC8NYn4c1S2FFk7OQ=
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.1.3/go.mod h1:STigKib4ZSefVvJjx88V2QpUGaoyUE1TiupcpsHpvKE=
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.2.0 h1:L+yrAn8TC9DQUw+S7moOJxQTp2jrHCoAZLpI747Nx2g=
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.2.0/go.mod h1:lhSwtkIO/Pfg5kz8k50yrDgj7ZQaElCPsXnixlrQn/I=
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.3.0 h1:UORXUYRoUYgYF96Y+QiBq33OKQVtn/nEjnSoQbe1UOA=
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.3.0/go.mod h1:Kc/8WcqMTczfH2xy5mDfCRd0NI/ca/j2jXmqJ7gz8yk=
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.1.2/go.mod h1:IssxoHII0ewO1VysMfCmdJP1D00tRhRhXIhhaEXIOVE=
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.2.0 h1:h4eePfG0ANOJYMonmIYOvxJ9uLmBEX4APb2O8Vhtv6k=
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.2.0/go.mod h1:Un2EtseZWSObmTBjgkt7Qz2am54S/0115jrF83lto1U=
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.3.0 h1:L1aPK9nc+8Ctcw+8I05vM6408weFc4a5RtLQDUeS0eE=
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.3.0/go.mod h1:e2q2uuEdq5+B3GE7jk+Mi9oz9V5nPPKXcXRg1XYavsU=
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.15.2 h1:Z4Pw7/Mlp6jJLoJnhgov8M1011HP/Pb3YYqcdYGCy6Q=
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.15.2/go.mod h1:GSMbVCewjbxRrw32m6YCd9DOzCRjAXB3qUOQnr58JEs=
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.16.0 h1:sWuSrAKdWSphiQCVcThozaFgTrwemXNXDI5CnFcP02s=
@@ -345,6 +369,7 @@ github.com/wealdtech/go-eth2-wallet-store-s3 v1.8.0/go.mod h1:OxYD+d79StAOHigNaI
github.com/wealdtech/go-eth2-wallet-store-scratch v1.4.2 h1:GvG3ZuzxbqFjGUaGoa8Tz7XbPlDA33G6nHQbSZInC3g=
github.com/wealdtech/go-eth2-wallet-store-scratch v1.4.2/go.mod h1:+TbqLmJuT98PWi/xW1bp5nwZbKz+SIJYVh/+NUkmnb4=
github.com/wealdtech/go-eth2-wallet-store-scratch v1.5.0/go.mod h1:RMIIV5/N8TgukTVzyumQd7AplpC440ZXDSk8VffeEwQ=
github.com/wealdtech/go-eth2-wallet-store-scratch v1.6.0/go.mod h1:XtXHbl4OV/XenQsvGmXbh+bVXaGS788oa30DB7kDInA=
github.com/wealdtech/go-eth2-wallet-types/v2 v2.2.0 h1:SfoBlW2LYjW05uHhnTZaezX37gbRsp+VYtxWT6SeAME=
github.com/wealdtech/go-eth2-wallet-types/v2 v2.2.0/go.mod h1:XEvrlKFnHLbg1tj4Dep76XKASeS13TBpvdeXmvLiH+k=
github.com/wealdtech/go-eth2-wallet-types/v2 v2.3.0-beta4 h1:VmpgUSr+aUexFmC2AYlQ7zpeAy0w0mcK58ihpDeMCL8=
@@ -353,6 +378,8 @@ github.com/wealdtech/go-eth2-wallet-types/v2 v2.3.0 h1:PsCvp/lw7+h8Q0V3jL0f+/w2V
github.com/wealdtech/go-eth2-wallet-types/v2 v2.3.0/go.mod h1:SLST6Pw/2wOEfsMYvIQjWlxbWX+jaZu8jIEbZJc4K5Q=
github.com/wealdtech/go-eth2-wallet-types/v2 v2.5.0 h1:J29mbkSCUMl2xdu8Lg6U+JptFGfmli6xl04DAHtq9aM=
github.com/wealdtech/go-eth2-wallet-types/v2 v2.5.0/go.mod h1:X9kYUH/E5YMqFMZ4xL6MJanABUkJGaH/yPZRT2o+yYA=
github.com/wealdtech/go-eth2-wallet-types/v2 v2.6.0 h1:vBrH5icPPSeb14cdShA7/P2PBZOgZscJ2IhBlTIaFrA=
github.com/wealdtech/go-eth2-wallet-types/v2 v2.6.0/go.mod h1:X9kYUH/E5YMqFMZ4xL6MJanABUkJGaH/yPZRT2o+yYA=
github.com/wealdtech/go-indexer v1.0.0 h1:/S4rfWQbSOnnYmwnvuTVatDibZ8o1s9bmTCHO16XINg=
github.com/wealdtech/go-indexer v1.0.0/go.mod h1:u1cjsbsOXsm5jzJDyLmZY7GsrdX8KYXKBXkZcAmk3Zg=
github.com/wealdtech/go-string2eth v1.1.0 h1:USJQmysUrBYYmZs7d45pMb90hRSyEwizP7lZaOZLDAw=
@@ -449,6 +476,8 @@ golang.org/x/sys v0.0.0-20200620081246-981b61492c35 h1:wb/9mP8eUAmHfkM8RmpeLq6nU
golang.org/x/sys v0.0.0-20200620081246-981b61492c35/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200722175500-76b94024e4b6 h1:X9xIZ1YU8bLZA3l6gqDUHSFiD0GFI9S548h6C8nDtOY=
golang.org/x/sys v0.0.0-20200722175500-76b94024e4b6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@@ -509,6 +538,8 @@ google.golang.org/genproto v0.0.0-20200711021454-869866162049 h1:YFTFpQhgvrLrmxt
google.golang.org/genproto v0.0.0-20200711021454-869866162049/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200715011427-11fb19a81f2c h1:6DWnZZ6EY/59QRRQttZKiktVL23UuQYs7uy75MhhLRM=
google.golang.org/genproto v0.0.0-20200715011427-11fb19a81f2c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200722002428-88e341933a54 h1:ASrBgpl9XvkNTP0m39/j18mid7aoF21npu2ioIBxYnY=
google.golang.org/genproto v0.0.0-20200722002428-88e341933a54/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=

View File

@@ -55,6 +55,21 @@ func FetchGenesisValidatorsRoot(conn *grpc.ClientConn) ([]byte, error) {
return res.GetGenesisValidatorsRoot(), nil
}
// FetchDepositContractAddress fetches the address of the deposit contract.
func FetchDepositContractAddress(conn *grpc.ClientConn) ([]byte, error) {
if conn == nil {
return nil, errors.New("no connection to beacon node")
}
client := ethpb.NewNodeClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
res, err := client.GetGenesis(ctx, &types.Empty{})
if err != nil {
return nil, err
}
return res.DepositContractAddress, nil
}
// FetchVersion fetches the version and metadata from the server.
func FetchVersion(conn *grpc.ClientConn) (string, string, error) {
if conn == nil {