Back to Freedom.Tech Back
All Cashu TS releasesAll versions
Release Tue, Sep 22, 2026 7 min read

Cashu TS 5.0.0-rc.11

Original release notes

This release finishes the nutroot wire format for v3 (BLS) keysets, adds abort signals and an optional keepalive to the transport, and closes a long list of findings from building real wallets against rc.10 on the web, Node and Deno. There are a few more breaking changes since rc.10; the migration guide has each one with before and after code.

Upgrading from rc.10: read these even if you never touch a v3 keyset

  • Quote lock keys derived from a seed are now scoped to the mint's NUT-06 identity pubkey, one counter per mint under quoteCounterKey(mintPubkey); the single QUOTE_COUNTER_KEY export is gone and a custom CounterSource must accept mint-quote-lock:<pubkey> keys. Keys derived by rc.10 are not recoverable by scan, so keep the privkey of any unpaid rc.10 quote. The derivation is marked @experimental: it follows draft NUT-13 and NUT-06 and may change again before GA, which is why the contract remains "persist the privkey with its quote".
  • Every Mint method that took a trailing customRequest now takes { customRequest?, signal? }. Wallet operation configs, builders (.signal()) and quote or state checks accept an AbortSignal too; a one-shot operation honours it until preparation finishes and never mid-commit. An aborted call rejects with CallerAbortError, now exported alongside UncancellableReadError.
  • Amount throws AmountError on implicit numeric coercion (a + 1, a < b, Number(a)); string contexts still work. Amount.from accepts a structuredClone'd Amount, so IndexedDB and postMessage round trips no longer need special handling.
  • getDecodedTokenBinary requires the keyset id list. Mint.oidcAuth is removed in favour of OIDCAuth.fromMintInfo, and OIDC endpoints must match the discovery document's scheme. Lock families are named 'nutroot' | 'p2pk' rather than by version.
  • Requests time out after 5 minutes per attempt by default (requestTimeout: Infinity disables it), retries back off more slowly and log at info, and a NetworkError names the mint origin and the underlying cause.
  • The ES build preserves modules, so a bundler that imports only Amount or the token codec no longer pays for the whole wallet. Wallet itself is unchanged in size.
  • NUT-17: a subscription whose socket closes now has its error callback invoked (any close code), so a plain on.mintQuotePaid can resubscribe or fall back. The optional wsKeepaliveMs on Wallet or Mint probes the socket and treats silence as a close, for the half-open connections a proxy leaves behind. WSConnection.onClose takes a WSCloseEvent, so the shipped types no longer need the DOM lib on Node.
  • mnemonicToSeedSync derives the BIP-39 seed from a phrase with no new dependency; validate the phrase first with @scure/bip39 or similar.
  • Every mint, batch mint and melt preview now has a serialize and deserialize pair.

v3 keysets

Nutroot is still a draft and v3 keysets are served only by demo mints, so nothing here affects funds on a public mint. The transcript picked up three spec changes since rc.10 (the commit leaf, melt outputs priced at quote plus fee reserve, and proof inputs named by Y), which is what makes rc.11 spend against current Nutshell. BLS keysets carry no DLEQ; requireDleq accepts 02 proofs on the strength of the pairing check. A wallet now refuses to bind to a keyset id version this build cannot spend rather than failing later, and refuses pre-v3 locks or NUT-29 batch operations the mint does not advertise.

---

What's Changed

  • fix(utils): resolve short keyset IDs in getDecodedTokenBinary by @Hardeezah in https://github.com/cashubtc/cashu-ts/pull/1153
  • feat(nutroot): the commit leaf (NUT-10 type 0x04) by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1151
  • test: raise the vitest timeout and shrink two heavy prepareMint fixtures by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1157
  • fix(mint): check a bolt11 melt preimage against the invoice payment hash by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1161
  • fix(utils): apply the keyset unit alphabet to version 01 ids too by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1162
  • feat(wallet): add serialize helpers for mint, batch mint and melt previews by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1159
  • fix(auth): check OIDC endpoint schemes against the discovery document by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1160
  • refactor: route the last UTF-8 decodes through utils/bytes by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1168
  • docs: say where transport policy lives by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1170
  • chore(docker): update NUT_IMAGE to cashubtc/nutshell:0.21.0 by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1173
  • feat(nutroot): melt output amount is the quote amount plus its fee reserve by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1172
  • fix(model): require boolean true for advertised NUT support by @KvngMikey in https://github.com/cashubtc/cashu-ts/pull/1176
  • feat(nutroot): name transcript proof inputs by Y by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1175
  • chore(deps): bump typescript-eslint from 8.69.0 to 8.70.0 in the eslint group by @dependabot[bot] in https://github.com/cashubtc/cashu-ts/pull/1180
  • fix(utils): getDecodedTokenBinary requires the keyset id list by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1178
  • fix(core): keep a token's witness verbatim when re-encoding by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1179
  • chore(deps): bump the vitest group with 2 updates by @dependabot[bot] in https://github.com/cashubtc/cashu-ts/pull/1182
  • chore(deps): bump the dev-tooling group with 3 updates by @dependabot[bot] in https://github.com/cashubtc/cashu-ts/pull/1183
  • chore(deps): bump the vitest family to 5.0.0 by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1187
  • test(mutation): give the Stryker vitest config a 20s test timeout by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1189
  • ci(mutation): pin vitest 4 for the weekly Stryker run by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1191
  • chore(docker): update CDK_IMAGE to cashubtc/mintd:0.18.1 by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1193
  • fix(wallet): refuse pre-v3 locks the mint does not advertise by @Kelbie in https://github.com/cashubtc/cashu-ts/pull/1195
  • fix(wallet): refuse keyset id versions this build cannot spend by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1199
  • docs: correct usage snippets that no longer compile by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1198
  • test(wallet): pin that a proof subscription refuses an unreadable keyset by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1201
  • fix(wallet): reject unspendable proofs for an unlocked payment request by @Kelbie in https://github.com/cashubtc/cashu-ts/pull/1197
  • feat(wallet): scope quote lock keys to the mint identity by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1202
  • fix(wallet): fill NUT-04 base fields on mint quote subscription updates by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1203
  • fix(core): refuse implicit numeric coercion of Amount by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1204
  • docs: point at the repository for files the package does not ship by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1206
  • fix(utils): refuse text with a lone surrogate in the CBOR and TLV encoders by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1209
  • fix(wallet): report the websocket mode on subscriptions without pollMs by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1207
  • fix(wallet): normalize melt quote subscription updates like HTTP responses by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1208
  • docs: document websocket teardown and injectWebSocketImpl by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1215
  • fix(transport): log a failed unsubscribe at info by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1214
  • fix(events): skip the batched quote check where the mint does not offer it by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1213
  • docs: correct the CREQB1 size claim and scope the pre-flight lock check to v3 by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1216
  • fix(transport): export CallerAbortError and UncancellableReadError by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1212
  • docs: say that proof-set concurrency is the app's job by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1220
  • feat(crypto): add mnemonicToSeedSync by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1221
  • fix(wallet): refuse NUT-29 batch operations the mint does not advertise by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1222
  • fix(transport): time out request attempts after 5 minutes by default by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1224
  • docs: lead the send pages with the recoverable pattern by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1223
  • fix(model): accept a structuredClone'd Amount in Amount.from by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1228
  • docs: say how Amount survives persistence by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1229
  • fix(crypto): write the BLS field orders as literals by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1231
  • refactor(auth): build OIDCAuth from mint info, not from Mint by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1232
  • build: preserve modules in the ES build by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1233
  • docs: make every docs-src snippet type-check by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1234
  • docs: tell errors apart by instanceof and name, not constructor.name by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1237
  • chore(eslint): use defineConfig instead of the deprecated tseslint.config by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1236
  • ci: type-check docs-src snippets against the shipped types by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1235
  • fix(wallet): log a keyset summary on load instead of the whole cache by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1238
  • fix(transport): quieter retry logging, slower backoff, and NetworkError names the mint by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1240
  • refactor(wallet): name lock families by encoding, not version by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1242
  • docs: say which keyset a wallet is on and how to tell the curve by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1243
  • feat(mint): per-call options with an abort signal on every Mint method by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1244
  • feat(wallet): accept an abort signal on wallet operations by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1245
  • chore(errors): move stray error classes into model/Errors by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1246
  • docs(keysets): say BLS keysets carry no DLEQ and requireDleq accepts them by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1248
  • fix(transport): drop the DOM CloseEvent type from the WSConnection public surface by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1249
  • fix(transport): fail established subscriptions when the socket closes by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1251
  • feat(transport): optional keepalive probe for NUT-17 sockets by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1253
  • docs(wallet): mark the quote lock seed derivation experimental by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1254
  • chore(main): release 5.0.0-rc.11 by @robwoodgate in https://github.com/cashubtc/cashu-ts/pull/1155

New Contributors

  • @Hardeezah made their first contribution in https://github.com/cashubtc/cashu-ts/pull/1153

Full Changelog: https://github.com/cashubtc/cashu-ts/compare/v5.0.0-rc.10...v5.0.0-rc.11