@cogcoin/client 0.5.15 → 1.0.1
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.
- package/README.md +80 -25
- package/dist/app-paths.d.ts +5 -6
- package/dist/app-paths.js +8 -16
- package/dist/art/balance.txt +10 -0
- package/dist/art/welcome.txt +16 -0
- package/dist/bitcoind/bootstrap/controller.d.ts +1 -0
- package/dist/bitcoind/bootstrap/controller.js +53 -1
- package/dist/bitcoind/client/follow-block-times.d.ts +1 -0
- package/dist/bitcoind/client/follow-block-times.js +1 -1
- package/dist/bitcoind/client/internal-types.d.ts +7 -3
- package/dist/bitcoind/client/managed-client.d.ts +4 -2
- package/dist/bitcoind/client/managed-client.js +14 -0
- package/dist/bitcoind/client/sync-engine.js +72 -11
- package/dist/bitcoind/hash-order.d.ts +4 -0
- package/dist/bitcoind/hash-order.js +13 -0
- package/dist/bitcoind/indexer-daemon-main.js +11 -3
- package/dist/bitcoind/normalize.js +3 -2
- package/dist/bitcoind/processing-start-height.d.ts +5 -0
- package/dist/bitcoind/processing-start-height.js +7 -0
- package/dist/bitcoind/progress/constants.d.ts +4 -0
- package/dist/bitcoind/progress/constants.js +4 -0
- package/dist/bitcoind/progress/controller.d.ts +2 -1
- package/dist/bitcoind/progress/controller.js +3 -3
- package/dist/bitcoind/progress/follow-scene.d.ts +6 -2
- package/dist/bitcoind/progress/follow-scene.js +29 -6
- package/dist/bitcoind/progress/formatting.d.ts +1 -0
- package/dist/bitcoind/progress/formatting.js +6 -0
- package/dist/bitcoind/progress/train-scene.js +37 -18
- package/dist/bitcoind/progress/tty-renderer.d.ts +6 -1
- package/dist/bitcoind/progress/tty-renderer.js +8 -4
- package/dist/bitcoind/rpc.d.ts +2 -1
- package/dist/bitcoind/rpc.js +3 -0
- package/dist/bitcoind/types.d.ts +6 -0
- package/dist/bytes.d.ts +1 -0
- package/dist/bytes.js +3 -0
- package/dist/cli/art.d.ts +2 -0
- package/dist/cli/art.js +37 -0
- package/dist/cli/commands/client-admin.d.ts +2 -0
- package/dist/cli/commands/client-admin.js +91 -0
- package/dist/cli/commands/follow.js +0 -2
- package/dist/cli/commands/mining-admin.js +6 -47
- package/dist/cli/commands/mining-read.js +11 -50
- package/dist/cli/commands/mining-runtime.js +142 -5
- package/dist/cli/commands/service-runtime.js +0 -2
- package/dist/cli/commands/status.js +8 -2
- package/dist/cli/commands/sync.js +49 -92
- package/dist/cli/commands/wallet-admin.js +142 -136
- package/dist/cli/commands/wallet-mutation.js +91 -79
- package/dist/cli/commands/wallet-read.js +15 -18
- package/dist/cli/context.js +5 -14
- package/dist/cli/mining-format.d.ts +0 -1
- package/dist/cli/mining-format.js +5 -37
- package/dist/cli/mining-json.d.ts +0 -18
- package/dist/cli/mining-json.js +0 -35
- package/dist/cli/mutation-command-groups.d.ts +1 -2
- package/dist/cli/mutation-command-groups.js +0 -5
- package/dist/cli/mutation-json.d.ts +24 -145
- package/dist/cli/mutation-json.js +30 -136
- package/dist/cli/mutation-resolved-json.d.ts +0 -7
- package/dist/cli/mutation-resolved-json.js +4 -10
- package/dist/cli/mutation-success.d.ts +2 -0
- package/dist/cli/mutation-success.js +11 -1
- package/dist/cli/mutation-text-format.js +1 -3
- package/dist/cli/output.d.ts +1 -1
- package/dist/cli/output.js +254 -231
- package/dist/cli/parse.d.ts +1 -1
- package/dist/cli/parse.js +93 -122
- package/dist/cli/preview-json.d.ts +17 -120
- package/dist/cli/preview-json.js +14 -97
- package/dist/cli/prompt.js +8 -13
- package/dist/cli/read-json.d.ts +15 -37
- package/dist/cli/read-json.js +44 -140
- package/dist/cli/runner.js +10 -13
- package/dist/cli/sync-progress.d.ts +6 -0
- package/dist/cli/sync-progress.js +91 -0
- package/dist/cli/types.d.ts +9 -17
- package/dist/cli/types.js +0 -2
- package/dist/cli/wallet-format.d.ts +1 -0
- package/dist/cli/wallet-format.js +208 -144
- package/dist/cli/workflow-hints.d.ts +3 -3
- package/dist/cli/workflow-hints.js +11 -8
- package/dist/client/default-client.d.ts +3 -1
- package/dist/client/default-client.js +45 -2
- package/dist/client/factory.js +1 -1
- package/dist/client/initialization.js +23 -0
- package/dist/client/persistence.js +5 -5
- package/dist/client/store-adapter.js +1 -0
- package/dist/sqlite/checkpoints.d.ts +1 -0
- package/dist/sqlite/checkpoints.js +7 -0
- package/dist/sqlite/store.js +14 -1
- package/dist/types.d.ts +1 -0
- package/dist/wallet/coin-control.d.ts +41 -12
- package/dist/wallet/coin-control.js +100 -428
- package/dist/wallet/descriptor-normalization.d.ts +1 -3
- package/dist/wallet/descriptor-normalization.js +0 -16
- package/dist/wallet/lifecycle.d.ts +7 -99
- package/dist/wallet/lifecycle.js +513 -968
- package/dist/wallet/managed-core-wallet.d.ts +13 -0
- package/dist/wallet/managed-core-wallet.js +20 -0
- package/dist/wallet/mining/constants.d.ts +5 -12
- package/dist/wallet/mining/constants.js +5 -12
- package/dist/wallet/mining/control.d.ts +1 -13
- package/dist/wallet/mining/control.js +45 -349
- package/dist/wallet/mining/index.d.ts +4 -5
- package/dist/wallet/mining/index.js +2 -3
- package/dist/wallet/mining/runner.d.ts +123 -13
- package/dist/wallet/mining/runner.js +899 -511
- package/dist/wallet/mining/runtime-artifacts.js +23 -3
- package/dist/wallet/mining/sentence-protocol.d.ts +44 -0
- package/dist/wallet/mining/sentence-protocol.js +123 -0
- package/dist/wallet/mining/sentences.d.ts +4 -8
- package/dist/wallet/mining/sentences.js +3 -52
- package/dist/wallet/mining/state.d.ts +11 -6
- package/dist/wallet/mining/state.js +7 -6
- package/dist/wallet/mining/types.d.ts +2 -30
- package/dist/wallet/mining/visualizer.d.ts +31 -3
- package/dist/wallet/mining/visualizer.js +135 -13
- package/dist/wallet/read/context.d.ts +0 -2
- package/dist/wallet/read/context.js +119 -140
- package/dist/wallet/read/filter.js +2 -11
- package/dist/wallet/read/index.d.ts +1 -1
- package/dist/wallet/read/project.js +24 -77
- package/dist/wallet/read/types.d.ts +10 -25
- package/dist/wallet/reset.d.ts +0 -1
- package/dist/wallet/reset.js +60 -138
- package/dist/wallet/root-resolution.d.ts +1 -5
- package/dist/wallet/root-resolution.js +0 -18
- package/dist/wallet/runtime.d.ts +0 -6
- package/dist/wallet/runtime.js +0 -8
- package/dist/wallet/state/client-password-agent.js +208 -0
- package/dist/wallet/state/client-password.d.ts +65 -0
- package/dist/wallet/state/client-password.js +952 -0
- package/dist/wallet/state/crypto.d.ts +1 -20
- package/dist/wallet/state/crypto.js +0 -63
- package/dist/wallet/state/provider.d.ts +23 -11
- package/dist/wallet/state/provider.js +248 -290
- package/dist/wallet/state/storage.d.ts +2 -2
- package/dist/wallet/state/storage.js +48 -16
- package/dist/wallet/tx/anchor.d.ts +3 -28
- package/dist/wallet/tx/anchor.js +349 -1250
- package/dist/wallet/tx/bitcoin-transfer.d.ts +35 -0
- package/dist/wallet/tx/bitcoin-transfer.js +200 -0
- package/dist/wallet/tx/cog.d.ts +5 -1
- package/dist/wallet/tx/cog.js +149 -185
- package/dist/wallet/tx/common.d.ts +61 -8
- package/dist/wallet/tx/common.js +266 -146
- package/dist/wallet/tx/domain-admin.d.ts +3 -1
- package/dist/wallet/tx/domain-admin.js +61 -99
- package/dist/wallet/tx/domain-market.d.ts +5 -1
- package/dist/wallet/tx/domain-market.js +221 -228
- package/dist/wallet/tx/field.d.ts +4 -10
- package/dist/wallet/tx/field.js +83 -924
- package/dist/wallet/tx/identity-selector.d.ts +9 -3
- package/dist/wallet/tx/identity-selector.js +17 -35
- package/dist/wallet/tx/index.d.ts +3 -1
- package/dist/wallet/tx/index.js +2 -1
- package/dist/wallet/tx/register.d.ts +3 -1
- package/dist/wallet/tx/register.js +62 -220
- package/dist/wallet/tx/reputation.d.ts +3 -1
- package/dist/wallet/tx/reputation.js +58 -95
- package/dist/wallet/types.d.ts +8 -122
- package/package.json +5 -5
- package/dist/wallet/archive.d.ts +0 -4
- package/dist/wallet/archive.js +0 -41
- package/dist/wallet/mining/hook-protocol.d.ts +0 -47
- package/dist/wallet/mining/hook-protocol.js +0 -161
- package/dist/wallet/mining/hook-runner.js +0 -52
- package/dist/wallet/mining/hooks.d.ts +0 -38
- package/dist/wallet/mining/hooks.js +0 -520
- package/dist/wallet/state/explicit-lock.d.ts +0 -4
- package/dist/wallet/state/explicit-lock.js +0 -19
- package/dist/wallet/state/session.d.ts +0 -12
- package/dist/wallet/state/session.js +0 -23
- /package/dist/wallet/{mining/hook-runner.d.ts → state/client-password-agent.d.ts} +0 -0
|
@@ -1,7 +1,87 @@
|
|
|
1
1
|
import { createBootstrapProgress } from "../../bitcoind/progress/formatting.js";
|
|
2
|
-
import { createFollowSceneState, syncFollowSceneState, } from "../../bitcoind/progress/follow-scene.js";
|
|
2
|
+
import { advanceFollowSceneState, createFollowSceneState, replaceFollowBlockTimes, syncFollowSceneState, } from "../../bitcoind/progress/follow-scene.js";
|
|
3
3
|
import { DEFAULT_RENDER_CLOCK, resolveTtyRenderPolicy, TtyRenderThrottle, } from "../../bitcoind/progress/render-policy.js";
|
|
4
4
|
import { TtyProgressRenderer } from "../../bitcoind/progress/tty-renderer.js";
|
|
5
|
+
const MINING_ARTWORK_COG_WIDTH = 22;
|
|
6
|
+
const MINING_SENTENCE_BOARD_SIZE = 5;
|
|
7
|
+
function formatCogAmountWithDecimals(value, { maxFractionDigits, minFractionDigits, }) {
|
|
8
|
+
const sign = value < 0n ? "-" : "";
|
|
9
|
+
const absolute = value < 0n ? -value : value;
|
|
10
|
+
const whole = absolute / 100000000n;
|
|
11
|
+
const fraction = absolute % 100000000n;
|
|
12
|
+
const paddedFraction = fraction.toString().padStart(8, "0");
|
|
13
|
+
const clampedMax = Math.max(0, Math.min(8, maxFractionDigits));
|
|
14
|
+
const clampedMin = Math.max(0, Math.min(clampedMax, minFractionDigits));
|
|
15
|
+
let fractionText = paddedFraction.slice(0, clampedMax);
|
|
16
|
+
while (fractionText.length > clampedMin && fractionText.endsWith("0")) {
|
|
17
|
+
fractionText = fractionText.slice(0, -1);
|
|
18
|
+
}
|
|
19
|
+
if (fractionText.length === 0 && clampedMin > 0) {
|
|
20
|
+
fractionText = "".padEnd(clampedMin, "0");
|
|
21
|
+
}
|
|
22
|
+
return fractionText.length > 0
|
|
23
|
+
? `${sign}${whole.toString()}.${fractionText}`
|
|
24
|
+
: `${sign}${whole.toString()}`;
|
|
25
|
+
}
|
|
26
|
+
function formatCompactCogBalanceText(balanceCogtoshi) {
|
|
27
|
+
if (balanceCogtoshi === null) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
for (let digits = 4; digits >= 1; digits -= 1) {
|
|
31
|
+
const cogSegment = `${formatCogAmountWithDecimals(balanceCogtoshi, {
|
|
32
|
+
maxFractionDigits: digits,
|
|
33
|
+
minFractionDigits: 1,
|
|
34
|
+
})} COG`;
|
|
35
|
+
if (cogSegment.length <= MINING_ARTWORK_COG_WIDTH) {
|
|
36
|
+
return cogSegment;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return `${formatCogAmountWithDecimals(balanceCogtoshi, {
|
|
40
|
+
maxFractionDigits: 1,
|
|
41
|
+
minFractionDigits: 1,
|
|
42
|
+
})} COG`;
|
|
43
|
+
}
|
|
44
|
+
function formatCompactSatBalanceText(balanceSats) {
|
|
45
|
+
return balanceSats === null ? null : `${balanceSats.toString()} SAT`;
|
|
46
|
+
}
|
|
47
|
+
function formatRewardCogAmount(value) {
|
|
48
|
+
return `${formatCogAmountWithDecimals(value, {
|
|
49
|
+
maxFractionDigits: 8,
|
|
50
|
+
minFractionDigits: 1,
|
|
51
|
+
})} COG`;
|
|
52
|
+
}
|
|
53
|
+
function formatSentenceRow(rank, domainName, sentence) {
|
|
54
|
+
return `${rank}. @${domainName}: ${sentence}`;
|
|
55
|
+
}
|
|
56
|
+
function formatRequiredWordsLine(words) {
|
|
57
|
+
if (words.length === 0) {
|
|
58
|
+
return "";
|
|
59
|
+
}
|
|
60
|
+
return `Required words: ${words.map((word) => word.toUpperCase()).join(", ")}`;
|
|
61
|
+
}
|
|
62
|
+
function formatProvisionalSentenceRow(entry) {
|
|
63
|
+
if (entry.domainName === null || entry.sentence === null) {
|
|
64
|
+
return "";
|
|
65
|
+
}
|
|
66
|
+
return `@${entry.domainName}: ${entry.sentence}`;
|
|
67
|
+
}
|
|
68
|
+
export function createEmptyMiningFollowVisualizerState() {
|
|
69
|
+
return {
|
|
70
|
+
balanceCogtoshi: null,
|
|
71
|
+
balanceSats: null,
|
|
72
|
+
visibleBlockTimesByHeight: {},
|
|
73
|
+
settledBlockHeight: null,
|
|
74
|
+
settledBoardEntries: [],
|
|
75
|
+
provisionalRequiredWords: [],
|
|
76
|
+
provisionalEntry: {
|
|
77
|
+
domainName: null,
|
|
78
|
+
sentence: null,
|
|
79
|
+
},
|
|
80
|
+
latestSentence: null,
|
|
81
|
+
latestTxid: null,
|
|
82
|
+
recentWin: null,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
5
85
|
const VISUALIZER_PROGRESS_SNAPSHOT = {
|
|
6
86
|
url: "",
|
|
7
87
|
filename: "mining-follow-visualizer",
|
|
@@ -9,14 +89,15 @@ const VISUALIZER_PROGRESS_SNAPSHOT = {
|
|
|
9
89
|
sha256: "",
|
|
10
90
|
sizeBytes: 1,
|
|
11
91
|
};
|
|
12
|
-
export function describeMiningVisualizerStatus(snapshot) {
|
|
92
|
+
export function describeMiningVisualizerStatus(snapshot, ui = createEmptyMiningFollowVisualizerState()) {
|
|
93
|
+
if (ui.recentWin !== null) {
|
|
94
|
+
return `You got #${ui.recentWin.rank} and mined ${formatRewardCogAmount(ui.recentWin.rewardCogtoshi)} in block #${ui.recentWin.blockHeight}`;
|
|
95
|
+
}
|
|
13
96
|
switch (snapshot.currentPhase) {
|
|
14
97
|
case "resuming":
|
|
15
98
|
return "Resuming after suspend";
|
|
16
99
|
case "waiting-provider":
|
|
17
|
-
return
|
|
18
|
-
? "Waiting for hook"
|
|
19
|
-
: "Waiting for provider";
|
|
100
|
+
return "Waiting for provider";
|
|
20
101
|
case "waiting-indexer":
|
|
21
102
|
return snapshot.indexerDaemonState === "reorging"
|
|
22
103
|
? "Indexer replaying reorg"
|
|
@@ -54,7 +135,7 @@ export function describeMiningVisualizerStatus(snapshot) {
|
|
|
54
135
|
if (snapshot.currentPublishDecision === "indeterminate-mempool-gate") {
|
|
55
136
|
return "Mempool gate indeterminate";
|
|
56
137
|
}
|
|
57
|
-
if (snapshot.
|
|
138
|
+
if (snapshot.livePublishInMempool) {
|
|
58
139
|
return "Waiting for next block";
|
|
59
140
|
}
|
|
60
141
|
return "Waiting for next block";
|
|
@@ -78,7 +159,7 @@ export function describeMiningVisualizerProgress(snapshot) {
|
|
|
78
159
|
return "Scoring mining candidates for the current tip.";
|
|
79
160
|
case "publishing":
|
|
80
161
|
return snapshot.currentPublishDecision === "fee-bump"
|
|
81
|
-
? "Publishing a fee bump for the live mining
|
|
162
|
+
? "Publishing a fee bump for the live mining transaction."
|
|
82
163
|
: snapshot.currentPublishDecision === "replacing"
|
|
83
164
|
|| snapshot.currentPublishDecision === "replaced"
|
|
84
165
|
? "Replacing the live mining transaction for the current tip."
|
|
@@ -95,7 +176,9 @@ export class MiningFollowVisualizer {
|
|
|
95
176
|
#renderThrottle;
|
|
96
177
|
#progress = createBootstrapProgress("follow_tip", VISUALIZER_PROGRESS_SNAPSHOT);
|
|
97
178
|
#scene = createFollowSceneState();
|
|
179
|
+
#ticker = null;
|
|
98
180
|
#latestSnapshot = null;
|
|
181
|
+
#latestUiState = createEmptyMiningFollowVisualizerState();
|
|
99
182
|
constructor(options = {}) {
|
|
100
183
|
const stream = options.stream ?? process.stderr;
|
|
101
184
|
const progressOutput = options.progressOutput ?? "auto";
|
|
@@ -115,23 +198,51 @@ export class MiningFollowVisualizer {
|
|
|
115
198
|
},
|
|
116
199
|
throttled: renderPolicy.linuxHeadlessThrottle,
|
|
117
200
|
});
|
|
201
|
+
if (this.#renderer !== null) {
|
|
202
|
+
this.#ticker = this.#clock.setInterval(() => {
|
|
203
|
+
this.#advanceAndRender();
|
|
204
|
+
}, renderPolicy.repaintIntervalMs);
|
|
205
|
+
}
|
|
118
206
|
}
|
|
119
|
-
update(snapshot) {
|
|
207
|
+
update(snapshot, uiState) {
|
|
120
208
|
if (this.#renderer === null) {
|
|
121
209
|
return;
|
|
122
210
|
}
|
|
123
211
|
this.#latestSnapshot = snapshot;
|
|
212
|
+
if (uiState !== undefined) {
|
|
213
|
+
this.#latestUiState = uiState;
|
|
214
|
+
}
|
|
215
|
+
replaceFollowBlockTimes(this.#scene, this.#latestUiState.visibleBlockTimesByHeight);
|
|
216
|
+
const indexedHeight = snapshot.indexerTipHeight ?? snapshot.coreBestHeight ?? null;
|
|
217
|
+
const nodeHeight = snapshot.coreBestHeight ?? indexedHeight;
|
|
218
|
+
syncFollowSceneState(this.#scene, {
|
|
219
|
+
indexedHeight,
|
|
220
|
+
nodeHeight,
|
|
221
|
+
liveActivated: true,
|
|
222
|
+
});
|
|
124
223
|
this.#renderThrottle.request();
|
|
125
224
|
}
|
|
126
225
|
close() {
|
|
226
|
+
if (this.#ticker !== null) {
|
|
227
|
+
this.#clock.clearInterval(this.#ticker);
|
|
228
|
+
this.#ticker = null;
|
|
229
|
+
}
|
|
127
230
|
this.#renderThrottle.flush();
|
|
128
231
|
this.#renderer?.close();
|
|
129
232
|
}
|
|
233
|
+
#advanceAndRender() {
|
|
234
|
+
if (this.#renderer === null || this.#latestSnapshot === null) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
advanceFollowSceneState(this.#scene, this.#clock.now());
|
|
238
|
+
this.#renderThrottle.request();
|
|
239
|
+
}
|
|
130
240
|
#renderLatestSnapshot() {
|
|
131
241
|
if (this.#renderer === null || this.#latestSnapshot === null) {
|
|
132
242
|
return;
|
|
133
243
|
}
|
|
134
244
|
const snapshot = this.#latestSnapshot;
|
|
245
|
+
const uiState = this.#latestUiState;
|
|
135
246
|
const indexedHeight = snapshot.indexerTipHeight ?? snapshot.coreBestHeight ?? null;
|
|
136
247
|
const nodeHeight = snapshot.coreBestHeight ?? indexedHeight;
|
|
137
248
|
this.#progress.phase = "follow_tip";
|
|
@@ -141,11 +252,22 @@ export class MiningFollowVisualizer {
|
|
|
141
252
|
this.#progress.targetHeight = nodeHeight;
|
|
142
253
|
this.#progress.etaSeconds = null;
|
|
143
254
|
this.#progress.lastError = snapshot.lastError;
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
255
|
+
this.#renderer.renderFollowScene(this.#progress, indexedHeight, nodeHeight, this.#scene, describeMiningVisualizerStatus(snapshot, uiState), {
|
|
256
|
+
artworkCogText: formatCompactCogBalanceText(uiState.balanceCogtoshi),
|
|
257
|
+
artworkSatText: formatCompactSatBalanceText(uiState.balanceSats),
|
|
258
|
+
extraLines: [
|
|
259
|
+
`✎ Block #${uiState.settledBlockHeight ?? "-----"} Sentences ✎`,
|
|
260
|
+
"",
|
|
261
|
+
...Array.from({ length: MINING_SENTENCE_BOARD_SIZE }, (_value, index) => {
|
|
262
|
+
const entry = uiState.settledBoardEntries[index];
|
|
263
|
+
return entry === undefined
|
|
264
|
+
? `${index + 1}.`
|
|
265
|
+
: formatSentenceRow(entry.rank, entry.domainName, entry.sentence);
|
|
266
|
+
}),
|
|
267
|
+
"----------",
|
|
268
|
+
formatRequiredWordsLine(uiState.provisionalRequiredWords),
|
|
269
|
+
formatProvisionalSentenceRow(uiState.provisionalEntry),
|
|
270
|
+
],
|
|
148
271
|
});
|
|
149
|
-
this.#renderer.renderFollowScene(this.#progress, indexedHeight, nodeHeight, this.#scene, describeMiningVisualizerStatus(snapshot));
|
|
150
272
|
}
|
|
151
273
|
}
|
|
@@ -4,7 +4,6 @@ import type { WalletLocalStateStatus, WalletReadContext } from "./types.js";
|
|
|
4
4
|
import type { WalletRuntimePaths } from "../runtime.js";
|
|
5
5
|
declare function inspectWalletLocalState(options?: {
|
|
6
6
|
dataDir?: string;
|
|
7
|
-
passphrase?: Uint8Array | string;
|
|
8
7
|
secretProvider?: WalletSecretProvider;
|
|
9
8
|
now?: number;
|
|
10
9
|
paths?: WalletRuntimePaths;
|
|
@@ -13,7 +12,6 @@ declare function inspectWalletLocalState(options?: {
|
|
|
13
12
|
export declare function openWalletReadContext(options: {
|
|
14
13
|
dataDir: string;
|
|
15
14
|
databasePath: string;
|
|
16
|
-
walletStatePassphrase?: Uint8Array | string;
|
|
17
15
|
secretProvider?: WalletSecretProvider;
|
|
18
16
|
walletControlLockHeld?: boolean;
|
|
19
17
|
startupTimeoutMs?: number;
|
|
@@ -6,19 +6,28 @@ import { UNINITIALIZED_WALLET_ROOT_ID } from "../../bitcoind/service-paths.js";
|
|
|
6
6
|
import { attachOrStartManagedBitcoindService, probeManagedBitcoindService, } from "../../bitcoind/service.js";
|
|
7
7
|
import { resolveCogcoinProcessingStartHeight } from "../../bitcoind/processing-start-height.js";
|
|
8
8
|
import {} from "../../bitcoind/types.js";
|
|
9
|
-
import {
|
|
9
|
+
import { verifyManagedCoreWalletReplica, } from "../lifecycle.js";
|
|
10
10
|
import { normalizeWalletStateRecord, persistWalletCoinControlStateIfNeeded } from "../coin-control.js";
|
|
11
11
|
import { persistNormalizedWalletDescriptorStateIfNeeded } from "../descriptor-normalization.js";
|
|
12
12
|
import { inspectMiningControlPlane } from "../mining/index.js";
|
|
13
13
|
import { normalizeMiningStateRecord } from "../mining/state.js";
|
|
14
14
|
import { resolveWalletRootIdFromLocalArtifacts } from "../root-resolution.js";
|
|
15
15
|
import { resolveWalletRuntimePathsForTesting } from "../runtime.js";
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
16
|
+
import { extractWalletRootIdHintFromWalletStateEnvelope, loadRawWalletStateEnvelope, loadWalletState, } from "../state/storage.js";
|
|
17
|
+
import { createDefaultWalletSecretProvider, createWalletSecretReference, inspectClientPasswordSetupReadiness, } from "../state/provider.js";
|
|
18
|
+
import { describeClientPasswordLockedMessage, describeClientPasswordMigrationMessage, describeClientPasswordSetupMessage, } from "../state/client-password.js";
|
|
19
19
|
import { createWalletReadModel } from "./project.js";
|
|
20
20
|
const DEFAULT_SERVICE_START_TIMEOUT_MS = 10_000;
|
|
21
21
|
const STALE_HEARTBEAT_THRESHOLD_MS = 15_000;
|
|
22
|
+
function btcAmountToSats(value) {
|
|
23
|
+
return BigInt(Math.round(value * 100_000_000));
|
|
24
|
+
}
|
|
25
|
+
function isSpendableFundingUtxo(entry, fundingScriptPubKeyHex) {
|
|
26
|
+
return entry.scriptPubKey === fundingScriptPubKeyHex
|
|
27
|
+
&& entry.confirmations >= 1
|
|
28
|
+
&& entry.spendable !== false
|
|
29
|
+
&& entry.safe !== false;
|
|
30
|
+
}
|
|
22
31
|
async function pathExists(path) {
|
|
23
32
|
try {
|
|
24
33
|
await access(path, constants.F_OK);
|
|
@@ -28,19 +37,26 @@ async function pathExists(path) {
|
|
|
28
37
|
return false;
|
|
29
38
|
}
|
|
30
39
|
}
|
|
31
|
-
function
|
|
40
|
+
function isWalletAccessError(error) {
|
|
32
41
|
const message = error instanceof Error ? error.message : String(error);
|
|
33
|
-
return message
|
|
34
|
-
|| message.startsWith("
|
|
35
|
-
|| message.startsWith("
|
|
42
|
+
return message.startsWith("wallet_secret_missing_")
|
|
43
|
+
|| message.startsWith("wallet_secret_provider_")
|
|
44
|
+
|| message.startsWith("wallet_client_password_")
|
|
45
|
+
|| message === "wallet_state_legacy_envelope_unsupported";
|
|
36
46
|
}
|
|
37
|
-
function
|
|
38
|
-
if (options.explicitlyLocked) {
|
|
39
|
-
return "Wallet state exists but is explicitly locked until `cogcoin unlock` is run.";
|
|
40
|
-
}
|
|
47
|
+
function describeWalletAccessMessage(options) {
|
|
41
48
|
const message = options.accessError instanceof Error ? options.accessError.message : String(options.accessError ?? "");
|
|
42
|
-
if (message === "
|
|
43
|
-
return "Wallet state exists but
|
|
49
|
+
if (message === "wallet_state_legacy_envelope_unsupported") {
|
|
50
|
+
return "Wallet state exists but was created by an older Cogcoin wallet format that this version no longer loads directly.";
|
|
51
|
+
}
|
|
52
|
+
if (message === "wallet_client_password_setup_required") {
|
|
53
|
+
return describeClientPasswordSetupMessage();
|
|
54
|
+
}
|
|
55
|
+
if (message === "wallet_client_password_migration_required") {
|
|
56
|
+
return describeClientPasswordMigrationMessage();
|
|
57
|
+
}
|
|
58
|
+
if (message === "wallet_client_password_locked") {
|
|
59
|
+
return describeClientPasswordLockedMessage();
|
|
44
60
|
}
|
|
45
61
|
if (message.startsWith("wallet_secret_provider_")) {
|
|
46
62
|
return "Wallet state exists but the local secret provider is unavailable.";
|
|
@@ -48,9 +64,9 @@ function describeLockedWalletMessage(options) {
|
|
|
48
64
|
if (message.startsWith("wallet_secret_missing_")) {
|
|
49
65
|
return "Wallet state exists but its local secret-provider material is unavailable.";
|
|
50
66
|
}
|
|
51
|
-
return
|
|
52
|
-
?
|
|
53
|
-
: "Wallet state exists but
|
|
67
|
+
return message.length > 0
|
|
68
|
+
? message
|
|
69
|
+
: "Wallet state exists but could not be loaded from the local secret provider.";
|
|
54
70
|
}
|
|
55
71
|
async function normalizeLoadedWalletStateForRead(options) {
|
|
56
72
|
if (options.dataDir === undefined) {
|
|
@@ -63,12 +79,10 @@ async function normalizeLoadedWalletStateForRead(options) {
|
|
|
63
79
|
walletRootId: options.loaded.state.walletRootId,
|
|
64
80
|
});
|
|
65
81
|
try {
|
|
66
|
-
const access =
|
|
67
|
-
|
|
68
|
-
:
|
|
69
|
-
|
|
70
|
-
secretReference: createWalletSecretReference(options.loaded.state.walletRootId),
|
|
71
|
-
};
|
|
82
|
+
const access = {
|
|
83
|
+
provider: options.access.provider,
|
|
84
|
+
secretReference: createWalletSecretReference(options.loaded.state.walletRootId),
|
|
85
|
+
};
|
|
72
86
|
const normalized = await persistNormalizedWalletDescriptorStateIfNeeded({
|
|
73
87
|
state: options.loaded.state,
|
|
74
88
|
access,
|
|
@@ -98,166 +112,109 @@ async function inspectWalletLocalState(options = {}) {
|
|
|
98
112
|
const paths = options.paths ?? resolveWalletRuntimePathsForTesting();
|
|
99
113
|
const now = options.now ?? Date.now();
|
|
100
114
|
const provider = options.secretProvider ?? createDefaultWalletSecretProvider();
|
|
101
|
-
const [hasPrimaryStateFile, hasBackupStateFile
|
|
115
|
+
const [hasPrimaryStateFile, hasBackupStateFile] = await Promise.all([
|
|
102
116
|
pathExists(paths.walletStatePath),
|
|
103
117
|
pathExists(paths.walletStateBackupPath),
|
|
104
|
-
pathExists(paths.walletUnlockSessionPath),
|
|
105
118
|
]);
|
|
119
|
+
const clientPasswordReadiness = await inspectClientPasswordSetupReadiness(provider).catch(() => "ready");
|
|
106
120
|
if (!hasPrimaryStateFile && !hasBackupStateFile) {
|
|
107
121
|
return {
|
|
108
122
|
availability: "uninitialized",
|
|
123
|
+
clientPasswordReadiness,
|
|
124
|
+
unlockRequired: false,
|
|
109
125
|
walletRootId: null,
|
|
110
126
|
state: null,
|
|
111
127
|
source: null,
|
|
112
|
-
unlockUntilUnixMs: null,
|
|
113
128
|
hasPrimaryStateFile,
|
|
114
129
|
hasBackupStateFile,
|
|
115
|
-
hasUnlockSessionFile,
|
|
116
130
|
message: "Wallet state has not been initialized yet.",
|
|
117
131
|
};
|
|
118
132
|
}
|
|
119
|
-
if (
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
dataDir: options.dataDir,
|
|
126
|
-
controlLockHeld: options.walletControlLockHeld,
|
|
127
|
-
});
|
|
128
|
-
if (unlocked === null) {
|
|
129
|
-
const explicitLock = await loadWalletExplicitLock(paths.walletExplicitLockPath);
|
|
130
|
-
const hasUnlockSessionFileNow = await pathExists(paths.walletUnlockSessionPath);
|
|
131
|
-
try {
|
|
132
|
-
const loaded = await loadWalletState({
|
|
133
|
-
primaryPath: paths.walletStatePath,
|
|
134
|
-
backupPath: paths.walletStateBackupPath,
|
|
135
|
-
}, {
|
|
136
|
-
provider,
|
|
137
|
-
});
|
|
138
|
-
await normalizeLoadedWalletStateForRead({
|
|
139
|
-
loaded,
|
|
140
|
-
access: { provider },
|
|
141
|
-
dataDir: options.dataDir,
|
|
142
|
-
now,
|
|
143
|
-
paths,
|
|
144
|
-
});
|
|
145
|
-
return {
|
|
146
|
-
availability: "locked",
|
|
147
|
-
walletRootId: loaded.state.walletRootId,
|
|
148
|
-
state: null,
|
|
149
|
-
source: loaded.source,
|
|
150
|
-
unlockUntilUnixMs: null,
|
|
151
|
-
hasPrimaryStateFile,
|
|
152
|
-
hasBackupStateFile,
|
|
153
|
-
hasUnlockSessionFile: hasUnlockSessionFileNow,
|
|
154
|
-
message: describeLockedWalletMessage({
|
|
155
|
-
explicitlyLocked: explicitLock?.walletRootId === loaded.state.walletRootId,
|
|
156
|
-
hasUnlockSessionFile: hasUnlockSessionFileNow,
|
|
157
|
-
}),
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
catch (error) {
|
|
161
|
-
const resolvedRoot = await resolveWalletRootIdFromLocalArtifacts({
|
|
162
|
-
paths,
|
|
163
|
-
provider,
|
|
164
|
-
}).catch(() => null);
|
|
165
|
-
if (isLockedWalletAccessError(error)) {
|
|
166
|
-
return {
|
|
167
|
-
availability: "locked",
|
|
168
|
-
walletRootId: resolvedRoot?.walletRootId ?? null,
|
|
169
|
-
state: null,
|
|
170
|
-
source: null,
|
|
171
|
-
unlockUntilUnixMs: null,
|
|
172
|
-
hasPrimaryStateFile,
|
|
173
|
-
hasBackupStateFile,
|
|
174
|
-
hasUnlockSessionFile: hasUnlockSessionFileNow,
|
|
175
|
-
message: describeLockedWalletMessage({
|
|
176
|
-
accessError: error,
|
|
177
|
-
explicitlyLocked: false,
|
|
178
|
-
hasUnlockSessionFile: hasUnlockSessionFileNow,
|
|
179
|
-
}),
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
return {
|
|
183
|
-
availability: "local-state-corrupt",
|
|
184
|
-
walletRootId: resolvedRoot?.walletRootId ?? null,
|
|
185
|
-
state: null,
|
|
186
|
-
source: null,
|
|
187
|
-
unlockUntilUnixMs: null,
|
|
188
|
-
hasPrimaryStateFile,
|
|
189
|
-
hasBackupStateFile,
|
|
190
|
-
hasUnlockSessionFile: hasUnlockSessionFileNow,
|
|
191
|
-
message: error instanceof Error ? error.message : String(error),
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
return {
|
|
196
|
-
availability: "ready",
|
|
197
|
-
walletRootId: unlocked.state.walletRootId,
|
|
198
|
-
state: normalizeWalletStateRecord({
|
|
199
|
-
...unlocked.state,
|
|
200
|
-
miningState: normalizeMiningStateRecord(unlocked.state.miningState),
|
|
201
|
-
}),
|
|
202
|
-
source: unlocked.source,
|
|
203
|
-
unlockUntilUnixMs: unlocked.session.unlockUntilUnixMs,
|
|
204
|
-
hasPrimaryStateFile,
|
|
205
|
-
hasBackupStateFile,
|
|
206
|
-
hasUnlockSessionFile: true,
|
|
207
|
-
message: null,
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
catch (error) {
|
|
133
|
+
if (clientPasswordReadiness !== "ready") {
|
|
134
|
+
const rawEnvelope = await loadRawWalletStateEnvelope({
|
|
135
|
+
primaryPath: paths.walletStatePath,
|
|
136
|
+
backupPath: paths.walletStateBackupPath,
|
|
137
|
+
}).catch(() => null);
|
|
138
|
+
if (rawEnvelope?.envelope.secretProvider == null) {
|
|
211
139
|
return {
|
|
212
140
|
availability: "local-state-corrupt",
|
|
213
|
-
|
|
141
|
+
clientPasswordReadiness: "ready",
|
|
142
|
+
unlockRequired: false,
|
|
143
|
+
walletRootId: extractWalletRootIdHintFromWalletStateEnvelope(rawEnvelope?.envelope ?? null),
|
|
214
144
|
state: null,
|
|
215
145
|
source: null,
|
|
216
|
-
unlockUntilUnixMs: null,
|
|
217
146
|
hasPrimaryStateFile,
|
|
218
147
|
hasBackupStateFile,
|
|
219
|
-
|
|
220
|
-
message: error instanceof Error ? error.message : String(error),
|
|
148
|
+
message: "Wallet state exists but was created by an older Cogcoin wallet format that this version no longer loads directly.",
|
|
221
149
|
};
|
|
222
150
|
}
|
|
151
|
+
const resolvedRoot = await resolveWalletRootIdFromLocalArtifacts({
|
|
152
|
+
paths,
|
|
153
|
+
provider,
|
|
154
|
+
}).catch(() => null);
|
|
155
|
+
return {
|
|
156
|
+
availability: "local-state-corrupt",
|
|
157
|
+
clientPasswordReadiness,
|
|
158
|
+
unlockRequired: false,
|
|
159
|
+
walletRootId: resolvedRoot?.walletRootId ?? null,
|
|
160
|
+
state: null,
|
|
161
|
+
source: null,
|
|
162
|
+
hasPrimaryStateFile,
|
|
163
|
+
hasBackupStateFile,
|
|
164
|
+
message: clientPasswordReadiness === "migration-required"
|
|
165
|
+
? describeClientPasswordMigrationMessage()
|
|
166
|
+
: describeClientPasswordSetupMessage(),
|
|
167
|
+
};
|
|
223
168
|
}
|
|
224
169
|
try {
|
|
225
|
-
const loaded = await
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
170
|
+
const loaded = await loadWalletState({
|
|
171
|
+
primaryPath: paths.walletStatePath,
|
|
172
|
+
backupPath: paths.walletStateBackupPath,
|
|
173
|
+
}, {
|
|
174
|
+
provider,
|
|
175
|
+
});
|
|
176
|
+
const normalized = await normalizeLoadedWalletStateForRead({
|
|
177
|
+
loaded,
|
|
178
|
+
access: { provider },
|
|
231
179
|
dataDir: options.dataDir,
|
|
232
180
|
now,
|
|
233
181
|
paths,
|
|
234
182
|
});
|
|
235
183
|
return {
|
|
236
184
|
availability: "ready",
|
|
237
|
-
|
|
185
|
+
clientPasswordReadiness,
|
|
186
|
+
unlockRequired: false,
|
|
187
|
+
walletRootId: normalized.state.walletRootId,
|
|
238
188
|
state: normalizeWalletStateRecord({
|
|
239
|
-
...
|
|
240
|
-
miningState: normalizeMiningStateRecord(
|
|
189
|
+
...normalized.state,
|
|
190
|
+
miningState: normalizeMiningStateRecord(normalized.state.miningState),
|
|
241
191
|
}),
|
|
242
|
-
source:
|
|
243
|
-
unlockUntilUnixMs: null,
|
|
192
|
+
source: normalized.source,
|
|
244
193
|
hasPrimaryStateFile,
|
|
245
194
|
hasBackupStateFile,
|
|
246
|
-
hasUnlockSessionFile,
|
|
247
195
|
message: null,
|
|
248
196
|
};
|
|
249
197
|
}
|
|
250
198
|
catch (error) {
|
|
199
|
+
const resolvedRoot = await resolveWalletRootIdFromLocalArtifacts({
|
|
200
|
+
paths,
|
|
201
|
+
provider,
|
|
202
|
+
}).catch(() => null);
|
|
203
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
251
204
|
return {
|
|
252
205
|
availability: "local-state-corrupt",
|
|
253
|
-
|
|
206
|
+
clientPasswordReadiness,
|
|
207
|
+
unlockRequired: message === "wallet_client_password_locked",
|
|
208
|
+
walletRootId: resolvedRoot?.walletRootId ?? null,
|
|
254
209
|
state: null,
|
|
255
210
|
source: null,
|
|
256
|
-
unlockUntilUnixMs: null,
|
|
257
211
|
hasPrimaryStateFile,
|
|
258
212
|
hasBackupStateFile,
|
|
259
|
-
|
|
260
|
-
|
|
213
|
+
message: isWalletAccessError(error)
|
|
214
|
+
? describeWalletAccessMessage({ accessError: error })
|
|
215
|
+
: error instanceof Error
|
|
216
|
+
? error.message
|
|
217
|
+
: String(error),
|
|
261
218
|
};
|
|
262
219
|
}
|
|
263
220
|
}
|
|
@@ -467,6 +424,7 @@ async function attachNodeStatus(options) {
|
|
|
467
424
|
if (probe.compatibility !== "compatible" && probe.compatibility !== "unreachable") {
|
|
468
425
|
return {
|
|
469
426
|
handle: null,
|
|
427
|
+
rpc: null,
|
|
470
428
|
status: null,
|
|
471
429
|
observedStatus: probe.status,
|
|
472
430
|
error: probe.error,
|
|
@@ -500,6 +458,7 @@ async function attachNodeStatus(options) {
|
|
|
500
458
|
};
|
|
501
459
|
return {
|
|
502
460
|
handle,
|
|
461
|
+
rpc,
|
|
503
462
|
status,
|
|
504
463
|
observedStatus: serviceStatus ?? null,
|
|
505
464
|
error: null,
|
|
@@ -508,18 +467,33 @@ async function attachNodeStatus(options) {
|
|
|
508
467
|
catch (error) {
|
|
509
468
|
return {
|
|
510
469
|
handle: null,
|
|
470
|
+
rpc: null,
|
|
511
471
|
status: null,
|
|
512
472
|
observedStatus: null,
|
|
513
473
|
error: error instanceof Error ? error.message : String(error),
|
|
514
474
|
};
|
|
515
475
|
}
|
|
516
476
|
}
|
|
477
|
+
async function readFundingSpendableSats(options) {
|
|
478
|
+
if (options.state === null || options.rpc === null) {
|
|
479
|
+
return null;
|
|
480
|
+
}
|
|
481
|
+
const state = options.state;
|
|
482
|
+
try {
|
|
483
|
+
const utxos = await options.rpc.listUnspent(state.managedCoreWallet.walletName, 1);
|
|
484
|
+
return utxos.reduce((sum, entry) => isSpendableFundingUtxo(entry, state.funding.scriptPubKeyHex)
|
|
485
|
+
? sum + btcAmountToSats(entry.amount)
|
|
486
|
+
: sum, 0n);
|
|
487
|
+
}
|
|
488
|
+
catch {
|
|
489
|
+
return null;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
517
492
|
export async function openWalletReadContext(options) {
|
|
518
493
|
const startupTimeoutMs = options.startupTimeoutMs ?? DEFAULT_SERVICE_START_TIMEOUT_MS;
|
|
519
494
|
const now = options.now ?? Date.now();
|
|
520
495
|
const localState = await inspectWalletLocalState({
|
|
521
496
|
dataDir: options.dataDir,
|
|
522
|
-
passphrase: options.walletStatePassphrase,
|
|
523
497
|
secretProvider: options.secretProvider,
|
|
524
498
|
walletControlLockHeld: options.walletControlLockHeld,
|
|
525
499
|
now,
|
|
@@ -611,6 +585,10 @@ export async function openWalletReadContext(options) {
|
|
|
611
585
|
now,
|
|
612
586
|
startupError: daemonError,
|
|
613
587
|
});
|
|
588
|
+
const fundingSpendableSats = await readFundingSpendableSats({
|
|
589
|
+
state: localState.state,
|
|
590
|
+
rpc: node.rpc,
|
|
591
|
+
});
|
|
614
592
|
const mining = await inspectMiningControlPlane({
|
|
615
593
|
provider: options.secretProvider,
|
|
616
594
|
localState,
|
|
@@ -634,6 +612,7 @@ export async function openWalletReadContext(options) {
|
|
|
634
612
|
model: localState.state === null
|
|
635
613
|
? null
|
|
636
614
|
: createWalletReadModel(localState.state, snapshot),
|
|
615
|
+
fundingSpendableSats,
|
|
637
616
|
mining,
|
|
638
617
|
async close() {
|
|
639
618
|
await daemonClient?.close().catch(() => undefined);
|
|
@@ -4,20 +4,11 @@ export function isRootDomainName(name) {
|
|
|
4
4
|
}
|
|
5
5
|
export function isMineableWalletDomain(context, domain) {
|
|
6
6
|
const state = context.localState.state;
|
|
7
|
-
const model = context.model;
|
|
8
7
|
const snapshot = context.snapshot;
|
|
9
|
-
if (state === null || model === null || snapshot === null) {
|
|
8
|
+
if (state === null || context.model === null || snapshot === null) {
|
|
10
9
|
return false;
|
|
11
10
|
}
|
|
12
|
-
if (!isRootDomainName(domain.name) || domain.anchored !== true || domain.readOnly || domain.
|
|
13
|
-
return false;
|
|
14
|
-
}
|
|
15
|
-
const localRecord = state.domains.find((entry) => entry.name === domain.name);
|
|
16
|
-
const ownerIdentity = model.identities.find((identity) => identity.index === domain.ownerLocalIndex);
|
|
17
|
-
if (localRecord?.currentCanonicalAnchorOutpoint === null
|
|
18
|
-
|| localRecord?.currentCanonicalAnchorOutpoint === undefined
|
|
19
|
-
|| ownerIdentity?.address == null
|
|
20
|
-
|| ownerIdentity.readOnly) {
|
|
11
|
+
if (!isRootDomainName(domain.name) || domain.anchored !== true || domain.readOnly || domain.localRelationship !== "local" || domain.domainId === null) {
|
|
21
12
|
return false;
|
|
22
13
|
}
|
|
23
14
|
const chainDomain = lookupDomain(snapshot.state, domain.name);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { openWalletReadContext, inspectWalletLocalState, readSnapshotWithRetry } from "./context.js";
|
|
2
2
|
export { filterWalletDomains, isMineableWalletDomain, isRootDomainName, type WalletDomainFilterOptions, } from "./filter.js";
|
|
3
3
|
export { createFieldPreview, createWalletReadModel, findDomainField, findWalletLock, findWalletDomain, formatFieldFormat, listDomainFields, listWalletLocks, } from "./project.js";
|
|
4
|
-
export type { WalletBitcoindStatus, WalletDomainDetailsView, WalletDomainView, WalletFieldView,
|
|
4
|
+
export type { WalletBitcoindStatus, WalletDomainDetailsView, WalletDomainView, WalletFieldView, WalletIndexerStatus, WalletLocalStateStatus, WalletLockView, WalletNodeStatus, WalletReadContext, WalletReadModel, WalletServiceHealth, WalletSnapshotView, WalletStateAvailability, } from "./types.js";
|