split the wallet's chain reads from its signing half
OnchainBackend depended on the concrete EsploraChain class, so the only wallet it could ever have was an Esplora-backed one. The seam is now WalletChainSource, and it is drawn at the scan rather than at the HTTP client: Esplora is address-level and has to walk the gap limit, NBXplorer is wallet-level and has no per-address endpoint at all, so there is nothing to share one level down. The backend keeps the keys and the money — derivation, snapshot cache, coin selection, PSBT construction, signing — and owns no HTTP. Which indexer answers is a constructor argument. Also adds the NBXplorer implementation of the seam, verified end to end against the owner's own pruned node, and the first tests over any of this: a stub Esplora drives a real backend through the gap-limit walk, balance summation, UTXO mapping, transaction scoring and address issuance. Nothing covered the scan before it was moved, which is the wrong time to have no tests. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
||||
type WalletSummary,
|
||||
} from 'officerdb';
|
||||
import { EsploraChain } from './chain';
|
||||
import { EsploraChainSource } from './chain-source-esplora';
|
||||
import { LndBackend } from './backends/lnd';
|
||||
import { ClnRestBackend } from './backends/clnrest';
|
||||
import { LndHubBackend } from './backends/lndhub';
|
||||
@@ -127,7 +128,10 @@ function build(wallet: WalletSummary, config: Record<string, unknown> | null, es
|
||||
throw new BackendError('wallet has no account xpubs', 500, 'BAD_CONFIG');
|
||||
}
|
||||
return new OnchainBackend({
|
||||
chain: new EsploraChain({ baseUrl: esploraUrl, network }),
|
||||
chain: new EsploraChainSource({
|
||||
chain: new EsploraChain({ baseUrl: esploraUrl, network }),
|
||||
label: `esplora(${hostOf(esploraUrl)})`,
|
||||
}),
|
||||
network,
|
||||
accountXpub,
|
||||
// The session is the signer. While locked it holds no key material, so watch-only reads below
|
||||
@@ -141,3 +145,12 @@ function build(wallet: WalletSummary, config: Record<string, unknown> | null, es
|
||||
throw new BackendError(`unknown wallet kind "${wallet.kind}"`, 400, 'BAD_CONFIG');
|
||||
}
|
||||
}
|
||||
|
||||
/** Host only, for a chain-source label. A malformed URL is labelled with itself rather than throwing. */
|
||||
function hostOf(url: string): string {
|
||||
try {
|
||||
return new URL(url).host;
|
||||
} catch {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user