@cogcoin/client 0.5.11 → 0.5.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +3 -1
  2. package/dist/app-paths.d.ts +1 -0
  3. package/dist/app-paths.js +3 -0
  4. package/dist/bitcoind/bootstrap/controller.d.ts +3 -0
  5. package/dist/bitcoind/bootstrap/controller.js +7 -5
  6. package/dist/bitcoind/client/factory.d.ts +8 -0
  7. package/dist/bitcoind/client/factory.js +43 -6
  8. package/dist/bitcoind/client/managed-client.js +19 -10
  9. package/dist/bitcoind/client/sync-engine.js +35 -4
  10. package/dist/bitcoind/progress/formatting.js +1 -1
  11. package/dist/bitcoind/testing.d.ts +1 -0
  12. package/dist/bitcoind/testing.js +1 -0
  13. package/dist/cli/commands/follow.js +47 -14
  14. package/dist/cli/commands/sync.js +48 -15
  15. package/dist/cli/context.js +5 -1
  16. package/dist/cli/output.js +11 -0
  17. package/dist/cli/runner.js +2 -0
  18. package/dist/cli/signals.d.ts +1 -1
  19. package/dist/cli/signals.js +17 -4
  20. package/dist/cli/types.d.ts +4 -0
  21. package/dist/cli/update-notifier.d.ts +2 -0
  22. package/dist/cli/update-notifier.js +276 -0
  23. package/dist/client/default-client.d.ts +1 -1
  24. package/dist/client/default-client.js +7 -1
  25. package/dist/client/factory.js +6 -1
  26. package/dist/sqlite/store.js +3 -0
  27. package/dist/types.d.ts +2 -0
  28. package/dist/wallet/archive.js +10 -8
  29. package/dist/wallet/coin-control.d.ts +41 -0
  30. package/dist/wallet/coin-control.js +365 -0
  31. package/dist/wallet/lifecycle.js +39 -2
  32. package/dist/wallet/mining/runner.js +46 -44
  33. package/dist/wallet/read/context.js +15 -6
  34. package/dist/wallet/reset.js +2 -0
  35. package/dist/wallet/state/storage.js +5 -4
  36. package/dist/wallet/tx/anchor.js +36 -51
  37. package/dist/wallet/tx/cog.js +19 -12
  38. package/dist/wallet/tx/common.d.ts +41 -10
  39. package/dist/wallet/tx/common.js +112 -5
  40. package/dist/wallet/tx/domain-admin.js +13 -8
  41. package/dist/wallet/tx/domain-market.js +19 -12
  42. package/dist/wallet/tx/field.js +21 -18
  43. package/dist/wallet/tx/register.js +17 -12
  44. package/dist/wallet/tx/reputation.js +13 -8
  45. package/dist/wallet/types.d.ts +4 -0
  46. package/package.json +1 -1
@@ -0,0 +1,2 @@
1
+ import type { ParsedCliArgs, RequiredCliRunnerContext } from "./types.js";
2
+ export declare function maybeNotifyAboutCliUpdate(parsed: ParsedCliArgs, context: RequiredCliRunnerContext): Promise<void>;
@@ -0,0 +1,276 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { writeJsonFileAtomic } from "../wallet/fs/atomic.js";
3
+ import { writeLine } from "./io.js";
4
+ const UPDATE_CHECK_CACHE_SCHEMA_VERSION = 1;
5
+ const UPDATE_CHECK_MAX_AGE_MS = 24 * 60 * 60 * 1000;
6
+ const UPDATE_CHECK_TIMEOUT_MS = 500;
7
+ const UPDATE_CHECK_URL = "https://registry.npmjs.org/@cogcoin/client/latest";
8
+ function createEmptyUpdateCheckCache() {
9
+ return {
10
+ schemaVersion: UPDATE_CHECK_CACHE_SCHEMA_VERSION,
11
+ lastCheckedAtUnixMs: 0,
12
+ latestVersion: null,
13
+ lastNotifiedCurrentVersion: null,
14
+ lastNotifiedLatestVersion: null,
15
+ lastNotifiedAtUnixMs: null,
16
+ };
17
+ }
18
+ function parseSemver(version) {
19
+ const match = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/.exec(version.trim());
20
+ if (match === null) {
21
+ return null;
22
+ }
23
+ const prerelease = match[4] === undefined
24
+ ? []
25
+ : match[4].split(".").map((raw) => ({
26
+ raw,
27
+ numeric: /^(0|[1-9]\d*)$/.test(raw),
28
+ numericValue: /^(0|[1-9]\d*)$/.test(raw) ? Number(raw) : null,
29
+ }));
30
+ return {
31
+ major: Number(match[1]),
32
+ minor: Number(match[2]),
33
+ patch: Number(match[3]),
34
+ prerelease,
35
+ };
36
+ }
37
+ function compareSemver(left, right) {
38
+ const leftParsed = parseSemver(left);
39
+ const rightParsed = parseSemver(right);
40
+ if (leftParsed === null || rightParsed === null) {
41
+ return null;
42
+ }
43
+ if (leftParsed.major !== rightParsed.major) {
44
+ return leftParsed.major > rightParsed.major ? 1 : -1;
45
+ }
46
+ if (leftParsed.minor !== rightParsed.minor) {
47
+ return leftParsed.minor > rightParsed.minor ? 1 : -1;
48
+ }
49
+ if (leftParsed.patch !== rightParsed.patch) {
50
+ return leftParsed.patch > rightParsed.patch ? 1 : -1;
51
+ }
52
+ if (leftParsed.prerelease.length === 0 && rightParsed.prerelease.length === 0) {
53
+ return 0;
54
+ }
55
+ if (leftParsed.prerelease.length === 0) {
56
+ return 1;
57
+ }
58
+ if (rightParsed.prerelease.length === 0) {
59
+ return -1;
60
+ }
61
+ const maxLength = Math.max(leftParsed.prerelease.length, rightParsed.prerelease.length);
62
+ for (let index = 0; index < maxLength; index += 1) {
63
+ const leftIdentifier = leftParsed.prerelease[index];
64
+ const rightIdentifier = rightParsed.prerelease[index];
65
+ if (leftIdentifier === undefined) {
66
+ return -1;
67
+ }
68
+ if (rightIdentifier === undefined) {
69
+ return 1;
70
+ }
71
+ if (leftIdentifier.numeric && rightIdentifier.numeric) {
72
+ if (leftIdentifier.numericValue !== rightIdentifier.numericValue) {
73
+ return leftIdentifier.numericValue > rightIdentifier.numericValue ? 1 : -1;
74
+ }
75
+ continue;
76
+ }
77
+ if (leftIdentifier.numeric !== rightIdentifier.numeric) {
78
+ return leftIdentifier.numeric ? -1 : 1;
79
+ }
80
+ if (leftIdentifier.raw !== rightIdentifier.raw) {
81
+ return leftIdentifier.raw > rightIdentifier.raw ? 1 : -1;
82
+ }
83
+ }
84
+ return 0;
85
+ }
86
+ function isUpdateCheckDisabled(env) {
87
+ const raw = env.COGCOIN_DISABLE_UPDATE_CHECK;
88
+ if (raw === undefined) {
89
+ return false;
90
+ }
91
+ const normalized = raw.trim().toLowerCase();
92
+ return normalized === "1" || normalized === "true" || normalized === "yes";
93
+ }
94
+ function isEligibleForUpdateNotification(parsed, context) {
95
+ if (parsed.outputMode !== "text" || parsed.help || parsed.version) {
96
+ return false;
97
+ }
98
+ return context.stdout.isTTY === true || context.stderr.isTTY === true;
99
+ }
100
+ function normalizeUpdateCheckCache(parsed) {
101
+ if (typeof parsed !== "object" || parsed === null) {
102
+ return null;
103
+ }
104
+ const candidate = parsed;
105
+ if (candidate.schemaVersion !== UPDATE_CHECK_CACHE_SCHEMA_VERSION) {
106
+ return null;
107
+ }
108
+ return {
109
+ schemaVersion: UPDATE_CHECK_CACHE_SCHEMA_VERSION,
110
+ lastCheckedAtUnixMs: typeof candidate.lastCheckedAtUnixMs === "number" ? candidate.lastCheckedAtUnixMs : 0,
111
+ latestVersion: typeof candidate.latestVersion === "string" ? candidate.latestVersion : null,
112
+ lastNotifiedCurrentVersion: typeof candidate.lastNotifiedCurrentVersion === "string"
113
+ ? candidate.lastNotifiedCurrentVersion
114
+ : null,
115
+ lastNotifiedLatestVersion: typeof candidate.lastNotifiedLatestVersion === "string"
116
+ ? candidate.lastNotifiedLatestVersion
117
+ : null,
118
+ lastNotifiedAtUnixMs: typeof candidate.lastNotifiedAtUnixMs === "number"
119
+ ? candidate.lastNotifiedAtUnixMs
120
+ : null,
121
+ lastCheckErrorKind: typeof candidate.lastCheckErrorKind === "string"
122
+ ? candidate.lastCheckErrorKind
123
+ : undefined,
124
+ };
125
+ }
126
+ async function loadUpdateCheckCache(cachePath) {
127
+ try {
128
+ const raw = await readFile(cachePath, "utf8");
129
+ return normalizeUpdateCheckCache(JSON.parse(raw));
130
+ }
131
+ catch (error) {
132
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
133
+ return null;
134
+ }
135
+ return null;
136
+ }
137
+ }
138
+ function shouldRefreshUpdateCheck(cache, now) {
139
+ return now - cache.lastCheckedAtUnixMs >= UPDATE_CHECK_MAX_AGE_MS;
140
+ }
141
+ function shouldNotifyForVersionPair(cache, currentVersion, latestVersion, now) {
142
+ const versionComparison = compareSemver(latestVersion, currentVersion);
143
+ if (versionComparison === null || versionComparison <= 0) {
144
+ return false;
145
+ }
146
+ if (cache.lastNotifiedCurrentVersion !== currentVersion
147
+ || cache.lastNotifiedLatestVersion !== latestVersion) {
148
+ return true;
149
+ }
150
+ if (cache.lastNotifiedAtUnixMs === null) {
151
+ return true;
152
+ }
153
+ return now - cache.lastNotifiedAtUnixMs >= UPDATE_CHECK_MAX_AGE_MS;
154
+ }
155
+ function recordUpdateNotification(cache, currentVersion, latestVersion, now) {
156
+ return {
157
+ ...cache,
158
+ lastNotifiedCurrentVersion: currentVersion,
159
+ lastNotifiedLatestVersion: latestVersion,
160
+ lastNotifiedAtUnixMs: now,
161
+ };
162
+ }
163
+ async function fetchLatestPublishedVersion(fetchImpl) {
164
+ const controller = new AbortController();
165
+ const timer = setTimeout(() => {
166
+ controller.abort();
167
+ }, UPDATE_CHECK_TIMEOUT_MS);
168
+ try {
169
+ const response = await fetchImpl(UPDATE_CHECK_URL, {
170
+ headers: {
171
+ accept: "application/json",
172
+ },
173
+ signal: controller.signal,
174
+ });
175
+ if (!response.ok) {
176
+ return {
177
+ kind: "failure",
178
+ errorKind: `http_${response.status}`,
179
+ };
180
+ }
181
+ let payload;
182
+ try {
183
+ payload = await response.json();
184
+ }
185
+ catch {
186
+ return {
187
+ kind: "failure",
188
+ errorKind: "invalid_json",
189
+ };
190
+ }
191
+ const latestVersion = typeof payload.version === "string"
192
+ ? payload.version
193
+ : null;
194
+ if (latestVersion === null) {
195
+ return {
196
+ kind: "failure",
197
+ errorKind: "invalid_payload",
198
+ };
199
+ }
200
+ if (parseSemver(latestVersion) === null) {
201
+ return {
202
+ kind: "failure",
203
+ errorKind: "invalid_semver",
204
+ };
205
+ }
206
+ return {
207
+ kind: "success",
208
+ latestVersion,
209
+ };
210
+ }
211
+ catch (error) {
212
+ if (error instanceof Error && error.name === "AbortError") {
213
+ return {
214
+ kind: "failure",
215
+ errorKind: "timeout",
216
+ };
217
+ }
218
+ return {
219
+ kind: "failure",
220
+ errorKind: "network",
221
+ };
222
+ }
223
+ finally {
224
+ clearTimeout(timer);
225
+ }
226
+ }
227
+ function writeUpdateNotice(context, currentVersion, latestVersion) {
228
+ writeLine(context.stderr, `Update available: Cogcoin ${currentVersion} -> ${latestVersion}`);
229
+ writeLine(context.stderr, "Run: npm install -g @cogcoin/client");
230
+ }
231
+ async function persistUpdateCheckCache(cachePath, cache) {
232
+ await writeJsonFileAtomic(cachePath, cache);
233
+ }
234
+ export async function maybeNotifyAboutCliUpdate(parsed, context) {
235
+ try {
236
+ if (!isEligibleForUpdateNotification(parsed, context) || isUpdateCheckDisabled(context.env)) {
237
+ return;
238
+ }
239
+ const currentVersion = await context.readPackageVersion();
240
+ if (parseSemver(currentVersion) === null) {
241
+ return;
242
+ }
243
+ const cachePath = context.resolveUpdateCheckStatePath();
244
+ const now = context.now();
245
+ let cache = await loadUpdateCheckCache(cachePath) ?? createEmptyUpdateCheckCache();
246
+ let cacheChanged = false;
247
+ if (shouldRefreshUpdateCheck(cache, now)) {
248
+ const updateResult = await fetchLatestPublishedVersion(context.fetchImpl);
249
+ cache = {
250
+ ...cache,
251
+ lastCheckedAtUnixMs: now,
252
+ latestVersion: updateResult.kind === "success"
253
+ ? updateResult.latestVersion
254
+ : cache.latestVersion,
255
+ lastCheckErrorKind: updateResult.kind === "success"
256
+ ? undefined
257
+ : updateResult.errorKind,
258
+ };
259
+ cacheChanged = true;
260
+ }
261
+ if (cache.latestVersion !== null
262
+ && shouldNotifyForVersionPair(cache, currentVersion, cache.latestVersion, now)) {
263
+ writeUpdateNotice(context, currentVersion, cache.latestVersion);
264
+ cache = recordUpdateNotification(cache, currentVersion, cache.latestVersion, now);
265
+ cacheChanged = true;
266
+ await persistUpdateCheckCache(cachePath, cache);
267
+ return;
268
+ }
269
+ if (cacheChanged) {
270
+ await persistUpdateCheckCache(cachePath, cache);
271
+ }
272
+ }
273
+ catch {
274
+ // Update checks are best-effort only.
275
+ }
276
+ }
@@ -2,7 +2,7 @@ import type { BitcoinBlock, GenesisParameters, IndexerState } from "@cogcoin/ind
2
2
  import type { ApplyBlockResult, Client, ClientStoreAdapter, ClientTip } from "../types.js";
3
3
  export declare class DefaultClient implements Client {
4
4
  #private;
5
- constructor(store: ClientStoreAdapter, genesisParameters: GenesisParameters, state: IndexerState, tip: ClientTip | null, snapshotInterval: number);
5
+ constructor(store: ClientStoreAdapter, genesisParameters: GenesisParameters, state: IndexerState, tip: ClientTip | null, snapshotInterval: number, blockRecordRetention: number);
6
6
  getTip(): Promise<ClientTip | null>;
7
7
  getState(): Promise<IndexerState>;
8
8
  applyBlock(block: BitcoinBlock): Promise<ApplyBlockResult>;
@@ -4,16 +4,18 @@ export class DefaultClient {
4
4
  #store;
5
5
  #genesisParameters;
6
6
  #snapshotInterval;
7
+ #blockRecordRetention;
7
8
  #state;
8
9
  #tip;
9
10
  #closed = false;
10
11
  #queue = Promise.resolve();
11
- constructor(store, genesisParameters, state, tip, snapshotInterval) {
12
+ constructor(store, genesisParameters, state, tip, snapshotInterval, blockRecordRetention) {
12
13
  this.#store = store;
13
14
  this.#genesisParameters = genesisParameters;
14
15
  this.#state = state;
15
16
  this.#tip = tip;
16
17
  this.#snapshotInterval = snapshotInterval;
18
+ this.#blockRecordRetention = blockRecordRetention;
17
19
  }
18
20
  async getTip() {
19
21
  await this.#queue;
@@ -39,6 +41,7 @@ export class DefaultClient {
39
41
  blockRecord: createStoredBlockRecord(applied.blockRecord, createdAt),
40
42
  checkpoint,
41
43
  deleteAboveHeight: null,
44
+ deleteBelowHeight: this.#blockRecordLowerBound(block.height),
42
45
  };
43
46
  await this.#store.writeAppliedBlock(writeEntry);
44
47
  this.#state = applied.state;
@@ -110,6 +113,9 @@ export class DefaultClient {
110
113
  #shouldCheckpoint(height) {
111
114
  return this.#snapshotInterval > 0 && height % this.#snapshotInterval === 0;
112
115
  }
116
+ #blockRecordLowerBound(height) {
117
+ return height - this.#blockRecordRetention + 1;
118
+ }
113
119
  #enqueue(operation) {
114
120
  const next = this.#queue.then(operation, operation);
115
121
  this.#queue = next.then(() => undefined, () => undefined);
@@ -3,13 +3,18 @@ import { DefaultClient } from "./default-client.js";
3
3
  import { initializeState } from "./initialization.js";
4
4
  import { createClientStoreAdapter } from "./store-adapter.js";
5
5
  const DEFAULT_SNAPSHOT_INTERVAL = 1000;
6
+ const DEFAULT_BLOCK_RECORD_RETENTION = 1000;
6
7
  export async function openClient(options) {
7
8
  const store = createClientStoreAdapter(options.store);
8
9
  const genesisParameters = options.genesisParameters ?? await loadBundledGenesisParameters();
9
10
  const snapshotInterval = options.snapshotInterval ?? DEFAULT_SNAPSHOT_INTERVAL;
11
+ const blockRecordRetention = options.blockRecordRetention ?? DEFAULT_BLOCK_RECORD_RETENTION;
10
12
  if (!Number.isInteger(snapshotInterval) || snapshotInterval < 1) {
11
13
  throw new RangeError("client_snapshot_interval_invalid");
12
14
  }
15
+ if (!Number.isInteger(blockRecordRetention) || blockRecordRetention < 1) {
16
+ throw new RangeError("client_block_record_retention_invalid");
17
+ }
13
18
  const { state, tip } = await initializeState(store, genesisParameters);
14
- return new DefaultClient(store, genesisParameters, state, tip, snapshotInterval);
19
+ return new DefaultClient(store, genesisParameters, state, tip, snapshotInterval, blockRecordRetention);
15
20
  }
@@ -66,6 +66,9 @@ export function createSqliteStoreAdapter(database) {
66
66
  await database.run(`DELETE FROM block_records WHERE height > ?`, [entry.deleteAboveHeight]);
67
67
  await deleteCheckpointsAbove(database, entry.deleteAboveHeight);
68
68
  }
69
+ if (entry.deleteBelowHeight !== null && entry.deleteBelowHeight !== undefined) {
70
+ await database.run(`DELETE FROM block_records WHERE height < ?`, [entry.deleteBelowHeight]);
71
+ }
69
72
  if (entry.blockRecord !== null && entry.blockRecord !== undefined) {
70
73
  await database.run(`INSERT INTO block_records (height, block_hash, previous_hash, record_bytes, state_hash_hex, created_at)
71
74
  VALUES (?, ?, ?, ?, ?, ?)`, [
package/dist/types.d.ts CHANGED
@@ -25,6 +25,7 @@ export interface WriteAppliedBlockEntry {
25
25
  blockRecord?: StoredBlockRecord | null;
26
26
  checkpoint?: ClientCheckpoint | null;
27
27
  deleteAboveHeight?: number | null;
28
+ deleteBelowHeight?: number | null;
28
29
  }
29
30
  export interface ClientStoreAdapter {
30
31
  loadTip(): Promise<ClientTip | null>;
@@ -39,6 +40,7 @@ export interface ClientOptions {
39
40
  store: ClientStoreAdapter;
40
41
  genesisParameters?: GenesisParameters;
41
42
  snapshotInterval?: number;
43
+ blockRecordRetention?: number;
42
44
  }
43
45
  export interface ApplyBlockResult {
44
46
  tip: ClientTip;
@@ -1,18 +1,20 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import { writeJsonFileAtomic } from "./fs/atomic.js";
3
+ import { normalizePortableWalletArchivePayload } from "./coin-control.js";
3
4
  import { decryptJsonWithPassphrase, encryptJsonWithPassphrase, } from "./state/crypto.js";
4
5
  export const PORTABLE_WALLET_ARCHIVE_FORMAT = "cogcoin-portable-wallet-archive";
5
6
  function assertPortableWalletArchivePayload(payload) {
6
- if (payload.schemaVersion !== 1
7
- || payload.walletRootId.trim() === ""
8
- || payload.mnemonic.phrase.trim() === ""
9
- || payload.expected.accountPath.trim() === ""
10
- || payload.expected.publicExternalDescriptor.trim() === ""
11
- || payload.expected.fundingAddress0.trim() === ""
12
- || payload.expected.fundingScriptPubKeyHex0.trim() === "") {
7
+ const normalized = normalizePortableWalletArchivePayload(payload);
8
+ if (normalized.schemaVersion !== 1
9
+ || normalized.walletRootId.trim() === ""
10
+ || normalized.mnemonic.phrase.trim() === ""
11
+ || normalized.expected.accountPath.trim() === ""
12
+ || normalized.expected.publicExternalDescriptor.trim() === ""
13
+ || normalized.expected.fundingAddress0.trim() === ""
14
+ || normalized.expected.fundingScriptPubKeyHex0.trim() === "") {
13
15
  throw new Error("wallet_archive_payload_invalid");
14
16
  }
15
- return payload;
17
+ return normalized;
16
18
  }
17
19
  export async function writePortableWalletArchive(path, payload, passphrase) {
18
20
  const envelope = await encryptJsonWithPassphrase(assertPortableWalletArchivePayload(payload), passphrase, {
@@ -0,0 +1,41 @@
1
+ import type { RpcListUnspentEntry, RpcLockedUnspent } from "../bitcoind/types.js";
2
+ import { persistWalletStateUpdate } from "./descriptor-normalization.js";
3
+ import type { WalletRuntimePaths } from "./runtime.js";
4
+ import type { OutpointRecord, PortableWalletArchivePayloadV1, UnlockSessionStateV1, WalletStateV1 } from "./types.js";
5
+ export declare const DEFAULT_PROACTIVE_RESERVE_SATS = 50000;
6
+ export interface WalletCoinControlRpc {
7
+ listUnspent(walletName: string, minConf?: number): Promise<RpcListUnspentEntry[]>;
8
+ listLockUnspent(walletName: string): Promise<RpcLockedUnspent[]>;
9
+ lockUnspent(walletName: string, unlock: boolean, outputs: RpcLockedUnspent[]): Promise<boolean>;
10
+ }
11
+ export declare function outpointKey(outpoint: OutpointRecord): string;
12
+ export declare function normalizeWalletStateRecord(state: WalletStateV1): WalletStateV1;
13
+ export declare function normalizePortableWalletArchivePayload(payload: PortableWalletArchivePayloadV1): PortableWalletArchivePayloadV1;
14
+ export declare function computeDesignatedProactiveReserveOutpoints(state: WalletStateV1, spendableUtxos: readonly RpcListUnspentEntry[]): OutpointRecord[];
15
+ export declare function reconcilePersistentPolicyLocks(options: {
16
+ rpc: WalletCoinControlRpc;
17
+ walletName: string;
18
+ state: WalletStateV1;
19
+ fixedInputs?: readonly OutpointRecord[];
20
+ temporarilyUnlockedOutpoints?: readonly OutpointRecord[];
21
+ cleanupInactiveTemporaryBuilderLocks?: boolean;
22
+ spendableUtxos?: readonly RpcListUnspentEntry[];
23
+ }): Promise<{
24
+ state: WalletStateV1;
25
+ changed: boolean;
26
+ spendableUtxos: readonly RpcListUnspentEntry[];
27
+ }>;
28
+ export declare function persistWalletCoinControlStateIfNeeded(options: {
29
+ state: WalletStateV1;
30
+ access: Parameters<typeof persistWalletStateUpdate>[0]["access"];
31
+ session?: UnlockSessionStateV1 | null;
32
+ paths: WalletRuntimePaths;
33
+ nowUnixMs: number;
34
+ replacePrimary?: boolean;
35
+ rpc: WalletCoinControlRpc;
36
+ cleanupInactiveTemporaryBuilderLocks?: boolean;
37
+ }): Promise<{
38
+ changed: boolean;
39
+ session: UnlockSessionStateV1 | null;
40
+ state: WalletStateV1;
41
+ }>;