@spirobel/monero-wallet-api 0.4.0 → 0.5.0
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 +80 -8
- package/dist/api.d.ts +4 -0
- package/dist/api.js +4 -0
- package/dist/io/atomicWrite.js +2 -1
- package/dist/io/logging.d.ts +40 -0
- package/dist/io/logging.js +174 -0
- package/dist/keypairs-seeds/keypairs.d.ts +8 -0
- package/dist/keypairs-seeds/keypairs.js +31 -3
- package/dist/multisig/DistributedKeyGenerator.d.ts +125 -0
- package/dist/multisig/DistributedKeyGenerator.js +197 -0
- package/dist/multisig/MultiSigTxSigner.d.ts +68 -0
- package/dist/multisig/MultiSigTxSigner.js +123 -0
- package/dist/multisig/escrow.d.ts +58 -0
- package/dist/multisig/escrow.js +104 -0
- package/dist/multisig/multisig.d.ts +36 -0
- package/dist/multisig/multisig.js +140 -0
- package/dist/node-interaction/nodeUrl.js +2 -1
- package/dist/scanning-syncing/backgroundWorker.d.ts +2 -0
- package/dist/scanning-syncing/backgroundWorker.js +20 -8
- package/dist/scanning-syncing/blocksbuffer/blocksBufferFetchLoop.js +9 -7
- package/dist/scanning-syncing/blocksbuffer/blocksbufferCoordination.js +2 -1
- package/dist/scanning-syncing/scanSettings.d.ts +11 -0
- package/dist/scanning-syncing/scanSettings.js +18 -3
- package/dist/scanning-syncing/scanresult/computeKeyImage.d.ts +2 -1
- package/dist/scanning-syncing/scanresult/computeKeyImage.js +4 -2
- package/dist/scanning-syncing/scanresult/scanCache.js +7 -3
- package/dist/scanning-syncing/scanresult/scanCacheOpened.d.ts +11 -0
- package/dist/scanning-syncing/scanresult/scanCacheOpened.js +104 -11
- package/dist/scanning-syncing/scanresult/scanCoordination.js +63 -72
- package/dist/scanning-syncing/scanresult/scanResult.d.ts +1 -1
- package/dist/scanning-syncing/scanresult/scanResult.js +19 -6
- package/dist/scanning-syncing/worker-entrypoints/worker.js +1 -1
- package/dist/scanning-syncing/worker-mains/coordinator-main.js +3 -2
- package/dist/scanning-syncing/worker-mains/cpubound-main.js +24 -14
- package/dist/scanning-syncing/worker-mains/multisig-main.d.ts +13 -0
- package/dist/scanning-syncing/worker-mains/multisig-main.js +31 -0
- package/dist/scanning-syncing/worker-mains/worker.js +23 -7
- package/dist/send-functionality/multisig.d.ts +72 -0
- package/dist/send-functionality/multisig.js +97 -0
- package/dist/send-functionality/transactionBuilding.d.ts +1 -0
- package/dist/send-functionality/transactionBuilding.js +23 -2
- package/dist/viewpair/ViewPair.d.ts +8 -0
- package/dist/viewpair/ViewPair.js +16 -8
- package/dist/wasm-processing/wasmFile.d.ts +1 -0
- package/dist/wasm-processing/wasmFile.js +8 -3
- package/dist/wasm-processing/wasmProcessor.d.ts +2 -2
- package/dist/wasm-processing/wasmProcessor.js +4 -5
- package/package.json +6 -2
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { log } from "../io/logging";
|
|
2
|
+
import { startWebworkerReady } from "../scanning-syncing/backgroundWorker";
|
|
3
|
+
export class MultiSig {
|
|
4
|
+
worker = undefined;
|
|
5
|
+
/**
|
|
6
|
+
* set up a distributed key generator with t threshold and n total participants
|
|
7
|
+
* @param t - total number of multisig participants
|
|
8
|
+
* @param n - threshold to sign a transaction
|
|
9
|
+
* @returns - Promise<DistributedKeyGenerator>
|
|
10
|
+
*/
|
|
11
|
+
static async createAndSetupGenerators(t, n) {
|
|
12
|
+
const dkg = new MultiSig();
|
|
13
|
+
await dkg.startWorker(t, n);
|
|
14
|
+
return dkg;
|
|
15
|
+
}
|
|
16
|
+
stopWorker() {
|
|
17
|
+
if (this.worker) {
|
|
18
|
+
this.worker.terminate();
|
|
19
|
+
delete this.worker;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async startWorker(t, n) {
|
|
23
|
+
if (!this.worker) {
|
|
24
|
+
this.worker = await startWebworkerReady();
|
|
25
|
+
const that = this;
|
|
26
|
+
const result_promise = new Promise((resolve) => {
|
|
27
|
+
if (!that.worker) {
|
|
28
|
+
resolve();
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
that.worker.onmessage = (e) => {
|
|
32
|
+
const msg = e.data;
|
|
33
|
+
if (msg.type === "multisig-ready") {
|
|
34
|
+
resolve();
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
handleUnknownMessage(msg, "startWorker");
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
that.worker.postMessage({
|
|
41
|
+
type: "setup",
|
|
42
|
+
t,
|
|
43
|
+
n,
|
|
44
|
+
role: "multisig",
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
return await result_promise;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
this.stopWorker();
|
|
51
|
+
this.startWorker(t, n);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* participate in a DKG round (nothrow).
|
|
56
|
+
*
|
|
57
|
+
* @param params dkg_secret_key as 64-byte hex string, context, dkg_public_keys array (length is n implicitly), t (threshold)
|
|
58
|
+
* @returns The participation message as hex, or an error object
|
|
59
|
+
*/
|
|
60
|
+
participateNoThrow(params) {
|
|
61
|
+
const msg = { type: "multisig-call", functionName: "participate", params };
|
|
62
|
+
const that = this;
|
|
63
|
+
const result_promise = new Promise((resolve) => {
|
|
64
|
+
if (!that.worker) {
|
|
65
|
+
handleNoWorkerButMethodCalled("participate");
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
that.worker.onmessage = (e) => {
|
|
69
|
+
const msg = e.data;
|
|
70
|
+
if (msg.type === "multisig-call-result") {
|
|
71
|
+
resolve(msg.result);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
handleUnknownMessage(msg, "participate");
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
that.worker.postMessage(msg);
|
|
78
|
+
});
|
|
79
|
+
return result_promise;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* verify DKG participations and extract the group key (nothrow).
|
|
83
|
+
*
|
|
84
|
+
* @param params dkg_secret_key as 64-byte hex string, context, t (threshold), dkg_public_keys array (length is n implicitly),
|
|
85
|
+
* participations [ paricipant index -> hex participation message ]
|
|
86
|
+
* @returns The group key and params, faulty participants, not-enough message, or error
|
|
87
|
+
*/
|
|
88
|
+
verifyNoThrow(params) {
|
|
89
|
+
const msg = { type: "multisig-call", functionName: "verify", params };
|
|
90
|
+
const that = this;
|
|
91
|
+
const result_promise = new Promise((resolve) => {
|
|
92
|
+
if (!that.worker) {
|
|
93
|
+
handleNoWorkerButMethodCalled("participate");
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
that.worker.onmessage = (e) => {
|
|
97
|
+
const msg = e.data;
|
|
98
|
+
if (msg.type === "multisig-call-result") {
|
|
99
|
+
resolve(msg.result);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
handleUnknownMessage(msg, "participate");
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
that.worker.postMessage(msg);
|
|
106
|
+
});
|
|
107
|
+
return result_promise;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* participate in a DKG round (throws on error).
|
|
111
|
+
*/
|
|
112
|
+
async participate(params) {
|
|
113
|
+
const result = await this.participateNoThrow(params);
|
|
114
|
+
if ("message" in result) {
|
|
115
|
+
throw new Error(`participate failed: ${result.message}`);
|
|
116
|
+
}
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* verify DKG participations and extract the group key (throws on error).
|
|
121
|
+
*/
|
|
122
|
+
async verify(params) {
|
|
123
|
+
const result = await this.verifyNoThrow(params);
|
|
124
|
+
if ("message" in result) {
|
|
125
|
+
throw new Error(`verify failed: ${result.message}`);
|
|
126
|
+
}
|
|
127
|
+
if ("faulty_participants" in result) {
|
|
128
|
+
throw new Error(`verify failed: ${result.faulty_participants}`);
|
|
129
|
+
}
|
|
130
|
+
return result;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function handleUnknownMessage(msg, functionName) {
|
|
134
|
+
log("multisig", [`${functionName}(): unknown message type: ${msg.type}`]);
|
|
135
|
+
throw new Error(`[multisig] ${functionName}(): unknown message type: ${msg.type}`);
|
|
136
|
+
}
|
|
137
|
+
function handleNoWorkerButMethodCalled(functionName) {
|
|
138
|
+
log("multisig", [`${functionName}(): no worker`]);
|
|
139
|
+
throw new Error(`[multisig] ${functionName}(): no worker`);
|
|
140
|
+
}
|
|
@@ -2,6 +2,7 @@ import { getBlocksBinExecuteRequest, loadGetBlocksBinResponse, getOutsBinJson, g
|
|
|
2
2
|
import { get_block_headers_range, get_fee_estimate, get_info, get_output_distribution, send_raw_transaction, } from "./jsonEndpoints";
|
|
3
3
|
import { makeInput, sampleDecoys, } from "../send-functionality/transactionBuilding";
|
|
4
4
|
import { WasmProcessor } from "../wasm-processing/wasmProcessor";
|
|
5
|
+
import { monero_wallet_api_wasm } from "../wasm-processing/wasmFile";
|
|
5
6
|
/**
|
|
6
7
|
* This class is useful to interact with Moneros DaemonRpc binary requests in a convenient way.
|
|
7
8
|
* (similar to how you would interact with a REST api that gives you json back.)
|
|
@@ -27,7 +28,7 @@ export class NodeUrl extends WasmProcessor {
|
|
|
27
28
|
}
|
|
28
29
|
static async create(node_url) {
|
|
29
30
|
const nodeUrl = new NodeUrl(node_url || LOCAL_NODE_DEFAULT_URL);
|
|
30
|
-
await nodeUrl.initWasmModule();
|
|
31
|
+
await nodeUrl.initWasmModule(monero_wallet_api_wasm);
|
|
31
32
|
return nodeUrl;
|
|
32
33
|
}
|
|
33
34
|
/**
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type CacheChangedCallbackParameters } from "./scanresult/scanCache";
|
|
2
|
+
export declare const CPU_POOL_SIZE = 4;
|
|
2
3
|
export type WorkerSet = {
|
|
3
4
|
fetchWorker: Worker;
|
|
4
5
|
cpuWorkers: Worker[];
|
|
@@ -7,3 +8,4 @@ export type WorkerSet = {
|
|
|
7
8
|
export declare function createWebworker(handle_result?: (result: CacheChangedCallbackParameters) => void, scan_settings_path?: string, pathPrefix?: string, handle_error?: (error: unknown) => void): Promise<WorkerSet | undefined>;
|
|
8
9
|
export declare function makeWebworkerScript(): string;
|
|
9
10
|
export declare function startWebworker(handle_result?: (result: unknown) => void, handle_error?: (error: unknown) => void): Worker;
|
|
11
|
+
export declare function startWebworkerReady(): Promise<Worker>;
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { LOCAL_NODE_DEFAULT_URL } from "../node-interaction/nodeUrl";
|
|
2
2
|
import {} from "./scanresult/scanCache";
|
|
3
|
-
import { openScanSettingsFile } from "./scanSettings";
|
|
3
|
+
import { openScanSettingsFile, SCAN_SETTINGS_STORE_NAME_DEFAULT, } from "./scanSettings";
|
|
4
|
+
import { log, setupLoggingPath } from "../io/logging";
|
|
4
5
|
import { workerMainCode } from "./worker-entrypoints/worker";
|
|
5
|
-
const CPU_POOL_SIZE = 4;
|
|
6
|
+
export const CPU_POOL_SIZE = 4;
|
|
6
7
|
export async function createWebworker(handle_result, scan_settings_path, pathPrefix, handle_error) {
|
|
7
8
|
try {
|
|
8
|
-
const
|
|
9
|
+
const resolvedPath = scan_settings_path || SCAN_SETTINGS_STORE_NAME_DEFAULT;
|
|
10
|
+
const scanSettings = await openScanSettingsFile(resolvedPath);
|
|
11
|
+
await setupLoggingPath(resolvedPath, pathPrefix ?? "", "mainthread");
|
|
9
12
|
const node_url = scanSettings?.node_url || LOCAL_NODE_DEFAULT_URL;
|
|
10
13
|
const cpu_worker_count = typeof scanSettings?.cpu_worker_count !== "undefined"
|
|
11
14
|
? scanSettings?.cpu_worker_count
|
|
@@ -16,7 +19,13 @@ export async function createWebworker(handle_result, scan_settings_path, pathPre
|
|
|
16
19
|
for (let i = 0; i < cpu_worker_count; i++) {
|
|
17
20
|
const channel = new MessageChannel();
|
|
18
21
|
const cpuWorker = await startWebworkerReady();
|
|
19
|
-
cpuWorker.postMessage({
|
|
22
|
+
cpuWorker.postMessage({
|
|
23
|
+
type: "setup",
|
|
24
|
+
role: "cpubound",
|
|
25
|
+
cpu_worker_id: i,
|
|
26
|
+
scan_settings_path: resolvedPath,
|
|
27
|
+
pathPrefix,
|
|
28
|
+
}, [channel.port1]);
|
|
20
29
|
cpuWorker.onerror = (e) => {
|
|
21
30
|
if (handle_error)
|
|
22
31
|
handle_error("cpu worker " + i + " error: " + (e.message ?? String(e)));
|
|
@@ -27,13 +36,16 @@ export async function createWebworker(handle_result, scan_settings_path, pathPre
|
|
|
27
36
|
const coordinationWorker = await startWebworkerReady();
|
|
28
37
|
coordinationWorker.postMessage({
|
|
29
38
|
type: "setup",
|
|
30
|
-
scan_settings_path,
|
|
39
|
+
scan_settings_path: resolvedPath,
|
|
31
40
|
pathPrefix,
|
|
32
41
|
role: "coordinator",
|
|
33
42
|
node_url,
|
|
34
43
|
start_height: 0,
|
|
35
44
|
}, cpuPorts); // transfer CPU port2s to coordination worker
|
|
36
|
-
|
|
45
|
+
log("createWebworker", [
|
|
46
|
+
"coordinator worker started, node_url=" + node_url,
|
|
47
|
+
", cpuPorts=" + cpuPorts.length,
|
|
48
|
+
]);
|
|
37
49
|
coordinationWorker.onmessage = (event) => {
|
|
38
50
|
if (event.data.type === "ERROR") {
|
|
39
51
|
if (handle_error)
|
|
@@ -79,7 +91,7 @@ export function startWebworker(handle_result, handle_error) {
|
|
|
79
91
|
handle_error(event.data.payload ?? event.data.error);
|
|
80
92
|
break;
|
|
81
93
|
case "DEBUG":
|
|
82
|
-
|
|
94
|
+
log("startWebworker", ["worker debug:", event.data.payload]);
|
|
83
95
|
break;
|
|
84
96
|
}
|
|
85
97
|
};
|
|
@@ -89,7 +101,7 @@ export function startWebworker(handle_result, handle_error) {
|
|
|
89
101
|
// WORKER_READY (meaning self.onmessage = handleMessage has executed).
|
|
90
102
|
// after that, postMessage is safe, no race between worker startup
|
|
91
103
|
// and message delivery.
|
|
92
|
-
function startWebworkerReady() {
|
|
104
|
+
export function startWebworkerReady() {
|
|
93
105
|
const worker = startWebworker();
|
|
94
106
|
return new Promise((resolve) => {
|
|
95
107
|
const onReady = (e) => {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { findRange, get_block_headers_range, get_info, mergeRanges, NodeUrl, sleep, } from "../../api";
|
|
2
2
|
import {} from "../connectionStatus";
|
|
3
|
+
import { log } from "../../io/logging";
|
|
3
4
|
export const MAX_BLOCKS_BUFFER_SIZE = 10;
|
|
4
5
|
// runs forever, fetching blocks from the node.
|
|
5
6
|
// handles scan level reorg detection and catastrophic reorg
|
|
@@ -8,7 +9,7 @@ connection_status, // we make a local copy of this and pass last_packet and sync
|
|
|
8
9
|
max_blocks_buffer_size = MAX_BLOCKS_BUFFER_SIZE, anchor_range, stopSync) {
|
|
9
10
|
connection_status = structuredClone(connection_status);
|
|
10
11
|
const nodeUrl = await NodeUrl.create(node_url);
|
|
11
|
-
|
|
12
|
+
log("blocksBufferFetchLoop", ["NodeUrl:", nodeUrl.node_url, "start:", start_height]);
|
|
12
13
|
start_height = await reduceStartHeightToTip(start_height, nodeUrl.node_url);
|
|
13
14
|
// initialise ranges on first call
|
|
14
15
|
let { current_range, scanned_ranges } = await initScannedRanges(nodeUrl.node_url, start_height, anchor_range ? [anchor_range] : []);
|
|
@@ -38,12 +39,10 @@ max_blocks_buffer_size = MAX_BLOCKS_BUFFER_SIZE, anchor_range, stopSync) {
|
|
|
38
39
|
await sleep(5000);
|
|
39
40
|
continue;
|
|
40
41
|
}
|
|
41
|
-
|
|
42
|
+
log("blocksBufferFetchLoop", ["fetching", nodeUrl.node_url, current_range.start, "->", current_range.end]);
|
|
42
43
|
const get_blocks_bin = await doRPCrequest(nodeUrl, current_range, stopSync);
|
|
43
44
|
const result_meta = await nodeUrl.loadGetBlocksBinResponse(get_blocks_bin);
|
|
44
|
-
|
|
45
|
-
result_meta.block_infos.length +
|
|
46
|
-
" blocks");
|
|
45
|
+
log("blocksBufferFetchLoop", "response: " + result_meta.block_infos.length + " blocks");
|
|
47
46
|
connection_status.last_packet = {
|
|
48
47
|
status: "OK",
|
|
49
48
|
bytes_read: get_blocks_bin.length,
|
|
@@ -343,8 +342,11 @@ export async function reduceStartHeightToTip(start_height, node_url) {
|
|
|
343
342
|
if (start_height > getInfo.height - 1) {
|
|
344
343
|
const oldStartHeight = start_height;
|
|
345
344
|
start_height = getInfo.height - 1;
|
|
346
|
-
|
|
347
|
-
|
|
345
|
+
log("reduceStartHeightToTip", [
|
|
346
|
+
"start height was larger than daemon height, setting start_height=" +
|
|
347
|
+
start_height,
|
|
348
|
+
" oldStartHeight=" + oldStartHeight,
|
|
349
|
+
]);
|
|
348
350
|
}
|
|
349
351
|
return start_height;
|
|
350
352
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { blocksBufferFetchLoop, readWriteConnectionStatusFile, CatastrophicReorgError, readOrInitConnectionStatus, } from "../../api";
|
|
2
|
+
import { log } from "../../io/logging";
|
|
2
3
|
export async function setupBlocksBufferGenerator(params) {
|
|
3
4
|
const blocksBuffer = [];
|
|
4
5
|
const connection_status = await readOrInitConnectionStatus(params.scanSettingsPath);
|
|
@@ -13,7 +14,7 @@ export async function handleConnectionStatusChanges(event, scanSettingsPath) {
|
|
|
13
14
|
cs2.last_packet = event;
|
|
14
15
|
}, scanSettingsPath);
|
|
15
16
|
if (event.status === "catastrophic_reorg") {
|
|
16
|
-
|
|
17
|
+
log("handleConnectionStatusChanges", "catastrophic reorg, stopping");
|
|
17
18
|
throw new CatastrophicReorgError("[blocksbufferCoordinator] catastrophic reorg, stopping");
|
|
18
19
|
}
|
|
19
20
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import type { LogSetting, PossibleLogs } from "../io/logging";
|
|
1
2
|
export declare const SCAN_SETTINGS_STORE_NAME_DEFAULT = "ScanSettings.json";
|
|
3
|
+
export declare const SUB_ADDRESS_INDEX_DEFAULT_VALUE = 1;
|
|
2
4
|
export type ScanSetting = {
|
|
3
5
|
primary_address: string;
|
|
4
6
|
subaddress_index?: number;
|
|
@@ -17,6 +19,9 @@ export type WriteScanSettingParams = {
|
|
|
17
19
|
wallet_route?: string;
|
|
18
20
|
wallet_name?: string;
|
|
19
21
|
wallet_slot?: number;
|
|
22
|
+
logs?: LogSetting;
|
|
23
|
+
logs_include?: PossibleLogs[];
|
|
24
|
+
logs_exclude?: PossibleLogs[];
|
|
20
25
|
};
|
|
21
26
|
export type ScanSettingOpened = {
|
|
22
27
|
primary_address: string;
|
|
@@ -36,6 +41,9 @@ export type ScanSettings = {
|
|
|
36
41
|
start_height: number | null;
|
|
37
42
|
merchant_confirmations?: number | null;
|
|
38
43
|
cpu_worker_count?: number;
|
|
44
|
+
logs?: LogSetting;
|
|
45
|
+
logs_include?: PossibleLogs[];
|
|
46
|
+
logs_exclude?: PossibleLogs[];
|
|
39
47
|
};
|
|
40
48
|
export type ScanSettingsOpened = {
|
|
41
49
|
wallets: (ScanSettingOpened | undefined)[];
|
|
@@ -43,6 +51,9 @@ export type ScanSettingsOpened = {
|
|
|
43
51
|
start_height: number | null;
|
|
44
52
|
merchant_confirmations?: number | null;
|
|
45
53
|
cpu_worker_count?: number;
|
|
54
|
+
logs?: LogSetting;
|
|
55
|
+
logs_include?: PossibleLogs[];
|
|
56
|
+
logs_exclude?: PossibleLogs[];
|
|
46
57
|
};
|
|
47
58
|
/**
|
|
48
59
|
* Writes scan settings to the default or specified storage file in json.
|
|
@@ -3,6 +3,10 @@ import { atomicWrite } from "../io/atomicWrite";
|
|
|
3
3
|
import { refreshEnvIndexedDB } from "../io/indexedDB";
|
|
4
4
|
import { LOCAL_NODE_DEFAULT_URL } from "../node-interaction/nodeUrl";
|
|
5
5
|
export const SCAN_SETTINGS_STORE_NAME_DEFAULT = "ScanSettings.json";
|
|
6
|
+
// default value for subaddress highest minor index eg up to which minor index,
|
|
7
|
+
// to add subaddresses to the scanner
|
|
8
|
+
// (we never touch major index, having two values is just too confusing)
|
|
9
|
+
export const SUB_ADDRESS_INDEX_DEFAULT_VALUE = 1;
|
|
6
10
|
/**
|
|
7
11
|
* Writes scan settings to the default or specified storage file in json.
|
|
8
12
|
*
|
|
@@ -231,7 +235,7 @@ export async function writeWalletToScanSettings(params) {
|
|
|
231
235
|
wallets: [
|
|
232
236
|
{
|
|
233
237
|
primary_address: params.primary_address,
|
|
234
|
-
subaddress_index: params.subaddress_index ||
|
|
238
|
+
subaddress_index: params.subaddress_index || SUB_ADDRESS_INDEX_DEFAULT_VALUE,
|
|
235
239
|
halted: params.halted,
|
|
236
240
|
wallet_route: params.wallet_route,
|
|
237
241
|
wallet_name: params.wallet_name,
|
|
@@ -239,10 +243,19 @@ export async function writeWalletToScanSettings(params) {
|
|
|
239
243
|
},
|
|
240
244
|
],
|
|
241
245
|
node_url: params.node_url,
|
|
246
|
+
logs: params.logs,
|
|
247
|
+
logs_include: params.logs_include,
|
|
248
|
+
logs_exclude: params.logs_exclude,
|
|
242
249
|
start_height: params.start_height || null,
|
|
243
250
|
}, params.scan_settings_path);
|
|
244
251
|
}
|
|
245
252
|
scanSettings.node_url = params.node_url || scanSettings.node_url;
|
|
253
|
+
if (params.logs)
|
|
254
|
+
scanSettings.logs = params.logs;
|
|
255
|
+
if (params.logs_include)
|
|
256
|
+
scanSettings.logs_include = params.logs_include;
|
|
257
|
+
if (params.logs_exclude)
|
|
258
|
+
scanSettings.logs_exclude = params.logs_exclude;
|
|
246
259
|
scanSettings.start_height =
|
|
247
260
|
params.start_height === undefined
|
|
248
261
|
? scanSettings.start_height
|
|
@@ -252,7 +265,7 @@ export async function writeWalletToScanSettings(params) {
|
|
|
252
265
|
// wallet does not exist yet in settings
|
|
253
266
|
scanSettings.wallets.push({
|
|
254
267
|
primary_address: params.primary_address,
|
|
255
|
-
subaddress_index: params.subaddress_index ||
|
|
268
|
+
subaddress_index: params.subaddress_index || SUB_ADDRESS_INDEX_DEFAULT_VALUE,
|
|
256
269
|
halted: params.halted,
|
|
257
270
|
wallet_route: params.wallet_route,
|
|
258
271
|
wallet_name: params.wallet_name,
|
|
@@ -264,7 +277,9 @@ export async function writeWalletToScanSettings(params) {
|
|
|
264
277
|
const wallet = scanSettings.wallets[already_has_settings];
|
|
265
278
|
if (wallet) {
|
|
266
279
|
wallet.subaddress_index =
|
|
267
|
-
params.subaddress_index ||
|
|
280
|
+
params.subaddress_index ||
|
|
281
|
+
wallet.subaddress_index ||
|
|
282
|
+
SUB_ADDRESS_INDEX_DEFAULT_VALUE;
|
|
268
283
|
wallet.halted = params.halted || wallet.halted;
|
|
269
284
|
wallet.wallet_route = params.wallet_route || wallet.wallet_route;
|
|
270
285
|
wallet.wallet_name = params.wallet_name || wallet.wallet_name;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import type { Output } from "../../api";
|
|
2
|
+
import { WasmProcessor } from "../../wasm-processing/wasmProcessor";
|
|
2
3
|
export type KeyImage = string;
|
|
3
|
-
export declare function computeKeyImage(output: Output, sender_spend_key: string): Promise<KeyImage | undefined>;
|
|
4
|
+
export declare function computeKeyImage(output: Output, sender_spend_key: string, wasmProcessor?: WasmProcessor): Promise<KeyImage | undefined>;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { monero_wallet_api_wasm } from "../../wasm-processing/wasmFile";
|
|
1
2
|
import { WasmProcessor } from "../../wasm-processing/wasmProcessor";
|
|
2
|
-
export async function computeKeyImage(output, sender_spend_key) {
|
|
3
|
-
|
|
3
|
+
export async function computeKeyImage(output, sender_spend_key, wasmProcessor) {
|
|
4
|
+
if (!wasmProcessor)
|
|
5
|
+
wasmProcessor = await WasmProcessor.init(monero_wallet_api_wasm);
|
|
4
6
|
wasmProcessor.writeToWasmMemory = (ptr, len) => {
|
|
5
7
|
wasmProcessor.writeString(ptr, len, output.serialized);
|
|
6
8
|
wasmProcessor.writeToWasmMemory = (ptr, len) => {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {} from "./computeKeyImage";
|
|
2
2
|
import { get_block_headers_range, } from "../../api";
|
|
3
3
|
import { atomicWrite } from "../../io/atomicWrite";
|
|
4
|
+
import { log } from "../../io/logging";
|
|
4
5
|
export async function initScanCache(viewpair, start_height, scan_settings_path, pathPrefix) {
|
|
5
6
|
const initialCache = await readCacheFileDefaultLocation(viewpair.primary_address, pathPrefix);
|
|
6
7
|
let cache = {
|
|
@@ -161,7 +162,7 @@ export function handleScanError(error) {
|
|
|
161
162
|
// treat errno 0 code "ConnectionRefused" as non fatal outcome, and rethrow,
|
|
162
163
|
// so that UI can be informed after catching it higher up
|
|
163
164
|
if (isConnectionError(error)) {
|
|
164
|
-
|
|
165
|
+
log("handleScanError", "Scan stopped. node might be offline. Connection Refused");
|
|
165
166
|
throw error;
|
|
166
167
|
}
|
|
167
168
|
// Treat AbortError as a normal, non-fatal outcome
|
|
@@ -169,11 +170,14 @@ export function handleScanError(error) {
|
|
|
169
170
|
typeof error === "object" &&
|
|
170
171
|
(("name" in error && error.name === "AbortError") ||
|
|
171
172
|
("code" in error && error.code === 20))) {
|
|
172
|
-
|
|
173
|
+
log("handleScanError", "Scan was aborted.");
|
|
173
174
|
return;
|
|
174
175
|
}
|
|
175
176
|
else {
|
|
176
|
-
|
|
177
|
+
log("handleScanError", [
|
|
178
|
+
error,
|
|
179
|
+
"\n, scanWithCache in scanning-syncing/scanWithCache.ts`",
|
|
180
|
+
]);
|
|
177
181
|
throw error;
|
|
178
182
|
}
|
|
179
183
|
}
|
|
@@ -46,6 +46,7 @@ export declare class ScanCacheOpened {
|
|
|
46
46
|
readonly decoyRetrySizes: number[];
|
|
47
47
|
static create(params: ScanCacheOpenedCreateParams): Promise<ScanCacheOpened>;
|
|
48
48
|
get start_height(): number | null;
|
|
49
|
+
get subaddress_index(): number;
|
|
49
50
|
get current_height(): number | null;
|
|
50
51
|
get current_top_range_height(): number | null;
|
|
51
52
|
changeStartHeight(start_height: number | null): Promise<void>;
|
|
@@ -60,6 +61,7 @@ export declare class ScanCacheOpened {
|
|
|
60
61
|
retry(): Promise<boolean>;
|
|
61
62
|
sendTransaction(signedTx: string): Promise<SendRawTransactionResult>;
|
|
62
63
|
signTransaction(unsignedTx: string): Promise<string>;
|
|
64
|
+
getFeeEstimate(): Promise<FeeEstimateResponse>;
|
|
63
65
|
calculateFeeAndSelectInputs(params: CreateTransactionParams): Promise<{
|
|
64
66
|
selectedInputs: Output[];
|
|
65
67
|
feeEstimate: {
|
|
@@ -70,10 +72,16 @@ export declare class ScanCacheOpened {
|
|
|
70
72
|
};
|
|
71
73
|
}>;
|
|
72
74
|
makeTransactionFromSelectedInputs(payments: Payment[], selectedInputs: Output[], feeEstimate: FeeEstimateResponse): Promise<string>;
|
|
75
|
+
makeSweepTransactionFromSelectedInputs(destination_address: string, selectedInputs: Output[], feeEstimate: FeeEstimateResponse): Promise<string>;
|
|
73
76
|
/**
|
|
74
77
|
* this function returns the unsigned transaction, throws {@link SendError}
|
|
75
78
|
*/
|
|
76
79
|
makeTransaction(params: CreateTransactionParams): Promise<string>;
|
|
80
|
+
/**
|
|
81
|
+
* sweep inputs to external wallet address (the wallet will receive input amount - fee)
|
|
82
|
+
* @param inputs use spendableInputs() to find inputs to put in
|
|
83
|
+
*/
|
|
84
|
+
sweepToExternalWallet(destination_address: string, inputs: Output[]): Promise<string>;
|
|
77
85
|
get daemon_height(): number;
|
|
78
86
|
get amount(): bigint;
|
|
79
87
|
get pending_amount(): bigint;
|
|
@@ -134,6 +142,9 @@ export declare class ScanCacheOpened {
|
|
|
134
142
|
* for all primary addresses
|
|
135
143
|
*/
|
|
136
144
|
feed(params: CacheChangedCallbackParameters): Promise<void>;
|
|
145
|
+
private _highest_subaddress_index;
|
|
146
|
+
private _no_stats;
|
|
147
|
+
get no_stats(): boolean;
|
|
137
148
|
private _cache;
|
|
138
149
|
private worker?;
|
|
139
150
|
private last_eta_height;
|