diff --git a/nip60/pay.go b/nip60/pay.go index f4316a3..63096b3 100644 --- a/nip60/pay.go +++ b/nip60/pay.go @@ -94,6 +94,11 @@ meltworked: nil, ) + // mark tokens as reserved before attempting melt + for _, i := range chosen.tokenIndexes { + w.Tokens[i].reserved = true + } + // request from mint to _melt_ into paying the invoice delay := 200 * time.Millisecond // this request will block until the invoice is paid or it fails @@ -103,17 +108,44 @@ meltworked: Inputs: chosen.proofs, Outputs: preChange.bm, }) -inspectmeltstatusresponse: - if err != nil || meltStatus.State == nut05.Unpaid { - return "", fmt.Errorf("error melting token: %w", err) - } else if meltStatus.State == nut05.Unknown { - return "", fmt.Errorf("we don't know what happened with the melt at %s: %v", chosen.mint, meltStatus) - } else if meltStatus.State == nut05.Pending { - for { + for { + if err != nil || meltStatus.State == nut05.Unpaid { + // unreserve tokens to available state on failure + for _, i := range chosen.tokenIndexes { + w.Tokens[i].reserved = false + } + return "", fmt.Errorf("error melting token: %w", err) + } else if meltStatus.State == nut05.Unknown { + // unreserve tokens to available state on failure + for _, i := range chosen.tokenIndexes { + w.Tokens[i].reserved = false + } + return "", fmt.Errorf("we don't know what happened with the melt at %s: %v", chosen.mint, meltStatus) + } else if meltStatus.State == nut05.Pending { time.Sleep(delay) delay *= 2 meltStatus, err = client.GetMeltQuoteState(ctx, chosen.mint, meltStatus.Quote) - goto inspectmeltstatusresponse + if err != nil { + // unreserve tokens to available state on failure + for _, i := range chosen.tokenIndexes { + w.Tokens[i].reserved = false + } + return "", fmt.Errorf("error checking melt status: %w", err) + } + if meltStatus.State == nut05.Unpaid || meltStatus.State == nut05.Unknown { + // unreserve tokens to available state on failure + for _, i := range chosen.tokenIndexes { + w.Tokens[i].reserved = false + } + return "", fmt.Errorf("melt failed with state %v", meltStatus.State) + } else if meltStatus.State == nut05.Paid { + // payment successful + break + } + // continue looping for pending state + continue + } else if meltStatus.State == nut05.Paid { + break } } diff --git a/nip60/send.go b/nip60/send.go index 668601c..98eacc9 100644 --- a/nip60/send.go +++ b/nip60/send.go @@ -153,6 +153,9 @@ func (w *Wallet) getProofsForSending( ) (chosenTokens, uint64, error) { byMint := make(map[string]chosenTokens) for t, token := range w.Tokens { + if token.reserved { + continue + } if fromMint != "" && token.Mint != fromMint { continue } diff --git a/nip60/token.go b/nip60/token.go index 8647d4c..e05d7a5 100644 --- a/nip60/token.go +++ b/nip60/token.go @@ -14,6 +14,7 @@ type Token struct { Proofs cashu.Proofs `json:"proofs"` Deleted []nostr.ID `json:"del,omitempty"` + reserved bool mintedAt nostr.Timestamp event *nostr.Event } diff --git a/nip60/wallet.go b/nip60/wallet.go index d99148c..35945dc 100644 --- a/nip60/wallet.go +++ b/nip60/wallet.go @@ -249,6 +249,10 @@ func (w *Wallet) removeDeletedToken(eventId nostr.ID) { func (w *Wallet) Balance() uint64 { var sum uint64 for _, token := range w.Tokens { + if token.reserved { + continue + } + sum += token.Proofs.Amount() } return sum