Skip to content

Cashu ts v4#1108

Open
gudnuf wants to merge 8 commits into
masterfrom
cashu-ts-v4
Open

Cashu ts v4#1108
gudnuf wants to merge 8 commits into
masterfrom
cashu-ts-v4

Conversation

@gudnuf

@gudnuf gudnuf commented May 22, 2026

Copy link
Copy Markdown
Contributor

Updates to cashu-ts v4

The biggest change is that cashu-ts v4 introduced an Amount type that handles big ints and units. I decided to just use toNumber on all the Amounts to keep the refactor minimial, but maybe there's something we can do here to better integrate with our existing money lib.

Another change is that we no longer need a custom wrapper for encoding tokens. Cashu-ts v3 was mutating the v2 keyset ID when encoding, but that is fixed in v4 so we can use getEncodedToken directly.

@gudnuf gudnuf self-assigned this May 22, 2026
@vercel

vercel Bot commented May 22, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agicash Ready Ready Preview, Comment Jun 1, 2026 6:29pm

Request Review

@supabase

supabase Bot commented May 22, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project hrebgkfhjpkbxpztqqke because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

orveth added 5 commits June 1, 2026 10:26
Scope classification doc for the @cashu/cashu-ts 3.6.1 → v4 bump:
breaking changes summary, file-by-file audit, per-bucket counts,
10 open questions, recommended 3-PR sequencing.

No code changes.
cashu-ts v4.0 (#536) fixed the proof.id mutation bug in getEncodedToken,
so the deep-clone wrapper in app/lib/cashu/token.ts is no longer needed.
Call getEncodedToken directly at all sites.
v4 KeyChain cache is mint-wide rather than unit-scoped, so the first
unit argument has been removed from the signature.
v4 types MintQuoteBolt11Response.expiry as `number | null` to match
NUT-23 — null means the mint did not communicate one, not that the
quote never expires. Per NUT-23 the field *is* the bolt11 invoice
expiry, so fall back to the decoded invoice's expiry (which
decodeBolt11 already returns) when the mint omits it, instead of
substituting a sentinel.

MeltQuoteBolt11Response.expiry remains non-nullable in v4 per its type
declaration, so no change is needed on the send-quote side.
Comment thread app/features/receive/cashu-receive-quote-repository.server.ts
Comment thread app/features/receive/cashu-receive-quote-service.ts
Comment thread app/lib/cashu/blind-signature-matching.ts
Comment thread app/lib/cashu/utils.ts
const isKeysetActive = (ks: MintKeyset | Keyset): boolean =>
'isActive' in ks ? ks.isActive : ks.active;

const getKeysetFinalExpiry = (

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need these hepter now because the property names changes? Do we actually use the below functions with both types?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes — both types are genuinely used, so these are load-bearing. findFirstActiveKeyset / getKeysetExpiry are called with:

  • MintKeyset[] from account-service.ts (via Mint.getKeySets() — props active / final_expiry)
  • Keyset[] from receive-cashu-token-service.ts (via wallet.keyChain.getKeysets() — props isActive / expiry)

v4 names the same fields differently across the two types, so isKeysetActive / getKeysetFinalExpiry normalize them. Removing the helpers would break one of the two call sites. (Could inline the normalization at each call site instead, but the helper is less code.)

orveth added 3 commits June 1, 2026 11:26
- classify-input.test.ts: drop the removed `{ version }` option from
  getEncodedToken (v4 has a single encoding) and wrap proof.amount in
  Amount.from() to match the new Proof type.
- blind-signature-matching.test.ts: drop the `amount` arg from
  createBlindSignature (v4 takes only B_, privateKey, id) and read the
  amount from the local parameter wrapped in Amount.from(), since the
  returned BlindSignature no longer carries an amount field.
- blind-signature-matching: sig.amount is now an Amount value object, not
  a number, so it can't index keyset.keys directly — call toNumber().
- tokenToMoney: post-Bucket-A, sumProofs returns Amount; call toNumber()
  so Money still receives a primitive amount.
@gudnuf gudnuf requested review from jbojcic1 and pmilic021 June 1, 2026 19:44
@gudnuf gudnuf marked this pull request as ready for review June 1, 2026 19:44

@pmilic021 pmilic021 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Comment on lines +70 to +73
tokenProofs: params.meltData.tokenProofs.map((p) => ({
...p,
amount: p.amount.toNumber(),
})),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: this is duplicated on a lot of places, maybe we should extract it in a helper

export const toStoredProofs = (proofs: Proof[]) =>
  proofs.map((p) => ({ ...p, amount: p.amount.toNumber() }));

or maybe even the whole toStoredMeltData.

Up to you, not sure if it's worth it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants