@cogcoin/client 0.5.3 → 0.5.4
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 +11 -3
- package/dist/art/wallet.txt +10 -0
- package/dist/bitcoind/indexer-daemon.d.ts +9 -0
- package/dist/bitcoind/indexer-daemon.js +51 -14
- package/dist/bitcoind/service.d.ts +9 -0
- package/dist/bitcoind/service.js +65 -24
- package/dist/bitcoind/testing.d.ts +2 -2
- package/dist/bitcoind/testing.js +2 -2
- package/dist/cli/commands/service-runtime.d.ts +2 -0
- package/dist/cli/commands/service-runtime.js +432 -0
- package/dist/cli/commands/wallet-admin.js +227 -132
- package/dist/cli/commands/wallet-mutation.js +597 -580
- package/dist/cli/context.js +23 -1
- package/dist/cli/mutation-json.d.ts +17 -1
- package/dist/cli/mutation-json.js +42 -0
- package/dist/cli/output.js +112 -1
- package/dist/cli/parse.d.ts +1 -1
- package/dist/cli/parse.js +65 -0
- package/dist/cli/preview-json.d.ts +19 -1
- package/dist/cli/preview-json.js +31 -0
- package/dist/cli/prompt.js +40 -12
- package/dist/cli/runner.js +12 -0
- package/dist/cli/signals.d.ts +1 -0
- package/dist/cli/signals.js +44 -0
- package/dist/cli/types.d.ts +24 -2
- package/dist/cli/types.js +6 -0
- package/dist/cli/wallet-format.js +3 -0
- package/dist/cli/workflow-hints.d.ts +1 -0
- package/dist/cli/workflow-hints.js +3 -0
- package/dist/wallet/fs/lock.d.ts +2 -0
- package/dist/wallet/fs/lock.js +32 -0
- package/dist/wallet/lifecycle.d.ts +19 -1
- package/dist/wallet/lifecycle.js +251 -3
- package/dist/wallet/material.d.ts +2 -0
- package/dist/wallet/material.js +8 -1
- package/dist/wallet/mnemonic-art.d.ts +2 -0
- package/dist/wallet/mnemonic-art.js +54 -0
- package/dist/wallet/reset.d.ts +61 -0
- package/dist/wallet/reset.js +781 -0
- package/package.json +3 -3
package/dist/cli/runner.js
CHANGED
|
@@ -6,6 +6,7 @@ import { runFollowCommand } from "./commands/follow.js";
|
|
|
6
6
|
import { runMiningAdminCommand } from "./commands/mining-admin.js";
|
|
7
7
|
import { runMiningReadCommand } from "./commands/mining-read.js";
|
|
8
8
|
import { runMiningRuntimeCommand } from "./commands/mining-runtime.js";
|
|
9
|
+
import { runServiceRuntimeCommand } from "./commands/service-runtime.js";
|
|
9
10
|
import { runStatusCommand } from "./commands/status.js";
|
|
10
11
|
import { runSyncCommand } from "./commands/sync.js";
|
|
11
12
|
import { runWalletAdminCommand } from "./commands/wallet-admin.js";
|
|
@@ -49,6 +50,14 @@ export async function runCli(argv, contextOverrides = {}) {
|
|
|
49
50
|
if (parsed.command === "status") {
|
|
50
51
|
return runStatusCommand(parsed, context);
|
|
51
52
|
}
|
|
53
|
+
if (parsed.command === "bitcoin-start"
|
|
54
|
+
|| parsed.command === "bitcoin-stop"
|
|
55
|
+
|| parsed.command === "bitcoin-status"
|
|
56
|
+
|| parsed.command === "indexer-start"
|
|
57
|
+
|| parsed.command === "indexer-stop"
|
|
58
|
+
|| parsed.command === "indexer-status") {
|
|
59
|
+
return runServiceRuntimeCommand(parsed, context);
|
|
60
|
+
}
|
|
52
61
|
if (parsed.command === "mine"
|
|
53
62
|
|| parsed.command === "mine-start"
|
|
54
63
|
|| parsed.command === "mine-stop") {
|
|
@@ -60,11 +69,14 @@ export async function runCli(argv, contextOverrides = {}) {
|
|
|
60
69
|
return runMiningAdminCommand(parsed, context);
|
|
61
70
|
}
|
|
62
71
|
if (parsed.command === "init"
|
|
72
|
+
|| parsed.command === "restore"
|
|
73
|
+
|| parsed.command === "reset"
|
|
63
74
|
|| parsed.command === "repair"
|
|
64
75
|
|| parsed.command === "unlock"
|
|
65
76
|
|| parsed.command === "wallet-export"
|
|
66
77
|
|| parsed.command === "wallet-import"
|
|
67
78
|
|| parsed.command === "wallet-init"
|
|
79
|
+
|| parsed.command === "wallet-restore"
|
|
68
80
|
|| parsed.command === "wallet-unlock"
|
|
69
81
|
|| parsed.command === "wallet-lock") {
|
|
70
82
|
return runWalletAdminCommand(parsed, context);
|
package/dist/cli/signals.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import type { InterruptibleOutcome, ManagedClientLike, SignalSource, StopSignalWatcher, WritableLike } from "./types.js";
|
|
2
2
|
export declare function createStopSignalWatcher(signalSource: SignalSource, stderr: WritableLike, client: ManagedClientLike, forceExit: (code: number) => never | void): StopSignalWatcher;
|
|
3
|
+
export declare function createOwnedLockCleanupSignalWatcher(signalSource: SignalSource, forceExit: (code: number) => never | void, lockPaths: readonly string[]): StopSignalWatcher;
|
|
3
4
|
export declare function waitForCompletionOrStop<T>(promise: Promise<T>, stopWatcher: StopSignalWatcher): Promise<InterruptibleOutcome<T>>;
|
package/dist/cli/signals.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { writeLine } from "./io.js";
|
|
2
|
+
import { clearLockIfOwnedByCurrentProcess } from "../wallet/fs/lock.js";
|
|
2
3
|
export function createStopSignalWatcher(signalSource, stderr, client, forceExit) {
|
|
3
4
|
let closing = false;
|
|
4
5
|
let resolved = false;
|
|
@@ -42,6 +43,49 @@ export function createStopSignalWatcher(signalSource, stderr, client, forceExit)
|
|
|
42
43
|
promise,
|
|
43
44
|
};
|
|
44
45
|
}
|
|
46
|
+
export function createOwnedLockCleanupSignalWatcher(signalSource, forceExit, lockPaths) {
|
|
47
|
+
let stopping = false;
|
|
48
|
+
let resolved = false;
|
|
49
|
+
let onSignal = () => { };
|
|
50
|
+
const cleanup = () => {
|
|
51
|
+
signalSource.off("SIGINT", onSignal);
|
|
52
|
+
signalSource.off("SIGTERM", onSignal);
|
|
53
|
+
};
|
|
54
|
+
const promise = new Promise((resolve) => {
|
|
55
|
+
const settle = (code) => {
|
|
56
|
+
if (resolved) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
resolved = true;
|
|
60
|
+
cleanup();
|
|
61
|
+
resolve(code);
|
|
62
|
+
};
|
|
63
|
+
const releaseOwnedLocks = async () => {
|
|
64
|
+
await Promise.allSettled([...new Set(lockPaths)].map(async (lockPath) => {
|
|
65
|
+
await clearLockIfOwnedByCurrentProcess(lockPath);
|
|
66
|
+
}));
|
|
67
|
+
};
|
|
68
|
+
onSignal = () => {
|
|
69
|
+
if (stopping) {
|
|
70
|
+
settle(130);
|
|
71
|
+
forceExit(130);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
stopping = true;
|
|
75
|
+
settle(130);
|
|
76
|
+
void releaseOwnedLocks().finally(() => {
|
|
77
|
+
forceExit(130);
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
});
|
|
81
|
+
signalSource.on("SIGINT", onSignal);
|
|
82
|
+
signalSource.on("SIGTERM", onSignal);
|
|
83
|
+
return {
|
|
84
|
+
cleanup,
|
|
85
|
+
isStopping: () => stopping,
|
|
86
|
+
promise,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
45
89
|
export async function waitForCompletionOrStop(promise, stopWatcher) {
|
|
46
90
|
const outcome = await Promise.race([
|
|
47
91
|
promise.then((value) => ({ kind: "completed", value }), (error) => ({ kind: "error", error })),
|
package/dist/cli/types.d.ts
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
import type { inspectPassiveClientStatus } from "../passive-status.js";
|
|
2
|
+
import { createRpcClient } from "../bitcoind/node.js";
|
|
3
|
+
import { attachOrStartIndexerDaemon, probeIndexerDaemon, readObservedIndexerDaemonStatus, stopIndexerDaemonService } from "../bitcoind/indexer-daemon.js";
|
|
4
|
+
import { attachOrStartManagedBitcoindService, probeManagedBitcoindService, stopManagedBitcoindService } from "../bitcoind/service.js";
|
|
2
5
|
import { openSqliteStore } from "../sqlite/index.js";
|
|
3
6
|
import type { ClientStoreAdapter } from "../types.js";
|
|
4
|
-
import type {
|
|
7
|
+
import type { WalletRuntimePaths } from "../wallet/runtime.js";
|
|
8
|
+
import type { exportWallet, WalletPrompter, importWallet, initializeWallet, lockWallet, previewResetWallet, repairWallet, resetWallet, restoreWalletFromMnemonic, unlockWallet } from "../wallet/lifecycle.js";
|
|
5
9
|
import type { openWalletReadContext } from "../wallet/read/index.js";
|
|
10
|
+
import { loadWalletExplicitLock } from "../wallet/state/explicit-lock.js";
|
|
11
|
+
import { loadUnlockSession } from "../wallet/state/session.js";
|
|
12
|
+
import { loadWalletState } from "../wallet/state/storage.js";
|
|
6
13
|
import type { WalletSecretProvider } from "../wallet/state/provider.js";
|
|
7
14
|
import type { disableMiningHooks, enableMiningHooks, followMiningLog, inspectMiningControlPlane, readMiningLog, runForegroundMining, setupBuiltInMining, startBackgroundMining, stopBackgroundMining } from "../wallet/mining/index.js";
|
|
8
15
|
import type { anchorDomain, buyDomain, claimCogLock, clearDomainDelegate, clearDomainEndpoint, clearDomainMiner, clearField, createField, giveReputation, lockCogToDomain, registerDomain, reclaimCogLock, revokeReputation, sendCog, setField, setDomainCanonical, setDomainDelegate, setDomainEndpoint, setDomainMiner, sellDomain, transferDomain } from "../wallet/tx/index.js";
|
|
9
16
|
export type ProgressOutput = "auto" | "tty" | "none";
|
|
10
17
|
export type OutputMode = "text" | "json" | "preview-json";
|
|
11
|
-
export type CommandName = "init" | "repair" | "sync" | "status" | "follow" | "unlock" | "anchor" | "domain-anchor" | "register" | "domain-register" | "transfer" | "domain-transfer" | "sell" | "domain-sell" | "unsell" | "domain-unsell" | "buy" | "domain-buy" | "domain-endpoint-set" | "domain-endpoint-clear" | "domain-delegate-set" | "domain-delegate-clear" | "domain-miner-set" | "domain-miner-clear" | "domain-canonical" | "field-list" | "field-show" | "field-create" | "field-set" | "field-clear" | "send" | "claim" | "reclaim" | "cog-send" | "cog-claim" | "cog-reclaim" | "cog-lock" | "rep-give" | "rep-revoke" | "cog-balance" | "cog-locks" | "hooks-mining-enable" | "hooks-mining-disable" | "hooks-mining-status" | "mine" | "mine-start" | "mine-stop" | "mine-setup" | "mine-status" | "mine-log" | "wallet-export" | "wallet-import" | "wallet-init" | "wallet-lock" | "wallet-unlock" | "wallet-status" | "wallet-address" | "wallet-ids" | "address" | "ids" | "balance" | "locks" | "domain-list" | "domains" | "domain-show" | "show" | "fields" | "field";
|
|
18
|
+
export type CommandName = "init" | "restore" | "reset" | "repair" | "sync" | "status" | "follow" | "bitcoin-start" | "bitcoin-stop" | "bitcoin-status" | "indexer-start" | "indexer-stop" | "indexer-status" | "unlock" | "anchor" | "domain-anchor" | "register" | "domain-register" | "transfer" | "domain-transfer" | "sell" | "domain-sell" | "unsell" | "domain-unsell" | "buy" | "domain-buy" | "domain-endpoint-set" | "domain-endpoint-clear" | "domain-delegate-set" | "domain-delegate-clear" | "domain-miner-set" | "domain-miner-clear" | "domain-canonical" | "field-list" | "field-show" | "field-create" | "field-set" | "field-clear" | "send" | "claim" | "reclaim" | "cog-send" | "cog-claim" | "cog-reclaim" | "cog-lock" | "rep-give" | "rep-revoke" | "cog-balance" | "cog-locks" | "hooks-mining-enable" | "hooks-mining-disable" | "hooks-mining-status" | "mine" | "mine-start" | "mine-stop" | "mine-setup" | "mine-status" | "mine-log" | "wallet-export" | "wallet-import" | "wallet-init" | "wallet-restore" | "wallet-lock" | "wallet-unlock" | "wallet-status" | "wallet-address" | "wallet-ids" | "address" | "ids" | "balance" | "locks" | "domain-list" | "domains" | "domain-show" | "show" | "fields" | "field";
|
|
12
19
|
export interface WritableLike {
|
|
13
20
|
isTTY?: boolean;
|
|
14
21
|
write(chunk: string): void;
|
|
@@ -88,9 +95,22 @@ export interface CliRunnerContext {
|
|
|
88
95
|
dataDir?: string;
|
|
89
96
|
progressOutput?: ProgressOutput;
|
|
90
97
|
}) => Promise<ManagedClientLike>;
|
|
98
|
+
attachManagedBitcoindService?: typeof attachOrStartManagedBitcoindService;
|
|
99
|
+
probeManagedBitcoindService?: typeof probeManagedBitcoindService;
|
|
100
|
+
stopManagedBitcoindService?: typeof stopManagedBitcoindService;
|
|
101
|
+
createBitcoinRpcClient?: typeof createRpcClient;
|
|
102
|
+
attachIndexerDaemon?: typeof attachOrStartIndexerDaemon;
|
|
103
|
+
probeIndexerDaemon?: typeof probeIndexerDaemon;
|
|
104
|
+
readObservedIndexerDaemonStatus?: typeof readObservedIndexerDaemonStatus;
|
|
105
|
+
stopIndexerDaemonService?: typeof stopIndexerDaemonService;
|
|
91
106
|
inspectPassiveClientStatus?: typeof inspectPassiveClientStatus;
|
|
92
107
|
openWalletReadContext?: typeof openWalletReadContext;
|
|
108
|
+
loadWalletState?: typeof loadWalletState;
|
|
109
|
+
loadUnlockSession?: typeof loadUnlockSession;
|
|
110
|
+
loadWalletExplicitLock?: typeof loadWalletExplicitLock;
|
|
93
111
|
initializeWallet?: typeof initializeWallet;
|
|
112
|
+
restoreWalletFromMnemonic?: typeof restoreWalletFromMnemonic;
|
|
113
|
+
previewResetWallet?: typeof previewResetWallet;
|
|
94
114
|
exportWallet?: typeof exportWallet;
|
|
95
115
|
importWallet?: typeof importWallet;
|
|
96
116
|
unlockWallet?: typeof unlockWallet;
|
|
@@ -126,12 +146,14 @@ export interface CliRunnerContext {
|
|
|
126
146
|
readMiningLog?: typeof readMiningLog;
|
|
127
147
|
followMiningLog?: typeof followMiningLog;
|
|
128
148
|
repairWallet?: typeof repairWallet;
|
|
149
|
+
resetWallet?: typeof resetWallet;
|
|
129
150
|
walletSecretProvider?: WalletSecretProvider;
|
|
130
151
|
createPrompter?: () => WalletPrompter;
|
|
131
152
|
ensureDirectory?: (path: string) => Promise<void>;
|
|
132
153
|
readPackageVersion?: () => Promise<string>;
|
|
133
154
|
resolveDefaultBitcoindDataDir?: () => string;
|
|
134
155
|
resolveDefaultClientDatabasePath?: () => string;
|
|
156
|
+
resolveWalletRuntimePaths?: () => WalletRuntimePaths;
|
|
135
157
|
}
|
|
136
158
|
export interface StopSignalWatcher {
|
|
137
159
|
cleanup(): void;
|
package/dist/cli/types.js
CHANGED
|
@@ -1,2 +1,8 @@
|
|
|
1
1
|
import { openManagedBitcoindClient } from "../bitcoind/index.js";
|
|
2
|
+
import { createRpcClient } from "../bitcoind/node.js";
|
|
3
|
+
import { attachOrStartIndexerDaemon, probeIndexerDaemon, readObservedIndexerDaemonStatus, stopIndexerDaemonService, } from "../bitcoind/indexer-daemon.js";
|
|
4
|
+
import { attachOrStartManagedBitcoindService, probeManagedBitcoindService, stopManagedBitcoindService, } from "../bitcoind/service.js";
|
|
2
5
|
import { openSqliteStore } from "../sqlite/index.js";
|
|
6
|
+
import { loadWalletExplicitLock } from "../wallet/state/explicit-lock.js";
|
|
7
|
+
import { loadUnlockSession } from "../wallet/state/session.js";
|
|
8
|
+
import { loadWalletState } from "../wallet/state/storage.js";
|
|
@@ -75,6 +75,9 @@ function formatPendingMutationDomainLabel(mutation) {
|
|
|
75
75
|
return kind;
|
|
76
76
|
}
|
|
77
77
|
export function getRepairRecommendation(context) {
|
|
78
|
+
if (context.localState.availability === "uninitialized") {
|
|
79
|
+
return "Run `cogcoin init` to create a new local wallet root.";
|
|
80
|
+
}
|
|
78
81
|
if (context.localState.availability === "local-state-corrupt") {
|
|
79
82
|
return "Run `cogcoin repair` to recover local wallet state.";
|
|
80
83
|
}
|
|
@@ -2,6 +2,7 @@ import type { WalletIdentityView, WalletLockView, WalletReadContext } from "../w
|
|
|
2
2
|
export declare function formatNextStepLines(nextSteps: readonly string[]): string[];
|
|
3
3
|
export declare function getFundingQuickstartGuidance(): string;
|
|
4
4
|
export declare function getInitNextSteps(): string[];
|
|
5
|
+
export declare function getRestoreNextSteps(): string[];
|
|
5
6
|
export declare function getBootstrapSyncNextStep(context: Pick<WalletReadContext, "bitcoind" | "indexer" | "nodeHealth">): string | null;
|
|
6
7
|
export declare function getRegisterNextSteps(domainName: string, registerKind: "root" | "subdomain"): string[];
|
|
7
8
|
export declare function getAnchorNextSteps(domainName: string): string[];
|
|
@@ -10,6 +10,9 @@ export function getFundingQuickstartGuidance() {
|
|
|
10
10
|
export function getInitNextSteps() {
|
|
11
11
|
return ["cogcoin sync", "cogcoin address"];
|
|
12
12
|
}
|
|
13
|
+
export function getRestoreNextSteps() {
|
|
14
|
+
return ["cogcoin sync", "cogcoin address"];
|
|
15
|
+
}
|
|
13
16
|
function blocksSyncBootstrap(context) {
|
|
14
17
|
return context.bitcoind.health === "service-version-mismatch"
|
|
15
18
|
|| context.bitcoind.health === "wallet-root-mismatch"
|
package/dist/wallet/fs/lock.d.ts
CHANGED
|
@@ -16,4 +16,6 @@ export declare class FileLockBusyError extends Error {
|
|
|
16
16
|
constructor(lockPath: string, existingMetadata: FileLockMetadata | null);
|
|
17
17
|
}
|
|
18
18
|
export declare function readLockMetadata(lockPath: string): Promise<FileLockMetadata | null>;
|
|
19
|
+
export declare function clearLockIfOwnedByCurrentProcess(lockPath: string): Promise<boolean>;
|
|
20
|
+
export declare function clearOrphanedFileLock(lockPath: string, isProcessAlive: (pid: number) => Promise<boolean>): Promise<boolean>;
|
|
19
21
|
export declare function acquireFileLock(lockPath: string, metadata?: Partial<FileLockMetadata>): Promise<FileLockHandle>;
|
package/dist/wallet/fs/lock.js
CHANGED
|
@@ -22,6 +22,38 @@ export async function readLockMetadata(lockPath) {
|
|
|
22
22
|
throw error;
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
|
+
export async function clearLockIfOwnedByCurrentProcess(lockPath) {
|
|
26
|
+
const metadata = await readLockMetadata(lockPath);
|
|
27
|
+
if (metadata === null || metadata.processId !== (process.pid ?? null)) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
await rm(lockPath, { force: true });
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
export async function clearOrphanedFileLock(lockPath, isProcessAlive) {
|
|
34
|
+
let metadata = null;
|
|
35
|
+
try {
|
|
36
|
+
metadata = await readLockMetadata(lockPath);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
await rm(lockPath, { force: true });
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
if (metadata === null) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
const processId = typeof metadata.processId === "number" && Number.isInteger(metadata.processId)
|
|
49
|
+
? metadata.processId
|
|
50
|
+
: null;
|
|
51
|
+
if (processId === null || !await isProcessAlive(processId)) {
|
|
52
|
+
await rm(lockPath, { force: true });
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
25
57
|
export async function acquireFileLock(lockPath, metadata = {}) {
|
|
26
58
|
await mkdir(dirname(lockPath), { recursive: true });
|
|
27
59
|
const fullMetadata = {
|
|
@@ -11,6 +11,7 @@ export interface WalletPrompter {
|
|
|
11
11
|
readonly isInteractive: boolean;
|
|
12
12
|
writeLine(message: string): void;
|
|
13
13
|
prompt(message: string): Promise<string>;
|
|
14
|
+
promptHidden?(message: string): Promise<string>;
|
|
14
15
|
clearSensitiveDisplay?(scope: "mnemonic-reveal"): void | Promise<void>;
|
|
15
16
|
}
|
|
16
17
|
export interface WalletInitializationResult {
|
|
@@ -40,6 +41,13 @@ export interface WalletImportResult {
|
|
|
40
41
|
unlockUntilUnixMs: number;
|
|
41
42
|
state: WalletStateV1;
|
|
42
43
|
}
|
|
44
|
+
export interface WalletRestoreResult {
|
|
45
|
+
walletRootId: string;
|
|
46
|
+
fundingAddress: string;
|
|
47
|
+
unlockUntilUnixMs: number;
|
|
48
|
+
state: WalletStateV1;
|
|
49
|
+
warnings?: string[];
|
|
50
|
+
}
|
|
43
51
|
export interface WalletRepairResult {
|
|
44
52
|
walletRootId: string;
|
|
45
53
|
recoveredFromBackup: boolean;
|
|
@@ -58,6 +66,7 @@ export interface WalletRepairResult {
|
|
|
58
66
|
miningResumeError: string | null;
|
|
59
67
|
note: string | null;
|
|
60
68
|
}
|
|
69
|
+
export { previewResetWallet, resetWallet, type WalletResetPreview, type WalletResetResult, } from "./reset.js";
|
|
61
70
|
interface WalletLifecycleRpcClient {
|
|
62
71
|
getDescriptorInfo(descriptor: string): Promise<{
|
|
63
72
|
descriptor: string;
|
|
@@ -189,6 +198,16 @@ export declare function importWallet(options: {
|
|
|
189
198
|
attachIndexerDaemon?: typeof attachOrStartIndexerDaemon;
|
|
190
199
|
rpcFactory?: (config: Parameters<typeof createRpcClient>[0]) => WalletLifecycleRpcClient;
|
|
191
200
|
}): Promise<WalletImportResult>;
|
|
201
|
+
export declare function restoreWalletFromMnemonic(options: {
|
|
202
|
+
dataDir: string;
|
|
203
|
+
provider?: WalletSecretProvider;
|
|
204
|
+
prompter: WalletPrompter;
|
|
205
|
+
nowUnixMs?: number;
|
|
206
|
+
unlockDurationMs?: number;
|
|
207
|
+
paths?: WalletRuntimePaths;
|
|
208
|
+
attachService?: typeof attachOrStartManagedBitcoindService;
|
|
209
|
+
rpcFactory?: (config: Parameters<typeof createRpcClient>[0]) => WalletLifecycleRpcClient;
|
|
210
|
+
}): Promise<WalletRestoreResult>;
|
|
192
211
|
export declare function repairWallet(options: {
|
|
193
212
|
dataDir: string;
|
|
194
213
|
databasePath: string;
|
|
@@ -204,4 +223,3 @@ export declare function repairWallet(options: {
|
|
|
204
223
|
requestMiningPreemption?: typeof requestMiningGenerationPreemption;
|
|
205
224
|
startBackgroundMining?: typeof import("./mining/runner.js").startBackgroundMining;
|
|
206
225
|
}): Promise<WalletRepairResult>;
|
|
207
|
-
export {};
|
package/dist/wallet/lifecycle.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
|
-
import { access, constants, mkdir, readFile, rename, rm } from "node:fs/promises";
|
|
2
|
+
import { access, constants, mkdir, readFile, readdir, rename, rm } from "node:fs/promises";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
import { openClient } from "../client.js";
|
|
5
5
|
import { attachOrStartIndexerDaemon, probeIndexerDaemon, readSnapshotWithRetry, } from "../bitcoind/indexer-daemon.js";
|
|
@@ -9,19 +9,21 @@ import { createRpcClient } from "../bitcoind/node.js";
|
|
|
9
9
|
import { openSqliteStore } from "../sqlite/index.js";
|
|
10
10
|
import { readPortableWalletArchive, writePortableWalletArchive } from "./archive.js";
|
|
11
11
|
import { normalizeWalletDescriptorState, persistNormalizedWalletDescriptorStateIfNeeded, persistWalletStateUpdate, resolveNormalizedWalletDescriptorState, stripDescriptorChecksum, } from "./descriptor-normalization.js";
|
|
12
|
-
import { acquireFileLock } from "./fs/lock.js";
|
|
13
|
-
import { createInternalCoreWalletPassphrase, createMnemonicConfirmationChallenge, deriveWalletMaterialFromMnemonic, generateWalletMaterial, } from "./material.js";
|
|
12
|
+
import { acquireFileLock, clearOrphanedFileLock } from "./fs/lock.js";
|
|
13
|
+
import { createInternalCoreWalletPassphrase, createMnemonicConfirmationChallenge, deriveWalletMaterialFromMnemonic, generateWalletMaterial, isEnglishMnemonicWord, validateEnglishMnemonic, } from "./material.js";
|
|
14
14
|
import { resolveWalletRuntimePathsForTesting } from "./runtime.js";
|
|
15
15
|
import { requestMiningGenerationPreemption } from "./mining/coordination.js";
|
|
16
16
|
import { loadClientConfig } from "./mining/config.js";
|
|
17
17
|
import { inspectMiningHookState } from "./mining/hooks.js";
|
|
18
18
|
import { loadMiningRuntimeStatus, saveMiningRuntimeStatus } from "./mining/runtime-artifacts.js";
|
|
19
19
|
import { normalizeMiningStateRecord } from "./mining/state.js";
|
|
20
|
+
import { renderWalletMnemonicRevealArt } from "./mnemonic-art.js";
|
|
20
21
|
import { clearWalletExplicitLock, loadWalletExplicitLock, saveWalletExplicitLock, } from "./state/explicit-lock.js";
|
|
21
22
|
import { clearUnlockSession, loadUnlockSession, saveUnlockSession } from "./state/session.js";
|
|
22
23
|
import { createDefaultWalletSecretProvider, createWalletRootId, createWalletSecretReference, } from "./state/provider.js";
|
|
23
24
|
import { loadWalletState, saveWalletState } from "./state/storage.js";
|
|
24
25
|
export const DEFAULT_UNLOCK_DURATION_MS = 15 * 60 * 1000;
|
|
26
|
+
export { previewResetWallet, resetWallet, } from "./reset.js";
|
|
25
27
|
function sanitizeWalletName(walletRootId) {
|
|
26
28
|
return `cogcoin-${walletRootId}`.replace(/[^a-zA-Z0-9._-]+/g, "-").slice(0, 63);
|
|
27
29
|
}
|
|
@@ -34,6 +36,32 @@ async function pathExists(path) {
|
|
|
34
36
|
return false;
|
|
35
37
|
}
|
|
36
38
|
}
|
|
39
|
+
async function readJsonFileOrNull(path) {
|
|
40
|
+
try {
|
|
41
|
+
return JSON.parse(await readFile(path, "utf8"));
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async function loadRawWalletEnvelope(paths) {
|
|
51
|
+
const primary = await readJsonFileOrNull(paths.walletStatePath);
|
|
52
|
+
if (primary !== null) {
|
|
53
|
+
return primary;
|
|
54
|
+
}
|
|
55
|
+
return readJsonFileOrNull(paths.walletStateBackupPath);
|
|
56
|
+
}
|
|
57
|
+
function extractWalletRootIdFromEnvelope(envelope) {
|
|
58
|
+
const keyId = envelope?.secretProvider?.keyId ?? null;
|
|
59
|
+
const prefix = "wallet-state:";
|
|
60
|
+
if (keyId === null || !keyId.startsWith(prefix)) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
return keyId.slice(prefix.length);
|
|
64
|
+
}
|
|
37
65
|
function createInitialWalletState(options) {
|
|
38
66
|
return {
|
|
39
67
|
schemaVersion: 1,
|
|
@@ -294,6 +322,12 @@ async function promptRequiredValue(prompter, message) {
|
|
|
294
322
|
}
|
|
295
323
|
return value;
|
|
296
324
|
}
|
|
325
|
+
async function promptHiddenValue(prompter, message) {
|
|
326
|
+
const value = prompter.promptHidden != null
|
|
327
|
+
? await prompter.promptHidden(message)
|
|
328
|
+
: await prompter.prompt(message);
|
|
329
|
+
return value.trim();
|
|
330
|
+
}
|
|
297
331
|
async function promptForArchivePassphrase(prompter, promptPrefix) {
|
|
298
332
|
const first = await promptRequiredValue(prompter, `${promptPrefix} passphrase: `);
|
|
299
333
|
const second = await promptRequiredValue(prompter, `Confirm ${promptPrefix.toLowerCase()} passphrase: `);
|
|
@@ -302,12 +336,33 @@ async function promptForArchivePassphrase(prompter, promptPrefix) {
|
|
|
302
336
|
}
|
|
303
337
|
return first;
|
|
304
338
|
}
|
|
339
|
+
async function promptForRestoreMnemonic(prompter) {
|
|
340
|
+
const words = [];
|
|
341
|
+
for (let index = 0; index < 24; index += 1) {
|
|
342
|
+
const word = (await promptHiddenValue(prompter, `Word ${index + 1} of 24: `)).toLowerCase();
|
|
343
|
+
if (!isEnglishMnemonicWord(word)) {
|
|
344
|
+
throw new Error("wallet_restore_mnemonic_invalid");
|
|
345
|
+
}
|
|
346
|
+
words.push(word);
|
|
347
|
+
}
|
|
348
|
+
const phrase = words.join(" ");
|
|
349
|
+
if (!validateEnglishMnemonic(phrase)) {
|
|
350
|
+
throw new Error("wallet_restore_mnemonic_invalid");
|
|
351
|
+
}
|
|
352
|
+
return phrase;
|
|
353
|
+
}
|
|
305
354
|
async function confirmTypedAcknowledgement(prompter, expected, message) {
|
|
306
355
|
const answer = (await prompter.prompt(message)).trim();
|
|
307
356
|
if (answer !== expected) {
|
|
308
357
|
throw new Error("wallet_typed_confirmation_rejected");
|
|
309
358
|
}
|
|
310
359
|
}
|
|
360
|
+
async function confirmRestoreReplacement(prompter) {
|
|
361
|
+
const answer = (await prompter.prompt("Type \"RESTORE\" to replace the existing local wallet state and managed Core wallet replica: ")).trim();
|
|
362
|
+
if (answer !== "RESTORE") {
|
|
363
|
+
throw new Error("wallet_restore_replace_confirmation_required");
|
|
364
|
+
}
|
|
365
|
+
}
|
|
311
366
|
async function confirmOverwriteIfNeeded(prompter, path) {
|
|
312
367
|
if (!await pathExists(path)) {
|
|
313
368
|
return;
|
|
@@ -516,6 +571,86 @@ async function clearManagedBitcoindArtifacts(servicePaths) {
|
|
|
516
571
|
await rm(servicePaths.bitcoindReadyPath, { force: true }).catch(() => undefined);
|
|
517
572
|
await rm(servicePaths.bitcoindWalletStatusPath, { force: true }).catch(() => undefined);
|
|
518
573
|
}
|
|
574
|
+
async function detectExistingManagedWalletReplica(dataDir) {
|
|
575
|
+
try {
|
|
576
|
+
const entries = await readdir(join(dataDir, "wallets"), { withFileTypes: true });
|
|
577
|
+
return entries.some((entry) => entry.isDirectory() && entry.name.startsWith("cogcoin-"));
|
|
578
|
+
}
|
|
579
|
+
catch (error) {
|
|
580
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
581
|
+
return false;
|
|
582
|
+
}
|
|
583
|
+
throw error;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
async function stopRecordedManagedProcess(pid, errorCode) {
|
|
587
|
+
if (pid === null || !await isProcessAlive(pid)) {
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
try {
|
|
591
|
+
process.kill(pid, "SIGTERM");
|
|
592
|
+
}
|
|
593
|
+
catch (error) {
|
|
594
|
+
if (!(error instanceof Error && "code" in error && error.code === "ESRCH")) {
|
|
595
|
+
throw error;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
try {
|
|
599
|
+
await waitForProcessExit(pid, 5_000, errorCode);
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
catch {
|
|
603
|
+
try {
|
|
604
|
+
process.kill(pid, "SIGKILL");
|
|
605
|
+
}
|
|
606
|
+
catch (error) {
|
|
607
|
+
if (!(error instanceof Error && "code" in error && error.code === "ESRCH")) {
|
|
608
|
+
throw error;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
await waitForProcessExit(pid, 5_000, errorCode);
|
|
613
|
+
}
|
|
614
|
+
async function clearOrphanedRepairLocks(lockPaths) {
|
|
615
|
+
for (const lockPath of lockPaths) {
|
|
616
|
+
await clearOrphanedFileLock(lockPath, isProcessAlive);
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
async function clearPreviousManagedWalletRuntime(options) {
|
|
620
|
+
if (options.walletRootId === null) {
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
const servicePaths = resolveManagedServicePaths(options.dataDir, options.walletRootId);
|
|
624
|
+
const bitcoindLock = await acquireFileLock(servicePaths.bitcoindLockPath, {
|
|
625
|
+
purpose: "wallet-restore-cleanup",
|
|
626
|
+
walletRootId: options.walletRootId,
|
|
627
|
+
});
|
|
628
|
+
const indexerLock = await acquireFileLock(servicePaths.indexerDaemonLockPath, {
|
|
629
|
+
purpose: "wallet-restore-cleanup",
|
|
630
|
+
walletRootId: options.walletRootId,
|
|
631
|
+
});
|
|
632
|
+
try {
|
|
633
|
+
const bitcoindStatus = await readJsonFileOrNull(servicePaths.bitcoindStatusPath);
|
|
634
|
+
const indexerStatus = await readJsonFileOrNull(servicePaths.indexerDaemonStatusPath);
|
|
635
|
+
await stopRecordedManagedProcess(bitcoindStatus?.processId ?? null, "managed_bitcoind_stop_timeout");
|
|
636
|
+
await stopRecordedManagedProcess(indexerStatus?.processId ?? null, "indexer_daemon_stop_timeout");
|
|
637
|
+
await clearManagedBitcoindArtifacts(servicePaths);
|
|
638
|
+
await clearIndexerDaemonArtifacts(servicePaths);
|
|
639
|
+
await rm(servicePaths.walletRuntimeRoot, { recursive: true, force: true }).catch(() => undefined);
|
|
640
|
+
await rm(servicePaths.indexerServiceRoot, { recursive: true, force: true }).catch(() => undefined);
|
|
641
|
+
await rm(join(options.dataDir, "wallets", sanitizeWalletName(options.walletRootId)), { recursive: true, force: true }).catch(() => undefined);
|
|
642
|
+
}
|
|
643
|
+
finally {
|
|
644
|
+
await indexerLock.release();
|
|
645
|
+
await bitcoindLock.release();
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
function formatRestoreCleanupWarning(error) {
|
|
649
|
+
const reason = error instanceof Error && error.message.trim().length > 0
|
|
650
|
+
? ` (${error.message})`
|
|
651
|
+
: "";
|
|
652
|
+
return `Previous managed runtime cleanup did not complete${reason}. Run \`cogcoin repair\` if status shows stale or conflicting managed services.`;
|
|
653
|
+
}
|
|
519
654
|
function createSilentNonInteractivePrompter() {
|
|
520
655
|
return {
|
|
521
656
|
isInteractive: false,
|
|
@@ -949,6 +1084,11 @@ export async function initializeWallet(options) {
|
|
|
949
1084
|
let mnemonicRevealed = false;
|
|
950
1085
|
options.prompter.writeLine("Cogcoin Wallet Initialization");
|
|
951
1086
|
options.prompter.writeLine("Write down this 24-word recovery phrase. It will only be shown once:");
|
|
1087
|
+
options.prompter.writeLine("");
|
|
1088
|
+
for (const line of renderWalletMnemonicRevealArt(material.mnemonic.words)) {
|
|
1089
|
+
options.prompter.writeLine(line);
|
|
1090
|
+
}
|
|
1091
|
+
options.prompter.writeLine("Single-line copy:");
|
|
952
1092
|
options.prompter.writeLine(material.mnemonic.phrase);
|
|
953
1093
|
mnemonicRevealed = true;
|
|
954
1094
|
try {
|
|
@@ -1213,6 +1353,106 @@ export async function importWallet(options) {
|
|
|
1213
1353
|
await controlLock.release();
|
|
1214
1354
|
}
|
|
1215
1355
|
}
|
|
1356
|
+
export async function restoreWalletFromMnemonic(options) {
|
|
1357
|
+
if (!options.prompter.isInteractive) {
|
|
1358
|
+
throw new Error("wallet_restore_requires_tty");
|
|
1359
|
+
}
|
|
1360
|
+
const provider = options.provider ?? createDefaultWalletSecretProvider();
|
|
1361
|
+
const nowUnixMs = options.nowUnixMs ?? Date.now();
|
|
1362
|
+
const unlockDurationMs = options.unlockDurationMs ?? DEFAULT_UNLOCK_DURATION_MS;
|
|
1363
|
+
const paths = options.paths ?? resolveWalletRuntimePathsForTesting();
|
|
1364
|
+
const controlLock = await acquireFileLock(paths.walletControlLockPath, {
|
|
1365
|
+
purpose: "wallet-restore",
|
|
1366
|
+
walletRootId: null,
|
|
1367
|
+
});
|
|
1368
|
+
try {
|
|
1369
|
+
const rawEnvelope = await loadRawWalletEnvelope(paths);
|
|
1370
|
+
const replacementStateExists = rawEnvelope !== null
|
|
1371
|
+
|| await pathExists(paths.walletStatePath)
|
|
1372
|
+
|| await pathExists(paths.walletStateBackupPath);
|
|
1373
|
+
const replacementCoreWalletExists = await detectExistingManagedWalletReplica(options.dataDir);
|
|
1374
|
+
const mnemonicPhrase = await promptForRestoreMnemonic(options.prompter);
|
|
1375
|
+
if (replacementStateExists || replacementCoreWalletExists) {
|
|
1376
|
+
await confirmRestoreReplacement(options.prompter);
|
|
1377
|
+
}
|
|
1378
|
+
let previousWalletRootId = extractWalletRootIdFromEnvelope(rawEnvelope);
|
|
1379
|
+
try {
|
|
1380
|
+
const loaded = await loadWalletState({
|
|
1381
|
+
primaryPath: paths.walletStatePath,
|
|
1382
|
+
backupPath: paths.walletStateBackupPath,
|
|
1383
|
+
}, {
|
|
1384
|
+
provider,
|
|
1385
|
+
});
|
|
1386
|
+
previousWalletRootId = loaded.state.walletRootId;
|
|
1387
|
+
}
|
|
1388
|
+
catch {
|
|
1389
|
+
previousWalletRootId = previousWalletRootId ?? null;
|
|
1390
|
+
}
|
|
1391
|
+
const miningLock = await acquireFileLock(paths.miningControlLockPath, {
|
|
1392
|
+
purpose: "wallet-restore",
|
|
1393
|
+
walletRootId: previousWalletRootId,
|
|
1394
|
+
});
|
|
1395
|
+
try {
|
|
1396
|
+
const warnings = [];
|
|
1397
|
+
const material = deriveWalletMaterialFromMnemonic(mnemonicPhrase);
|
|
1398
|
+
const walletRootId = createWalletRootId();
|
|
1399
|
+
const internalCoreWalletPassphrase = createInternalCoreWalletPassphrase();
|
|
1400
|
+
const secretReference = createWalletSecretReference(walletRootId);
|
|
1401
|
+
const secret = randomBytes(32);
|
|
1402
|
+
await provider.storeSecret(secretReference.keyId, secret);
|
|
1403
|
+
const initialState = createInitialWalletState({
|
|
1404
|
+
walletRootId,
|
|
1405
|
+
nowUnixMs,
|
|
1406
|
+
material,
|
|
1407
|
+
internalCoreWalletPassphrase,
|
|
1408
|
+
});
|
|
1409
|
+
await clearUnlockSession(paths.walletUnlockSessionPath);
|
|
1410
|
+
await clearWalletExplicitLock(paths.walletExplicitLockPath);
|
|
1411
|
+
await saveWalletState({
|
|
1412
|
+
primaryPath: paths.walletStatePath,
|
|
1413
|
+
backupPath: paths.walletStateBackupPath,
|
|
1414
|
+
}, initialState, {
|
|
1415
|
+
provider,
|
|
1416
|
+
secretReference,
|
|
1417
|
+
});
|
|
1418
|
+
const restoredState = await recreateManagedCoreWalletReplica(initialState, provider, paths, options.dataDir, nowUnixMs, {
|
|
1419
|
+
attachService: options.attachService,
|
|
1420
|
+
rpcFactory: options.rpcFactory,
|
|
1421
|
+
});
|
|
1422
|
+
const unlockUntilUnixMs = nowUnixMs + unlockDurationMs;
|
|
1423
|
+
await clearWalletExplicitLock(paths.walletExplicitLockPath);
|
|
1424
|
+
await saveUnlockSession(paths.walletUnlockSessionPath, createUnlockSession(restoredState, unlockUntilUnixMs, secretReference.keyId, nowUnixMs), {
|
|
1425
|
+
provider,
|
|
1426
|
+
secretReference,
|
|
1427
|
+
});
|
|
1428
|
+
if (previousWalletRootId !== null && previousWalletRootId !== walletRootId) {
|
|
1429
|
+
try {
|
|
1430
|
+
await clearPreviousManagedWalletRuntime({
|
|
1431
|
+
dataDir: options.dataDir,
|
|
1432
|
+
walletRootId: previousWalletRootId,
|
|
1433
|
+
});
|
|
1434
|
+
}
|
|
1435
|
+
catch (error) {
|
|
1436
|
+
warnings.push(formatRestoreCleanupWarning(error));
|
|
1437
|
+
}
|
|
1438
|
+
await provider.deleteSecret(createWalletSecretReference(previousWalletRootId).keyId).catch(() => undefined);
|
|
1439
|
+
}
|
|
1440
|
+
return {
|
|
1441
|
+
walletRootId,
|
|
1442
|
+
fundingAddress: restoredState.funding.address,
|
|
1443
|
+
unlockUntilUnixMs,
|
|
1444
|
+
state: restoredState,
|
|
1445
|
+
warnings,
|
|
1446
|
+
};
|
|
1447
|
+
}
|
|
1448
|
+
finally {
|
|
1449
|
+
await miningLock.release();
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
finally {
|
|
1453
|
+
await controlLock.release();
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1216
1456
|
export async function repairWallet(options) {
|
|
1217
1457
|
const provider = options.provider ?? createDefaultWalletSecretProvider();
|
|
1218
1458
|
const nowUnixMs = options.nowUnixMs ?? Date.now();
|
|
@@ -1222,6 +1462,10 @@ export async function repairWallet(options) {
|
|
|
1222
1462
|
const probeManagedIndexerDaemon = options.probeIndexerDaemon ?? probeIndexerDaemon;
|
|
1223
1463
|
const attachManagedIndexerDaemon = options.attachIndexerDaemon ?? attachOrStartIndexerDaemon;
|
|
1224
1464
|
const requestMiningPreemptionForRepair = options.requestMiningPreemption ?? requestMiningGenerationPreemption;
|
|
1465
|
+
await clearOrphanedRepairLocks([
|
|
1466
|
+
paths.walletControlLockPath,
|
|
1467
|
+
paths.miningControlLockPath,
|
|
1468
|
+
]);
|
|
1225
1469
|
const controlLock = await acquireFileLock(paths.walletControlLockPath, {
|
|
1226
1470
|
purpose: "wallet-repair",
|
|
1227
1471
|
walletRootId: null,
|
|
@@ -1245,6 +1489,10 @@ export async function repairWallet(options) {
|
|
|
1245
1489
|
let repairedState = loaded.state;
|
|
1246
1490
|
let repairStateNeedsPersist = false;
|
|
1247
1491
|
const servicePaths = resolveManagedServicePaths(options.dataDir, repairedState.walletRootId);
|
|
1492
|
+
await clearOrphanedRepairLocks([
|
|
1493
|
+
servicePaths.bitcoindLockPath,
|
|
1494
|
+
servicePaths.indexerDaemonLockPath,
|
|
1495
|
+
]);
|
|
1248
1496
|
const preRepairMiningRuntime = await loadMiningRuntimeStatus(paths.miningStatusPath).catch(() => null);
|
|
1249
1497
|
const backgroundWorkerAlive = preRepairMiningRuntime?.runMode === "background"
|
|
1250
1498
|
&& preRepairMiningRuntime.backgroundWorkerPid !== null
|
|
@@ -36,6 +36,8 @@ export interface WalletDerivedIdentity {
|
|
|
36
36
|
nostrNpub: string;
|
|
37
37
|
}
|
|
38
38
|
export declare function generateWalletMaterial(): WalletMaterial;
|
|
39
|
+
export declare function isEnglishMnemonicWord(word: string): boolean;
|
|
40
|
+
export declare function validateEnglishMnemonic(phrase: string): boolean;
|
|
39
41
|
export declare function deriveWalletMaterialFromMnemonic(phrase: string): WalletMaterial;
|
|
40
42
|
export declare function deriveWalletIdentityMaterial(accountKey: string, index: number): WalletDerivedIdentity;
|
|
41
43
|
export declare function createInternalCoreWalletPassphrase(): string;
|