@cogcoin/client 0.5.2 → 0.5.3
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 -1
- package/dist/app-paths.d.ts +1 -0
- package/dist/app-paths.js +2 -0
- package/dist/cli/output.js +1 -1
- package/dist/cli/parse.d.ts +1 -1
- package/dist/cli/parse.js +4 -4
- package/dist/wallet/lifecycle.d.ts +11 -0
- package/dist/wallet/lifecycle.js +143 -37
- package/dist/wallet/mining/control.js +4 -4
- package/dist/wallet/mining/runner.js +2 -2
- package/dist/wallet/read/context.d.ts +2 -0
- package/dist/wallet/read/context.js +64 -17
- package/dist/wallet/runtime.d.ts +1 -0
- package/dist/wallet/runtime.js +1 -0
- package/dist/wallet/state/explicit-lock.d.ts +4 -0
- package/dist/wallet/state/explicit-lock.js +19 -0
- package/dist/wallet/tx/anchor.js +1 -0
- package/dist/wallet/tx/cog.js +3 -0
- package/dist/wallet/tx/domain-admin.js +1 -0
- package/dist/wallet/tx/domain-market.js +3 -0
- package/dist/wallet/tx/field.js +2 -0
- package/dist/wallet/tx/register.js +1 -0
- package/dist/wallet/tx/reputation.js +1 -0
- package/dist/wallet/types.d.ts +5 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# `@cogcoin/client`
|
|
2
2
|
|
|
3
|
-
`@cogcoin/client@0.5.
|
|
3
|
+
`@cogcoin/client@0.5.3` is the store-backed Cogcoin client package for applications that want a local wallet, durable SQLite-backed state, and a managed Bitcoin Core integration around `@cogcoin/indexer`. It publishes the reusable client APIs, the SQLite adapter, the managed `bitcoind` integration, and the first-party `cogcoin` CLI in one package.
|
|
4
4
|
|
|
5
5
|
Use Node 22 or newer.
|
|
6
6
|
|
|
@@ -32,6 +32,8 @@ npx cogcoin sync
|
|
|
32
32
|
|
|
33
33
|
Verify the installed genesis artifacts before using the client in a production implementation.
|
|
34
34
|
The installed package provides the `cogcoin` command for local wallet setup, sync, reads, writes, and mining workflows.
|
|
35
|
+
Provider-backed local wallets unlock on demand by default; `cogcoin wallet lock` suppresses that behavior until `cogcoin unlock` is run again.
|
|
36
|
+
Passphrase-wrapped wallet-state flows still require explicit passphrase-based access.
|
|
35
37
|
|
|
36
38
|
## Dependency Surface
|
|
37
39
|
|
|
@@ -79,6 +81,7 @@ The installed `cogcoin` command covers the first-party local wallet and node wor
|
|
|
79
81
|
- mining and hook commands such as `mine`, `mine start`, `mine stop`, `mine status`, `mine log`, `mine setup`, and `hooks status`
|
|
80
82
|
|
|
81
83
|
The CLI also supports stable `--output json` and `--output preview-json` envelopes on the commands that advertise machine-readable output.
|
|
84
|
+
For provider-backed local wallets, normal reads, mutations, export, and mining setup flows auto-materialize a local unlock session when the wallet is not explicitly locked.
|
|
82
85
|
|
|
83
86
|
## SQLite Store
|
|
84
87
|
|
package/dist/app-paths.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ export interface CogcoinResolvedPaths {
|
|
|
18
18
|
walletStatePath: string;
|
|
19
19
|
walletStateBackupPath: string;
|
|
20
20
|
walletUnlockSessionPath: string;
|
|
21
|
+
walletExplicitLockPath: string;
|
|
21
22
|
walletControlLockPath: string;
|
|
22
23
|
bitcoindLockPath: string;
|
|
23
24
|
bitcoindStatusPath: string;
|
package/dist/app-paths.js
CHANGED
|
@@ -64,6 +64,7 @@ export function resolveCogcoinPathsForTesting(resolution = {}) {
|
|
|
64
64
|
const walletStatePath = joinForPlatform(platform, walletStateDirectory, "wallet-state.enc");
|
|
65
65
|
const walletStateBackupPath = joinForPlatform(platform, walletStateDirectory, "wallet-state.enc.bak");
|
|
66
66
|
const walletUnlockSessionPath = joinForPlatform(platform, runtimeRoot, "wallet-unlock-session.enc");
|
|
67
|
+
const walletExplicitLockPath = joinForPlatform(platform, runtimeRoot, "wallet-explicit-lock.json");
|
|
67
68
|
const walletControlLockPath = joinForPlatform(platform, runtimeRoot, "wallet-control.lock");
|
|
68
69
|
const bitcoindLockPath = joinForPlatform(platform, runtimeRoot, "bitcoind.lock");
|
|
69
70
|
const bitcoindStatusPath = joinForPlatform(platform, runtimeRoot, "bitcoind-status.json");
|
|
@@ -91,6 +92,7 @@ export function resolveCogcoinPathsForTesting(resolution = {}) {
|
|
|
91
92
|
walletStatePath,
|
|
92
93
|
walletStateBackupPath,
|
|
93
94
|
walletUnlockSessionPath,
|
|
95
|
+
walletExplicitLockPath,
|
|
94
96
|
walletControlLockPath,
|
|
95
97
|
bitcoindLockPath,
|
|
96
98
|
bitcoindStatusPath,
|
package/dist/cli/output.js
CHANGED
|
@@ -211,7 +211,7 @@ export function createCliErrorPresentation(errorCode, fallbackMessage) {
|
|
|
211
211
|
if (errorCode === "wallet_locked") {
|
|
212
212
|
return {
|
|
213
213
|
what: "Wallet is locked.",
|
|
214
|
-
why: "This command needs access to the unlocked local wallet state before it can continue.",
|
|
214
|
+
why: "This command needs access to the unlocked local wallet state before it can continue. Provider-backed wallets unlock on demand unless they were explicitly locked or the local secret store is unavailable.",
|
|
215
215
|
next: "Run `cogcoin unlock --for 15m` and retry.",
|
|
216
216
|
};
|
|
217
217
|
}
|
package/dist/cli/parse.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { ParsedCliArgs } from "./types.js";
|
|
2
|
-
export declare const HELP_TEXT = "Usage: cogcoin <command> [options]\n\nCommands:\n status Show wallet-aware local service and chain status\n status --output json Emit the stable v1 machine-readable status envelope\n init Initialize a new local wallet root\n init --output json Emit the stable v1 machine-readable init result envelope\n repair Recover bounded wallet/indexer/runtime state\n unlock
|
|
2
|
+
export declare const HELP_TEXT = "Usage: cogcoin <command> [options]\n\nCommands:\n status Show wallet-aware local service and chain status\n status --output json Emit the stable v1 machine-readable status envelope\n init Initialize a new local wallet root\n init --output json Emit the stable v1 machine-readable init result envelope\n repair Recover bounded wallet/indexer/runtime state\n unlock Clear an explicit wallet lock and unlock for a limited duration\n wallet address Alias for address\n wallet ids Alias for ids\n hooks enable mining Enable a validated custom mining hook\n hooks disable mining Return to built-in mining hooks\n hooks status Show mining hook validation and trust status\n mine Run the miner in the foreground\n mine start Start the miner as a background worker\n mine stop Stop the active background miner\n mine setup Configure the built-in mining provider\n mine setup --output json\n Emit the stable v1 machine-readable mine setup result envelope\n mine status Show mining control-plane health and readiness\n mine log Show recent mining control-plane events\n anchor <domain> Anchor an owned unanchored domain with the Tx1/Tx2 family\n register <domain> [--from <identity>]\n Register a root domain or subdomain\n transfer <domain> --to <btc-target>\n Transfer an unanchored domain to another BTC identity\n sell <domain> <price> List an unanchored domain for sale in COG\n unsell <domain> Clear an active domain listing\n buy <domain> [--from <identity>]\n Buy an unanchored listed domain in COG\n send <amount> --to <btc-target>\n Send COG from one local identity to another BTC target\n claim <lock-id> --preimage <32-byte-hex>\n Claim an active COG lock before timeout\n reclaim <lock-id> Reclaim an expired COG lock as the original locker\n cog lock <amount> --to-domain <domain> (--for <blocks-or-duration> | --until-height <height>) --condition <sha256hex>\n Lock COG to an anchored recipient domain\n wallet status Show detailed wallet-local status and service health\n wallet init Initialize a new local wallet root\n wallet unlock Clear an explicit wallet lock and unlock for a limited duration\n wallet lock Lock the local wallet and disable on-demand unlock\n wallet export <path> Export a portable encrypted wallet archive\n wallet import <path> Import a portable encrypted wallet archive\n address Show the BTC funding identity for this wallet\n ids List locally controlled identities\n balance Show per-identity COG balances\n locks Show locally related active COG locks\n domain list Alias for domains\n domain show <domain> Alias for show <domain>\n domains [--anchored] [--listed] [--mineable]\n Show locally related domains\n show <domain> Show one domain and its local-wallet relationship\n fields <domain> List current fields on a domain\n field <domain> <field> Show one current field value\n field create <domain> <field>\n Create a new anchored field, optionally with an initial value\n field set <domain> <field>\n Update an existing anchored field value\n field clear <domain> <field>\n Clear an existing anchored field value\n rep give <source-domain> <target-domain> <amount>\n Burn COG as anchored-domain reputation support\n rep revoke <source-domain> <target-domain> <amount>\n Revoke visible support without refunding burned COG\n\nOptions:\n --db <path> Override the SQLite database path\n --data-dir <path> Override the managed bitcoin datadir\n --for <duration> Unlock duration like 15m, 2h, or 1d when unlocking explicitly\n --message <text> Founding message text for anchor\n --to <btc-target> Transfer or send target as an address or spk:<hex>\n --from <identity> Resolve sender identity as id:<n>, domain:<name>, address, or spk:<hex>\n --to-domain <domain>\n Recipient domain for cog lock\n --condition <sha256hex>\n 32-byte lock condition hash\n --until-height <height>\n Absolute timeout height for cog lock\n --preimage <32-byte-hex>\n Claim preimage for an active lock\n --review <text> Optional public review text for reputation operations\n --text <utf8> UTF-8 payload text for endpoint or field writes\n --json <json> UTF-8 payload JSON text for endpoint or field writes\n --bytes <spec> Payload bytes as hex:<hex> or @<path>\n --permanent Create the field as permanent\n --format <spec> Advanced field format as raw:<u8>\n --value <spec> Advanced field value as hex:<hex>, @<path>, or utf8:<text>\n --claimable Show only currently claimable locks\n --reclaimable Show only currently reclaimable locks\n --anchored Show only anchored domains\n --listed Show only currently listed domains\n --mineable Show only locally mineable root domains\n --limit <n> Limit list rows (1..1000)\n --all Show all rows for list commands\n --verify Run full custom-hook verification\n --follow Follow mining log output\n --output <mode> Output mode: text, json, or preview-json\n --progress <mode> Progress output mode: auto, tty, or none\n --force-race Allow a visible root registration race\n --yes Approve eligible plain yes/no mutation confirmations non-interactively\n --help Show help\n --version Show package version\n\nQuickstart:\n 1. Run `cogcoin init` to create the wallet.\n 2. Run `cogcoin sync` to bootstrap assumeutxo and the managed Bitcoin/indexer state.\n 3. Run `cogcoin address`, then fund the wallet with about 0.0015 BTC so you can buy a 6+ character domain to start mining and still keep BTC available for mining transaction fees.\n\nExamples:\n cogcoin status --output json\n cogcoin init --output json\n cogcoin wallet address\n cogcoin domain list --mineable\n cogcoin register alpha-child\n cogcoin register weatherbot --from id:1\n cogcoin anchor alpha\n cogcoin buy alpha\n cogcoin buy alpha --from id:1\n cogcoin field create alpha bio --text \"hello\"\n cogcoin rep give alpha beta 10 --review \"great operator\"\n cogcoin hooks status\n cogcoin mine setup --output json\n cogcoin register alpha-child --output preview-json\n cogcoin mine status\n";
|
|
3
3
|
export declare function parseCliArgs(argv: string[]): ParsedCliArgs;
|
package/dist/cli/parse.js
CHANGED
|
@@ -7,7 +7,7 @@ Commands:
|
|
|
7
7
|
init Initialize a new local wallet root
|
|
8
8
|
init --output json Emit the stable v1 machine-readable init result envelope
|
|
9
9
|
repair Recover bounded wallet/indexer/runtime state
|
|
10
|
-
unlock
|
|
10
|
+
unlock Clear an explicit wallet lock and unlock for a limited duration
|
|
11
11
|
wallet address Alias for address
|
|
12
12
|
wallet ids Alias for ids
|
|
13
13
|
hooks enable mining Enable a validated custom mining hook
|
|
@@ -39,8 +39,8 @@ Commands:
|
|
|
39
39
|
Lock COG to an anchored recipient domain
|
|
40
40
|
wallet status Show detailed wallet-local status and service health
|
|
41
41
|
wallet init Initialize a new local wallet root
|
|
42
|
-
wallet unlock
|
|
43
|
-
wallet lock Lock the local wallet
|
|
42
|
+
wallet unlock Clear an explicit wallet lock and unlock for a limited duration
|
|
43
|
+
wallet lock Lock the local wallet and disable on-demand unlock
|
|
44
44
|
wallet export <path> Export a portable encrypted wallet archive
|
|
45
45
|
wallet import <path> Import a portable encrypted wallet archive
|
|
46
46
|
address Show the BTC funding identity for this wallet
|
|
@@ -68,7 +68,7 @@ Commands:
|
|
|
68
68
|
Options:
|
|
69
69
|
--db <path> Override the SQLite database path
|
|
70
70
|
--data-dir <path> Override the managed bitcoin datadir
|
|
71
|
-
--for <duration> Unlock duration like 15m, 2h, or 1d
|
|
71
|
+
--for <duration> Unlock duration like 15m, 2h, or 1d when unlocking explicitly
|
|
72
72
|
--message <text> Founding message text for anchor
|
|
73
73
|
--to <btc-target> Transfer or send target as an address or spk:<hex>
|
|
74
74
|
--from <identity> Resolve sender identity as id:<n>, domain:<name>, address, or spk:<hex>
|
|
@@ -127,6 +127,16 @@ export declare function loadUnlockedWalletState(options?: {
|
|
|
127
127
|
attachService?: typeof attachOrStartManagedBitcoindService;
|
|
128
128
|
rpcFactory?: (config: Parameters<typeof createRpcClient>[0]) => WalletLifecycleRpcClient;
|
|
129
129
|
}): Promise<LoadedUnlockedWalletState | null>;
|
|
130
|
+
export declare function loadOrAutoUnlockWalletState(options?: {
|
|
131
|
+
provider?: WalletSecretProvider;
|
|
132
|
+
nowUnixMs?: number;
|
|
133
|
+
unlockDurationMs?: number;
|
|
134
|
+
paths?: WalletRuntimePaths;
|
|
135
|
+
dataDir?: string;
|
|
136
|
+
controlLockHeld?: boolean;
|
|
137
|
+
attachService?: typeof attachOrStartManagedBitcoindService;
|
|
138
|
+
rpcFactory?: (config: Parameters<typeof createRpcClient>[0]) => WalletLifecycleRpcClient;
|
|
139
|
+
}): Promise<LoadedUnlockedWalletState | null>;
|
|
130
140
|
export declare function initializeWallet(options: {
|
|
131
141
|
dataDir: string;
|
|
132
142
|
provider?: WalletSecretProvider;
|
|
@@ -146,6 +156,7 @@ export declare function unlockWallet(options?: {
|
|
|
146
156
|
export declare function lockWallet(options: {
|
|
147
157
|
dataDir: string;
|
|
148
158
|
provider?: WalletSecretProvider;
|
|
159
|
+
nowUnixMs?: number;
|
|
149
160
|
paths?: WalletRuntimePaths;
|
|
150
161
|
attachService?: typeof attachOrStartManagedBitcoindService;
|
|
151
162
|
rpcFactory?: (config: Parameters<typeof createRpcClient>[0]) => WalletLifecycleRpcClient;
|
package/dist/wallet/lifecycle.js
CHANGED
|
@@ -17,6 +17,7 @@ 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 { clearWalletExplicitLock, loadWalletExplicitLock, saveWalletExplicitLock, } from "./state/explicit-lock.js";
|
|
20
21
|
import { clearUnlockSession, loadUnlockSession, saveUnlockSession } from "./state/session.js";
|
|
21
22
|
import { createDefaultWalletSecretProvider, createWalletRootId, createWalletSecretReference, } from "./state/provider.js";
|
|
22
23
|
import { loadWalletState, saveWalletState } from "./state/storage.js";
|
|
@@ -142,6 +143,54 @@ function createUnlockSession(state, unlockUntilUnixMs, secretKeyId, nowUnixMs) {
|
|
|
142
143
|
wrappedSessionKeyMaterial: secretKeyId,
|
|
143
144
|
};
|
|
144
145
|
}
|
|
146
|
+
function createWalletExplicitLock(walletRootId, nowUnixMs) {
|
|
147
|
+
return {
|
|
148
|
+
schemaVersion: 1,
|
|
149
|
+
walletRootId,
|
|
150
|
+
lockedAtUnixMs: nowUnixMs,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
async function normalizeUnlockedWalletStateIfNeeded(options) {
|
|
154
|
+
let state = options.state;
|
|
155
|
+
let session = options.session;
|
|
156
|
+
let source = options.source;
|
|
157
|
+
if (options.dataDir !== undefined) {
|
|
158
|
+
const node = await (options.attachService ?? attachOrStartManagedBitcoindService)({
|
|
159
|
+
dataDir: options.dataDir,
|
|
160
|
+
chain: "main",
|
|
161
|
+
startHeight: 0,
|
|
162
|
+
walletRootId: state.walletRootId,
|
|
163
|
+
});
|
|
164
|
+
try {
|
|
165
|
+
const normalized = await persistNormalizedWalletDescriptorStateIfNeeded({
|
|
166
|
+
state,
|
|
167
|
+
access: {
|
|
168
|
+
provider: options.provider,
|
|
169
|
+
secretReference: createWalletSecretReference(state.walletRootId),
|
|
170
|
+
},
|
|
171
|
+
session,
|
|
172
|
+
paths: options.paths,
|
|
173
|
+
nowUnixMs: options.nowUnixMs,
|
|
174
|
+
replacePrimary: options.source === "backup",
|
|
175
|
+
rpc: (options.rpcFactory ?? createRpcClient)(node.rpc),
|
|
176
|
+
});
|
|
177
|
+
state = normalized.state;
|
|
178
|
+
session = normalized.session ?? session;
|
|
179
|
+
source = normalized.changed ? "primary" : options.source;
|
|
180
|
+
}
|
|
181
|
+
finally {
|
|
182
|
+
await node.stop?.().catch(() => undefined);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
session,
|
|
187
|
+
state: {
|
|
188
|
+
...state,
|
|
189
|
+
miningState: normalizeMiningStateRecord(state.miningState),
|
|
190
|
+
},
|
|
191
|
+
source,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
145
194
|
function createPortableWalletArchivePayload(state, exportedAtUnixMs) {
|
|
146
195
|
return {
|
|
147
196
|
schemaVersion: 1,
|
|
@@ -791,47 +840,95 @@ export async function loadUnlockedWalletState(options = {}) {
|
|
|
791
840
|
await clearUnlockSession(paths.walletUnlockSessionPath);
|
|
792
841
|
return null;
|
|
793
842
|
}
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
843
|
+
return await normalizeUnlockedWalletStateIfNeeded({
|
|
844
|
+
provider,
|
|
845
|
+
session,
|
|
846
|
+
state: loaded.state,
|
|
847
|
+
source: loaded.source,
|
|
848
|
+
nowUnixMs,
|
|
849
|
+
paths,
|
|
850
|
+
dataDir: options.dataDir,
|
|
851
|
+
attachService: options.attachService,
|
|
852
|
+
rpcFactory: options.rpcFactory,
|
|
853
|
+
});
|
|
854
|
+
}
|
|
855
|
+
catch {
|
|
856
|
+
return null;
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
export async function loadOrAutoUnlockWalletState(options = {}) {
|
|
860
|
+
const provider = options.provider ?? createDefaultWalletSecretProvider();
|
|
861
|
+
const nowUnixMs = options.nowUnixMs ?? Date.now();
|
|
862
|
+
const unlockDurationMs = options.unlockDurationMs ?? DEFAULT_UNLOCK_DURATION_MS;
|
|
863
|
+
const paths = options.paths ?? resolveWalletRuntimePathsForTesting();
|
|
864
|
+
const loadExisting = () => loadUnlockedWalletState({
|
|
865
|
+
provider,
|
|
866
|
+
nowUnixMs,
|
|
867
|
+
paths,
|
|
868
|
+
dataDir: options.dataDir,
|
|
869
|
+
attachService: options.attachService,
|
|
870
|
+
rpcFactory: options.rpcFactory,
|
|
871
|
+
});
|
|
872
|
+
const existing = await loadExisting();
|
|
873
|
+
if (existing !== null) {
|
|
874
|
+
return existing;
|
|
875
|
+
}
|
|
876
|
+
const loadAndMaybeAutoUnlock = async () => {
|
|
877
|
+
const reloaded = await loadExisting();
|
|
878
|
+
if (reloaded !== null) {
|
|
879
|
+
return reloaded;
|
|
880
|
+
}
|
|
881
|
+
let loaded;
|
|
882
|
+
try {
|
|
883
|
+
loaded = await loadWalletState({
|
|
884
|
+
primaryPath: paths.walletStatePath,
|
|
885
|
+
backupPath: paths.walletStateBackupPath,
|
|
886
|
+
}, {
|
|
887
|
+
provider,
|
|
802
888
|
});
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
nowUnixMs,
|
|
813
|
-
replacePrimary: loaded.source === "backup",
|
|
814
|
-
rpc: (options.rpcFactory ?? createRpcClient)(node.rpc),
|
|
815
|
-
});
|
|
816
|
-
state = normalized.state;
|
|
817
|
-
session = normalized.session ?? session;
|
|
818
|
-
source = normalized.changed ? "primary" : loaded.source;
|
|
819
|
-
}
|
|
820
|
-
finally {
|
|
821
|
-
await node.stop?.().catch(() => undefined);
|
|
889
|
+
}
|
|
890
|
+
catch {
|
|
891
|
+
return null;
|
|
892
|
+
}
|
|
893
|
+
const explicitLock = await loadWalletExplicitLock(paths.walletExplicitLockPath);
|
|
894
|
+
if (explicitLock !== null) {
|
|
895
|
+
if (explicitLock.walletRootId === loaded.state.walletRootId) {
|
|
896
|
+
await clearUnlockSession(paths.walletUnlockSessionPath);
|
|
897
|
+
return null;
|
|
822
898
|
}
|
|
899
|
+
await clearWalletExplicitLock(paths.walletExplicitLockPath);
|
|
823
900
|
}
|
|
824
|
-
|
|
901
|
+
const secretReference = createWalletSecretReference(loaded.state.walletRootId);
|
|
902
|
+
const unlockUntilUnixMs = nowUnixMs + unlockDurationMs;
|
|
903
|
+
const session = createUnlockSession(loaded.state, unlockUntilUnixMs, secretReference.keyId, nowUnixMs);
|
|
904
|
+
await saveUnlockSession(paths.walletUnlockSessionPath, session, {
|
|
905
|
+
provider,
|
|
906
|
+
secretReference,
|
|
907
|
+
});
|
|
908
|
+
return await normalizeUnlockedWalletStateIfNeeded({
|
|
909
|
+
provider,
|
|
825
910
|
session,
|
|
826
|
-
state:
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
911
|
+
state: loaded.state,
|
|
912
|
+
source: loaded.source,
|
|
913
|
+
nowUnixMs,
|
|
914
|
+
paths,
|
|
915
|
+
dataDir: options.dataDir,
|
|
916
|
+
attachService: options.attachService,
|
|
917
|
+
rpcFactory: options.rpcFactory,
|
|
918
|
+
});
|
|
919
|
+
};
|
|
920
|
+
if (options.controlLockHeld) {
|
|
921
|
+
return await loadAndMaybeAutoUnlock();
|
|
832
922
|
}
|
|
833
|
-
|
|
834
|
-
|
|
923
|
+
const controlLock = await acquireFileLock(paths.walletControlLockPath, {
|
|
924
|
+
purpose: "wallet-auto-unlock",
|
|
925
|
+
walletRootId: null,
|
|
926
|
+
});
|
|
927
|
+
try {
|
|
928
|
+
return await loadAndMaybeAutoUnlock();
|
|
929
|
+
}
|
|
930
|
+
finally {
|
|
931
|
+
await controlLock.release();
|
|
835
932
|
}
|
|
836
933
|
}
|
|
837
934
|
export async function initializeWallet(options) {
|
|
@@ -884,6 +981,7 @@ export async function initializeWallet(options) {
|
|
|
884
981
|
});
|
|
885
982
|
const verifiedState = await importDescriptorIntoManagedCoreWallet(initialState, provider, paths, options.dataDir, nowUnixMs, options.attachService, options.rpcFactory);
|
|
886
983
|
const unlockUntilUnixMs = nowUnixMs + unlockDurationMs;
|
|
984
|
+
await clearWalletExplicitLock(paths.walletExplicitLockPath);
|
|
887
985
|
await saveUnlockSession(paths.walletUnlockSessionPath, createUnlockSession(verifiedState, unlockUntilUnixMs, secretReference.keyId, nowUnixMs), {
|
|
888
986
|
provider,
|
|
889
987
|
secretReference,
|
|
@@ -917,6 +1015,7 @@ export async function unlockWallet(options = {}) {
|
|
|
917
1015
|
});
|
|
918
1016
|
const secretReference = createWalletSecretReference(loaded.state.walletRootId);
|
|
919
1017
|
const unlockUntilUnixMs = nowUnixMs + unlockDurationMs;
|
|
1018
|
+
await clearWalletExplicitLock(paths.walletExplicitLockPath);
|
|
920
1019
|
await saveUnlockSession(paths.walletUnlockSessionPath, createUnlockSession(loaded.state, unlockUntilUnixMs, secretReference.keyId, nowUnixMs), {
|
|
921
1020
|
provider,
|
|
922
1021
|
secretReference,
|
|
@@ -933,6 +1032,7 @@ export async function unlockWallet(options = {}) {
|
|
|
933
1032
|
}
|
|
934
1033
|
export async function lockWallet(options) {
|
|
935
1034
|
const provider = options.provider ?? createDefaultWalletSecretProvider();
|
|
1035
|
+
const nowUnixMs = options.nowUnixMs ?? Date.now();
|
|
936
1036
|
const paths = options.paths ?? resolveWalletRuntimePathsForTesting();
|
|
937
1037
|
const controlLock = await acquireFileLock(paths.walletControlLockPath, {
|
|
938
1038
|
purpose: "wallet-lock",
|
|
@@ -968,6 +1068,9 @@ export async function lockWallet(options) {
|
|
|
968
1068
|
walletRootId = null;
|
|
969
1069
|
}
|
|
970
1070
|
await clearUnlockSession(paths.walletUnlockSessionPath);
|
|
1071
|
+
if (walletRootId !== null) {
|
|
1072
|
+
await saveWalletExplicitLock(paths.walletExplicitLockPath, createWalletExplicitLock(walletRootId, nowUnixMs));
|
|
1073
|
+
}
|
|
971
1074
|
return {
|
|
972
1075
|
walletRootId,
|
|
973
1076
|
coreLocked,
|
|
@@ -989,10 +1092,11 @@ export async function exportWallet(options) {
|
|
|
989
1092
|
walletRootId: null,
|
|
990
1093
|
});
|
|
991
1094
|
try {
|
|
992
|
-
const unlocked = await
|
|
1095
|
+
const unlocked = await loadOrAutoUnlockWalletState({
|
|
993
1096
|
provider,
|
|
994
1097
|
nowUnixMs,
|
|
995
1098
|
paths,
|
|
1099
|
+
controlLockHeld: true,
|
|
996
1100
|
});
|
|
997
1101
|
if (unlocked === null) {
|
|
998
1102
|
throw new Error("wallet_locked");
|
|
@@ -1071,6 +1175,7 @@ export async function importWallet(options) {
|
|
|
1071
1175
|
internalCoreWalletPassphrase: createInternalCoreWalletPassphrase(),
|
|
1072
1176
|
});
|
|
1073
1177
|
await clearUnlockSession(paths.walletUnlockSessionPath);
|
|
1178
|
+
await clearWalletExplicitLock(paths.walletExplicitLockPath);
|
|
1074
1179
|
await saveWalletState({
|
|
1075
1180
|
primaryPath: paths.walletStatePath,
|
|
1076
1181
|
backupPath: paths.walletStateBackupPath,
|
|
@@ -1083,6 +1188,7 @@ export async function importWallet(options) {
|
|
|
1083
1188
|
rpcFactory: options.rpcFactory,
|
|
1084
1189
|
});
|
|
1085
1190
|
const unlockUntilUnixMs = nowUnixMs + unlockDurationMs;
|
|
1191
|
+
await clearWalletExplicitLock(paths.walletExplicitLockPath);
|
|
1086
1192
|
await saveUnlockSession(paths.walletUnlockSessionPath, createUnlockSession(importedState, unlockUntilUnixMs, secretReference.keyId, nowUnixMs), {
|
|
1087
1193
|
provider,
|
|
1088
1194
|
secretReference,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
2
|
import { acquireFileLock } from "../fs/lock.js";
|
|
3
|
-
import {
|
|
3
|
+
import { loadOrAutoUnlockWalletState } from "../lifecycle.js";
|
|
4
4
|
import { resolveWalletRuntimePathsForTesting } from "../runtime.js";
|
|
5
5
|
import { saveWalletState } from "../state/storage.js";
|
|
6
6
|
import { createDefaultWalletSecretProvider, createWalletSecretReference, } from "../state/provider.js";
|
|
@@ -397,7 +397,7 @@ export async function enableMiningHooks(options) {
|
|
|
397
397
|
paths,
|
|
398
398
|
reason: "hooks-enable-mining",
|
|
399
399
|
});
|
|
400
|
-
const unlocked = await
|
|
400
|
+
const unlocked = await loadOrAutoUnlockWalletState({
|
|
401
401
|
provider,
|
|
402
402
|
nowUnixMs,
|
|
403
403
|
paths,
|
|
@@ -556,7 +556,7 @@ export async function disableMiningHooks(options) {
|
|
|
556
556
|
paths,
|
|
557
557
|
reason: "hooks-disable-mining",
|
|
558
558
|
});
|
|
559
|
-
const unlocked = await
|
|
559
|
+
const unlocked = await loadOrAutoUnlockWalletState({
|
|
560
560
|
provider,
|
|
561
561
|
nowUnixMs,
|
|
562
562
|
paths,
|
|
@@ -664,7 +664,7 @@ export async function setupBuiltInMining(options) {
|
|
|
664
664
|
paths,
|
|
665
665
|
reason: "mine-setup",
|
|
666
666
|
});
|
|
667
|
-
const unlocked = await
|
|
667
|
+
const unlocked = await loadOrAutoUnlockWalletState({
|
|
668
668
|
provider,
|
|
669
669
|
nowUnixMs,
|
|
670
670
|
paths,
|
|
@@ -10,7 +10,7 @@ import { COG_OPCODES, COG_PREFIX } from "../cogop/constants.js";
|
|
|
10
10
|
import { extractOpReturnPayloadFromScriptHex } from "../tx/register.js";
|
|
11
11
|
import { DEFAULT_WALLET_MUTATION_FEE_RATE_SAT_VB, buildWalletMutationTransaction, isAlreadyAcceptedError, isBroadcastUnknownError, saveWalletStatePreservingUnlock, } from "../tx/common.js";
|
|
12
12
|
import { acquireFileLock } from "../fs/lock.js";
|
|
13
|
-
import {
|
|
13
|
+
import { loadOrAutoUnlockWalletState } from "../lifecycle.js";
|
|
14
14
|
import { isMineableWalletDomain, openWalletReadContext, } from "../read/index.js";
|
|
15
15
|
import { resolveWalletRuntimePathsForTesting } from "../runtime.js";
|
|
16
16
|
import { createDefaultWalletSecretProvider, } from "../state/provider.js";
|
|
@@ -1567,7 +1567,7 @@ async function publishCandidate(options) {
|
|
|
1567
1567
|
};
|
|
1568
1568
|
}
|
|
1569
1569
|
async function ensureBuiltInSetupIfNeeded(options) {
|
|
1570
|
-
const unlocked = await
|
|
1570
|
+
const unlocked = await loadOrAutoUnlockWalletState({
|
|
1571
1571
|
provider: options.provider,
|
|
1572
1572
|
paths: options.paths,
|
|
1573
1573
|
});
|
|
@@ -8,12 +8,14 @@ declare function inspectWalletLocalState(options?: {
|
|
|
8
8
|
secretProvider?: WalletSecretProvider;
|
|
9
9
|
now?: number;
|
|
10
10
|
paths?: WalletRuntimePaths;
|
|
11
|
+
walletControlLockHeld?: boolean;
|
|
11
12
|
}): Promise<WalletLocalStateStatus>;
|
|
12
13
|
export declare function openWalletReadContext(options: {
|
|
13
14
|
dataDir: string;
|
|
14
15
|
databasePath: string;
|
|
15
16
|
walletStatePassphrase?: Uint8Array | string;
|
|
16
17
|
secretProvider?: WalletSecretProvider;
|
|
18
|
+
walletControlLockHeld?: boolean;
|
|
17
19
|
startupTimeoutMs?: number;
|
|
18
20
|
now?: number;
|
|
19
21
|
paths?: WalletRuntimePaths;
|
|
@@ -5,11 +5,12 @@ import { createRpcClient } from "../../bitcoind/node.js";
|
|
|
5
5
|
import { UNINITIALIZED_WALLET_ROOT_ID } from "../../bitcoind/service-paths.js";
|
|
6
6
|
import { attachOrStartManagedBitcoindService, probeManagedBitcoindService, } from "../../bitcoind/service.js";
|
|
7
7
|
import {} from "../../bitcoind/types.js";
|
|
8
|
-
import {
|
|
8
|
+
import { loadOrAutoUnlockWalletState, verifyManagedCoreWalletReplica, } from "../lifecycle.js";
|
|
9
9
|
import { persistNormalizedWalletDescriptorStateIfNeeded } from "../descriptor-normalization.js";
|
|
10
10
|
import { inspectMiningControlPlane } from "../mining/index.js";
|
|
11
11
|
import { normalizeMiningStateRecord } from "../mining/state.js";
|
|
12
12
|
import { resolveWalletRuntimePathsForTesting } from "../runtime.js";
|
|
13
|
+
import { loadWalletExplicitLock } from "../state/explicit-lock.js";
|
|
13
14
|
import { loadWalletState } from "../state/storage.js";
|
|
14
15
|
import { createDefaultWalletSecretProvider, createWalletSecretReference, } from "../state/provider.js";
|
|
15
16
|
import { createWalletReadModel } from "./project.js";
|
|
@@ -24,6 +25,30 @@ async function pathExists(path) {
|
|
|
24
25
|
return false;
|
|
25
26
|
}
|
|
26
27
|
}
|
|
28
|
+
function isLockedWalletAccessError(error) {
|
|
29
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
30
|
+
return message === "wallet_envelope_missing_secret_provider"
|
|
31
|
+
|| message.startsWith("wallet_secret_missing_")
|
|
32
|
+
|| message.startsWith("wallet_secret_provider_");
|
|
33
|
+
}
|
|
34
|
+
function describeLockedWalletMessage(options) {
|
|
35
|
+
if (options.explicitlyLocked) {
|
|
36
|
+
return "Wallet state exists but is explicitly locked until `cogcoin unlock` is run.";
|
|
37
|
+
}
|
|
38
|
+
const message = options.accessError instanceof Error ? options.accessError.message : String(options.accessError ?? "");
|
|
39
|
+
if (message === "wallet_envelope_missing_secret_provider") {
|
|
40
|
+
return "Wallet state exists but requires the local wallet-state passphrase.";
|
|
41
|
+
}
|
|
42
|
+
if (message.startsWith("wallet_secret_provider_")) {
|
|
43
|
+
return "Wallet state exists but the local secret provider is unavailable.";
|
|
44
|
+
}
|
|
45
|
+
if (message.startsWith("wallet_secret_missing_")) {
|
|
46
|
+
return "Wallet state exists but its local secret-provider material is unavailable.";
|
|
47
|
+
}
|
|
48
|
+
return options.hasUnlockSessionFile
|
|
49
|
+
? "Wallet state exists but the unlock session is expired, invalid, or belongs to a different wallet root."
|
|
50
|
+
: "Wallet state exists but is currently locked.";
|
|
51
|
+
}
|
|
27
52
|
async function normalizeLoadedWalletStateForRead(options) {
|
|
28
53
|
if (options.dataDir === undefined) {
|
|
29
54
|
return options.loaded;
|
|
@@ -82,13 +107,16 @@ async function inspectWalletLocalState(options = {}) {
|
|
|
82
107
|
if (options.passphrase === undefined) {
|
|
83
108
|
try {
|
|
84
109
|
const provider = options.secretProvider ?? createDefaultWalletSecretProvider();
|
|
85
|
-
const unlocked = await
|
|
110
|
+
const unlocked = await loadOrAutoUnlockWalletState({
|
|
86
111
|
provider,
|
|
87
112
|
nowUnixMs: now,
|
|
88
113
|
paths,
|
|
89
114
|
dataDir: options.dataDir,
|
|
115
|
+
controlLockHeld: options.walletControlLockHeld,
|
|
90
116
|
});
|
|
91
117
|
if (unlocked === null) {
|
|
118
|
+
const explicitLock = await loadWalletExplicitLock(paths.walletExplicitLockPath);
|
|
119
|
+
const hasUnlockSessionFileNow = await pathExists(paths.walletUnlockSessionPath);
|
|
92
120
|
try {
|
|
93
121
|
const loaded = await loadWalletState({
|
|
94
122
|
primaryPath: paths.walletStatePath,
|
|
@@ -103,8 +131,39 @@ async function inspectWalletLocalState(options = {}) {
|
|
|
103
131
|
now,
|
|
104
132
|
paths,
|
|
105
133
|
});
|
|
134
|
+
return {
|
|
135
|
+
availability: "locked",
|
|
136
|
+
walletRootId: loaded.state.walletRootId,
|
|
137
|
+
state: null,
|
|
138
|
+
source: loaded.source,
|
|
139
|
+
unlockUntilUnixMs: null,
|
|
140
|
+
hasPrimaryStateFile,
|
|
141
|
+
hasBackupStateFile,
|
|
142
|
+
hasUnlockSessionFile: hasUnlockSessionFileNow,
|
|
143
|
+
message: describeLockedWalletMessage({
|
|
144
|
+
explicitlyLocked: explicitLock?.walletRootId === loaded.state.walletRootId,
|
|
145
|
+
hasUnlockSessionFile: hasUnlockSessionFileNow,
|
|
146
|
+
}),
|
|
147
|
+
};
|
|
106
148
|
}
|
|
107
149
|
catch (error) {
|
|
150
|
+
if (isLockedWalletAccessError(error)) {
|
|
151
|
+
return {
|
|
152
|
+
availability: "locked",
|
|
153
|
+
walletRootId: null,
|
|
154
|
+
state: null,
|
|
155
|
+
source: null,
|
|
156
|
+
unlockUntilUnixMs: null,
|
|
157
|
+
hasPrimaryStateFile,
|
|
158
|
+
hasBackupStateFile,
|
|
159
|
+
hasUnlockSessionFile: hasUnlockSessionFileNow,
|
|
160
|
+
message: describeLockedWalletMessage({
|
|
161
|
+
accessError: error,
|
|
162
|
+
explicitlyLocked: false,
|
|
163
|
+
hasUnlockSessionFile: hasUnlockSessionFileNow,
|
|
164
|
+
}),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
108
167
|
return {
|
|
109
168
|
availability: "local-state-corrupt",
|
|
110
169
|
walletRootId: null,
|
|
@@ -113,23 +172,10 @@ async function inspectWalletLocalState(options = {}) {
|
|
|
113
172
|
unlockUntilUnixMs: null,
|
|
114
173
|
hasPrimaryStateFile,
|
|
115
174
|
hasBackupStateFile,
|
|
116
|
-
hasUnlockSessionFile,
|
|
175
|
+
hasUnlockSessionFile: hasUnlockSessionFileNow,
|
|
117
176
|
message: error instanceof Error ? error.message : String(error),
|
|
118
177
|
};
|
|
119
178
|
}
|
|
120
|
-
return {
|
|
121
|
-
availability: "locked",
|
|
122
|
-
walletRootId: null,
|
|
123
|
-
state: null,
|
|
124
|
-
source: null,
|
|
125
|
-
unlockUntilUnixMs: null,
|
|
126
|
-
hasPrimaryStateFile,
|
|
127
|
-
hasBackupStateFile,
|
|
128
|
-
hasUnlockSessionFile,
|
|
129
|
-
message: hasUnlockSessionFile
|
|
130
|
-
? "Wallet state exists but the unlock session is expired, invalid, or belongs to a different wallet root."
|
|
131
|
-
: "Wallet state exists but is currently locked.",
|
|
132
|
-
};
|
|
133
179
|
}
|
|
134
180
|
return {
|
|
135
181
|
availability: "ready",
|
|
@@ -142,7 +188,7 @@ async function inspectWalletLocalState(options = {}) {
|
|
|
142
188
|
unlockUntilUnixMs: unlocked.session.unlockUntilUnixMs,
|
|
143
189
|
hasPrimaryStateFile,
|
|
144
190
|
hasBackupStateFile,
|
|
145
|
-
hasUnlockSessionFile,
|
|
191
|
+
hasUnlockSessionFile: true,
|
|
146
192
|
message: null,
|
|
147
193
|
};
|
|
148
194
|
}
|
|
@@ -460,6 +506,7 @@ export async function openWalletReadContext(options) {
|
|
|
460
506
|
dataDir: options.dataDir,
|
|
461
507
|
passphrase: options.walletStatePassphrase,
|
|
462
508
|
secretProvider: options.secretProvider,
|
|
509
|
+
walletControlLockHeld: options.walletControlLockHeld,
|
|
463
510
|
now,
|
|
464
511
|
paths: options.paths,
|
|
465
512
|
});
|
package/dist/wallet/runtime.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export interface WalletRuntimePaths {
|
|
|
10
10
|
walletStatePath: string;
|
|
11
11
|
walletStateBackupPath: string;
|
|
12
12
|
walletUnlockSessionPath: string;
|
|
13
|
+
walletExplicitLockPath: string;
|
|
13
14
|
walletControlLockPath: string;
|
|
14
15
|
bitcoindLockPath: string;
|
|
15
16
|
bitcoindStatusPath: string;
|
package/dist/wallet/runtime.js
CHANGED
|
@@ -12,6 +12,7 @@ export function resolveWalletRuntimePathsForTesting(resolution = {}) {
|
|
|
12
12
|
walletStatePath: paths.walletStatePath,
|
|
13
13
|
walletStateBackupPath: paths.walletStateBackupPath,
|
|
14
14
|
walletUnlockSessionPath: paths.walletUnlockSessionPath,
|
|
15
|
+
walletExplicitLockPath: paths.walletExplicitLockPath,
|
|
15
16
|
walletControlLockPath: paths.walletControlLockPath,
|
|
16
17
|
bitcoindLockPath: paths.bitcoindLockPath,
|
|
17
18
|
bitcoindStatusPath: paths.bitcoindStatusPath,
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { WalletExplicitLockStateV1 } from "../types.js";
|
|
2
|
+
export declare function loadWalletExplicitLock(lockPath: string): Promise<WalletExplicitLockStateV1 | null>;
|
|
3
|
+
export declare function saveWalletExplicitLock(lockPath: string, state: WalletExplicitLockStateV1): Promise<void>;
|
|
4
|
+
export declare function clearWalletExplicitLock(lockPath: string): Promise<void>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { readFile, rm } from "node:fs/promises";
|
|
2
|
+
import { writeJsonFileAtomic } from "../fs/atomic.js";
|
|
3
|
+
export async function loadWalletExplicitLock(lockPath) {
|
|
4
|
+
try {
|
|
5
|
+
return JSON.parse(await readFile(lockPath, "utf8"));
|
|
6
|
+
}
|
|
7
|
+
catch (error) {
|
|
8
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
throw error;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export async function saveWalletExplicitLock(lockPath, state) {
|
|
15
|
+
await writeJsonFileAtomic(lockPath, state, { mode: 0o600 });
|
|
16
|
+
}
|
|
17
|
+
export async function clearWalletExplicitLock(lockPath) {
|
|
18
|
+
await rm(lockPath, { force: true });
|
|
19
|
+
}
|
package/dist/wallet/tx/anchor.js
CHANGED
package/dist/wallet/tx/cog.js
CHANGED
|
@@ -623,6 +623,7 @@ export async function sendCog(options) {
|
|
|
623
623
|
dataDir: options.dataDir,
|
|
624
624
|
databasePath: options.databasePath,
|
|
625
625
|
secretProvider: provider,
|
|
626
|
+
walletControlLockHeld: true,
|
|
626
627
|
paths,
|
|
627
628
|
});
|
|
628
629
|
try {
|
|
@@ -763,6 +764,7 @@ export async function lockCogToDomain(options) {
|
|
|
763
764
|
dataDir: options.dataDir,
|
|
764
765
|
databasePath: options.databasePath,
|
|
765
766
|
secretProvider: provider,
|
|
767
|
+
walletControlLockHeld: true,
|
|
766
768
|
paths,
|
|
767
769
|
});
|
|
768
770
|
try {
|
|
@@ -918,6 +920,7 @@ async function runClaimLikeMutation(options, reclaim) {
|
|
|
918
920
|
dataDir: options.dataDir,
|
|
919
921
|
databasePath: options.databasePath,
|
|
920
922
|
secretProvider: provider,
|
|
923
|
+
walletControlLockHeld: true,
|
|
921
924
|
paths,
|
|
922
925
|
});
|
|
923
926
|
try {
|
|
@@ -683,6 +683,7 @@ export async function transferDomain(options) {
|
|
|
683
683
|
dataDir: options.dataDir,
|
|
684
684
|
databasePath: options.databasePath,
|
|
685
685
|
secretProvider: provider,
|
|
686
|
+
walletControlLockHeld: true,
|
|
686
687
|
paths,
|
|
687
688
|
});
|
|
688
689
|
try {
|
|
@@ -916,6 +917,7 @@ async function runSellMutation(options) {
|
|
|
916
917
|
dataDir: options.dataDir,
|
|
917
918
|
databasePath: options.databasePath,
|
|
918
919
|
secretProvider: provider,
|
|
920
|
+
walletControlLockHeld: true,
|
|
919
921
|
paths,
|
|
920
922
|
});
|
|
921
923
|
try {
|
|
@@ -1143,6 +1145,7 @@ export async function buyDomain(options) {
|
|
|
1143
1145
|
dataDir: options.dataDir,
|
|
1144
1146
|
databasePath: options.databasePath,
|
|
1145
1147
|
secretProvider: provider,
|
|
1148
|
+
walletControlLockHeld: true,
|
|
1146
1149
|
paths,
|
|
1147
1150
|
});
|
|
1148
1151
|
try {
|
package/dist/wallet/tx/field.js
CHANGED
|
@@ -1267,6 +1267,7 @@ async function submitStandaloneFieldMutation(options) {
|
|
|
1267
1267
|
dataDir: options.dataDir,
|
|
1268
1268
|
databasePath: options.databasePath,
|
|
1269
1269
|
secretProvider: provider,
|
|
1270
|
+
walletControlLockHeld: true,
|
|
1270
1271
|
paths,
|
|
1271
1272
|
});
|
|
1272
1273
|
try {
|
|
@@ -1418,6 +1419,7 @@ async function submitFieldCreateFamily(options) {
|
|
|
1418
1419
|
dataDir: options.dataDir,
|
|
1419
1420
|
databasePath: options.databasePath,
|
|
1420
1421
|
secretProvider: provider,
|
|
1422
|
+
walletControlLockHeld: true,
|
|
1421
1423
|
paths,
|
|
1422
1424
|
});
|
|
1423
1425
|
try {
|
package/dist/wallet/types.d.ts
CHANGED
package/package.json
CHANGED