@spirobel/monero-wallet-api 0.5.4 → 0.5.5
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/dist/io/sleep.d.ts +1 -1
- package/dist/io/sleep.js +16 -1
- package/dist/scanning-syncing/backgroundWorker.d.ts +2 -0
- package/dist/scanning-syncing/backgroundWorker.js +92 -10
- package/dist/scanning-syncing/blocksbuffer/blocksBufferFetchLoop.js +33 -2
- package/dist/scanning-syncing/connectionStatus.d.ts +6 -0
- package/dist/scanning-syncing/connectionStatus.js +15 -0
- package/dist/scanning-syncing/connectionStatusOpened.d.ts +2 -0
- package/dist/scanning-syncing/connectionStatusOpened.js +20 -3
- package/dist/scanning-syncing/openWallet.d.ts +4 -1
- package/dist/scanning-syncing/openWallet.js +3 -0
- package/dist/scanning-syncing/scanresult/scanCacheOpened.d.ts +10 -4
- package/dist/scanning-syncing/scanresult/scanCacheOpened.js +117 -56
- package/dist/scanning-syncing/scanresult/scanCoordination.d.ts +6 -3
- package/dist/scanning-syncing/scanresult/scanCoordination.js +87 -25
- package/dist/scanning-syncing/scanresult/scanLoop.d.ts +1 -2
- package/dist/scanning-syncing/scanresult/scanLoop.js +0 -13
- package/dist/scanning-syncing/worker-entrypoints/worker.js +1 -1
- package/dist/scanning-syncing/worker-mains/coordinator-main.d.ts +1 -0
- package/dist/scanning-syncing/worker-mains/coordinator-main.js +16 -1
- package/dist/scanning-syncing/worker-mains/cpubound-main.js +3 -2
- package/dist/scanning-syncing/worker-mains/worker.js +45 -2
- package/package.json +1 -1
package/dist/io/sleep.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const sleep: (ms: number) => Promise<
|
|
1
|
+
export declare const sleep: (ms: number, signal?: AbortSignal) => Promise<void>;
|
package/dist/io/sleep.js
CHANGED
|
@@ -1 +1,16 @@
|
|
|
1
|
-
export const sleep = (ms) => new Promise((resolve) =>
|
|
1
|
+
export const sleep = (ms, signal) => new Promise((resolve, reject) => {
|
|
2
|
+
if (signal?.aborted) {
|
|
3
|
+
reject(signal.reason ?? new DOMException("aborted", "AbortError"));
|
|
4
|
+
return;
|
|
5
|
+
}
|
|
6
|
+
const onAbort = () => {
|
|
7
|
+
clearTimeout(timer);
|
|
8
|
+
signal?.removeEventListener("abort", onAbort);
|
|
9
|
+
reject(signal?.reason ?? new DOMException("aborted", "AbortError"));
|
|
10
|
+
};
|
|
11
|
+
const timer = setTimeout(() => {
|
|
12
|
+
signal?.removeEventListener("abort", onAbort);
|
|
13
|
+
resolve();
|
|
14
|
+
}, ms);
|
|
15
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
16
|
+
});
|
|
@@ -3,7 +3,9 @@ export declare const CPU_POOL_SIZE = 4;
|
|
|
3
3
|
export type WorkerSet = {
|
|
4
4
|
fetchWorker: Worker;
|
|
5
5
|
cpuWorkers: Worker[];
|
|
6
|
+
shutdown: (timeoutMs?: number) => Promise<void>;
|
|
6
7
|
terminate: () => void;
|
|
8
|
+
dumpHeaps: (dir?: string) => Promise<string[]>;
|
|
7
9
|
};
|
|
8
10
|
export declare function createWebworker(handle_result?: (result: CacheChangedCallbackParameters) => void, scan_settings_path?: string, pathPrefix?: string, handle_error?: (error: unknown) => void): Promise<WorkerSet | undefined>;
|
|
9
11
|
export declare function makeWebworkerScript(): string;
|
|
@@ -46,6 +46,36 @@ export async function createWebworker(handle_result, scan_settings_path, pathPre
|
|
|
46
46
|
"coordinator worker started, node_url=" + node_url,
|
|
47
47
|
", cpuPorts=" + cpuPorts.length,
|
|
48
48
|
]);
|
|
49
|
+
let shutdownResolve;
|
|
50
|
+
let shuttingDown = false;
|
|
51
|
+
const hardTerminate = () => {
|
|
52
|
+
for (const p of cpuPorts) {
|
|
53
|
+
try {
|
|
54
|
+
p.close();
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// port may already be closed
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
coordinationWorker.onmessage = null;
|
|
61
|
+
coordinationWorker.onerror = null;
|
|
62
|
+
for (const w of cpuWorkers) {
|
|
63
|
+
w.onerror = null;
|
|
64
|
+
w.onmessage = null;
|
|
65
|
+
try {
|
|
66
|
+
w.terminate();
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// already dead
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
coordinationWorker.terminate();
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// already dead
|
|
77
|
+
}
|
|
78
|
+
};
|
|
49
79
|
coordinationWorker.onmessage = (event) => {
|
|
50
80
|
if (event.data.type === "ERROR") {
|
|
51
81
|
if (handle_error)
|
|
@@ -55,22 +85,74 @@ export async function createWebworker(handle_result, scan_settings_path, pathPre
|
|
|
55
85
|
if (handle_result)
|
|
56
86
|
handle_result(event.data.payload);
|
|
57
87
|
}
|
|
88
|
+
else if (event.data.type === "SHUTDOWN_DONE") {
|
|
89
|
+
log("createWebworker", ["SHUTDOWN_DONE received"]);
|
|
90
|
+
shutdownResolve?.();
|
|
91
|
+
shutdownResolve = undefined;
|
|
92
|
+
}
|
|
58
93
|
};
|
|
94
|
+
// wait for one HEAP_SNAPSHOT_DONE / ERROR from a worker
|
|
95
|
+
const waitHeap = (w, path, timeoutMs = 15000) => new Promise((resolve, reject) => {
|
|
96
|
+
const t = setTimeout(() => {
|
|
97
|
+
w.removeEventListener("message", onMsg);
|
|
98
|
+
reject(new Error("heap snapshot timeout: " + path));
|
|
99
|
+
}, timeoutMs);
|
|
100
|
+
const onMsg = (event) => {
|
|
101
|
+
if (event.data?.type === "HEAP_SNAPSHOT_DONE") {
|
|
102
|
+
clearTimeout(t);
|
|
103
|
+
w.removeEventListener("message", onMsg);
|
|
104
|
+
resolve(event.data.path || path);
|
|
105
|
+
}
|
|
106
|
+
else if (event.data?.type === "HEAP_SNAPSHOT_ERROR") {
|
|
107
|
+
clearTimeout(t);
|
|
108
|
+
w.removeEventListener("message", onMsg);
|
|
109
|
+
reject(new Error(String(event.data.error || "heap snapshot failed")));
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
w.addEventListener("message", onMsg);
|
|
113
|
+
try {
|
|
114
|
+
w.postMessage({ type: "heap_snapshot", path });
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
clearTimeout(t);
|
|
118
|
+
w.removeEventListener("message", onMsg);
|
|
119
|
+
reject(err);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
59
122
|
return {
|
|
60
123
|
fetchWorker: coordinationWorker,
|
|
61
124
|
cpuWorkers,
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
125
|
+
// graceful only: abort fetch, cancel cpus, wait. does not terminate.
|
|
126
|
+
shutdown: async (timeoutMs = 5000) => {
|
|
127
|
+
if (shuttingDown)
|
|
128
|
+
return;
|
|
129
|
+
shuttingDown = true;
|
|
130
|
+
log("createWebworker", ["shutdown start, timeoutMs=", timeoutMs]);
|
|
131
|
+
const done = new Promise((resolve) => {
|
|
132
|
+
shutdownResolve = resolve;
|
|
133
|
+
});
|
|
134
|
+
try {
|
|
135
|
+
coordinationWorker.postMessage({ type: "shutdown" });
|
|
65
136
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
w.onerror = null;
|
|
70
|
-
w.onmessage = null;
|
|
71
|
-
w.terminate();
|
|
137
|
+
catch (err) {
|
|
138
|
+
log("createWebworker", ["post shutdown failed", String(err)]);
|
|
139
|
+
return;
|
|
72
140
|
}
|
|
73
|
-
|
|
141
|
+
await Promise.race([done, sleep(timeoutMs)]);
|
|
142
|
+
},
|
|
143
|
+
terminate: () => {
|
|
144
|
+
hardTerminate();
|
|
145
|
+
},
|
|
146
|
+
dumpHeaps: async (dir = ".") => {
|
|
147
|
+
const stamp = Date.now();
|
|
148
|
+
const paths = [];
|
|
149
|
+
const coordPath = `${dir}/coordinator-${stamp}.heapsnapshot`;
|
|
150
|
+
paths.push(await waitHeap(coordinationWorker, coordPath));
|
|
151
|
+
for (let i = 0; i < cpuWorkers.length; i++) {
|
|
152
|
+
const p = `${dir}/cpubound-${i}-${stamp}.heapsnapshot`;
|
|
153
|
+
paths.push(await waitHeap(cpuWorkers[i], p));
|
|
154
|
+
}
|
|
155
|
+
return paths;
|
|
74
156
|
},
|
|
75
157
|
};
|
|
76
158
|
}
|
|
@@ -27,6 +27,10 @@ max_blocks_buffer_size = MAX_BLOCKS_BUFFER_SIZE, anchor_range, stopSync) {
|
|
|
27
27
|
};
|
|
28
28
|
yield connection_status.last_packet;
|
|
29
29
|
while (true) {
|
|
30
|
+
if (stopSync?.aborted) {
|
|
31
|
+
log("blocksBufferFetchLoop", ["aborted, exiting fetch loop"]);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
30
34
|
// avoid overwriting last_packet in case of catastrophic reorg
|
|
31
35
|
// this generator will block on this. coordinator should rethrow the CatastrophicReorgError
|
|
32
36
|
if (connection_status.last_packet.status === "catastrophic_reorg") {
|
|
@@ -39,9 +43,17 @@ max_blocks_buffer_size = MAX_BLOCKS_BUFFER_SIZE, anchor_range, stopSync) {
|
|
|
39
43
|
bytes_read: 0,
|
|
40
44
|
node_url: node_url,
|
|
41
45
|
timestamp: new Date().toISOString(),
|
|
46
|
+
daemon_height: connection_status.sync.daemon_height ||
|
|
47
|
+
connection_status.last_packet.daemon_height,
|
|
42
48
|
};
|
|
43
49
|
yield connection_status.last_packet;
|
|
44
|
-
|
|
50
|
+
try {
|
|
51
|
+
await sleep(1000, stopSync);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
log("blocksBufferFetchLoop", ["aborted during buffer-full sleep"]);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
45
57
|
continue;
|
|
46
58
|
}
|
|
47
59
|
log("blocksBufferFetchLoop", [
|
|
@@ -56,11 +68,18 @@ max_blocks_buffer_size = MAX_BLOCKS_BUFFER_SIZE, anchor_range, stopSync) {
|
|
|
56
68
|
get_blocks_bin = await doRPCrequest(nodeUrl, current_range, stopSync);
|
|
57
69
|
}
|
|
58
70
|
catch (error) {
|
|
71
|
+
// abort is intentional shutdown, not a connection failure
|
|
72
|
+
if (stopSync?.aborted || isAbortError(error)) {
|
|
73
|
+
log("blocksBufferFetchLoop", ["aborted during rpc request"]);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
59
76
|
connection_status.last_packet = {
|
|
60
77
|
status: "connection_failed",
|
|
61
78
|
bytes_read: 0,
|
|
62
79
|
node_url,
|
|
63
80
|
timestamp: new Date().toISOString(),
|
|
81
|
+
daemon_height: connection_status.sync.daemon_height ||
|
|
82
|
+
connection_status.last_packet.daemon_height,
|
|
64
83
|
};
|
|
65
84
|
yield connection_status.last_packet;
|
|
66
85
|
throw error;
|
|
@@ -78,7 +97,13 @@ max_blocks_buffer_size = MAX_BLOCKS_BUFFER_SIZE, anchor_range, stopSync) {
|
|
|
78
97
|
yield connection_status.last_packet;
|
|
79
98
|
// no new blocks: at tip, sleep and retry
|
|
80
99
|
if (!result_meta.block_infos.length) {
|
|
81
|
-
|
|
100
|
+
try {
|
|
101
|
+
await sleep(1000, stopSync);
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
log("blocksBufferFetchLoop", ["aborted during tip sleep"]);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
82
107
|
continue;
|
|
83
108
|
}
|
|
84
109
|
const bufferItem = makeBlocksBufferItem(result_meta, get_blocks_bin);
|
|
@@ -379,3 +404,9 @@ export async function reduceStartHeightToTip(start_height, node_url) {
|
|
|
379
404
|
export class CatastrophicReorgError extends Error {
|
|
380
405
|
name = "CatastrophicReorgError";
|
|
381
406
|
}
|
|
407
|
+
function isAbortError(error) {
|
|
408
|
+
if (!error || typeof error !== "object")
|
|
409
|
+
return false;
|
|
410
|
+
const name = error.name;
|
|
411
|
+
return name === "AbortError" || name === "DOMException";
|
|
412
|
+
}
|
|
@@ -19,6 +19,12 @@ export type ConnectionStatus = {
|
|
|
19
19
|
last_packet: ConnectionSatusLastPacket;
|
|
20
20
|
sync: ConnectionStatusSync;
|
|
21
21
|
};
|
|
22
|
+
export declare function applyWalletScanProgress(cs: ConnectionStatus, progress: {
|
|
23
|
+
current_scan_height: number;
|
|
24
|
+
scanned_ranges?: CacheRange[];
|
|
25
|
+
daemon_height?: number;
|
|
26
|
+
eta?: string;
|
|
27
|
+
}): void;
|
|
22
28
|
export declare const DEFAULT_CONNECTION_STATUS_PREFIX = "ConnectionStatus-";
|
|
23
29
|
export declare function msToHHMM(ms: number): string;
|
|
24
30
|
export declare function emptyConnectionStatus(overrides?: Partial<ConnectionStatus>): ConnectionStatus;
|
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
import { atomicWrite, } from "../api";
|
|
2
2
|
import { SCAN_SETTINGS_STORE_NAME_DEFAULT } from "../api";
|
|
3
|
+
// wallet progress write: always set scan fields; only replace eta when a new one is provided
|
|
4
|
+
// so a missing eta does not wipe / flicker the previous value.
|
|
5
|
+
export function applyWalletScanProgress(cs, progress) {
|
|
6
|
+
cs.sync.current_scan_height = progress.current_scan_height;
|
|
7
|
+
if (progress.scanned_ranges) {
|
|
8
|
+
cs.sync.scanned_ranges = progress.scanned_ranges;
|
|
9
|
+
}
|
|
10
|
+
if (typeof progress.daemon_height === "number") {
|
|
11
|
+
cs.sync.daemon_height = progress.daemon_height;
|
|
12
|
+
}
|
|
13
|
+
if (progress.eta !== undefined) {
|
|
14
|
+
cs.sync.eta = progress.eta;
|
|
15
|
+
}
|
|
16
|
+
cs.sync.timestamp = new Date().toISOString();
|
|
17
|
+
}
|
|
3
18
|
export const DEFAULT_CONNECTION_STATUS_PREFIX = "ConnectionStatus-";
|
|
4
19
|
export function msToHHMM(ms) {
|
|
5
20
|
const totalSeconds = Math.floor(ms / 1000);
|
|
@@ -4,6 +4,7 @@ export declare class ConnectionStatusOpened {
|
|
|
4
4
|
private _timer;
|
|
5
5
|
private _cached;
|
|
6
6
|
private _prevConnected;
|
|
7
|
+
private _prevSyncKey;
|
|
7
8
|
private _path;
|
|
8
9
|
constructor(scan_settings_path: string, _onChange?: ((status: ConnectionStatus | null) => void) | null | undefined);
|
|
9
10
|
watch(intervalMs?: number): Promise<void>;
|
|
@@ -11,5 +12,6 @@ export declare class ConnectionStatusOpened {
|
|
|
11
12
|
get connectionStatus(): ConnectionStatus | null;
|
|
12
13
|
get isConnected(): boolean;
|
|
13
14
|
get daemonHeight(): number | undefined;
|
|
15
|
+
private _syncKey;
|
|
14
16
|
private _poll;
|
|
15
17
|
}
|
|
@@ -4,6 +4,8 @@ export class ConnectionStatusOpened {
|
|
|
4
4
|
_timer;
|
|
5
5
|
_cached = null;
|
|
6
6
|
_prevConnected = false;
|
|
7
|
+
// notify when sync progress fields change, not only connect flip
|
|
8
|
+
_prevSyncKey = "";
|
|
7
9
|
_path;
|
|
8
10
|
constructor(scan_settings_path, _onChange) {
|
|
9
11
|
this._onChange = _onChange;
|
|
@@ -37,14 +39,29 @@ export class ConnectionStatusOpened {
|
|
|
37
39
|
return age >= 0 && age <= 10_000;
|
|
38
40
|
}
|
|
39
41
|
get daemonHeight() {
|
|
40
|
-
return this._cached?.
|
|
42
|
+
return this._cached?.sync?.daemon_height;
|
|
43
|
+
}
|
|
44
|
+
_syncKey(cs) {
|
|
45
|
+
const s = cs?.sync;
|
|
46
|
+
if (!s)
|
|
47
|
+
return "";
|
|
48
|
+
return [
|
|
49
|
+
s.daemon_height ?? "",
|
|
50
|
+
s.current_scan_height ?? "",
|
|
51
|
+
s.eta ?? "",
|
|
52
|
+
s.timestamp ?? "",
|
|
53
|
+
].join("|");
|
|
41
54
|
}
|
|
42
55
|
async _poll() {
|
|
43
56
|
this._cached =
|
|
44
57
|
(await readConnectionStatusFile(this._path).catch(() => null)) || null;
|
|
45
58
|
const now = this.isConnected;
|
|
46
|
-
|
|
47
|
-
|
|
59
|
+
const syncKey = this._syncKey(this._cached);
|
|
60
|
+
const connectedChanged = now !== this._prevConnected;
|
|
61
|
+
const syncChanged = syncKey !== this._prevSyncKey;
|
|
62
|
+
this._prevConnected = now;
|
|
63
|
+
this._prevSyncKey = syncKey;
|
|
64
|
+
if (connectedChanged || syncChanged) {
|
|
48
65
|
this._onChange?.(this._cached);
|
|
49
66
|
}
|
|
50
67
|
}
|
|
@@ -7,9 +7,12 @@ import { ManyScanCachesOpened, ScanCacheOpened, type ManyScanCachesOpenedCreateO
|
|
|
7
7
|
* @param options.no_worker to feed the ManyScanCachesOpened manually with .feed(params) from CacheChangedCallbackParams
|
|
8
8
|
* @param options.no_stats to disable creation of stats file with aggregated information e.g. amount per wallet / subaddress
|
|
9
9
|
* @param options.notifyMasterChanged pass the output of this to another (no_worker) instance to feed
|
|
10
|
+
* @param options.logs "console" | "file" | "console-and-file" | "off"
|
|
11
|
+
* @param options.logs_include function names to include (e.g. handleCpuboundScan, blocksBufferFetchLoop)
|
|
12
|
+
* @param options.logs_exclude function names to exclude
|
|
10
13
|
* @returns Promise<ManyScanCachesOpened>
|
|
11
14
|
*/
|
|
12
|
-
export declare function openWallets(options?: ManyScanCachesOpenedCreateOptions): Promise<ManyScanCachesOpened
|
|
15
|
+
export declare function openWallets(options?: ManyScanCachesOpenedCreateOptions): Promise<ManyScanCachesOpened>;
|
|
13
16
|
/**
|
|
14
17
|
* Opens a **single wallet** for scanning.
|
|
15
18
|
* **Touches ScanSettings.json**,
|
|
@@ -8,6 +8,9 @@ import { openScanSettingsFile, writeWalletToScanSettings } from "../api";
|
|
|
8
8
|
* @param options.no_worker to feed the ManyScanCachesOpened manually with .feed(params) from CacheChangedCallbackParams
|
|
9
9
|
* @param options.no_stats to disable creation of stats file with aggregated information e.g. amount per wallet / subaddress
|
|
10
10
|
* @param options.notifyMasterChanged pass the output of this to another (no_worker) instance to feed
|
|
11
|
+
* @param options.logs "console" | "file" | "console-and-file" | "off"
|
|
12
|
+
* @param options.logs_include function names to include (e.g. handleCpuboundScan, blocksBufferFetchLoop)
|
|
13
|
+
* @param options.logs_exclude function names to exclude
|
|
11
14
|
* @returns Promise<ManyScanCachesOpened>
|
|
12
15
|
*/
|
|
13
16
|
export async function openWallets(options) {
|
|
@@ -129,7 +129,8 @@ export declare class ScanCacheOpened {
|
|
|
129
129
|
remove: () => null;
|
|
130
130
|
};
|
|
131
131
|
pause(): Promise<void>;
|
|
132
|
-
|
|
132
|
+
dumpWorkerHeaps(dir?: string): Promise<string[]>;
|
|
133
|
+
stopWorker(): Promise<void>;
|
|
133
134
|
unpause(): Promise<void>;
|
|
134
135
|
private _onWorkerError;
|
|
135
136
|
/**
|
|
@@ -178,6 +179,9 @@ export type ManyScanCachesOpenedCreateOptions = {
|
|
|
178
179
|
retryDelayMs?: number;
|
|
179
180
|
connectionStatusIntervalMs?: number;
|
|
180
181
|
onConnectionStatusChange?: ((status: ConnectionStatus | null) => void) | null;
|
|
182
|
+
logs?: LogSetting;
|
|
183
|
+
logs_include?: PossibleLogs[];
|
|
184
|
+
logs_exclude?: PossibleLogs[];
|
|
181
185
|
};
|
|
182
186
|
export declare class ManyScanCachesOpened {
|
|
183
187
|
readonly connectionStatusOpened: ConnectionStatusOpened;
|
|
@@ -187,8 +191,9 @@ export declare class ManyScanCachesOpened {
|
|
|
187
191
|
get current_height(): number | null;
|
|
188
192
|
get node_url(): string;
|
|
189
193
|
changeNodeUrlAndStartHeight(node_url?: string, start_height?: number | null): Promise<void>;
|
|
190
|
-
retry(): Promise<boolean>;
|
|
191
|
-
stopWorker(): void
|
|
194
|
+
retry(): Promise<boolean | undefined>;
|
|
195
|
+
stopWorker(): Promise<void>;
|
|
196
|
+
dumpWorkerHeaps(dir?: string): Promise<string[]>;
|
|
192
197
|
changeNodeUrl(node_url: string): Promise<void>;
|
|
193
198
|
get merchant_confirmations(): number | null | undefined;
|
|
194
199
|
get cpu_worker_count(): number | undefined;
|
|
@@ -206,8 +211,9 @@ export declare class ManyScanCachesOpened {
|
|
|
206
211
|
setWalletSlot(primary_address: string, slot?: number): Promise<void>;
|
|
207
212
|
changeStartHeight(start_height: number | null): Promise<void>;
|
|
208
213
|
private static _buildWallets;
|
|
209
|
-
static create(options: ManyScanCachesOpenedCreateOptions): Promise<ManyScanCachesOpened
|
|
214
|
+
static create(options: ManyScanCachesOpenedCreateOptions): Promise<ManyScanCachesOpened>;
|
|
210
215
|
buildWallets(): Promise<void>;
|
|
216
|
+
private reloadWalletsAfterStop;
|
|
211
217
|
addViewWallet(primary_address: string, view_key: string, fields?: {
|
|
212
218
|
wallet_name?: string;
|
|
213
219
|
wallet_slot?: number;
|