diff --git a/Makefile b/Makefile index 1c8a147..d3b49f2 100755 --- a/Makefile +++ b/Makefile @@ -1,10 +1,14 @@ -.PHONY: build clean cov help intergrationtest lint run test vet proto proto-lint +.PHONY: build build-noah clean cov help intergrationtest lint run test vet proto proto-lint ## build: build for all platforms build: @echo "Building coordinatord binary..." @bash ./scripts/build +build-noah: + @echo "Building noah binary..." + @bash ./scripts/build-noah + ## clean: cleans the binary clean: @echo "Cleaning..." diff --git a/cmd/noah/balance.go b/cmd/noah/balance.go new file mode 100644 index 0000000..3685dfe --- /dev/null +++ b/cmd/noah/balance.go @@ -0,0 +1,18 @@ +package main + +import ( + "fmt" + + "github.com/urfave/cli/v2" +) + +var balanceCommand = cli.Command{ + Name: "balance", + Usage: "Print balance of the Noah wallet", + Action: balanceAction, +} + +func balanceAction(ctx *cli.Context) error { + fmt.Println("balance is not implemented yet") + return nil +} diff --git a/cmd/noah/common.go b/cmd/noah/common.go new file mode 100644 index 0000000..5092d80 --- /dev/null +++ b/cmd/noah/common.go @@ -0,0 +1,114 @@ +package main + +import ( + "bytes" + "crypto/sha256" + "encoding/hex" + "fmt" + "syscall" + + "github.com/ark-network/ark/common" + "github.com/decred/dcrd/dcrec/secp256k1/v4" + "golang.org/x/term" +) + +func hashPassword(password []byte) []byte { + hash := sha256.Sum256(password) + return hash[:] +} + +func verifyPassword(password []byte) error { + state, err := getState() + if err != nil { + return err + } + + passwordHashString, ok := state["password_hash"] + if !ok { + return fmt.Errorf("password hash not found") + } + + passwordHash, err := hex.DecodeString(passwordHashString) + if err != nil { + return err + } + + currentPassHash := hashPassword(password) + + if !bytes.Equal(passwordHash, currentPassHash) { + return fmt.Errorf("invalid password") + } + + return nil +} + +func readPassword() ([]byte, error) { + fmt.Print("password: ") + passwordInput, err := term.ReadPassword(int(syscall.Stdin)) + fmt.Println() // new line + if err != nil { + return nil, err + } + + err = verifyPassword(passwordInput) + if err != nil { + return nil, err + } + + return passwordInput, nil +} + +func privateKeyFromPassword() (*secp256k1.PrivateKey, error) { + state, err := getState() + if err != nil { + return nil, err + } + + encryptedPrivateKeyString, ok := state["encrypted_private_key"] + if !ok { + return nil, fmt.Errorf("encrypted private key not found") + } + + encryptedPrivateKey, err := hex.DecodeString(encryptedPrivateKeyString) + if err != nil { + return nil, err + } + + password, err := readPassword() + if err != nil { + return nil, err + } + + cypher := NewAES128Cypher() + privateKeyBytes, err := cypher.Decrypt(encryptedPrivateKey, password) + if err != nil { + return nil, err + } + + privateKey := secp256k1.PrivKeyFromBytes(privateKeyBytes) + return privateKey, nil +} + +func getServiceProviderPublicKey() (*secp256k1.PublicKey, error) { + state, err := getState() + if err != nil { + return nil, err + } + + arkURL, ok := state["ark_url"] + if !ok { + return nil, fmt.Errorf("ark url not found") + } + + arkPubKey, _, err := common.DecodeUrl(arkURL) + if err != nil { + return nil, err + } + + _, publicKey, err := common.DecodePubKey(arkPubKey) + if err != nil { + return nil, err + } + + return publicKey, nil +} diff --git a/cmd/noah/config.go b/cmd/noah/config.go new file mode 100644 index 0000000..8e43d3e --- /dev/null +++ b/cmd/noah/config.go @@ -0,0 +1,54 @@ +package main + +import ( + "fmt" + + "github.com/ark-network/ark/common" + "github.com/urfave/cli/v2" +) + +var configCommand = cli.Command{ + Name: "config", + Usage: "Print local configuration of the Noah CLI", + Action: printConfigAction, + Subcommands: []*cli.Command{ + { + Name: "connect", + Usage: "connect ", + Action: connectAction, + }, + }, +} + +func printConfigAction(ctx *cli.Context) error { + state, err := getState() + if err != nil { + return err + } + + for key, value := range state { + fmt.Println(key + ": " + value) + } + + return nil +} + +func connectAction(ctx *cli.Context) error { + if ctx.NArg() != 1 { + return fmt.Errorf("missing ark URL") + } + + url := ctx.Args().Get(0) + + _, _, err := common.DecodeUrl(url) + if err != nil { + return err + } + + if err := setState(map[string]string{"ark_url": url}); err != nil { + return err + } + + fmt.Println("Connected to " + url) + return nil +} diff --git a/cmd/noah/cypher.go b/cmd/noah/cypher.go new file mode 100644 index 0000000..7053bee --- /dev/null +++ b/cmd/noah/cypher.go @@ -0,0 +1,106 @@ +package main + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "fmt" + "runtime/debug" + + "golang.org/x/crypto/scrypt" +) + +type Cypher struct{} + +func NewAES128Cypher() *Cypher { + return &Cypher{} +} + +func (c *Cypher) Encrypt(privateKey, password []byte) ([]byte, error) { + // Due to https://github.com/golang/go/issues/7168. + // This call makes sure that memory is freed in case the GC doesn't do that + // right after the encryption/decryption. + defer debug.FreeOSMemory() + + if len(privateKey) == 0 { + return nil, fmt.Errorf("missing plaintext private key") + } + if len(password) == 0 { + return nil, fmt.Errorf("missing encryption password") + } + + key, salt, err := deriveKey(password, nil) + if err != nil { + return nil, err + } + + blockCipher, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + gcm, err := cipher.NewGCM(blockCipher) + if err != nil { + return nil, err + } + nonce := make([]byte, gcm.NonceSize()) + if _, err = rand.Read(nonce); err != nil { + return nil, err + } + + ciphertext := gcm.Seal(nonce, nonce, privateKey, nil) + ciphertext = append(ciphertext, salt...) + + return ciphertext, nil +} + +func (c *Cypher) Decrypt(encrypted, password []byte) ([]byte, error) { + defer debug.FreeOSMemory() + + if len(encrypted) == 0 { + return nil, fmt.Errorf("missing encrypted mnemonic") + } + if len(password) == 0 { + return nil, fmt.Errorf("missing decryption password") + } + + salt := encrypted[len(encrypted)-32:] + data := encrypted[:len(encrypted)-32] + + key, _, err := deriveKey(password, salt) + if err != nil { + return nil, err + } + + blockCipher, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + gcm, err := cipher.NewGCM(blockCipher) + if err != nil { + return nil, err + } + nonce, text := data[:gcm.NonceSize()], data[gcm.NonceSize():] + plaintext, err := gcm.Open(nil, nonce, text, nil) + if err != nil { + return nil, fmt.Errorf("invalid password") + } + return plaintext, nil +} + +// deriveKey derives a 32 byte array key from a custom passhprase +func deriveKey(password, salt []byte) ([]byte, []byte, error) { + if salt == nil { + salt = make([]byte, 32) + if _, err := rand.Read(salt); err != nil { + return nil, nil, err + } + } + // 2^20 = 1048576 recommended length for key-stretching + // check the doc for other recommended values: + // https://godoc.org/golang.org/x/crypto/scrypt + key, err := scrypt.Key(password, salt, 1048576, 8, 1, 32) + if err != nil { + return nil, nil, err + } + return key, salt, nil +} diff --git a/cmd/noah/init.go b/cmd/noah/init.go new file mode 100644 index 0000000..2773a25 --- /dev/null +++ b/cmd/noah/init.go @@ -0,0 +1,90 @@ +package main + +import ( + "encoding/hex" + "fmt" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/decred/dcrd/dcrec/secp256k1/v4" + "github.com/urfave/cli/v2" +) + +var ( + passwordFlag = cli.StringFlag{ + Name: "password", + Usage: "password to encrypt private key", + Value: "", + Required: true, + } + + privateKeyFlag = cli.StringFlag{ + Name: "prvkey", + Usage: "optional, private key to encrypt", + Value: "", + Required: false, + } +) + +var initCommand = cli.Command{ + Name: "init", + Usage: "Initialize Noah wallet private key, encrypted with password", + Action: initAction, + Flags: []cli.Flag{ + &passwordFlag, + &privateKeyFlag, + }, +} + +func initAction(ctx *cli.Context) error { + privateKeyString := ctx.String("prvkey") + password := ctx.String("password") + + if len(password) <= 0 { + return fmt.Errorf("missing password flag (--password)") + } + + var privateKey *secp256k1.PrivateKey + + if len(privateKeyString) <= 0 { + privKey, err := generateRandomPrivateKey() + if err != nil { + return err + } + privateKey = privKey + } else { + privKeyBytes, err := hex.DecodeString(privateKeyString) + if err != nil { + return err + } + + privateKey = secp256k1.PrivKeyFromBytes(privKeyBytes) + } + + cypher := NewAES128Cypher() + + encryptedPrivateKey, err := cypher.Encrypt(privateKey.Serialize(), []byte(password)) + if err != nil { + return err + } + + passwordHash := hashPassword([]byte(password)) + + state := map[string]string{ + "encrypted_private_key": hex.EncodeToString(encryptedPrivateKey), + "password_hash": hex.EncodeToString(passwordHash), + } + + if err := setState(state); err != nil { + return err + } + + return nil +} + +func generateRandomPrivateKey() (*secp256k1.PrivateKey, error) { + privKey, err := btcec.NewPrivateKey() + if err != nil { + return nil, err + } + return privKey, nil +} diff --git a/cmd/noah/main.go b/cmd/noah/main.go new file mode 100644 index 0000000..72490b0 --- /dev/null +++ b/cmd/noah/main.go @@ -0,0 +1,158 @@ +package main + +import ( + "encoding/json" + "fmt" + "os" + "os/user" + "path/filepath" + "strings" + + "github.com/ark-network/ark/common" + "github.com/urfave/cli/v2" +) + +const ( + DATADIR_ENVVAR = "NOAH_DATADIR" + STATE_FILE = "state.json" + defaultArkURL = "ark://apub1qgvdtj5ttpuhkldavhq8thtm5auyk0ec4dcmrfdgu0u5hgp9we22v3hrs4x?relays=arelay1qt6f8p7h5f6tm7fv2z5wg92sz92rn9desfhd5733se4lkrptqtdrq65987l-arelay1qt6f8p7h5f6tm7fv2z5wg92sz92rn9desfhd5733se4lkrptqtdrq65987l" +) + +var ( + version = "alpha" + + noahDataDirectory = common.AppDataDir("noah", false) + statePath = filepath.Join(noahDataDirectory, STATE_FILE) + + initialState = map[string]string{ + "ark_url": defaultArkURL, + "encrypted_private_key": "", + "password_hash": "", + } +) + +func initCLIEnv() { + dataDir := cleanAndExpandPath(os.Getenv(DATADIR_ENVVAR)) + if len(dataDir) <= 0 { + return + } + + noahDataDirectory = dataDir + statePath = filepath.Join(noahDataDirectory, STATE_FILE) +} + +func main() { + initCLIEnv() + + app := cli.NewApp() + + app.Version = version + app.Name = "noah CLI" + app.Usage = "Command line interface for Ark wallet" + app.Commands = append( + app.Commands, + &balanceCommand, + &configCommand, + &initCommand, + &receiveCommand, + &redeemCommand, + &sendCommand, + ) + + app.Before = func(ctx *cli.Context) error { + if _, err := os.Stat(noahDataDirectory); os.IsNotExist(err) { + return os.Mkdir(noahDataDirectory, os.ModeDir|0755) + } + return nil + } + + err := app.Run(os.Args) + if err != nil { + fmt.Println(fmt.Errorf("error: %v", err)) + os.Exit(1) + } +} + +// cleanAndExpandPath expands environment variables and leading ~ in the +// passed path, cleans the result, and returns it. +// This function is taken from https://github.com/btcsuite/btcd +func cleanAndExpandPath(path string) string { + if path == "" { + return "" + } + + // Expand initial ~ to OS specific home directory. + if strings.HasPrefix(path, "~") { + var homeDir string + u, err := user.Current() + if err == nil { + homeDir = u.HomeDir + } else { + homeDir = os.Getenv("HOME") + } + + path = strings.Replace(path, "~", homeDir, 1) + } + + // NOTE: The os.ExpandEnv doesn't work with Windows-style %VARIABLE%, + // but the variables can still be expanded via POSIX-style $VARIABLE. + return filepath.Clean(os.ExpandEnv(path)) +} + +func getState() (map[string]string, error) { + file, err := os.ReadFile(statePath) + if err != nil { + if !os.IsNotExist(err) { + return nil, err + } + if err := setInitialState(); err != nil { + return nil, err + } + return initialState, nil + } + + data := map[string]string{} + if err := json.Unmarshal(file, &data); err != nil { + return nil, err + } + + return data, nil +} + +func setInitialState() error { + jsonString, err := json.Marshal(initialState) + if err != nil { + return err + } + return os.WriteFile(statePath, jsonString, 0755) +} + +func setState(data map[string]string) error { + currentData, err := getState() + if err != nil { + return err + } + + mergedData := merge(currentData, data) + + jsonString, err := json.Marshal(mergedData) + if err != nil { + return err + } + err = os.WriteFile(statePath, jsonString, 0755) + if err != nil { + return fmt.Errorf("writing to file: %w", err) + } + + return nil +} + +func merge(maps ...map[string]string) map[string]string { + merge := make(map[string]string, 0) + for _, m := range maps { + for k, v := range m { + merge[k] = v + } + } + return merge +} diff --git a/cmd/noah/receive.go b/cmd/noah/receive.go new file mode 100644 index 0000000..8370fbf --- /dev/null +++ b/cmd/noah/receive.go @@ -0,0 +1,37 @@ +package main + +import ( + "fmt" + + "github.com/ark-network/ark/common" + "github.com/urfave/cli/v2" +) + +var receiveCommand = cli.Command{ + Name: "receive", + Usage: "Print the Ark address associated with your wallet and the connected Ark", + Action: receiveAction, +} + +func receiveAction(ctx *cli.Context) error { + privateKey, err := privateKeyFromPassword() + if err != nil { + return err + } + + publicKey := privateKey.PubKey() + + aspPublicKey, err := getServiceProviderPublicKey() + if err != nil { + return err + } + + addr, err := common.EncodeAddress(common.MainNet.Addr, publicKey, aspPublicKey) + if err != nil { + return err + } + + fmt.Println(addr) + + return nil +} diff --git a/cmd/noah/redeem.go b/cmd/noah/redeem.go new file mode 100644 index 0000000..229a4eb --- /dev/null +++ b/cmd/noah/redeem.go @@ -0,0 +1,67 @@ +package main + +import ( + "fmt" + + "github.com/urfave/cli/v2" +) + +var ( + addressFlag = cli.StringFlag{ + Name: "address", + Usage: "main chain address receiving the redeeemed VTXO", + Value: "", + Required: true, + } + + amountToRedeemFlag = cli.Uint64Flag{ + Name: "amount", + Usage: "amount to redeem", + Value: 0, + Required: false, + } + + forceFlag = cli.BoolFlag{ + Name: "force", + Usage: "force redemption without collaborate with the Ark service provider", + Value: false, + Required: false, + } +) + +var redeemCommand = cli.Command{ + Name: "redeem", + Usage: "Redeem VTXO(s) to onchain", + Flags: []cli.Flag{&addressFlag, &amountToRedeemFlag, &forceFlag}, + Action: redeemAction, +} + +func redeemAction(ctx *cli.Context) error { + address := ctx.String("address") + amount := ctx.Uint64("amount") + force := ctx.Bool("force") + + if len(address) <= 0 { + return fmt.Errorf("missing address flag (--address)") + } + + if !force && amount <= 0 { + return fmt.Errorf("missing amount flag (--amount)") + } + + if force { + return unilateralRedeem(address) + } + + return collaborativeRedeem(address, amount) +} + +func collaborativeRedeem(address string, amount uint64) error { + fmt.Println("collaborative redeem is not implemented yet") + return nil +} + +func unilateralRedeem(address string) error { + fmt.Println("unilateral redeem is not implemented yet") + return nil +} diff --git a/cmd/noah/send.go b/cmd/noah/send.go new file mode 100644 index 0000000..907482e --- /dev/null +++ b/cmd/noah/send.go @@ -0,0 +1,60 @@ +package main + +import ( + "encoding/json" + "fmt" + + "github.com/ark-network/ark/common" + "github.com/urfave/cli/v2" +) + +var ( + receiversFlag = cli.StringFlag{ + Name: "receivers", + Usage: "receivers of the send transaction, JSON encoded: '[{\"to\": \"<...>\", \"amount\": <...>}, ...]'", + Value: "", + Required: true, + } +) + +var sendCommand = cli.Command{ + Name: "send", + Usage: "Send VTXOs to a list of addresses", + Action: sendAction, + Flags: []cli.Flag{&receiversFlag}, +} + +func sendAction(ctx *cli.Context) error { + receivers := ctx.String("receivers") + + // parse json encoded receivers + var receiversJSON []receiverJSON + if err := json.Unmarshal([]byte(receivers), &receiversJSON); err != nil { + return fmt.Errorf("invalid receivers: %s", err) + } + + if len(receiversJSON) <= 0 { + return fmt.Errorf("no receivers specified") + } + + for _, receiver := range receiversJSON { + // TODO: check if receiver asp public key is valid + _, _, _, err := common.DecodeAddress(receiver.To) + if err != nil { + return fmt.Errorf("invalid receiver address: %s", err) + } + + if receiver.Amount <= 0 { + return fmt.Errorf("invalid amount: %d", receiver.Amount) + } + } + + fmt.Println("send command is not implemented yet") + + return nil +} + +type receiverJSON struct { + To string `json:"to"` + Amount int64 `json:"amount"` +} diff --git a/go.mod b/go.mod index d9ef56d..6590f71 100644 --- a/go.mod +++ b/go.mod @@ -6,23 +6,26 @@ replace github.com/ark-network/ark/common => ./pkg/common require ( github.com/ark-network/ark/common v0.0.0-00010101000000-000000000000 + github.com/btcsuite/btcd/btcec/v2 v2.2.0 + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 github.com/google/uuid v1.3.1 github.com/sirupsen/logrus v1.9.3 github.com/spf13/viper v1.17.0 + github.com/urfave/cli/v2 v2.25.7 github.com/vulpemventures/go-elements v0.4.7 + golang.org/x/term v0.13.0 google.golang.org/grpc v1.59.0 google.golang.org/protobuf v1.31.0 ) require ( github.com/btcsuite/btcd v0.23.1 // indirect - github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect github.com/btcsuite/btcd/btcutil v1.1.3 // indirect github.com/btcsuite/btcd/btcutil/psbt v1.1.4 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/go-cmp v0.6.0 // indirect @@ -30,6 +33,7 @@ require ( github.com/magiconair/properties v1.8.7 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sagikazarmark/locafero v0.3.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect @@ -38,6 +42,7 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/vulpemventures/fastsha256 v0.0.0-20160815193821-637e65642941 // indirect + github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect golang.org/x/crypto v0.14.0 // indirect diff --git a/go.sum b/go.sum index 9ac65e2..4577790 100644 --- a/go.sum +++ b/go.sum @@ -75,6 +75,8 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -212,6 +214,8 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1: github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9cJvm4SvQ= github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= @@ -242,12 +246,16 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= +github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= +github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/vulpemventures/fastsha256 v0.0.0-20160815193821-637e65642941 h1:CTcw80hz/Sw8hqlKX5ZYvBUF5gAHSHwdjXxRf/cjDcI= github.com/vulpemventures/fastsha256 v0.0.0-20160815193821-637e65642941/go.mod h1:GXBJykxW2kUcktGdsgyay7uwwWvkljASfljNcT0mbh8= github.com/vulpemventures/go-elements v0.4.7 h1:M5dtBHwRXqct75DJeEv5b0PUFS93t0gh2naJaGlvp60= github.com/vulpemventures/go-elements v0.4.7/go.mod h1:aBGuWXHaiAIUIcwqCdtEh2iQ3kJjKwHU9ywvhlcRSeU= github.com/vulpemventures/go-secp256k1-zkp v1.1.6 h1:BmsrmXRLUibwa75Qkk8yELjpzCzlAjYFGLiLiOdq7Xo= github.com/vulpemventures/go-secp256k1-zkp v1.1.6/go.mod h1:zo7CpgkuPgoe7fAV+inyxsI9IhGmcoFgyD8nqZaPSOM= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -410,6 +418,8 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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= diff --git a/scripts/build-noah b/scripts/build-noah new file mode 100755 index 0000000..13b71a8 --- /dev/null +++ b/scripts/build-noah @@ -0,0 +1,16 @@ +#!/bin/bash + +set -e + +PARENT_PATH=$(dirname $( + cd $(dirname $0) + pwd -P +)) + +OS=$(eval "go env GOOS") +ARCH=$(eval "go env GOARCH") + +pushd $PARENT_PATH +mkdir -p build +GO111MODULE=on go build -ldflags="-s -w" -o build/noah-$OS-$ARCH ./cmd/noah +popd