mirror of
https://github.com/tompro/sattle.git
synced 2026-10-26 01:49:58 +00:00
fix(lnurlcash): commit carves before the settlement wait (#6)
A flow that carves and then waits minutes on a settlement poll used to commit the carve only after the whole flow resolved - an abort mid-wait left burned inputs spendable locally and stranded the fresh outputs. ensureExactAmount now reports a mutation-bearing carve through the new FundOperationOptions.onCarve checkpoint the moment its outcome is known; payWithBearers and transferBetweenMints thread it through. Because the carve may now be committed before the flows' classification rotates run, those rotations no longer rewrite carve.note in the result - returned funds come back as a separate verified rotatedNote, so the committed carve and the re-secured note can both be persisted. NWC's payChangeset adapts to the rotatedNote field; its own commit timing is unchanged (follow-up).
This commit is contained in:
@@ -23,18 +23,19 @@ import {errResult, okResult} from './protocol'
|
||||
|
||||
// maps a PayResult onto the store delta, mirroring PayInvoiceDialog's
|
||||
// semantics: carve inputs lock spent, change is tracked, returned funds
|
||||
// are tracked UNMARKED, rescued secrets are tracked unverified. One
|
||||
// are tracked UNMARKED, rescued secrets are tracked unverified. The
|
||||
// returned funds live in `rotatedNote` when the classification rotate
|
||||
// re-secured them (burning the carved note in the process); one
|
||||
// deliberate divergence: in the exact-match + funds-returned case the
|
||||
// original bearer (old k1, burned server-side by the classification
|
||||
// rotate) is left for the next refresh to reconcile, exactly as the UI
|
||||
// leaves it - the money itself sits in the re-secured note, which IS
|
||||
// tracked.
|
||||
// original bearer (old k1, burned server-side by that rotate) is left for
|
||||
// the next refresh to reconcile, exactly as the UI leaves it - the money
|
||||
// itself sits in the re-secured note, which IS tracked.
|
||||
export const payChangeset = (bearers: Bearer[], result: PayResult): NwcChangeset => {
|
||||
const add: NewBearer[] = []
|
||||
const markSpent: string[] = result.carve.consumed.map((b) => b.id)
|
||||
if (result.carve.change) add.push(result.carve.change)
|
||||
if (result.outcome === 'failed-funds-returned') {
|
||||
add.push(result.carve.note)
|
||||
add.push(result.rotatedNote ?? result.carve.note)
|
||||
} else {
|
||||
// settled / still-pending / already-spent: the carved note is gone or
|
||||
// locked. When it was one of the wallet's own bearers (an exact-match
|
||||
|
||||
Reference in New Issue
Block a user