Skip to content

Commit

Permalink
Merge pull request #16 from blinklabs-io/feat/cli
Browse files Browse the repository at this point in the history
feat: initial cli support
  • Loading branch information
wolf31o2 authored Sep 30, 2023
2 parents 537ca76 + 2e98125 commit fa6cf4f
Show file tree
Hide file tree
Showing 9 changed files with 215 additions and 48 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@
go.work

# binary
bursa
/bursa
49 changes: 8 additions & 41 deletions bursa.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"encoding/json"
"fmt"

"github.com/blinklabs-io/bursa/internal/config"
// TODO: replace these w/ gOuroboros (blinklabs-io/gouroboros#364)
"github.com/fivebinaries/go-cardano-serialization/address"
"github.com/fivebinaries/go-cardano-serialization/bip32"
Expand Down Expand Up @@ -86,9 +85,9 @@ func GetPaymentVKey(paymentKey bip32.XPrv) KeyFile {
panic(err)
}
return KeyFile{
Type: "PaymentVerificationKeyShelley_ed25519",
Type: "PaymentVerificationKeyShelley_ed25519",
Description: "Payment Verification Key",
CborHex: fmt.Sprintf("%x", keyCbor),
CborHex: fmt.Sprintf("%x", keyCbor),
}
}

Expand All @@ -98,9 +97,9 @@ func GetPaymentSKey(paymentKey bip32.XPrv) KeyFile {
panic(err)
}
return KeyFile{
Type: "PaymentExtendedSigningKeyShelley_ed25519_bip32",
Type: "PaymentExtendedSigningKeyShelley_ed25519_bip32",
Description: "Payment Signing Key",
CborHex: fmt.Sprintf("%x", keyCbor),
CborHex: fmt.Sprintf("%x", keyCbor),
}
}

Expand All @@ -114,9 +113,9 @@ func GetStakeVKey(stakeKey bip32.XPrv) KeyFile {
panic(err)
}
return KeyFile{
Type: "StakeVerificationKeyShelley_ed25519",
Type: "StakeVerificationKeyShelley_ed25519",
Description: "Stake Verification Key",
CborHex: fmt.Sprintf("%x", keyCbor),
CborHex: fmt.Sprintf("%x", keyCbor),
}
}

Expand All @@ -126,9 +125,9 @@ func GetStakeSKey(stakeKey bip32.XPrv) KeyFile {
panic(err)
}
return KeyFile{
Type: "StakeExtendedSigningKeyShelley_ed25519_bip32",
Type: "StakeExtendedSigningKeyShelley_ed25519_bip32",
Description: "Stake Signing Key",
CborHex: fmt.Sprintf("%x", keyCbor),
CborHex: fmt.Sprintf("%x", keyCbor),
}
}

Expand Down Expand Up @@ -170,35 +169,3 @@ func GetKeyFile(keyFile KeyFile) string {
// Append newline
return fmt.Sprintf("%s\n", ret)
}

func Run() {
// Load Config
cfg, err := config.LoadConfig()
if err != nil {
panic(err)
}

mnemonic := cfg.Mnemonic
if mnemonic == "" {
mnemonic, err = NewMnemonic()
if err != nil {
panic(err)
}
}
rootKey, err := GetRootKeyFromMnemonic(mnemonic)
if err != nil {
panic(err)
}
accountKey := GetAccountKey(rootKey, 0) // TODO: more accounts
addr := GetAddress(accountKey, cfg.Network, 0) // TODO: more addresses

fmt.Println("Loaded mnemonic and generated address...")
fmt.Printf("MNEMONIC=%s\n", mnemonic)
fmt.Printf("PAYMENT_ADDRESS=%s\n", addr.String())
fmt.Printf("STAKE_ADDRESS=%s\n", addr.ToReward().String())

fmt.Printf("payment.vkey=%s", GetKeyFile(GetPaymentVKey(GetPaymentKey(accountKey, 0))))
fmt.Printf("payment.skey=%s", GetKeyFile(GetPaymentSKey(GetPaymentKey(accountKey, 0))))
fmt.Printf("stake.vkey=%s", GetKeyFile(GetStakeVKey(GetStakeKey(accountKey, 0))))
fmt.Printf("stake.vkey=%s", GetKeyFile(GetStakeSKey(GetStakeKey(accountKey, 0))))
}
23 changes: 23 additions & 0 deletions cmd/bursa/cli.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2023 Blink Labs, LLC.
//
// 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 main

import (
"github.com/blinklabs-io/bursa/internal/cli"
)

func cliRun() {
cli.Run()
}
21 changes: 19 additions & 2 deletions cmd/bursa/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,25 @@

package main

import "github.com/blinklabs-io/bursa"
import (
"fmt"
"os"
)

func main() {
bursa.Run()
var subCommand string
// Parse subcommand (default: "cli")
if len(os.Args) < 2 {
subCommand = "cli"
} else {
subCommand = os.Args[1]
}

switch subCommand {
case "cli":
cliRun()
default:
fmt.Printf("Unknown subcommand: %s\n", subCommand)
os.Exit(1)
}
}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ require (
github.com/fxamacker/cbor/v2 v2.5.0
github.com/kelseyhightower/envconfig v1.4.0
github.com/tyler-smith/go-bip39 v1.1.0
go.uber.org/zap v1.26.0
)

require (
github.com/btcsuite/btcutil v1.0.2 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.uber.org/multierr v1.10.0 // indirect
golang.org/x/crypto v0.12.0 // indirect
golang.org/x/sys v0.11.0 // indirect
)
9 changes: 7 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,16 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
Expand All @@ -51,4 +56,4 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
91 changes: 91 additions & 0 deletions internal/cli/cli.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright 2023 Blink Labs, LLC.
//
// 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 cli

import (
"fmt"
"os"

"github.com/blinklabs-io/bursa"
"github.com/blinklabs-io/bursa/internal/config"
"github.com/blinklabs-io/bursa/internal/logging"
)

func NewDefaultWallet(mnemonic string) (*bursa.Wallet, error) {
cfg := config.GetConfig()
logger := logging.GetLogger()

rootKey, err := bursa.GetRootKeyFromMnemonic(mnemonic)
if err != nil {
logger.Errorf("failed to get root key from mnemonic")
return nil, fmt.Errorf("failed to get root key from mnemonic: %s", err)
}
accountKey := bursa.GetAccountKey(rootKey, 0)
paymentKey := bursa.GetPaymentKey(accountKey, 0)
stakeKey := bursa.GetStakeKey(accountKey, 0)
addr := bursa.GetAddress(accountKey, cfg.Network, 0)
w := &bursa.Wallet{
Mnemonic: mnemonic,
PaymentAddress: addr.String(),
StakeAddress: addr.ToReward().String(),
PaymentVKey: bursa.GetPaymentVKey(paymentKey),
PaymentSKey: bursa.GetPaymentSKey(paymentKey),
StakeVKey: bursa.GetStakeVKey(stakeKey),
StakeSKey: bursa.GetStakeSKey(stakeKey),
}
return w, nil
}

func Run() {
// Load Config
cfg, err := config.LoadConfig()
if err != nil {
fmt.Printf("Failed to load config: %s\n", err)
os.Exit(1)
}
// Configure logging
logging.Setup()
logger := logging.GetLogger()
// Sync logger on exit
defer func() {
if err := logger.Sync(); err != nil {
// ignore error
return
}
}()

// Load mnemonic
mnemonic := cfg.Mnemonic
if mnemonic == "" {
mnemonic, err = bursa.NewMnemonic()
if err != nil {
logger.Fatalf("failed to load mnemonic: %s", err)
}
}
w, err := NewDefaultWallet(mnemonic)
if err != nil {
logger.Fatalf("failed to initialize wallet: %s", err)
}

logger.Infof("Loaded mnemonic and generated address...")
fmt.Printf("MNEMONIC=%s\n", w.Mnemonic)
fmt.Printf("PAYMENT_ADDRESS=%s\n", w.PaymentAddress)
fmt.Printf("STAKE_ADDRESS=%s\n", w.StakeAddress)

fmt.Printf("payment.vkey=%s\n", w.PaymentVKey)
fmt.Printf("payment.skey=%s\n", w.PaymentSKey)
fmt.Printf("stake.vkey=%s\n", w.StakeVKey)
fmt.Printf("stake.skey=%s\n", w.StakeSKey)
}
12 changes: 10 additions & 2 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,20 @@ import (
)

type Config struct {
Mnemonic string `envconfig:"MNEMONIC"`
Network string `envconfig:"NETWORK"`
Logging LoggingConfig `yaml:"logging"`
Mnemonic string `envconfig:"MNEMONIC"`
Network string `envconfig:"NETWORK"`
}

type LoggingConfig struct {
Level string `yaml:"level" envconfig:"LOGGING_LEVEL"`
}

// We use a singleton for the config for convenience
var globalConfig = Config{
Logging: LoggingConfig{
Level: "info",
},
Mnemonic: "",
Network: "mainnet",
}
Expand Down
54 changes: 54 additions & 0 deletions internal/logging/logging.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package logging

import (
"log"
"time"

"github.com/blinklabs-io/bursa/internal/config"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)

type Logger = zap.SugaredLogger

var globalLogger *Logger

func Setup() {
cfg := config.GetConfig()
// Build our custom logging config
loggerConfig := zap.NewProductionConfig()
// Change timestamp key name
loggerConfig.EncoderConfig.TimeKey = "timestamp"
// Use a human readable time format
loggerConfig.EncoderConfig.EncodeTime = zapcore.TimeEncoderOfLayout(time.RFC3339)

// Set level
if cfg.Logging.Level != "" {
level, err := zapcore.ParseLevel(cfg.Logging.Level)
if err != nil {
log.Fatalf("error configuring logger: %s", err)
}
loggerConfig.Level.SetLevel(level)
}

// Create the logger
l, err := loggerConfig.Build()
if err != nil {
log.Fatal(err)
}

// Store the "sugared" version of the logger
globalLogger = l.Sugar()
}

func GetLogger() *Logger {
return globalLogger
}

func GetDesugaredLogger() *zap.Logger {
return globalLogger.Desugar()
}

func GetAccessLogger() *zap.Logger {
return globalLogger.Desugar().With(zap.String("type", "access")).WithOptions(zap.WithCaller(false))
}

0 comments on commit fa6cf4f

Please sign in to comment.