Skip to content

chore(deps): bump @nostr-dev-kit/ndk to 3.0.3 - #4701

Open
kaloudis wants to merge 1 commit into
ZeusLN:masterfrom
kaloudis:fix/ndk-3-mint-discovery
Open

kaloudis wants to merge 1 commit into
ZeusLN:masterfrom
kaloudis:fix/ndk-3-mint-discovery

Conversation

@kaloudis

Copy link
Copy Markdown
Contributor

Description

Relates to issue: ZEUS-0000

Supersedes #4605. Dependabot's bump of @nostr-dev-kit/ndk to 3.0.3 cannot merge on its own: NDK 3 changes two defaults that between them break Cashu mint discovery entirely. This PR carries the same bump plus the two-line behavioral opt-outs needed to keep the old behavior, with before/after measurements on device.

Full analysis is in #4605 (comment). Summary:

1. NDKPool.connect() never resolves without a timeout argument. 3.x races "every relay reported CONNECTED" against a timeout promise that is new Promise(() => {}) when no timeout is passed:

const timeoutPromise = typeof timeoutMs === "number"
    ? new Promise((resolve) => setTimeout(resolve, timeoutMs))
    : new Promise(() => {});          // never resolves
await Promise.race([allConnectedPromise, timeoutPromise]);

2.13.0-rc2 instead awaited the per-relay connect promises, each of which resolves as soon as the socket is created. DEFAULT_NOSTR_RELAYS is never fully connected in practice (only 4 to 5 of 8 reach CONNECTED, wss://nostr.land sits in AUTH_REQUIRED, wss://nostr.wine and wss://relay.8333.space are usually down), so await this.ndk.connect() never returns. Discover Mints and the trusted-mints list spin forever with no error, because the 10s safety timeout in subscribeAndCollectEvents is never even reached.

2. The outbox model flipped from opt-in to on by default. 2.13 had if (opts.enableOutboxModel); 3.0.3 has if (!(opts.enableOutboxModel === false)). Mint discovery from follows subscribes with the followed author set (613 pubkeys for the ZEUS npub), and outbox tracking resolves each author's relay list and reconnects the subscription as those lists arrive. Measured effect: the relay pool grew from 8 to 43 relays and the JS thread was starved badly enough that a setTimeout(resolve, 10000) fired after 94 seconds. Even with fix 1 alone, trusted mints took ~122s instead of ~10s.

Both opt-outs are scoped to the three new NDK(...) sites in stores/CashuStore.ts, which are the only NDK usage in the app.

Measurements

Same device, same checkout, live relays, calling the real store methods:

Flow 2.13.0-rc2 (before) 3.0.3 as dependabot proposed 3.0.3 + this PR
fetchMints() (Discover Mints) 12 recommendations, ~14.5s never settles 12 recommendations, ~16.1s
fetchMintsFromFollows() (ZEUS npub) 17 recommendations, ~10.7s never settles 17 recommendations, ~11.0s
fetchMintsFromFollows(custom npub) 13 recommendations, ~10.9s never settles 13 recommendations, ~10.8s
fetchReviewerProfiles() 4 profiles never reached 4 profiles
invalid npub guard [] + "Invalid npub format" unchanged [] + "Invalid npub format"
relay pool size 8 43 8

Top recommended mints come back identical and in the same order before and after (mint.cashu.chat(7), mint.minibits.cash/Bitcoin(5), mint.coinos.io(3) for Discover Mints).

Note that CI is blind to all of this: tsc passes against 3.0.3, and stores/CashuStore.test.ts does jest.mock('@nostr-dev-kit/ndk', () => ({})).

This pull request is categorized as a:

  • New feature
  • Bug fix
  • Code refactor
  • Configuration change
  • Locales update
  • Quality assurance
  • Other

Checklist

  • I’ve run yarn run tsc and made sure my code compiles correctly
  • I’ve run yarn run lint and made sure my code didn’t contain any problematic patterns
  • I’ve run yarn run prettier and made sure my code is formatted correctly
  • I’ve run yarn run test and made sure all of the tests pass

Testing

If you modified or added a utility file, did you add new unit tests?

  • No, I’m a fool
  • Yes
  • N/A

No utility file was modified. stores/CashuStore.test.ts mocks NDK out entirely, so a unit test cannot cover this; verification was done against live relays on device, as tabulated above.

I have tested this PR on the following platforms (please specify OS version and phone model/VM):

  • Android
  • iOS (iPhone 17 Pro simulator, iOS 26.5)

Android run still owed.

I have tested this PR with the following types of nodes (please specify node version and API version where appropriate):

On-device

  • LDK Node
  • Embedded LND

Remote

  • LND (REST)
  • LND (Lightning Node Connect)
  • Core Lightning (CLNRest)
  • Nostr Wallet Connect
  • LndHub

The affected code path is Cashu mint discovery over nostr relays, which does not talk to the Lightning backend, so no backend-specific behavior is exercised here.

Locales

  • I’ve added new locale text that requires translations
  • I’m aware that new translations should be made on the ZEUS Transfix page and not directly to this repo

Third Party Dependencies and Packages

  • Contributors will need to run yarn after this PR is merged in
  • 3rd party dependencies have been modified:
    • verify that package.json and yarn.lock have been properly updated
    • verify that dependencies are installed for both iOS and Android platforms

yarn.lock also picks up shiki and sandpack, which NDK 3 declares as runtime dependencies (a docs-tooling leak upstream). Its dist never imports them, so this is node_modules bloat only and they stay out of the bundle; confirmed by bundling for iOS.

Other:

  • Changes were made that require an update to the README
  • Changes were made that require an update to onboarding

@github-actions

github-actions Bot commented Sep 22, 2026

Copy link
Copy Markdown

Test coverage

Metric Coverage Covered/Total vs master
Statements 42.77% 6051/14145 n/a
Branches 39.38% 3522/8942 n/a
Functions 31.66% 799/2523 n/a
Lines 43.22% 5792/13401 n/a

Commit: 5fc09b6 | Test run

@kaloudis kaloudis added Dependencies Pull requests that update a dependency file Nostr labels Sep 22, 2026
@kaloudis
kaloudis requested a review from ajaysehwal September 22, 2026 05:07
@kaloudis kaloudis added this to the v13.2.3 milestone Sep 22, 2026
NDK 3 changes two defaults that between them break Cashu mint discovery.

NDKPool.connect() now resolves only once every relay reports CONNECTED,
racing that against a timeout promise that is never created when no
timeout argument is passed. DEFAULT_NOSTR_RELAYS is never fully
reachable in practice (nostr.land sits in AUTH_REQUIRED, others are
often down), so `await ndk.connect()` never returns and Discover Mints
spins forever with no error surfaced. Pass an explicit connect timeout.

The outbox model also flipped from opt-in to on by default. Mint
discovery subscribes with hundreds of authors, and outbox tracking
resolves each author's relay list and reconnects the subscription as
those lists arrive, growing the pool past 40 relays and starving the JS
thread: a 10 second collection timer fired after 94 seconds. Opt out to
keep the 2.x behavior.

Verified on device against live relays that mint discovery, trusted
mints from both the ZEUS npub and a custom npub, and reviewer profile
lookups all return the same results in the same time as 2.13.0-rc2.
@kaloudis
kaloudis force-pushed the fix/ndk-3-mint-discovery branch from 4b5ae85 to 5fc09b6 Compare September 22, 2026 14:34

This branch has not been deployed

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

Labels

Dependencies Pull requests that update a dependency file Nostr

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant