mirror of
https://github.com/AthanorLabs/atomic-swap.git
synced 2026-01-09 14:18:03 -05:00
162 lines
4.6 KiB
Go
162 lines
4.6 KiB
Go
// Copyright 2023 The AthanorLabs/atomic-swap Authors
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
|
|
// Package cliutil provides utility functions intended for sharing by the main packages of multiple executables.
|
|
package cliutil
|
|
|
|
import (
|
|
"crypto/ecdsa"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime/debug"
|
|
"strings"
|
|
|
|
"github.com/cockroachdb/apd/v3"
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
ethcrypto "github.com/ethereum/go-ethereum/crypto"
|
|
logging "github.com/ipfs/go-log"
|
|
"github.com/urfave/cli/v2"
|
|
|
|
"github.com/athanorlabs/atomic-swap/common"
|
|
)
|
|
|
|
var (
|
|
// Only use this logger in functions called by programs that use formatted logs like swapd (not swapcli)
|
|
log = logging.Logger("cmd")
|
|
)
|
|
|
|
func createAndWriteEthKeyFile(ethPrivKeyFile string, env common.Environment, devXMRMaker, devXMRTaker bool) error {
|
|
var key *ecdsa.PrivateKey
|
|
var err error
|
|
|
|
switch {
|
|
case env == common.Development && devXMRMaker:
|
|
key, err = ethcrypto.HexToECDSA(common.DefaultPrivKeyXMRMaker)
|
|
case env == common.Development && devXMRTaker:
|
|
key, err = ethcrypto.HexToECDSA(common.DefaultPrivKeyXMRTaker)
|
|
default:
|
|
key, err = ethcrypto.GenerateKey()
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
privKeyStr := hexutil.Encode(ethcrypto.FromECDSA(key))
|
|
privKeyStr = strings.TrimPrefix(privKeyStr, "0x")
|
|
|
|
if err := os.WriteFile(ethPrivKeyFile, []byte(privKeyStr), 0600); err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Infof("New ETH wallet key generated in %s", ethPrivKeyFile)
|
|
log.Infof("Fund address %s to take an offer",
|
|
ethcrypto.PubkeyToAddress(*(key.Public().(*ecdsa.PublicKey))).Hex())
|
|
return nil
|
|
}
|
|
|
|
// GetEthereumPrivateKey reads or creates and returns an ethereum private key for the given the CLI options.
|
|
func GetEthereumPrivateKey(ethPrivKeyFile string, env common.Environment, devXMRMaker, devXMRTaker bool) (
|
|
*ecdsa.PrivateKey,
|
|
error,
|
|
) {
|
|
if ethPrivKeyFile == "" {
|
|
panic("missing required parameter ethPrivKeyFile")
|
|
}
|
|
|
|
exists, err := common.FileExists(ethPrivKeyFile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !exists {
|
|
if err = createAndWriteEthKeyFile(ethPrivKeyFile, env, devXMRMaker, devXMRTaker); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
fileData, err := os.ReadFile(filepath.Clean(ethPrivKeyFile))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read eth-privkey file: %w", err)
|
|
}
|
|
ethPrivKeyHex := strings.TrimSpace(string(fileData))
|
|
privkey, err := ethcrypto.HexToECDSA(ethPrivKeyHex)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if exists {
|
|
log.Infof("Using ETH wallet key located in %s", ethPrivKeyFile)
|
|
log.Infof("ETH address: %s", ethcrypto.PubkeyToAddress(*(privkey.Public().(*ecdsa.PublicKey))).Hex())
|
|
}
|
|
|
|
return privkey, nil
|
|
}
|
|
|
|
// GetVersion returns our version string for an executable
|
|
func GetVersion() string {
|
|
info, ok := debug.ReadBuildInfo()
|
|
if !ok {
|
|
return "unknown-version"
|
|
}
|
|
|
|
commitHash := "???????"
|
|
dirty := ""
|
|
|
|
for _, setting := range info.Settings {
|
|
switch setting.Key {
|
|
case "vcs.revision":
|
|
commitHash = setting.Value
|
|
case "vcs.modified":
|
|
if setting.Value == "true" {
|
|
dirty = "-dirty"
|
|
}
|
|
}
|
|
}
|
|
|
|
return fmt.Sprintf("%s %.7s%s-%s",
|
|
info.Main.Version, // " (devel)" unless passing a git tagged version to `go install`
|
|
commitHash, // 7 bytes is what "git rev-parse --short HEAD" returns
|
|
dirty, // add "-dirty" to commit hash if repo was not clean
|
|
info.GoVersion,
|
|
)
|
|
}
|
|
|
|
// ReadUnsignedDecimalFlag reads a string flag and parses it into an *apd.Decimal.
|
|
func ReadUnsignedDecimalFlag(ctx *cli.Context, flagName string) (*apd.Decimal, error) {
|
|
s := ctx.String(flagName)
|
|
if s == "" {
|
|
return nil, fmt.Errorf("flag --%s cannot be empty", flagName)
|
|
}
|
|
bf, _, err := new(apd.Decimal).SetString(s)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid value %q for flag --%s", s, flagName)
|
|
}
|
|
if bf.IsZero() {
|
|
return nil, fmt.Errorf("value of flag --%s cannot be zero", flagName)
|
|
}
|
|
if bf.Negative {
|
|
return nil, fmt.Errorf("value of flag --%s cannot be negative", flagName)
|
|
}
|
|
|
|
return bf, nil
|
|
}
|
|
|
|
// ExpandBootnodes expands the boot nodes passed on the command line that
|
|
// can be specified individually with multiple flags, but can also contain
|
|
// multiple boot nodes passed to single flag separated by commas.
|
|
func ExpandBootnodes(nodesCLI []string) []string {
|
|
var nodes []string // nodes from all flag values combined
|
|
for _, flagVal := range nodesCLI {
|
|
splitNodes := strings.Split(flagVal, ",")
|
|
for _, n := range splitNodes {
|
|
n = strings.TrimSpace(n)
|
|
// Handle the empty string to not use default bootnodes. Doing it here after
|
|
// the split has the arguably positive side effect of skipping empty entries.
|
|
if len(n) > 0 {
|
|
nodes = append(nodes, strings.TrimSpace(n))
|
|
}
|
|
}
|
|
}
|
|
return nodes
|
|
}
|