add an nbxplorer client to the wallet sidecar

The second chain source. Esplora is address-level, so finding a wallet's coins means
walking the gap limit ourselves — 43-160 requests per refresh. NBXplorer is scheme-level:
register the account xpub once and every question after that is a single call. So this is
deliberately NOT an implementation of EsploraChain's interface; there is no per-address
query worth emulating, and emulating one would throw the advantage away.

Verified end to end against the owner's live 2.6.9 instance: status, track, balance,
utxos, transactions, unused address and fee estimates all round-trip, and NBXplorer
derives bc1qwnvlm8... for BIP84 0/0 — byte-identical to what keys.ts derives.

Three things the upstream docs get wrong or leave out, all confirmed by hand:
  - single-sig taproot is `-[taproot]`, absent from NBXplorer's own scheme table
  - querying an UNTRACKED scheme returns 200 with every figure zeroed, which reads as a
    real empty wallet; track() is therefore on every read path, not just at setup
  - a rejected broadcast returns 200 with success:false, never an HTTP error

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-03 23:31:55 +00:00
co-authored by Claude Opus 5
parent ff73e86983
commit 2d71424d5a
2 changed files with 307 additions and 1 deletions
@@ -13,7 +13,7 @@ import { encryptSecret, decryptSecret } from '../crypto';
// moment someone forgot to strip it.
/** The services that keep a connection here. Extending it is a one-line change, not a migration. */
export type ServiceName = 'transmission' | 'slskd' | 'esplora';
export type ServiceName = 'transmission' | 'slskd' | 'esplora' | 'nbxplorer';
export type ServiceConnection = {
id: number;