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

better define sat unit #74

Merged
merged 2 commits into from
Oct 30, 2024
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
34 changes: 30 additions & 4 deletions cashu/cashu.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,27 @@ import (
"github.com/fxamacker/cbor/v2"
)

type Unit int

const (
Sat Unit = iota

BOLT11_METHOD = "bolt11"
)

func (unit Unit) String() string {
switch unit {
case Sat:
return "sat"
default:
return "unknown"
}
}

var (
ErrInvalidTokenV3 = errors.New("invalid V3 token")
ErrInvalidTokenV4 = errors.New("invalid V4 token")
ErrInvalidUnit = errors.New("invalid unit")
)

// Cashu BlindedMessage. See https://github.com/cashubtc/nuts/blob/main/00.md#blindedmessage
Expand Down Expand Up @@ -143,15 +161,19 @@ type TokenV3Proof struct {
Proofs Proofs `json:"proofs"`
}

func NewTokenV3(proofs Proofs, mint, unit string, includeDLEQ bool) TokenV3 {
func NewTokenV3(proofs Proofs, mint string, unit Unit, includeDLEQ bool) (TokenV3, error) {
if !includeDLEQ {
for i := 0; i < len(proofs); i++ {
proofs[i].DLEQ = nil
}
}

if unit != Sat {
return TokenV3{}, ErrInvalidUnit
}

tokenProof := TokenV3Proof{Mint: mint, Proofs: proofs}
return TokenV3{Token: []TokenV3Proof{tokenProof}, Unit: unit}
return TokenV3{Token: []TokenV3Proof{tokenProof}, Unit: unit.String()}, nil
}

func DecodeTokenV3(tokenstr string) (*TokenV3, error) {
Expand Down Expand Up @@ -237,7 +259,11 @@ type DLEQV4 struct {
R []byte `json:"r"`
}

func NewTokenV4(proofs Proofs, mint, unit string, includeDLEQ bool) (TokenV4, error) {
func NewTokenV4(proofs Proofs, mint string, unit Unit, includeDLEQ bool) (TokenV4, error) {
if unit != Sat {
return TokenV4{}, ErrInvalidUnit
}

proofsMap := make(map[string][]ProofV4)
for _, proof := range proofs {
C, err := hex.DecodeString(proof.C)
Expand Down Expand Up @@ -294,7 +320,7 @@ func NewTokenV4(proofs Proofs, mint, unit string, includeDLEQ bool) (TokenV4, er
i++
}

return TokenV4{MintURL: mint, Unit: unit, TokenProofs: proofsV4}, nil
return TokenV4{MintURL: mint, Unit: unit.String(), TokenProofs: proofsV4}, nil
}

func DecodeTokenV4(tokenstr string) (*TokenV4, error) {
Expand Down
4 changes: 2 additions & 2 deletions cmd/nutw/nutw.go
Original file line number Diff line number Diff line change
Expand Up @@ -451,9 +451,9 @@ func send(ctx *cli.Context) error {

var token cashu.Token
if ctx.Bool(legacyFlag) {
token = cashu.NewTokenV3(proofsToSend, selectedMint, "sat", includeDLEQ)
token, _ = cashu.NewTokenV3(proofsToSend, selectedMint, cashu.Sat, includeDLEQ)
} else {
token, err = cashu.NewTokenV4(proofsToSend, selectedMint, "sat", includeDLEQ)
token, err = cashu.NewTokenV4(proofsToSend, selectedMint, cashu.Sat, includeDLEQ)
if err != nil {
printErr(fmt.Errorf("could not serialize token: %v", err))
}
Expand Down
3 changes: 2 additions & 1 deletion crypto/keyset.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/btcsuite/btcd/btcutil/hdkeychain"
"github.com/decred/dcrd/dcrec/secp256k1/v4"
"github.com/elnosh/gonuts/cashu"
"github.com/elnosh/gonuts/cashu/nuts/nut01"
)

Expand Down Expand Up @@ -82,7 +83,7 @@ func GenerateKeyset(master *hdkeychain.ExtendedKey, index uint32, inputFeePpk ui

return &MintKeyset{
Id: keysetId,
Unit: "sat",
Unit: cashu.Sat.String(),
Active: true,
DerivationPathIdx: index,
Keys: keys,
Expand Down
79 changes: 30 additions & 49 deletions mint/mint.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ import (

const (
QuoteExpiryMins = 10
BOLT11_METHOD = "bolt11"
SAT_UNIT = "sat"
)

type Mint struct {
Expand Down Expand Up @@ -245,20 +243,17 @@ func (m *Mint) logDebugf(format string, args ...any) {
// and returns a mint quote or an error.
// The request to mint a token is explained in
// NUT-04 here: https://github.com/cashubtc/nuts/blob/main/04.md.
func (m *Mint) RequestMintQuote(method string, amount uint64, unit string) (storage.MintQuote, error) {
// only support bolt11
if method != BOLT11_METHOD {
return storage.MintQuote{}, cashu.PaymentMethodNotSupportedErr
}
func (m *Mint) RequestMintQuote(mintQuoteRequest nut04.PostMintQuoteBolt11Request) (storage.MintQuote, error) {
// only support sat unit
if unit != SAT_UNIT {
errmsg := fmt.Sprintf("unit '%v' not supported", unit)
if mintQuoteRequest.Unit != cashu.Sat.String() {
errmsg := fmt.Sprintf("unit '%v' not supported", mintQuoteRequest.Unit)
return storage.MintQuote{}, cashu.BuildCashuError(errmsg, cashu.UnitErrCode)
}

// check limits
requestAmount := mintQuoteRequest.Amount
if m.limits.MintingSettings.MaxAmount > 0 {
if amount > m.limits.MintingSettings.MaxAmount {
if requestAmount > m.limits.MintingSettings.MaxAmount {
return storage.MintQuote{}, cashu.MintAmountExceededErr
}
}
Expand All @@ -268,14 +263,14 @@ func (m *Mint) RequestMintQuote(method string, amount uint64, unit string) (stor
errmsg := fmt.Sprintf("could not get mint balance from db: %v", err)
return storage.MintQuote{}, cashu.BuildCashuError(errmsg, cashu.DBErrCode)
}
if balance+amount > m.limits.MaxBalance {
if balance+requestAmount > m.limits.MaxBalance {
return storage.MintQuote{}, cashu.MintingDisabled
}
}

// get an invoice from the lightning backend
m.logInfof("requesting invoice from lightning backend for %v sats", amount)
invoice, err := m.requestInvoice(amount)
m.logInfof("requesting invoice from lightning backend for %v sats", requestAmount)
invoice, err := m.requestInvoice(requestAmount)
if err != nil {
errmsg := fmt.Sprintf("could not generate invoice: %v", err)
return storage.MintQuote{}, cashu.BuildCashuError(errmsg, cashu.LightningBackendErrCode)
Expand All @@ -288,7 +283,7 @@ func (m *Mint) RequestMintQuote(method string, amount uint64, unit string) (stor
}
mintQuote := storage.MintQuote{
Id: quoteId,
Amount: amount,
Amount: requestAmount,
PaymentRequest: invoice.PaymentRequest,
PaymentHash: invoice.PaymentHash,
State: nut04.Unpaid,
Expand All @@ -306,11 +301,7 @@ func (m *Mint) RequestMintQuote(method string, amount uint64, unit string) (stor

// GetMintQuoteState returns the state of a mint quote.
// Used to check whether a mint quote has been paid.
func (m *Mint) GetMintQuoteState(method, quoteId string) (storage.MintQuote, error) {
if method != BOLT11_METHOD {
return storage.MintQuote{}, cashu.PaymentMethodNotSupportedErr
}

func (m *Mint) GetMintQuoteState(quoteId string) (storage.MintQuote, error) {
mintQuote, err := m.db.GetMintQuote(quoteId)
if err != nil {
return storage.MintQuote{}, cashu.QuoteNotExistErr
Expand Down Expand Up @@ -341,15 +332,13 @@ func (m *Mint) GetMintQuoteState(method, quoteId string) (storage.MintQuote, err

// MintTokens verifies whether the mint quote with id has been paid and proceeds to
// sign the blindedMessages and return the BlindedSignatures if it was paid.
func (m *Mint) MintTokens(method, id string, blindedMessages cashu.BlindedMessages) (cashu.BlindedSignatures, error) {
if method != BOLT11_METHOD {
return nil, cashu.PaymentMethodNotSupportedErr
}

mintQuote, err := m.db.GetMintQuote(id)
func (m *Mint) MintTokens(mintTokensRequest nut04.PostMintBolt11Request) (cashu.BlindedSignatures, error) {
mintQuote, err := m.db.GetMintQuote(mintTokensRequest.Quote)
if err != nil {
return nil, cashu.QuoteNotExistErr
}

blindedMessages := mintTokensRequest.Outputs
var blindedSignatures cashu.BlindedSignatures

invoicePaid := false
Expand Down Expand Up @@ -500,16 +489,14 @@ func (m *Mint) Swap(proofs cashu.Proofs, blindedMessages cashu.BlindedMessages)

// RequestMeltQuote will process a request to melt tokens and return a MeltQuote.
// A melt is requested by a wallet to request the mint to pay an invoice.
func (m *Mint) RequestMeltQuote(method, request, unit string) (storage.MeltQuote, error) {
if method != BOLT11_METHOD {
return storage.MeltQuote{}, cashu.PaymentMethodNotSupportedErr
}
if unit != SAT_UNIT {
errmsg := fmt.Sprintf("unit '%v' not supported", unit)
func (m *Mint) RequestMeltQuote(meltQuoteRequest nut05.PostMeltQuoteBolt11Request) (storage.MeltQuote, error) {
if meltQuoteRequest.Unit != cashu.Sat.String() {
errmsg := fmt.Sprintf("unit '%v' not supported", meltQuoteRequest.Unit)
return storage.MeltQuote{}, cashu.BuildCashuError(errmsg, cashu.UnitErrCode)
}

// check invoice passed is valid
request := meltQuoteRequest.Request
bolt11, err := decodepay.Decodepay(request)
if err != nil {
errmsg := fmt.Sprintf("invalid invoice: %v", err)
Expand Down Expand Up @@ -575,11 +562,7 @@ func (m *Mint) RequestMeltQuote(method, request, unit string) (storage.MeltQuote

// GetMeltQuoteState returns the state of a melt quote.
// Used to check whether a melt quote has been paid.
func (m *Mint) GetMeltQuoteState(ctx context.Context, method, quoteId string) (storage.MeltQuote, error) {
if method != BOLT11_METHOD {
return storage.MeltQuote{}, cashu.PaymentMethodNotSupportedErr
}

func (m *Mint) GetMeltQuoteState(ctx context.Context, quoteId string) (storage.MeltQuote, error) {
meltQuote, err := m.db.GetMeltQuote(quoteId)
if err != nil {
return storage.MeltQuote{}, cashu.QuoteNotExistErr
Expand Down Expand Up @@ -675,7 +658,9 @@ func (m *Mint) removePendingProofsForQuote(quoteId string) (cashu.Proofs, error)

// MeltTokens verifies whether proofs provided are valid
// and proceeds to attempt payment.
func (m *Mint) MeltTokens(ctx context.Context, method, quoteId string, proofs cashu.Proofs) (storage.MeltQuote, error) {
func (m *Mint) MeltTokens(ctx context.Context, meltTokensRequest nut05.PostMeltBolt11Request) (storage.MeltQuote, error) {
proofs := meltTokensRequest.Inputs

var proofsAmount uint64
Ys := make([]string, len(proofs))
for i, proof := range proofs {
Expand All @@ -689,11 +674,7 @@ func (m *Mint) MeltTokens(ctx context.Context, method, quoteId string, proofs ca
Ys[i] = Yhex
}

if method != BOLT11_METHOD {
return storage.MeltQuote{}, cashu.PaymentMethodNotSupportedErr
}

meltQuote, err := m.db.GetMeltQuote(quoteId)
meltQuote, err := m.db.GetMeltQuote(meltTokensRequest.Quote)
if err != nil {
return storage.MeltQuote{}, cashu.QuoteNotExistErr
}
Expand Down Expand Up @@ -921,11 +902,11 @@ func (m *Mint) ProofsStateCheck(Ys []string) ([]nut07.ProofState, error) {
defer cancel()

m.logDebugf("checking if status of pending proofs has changed")
for quoteId, _ := range pendingQuotes {
for quoteId := range pendingQuotes {
// GetMeltQuoteState will check the status of the quote
// and update the db tables (pending proofs, used proofs) appropriately
// if the status has changed
_, err := m.GetMeltQuoteState(ctx, BOLT11_METHOD, quoteId)
_, err := m.GetMeltQuoteState(ctx, quoteId)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -1388,8 +1369,8 @@ func (m *Mint) SetMintInfo(mintInfo MintInfo) {
4: nut06.NutSetting{
Methods: []nut06.MethodSetting{
{
Method: BOLT11_METHOD,
Unit: SAT_UNIT,
Method: cashu.BOLT11_METHOD,
Unit: cashu.Sat.String(),
MinAmount: m.limits.MintingSettings.MinAmount,
MaxAmount: m.limits.MintingSettings.MaxAmount,
},
Expand All @@ -1399,8 +1380,8 @@ func (m *Mint) SetMintInfo(mintInfo MintInfo) {
5: nut06.NutSetting{
Methods: []nut06.MethodSetting{
{
Method: BOLT11_METHOD,
Unit: SAT_UNIT,
Method: cashu.BOLT11_METHOD,
Unit: cashu.Sat.String(),
MinAmount: m.limits.MeltingSettings.MinAmount,
MaxAmount: m.limits.MeltingSettings.MaxAmount,
},
Expand All @@ -1418,7 +1399,7 @@ func (m *Mint) SetMintInfo(mintInfo MintInfo) {

info := nut06.MintInfo{
Name: mintInfo.Name,
Version: "gonuts/0.2.0",
Version: "gonuts/0.3.0",
Description: mintInfo.Description,
LongDescription: mintInfo.LongDescription,
Contact: mintInfo.Contact,
Expand Down
Loading
Loading