Hide the wallet interface dropdown once an LDK Node wallet has been
initialized, matching the existing behavior for Embedded LND wallets
with an admin macaroon. Show a read-only, localized Network label in
its place, as Embedded LND does.
Use the Screen component for the themed gradient background, add
horizontal margins around the duress PIN explanation text, and match
SetPin's heading offset.
When the Lockscreen was opened from Security settings to delete or
change a PIN or password, entering duress credentials still triggered
deleteNodes() and wiped all wallet configurations. Duress credentials
now count as an incorrect entry in these flows and only trigger the
wipe on a genuine login attempt.
Also clarify the prompts in the delete duress flows so users know the
login credential is expected, not the duress one.
Fixes#3725
pbts emits proto/lightning.d.ts unformatted, which then fails the
prettier check since it globs **/*.ts*. Format it as part of gen-proto
so regenerating bindings doesn't require a manual fixup pass.
proto/lightning.js is left as pbjs emits it - it isn't covered by the
prettier check.
Addresses two high-severity Dependabot alerts:
- shell-quote <= 1.8.4 (GHSA-395f-4hp3-45gv, quadratic parse() DoS):
bump concurrently to 10.0.4 (pins shell-quote 1.9.0) and refresh the
remaining lockfile entries to 1.10.0. Closes alert #377.
- brace-expansion <= 5.0.7 (GHSA-mh99-v99m-4gvg, OOM crash via chained
brace groups): only 5.0.8 (ESM-only) is patched, so the CJS
minimatch@3/@5 chains must stay on 1.1.16/2.1.2 for now. Remove the
global minimatch/brace-expansion resolutions, which were forcing
minimatch ^5/^10 requests (protobufjs-cli -> glob@8,
react-native-blob-util -> glob@13, and
@typescript-eslint/typescript-estree) down to 3.1.5/1.1.16 and
orphaning the scoped react-native-blob-util/* pins (they never
matched: the chain runs through glob, not a direct dep). Each
minimatch major now resolves its proper brace-expansion line,
including the patched 5.0.8 for the ^5.0.5 range.
All affected packages are dev/build tooling; nothing ships in the app
bundle. Alert #388 remains open on brace-expansion 1.1.16/2.1.2 until
upstream backports land.
The module's 'mocha --reporter spec' test script has been dead
scaffolding since the beginning - upstream lightninglabs/lnc-rn never
shipped a test directory - so yarn test always failed with 'No test
files found'.
Add a suite for the parts of lib/ that run in plain Node (lnc.ts needs
react-native and is exercised through the app):
- api/createRpc: unary calls route to lnc.request with capitalized
method names; every entry in lnc-core's subscriptionMethods routes
to lnc.subscribe
- util/credentialStore: field storage, isPaired logic, clear()
- util/log: level filtering, prefix naming, fromEnv no-op default
Wiring notes:
- .mocharc.yml requires ts-node/register/transpile-only so no
@types/mocha or @types/chai devDependencies are needed
- the spec pattern avoids ** because the minimatch 9 resolution pin
makes mocha's bundled glob 7 crash on globstar (GLOBSTAR is a Symbol
in minimatch 4+)
- root jest gains 'zeus_modules' in testPathIgnorePatterns: its
crawler only skips node_modules, so it would otherwise collect these
mocha tests into the app's jest run
The lnc-rn prepare step (bob build) failed its typescript target on
every yarn install inside the module: tsc's automatic @types inclusion
walks up parent node_modules, so the vendored copy picked up the zeus
root's @types/lodash, whose 'infer N extends number' syntax the
package's pinned TypeScript 4.5.5 cannot parse (TS1005). Upstream
lnc-rn never hits this because it is not nested inside another repo.
Fix: restrict typeRoots to the package's own node_modules/@types.
Also commit the dist/ output regenerated by the pinned toolchain so
prepare is idempotent and installs leave a clean tree:
- dist/typescript is byte-identical, so the type surface zeus's tsc
consumes is unchanged
- dist/commonjs and dist/module drift is babel class-property lowering
(previous committed copy kept class-fields syntax); zeus never runs
these files - Metro resolves the react-native field to lib/ source
- dist/commonjs/package.json ({"type":"commonjs"}) is dropped: bob
0.18.3 does not emit it and the package has no "type" field, so CJS
is already the default
Root:
- bump brace-expansion resolutions for GHSA-3jxr-9vmj-r5cp: blanket
pin 1.1.13 -> 1.1.16, protobufjs-cli scope 2.0.3 -> 2.1.2; add
react-native-blob-util/brace-expansion 5.0.8 so the minimatch 10 /
glob 13 subtree gets the only patched line for GHSA-mh99-v99m-4gvg
- re-resolve the stale ws@^6.2.3 lockfile entry 6.2.3 -> 6.2.6 for
GHSA-96hv-2xvq-fx4p (dev-only, @react-native-community/cli-server-api)
zeus_modules/@lightninglabs/lnc-rn (vendored; dev tooling only, none
of this is bundled into the app):
- js-yaml 3.14.1 -> 3.15.0 and 4.1.0 -> 4.3.0 (via mocha/js-yaml
resolution) for GHSA-52cp-r559-cp3m and GHSA-h67p-54hq-rp68
- ws 6.2.3 -> 6.2.6 and 7.5.10 -> 7.5.13 for GHSA-96hv-2xvq-fx4p
Applies lightninglabs/lnc-rn#45 to the vendored copy in zeus_modules:
- add eslint.config.mjs (flat config, eslint v9 + typescript-eslint v8)
translating the previous tslint.json rule set
- swap tslint/tslint-config-prettier devDependencies for @eslint/js,
eslint, eslint-config-prettier, globals and typescript-eslint;
lint script is now 'eslint lib'
- drop unused Proxy handler params in lib/api/createRpc.ts and the
unused catch binding in lib/lnc.ts, mirrored into the prebuilt dist/
- regenerate the module's local yarn.lock
No runtime behavior change. The root package.json and yarn.lock are
untouched, so contributors do not need to re-run yarn.
protobufjs v8 reads TextDecoder at import time, and Hermes does not
provide it. The polyfill assignment in index.js ran after hoisted
imports, so the app crashed on launch with 'Property TextDecoder
doesn't exist'. Move the polyfills into their own module imported
first so they are installed before any other module executes.
Upgrades the protobuf toolchain and runtime together, as they are
version-coupled (protobufjs-cli 2.5.x peer-requires protobufjs ^8.6):
- protobufjs 7.6.5 -> 8.7.1 (runtime; v8's only breaking change is
Edition 2024 descriptor support - LND protos are proto3 and the
runtime APIs Zeus uses, util.Long/configure/Writer/Reader, are
unchanged)
- protobufjs-cli 2.0.0 -> 2.5.1 (dev; supersedes #4257, which would
have created a peer mismatch against the 7.x runtime)
- long 5.2.3 -> 5.3.2 (protobufjs 8 requires ^5.3.2; keeping the
direct dep in lockstep avoids two hoisted Long classes and
instanceof mismatches in the Long wiring in index.js)
- gen-proto: add -p proto so pbjs can resolve import "lightning.proto"
from the rpc subdirectory protos; the script failed with ENOENT
without it (on both old and new CLI versions)
- proto/lightning.js + lightning.d.ts regenerated with the new
toolchain (v8-era codegen: unknown-field preservation, recursion
depth guards); d.ts formatted with the repo prettier config
Slimmed-down version of #4247 (dependabot minor-and-patch group),
excluding the React Native 0.86 upgrade train and one breaking bump:
- react-native, @react-native/*, @react-native-community/cli,
@types/react, react-native-reanimated, react-native-worklets:
kept at 0.85.3-era versions; RN 0.86 should land as its own PR
(@react-native/jest-preset is an exact-version peer dep of RN,
and the @types/react bump caused the tsc failures on #4247)
- js-lnurl kept at 0.5.1: 0.6.0 removes the decipherAES export
used by views/LnurlPay/Success.tsx and needs a migration PR
- events, mobx, concurrently, protobufjs-cli omitted: already
bumped on master via #4248/#4253/#4251/#4252
Also bumps the six remaining @typescript-eslint/* resolution pins
to 8.65.0 so they stay consistent with eslint-plugin/parser
(dependabot left them at 8.59.3).
Previously a rejected /proposal call cleared the LSP's error message
entirely, so users saw a plain unwrapped invoice with no indication
the LSP declined to wrap it (e.g. channel opens frozen around a
reorg-risk block range).
On LND REST, closeChannel is a streaming endpoint whose HTTP response
stays open until the closing tx confirms. ChannelsStore.closeChannel
force-resolves after 6 seconds and the user returns to a repopulated
channel list, but the underlying request's handlers were never
detached. When the generic 30-second REST timeout rejected the still-
pending call, handleChannelCloseError ran getChannelsError(), setting
channels = [] and blanking the open channels list until the next
refetch.
Fix in two parts:
- share the settled flag in both directions so the real call's late
then/catch handlers no-op once the forced resolution has fired
- stop calling getChannelsError() from handleChannelCloseError; a
failed close request doesn't invalidate the channel list, so only
set closeChannelErr and clear closingChannel
Fixes#4229
The knob locked permanently after a successful swipe, so if the send
failed and the user navigated back to retry, it was stuck at the right.
Reset it when the screen regains focus.
lnd recreates a missing edge with max_htlc 0 while presetting the
required-max-htlc message flag, so its keep-current-value path leaves 0
in place and a blank max_htlc_msat always fails validation with
'min_htlc 1000 mSAT greater than max_htlc 0 mSAT'.
Pass each channel's local_constraints.max_pending_amt_msat through the
sub-item list and use it as max_htlc_msat when create_missing_edge is
enabled and the field is left blank - the same value lnd's own
on-the-fly migration would pick. Explicit values still win, and with
the toggle off, blank continues to mean 'keep current' like lncli.
The initialStart clause was self-defeating: any connecting fetchData run
sets initialStart to false ~30 lines earlier, so the condition could
never block by the time it was evaluated. The invariant it aimed for -
don't consume the initial deep link before startup wallet selection -
is now enforced by the _replacedForWalletSelection gate and the
once-only URL tracking in LinkingUtils.
When 'Select wallet on start-up' is enabled, the Wallet view is replaced
by the wallet selection screen and later re-created, so more than one
instance can consume Linking.getInitialURL() - each with its own fresh
initialLoad state - loading the same invoice twice. A late focus or
AppState trigger on the replaced instance could also fall through to
fetchData (initialStart was already false by then), connecting to the
previously selected wallet in the background and opening the deep link
over the wallet picker.
- track the last handled URL in the LinkingUtils singleton and skip it
in handleInitialUrl, so the initial URL is only ever processed once,
regardless of how many Wallet instances mount. This also covers
Android's onNewIntent + setIntent behavior, which makes
getInitialURL() return the most recent warm deep link on every
subsequent call. Deliberate re-taps of the same link still work, as
the 'url' event path bypasses the check
- gate getSettingsAndNavigate once the instance has replaced itself
with the startup wallet selection screen
- store the Linking 'url' subscription, remove any prior one before
re-registering, and clean it up on unmount so a stale instance can't
keep handling warm deep links alongside the live one
Fixes#4218
The PaymentRequest view rendered the decoded expiry as raw seconds
(e.g. 3600) and cltv_expiry as a bare number. Display the expiry as a
humanized duration via the Invoice model's existing formatter, and
append the blocks unit to CLTV expiry on both the PaymentRequest and
Invoice views.
The model's originalTimeUntilExpiryInSeconds only worked when a bolt11
string was available to decode, but pay_req is built from a backend
decodepayreq response that carries no bolt11 string. Fall back to the
raw expiry/expires_at fields in that case.
Previously the pan responder stayed fully active after a successful
swipe, and any new touch on the knob reset the pan value to 0 while
navigation to the sending screen was still pending, making the button
visibly pop back to the left before the transition. The offset state
was also captured in a stale closure (always 0), and the success
animation was a JS-driven spring started after the payment work, so it
could be starved by the JS thread and leave the knob short of the
right edge.
Pin the knob at the end position synchronously on success, ignore
further responder grants once completed, drop the broken offset
accumulation, and spring back on responder termination.
Adds an updateChannelPolicy command to the LND Developer Tools,
mirroring lncli updatechanpolicy: base_fee_msat, fee_rate_ppm,
time_lock_delta, and min/max_htlc_msat inputs, a create_missing_edge
toggle, and a global or per-channel target picker.
Backed by a raw PolicyUpdateRequest passthrough on lnd (REST),
embedded-lnd (new lndmobile binding + iOS dispatch table entry), and
lightning-node-connect, kept separate from the production setFees
flow so units and inbound-fee handling there are untouched.
Adds scheduled weekly version-update PRs for the root npm manifest and
the GitHub Actions used by CI. Minor/patch npm bumps are grouped into a
single PR to keep noise down across the large dependency tree; major
bumps get their own PRs so native / crypto-sensitive upgrades can be
reviewed and tested in isolation.
Security updates were already enabled at the repo level (Dependabot
already opens security PRs across all manifests, including the vendored
zeus_modules sublocks); this adds routine version bumps on top.
Closes five Dependabot alerts in the root manifest:
- ws 8.20.1 -> 8.21.0 memory-exhaustion DoS (high) #343
- ws 7.5.10 -> 7.5.11 memory-exhaustion DoS (high) #342
- js-yaml 4.1.1 -> 4.3.0 quadratic DoS (medium) #362
- js-yaml 3.14.2 -> 3.15.0 quadratic DoS (medium) #363
- markdown-it 14.1.1 -> 14.2.0 quadratic DoS (medium) #349
ws (v8): the vulnerable copy was pinned by engine.io-client@6.6.5 via
ws ~8.20.1. Refreshing engine.io-client to 6.6.6 (within its existing
~6.6.1 range) naturally pulls the patched ws ~8.21.0 -> 8.21.0, so no
resolution override was needed.
ws (v7) and both js-yaml copies: existing ranges already permitted the
patched versions; fixed by refreshing the lockfile.
markdown-it: was explicitly pinned to the vulnerable 14.1.1 in
resolutions; bumped that entry to 14.2.0.
Lockfile-only re-resolution (yarn install --ignore-scripts); no source
changes.
Adds 16 project skills (plus 3 runnable diagnostic scripts) that encode
the project's architecture contracts, backend capability matrix, storage
and migration protocols, build/run/debug runbooks, failure archaeology,
Lightning domain reference, and research discipline, so contributors and
AI coding sessions can operate at maintainer standard without rederiving
project knowledge.
All facts were verified against master c5fd094fb and adversarially
reviewed (factual/doctrine/usability passes) before inclusion. Also
updates .gitignore to share .claude/skills/ while keeping all other
.claude/ files (e.g. settings.local.json) local.
Resolves#4178. Before v13.1.0 the Tor path always trusted self-signed
certificates because the old react-native-tor library defaulted
trustSSL=true. react-native-nitro-tor 0.5.3 had no such knob — TLS was
strict, so users connecting to their own LND/CLN node over a hidden
service (the default LND REST + self-signed cert setup) regressed on
upgrade.
This PR plumbs a trust_invalid_certs field through doTorRequest and
hardcodes it to true on the Tor branch in backends/LND.ts and
backends/CLNRest.ts. The certVerification setting is intentionally
ignored over Tor: the .onion address authenticates the endpoint at the
Tor protocol layer, and the upstream daemon's self-signed cert can
never match an .onion hostname, so TLS validation here is a category
error. The wallet config UI already hides the certVerification toggle
when Tor is enabled, so this matches the user-visible model.
The other doTorRequest callers (utils/handleAnything.ts,
stores/SettingsStore.ts, components/LayerBalances/LightningSwipeableRow.tsx)
keep the strict default — they talk to public third-party services
(lnurl resolution, Olympus, Zeus servers), not user-owned nodes.
Schema/Rust support landed upstream in:
- niteshbalusu11/tor-rust-sdk#4
- niteshbalusu11/react-native-nitro-tor#10
Picks up the matching react-native-nitro-tor 0.6.0 release.