mirror of
https://github.com/minibits-cash/minibits_wallet.git
synced 2026-08-12 01:17:43 +00:00
Some mints (nutshell < 0.20.1) return paid-melt-quote change[]
signatures in an order that does not match the blank outputs the
wallet sent. cashu-ts OutputData.toProof assumes positional pairing
and throws on its DLEQ check, so mapping over the array aborted on the
first mismatch and the catch discarded ALL change — recording it as
fee. A user lost ~100k sats of change on a single transfer this way.
Add CashuUtils.recoverMeltChange, a resilient helper that:
- matches each signature to the blank whose blinded message makes the
mint's DLEQ proof verify (verifyDLEQProof as alignment oracle),
correctly re-pairing reordered change while keeping DLEQ as a hard
guarantee;
- on a genuine DLEQ failure (no blank verifies) falls back to
unblinding the positional blank WITHOUT DLEQ so funds are recovered
rather than dropped, logged at error level;
- returns stats so callers can surface anomalies.
Both melt finalize paths (transferOperationApi._finalizePaid and
meltOperations.handlePendingMeltTask) use the helper and append a
COMPLETED-status tx.data entry with the recovery stats when a genuine
error occurred (no-DLEQ fallback / unmatched) — benign reordering is
not flagged.
Covered by __tests__/recoverMeltChange.test.ts (in-order, shuffled,
fewer-sigs-than-blanks, duplicate denominations, no-DLEQ fallback,
unmatched).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>