Skip to content

Commit

Permalink
mint - mint info retrieval
Browse files Browse the repository at this point in the history
  • Loading branch information
elnosh committed Aug 2, 2024
1 parent 5ce9bfc commit fef2961
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 125 deletions.
2 changes: 1 addition & 1 deletion cmd/mint/mint.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func main() {
if err != nil {
log.Fatal("error loading .env file")
}
mintConfig := mint.GetConfig()
mintConfig := mint.ConfigFromEnv()

mintServer, err := mint.SetupMintServer(mintConfig)
if err != nil {
Expand Down
67 changes: 7 additions & 60 deletions mint/config.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
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"
)

Expand All @@ -19,6 +16,7 @@ type Config struct {
DBPath string
DBMigrationPath string
InputFeePpk uint
MintInfo nut06.MintInfo
Limits MintLimits
}

Expand All @@ -38,7 +36,7 @@ type MintLimits struct {
MeltingSettings MeltMethodSettings
}

func GetConfig() Config {
func ConfigFromEnv() Config {
var inputFeePpk uint = 0
if inputFeeEnv, ok := os.LookupEnv("INPUT_FEE_PPK"); ok {
fee, err := strconv.ParseUint(inputFeeEnv, 10, 16)
Expand Down Expand Up @@ -77,53 +75,35 @@ func GetConfig() Config {
}
mintLimits.MeltingSettings = MeltMethodSettings{MaxAmount: maxMelt}
}
mintInfo, _ := MintInfoEnv()

return Config{
DerivationPathIdx: uint32(derivationPathIdx),
Port: os.Getenv("MINT_PORT"),
DBPath: os.Getenv("MINT_DB_PATH"),
DBMigrationPath: "../../mint/storage/sqlite/migrations",
InputFeePpk: inputFeePpk,
MintInfo: mintInfo,
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) {
func MintInfoEnv() (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)
return nut06.MintInfo{}, fmt.Errorf("error parsing contact info: %v", err)
}

for _, info := range infoArr {
Expand All @@ -132,38 +112,5 @@ func (m *Mint) getMintInfo() (*nut06.MintInfo, error) {
}
}
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
return mintInfo, nil
}
133 changes: 102 additions & 31 deletions mint/mint.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ type Mint struct {
db storage.MintDB

// active keysets
ActiveKeysets map[string]crypto.MintKeyset
activeKeysets map[string]crypto.MintKeyset

// map of all keysets (both active and inactive)
Keysets map[string]crypto.MintKeyset
keysets map[string]crypto.MintKeyset

LightningClient lightning.Client
MintInfo *nut06.MintInfo
Limits MintLimits
lightningClient lightning.Client
mintInfo nut06.MintInfo
limits MintLimits
}

func LoadMint(config Config) (*Mint, error) {
Expand Down Expand Up @@ -87,8 +87,8 @@ func LoadMint(config Config) (*Mint, error) {

mint := &Mint{
db: db,
ActiveKeysets: map[string]crypto.MintKeyset{activeKeyset.Id: *activeKeyset},
Limits: config.Limits,
activeKeysets: map[string]crypto.MintKeyset{activeKeyset.Id: *activeKeyset},
limits: config.Limits,
}

dbKeysets, err := mint.db.GetKeysets()
Expand Down Expand Up @@ -136,19 +136,16 @@ func LoadMint(config Config) (*Mint, error) {
}
}

mint.Keysets = mintKeysets
mint.Keysets[activeKeyset.Id] = *activeKeyset
mint.LightningClient = lightning.NewLightningClient()
mint.MintInfo, err = mint.getMintInfo()
if err != nil {
return nil, err
}
mint.keysets = mintKeysets
mint.keysets[activeKeyset.Id] = *activeKeyset
mint.lightningClient = lightning.NewLightningClient()
mint.mintInfo = config.MintInfo

for _, keyset := range mint.Keysets {
for _, keyset := range mint.keysets {
if keyset.Id != activeKeyset.Id && keyset.Active {
keyset.Active = false
mint.db.UpdateKeysetActive(keyset.Id, false)
mint.Keysets[keyset.Id] = keyset
mint.keysets[keyset.Id] = keyset
}
}

Expand Down Expand Up @@ -186,17 +183,17 @@ func (m *Mint) RequestMintQuote(method string, amount uint64, unit string) (stor
}

// check limits
if m.Limits.MintingSettings.MaxAmount > 0 {
if amount > m.Limits.MintingSettings.MaxAmount {
if m.limits.MintingSettings.MaxAmount > 0 {
if amount > m.limits.MintingSettings.MaxAmount {
return storage.MintQuote{}, cashu.MintAmountExceededErr
}
}
if m.Limits.MaxBalance > 0 {
if m.limits.MaxBalance > 0 {
balance, err := m.db.GetBalance()
if err != nil {
return storage.MintQuote{}, err
}
if balance+amount > m.Limits.MaxBalance {
if balance+amount > m.limits.MaxBalance {
return storage.MintQuote{}, cashu.MintingDisabled
}
}
Expand Down Expand Up @@ -243,7 +240,7 @@ func (m *Mint) GetMintQuoteState(method, quoteId string) (storage.MintQuote, err
}

// check if the invoice has been paid
status, err := m.LightningClient.InvoiceStatus(mintQuote.PaymentHash)
status, err := m.lightningClient.InvoiceStatus(mintQuote.PaymentHash)
if err != nil {
msg := fmt.Sprintf("error getting status of payment request: %v", err)
return storage.MintQuote{}, cashu.BuildCashuError(msg, cashu.LightningBackendErrCode)
Expand Down Expand Up @@ -274,7 +271,7 @@ func (m *Mint) MintTokens(method, id string, blindedMessages cashu.BlindedMessag
}
var blindedSignatures cashu.BlindedSignatures

status, err := m.LightningClient.InvoiceStatus(mintQuote.PaymentHash)
status, err := m.lightningClient.InvoiceStatus(mintQuote.PaymentHash)
if err != nil {
msg := fmt.Sprintf("error getting status of payment request: %v", err)
return nil, cashu.BuildCashuError(msg, cashu.LightningBackendErrCode)
Expand Down Expand Up @@ -395,8 +392,8 @@ func (m *Mint) RequestMeltQuote(method, request, unit string) (storage.MeltQuote
satAmount := uint64(bolt11.MSatoshi) / 1000

// check melt limit
if m.Limits.MeltingSettings.MaxAmount > 0 {
if satAmount > m.Limits.MeltingSettings.MaxAmount {
if m.limits.MeltingSettings.MaxAmount > 0 {
if satAmount > m.limits.MeltingSettings.MaxAmount {
return storage.MeltQuote{}, cashu.MeltAmountExceededErr
}
}
Expand All @@ -407,7 +404,7 @@ func (m *Mint) RequestMeltQuote(method, request, unit string) (storage.MeltQuote
}

// Fee reserve that is required by the mint
fee := m.LightningClient.FeeReserve(satAmount)
fee := m.lightningClient.FeeReserve(satAmount)
expiry := uint64(time.Now().Add(time.Minute * QuoteExpiryMins).Unix())

meltQuote := storage.MeltQuote{
Expand Down Expand Up @@ -483,7 +480,7 @@ func (m *Mint) MeltTokens(method, quoteId string, proofs cashu.Proofs) (storage.

// if proofs are valid, ask the lightning backend
// to make the payment
preimage, err := m.LightningClient.SendPayment(meltQuote.InvoiceRequest, meltQuote.Amount)
preimage, err := m.lightningClient.SendPayment(meltQuote.InvoiceRequest, meltQuote.Amount)
if err != nil {
return storage.MeltQuote{}, cashu.BuildCashuError(err.Error(), cashu.LightningBackendErrCode)
}
Expand Down Expand Up @@ -533,7 +530,7 @@ func (m *Mint) verifyProofs(proofs cashu.Proofs, Ys []string) error {
// check that id in the proof matches id of any
// of the mint's keyset
var k *secp256k1.PrivateKey
if keyset, ok := m.Keysets[proof.Id]; !ok {
if keyset, ok := m.keysets[proof.Id]; !ok {
return cashu.UnknownKeysetErr
} else {
if key, ok := keyset.Keys[proof.Amount]; ok {
Expand Down Expand Up @@ -566,11 +563,11 @@ func (m *Mint) signBlindedMessages(blindedMessages cashu.BlindedMessages) (cashu
blindedSignatures := make(cashu.BlindedSignatures, len(blindedMessages))

for i, msg := range blindedMessages {
if _, ok := m.Keysets[msg.Id]; !ok {
if _, ok := m.keysets[msg.Id]; !ok {
return nil, cashu.UnknownKeysetErr
}
var k *secp256k1.PrivateKey
keyset, ok := m.ActiveKeysets[msg.Id]
keyset, ok := m.activeKeysets[msg.Id]
if !ok {
return nil, cashu.InactiveKeysetSignatureRequest
} else {
Expand Down Expand Up @@ -605,7 +602,7 @@ func (m *Mint) signBlindedMessages(blindedMessages cashu.BlindedMessages) (cashu
// requestInvoices requests an invoice from the Lightning backend
// for the given amount
func (m *Mint) requestInvoice(amount uint64) (*lightning.Invoice, error) {
invoice, err := m.LightningClient.CreateInvoice(amount)
invoice, err := m.lightningClient.CreateInvoice(amount)
if err != nil {
return nil, err
}
Expand All @@ -617,7 +614,81 @@ func (m *Mint) TransactionFees(inputs cashu.Proofs) uint {
for _, proof := range inputs {
// note: not checking that proof id is from valid keyset
// because already doing that in call to verifyProofs
fees += m.Keysets[proof.Id].InputFeePpk
fees += m.keysets[proof.Id].InputFeePpk
}
return (fees + 999) / 1000
}

func (m *Mint) GetActiveKeyset() crypto.MintKeyset {
var keyset crypto.MintKeyset
for _, k := range m.activeKeysets {
keyset = k
break
}
return keyset
}

func (m *Mint) RetrieveMintInfo() (nut06.MintInfo, error) {
m.mintInfo.Version = "gonuts/0.0.1"

seed, err := m.db.GetSeed()
if err != nil {
return nut06.MintInfo{}, err
}
master, err := hdkeychain.NewMaster(seed, &chaincfg.MainNetParams)
if err != nil {
return nut06.MintInfo{}, err
}
publicKey, err := master.ECPubKey()
if err != nil {
return nut06.MintInfo{}, err
}
m.mintInfo.Pubkey = hex.EncodeToString(publicKey.SerializeCompressed())

mintingDisabled := false
mintBalance, err := m.db.GetBalance()
if err != nil {
msg := fmt.Sprintf("error getting mint balance: %v", err)
return nut06.MintInfo{}, cashu.BuildCashuError(msg, cashu.DBErrCode)
}

if m.limits.MaxBalance > 0 {
if mintBalance >= m.limits.MaxBalance {
mintingDisabled = true
}
}

nuts := nut06.NutsMap{
4: nut06.NutSetting{
Methods: []nut06.MethodSetting{
{
Method: BOLT11_METHOD,
Unit: SAT_UNIT,
MinAmount: m.limits.MintingSettings.MinAmount,
MaxAmount: m.limits.MintingSettings.MaxAmount,
},
},
Disabled: mintingDisabled,
},
5: nut06.NutSetting{
Methods: []nut06.MethodSetting{
{
Method: BOLT11_METHOD,
Unit: SAT_UNIT,
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},
}

m.mintInfo.Nuts = nuts
return m.mintInfo, nil
}
Loading

0 comments on commit fef2961

Please sign in to comment.