@cogcoin/client 1.1.9 → 1.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/README.md +1 -1
  2. package/dist/bitcoind/managed-bitcoind-service-config.d.ts +13 -0
  3. package/dist/bitcoind/managed-bitcoind-service-config.js +165 -0
  4. package/dist/bitcoind/managed-bitcoind-service-lifecycle.d.ts +28 -0
  5. package/dist/bitcoind/managed-bitcoind-service-lifecycle.js +290 -0
  6. package/dist/bitcoind/managed-bitcoind-service-process.d.ts +8 -0
  7. package/dist/bitcoind/managed-bitcoind-service-process.js +48 -0
  8. package/dist/bitcoind/managed-bitcoind-service-replica.d.ts +8 -0
  9. package/dist/bitcoind/managed-bitcoind-service-replica.js +142 -0
  10. package/dist/bitcoind/managed-bitcoind-service-status.d.ts +42 -0
  11. package/dist/bitcoind/managed-bitcoind-service-status.js +178 -0
  12. package/dist/bitcoind/managed-bitcoind-service-types.d.ts +36 -0
  13. package/dist/bitcoind/managed-bitcoind-service-types.js +1 -0
  14. package/dist/bitcoind/service.d.ts +7 -63
  15. package/dist/bitcoind/service.js +7 -797
  16. package/dist/wallet/mining/engine-types.d.ts +1 -0
  17. package/dist/wallet/mining/engine-types.js +9 -1
  18. package/dist/wallet/mining/publish.js +3 -6
  19. package/dist/wallet/mining/runner.js +30 -18
  20. package/dist/wallet/mining/visualizer.js +7 -6
  21. package/dist/wallet/read/context.d.ts +4 -10
  22. package/dist/wallet/read/context.js +4 -227
  23. package/dist/wallet/read/local-state.d.ts +28 -0
  24. package/dist/wallet/read/local-state.js +233 -0
  25. package/dist/wallet/read/managed-bitcoind.d.ts +30 -0
  26. package/dist/wallet/read/managed-bitcoind.js +138 -0
  27. package/dist/wallet/read/managed-indexer.d.ts +23 -0
  28. package/dist/wallet/read/managed-indexer.js +87 -0
  29. package/dist/wallet/read/managed-services.d.ts +6 -21
  30. package/dist/wallet/read/managed-services.js +23 -196
  31. package/package.json +1 -1
@@ -88,6 +88,7 @@ export type ReadyMiningReadContext = WalletReadContext & {
88
88
  snapshot: NonNullable<WalletReadContext["snapshot"]>;
89
89
  model: NonNullable<WalletReadContext["model"]>;
90
90
  };
91
+ export declare function resolveReadyMiningReadContext(readContext: WalletReadContext): ReadyMiningReadContext | null;
91
92
  export interface MiningPublishSkipResult {
92
93
  state: WalletStateV1;
93
94
  txid: null;
@@ -1 +1,9 @@
1
- export {};
1
+ export function resolveReadyMiningReadContext(readContext) {
2
+ if (readContext.localState.availability !== "ready"
3
+ || readContext.localState.state === null
4
+ || readContext.snapshot === null
5
+ || readContext.model === null) {
6
+ return null;
7
+ }
8
+ return readContext;
9
+ }
@@ -6,7 +6,7 @@ import { serializeMine } from "../cogop/index.js";
6
6
  import { openWalletReadContext } from "../read/index.js";
7
7
  import { assertFixedInputPrefixMatches, buildWalletMutationTransaction, fundAndValidateWalletMutationDraft, isAlreadyAcceptedError, isBroadcastUnknownError, isInsufficientFundsError, outpointKey as walletMutationOutpointKey, reconcilePersistentPolicyLocks, resolveWalletMutationFeeSelection, saveWalletStatePreservingUnlock, } from "../tx/common.js";
8
8
  import { createMiningEventRecord } from "./events.js";
9
- import {} from "./engine-types.js";
9
+ import { resolveReadyMiningReadContext, } from "./engine-types.js";
10
10
  import { cloneMiningState, defaultMiningStatePatch, livePublishTargetsCandidateTip, miningCandidateIsCurrent, resolveSharedMiningConflictOutpoint, } from "./engine-state.js";
11
11
  import { deriveMiningWordIndices, numberToSats, resolveBip39WordsFromIndices, } from "./engine-utils.js";
12
12
  import { clearMiningPublishState, miningPublishMayStillExist, } from "./state.js";
@@ -576,13 +576,10 @@ export async function publishCandidate(options) {
576
576
  });
577
577
  try {
578
578
  options.throwIfStopping?.();
579
- if (lockedReadContext.localState.availability !== "ready"
580
- || lockedReadContext.localState.state === null
581
- || lockedReadContext.snapshot === null
582
- || lockedReadContext.model === null) {
579
+ const readyReadContext = resolveReadyMiningReadContext(lockedReadContext);
580
+ if (readyReadContext === null) {
583
581
  return await createStaleCandidateSkipResult(options.fallbackState);
584
582
  }
585
- const readyReadContext = lockedReadContext;
586
583
  const refreshedCandidate = refreshMiningCandidateFromCurrentState(readyReadContext, options.candidate);
587
584
  if (refreshedCandidate === null) {
588
585
  return await createStaleCandidateSkipResult(readyReadContext.localState.state);
@@ -27,6 +27,7 @@ import { createInsufficientFundsMiningPublishErrorMessage as createInsufficientF
27
27
  import { runMiningPhaseMachine } from "./cycle.js";
28
28
  import { attemptSaveMempool, handleDetectedMiningRuntimeResume, handleRecoverableMiningBitcoindFailure, isRecoverableMiningBitcoindError, refreshAndSaveMiningRuntimeStatus, resetMiningBitcoindRecoveryState, saveStopSnapshot, } from "./lifecycle.js";
29
29
  import { compareLexicographically, deriveMiningWordIndices, getBlockRewardCogtoshi, numberToSats, resolveBip39WordsFromIndices, rootDomain, tieBreakHash, } from "./engine-utils.js";
30
+ import { resolveReadyMiningReadContext } from "./engine-types.js";
30
31
  import { isMiningGenerationAbortRequested, markMiningGenerationActive, markMiningGenerationInactive, readMiningGenerationActivity, readMiningPreemptionRequest, requestMiningGenerationPreemption, } from "./coordination.js";
31
32
  import { clearMiningPublishState, miningPublishIsInMempool, miningPublishMayStillExist, normalizeMiningPublishState, normalizeMiningStateRecord, } from "./state.js";
32
33
  import { runForegroundMining as runForegroundMiningSupervisor, } from "./supervisor.js";
@@ -292,9 +293,20 @@ async function performMiningCycle(options) {
292
293
  }
293
294
  const displaySats = await resolveFundingDisplaySats(effectiveReadContext.localState.state, rpc).catch(() => null);
294
295
  syncMiningVisualizerBalances(options.loopState, effectiveReadContext, displaySats);
295
- if (effectiveReadContext.localState.state.miningState.state === "repair-required") {
296
+ const readyReadContext = resolveReadyMiningReadContext(effectiveReadContext);
297
+ if (readyReadContext === null) {
296
298
  clearMiningProviderWait(options.loopState);
297
299
  await saveCycleStatus(effectiveReadContext, {
300
+ runMode: options.runMode,
301
+ currentPhase: "waiting-indexer",
302
+ lastError: null,
303
+ note: "Mining is waiting for Bitcoin Core and the indexer to align.",
304
+ });
305
+ return;
306
+ }
307
+ if (readyReadContext.localState.state.miningState.state === "repair-required") {
308
+ clearMiningProviderWait(options.loopState);
309
+ await saveCycleStatus(readyReadContext, {
298
310
  runMode: options.runMode,
299
311
  currentPhase: "waiting",
300
312
  lastError: null,
@@ -302,9 +314,9 @@ async function performMiningCycle(options) {
302
314
  });
303
315
  return;
304
316
  }
305
- if (hasBlockingMutation(effectiveReadContext.localState.state)) {
317
+ if (hasBlockingMutation(readyReadContext.localState.state)) {
306
318
  clearMiningProviderWait(options.loopState);
307
- const nextState = defaultMiningStatePatch(effectiveReadContext.localState.state, {
319
+ const nextState = defaultMiningStatePatch(readyReadContext.localState.state, {
308
320
  state: "paused",
309
321
  pauseReason: "wallet-busy",
310
322
  });
@@ -313,15 +325,15 @@ async function performMiningCycle(options) {
313
325
  provider: options.provider,
314
326
  paths: options.paths,
315
327
  });
316
- effectiveReadContext = {
317
- ...effectiveReadContext,
328
+ const blockedReadContext = {
329
+ ...readyReadContext,
318
330
  localState: {
319
- ...effectiveReadContext.localState,
331
+ ...readyReadContext.localState,
320
332
  availability: "ready",
321
333
  state: nextState,
322
334
  },
323
335
  };
324
- await saveCycleStatus(effectiveReadContext, {
336
+ await saveCycleStatus(blockedReadContext, {
325
337
  runMode: options.runMode,
326
338
  currentPhase: "waiting",
327
339
  lastError: null,
@@ -332,9 +344,9 @@ async function performMiningCycle(options) {
332
344
  const preemptionRequest = await readMiningPreemptionRequest(options.paths);
333
345
  if (preemptionRequest !== null) {
334
346
  clearMiningProviderWait(options.loopState);
335
- const nextState = defaultMiningStatePatch(effectiveReadContext.localState.state, {
336
- state: effectiveReadContext.localState.state.miningState.livePublishInMempool
337
- && effectiveReadContext.localState.state.miningState.state === "paused-stale"
347
+ const nextState = defaultMiningStatePatch(readyReadContext.localState.state, {
348
+ state: readyReadContext.localState.state.miningState.livePublishInMempool
349
+ && readyReadContext.localState.state.miningState.state === "paused-stale"
338
350
  ? "paused-stale"
339
351
  : "paused",
340
352
  pauseReason: preemptionRequest.reason,
@@ -345,9 +357,9 @@ async function performMiningCycle(options) {
345
357
  paths: options.paths,
346
358
  });
347
359
  await saveCycleStatus({
348
- ...effectiveReadContext,
360
+ ...readyReadContext,
349
361
  localState: {
350
- ...effectiveReadContext.localState,
362
+ ...readyReadContext.localState,
351
363
  state: nextState,
352
364
  },
353
365
  }, {
@@ -370,10 +382,10 @@ async function performMiningCycle(options) {
370
382
  network: networkInfo,
371
383
  mempool: mempoolInfo,
372
384
  });
373
- clearRecoveredBitcoindError = resetMiningBitcoindRecoveryState(options.loopState, effectiveReadContext.nodeStatus?.serviceStatus ?? { pid: service.pid });
385
+ clearRecoveredBitcoindError = resetMiningBitcoindRecoveryState(options.loopState, readyReadContext.nodeStatus?.serviceStatus ?? { pid: service.pid });
374
386
  if (targetBlockHeight !== null && getBlockRewardCogtoshi(targetBlockHeight) === 0n) {
375
387
  clearMiningProviderWait(options.loopState);
376
- const nextState = defaultMiningStatePatch(effectiveReadContext.localState.state, {
388
+ const nextState = defaultMiningStatePatch(readyReadContext.localState.state, {
377
389
  state: "paused",
378
390
  pauseReason: "zero-reward",
379
391
  });
@@ -383,9 +395,9 @@ async function performMiningCycle(options) {
383
395
  paths: options.paths,
384
396
  });
385
397
  await saveCycleStatus({
386
- ...effectiveReadContext,
398
+ ...readyReadContext,
387
399
  localState: {
388
- ...effectiveReadContext.localState,
400
+ ...readyReadContext.localState,
389
401
  state: nextState,
390
402
  },
391
403
  }, {
@@ -397,7 +409,7 @@ async function performMiningCycle(options) {
397
409
  });
398
410
  await appendEvent(options.paths, createEvent("publish-skipped-zero-reward", "Skipped mining because the target block reward is zero.", {
399
411
  targetBlockHeight,
400
- referencedBlockHashDisplay: effectiveReadContext.nodeStatus?.nodeBestHashHex ?? null,
412
+ referencedBlockHashDisplay: readyReadContext.nodeStatus?.nodeBestHashHex ?? null,
401
413
  runId: options.backgroundWorkerRunId,
402
414
  }));
403
415
  return;
@@ -409,7 +421,7 @@ async function performMiningCycle(options) {
409
421
  paths: options.paths,
410
422
  runMode: options.runMode,
411
423
  backgroundWorkerRunId: options.backgroundWorkerRunId,
412
- readContext: effectiveReadContext,
424
+ readContext: readyReadContext,
413
425
  rpc,
414
426
  targetBlockHeight,
415
427
  tipKey,
@@ -64,9 +64,6 @@ function formatRewardCogAmount(value) {
64
64
  minFractionDigits: 1,
65
65
  })} COG`;
66
66
  }
67
- function escapeRegExp(value) {
68
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
69
- }
70
67
  function consumeWrappedLine(text, capacity) {
71
68
  const remaining = text.trimStart();
72
69
  if (remaining.length <= capacity) {
@@ -91,12 +88,16 @@ function consumeWrappedLine(text, capacity) {
91
88
  function highlightRequiredWords(sentence, requiredWords) {
92
89
  const uniqueWords = [...new Set(requiredWords
93
90
  .map((word) => word.trim().toLowerCase())
94
- .filter((word) => word.length > 0))].sort((left, right) => right.length - left.length);
91
+ .filter((word) => word.length > 0))];
95
92
  if (uniqueWords.length === 0) {
96
93
  return sentence;
97
94
  }
98
- const pattern = new RegExp(`\\b(?:${uniqueWords.map(escapeRegExp).join("|")})\\b`, "gi");
99
- return sentence.replace(pattern, (match) => match.toUpperCase());
95
+ return sentence.replace(/[A-Za-z]+/g, (match) => {
96
+ const normalizedToken = match.toLowerCase();
97
+ return uniqueWords.some((word) => normalizedToken.includes(word))
98
+ ? match.toUpperCase()
99
+ : match;
100
+ });
100
101
  }
101
102
  function formatSentenceSlot(prefix, sentence, requiredWords, lineCount) {
102
103
  if (sentence === null) {
@@ -1,14 +1,8 @@
1
- import { readSnapshotWithRetry } from "../../bitcoind/indexer-daemon.js";
1
+ export { readSnapshotWithRetry, } from "../../bitcoind/indexer-daemon.js";
2
2
  import { type WalletSecretProvider } from "../state/provider.js";
3
- import type { WalletLocalStateStatus, WalletReadContext } from "./types.js";
3
+ import { inspectWalletLocalState } from "./local-state.js";
4
+ import type { WalletReadContext } from "./types.js";
4
5
  import type { WalletRuntimePaths } from "../runtime.js";
5
- declare function inspectWalletLocalState(options?: {
6
- dataDir?: string;
7
- secretProvider?: WalletSecretProvider;
8
- now?: number;
9
- paths?: WalletRuntimePaths;
10
- walletControlLockHeld?: boolean;
11
- }): Promise<WalletLocalStateStatus>;
12
6
  export declare function openWalletReadContext(options: {
13
7
  dataDir: string;
14
8
  databasePath: string;
@@ -19,4 +13,4 @@ export declare function openWalletReadContext(options: {
19
13
  now?: number;
20
14
  paths?: WalletRuntimePaths;
21
15
  }): Promise<WalletReadContext>;
22
- export { inspectWalletLocalState, readSnapshotWithRetry, };
16
+ export { inspectWalletLocalState, };
@@ -1,236 +1,13 @@
1
- import { access, constants } from "node:fs/promises";
2
1
  import { readPackageVersionFromDisk } from "../../package-version.js";
3
- import { readSnapshotWithRetry, } from "../../bitcoind/indexer-daemon.js";
4
- import { createRpcClient } from "../../bitcoind/node.js";
2
+ export { readSnapshotWithRetry, } from "../../bitcoind/indexer-daemon.js";
5
3
  import { UNINITIALIZED_WALLET_ROOT_ID } from "../../bitcoind/service-paths.js";
6
- import { attachOrStartManagedBitcoindService } from "../../bitcoind/service.js";
7
- import {} from "../../bitcoind/types.js";
8
- import { normalizeWalletStateRecord, persistWalletCoinControlStateIfNeeded } from "../coin-control.js";
9
- import { persistNormalizedWalletDescriptorStateIfNeeded } from "../descriptor-normalization.js";
10
4
  import { inspectMiningControlPlane } from "../mining/index.js";
11
- import { normalizeMiningStateRecord } from "../mining/state.js";
12
- import { resolveWalletRootIdFromLocalArtifacts } from "../root-resolution.js";
13
5
  import { resolveWalletRuntimePathsForTesting } from "../runtime.js";
14
- import { extractWalletRootIdHintFromWalletStateEnvelope, loadRawWalletStateEnvelope, loadWalletState, } from "../state/storage.js";
15
- import { createDefaultWalletSecretProvider, createWalletSecretReference, inspectClientPasswordSetupReadiness, } from "../state/provider.js";
16
- import { describeClientPasswordLockedMessage, describeClientPasswordMigrationMessage, describeClientPasswordSetupMessage, } from "../state/client-password.js";
6
+ import { createDefaultWalletSecretProvider, } from "../state/provider.js";
17
7
  import { openManagedWalletReadServiceBundle } from "./managed-services.js";
8
+ import { inspectWalletLocalState, readFundingSpendableSats } from "./local-state.js";
18
9
  import { createWalletReadModel } from "./project.js";
19
10
  const DEFAULT_SERVICE_START_TIMEOUT_MS = 60_000;
20
- function btcAmountToSats(value) {
21
- return BigInt(Math.round(value * 100_000_000));
22
- }
23
- function isSpendableFundingUtxo(entry, fundingScriptPubKeyHex) {
24
- return entry.scriptPubKey === fundingScriptPubKeyHex
25
- && entry.confirmations >= 1
26
- && entry.spendable !== false
27
- && entry.safe !== false;
28
- }
29
- async function pathExists(path) {
30
- try {
31
- await access(path, constants.F_OK);
32
- return true;
33
- }
34
- catch {
35
- return false;
36
- }
37
- }
38
- function isWalletAccessError(error) {
39
- const message = error instanceof Error ? error.message : String(error);
40
- return message.startsWith("wallet_secret_missing_")
41
- || message.startsWith("wallet_secret_provider_")
42
- || message.startsWith("wallet_client_password_")
43
- || message === "wallet_state_legacy_envelope_unsupported";
44
- }
45
- function describeWalletAccessMessage(options) {
46
- const message = options.accessError instanceof Error ? options.accessError.message : String(options.accessError ?? "");
47
- if (message === "wallet_state_legacy_envelope_unsupported") {
48
- return "Wallet state exists but was created by an older Cogcoin wallet format that this version no longer loads directly.";
49
- }
50
- if (message === "wallet_client_password_setup_required") {
51
- return describeClientPasswordSetupMessage();
52
- }
53
- if (message === "wallet_client_password_migration_required") {
54
- return describeClientPasswordMigrationMessage();
55
- }
56
- if (message === "wallet_client_password_locked") {
57
- return describeClientPasswordLockedMessage();
58
- }
59
- if (message.startsWith("wallet_secret_provider_")) {
60
- return "Wallet state exists but the local secret provider is unavailable.";
61
- }
62
- if (message.startsWith("wallet_secret_missing_")) {
63
- return "Wallet state exists but its local secret-provider material is unavailable.";
64
- }
65
- return message.length > 0
66
- ? message
67
- : "Wallet state exists but could not be loaded from the local secret provider.";
68
- }
69
- async function normalizeLoadedWalletStateForRead(options) {
70
- if (options.dataDir === undefined) {
71
- return options.loaded;
72
- }
73
- const node = await attachOrStartManagedBitcoindService({
74
- dataDir: options.dataDir,
75
- chain: "main",
76
- startHeight: 0,
77
- walletRootId: options.loaded.state.walletRootId,
78
- });
79
- try {
80
- const access = {
81
- provider: options.access.provider,
82
- secretReference: createWalletSecretReference(options.loaded.state.walletRootId),
83
- };
84
- const normalized = await persistNormalizedWalletDescriptorStateIfNeeded({
85
- state: options.loaded.state,
86
- access,
87
- paths: options.paths,
88
- nowUnixMs: options.now,
89
- replacePrimary: options.loaded.source === "backup",
90
- rpc: createRpcClient(node.rpc),
91
- });
92
- const coinControl = await persistWalletCoinControlStateIfNeeded({
93
- state: normalized.state,
94
- access,
95
- paths: options.paths,
96
- nowUnixMs: options.now,
97
- replacePrimary: (normalized.changed ? "primary" : options.loaded.source) === "backup",
98
- rpc: createRpcClient(node.rpc),
99
- });
100
- return {
101
- source: coinControl.changed ? "primary" : normalized.changed ? "primary" : options.loaded.source,
102
- state: coinControl.state,
103
- };
104
- }
105
- finally {
106
- await node.stop?.().catch(() => undefined);
107
- }
108
- }
109
- async function inspectWalletLocalState(options = {}) {
110
- const paths = options.paths ?? resolveWalletRuntimePathsForTesting();
111
- const now = options.now ?? Date.now();
112
- const provider = options.secretProvider ?? createDefaultWalletSecretProvider();
113
- const [hasPrimaryStateFile, hasBackupStateFile] = await Promise.all([
114
- pathExists(paths.walletStatePath),
115
- pathExists(paths.walletStateBackupPath),
116
- ]);
117
- const clientPasswordReadiness = await inspectClientPasswordSetupReadiness(provider).catch(() => "ready");
118
- if (!hasPrimaryStateFile && !hasBackupStateFile) {
119
- return {
120
- availability: "uninitialized",
121
- clientPasswordReadiness,
122
- unlockRequired: false,
123
- walletRootId: null,
124
- state: null,
125
- source: null,
126
- hasPrimaryStateFile,
127
- hasBackupStateFile,
128
- message: "Wallet state has not been initialized yet.",
129
- };
130
- }
131
- if (clientPasswordReadiness !== "ready") {
132
- const rawEnvelope = await loadRawWalletStateEnvelope({
133
- primaryPath: paths.walletStatePath,
134
- backupPath: paths.walletStateBackupPath,
135
- }).catch(() => null);
136
- if (rawEnvelope?.envelope.secretProvider == null) {
137
- return {
138
- availability: "local-state-corrupt",
139
- clientPasswordReadiness: "ready",
140
- unlockRequired: false,
141
- walletRootId: extractWalletRootIdHintFromWalletStateEnvelope(rawEnvelope?.envelope ?? null),
142
- state: null,
143
- source: null,
144
- hasPrimaryStateFile,
145
- hasBackupStateFile,
146
- message: "Wallet state exists but was created by an older Cogcoin wallet format that this version no longer loads directly.",
147
- };
148
- }
149
- const resolvedRoot = await resolveWalletRootIdFromLocalArtifacts({
150
- paths,
151
- provider,
152
- }).catch(() => null);
153
- return {
154
- availability: "local-state-corrupt",
155
- clientPasswordReadiness,
156
- unlockRequired: false,
157
- walletRootId: resolvedRoot?.walletRootId ?? null,
158
- state: null,
159
- source: null,
160
- hasPrimaryStateFile,
161
- hasBackupStateFile,
162
- message: clientPasswordReadiness === "migration-required"
163
- ? describeClientPasswordMigrationMessage()
164
- : describeClientPasswordSetupMessage(),
165
- };
166
- }
167
- try {
168
- const loaded = await loadWalletState({
169
- primaryPath: paths.walletStatePath,
170
- backupPath: paths.walletStateBackupPath,
171
- }, {
172
- provider,
173
- });
174
- const normalized = await normalizeLoadedWalletStateForRead({
175
- loaded,
176
- access: { provider },
177
- dataDir: options.dataDir,
178
- now,
179
- paths,
180
- });
181
- return {
182
- availability: "ready",
183
- clientPasswordReadiness,
184
- unlockRequired: false,
185
- walletRootId: normalized.state.walletRootId,
186
- state: normalizeWalletStateRecord({
187
- ...normalized.state,
188
- miningState: normalizeMiningStateRecord(normalized.state.miningState),
189
- }),
190
- source: normalized.source,
191
- hasPrimaryStateFile,
192
- hasBackupStateFile,
193
- message: null,
194
- };
195
- }
196
- catch (error) {
197
- const resolvedRoot = await resolveWalletRootIdFromLocalArtifacts({
198
- paths,
199
- provider,
200
- }).catch(() => null);
201
- const message = error instanceof Error ? error.message : String(error);
202
- return {
203
- availability: "local-state-corrupt",
204
- clientPasswordReadiness,
205
- unlockRequired: message === "wallet_client_password_locked",
206
- walletRootId: resolvedRoot?.walletRootId ?? null,
207
- state: null,
208
- source: null,
209
- hasPrimaryStateFile,
210
- hasBackupStateFile,
211
- message: isWalletAccessError(error)
212
- ? describeWalletAccessMessage({ accessError: error })
213
- : error instanceof Error
214
- ? error.message
215
- : String(error),
216
- };
217
- }
218
- }
219
- async function readFundingSpendableSats(options) {
220
- if (options.state === null || options.rpc === null) {
221
- return null;
222
- }
223
- const state = options.state;
224
- try {
225
- const utxos = await options.rpc.listUnspent(state.managedCoreWallet.walletName, 1);
226
- return utxos.reduce((sum, entry) => isSpendableFundingUtxo(entry, state.funding.scriptPubKeyHex)
227
- ? sum + btcAmountToSats(entry.amount)
228
- : sum, 0n);
229
- }
230
- catch {
231
- return null;
232
- }
233
- }
234
11
  export async function openWalletReadContext(options) {
235
12
  const expectedIndexerBinaryVersion = options.expectedIndexerBinaryVersion === undefined
236
13
  ? await readPackageVersionFromDisk()
@@ -288,4 +65,4 @@ export async function openWalletReadContext(options) {
288
65
  },
289
66
  };
290
67
  }
291
- export { inspectWalletLocalState, readSnapshotWithRetry, };
68
+ export { inspectWalletLocalState, };
@@ -0,0 +1,28 @@
1
+ import { attachOrStartManagedBitcoindService } from "../../bitcoind/service.js";
2
+ import { createRpcClient } from "../../bitcoind/node.js";
3
+ import { type WalletRuntimePaths } from "../runtime.js";
4
+ import { type WalletSecretProvider } from "../state/provider.js";
5
+ import type { WalletLocalStateStatus } from "./types.js";
6
+ type WalletLocalStateDeps = {
7
+ attachOrStartManagedBitcoindService: typeof attachOrStartManagedBitcoindService;
8
+ createRpcClient: typeof createRpcClient;
9
+ };
10
+ export declare function inspectWalletLocalStateWithDependencies(options?: {
11
+ dataDir?: string;
12
+ secretProvider?: WalletSecretProvider;
13
+ now?: number;
14
+ paths?: WalletRuntimePaths;
15
+ walletControlLockHeld?: boolean;
16
+ }, dependencies?: WalletLocalStateDeps): Promise<WalletLocalStateStatus>;
17
+ export declare function inspectWalletLocalState(options?: {
18
+ dataDir?: string;
19
+ secretProvider?: WalletSecretProvider;
20
+ now?: number;
21
+ paths?: WalletRuntimePaths;
22
+ walletControlLockHeld?: boolean;
23
+ }): Promise<WalletLocalStateStatus>;
24
+ export declare function readFundingSpendableSats(options: {
25
+ state: WalletLocalStateStatus["state"];
26
+ rpc: ReturnType<typeof createRpcClient> | null;
27
+ }): Promise<bigint | null>;
28
+ export {};