nip60: don't lose tokens when bolt11 payment fails.
This commit is contained in:
+40
-8
@@ -94,6 +94,11 @@ meltworked:
|
|||||||
nil,
|
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
|
// request from mint to _melt_ into paying the invoice
|
||||||
delay := 200 * time.Millisecond
|
delay := 200 * time.Millisecond
|
||||||
// this request will block until the invoice is paid or it fails
|
// this request will block until the invoice is paid or it fails
|
||||||
@@ -103,17 +108,44 @@ meltworked:
|
|||||||
Inputs: chosen.proofs,
|
Inputs: chosen.proofs,
|
||||||
Outputs: preChange.bm,
|
Outputs: preChange.bm,
|
||||||
})
|
})
|
||||||
inspectmeltstatusresponse:
|
for {
|
||||||
if err != nil || meltStatus.State == nut05.Unpaid {
|
if err != nil || meltStatus.State == nut05.Unpaid {
|
||||||
return "", fmt.Errorf("error melting token: %w", err)
|
// unreserve tokens to available state on failure
|
||||||
} else if meltStatus.State == nut05.Unknown {
|
for _, i := range chosen.tokenIndexes {
|
||||||
return "", fmt.Errorf("we don't know what happened with the melt at %s: %v", chosen.mint, meltStatus)
|
w.Tokens[i].reserved = false
|
||||||
} else if meltStatus.State == nut05.Pending {
|
}
|
||||||
for {
|
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)
|
time.Sleep(delay)
|
||||||
delay *= 2
|
delay *= 2
|
||||||
meltStatus, err = client.GetMeltQuoteState(ctx, chosen.mint, meltStatus.Quote)
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -153,6 +153,9 @@ func (w *Wallet) getProofsForSending(
|
|||||||
) (chosenTokens, uint64, error) {
|
) (chosenTokens, uint64, error) {
|
||||||
byMint := make(map[string]chosenTokens)
|
byMint := make(map[string]chosenTokens)
|
||||||
for t, token := range w.Tokens {
|
for t, token := range w.Tokens {
|
||||||
|
if token.reserved {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if fromMint != "" && token.Mint != fromMint {
|
if fromMint != "" && token.Mint != fromMint {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ type Token struct {
|
|||||||
Proofs cashu.Proofs `json:"proofs"`
|
Proofs cashu.Proofs `json:"proofs"`
|
||||||
Deleted []nostr.ID `json:"del,omitempty"`
|
Deleted []nostr.ID `json:"del,omitempty"`
|
||||||
|
|
||||||
|
reserved bool
|
||||||
mintedAt nostr.Timestamp
|
mintedAt nostr.Timestamp
|
||||||
event *nostr.Event
|
event *nostr.Event
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -249,6 +249,10 @@ func (w *Wallet) removeDeletedToken(eventId nostr.ID) {
|
|||||||
func (w *Wallet) Balance() uint64 {
|
func (w *Wallet) Balance() uint64 {
|
||||||
var sum uint64
|
var sum uint64
|
||||||
for _, token := range w.Tokens {
|
for _, token := range w.Tokens {
|
||||||
|
if token.reserved {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
sum += token.Proofs.Amount()
|
sum += token.Proofs.Amount()
|
||||||
}
|
}
|
||||||
return sum
|
return sum
|
||||||
|
|||||||
Reference in New Issue
Block a user