diff --git a/cashu/nuts/nut04/nut04.go b/cashu/nuts/nut04/nut04.go index 55557a9..a1632f7 100644 --- a/cashu/nuts/nut04/nut04.go +++ b/cashu/nuts/nut04/nut04.go @@ -3,7 +3,50 @@ // [NUT-04]: https://github.com/cashubtc/nuts/blob/main/04.md package nut04 -import "github.com/elnosh/gonuts/cashu" +import ( + "encoding/json" + + "github.com/elnosh/gonuts/cashu" +) + +type State int + +const ( + Unpaid State = iota + Paid + Pending + Issued + Unknown +) + +func (state State) String() string { + switch state { + case Unpaid: + return "UNPAID" + case Paid: + return "PAID" + case Pending: + return "PENDING" + case Issued: + return "ISSUED" + default: + return "unknown" + } +} + +func StringToState(state string) State { + switch state { + case "UNPAID": + return Unpaid + case "PAID": + return Paid + case "PENDING": + return Pending + case "ISSUED": + return Issued + } + return Unknown +} type PostMintQuoteBolt11Request struct { Amount uint64 `json:"amount"` @@ -13,7 +56,8 @@ type PostMintQuoteBolt11Request struct { type PostMintQuoteBolt11Response struct { Quote string `json:"quote"` Request string `json:"request"` - Paid bool `json:"paid"` + State State `json:"state"` + Paid bool `json:"paid"` // DEPRECATED: use State instead Expiry int64 `json:"expiry"` } @@ -25,3 +69,39 @@ type PostMintBolt11Request struct { type PostMintBolt11Response struct { Signatures cashu.BlindedSignatures `json:"signatures"` } + +type TempQuote struct { + Quote string `json:"quote"` + Request string `json:"request"` + State string `json:"state"` + Paid bool `json:"paid"` // DEPRECATED: use State instead + Expiry int64 `json:"expiry"` +} + +func (quoteResponse *PostMintQuoteBolt11Response) MarshalJSON() ([]byte, error) { + var tempQuote = TempQuote{ + Quote: quoteResponse.Quote, + Request: quoteResponse.Request, + State: quoteResponse.State.String(), + Paid: quoteResponse.Paid, + Expiry: quoteResponse.Expiry, + } + return json.Marshal(tempQuote) +} + +func (quoteResponse *PostMintQuoteBolt11Response) UnmarshalJSON(data []byte) error { + tempQuote := &TempQuote{} + + if err := json.Unmarshal(data, tempQuote); err != nil { + return err + } + + quoteResponse.Quote = tempQuote.Quote + quoteResponse.Request = tempQuote.Request + state := StringToState(tempQuote.State) + quoteResponse.State = state + quoteResponse.Paid = tempQuote.Paid + quoteResponse.Expiry = tempQuote.Expiry + + return nil +} diff --git a/mint/mint.go b/mint/mint.go index 15056ce..7d14916 100644 --- a/mint/mint.go +++ b/mint/mint.go @@ -119,7 +119,8 @@ func (m *Mint) RequestMintQuote(method string, amount uint64, unit string) (nut0 reqMintQuoteResponse := nut04.PostMintQuoteBolt11Response{ Quote: invoice.Id, Request: invoice.PaymentRequest, - Paid: invoice.Settled, + State: nut04.Unpaid, + Paid: invoice.Settled, // DEPRECATED: remove after wallets have upgraded Expiry: invoice.Expiry, } @@ -144,15 +145,22 @@ func (m *Mint) GetMintQuoteState(method, quoteId string) (nut04.PostMintQuoteBol msg := fmt.Sprintf("error getting invoice status: %v", err) return nut04.PostMintQuoteBolt11Response{}, cashu.BuildCashuError(msg, cashu.InvoiceErrCode) } - if status.Settled && status.Settled != invoice.Settled { + + state := nut04.Unpaid + if status.Settled { invoice.Settled = status.Settled + state = nut04.Paid + if invoice.Redeemed { + state = nut04.Issued + } m.db.SaveInvoice(*invoice) } quoteState := nut04.PostMintQuoteBolt11Response{ Quote: invoice.Id, Request: invoice.PaymentRequest, - Paid: invoice.Settled, + State: state, + Paid: invoice.Settled, // DEPRECATED: remove after wallets have upgraded Expiry: invoice.Expiry, } return quoteState, nil diff --git a/mint/server.go b/mint/server.go index eb4b079..372d1c7 100644 --- a/mint/server.go +++ b/mint/server.go @@ -219,7 +219,7 @@ func (ms *MintServer) mintRequest(rw http.ResponseWriter, req *http.Request) { return } - jsonRes, err := json.Marshal(reqMintResponse) + jsonRes, err := json.Marshal(&reqMintResponse) if err != nil { ms.writeErr(rw, req, cashu.StandardErr) return @@ -246,7 +246,7 @@ func (ms *MintServer) mintQuoteState(rw http.ResponseWriter, req *http.Request) ms.writeErr(rw, req, err) return } - jsonRes, err := json.Marshal(mintQuoteStateResponse) + jsonRes, err := json.Marshal(&mintQuoteStateResponse) if err != nil { ms.writeErr(rw, req, cashu.StandardErr) return diff --git a/wallet/wallet.go b/wallet/wallet.go index b2d9369..d1b680c 100644 --- a/wallet/wallet.go +++ b/wallet/wallet.go @@ -310,16 +310,6 @@ func (w *Wallet) RequestMint(amount uint64) (*nut04.PostMintQuoteBolt11Response, return mintResponse, nil } -// CheckQuotePaid reports whether the mint quote has been paid -func (w *Wallet) CheckQuotePaid(quoteId string) bool { - mintQuote, err := GetMintQuoteState(w.currentMint.mintURL, quoteId) - if err != nil { - return false - } - - return mintQuote.Paid -} - // MintTokens will check whether if the mint quote has been paid. // If yes, it will create blinded messages that will send to the mint // to get the blinded signatures. @@ -330,7 +320,8 @@ func (w *Wallet) MintTokens(quoteId string) (cashu.Proofs, error) { if err != nil { return nil, err } - if !mintQuote.Paid { + // TODO: remove usage of 'Paid' field after mints have upgraded + if !mintQuote.Paid || mintQuote.State == nut04.Unpaid { return nil, errors.New("invoice not paid") }