Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: initial cli support #16

Merged
merged 1 commit into from
Sep 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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))
}
Loading