refactor(core): centralize mint quote claimability - #398
Conversation
🦋 Changeset detectedLatest commit: 2675637 The changes in this PR will be included in the next version bump. This PR includes changesets to release 8 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #398 +/- ##
==========================================
+ Coverage 92.63% 92.81% +0.17%
==========================================
Files 111 112 +1
Lines 17633 17751 +118
==========================================
+ Hits 16334 16475 +141
+ Misses 1299 1276 -23
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2675637aff
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| ); | ||
| } | ||
|
|
||
| if (canonicalQuote && (result.category !== 'terminal' || result.quoteSnapshot !== undefined)) { |
There was a problem hiding this comment.
Preserve terminal failures during accounting reclassification
When a BOLT12 or on-chain pending operation is missing its NUT-20 pubkey, checkPending returns a terminal missing_quote_pubkey failure together with a quote snapshot. This condition nevertheless reassesses the persisted quote, replaces that terminal result with ready or waiting, and clears terminalFailure; a funded quote can therefore enter execution before the missing-key invariant is handled, and callers receive the wrong check result. Skip accounting reclassification for non-accounting terminal failures so the operation fails immediately.
AGENTS.md reference: AGENTS.md:L162-L164
Useful? React with 👍 / 👎.
| for (const quote of quotes) { | ||
| if (!quote.reusable) { | ||
| continue; | ||
| } | ||
| if (getMintQuoteAvailableAmount(quote).isZero()) { | ||
| continue; | ||
| } | ||
|
|
||
| claimed.push( | ||
| ...(await this.claimMintQuote(quote.mintUrl, quote.method, quote.quoteId, options)), | ||
| ); |
There was a problem hiding this comment.
Gate startup quote claims on mint trust
Because this loop now forwards BOLT11 quotes as well as reusable quotes, processor startup can redeem an existing paid BOLT11 operation after its mint has been untrusted. claimMintQuote executes pending siblings without checking isTrustedMint, whereas the watcher and recovery paths explicitly skip untrusted mints, so restarting the manager can contact and mutate wallet state for a mint the user disabled. Check trust before automatically claiming these quotes.
AGENTS.md reference: AGENTS.md:L162-L163
Useful? React with 👍 / 👎.
| } | ||
| } | ||
| async ({ mintUrl, method, quoteId }) => { | ||
| this.scheduleQuoteClaim(mintUrl, method, quoteId); |
There was a problem hiding this comment.
Queue a follow-up claim when an update arrives in flight
Routing every BOLT11 quote update through scheduleQuoteClaim makes paid transitions subject to its in-flight deduplication. If an UNPAID assessment is still running when a concurrent PAID notification is persisted, the second call is discarded because the quote key is already in claimingQuotes; the first task can then return waiting, and unchanged later snapshots do not emit another quote-update event, leaving the paid operation pending until restart or manual recovery. Record a dirty/pending rerun instead of dropping an update received during an active claim.
Useful? React with 👍 / 👎.
| @@ -334,12 +360,6 @@ export class MintBolt12Handler implements MintMethodHandler<'bolt12'> { | |||
|
|
|||
There was a problem hiding this comment.
Revalidate accounting on the execute-time quote
BOLT12 and on-chain execution fetch a fresh remote quote after the service-level claimability assessment, but removing this check from assertQuoteMatchesRequest means that fresh response is no longer rejected when amount_issued exceeds amount_paid. If the mint returns contradictory accounting between readiness and execution, the handlers now pass that invalid quote into mintProofsBolt12 or mintProofsOnchain and sign/send outputs instead of stopping before mutation. Assess the execute-time quote or retain the accounting invariant check here.
AGENTS.md reference: AGENTS.md:L163-L163
Useful? React with 👍 / 👎.
Problem
Canonical Mint Quote Accounting was already uniform, but readiness, scheduling, recovery, and pending selection still rebuilt payment-method behavior from BOLT11 compatibility
state,method, andreusable. Those scattered rules could disagree, especially when remote balance accounting lagged local issuance or a quote observation jumped directly to complete.Summary
Impact
BOLT11 compatibility state remains available for import and projection but no longer drives runtime claimability. BOLT12 and on-chain quotes retain repeated partial claims, including when remote issuance counters lag local finalized operations.
Verification
bun run --filter='@cashu/coco-core' test:unit— 1,186 passedbun run --filter='@cashu/coco-core' buildbun run --filter='@cashu/coco-core' typecheckgit diff --checkThe live SQLite integration suite requires
MINT_URL; IndexedDB contracts were run in Chromium.Changeset
Adds
.changeset/canonical-mint-quote-claimability.mdfor the affected published packages.Resolves #387.