@cogcoin/client 1.1.4 → 1.1.6
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 +4 -5
- package/dist/bitcoind/indexer-daemon.d.ts +3 -7
- package/dist/bitcoind/indexer-daemon.js +43 -158
- package/dist/bitcoind/managed-runtime/bitcoind-policy.d.ts +16 -0
- package/dist/bitcoind/managed-runtime/bitcoind-policy.js +177 -0
- package/dist/bitcoind/managed-runtime/indexer-policy.d.ts +34 -0
- package/dist/bitcoind/managed-runtime/indexer-policy.js +200 -0
- package/dist/bitcoind/managed-runtime/status.d.ts +11 -0
- package/dist/bitcoind/managed-runtime/status.js +59 -0
- package/dist/bitcoind/managed-runtime/types.d.ts +37 -0
- package/dist/bitcoind/managed-runtime/types.js +1 -0
- package/dist/bitcoind/progress/tty-renderer.js +3 -2
- package/dist/bitcoind/service.d.ts +2 -7
- package/dist/bitcoind/service.js +46 -94
- package/dist/cli/command-registry.d.ts +39 -0
- package/dist/cli/command-registry.js +1132 -0
- package/dist/cli/commands/client-admin.js +6 -56
- package/dist/cli/commands/mining-admin.js +9 -32
- package/dist/cli/commands/mining-read.js +15 -56
- package/dist/cli/commands/mining-runtime.js +258 -57
- package/dist/cli/commands/service-runtime.js +1 -64
- package/dist/cli/commands/status.js +2 -15
- package/dist/cli/commands/update.js +6 -21
- package/dist/cli/commands/wallet-admin.js +18 -120
- package/dist/cli/commands/wallet-mutation.js +4 -7
- package/dist/cli/commands/wallet-read.js +31 -138
- package/dist/cli/context.js +2 -4
- package/dist/cli/mining-format.js +8 -2
- package/dist/cli/mutation-command-groups.d.ts +11 -11
- package/dist/cli/mutation-command-groups.js +9 -18
- package/dist/cli/mutation-json.d.ts +1 -17
- package/dist/cli/mutation-json.js +1 -28
- package/dist/cli/mutation-success.d.ts +0 -1
- package/dist/cli/mutation-success.js +0 -19
- package/dist/cli/output.d.ts +1 -10
- package/dist/cli/output.js +52 -481
- package/dist/cli/parse.d.ts +1 -1
- package/dist/cli/parse.js +38 -695
- package/dist/cli/runner.js +28 -113
- package/dist/cli/types.d.ts +7 -8
- package/dist/cli/update-notifier.js +1 -1
- package/dist/cli/wallet-format.js +1 -1
- package/dist/wallet/lifecycle/access.d.ts +5 -0
- package/dist/wallet/lifecycle/access.js +79 -0
- package/dist/wallet/lifecycle/context.d.ts +26 -0
- package/dist/wallet/lifecycle/context.js +58 -0
- package/dist/wallet/lifecycle/managed-core.d.ts +15 -0
- package/dist/wallet/lifecycle/managed-core.js +197 -0
- package/dist/wallet/lifecycle/repair-bitcoind.d.ts +10 -0
- package/dist/wallet/lifecycle/repair-bitcoind.js +142 -0
- package/dist/wallet/lifecycle/repair-indexer.d.ts +8 -0
- package/dist/wallet/lifecycle/repair-indexer.js +117 -0
- package/dist/wallet/lifecycle/repair-mining.d.ts +49 -0
- package/dist/wallet/lifecycle/repair-mining.js +304 -0
- package/dist/wallet/lifecycle/repair-runtime.d.ts +36 -0
- package/dist/wallet/lifecycle/repair-runtime.js +206 -0
- package/dist/wallet/lifecycle/repair.d.ts +9 -0
- package/dist/wallet/lifecycle/repair.js +127 -0
- package/dist/wallet/lifecycle/setup-prompts.d.ts +7 -0
- package/dist/wallet/lifecycle/setup-prompts.js +88 -0
- package/dist/wallet/lifecycle/setup-state.d.ts +26 -0
- package/dist/wallet/lifecycle/setup-state.js +159 -0
- package/dist/wallet/lifecycle/setup.d.ts +15 -0
- package/dist/wallet/lifecycle/setup.js +124 -0
- package/dist/wallet/lifecycle/types.d.ts +156 -0
- package/dist/wallet/lifecycle/types.js +1 -0
- package/dist/wallet/lifecycle.d.ts +4 -165
- package/dist/wallet/lifecycle.js +3 -1656
- package/dist/wallet/mining/candidate.d.ts +60 -0
- package/dist/wallet/mining/candidate.js +290 -0
- package/dist/wallet/mining/competitiveness.d.ts +22 -0
- package/dist/wallet/mining/competitiveness.js +640 -0
- package/dist/wallet/mining/control.js +7 -251
- package/dist/wallet/mining/cycle.d.ts +39 -0
- package/dist/wallet/mining/cycle.js +542 -0
- package/dist/wallet/mining/engine-state.d.ts +66 -0
- package/dist/wallet/mining/engine-state.js +211 -0
- package/dist/wallet/mining/engine-types.d.ts +173 -0
- package/dist/wallet/mining/engine-types.js +1 -0
- package/dist/wallet/mining/engine-utils.d.ts +7 -0
- package/dist/wallet/mining/engine-utils.js +75 -0
- package/dist/wallet/mining/events.d.ts +2 -0
- package/dist/wallet/mining/events.js +19 -0
- package/dist/wallet/mining/lifecycle.d.ts +71 -0
- package/dist/wallet/mining/lifecycle.js +355 -0
- package/dist/wallet/mining/projection.d.ts +61 -0
- package/dist/wallet/mining/projection.js +319 -0
- package/dist/wallet/mining/publish.d.ts +79 -0
- package/dist/wallet/mining/publish.js +614 -0
- package/dist/wallet/mining/runner.d.ts +12 -418
- package/dist/wallet/mining/runner.js +274 -3433
- package/dist/wallet/mining/supervisor.d.ts +134 -0
- package/dist/wallet/mining/supervisor.js +558 -0
- package/dist/wallet/mining/visualizer-sync.d.ts +42 -0
- package/dist/wallet/mining/visualizer-sync.js +166 -0
- package/dist/wallet/mining/visualizer.d.ts +1 -0
- package/dist/wallet/mining/visualizer.js +33 -18
- package/dist/wallet/read/context.js +13 -188
- package/dist/wallet/reset.d.ts +1 -1
- package/dist/wallet/reset.js +35 -11
- package/dist/wallet/runtime.d.ts +0 -6
- package/dist/wallet/runtime.js +2 -38
- package/dist/wallet/tx/common.d.ts +18 -0
- package/dist/wallet/tx/common.js +40 -26
- package/package.json +1 -1
- package/dist/wallet/state/seed-index.d.ts +0 -43
- package/dist/wallet/state/seed-index.js +0 -151
package/dist/wallet/reset.js
CHANGED
|
@@ -14,7 +14,6 @@ import { loadMiningRuntimeStatus } from "./mining/runtime-artifacts.js";
|
|
|
14
14
|
import { clearLegacyWalletLockArtifacts, withUnlockedManagedCoreWallet } from "./managed-core-wallet.js";
|
|
15
15
|
import { resolveWalletRuntimePathsForTesting } from "./runtime.js";
|
|
16
16
|
import { createDefaultWalletSecretProvider, createWalletRootId, createWalletSecretReference, } from "./state/provider.js";
|
|
17
|
-
import { loadWalletSeedIndex } from "./state/seed-index.js";
|
|
18
17
|
import { extractWalletRootIdHintFromWalletStateEnvelope, loadRawWalletStateEnvelope, loadWalletState, saveWalletState, } from "./state/storage.js";
|
|
19
18
|
import { confirmTypedAcknowledgement } from "./tx/confirm.js";
|
|
20
19
|
function sanitizeWalletName(walletRootId) {
|
|
@@ -50,6 +49,36 @@ async function readJsonFileOrNull(path) {
|
|
|
50
49
|
return null;
|
|
51
50
|
}
|
|
52
51
|
}
|
|
52
|
+
async function collectLegacyImportedSeedSecretProviderKeyIds(paths) {
|
|
53
|
+
const seedsRoot = join(paths.stateRoot, "seeds");
|
|
54
|
+
const entries = await readdir(seedsRoot, { withFileTypes: true }).catch((error) => {
|
|
55
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
throw error;
|
|
59
|
+
});
|
|
60
|
+
const keyIds = new Set();
|
|
61
|
+
for (const entry of entries) {
|
|
62
|
+
if (!entry.isDirectory()) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const seedRoot = join(seedsRoot, entry.name);
|
|
66
|
+
const candidatePaths = [
|
|
67
|
+
join(seedRoot, "wallet-state.enc"),
|
|
68
|
+
join(seedRoot, "wallet-state.enc.bak"),
|
|
69
|
+
join(seedRoot, "wallet-init-pending.enc"),
|
|
70
|
+
join(seedRoot, "wallet-init-pending.enc.bak"),
|
|
71
|
+
];
|
|
72
|
+
for (const candidatePath of candidatePaths) {
|
|
73
|
+
const envelope = await readJsonFileOrNull(candidatePath);
|
|
74
|
+
const keyId = envelope?.secretProvider?.keyId?.trim() ?? "";
|
|
75
|
+
if (keyId.length > 0) {
|
|
76
|
+
keyIds.add(keyId);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return [...keyIds].sort((left, right) => left.localeCompare(right));
|
|
81
|
+
}
|
|
53
82
|
async function isProcessAlive(pid) {
|
|
54
83
|
if (pid === null) {
|
|
55
84
|
return false;
|
|
@@ -454,12 +483,7 @@ async function preflightReset(options) {
|
|
|
454
483
|
}
|
|
455
484
|
const tracked = await collectTrackedManagedProcesses(options.paths);
|
|
456
485
|
const secretProviderKeyId = rawEnvelope?.envelope.secretProvider?.keyId ?? null;
|
|
457
|
-
const
|
|
458
|
-
paths: options.paths,
|
|
459
|
-
}).catch(() => null);
|
|
460
|
-
const importedSeedSecretProviderKeyIds = [...new Set((seedIndex?.seeds ?? [])
|
|
461
|
-
.filter((seed) => seed.kind === "imported")
|
|
462
|
-
.map((seed) => createWalletSecretReference(seed.walletRootId).keyId))];
|
|
486
|
+
const importedSeedSecretProviderKeyIds = await collectLegacyImportedSeedSecretProviderKeyIds(options.paths);
|
|
463
487
|
return {
|
|
464
488
|
dataRoot: options.paths.dataRoot,
|
|
465
489
|
removedRoots,
|
|
@@ -555,8 +579,8 @@ async function resolveResetExecutionDecision(options) {
|
|
|
555
579
|
let walletChoice = "";
|
|
556
580
|
let loadedWalletForEntropyReset = null;
|
|
557
581
|
if (options.preflight.wallet.present) {
|
|
558
|
-
const answer = (await options.prompter.prompt("Wallet reset choice ([Enter] retain base entropy, \"skip\", or \"
|
|
559
|
-
if (answer !== "" && answer !== "skip" && answer !== "
|
|
582
|
+
const answer = (await options.prompter.prompt("Wallet reset choice ([Enter] retain base entropy, \"skip\", or \"clear wallet entropy\"): ")).trim();
|
|
583
|
+
if (answer !== "" && answer !== "skip" && answer !== "clear wallet entropy") {
|
|
560
584
|
throw new Error("reset_wallet_choice_invalid");
|
|
561
585
|
}
|
|
562
586
|
walletChoice = answer;
|
|
@@ -592,7 +616,7 @@ function determineWalletAction(walletPresent, walletChoice) {
|
|
|
592
616
|
if (walletChoice === "skip") {
|
|
593
617
|
return "kept-unchanged";
|
|
594
618
|
}
|
|
595
|
-
if (walletChoice === "
|
|
619
|
+
if (walletChoice === "clear wallet entropy") {
|
|
596
620
|
return "deleted";
|
|
597
621
|
}
|
|
598
622
|
return "retain-mnemonic";
|
|
@@ -636,7 +660,7 @@ export async function previewResetWallet(options) {
|
|
|
636
660
|
walletPrompt: preflight.wallet.present
|
|
637
661
|
? {
|
|
638
662
|
defaultAction: "retain-mnemonic",
|
|
639
|
-
acceptedInputs: ["", "skip", "
|
|
663
|
+
acceptedInputs: ["", "skip", "clear wallet entropy"],
|
|
640
664
|
entropyRetainingResetAvailable: preflight.wallet.mode === "provider-backed",
|
|
641
665
|
envelopeSource: preflight.wallet.envelopeSource,
|
|
642
666
|
}
|
package/dist/wallet/runtime.d.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import type { CogcoinPathResolution } from "../app-paths.js";
|
|
2
|
-
export type WalletSeedKind = "main" | "imported";
|
|
3
2
|
export interface WalletRuntimePathResolution extends CogcoinPathResolution {
|
|
4
|
-
seedName?: string | null;
|
|
5
3
|
}
|
|
6
4
|
export interface WalletRuntimePaths {
|
|
7
5
|
dataRoot: string;
|
|
@@ -11,9 +9,6 @@ export interface WalletRuntimePaths {
|
|
|
11
9
|
walletRuntimeRoot: string;
|
|
12
10
|
stateRoot: string;
|
|
13
11
|
walletStateRoot: string;
|
|
14
|
-
seedRegistryPath: string;
|
|
15
|
-
selectedSeedName: string;
|
|
16
|
-
selectedSeedKind: WalletSeedKind;
|
|
17
12
|
bitcoinDataDir: string;
|
|
18
13
|
indexerRoot: string;
|
|
19
14
|
walletStateDirectory: string;
|
|
@@ -31,5 +26,4 @@ export interface WalletRuntimePaths {
|
|
|
31
26
|
miningEventsPath: string;
|
|
32
27
|
miningControlLockPath: string;
|
|
33
28
|
}
|
|
34
|
-
export declare function deriveWalletRuntimePathsForSeed(basePaths: WalletRuntimePaths, seedName: string | null | undefined): WalletRuntimePaths;
|
|
35
29
|
export declare function resolveWalletRuntimePathsForTesting(resolution?: WalletRuntimePathResolution): WalletRuntimePaths;
|
package/dist/wallet/runtime.js
CHANGED
|
@@ -1,41 +1,8 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
2
|
import { resolveCogcoinPathsForTesting } from "../app-paths.js";
|
|
3
|
-
function resolveSeedLayout(sharedStateRoot, sharedRuntimeRoot, seedName) {
|
|
4
|
-
if (seedName === "main") {
|
|
5
|
-
return {
|
|
6
|
-
seedKind: "main",
|
|
7
|
-
walletStateRoot: sharedStateRoot,
|
|
8
|
-
walletRuntimeRoot: sharedRuntimeRoot,
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
return {
|
|
12
|
-
seedKind: "imported",
|
|
13
|
-
walletStateRoot: join(sharedStateRoot, "seeds", seedName),
|
|
14
|
-
walletRuntimeRoot: join(sharedRuntimeRoot, "seeds", seedName),
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
export function deriveWalletRuntimePathsForSeed(basePaths, seedName) {
|
|
18
|
-
const resolvedSeedName = seedName ?? "main";
|
|
19
|
-
const seedLayout = resolveSeedLayout(basePaths.stateRoot, basePaths.runtimeRoot, resolvedSeedName);
|
|
20
|
-
return {
|
|
21
|
-
...basePaths,
|
|
22
|
-
walletRuntimeRoot: seedLayout.walletRuntimeRoot,
|
|
23
|
-
walletStateRoot: seedLayout.walletStateRoot,
|
|
24
|
-
selectedSeedName: resolvedSeedName,
|
|
25
|
-
selectedSeedKind: seedLayout.seedKind,
|
|
26
|
-
walletStateDirectory: seedLayout.walletStateRoot,
|
|
27
|
-
walletStatePath: join(seedLayout.walletStateRoot, "wallet-state.enc"),
|
|
28
|
-
walletStateBackupPath: join(seedLayout.walletStateRoot, "wallet-state.enc.bak"),
|
|
29
|
-
walletInitPendingPath: join(seedLayout.walletStateRoot, "wallet-init-pending.enc"),
|
|
30
|
-
walletInitPendingBackupPath: join(seedLayout.walletStateRoot, "wallet-init-pending.enc.bak"),
|
|
31
|
-
miningRoot: join(seedLayout.walletRuntimeRoot, "mining"),
|
|
32
|
-
miningStatusPath: join(seedLayout.walletRuntimeRoot, "mining", "status.json"),
|
|
33
|
-
miningEventsPath: join(seedLayout.walletRuntimeRoot, "mining", "events.jsonl"),
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
3
|
export function resolveWalletRuntimePathsForTesting(resolution = {}) {
|
|
37
4
|
const paths = resolveCogcoinPathsForTesting(resolution);
|
|
38
|
-
return
|
|
5
|
+
return {
|
|
39
6
|
dataRoot: paths.dataRoot,
|
|
40
7
|
clientDataDir: paths.clientDataDir,
|
|
41
8
|
clientConfigPath: paths.clientConfigPath,
|
|
@@ -43,9 +10,6 @@ export function resolveWalletRuntimePathsForTesting(resolution = {}) {
|
|
|
43
10
|
walletRuntimeRoot: paths.runtimeRoot,
|
|
44
11
|
stateRoot: paths.stateRoot,
|
|
45
12
|
walletStateRoot: paths.stateRoot,
|
|
46
|
-
seedRegistryPath: join(paths.stateRoot, "seed-index.json"),
|
|
47
|
-
selectedSeedName: "main",
|
|
48
|
-
selectedSeedKind: "main",
|
|
49
13
|
bitcoinDataDir: paths.bitcoinDataDir,
|
|
50
14
|
indexerRoot: paths.indexerRoot,
|
|
51
15
|
walletStateDirectory: paths.stateRoot,
|
|
@@ -62,5 +26,5 @@ export function resolveWalletRuntimePathsForTesting(resolution = {}) {
|
|
|
62
26
|
miningStatusPath: join(paths.runtimeRoot, "mining", "status.json"),
|
|
63
27
|
miningEventsPath: join(paths.runtimeRoot, "mining", "events.jsonl"),
|
|
64
28
|
miningControlLockPath: paths.miningControlLockPath,
|
|
65
|
-
}
|
|
29
|
+
};
|
|
66
30
|
}
|
|
@@ -168,6 +168,24 @@ export declare function buildWalletMutationTransaction<TPlan>(options: {
|
|
|
168
168
|
availableFundingMinConf?: number;
|
|
169
169
|
temporarilyUnlockedPolicyOutpoints?: readonly OutpointRecord[];
|
|
170
170
|
}): Promise<BuiltWalletMutationTransaction>;
|
|
171
|
+
export declare function fundAndValidateWalletMutationDraft<TPlan>(options: {
|
|
172
|
+
rpc: WalletMutationRpcClient;
|
|
173
|
+
walletName: string;
|
|
174
|
+
plan: TPlan & {
|
|
175
|
+
fixedInputs: FixedWalletInput[];
|
|
176
|
+
outputs: unknown[];
|
|
177
|
+
changeAddress: string;
|
|
178
|
+
changePosition?: number | null;
|
|
179
|
+
allowedFundingScriptPubKeyHex: string;
|
|
180
|
+
eligibleFundingOutpointKeys: Set<string>;
|
|
181
|
+
};
|
|
182
|
+
validateFundedDraft(decoded: RpcDecodedPsbt, funded: RpcWalletCreateFundedPsbtResult, plan: TPlan): void;
|
|
183
|
+
feeRate?: number;
|
|
184
|
+
availableFundingMinConf?: number;
|
|
185
|
+
}): Promise<{
|
|
186
|
+
funded: RpcWalletCreateFundedPsbtResult;
|
|
187
|
+
decoded: RpcDecodedPsbt;
|
|
188
|
+
}>;
|
|
171
189
|
export declare function buildWalletMutationTransactionWithReserveFallback<TPlan>(options: {
|
|
172
190
|
rpc: WalletMutationRpcClient;
|
|
173
191
|
walletName: string;
|
package/dist/wallet/tx/common.js
CHANGED
|
@@ -416,35 +416,16 @@ export async function pauseMiningForWalletMutation(options) {
|
|
|
416
416
|
});
|
|
417
417
|
}
|
|
418
418
|
export async function buildWalletMutationTransaction(options) {
|
|
419
|
-
const availableFundingMinConf = options.availableFundingMinConf ?? 1;
|
|
420
|
-
const availableFundingUtxos = (await options.rpc.listUnspent(options.walletName, availableFundingMinConf))
|
|
421
|
-
.filter((entry) => isSpendableFundingUtxo(entry, options.plan.allowedFundingScriptPubKeyHex, availableFundingMinConf));
|
|
422
|
-
const availableFundingValueByKey = new Map(availableFundingUtxos.map((entry) => [
|
|
423
|
-
outpointKey({ txid: entry.txid, vout: entry.vout }),
|
|
424
|
-
btcNumberToSats(entry.amount),
|
|
425
|
-
]));
|
|
426
|
-
const validationPlan = {
|
|
427
|
-
...options.plan,
|
|
428
|
-
eligibleFundingOutpointKeys: new Set([
|
|
429
|
-
...options.plan.eligibleFundingOutpointKeys,
|
|
430
|
-
...availableFundingUtxos.map((entry) => outpointKey({ txid: entry.txid, vout: entry.vout })),
|
|
431
|
-
]),
|
|
432
|
-
};
|
|
433
419
|
const temporaryBuilderLockedOutpoints = [];
|
|
434
420
|
try {
|
|
435
|
-
const funded = await
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
fee_rate: options.feeRate ?? DEFAULT_WALLET_MUTATION_FEE_RATE_SAT_VB,
|
|
443
|
-
replaceable: true,
|
|
444
|
-
subtractFeeFromOutputs: [],
|
|
421
|
+
const { funded, decoded } = await fundAndValidateWalletMutationDraft({
|
|
422
|
+
rpc: options.rpc,
|
|
423
|
+
walletName: options.walletName,
|
|
424
|
+
plan: options.plan,
|
|
425
|
+
validateFundedDraft: options.validateFundedDraft,
|
|
426
|
+
feeRate: options.feeRate,
|
|
427
|
+
availableFundingMinConf: options.availableFundingMinConf,
|
|
445
428
|
});
|
|
446
|
-
const decoded = await options.rpc.decodePsbt(funded.psbt);
|
|
447
|
-
options.validateFundedDraft(decoded, funded, validationPlan);
|
|
448
429
|
let signed;
|
|
449
430
|
let finalized;
|
|
450
431
|
let rawHex;
|
|
@@ -490,6 +471,39 @@ export async function buildWalletMutationTransaction(options) {
|
|
|
490
471
|
throw error;
|
|
491
472
|
}
|
|
492
473
|
}
|
|
474
|
+
export async function fundAndValidateWalletMutationDraft(options) {
|
|
475
|
+
const availableFundingMinConf = options.availableFundingMinConf ?? 1;
|
|
476
|
+
const availableFundingUtxos = (await options.rpc.listUnspent(options.walletName, availableFundingMinConf))
|
|
477
|
+
.filter((entry) => isSpendableFundingUtxo(entry, options.plan.allowedFundingScriptPubKeyHex, availableFundingMinConf));
|
|
478
|
+
const availableFundingValueByKey = new Map(availableFundingUtxos.map((entry) => [
|
|
479
|
+
outpointKey({ txid: entry.txid, vout: entry.vout }),
|
|
480
|
+
btcNumberToSats(entry.amount),
|
|
481
|
+
]));
|
|
482
|
+
const validationPlan = {
|
|
483
|
+
...options.plan,
|
|
484
|
+
eligibleFundingOutpointKeys: new Set([
|
|
485
|
+
...options.plan.eligibleFundingOutpointKeys,
|
|
486
|
+
...availableFundingUtxos.map((entry) => outpointKey({ txid: entry.txid, vout: entry.vout })),
|
|
487
|
+
]),
|
|
488
|
+
};
|
|
489
|
+
const funded = await options.rpc.walletCreateFundedPsbt(options.walletName, options.plan.fixedInputs, options.plan.outputs, 0, {
|
|
490
|
+
add_inputs: true,
|
|
491
|
+
include_unsafe: false,
|
|
492
|
+
minconf: availableFundingMinConf,
|
|
493
|
+
changeAddress: options.plan.changeAddress,
|
|
494
|
+
...(options.plan.changePosition == null ? {} : { changePosition: options.plan.changePosition }),
|
|
495
|
+
lockUnspents: false,
|
|
496
|
+
fee_rate: options.feeRate ?? DEFAULT_WALLET_MUTATION_FEE_RATE_SAT_VB,
|
|
497
|
+
replaceable: true,
|
|
498
|
+
subtractFeeFromOutputs: [],
|
|
499
|
+
});
|
|
500
|
+
const decoded = await options.rpc.decodePsbt(funded.psbt);
|
|
501
|
+
options.validateFundedDraft(decoded, funded, validationPlan);
|
|
502
|
+
return {
|
|
503
|
+
funded,
|
|
504
|
+
decoded,
|
|
505
|
+
};
|
|
506
|
+
}
|
|
493
507
|
export async function buildWalletMutationTransactionWithReserveFallback(options) {
|
|
494
508
|
return buildWalletMutationTransaction({
|
|
495
509
|
rpc: options.rpc,
|
package/package.json
CHANGED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import type { WalletSeedKind, WalletRuntimePaths } from "../runtime.js";
|
|
2
|
-
import { type RawWalletStateEnvelope } from "./storage.js";
|
|
3
|
-
export interface WalletSeedRecord {
|
|
4
|
-
name: string;
|
|
5
|
-
kind: WalletSeedKind;
|
|
6
|
-
walletRootId: string;
|
|
7
|
-
createdAtUnixMs: number;
|
|
8
|
-
restoredAtUnixMs: number | null;
|
|
9
|
-
}
|
|
10
|
-
export interface WalletSeedIndexV1 {
|
|
11
|
-
schemaVersion: 1;
|
|
12
|
-
lastWrittenAtUnixMs: number;
|
|
13
|
-
seeds: WalletSeedRecord[];
|
|
14
|
-
}
|
|
15
|
-
export declare function normalizeWalletSeedName(name: string): string;
|
|
16
|
-
export declare function isValidWalletSeedName(name: string): boolean;
|
|
17
|
-
export declare function assertValidImportedWalletSeedName(name: string): string;
|
|
18
|
-
export declare function findWalletSeedRecord(index: WalletSeedIndexV1, seedName: string): WalletSeedRecord | null;
|
|
19
|
-
export declare function loadWalletSeedIndex(options: {
|
|
20
|
-
paths: Pick<WalletRuntimePaths, "seedRegistryPath" | "walletStatePath" | "walletStateBackupPath">;
|
|
21
|
-
nowUnixMs?: number;
|
|
22
|
-
loadRawWalletStateEnvelope?: (paths: {
|
|
23
|
-
primaryPath: string;
|
|
24
|
-
backupPath: string;
|
|
25
|
-
}) => Promise<RawWalletStateEnvelope | null>;
|
|
26
|
-
}): Promise<WalletSeedIndexV1>;
|
|
27
|
-
export declare function saveWalletSeedIndex(paths: Pick<WalletRuntimePaths, "seedRegistryPath">, index: WalletSeedIndexV1): Promise<void>;
|
|
28
|
-
export declare function ensureMainWalletSeedIndexRecord(options: {
|
|
29
|
-
paths: Pick<WalletRuntimePaths, "seedRegistryPath" | "walletStatePath" | "walletStateBackupPath">;
|
|
30
|
-
walletRootId: string;
|
|
31
|
-
nowUnixMs?: number;
|
|
32
|
-
}): Promise<WalletSeedIndexV1>;
|
|
33
|
-
export declare function addImportedWalletSeedRecord(options: {
|
|
34
|
-
paths: Pick<WalletRuntimePaths, "seedRegistryPath" | "walletStatePath" | "walletStateBackupPath">;
|
|
35
|
-
seedName: string;
|
|
36
|
-
walletRootId: string;
|
|
37
|
-
nowUnixMs?: number;
|
|
38
|
-
}): Promise<WalletSeedIndexV1>;
|
|
39
|
-
export declare function removeWalletSeedRecord(options: {
|
|
40
|
-
paths: Pick<WalletRuntimePaths, "seedRegistryPath" | "walletStatePath" | "walletStateBackupPath">;
|
|
41
|
-
seedName: string;
|
|
42
|
-
nowUnixMs?: number;
|
|
43
|
-
}): Promise<WalletSeedIndexV1>;
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
import { mkdir, readFile } from "node:fs/promises";
|
|
2
|
-
import { dirname } from "node:path";
|
|
3
|
-
import { writeFileAtomic } from "../fs/atomic.js";
|
|
4
|
-
import { extractWalletRootIdHintFromWalletStateEnvelope, loadRawWalletStateEnvelope, } from "./storage.js";
|
|
5
|
-
function createEmptySeedIndex(nowUnixMs) {
|
|
6
|
-
return {
|
|
7
|
-
schemaVersion: 1,
|
|
8
|
-
lastWrittenAtUnixMs: nowUnixMs,
|
|
9
|
-
seeds: [],
|
|
10
|
-
};
|
|
11
|
-
}
|
|
12
|
-
function sortSeedRecords(seeds) {
|
|
13
|
-
return [...seeds].sort((left, right) => left.name.localeCompare(right.name));
|
|
14
|
-
}
|
|
15
|
-
async function readSeedIndexFile(path) {
|
|
16
|
-
try {
|
|
17
|
-
const parsed = JSON.parse(await readFile(path, "utf8"));
|
|
18
|
-
if (parsed?.schemaVersion !== 1 || !Array.isArray(parsed.seeds)) {
|
|
19
|
-
throw new Error("wallet_seed_index_invalid");
|
|
20
|
-
}
|
|
21
|
-
return {
|
|
22
|
-
schemaVersion: 1,
|
|
23
|
-
lastWrittenAtUnixMs: typeof parsed.lastWrittenAtUnixMs === "number" ? parsed.lastWrittenAtUnixMs : 0,
|
|
24
|
-
seeds: sortSeedRecords(parsed.seeds),
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
catch (error) {
|
|
28
|
-
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
29
|
-
return null;
|
|
30
|
-
}
|
|
31
|
-
throw new Error("wallet_seed_index_invalid");
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
export function normalizeWalletSeedName(name) {
|
|
35
|
-
return name.trim().toLowerCase();
|
|
36
|
-
}
|
|
37
|
-
export function isValidWalletSeedName(name) {
|
|
38
|
-
return /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(name);
|
|
39
|
-
}
|
|
40
|
-
export function assertValidImportedWalletSeedName(name) {
|
|
41
|
-
const normalized = normalizeWalletSeedName(name);
|
|
42
|
-
if (!isValidWalletSeedName(normalized)) {
|
|
43
|
-
throw new Error("wallet_seed_name_invalid");
|
|
44
|
-
}
|
|
45
|
-
if (normalized === "main") {
|
|
46
|
-
throw new Error("wallet_seed_name_reserved");
|
|
47
|
-
}
|
|
48
|
-
return normalized;
|
|
49
|
-
}
|
|
50
|
-
export function findWalletSeedRecord(index, seedName) {
|
|
51
|
-
const normalized = normalizeWalletSeedName(seedName);
|
|
52
|
-
return index.seeds.find((seed) => seed.name === normalized) ?? null;
|
|
53
|
-
}
|
|
54
|
-
export async function loadWalletSeedIndex(options) {
|
|
55
|
-
const nowUnixMs = options.nowUnixMs ?? Date.now();
|
|
56
|
-
const stored = await readSeedIndexFile(options.paths.seedRegistryPath);
|
|
57
|
-
if (stored !== null) {
|
|
58
|
-
return stored;
|
|
59
|
-
}
|
|
60
|
-
const rawEnvelope = await (options.loadRawWalletStateEnvelope ?? loadRawWalletStateEnvelope)({
|
|
61
|
-
primaryPath: options.paths.walletStatePath,
|
|
62
|
-
backupPath: options.paths.walletStateBackupPath,
|
|
63
|
-
}).catch(() => null);
|
|
64
|
-
const mainWalletRootId = extractWalletRootIdHintFromWalletStateEnvelope(rawEnvelope?.envelope ?? null);
|
|
65
|
-
if (mainWalletRootId === null) {
|
|
66
|
-
return createEmptySeedIndex(nowUnixMs);
|
|
67
|
-
}
|
|
68
|
-
return {
|
|
69
|
-
schemaVersion: 1,
|
|
70
|
-
lastWrittenAtUnixMs: nowUnixMs,
|
|
71
|
-
seeds: [{
|
|
72
|
-
name: "main",
|
|
73
|
-
kind: "main",
|
|
74
|
-
walletRootId: mainWalletRootId,
|
|
75
|
-
createdAtUnixMs: nowUnixMs,
|
|
76
|
-
restoredAtUnixMs: null,
|
|
77
|
-
}],
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
export async function saveWalletSeedIndex(paths, index) {
|
|
81
|
-
await mkdir(dirname(paths.seedRegistryPath), { recursive: true });
|
|
82
|
-
await writeFileAtomic(paths.seedRegistryPath, `${JSON.stringify({
|
|
83
|
-
...index,
|
|
84
|
-
seeds: sortSeedRecords(index.seeds),
|
|
85
|
-
}, null, 2)}\n`, { mode: 0o600 });
|
|
86
|
-
}
|
|
87
|
-
export async function ensureMainWalletSeedIndexRecord(options) {
|
|
88
|
-
const nowUnixMs = options.nowUnixMs ?? Date.now();
|
|
89
|
-
const index = await loadWalletSeedIndex({
|
|
90
|
-
paths: options.paths,
|
|
91
|
-
nowUnixMs,
|
|
92
|
-
});
|
|
93
|
-
const existing = findWalletSeedRecord(index, "main");
|
|
94
|
-
const seeds = index.seeds.filter((seed) => seed.name !== "main");
|
|
95
|
-
seeds.push({
|
|
96
|
-
name: "main",
|
|
97
|
-
kind: "main",
|
|
98
|
-
walletRootId: options.walletRootId,
|
|
99
|
-
createdAtUnixMs: existing?.createdAtUnixMs ?? nowUnixMs,
|
|
100
|
-
restoredAtUnixMs: existing?.restoredAtUnixMs ?? null,
|
|
101
|
-
});
|
|
102
|
-
const nextIndex = {
|
|
103
|
-
schemaVersion: 1,
|
|
104
|
-
lastWrittenAtUnixMs: nowUnixMs,
|
|
105
|
-
seeds: sortSeedRecords(seeds),
|
|
106
|
-
};
|
|
107
|
-
await saveWalletSeedIndex(options.paths, nextIndex);
|
|
108
|
-
return nextIndex;
|
|
109
|
-
}
|
|
110
|
-
export async function addImportedWalletSeedRecord(options) {
|
|
111
|
-
const nowUnixMs = options.nowUnixMs ?? Date.now();
|
|
112
|
-
const seedName = assertValidImportedWalletSeedName(options.seedName);
|
|
113
|
-
const index = await loadWalletSeedIndex({
|
|
114
|
-
paths: options.paths,
|
|
115
|
-
nowUnixMs,
|
|
116
|
-
});
|
|
117
|
-
if (findWalletSeedRecord(index, seedName) !== null) {
|
|
118
|
-
throw new Error("wallet_seed_name_exists");
|
|
119
|
-
}
|
|
120
|
-
const nextIndex = {
|
|
121
|
-
schemaVersion: 1,
|
|
122
|
-
lastWrittenAtUnixMs: nowUnixMs,
|
|
123
|
-
seeds: sortSeedRecords([
|
|
124
|
-
...index.seeds,
|
|
125
|
-
{
|
|
126
|
-
name: seedName,
|
|
127
|
-
kind: "imported",
|
|
128
|
-
walletRootId: options.walletRootId,
|
|
129
|
-
createdAtUnixMs: nowUnixMs,
|
|
130
|
-
restoredAtUnixMs: nowUnixMs,
|
|
131
|
-
},
|
|
132
|
-
]),
|
|
133
|
-
};
|
|
134
|
-
await saveWalletSeedIndex(options.paths, nextIndex);
|
|
135
|
-
return nextIndex;
|
|
136
|
-
}
|
|
137
|
-
export async function removeWalletSeedRecord(options) {
|
|
138
|
-
const nowUnixMs = options.nowUnixMs ?? Date.now();
|
|
139
|
-
const seedName = normalizeWalletSeedName(options.seedName);
|
|
140
|
-
const index = await loadWalletSeedIndex({
|
|
141
|
-
paths: options.paths,
|
|
142
|
-
nowUnixMs,
|
|
143
|
-
});
|
|
144
|
-
const nextIndex = {
|
|
145
|
-
schemaVersion: 1,
|
|
146
|
-
lastWrittenAtUnixMs: nowUnixMs,
|
|
147
|
-
seeds: sortSeedRecords(index.seeds.filter((seed) => seed.name !== seedName)),
|
|
148
|
-
};
|
|
149
|
-
await saveWalletSeedIndex(options.paths, nextIndex);
|
|
150
|
-
return nextIndex;
|
|
151
|
-
}
|