Skip to content

Commit

Permalink
Merge pull request #44 from elnosh/mint-info
Browse files Browse the repository at this point in the history
refactor mint config
  • Loading branch information
elnosh authored Aug 5, 2024
2 parents 5ce9bfc + 1f081b5 commit 18811ac
Show file tree
Hide file tree
Showing 8 changed files with 333 additions and 288 deletions.
136 changes: 134 additions & 2 deletions cmd/mint/mint.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,152 @@
package main

import (
"encoding/json"
"errors"
"fmt"
"log"
"os"
"strconv"

"github.com/elnosh/gonuts/cashu/nuts/nut06"
"github.com/elnosh/gonuts/mint"
"github.com/elnosh/gonuts/mint/lightning"
"github.com/joho/godotenv"
"github.com/lightningnetwork/lnd/macaroons"
"google.golang.org/grpc/credentials"
"gopkg.in/macaroon.v2"
)

func configFromEnv() (*mint.Config, error) {
var inputFeePpk uint = 0
if inputFeeEnv, ok := os.LookupEnv("INPUT_FEE_PPK"); ok {
fee, err := strconv.ParseUint(inputFeeEnv, 10, 16)
if err != nil {
return nil, fmt.Errorf("invalid INPUT_FEE_PPK: %v", err)
}
inputFeePpk = uint(fee)
}

derivationPathIdx, err := strconv.ParseUint(os.Getenv("DERIVATION_PATH_IDX"), 10, 32)
if err != nil {
return nil, fmt.Errorf("invalid DERIVATION_PATH_IDX: %v", err)
}

mintLimits := mint.MintLimits{}
if maxBalanceEnv, ok := os.LookupEnv("MAX_BALANCE"); ok {
maxBalance, err := strconv.ParseUint(maxBalanceEnv, 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid MAX_BALANCE: %v", err)
}
mintLimits.MaxBalance = maxBalance
}

if maxMintEnv, ok := os.LookupEnv("MINTING_MAX_AMOUNT"); ok {
maxMint, err := strconv.ParseUint(maxMintEnv, 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid MINTING_MAX_AMOUNT: %v", err)
}
mintLimits.MintingSettings = mint.MintMethodSettings{MaxAmount: maxMint}
}

if maxMeltEnv, ok := os.LookupEnv("MELTING_MAX_AMOUNT"); ok {
maxMelt, err := strconv.ParseUint(maxMeltEnv, 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid MELTING_MAX_AMOUNT: %v", err)
}
mintLimits.MeltingSettings = mint.MeltMethodSettings{MaxAmount: maxMelt}
}

mintInfo := mint.MintInfo{
Name: os.Getenv("MINT_NAME"),
Description: os.Getenv("MINT_DESCRIPTION"),
}

mintInfo.LongDescription = os.Getenv("MINT_DESCRIPTION_LONG")
mintInfo.Motd = os.Getenv("MINT_MOTD")

contact := os.Getenv("MINT_CONTACT_INFO")
var mintContactInfo []nut06.ContactInfo
if len(contact) > 0 {
var infoArr [][]string
err := json.Unmarshal([]byte(contact), &infoArr)
if err != nil {
return nil, fmt.Errorf("error parsing contact info: %v", err)
}

for _, info := range infoArr {
contactInfo := nut06.ContactInfo{Method: info[0], Info: info[1]}
mintContactInfo = append(mintContactInfo, contactInfo)
}
}
mintInfo.Contact = mintContactInfo

// read values for setting up LND
host := os.Getenv("LND_GRPC_HOST")
if host == "" {
return nil, errors.New("LND_GRPC_HOST cannot be empty")
}
certPath := os.Getenv("LND_CERT_PATH")
if certPath == "" {
return nil, errors.New("LND_CERT_PATH cannot be empty")
}
macaroonPath := os.Getenv("LND_MACAROON_PATH")
if macaroonPath == "" {
return nil, errors.New("LND_MACAROON_PATH cannot be empty")
}

creds, err := credentials.NewClientTLSFromFile(certPath, "")
if err != nil {
return nil, err
}

macaroonBytes, err := os.ReadFile(macaroonPath)
if err != nil {
return nil, fmt.Errorf("error reading macaroon: os.ReadFile %v", err)
}

macaroon := &macaroon.Macaroon{}
if err = macaroon.UnmarshalBinary(macaroonBytes); err != nil {
return nil, fmt.Errorf("unable to decode macaroon: %v", err)
}
macarooncreds, err := macaroons.NewMacaroonCredential(macaroon)
if err != nil {
return nil, fmt.Errorf("error setting macaroon creds: %v", err)
}
lndConfig := lightning.LndConfig{
GRPCHost: host,
Cert: creds,
Macaroon: macarooncreds,
}

lndClient, err := lightning.SetupLndClient(lndConfig)
if err != nil {
return nil, fmt.Errorf("error setting LND client: %v", err)
}

return &mint.Config{
DerivationPathIdx: uint32(derivationPathIdx),
Port: os.Getenv("MINT_PORT"),
MintPath: os.Getenv("MINT_DB_PATH"),
DBMigrationPath: "../../mint/storage/sqlite/migrations",
InputFeePpk: inputFeePpk,
MintInfo: mintInfo,
Limits: mintLimits,
LightningClient: lndClient,
}, nil
}

func main() {
err := godotenv.Load()
if err != nil {
log.Fatal("error loading .env file")
}
mintConfig := mint.GetConfig()
mintConfig, err := configFromEnv()
if err != nil {
log.Fatalf("error reading config: %v", err)
}

mintServer, err := mint.SetupMintServer(mintConfig)
mintServer, err := mint.SetupMintServer(*mintConfig)
if err != nil {
log.Fatalf("error starting mint server: %v", err)
}
Expand Down
152 changes: 12 additions & 140 deletions mint/config.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
package mint

import (
"encoding/hex"
"encoding/json"
"fmt"
"log"
"os"
"strconv"

"github.com/btcsuite/btcd/btcutil/hdkeychain"
"github.com/btcsuite/btcd/chaincfg"
"github.com/elnosh/gonuts/cashu/nuts/nut06"
"github.com/elnosh/gonuts/mint/lightning"
)

type Config struct {
DerivationPathIdx uint32
Port string
DBPath string
MintPath string
DBMigrationPath string
InputFeePpk uint
MintInfo MintInfo
Limits MintLimits
LightningClient lightning.Client
}

type MintInfo struct {
Name string
Description string
LongDescription string
Contact []nut06.ContactInfo
Motd string
}

type MintMethodSettings struct {
Expand All @@ -37,133 +39,3 @@ type MintLimits struct {
MintingSettings MintMethodSettings
MeltingSettings MeltMethodSettings
}

func GetConfig() Config {
var inputFeePpk uint = 0
if inputFeeEnv, ok := os.LookupEnv("INPUT_FEE_PPK"); ok {
fee, err := strconv.ParseUint(inputFeeEnv, 10, 16)
if err != nil {
log.Fatalf("invalid INPUT_FEE_PPK: %v", err)
}
inputFeePpk = uint(fee)
}

derivationPathIdx, err := strconv.ParseUint(os.Getenv("DERIVATION_PATH_IDX"), 10, 32)
if err != nil {
log.Fatalf("invalid DERIVATION_PATH_IDX: %v", err)
}

mintLimits := MintLimits{}
if maxBalanceEnv, ok := os.LookupEnv("MAX_BALANCE"); ok {
maxBalance, err := strconv.ParseUint(maxBalanceEnv, 10, 64)
if err != nil {
log.Fatalf("invalid MAX_BALANCE: %v", err)
}
mintLimits.MaxBalance = maxBalance
}

if maxMintEnv, ok := os.LookupEnv("MINTING_MAX_AMOUNT"); ok {
maxMint, err := strconv.ParseUint(maxMintEnv, 10, 64)
if err != nil {
log.Fatalf("invalid MINTING_MAX_AMOUNT: %v", err)
}
mintLimits.MintingSettings = MintMethodSettings{MaxAmount: maxMint}
}

if maxMeltEnv, ok := os.LookupEnv("MELTING_MAX_AMOUNT"); ok {
maxMelt, err := strconv.ParseUint(maxMeltEnv, 10, 64)
if err != nil {
log.Fatalf("invalid MELTING_MAX_AMOUNT: %v", err)
}
mintLimits.MeltingSettings = MeltMethodSettings{MaxAmount: maxMelt}
}

return Config{
DerivationPathIdx: uint32(derivationPathIdx),
Port: os.Getenv("MINT_PORT"),
DBPath: os.Getenv("MINT_DB_PATH"),
DBMigrationPath: "../../mint/storage/sqlite/migrations",
InputFeePpk: inputFeePpk,
Limits: mintLimits,
}
}

// getMintInfo returns information about the mint as
// defined in NUT-06: https://github.com/cashubtc/nuts/blob/main/06.md
func (m *Mint) getMintInfo() (*nut06.MintInfo, error) {
mintInfo := nut06.MintInfo{
Name: os.Getenv("MINT_NAME"),
Version: "gonuts/0.0.1",
Description: os.Getenv("MINT_DESCRIPTION"),
}

mintInfo.LongDescription = os.Getenv("MINT_DESCRIPTION_LONG")
mintInfo.Motd = os.Getenv("MINT_MOTD")

seed, err := m.db.GetSeed()
if err != nil {
return nil, err
}

master, err := hdkeychain.NewMaster(seed, &chaincfg.MainNetParams)
if err != nil {
return nil, err
}

publicKey, err := master.ECPubKey()
if err != nil {
return nil, err
}

mintInfo.Pubkey = hex.EncodeToString(publicKey.SerializeCompressed())

contact := os.Getenv("MINT_CONTACT_INFO")
var mintContactInfo []nut06.ContactInfo
if len(contact) > 0 {
var infoArr [][]string
err := json.Unmarshal([]byte(contact), &infoArr)
if err != nil {
return nil, fmt.Errorf("error parsing contact info: %v", err)
}

for _, info := range infoArr {
contactInfo := nut06.ContactInfo{Method: info[0], Info: info[1]}
mintContactInfo = append(mintContactInfo, contactInfo)
}
}
mintInfo.Contact = mintContactInfo

nuts := nut06.NutsMap{
4: nut06.NutSetting{
Methods: []nut06.MethodSetting{
{
Method: "bolt11",
Unit: "sat",
MinAmount: m.Limits.MintingSettings.MinAmount,
MaxAmount: m.Limits.MintingSettings.MaxAmount,
},
},
Disabled: false,
},
5: nut06.NutSetting{
Methods: []nut06.MethodSetting{
{
Method: "bolt11",
Unit: "sat",
MinAmount: m.Limits.MeltingSettings.MinAmount,
MaxAmount: m.Limits.MeltingSettings.MaxAmount,
},
},
Disabled: false,
},
7: map[string]bool{"supported": false},
8: map[string]bool{"supported": false},
9: map[string]bool{"supported": false},
10: map[string]bool{"supported": false},
11: map[string]bool{"supported": false},
12: map[string]bool{"supported": false},
}

mintInfo.Nuts = nuts
return &mintInfo, nil
}
27 changes: 0 additions & 27 deletions mint/lightning/lightning.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,5 @@
package lightning

import (
"log"
"os"
)

const (
LND = "Lnd"
)

// Client interface to interact with a Lightning backend
type Client interface {
CreateInvoice(amount uint64) (Invoice, error)
Expand All @@ -17,24 +8,6 @@ type Client interface {
SendPayment(request string, amount uint64) (string, error)
}

func NewLightningClient() Client {
backend := os.Getenv("LIGHTNING_BACKEND")

switch backend {
case LND:
lndClient, err := CreateLndClient()
if err != nil {
log.Fatalf("error setting up lightning backend: %v", err)
}
return lndClient

default:
log.Fatal("please specify a lightning backend")
}

return nil
}

type Invoice struct {
PaymentRequest string
PaymentHash string
Expand Down
Loading

0 comments on commit 18811ac

Please sign in to comment.