func DefaultDataDir() string {
	home := homeDir()
	if home != "" {
		switch runtime.GOOS {
		case "darwin":
			return filepath.Join(home, "Library", "Ethereum")
		case "windows":
			fallback := filepath.Join(home, "AppData", "Roaming", "Ethereum")
			appdata := windowsAppData()
			if appdata == "" || isNonEmptyDir(fallback) {
				return fallback
			}
			return filepath.Join(appdata, "Ethereum")
		default:
			return filepath.Join(home, ".ethereum")
		}
	}
	return ""
}
DefaultDataDir is the default data directory to use for the databases and other
persistence requirements.
package cli
import (
	"errors"
	"fmt"
	"math/big"
	"os"
	"os/user"
	"path/filepath"
	"runtime"
	"github.com/ethereum/go-ethereum/accounts"
	"github.com/ethereum/go-ethereum/accounts/keystore"
	"github.com/ethereum/go-ethereum/accounts/usbwallet"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/params"
	homedir "github.com/mitchellh/go-homedir"
	"github.com/spf13/viper"
)
func ObtainWallets(chainID *big.Int) ([]accounts.Wallet, error) {
	var wallets []accounts.Wallet
	gethWallets, err := obtainGethWallets(chainID)
	if err != nil {
		return nil, err
	}
	wallets = append(wallets, gethWallets...)
	parityWallets, err := obtainParityWallets(chainID)
	if err != nil {
		return nil, err
	}
	wallets = append(wallets, parityWallets...)
	ledgerWallets, err := obtainLedgerWallets(chainID)
	if err != nil {
		return nil, err
	}
	wallets = append(wallets, ledgerWallets...)
	return wallets, nil
}
func ObtainWalletAndAccount(chainID *big.Int, address common.Address) (accounts.Wallet, *accounts.Account, error) {
	var account *accounts.Account
	wallet, err := ObtainWallet(chainID, address)
	if err == nil {
		account, err = ObtainAccount(&wallet, &address, viper.GetString("passphrase"))
	}
	return wallet, account, err
}
func ObtainWallet(chainID *big.Int, address common.Address) (accounts.Wallet, error) {
	wallet, err := obtainGethWallet(chainID, address)
	if err == nil {
		return wallet, nil
	}
	wallet, err = obtainParityWallet(chainID, address)
	if err == nil {
		return wallet, err
	}
	return wallet, fmt.Errorf("failed to obtain wallet for %s", address.Hex())
}
func obtainGethWallet(chainID *big.Int, address common.Address) (accounts.Wallet, error) {
	keydir := DefaultDataDir()
	switch {
	case chainID.Cmp(params.MainnetChainConfig.ChainID) == 0:
	case chainID.Cmp(params.RopstenChainConfig.ChainID) == 0:
		keydir = filepath.Join(keydir, "testnet")
	case chainID.Cmp(params.RinkebyChainConfig.ChainID) == 0:
		keydir = filepath.Join(keydir, "rinkeby")
	case chainID.Cmp(params.GoerliChainConfig.ChainID) == 0:
		keydir = filepath.Join(keydir, "goerli")
	}
	keydir = filepath.Join(keydir, "keystore")
	backends := []accounts.Backend{keystore.NewKeyStore(keydir, keystore.StandardScryptN, keystore.StandardScryptP)}
	accountManager := accounts.NewManager(nil, backends...)
	defer accountManager.Close()
	account := accounts.Account{Address: address}
	wallet, err := accountManager.Find(account)
	return wallet, err
}
func obtainGethWallets(chainID *big.Int) ([]accounts.Wallet, error) {
	keydir := DefaultDataDir()
	switch {
	case chainID.Cmp(params.MainnetChainConfig.ChainID) == 0:
	case chainID.Cmp(params.RopstenChainConfig.ChainID) == 0:
		keydir = filepath.Join(keydir, "testnet")
	case chainID.Cmp(params.RinkebyChainConfig.ChainID) == 0:
		keydir = filepath.Join(keydir, "rinkeby")
	case chainID.Cmp(params.GoerliChainConfig.ChainID) == 0:
		keydir = filepath.Join(keydir, "goerli")
	}
	keydir = filepath.Join(keydir, "keystore")
	backends := []accounts.Backend{keystore.NewKeyStore(keydir, keystore.StandardScryptN, keystore.StandardScryptP)}
	accountManager := accounts.NewManager(nil, backends...)
	defer accountManager.Close()
	return accountManager.Wallets(), nil
}
func obtainParityWallet(chainID *big.Int, address common.Address) (accounts.Wallet, error) {
	keydir, err := homedir.Dir()
	if err != nil {
		return nil, fmt.Errorf("failed to find home directory")
	}
	switch runtime.GOOS {
	case "windows":
		keydir = filepath.Join(keydir, "AppData\\Roaming\\Parity\\Ethereum\\keys")
	case "darwin":
		keydir = filepath.Join(keydir, "Library/Application Support/io.parity.ethereum/keys")
	case "linux":
		keydir = filepath.Join(keydir, ".local/share/io.parity.ethereum/keys")
	default:
		return nil, fmt.Errorf("unsupported operating system")
	}
	if chainID.Cmp(params.MainnetChainConfig.ChainID) == 0 {
		keydir = filepath.Join(keydir, "ethereum")
	} else if chainID.Cmp(params.RopstenChainConfig.ChainID) == 0 {
		keydir = filepath.Join(keydir, "test")
	}
	backends := []accounts.Backend{keystore.NewKeyStore(keydir, keystore.StandardScryptN, keystore.StandardScryptP)}
	accountManager := accounts.NewManager(nil, backends...)
	defer accountManager.Close()
	account := accounts.Account{Address: address}
	wallet, err := accountManager.Find(account)
	return wallet, err
}
func obtainParityWallets(chainID *big.Int) ([]accounts.Wallet, error) {
	keydir, err := homedir.Dir()
	if err != nil {
		return nil, fmt.Errorf("failed to find home directory")
	}
	switch runtime.GOOS {
	case "windows":
		keydir = filepath.Join(keydir, "AppData\\Roaming\\Parity\\Ethereum\\keys")
	case "darwin":
		keydir = filepath.Join(keydir, "Library/Application Support/io.parity.ethereum/keys")
	case "linux":
		keydir = filepath.Join(keydir, ".local/share/io.parity.ethereum/keys")
	default:
		return nil, fmt.Errorf("unsupported operating system")
	}
	if chainID.Cmp(params.MainnetChainConfig.ChainID) == 0 {
		keydir = filepath.Join(keydir, "ethereum")
	} else if chainID.Cmp(params.RopstenChainConfig.ChainID) == 0 {
		keydir = filepath.Join(keydir, "test")
	}
	backends := []accounts.Backend{keystore.NewKeyStore(keydir, keystore.StandardScryptN, keystore.StandardScryptP)}
	accountManager := accounts.NewManager(nil, backends...)
	defer accountManager.Close()
	return accountManager.Wallets(), nil
}
func obtainLedgerWallets(chainID *big.Int) ([]accounts.Wallet, error) {
	ledgerhub, err := usbwallet.NewLedgerHub()
	if err != nil {
		return nil, err
	}
	backends := []accounts.Backend{ledgerhub}
	accountManager := accounts.NewManager(nil, backends...)
	defer accountManager.Close()
	usbWallets := viper.GetInt("usbwallets")
	for _, wallet := range accountManager.Wallets() {
		err = wallet.Open("")
		if err != nil {
			continue
		}
		path := accounts.LegacyLedgerBaseDerivationPath
		for i := 0; i < usbWallets; i++ {
			path[3] = uint32(i)
			wallet.Derive(path, true)
		}
	}
	return accountManager.Wallets(), nil
}
func ObtainAccount(wallet *accounts.Wallet, address *common.Address, passphrase string) (*accounts.Account, error) {
	for _, account := range (*wallet).Accounts() {
		if *address == account.Address {
			if passphrase != "" && !VerifyPassphrase(*wallet, account, passphrase) {
				return nil, errors.New("invalid passphrase")
			}
			return &account, nil
		}
	}
	return nil, errors.New("account not found")
}
func VerifyPassphrase(wallet accounts.Wallet, account accounts.Account, passphrase string) bool {
	_, err := wallet.SignDataWithPassphrase(account, passphrase, "application/octet-stream", []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
	return err == nil
}