move the wallet's chain source out of env and into the ui

WALLET_ESPLORA_URL was the one wallet setting an owner actually has to change — off a
public explorer that rate-limits and sees every address, onto their own indexer — and it
was the one they could only change with a shell and a restart. It now lives in
service_connections under 'esplora' and is edited at Wallet -> Settings -> Chain source,
probed against /blocks/tip/height before it is stored.

The URL joins the backend fingerprint, so re-pointing rebuilds every on-chain backend and
drops the gap-limit scan taken through the old endpoint. /_health probes what the wallets
actually use rather than the built-in default, and /_officer/config no longer reports a URL
it cannot know.

Also two receive-screen defects the Blockstream 429 exposed: a query error rendered as
"No address available", and the "new address" button called refetch() on the ?peek=true
query, so it re-fetched the same address instead of advancing the index.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-03 22:59:00 +00:00
co-authored by Claude Opus 5
parent f45bc9292b
commit ff73e86983
13 changed files with 396 additions and 41 deletions
+7 -2
View File
@@ -116,12 +116,17 @@ export async function handleOfficerRoute(req: Request, url: URL): Promise<Respon
}
}
/** Non-secret deployment facts the UI needs before any wallet exists. */
/**
* Non-secret deployment facts the UI needs before any wallet exists.
*
* No esplora URL: that is per-owner now and lives at `/_config`, which is also the only place that can
* say whether it is the owner's endpoint or the fallback. Reporting the default here would have shown
* the wrong URL to anyone who had set their own.
*/
function handleConfig(): Response {
const cfg = getConfig();
return json({
network: cfg.network,
esploraUrl: cfg.esploraUrl,
unlockTtlSec: cfg.unlockTtlSec,
// The UI blocks wallet creation on this rather than letting the first write fail on a crypto error.
storeKeyConfigured: hasStoreKey(),