@spirobel/monero-wallet-api 0.1.2 → 0.3.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 +13 -1
- package/dist/api.d.ts +25 -53
- package/dist/api.js +23 -101
- package/dist/io/BunFileInterface.d.ts +32 -0
- package/dist/io/BunFileInterface.js +1 -0
- package/dist/io/atomicWrite.d.ts +2 -0
- package/dist/io/atomicWrite.js +10 -0
- package/dist/io/extension.d.ts +18 -0
- package/dist/io/extension.js +11 -0
- package/dist/io/indexedDB.d.ts +45 -0
- package/dist/io/indexedDB.js +221 -0
- package/dist/io/readDir.d.ts +1 -0
- package/dist/io/readDir.js +7 -0
- package/dist/io/sleep.d.ts +1 -0
- package/dist/io/sleep.js +1 -0
- package/dist/keypairs-seeds/keypairs.d.ts +29 -0
- package/dist/keypairs-seeds/keypairs.js +207 -0
- package/dist/keypairs-seeds/writeKeypairs.d.ts +11 -0
- package/dist/keypairs-seeds/writeKeypairs.js +75 -0
- package/dist/node-interaction/binaryEndpoints.d.ts +67 -10
- package/dist/node-interaction/binaryEndpoints.js +127 -53
- package/dist/node-interaction/jsonEndpoints.d.ts +249 -187
- package/dist/node-interaction/jsonEndpoints.js +287 -0
- package/dist/node-interaction/nodeUrl.d.ts +129 -0
- package/dist/node-interaction/nodeUrl.js +113 -0
- package/dist/scanning-syncing/backgroundWorker.d.ts +6 -0
- package/dist/scanning-syncing/backgroundWorker.js +56 -0
- package/dist/scanning-syncing/connectionStatus.d.ts +15 -0
- package/dist/scanning-syncing/connectionStatus.js +35 -0
- package/dist/scanning-syncing/openWallet.d.ts +28 -0
- package/dist/scanning-syncing/openWallet.js +57 -0
- package/dist/scanning-syncing/scanSettings.d.ts +96 -0
- package/dist/scanning-syncing/scanSettings.js +243 -0
- package/dist/scanning-syncing/scanresult/computeKeyImage.d.ts +3 -0
- package/dist/scanning-syncing/scanresult/computeKeyImage.js +21 -0
- package/dist/scanning-syncing/scanresult/getBlocksbinBuffer.d.ts +28 -0
- package/dist/scanning-syncing/scanresult/getBlocksbinBuffer.js +52 -0
- package/dist/scanning-syncing/scanresult/reorg.d.ts +14 -0
- package/dist/scanning-syncing/scanresult/reorg.js +78 -0
- package/dist/scanning-syncing/scanresult/scanCache.d.ts +84 -0
- package/dist/scanning-syncing/scanresult/scanCache.js +134 -0
- package/dist/scanning-syncing/scanresult/scanCacheOpened.d.ts +149 -0
- package/dist/scanning-syncing/scanresult/scanCacheOpened.js +648 -0
- package/dist/scanning-syncing/scanresult/scanResult.d.ts +64 -0
- package/dist/scanning-syncing/scanresult/scanResult.js +213 -0
- package/dist/scanning-syncing/scanresult/scanStats.d.ts +60 -0
- package/dist/scanning-syncing/scanresult/scanStats.js +273 -0
- package/dist/scanning-syncing/worker-entrypoints/worker.d.ts +1 -0
- package/dist/scanning-syncing/worker-entrypoints/worker.js +8 -0
- package/dist/scanning-syncing/worker-mains/worker.d.ts +1 -0
- package/dist/scanning-syncing/worker-mains/worker.js +7 -0
- package/dist/send-functionality/conversion.d.ts +4 -0
- package/dist/send-functionality/conversion.js +75 -0
- package/dist/send-functionality/inputSelection.d.ts +13 -0
- package/dist/send-functionality/inputSelection.js +8 -0
- package/dist/send-functionality/transactionBuilding.d.ts +51 -0
- package/dist/send-functionality/transactionBuilding.js +111 -0
- package/dist/tools/monero-tools.d.ts +46 -0
- package/dist/tools/monero-tools.js +165 -0
- package/dist/viewpair/ViewPair.d.ts +157 -0
- package/dist/viewpair/ViewPair.js +346 -0
- package/dist/wasm-processing/wasi.js +1 -2
- package/dist/wasm-processing/wasmFile.d.ts +1 -1
- package/dist/wasm-processing/wasmFile.js +2 -2
- package/dist/wasm-processing/wasmProcessor.d.ts +16 -4
- package/dist/wasm-processing/wasmProcessor.js +23 -7
- package/package.json +29 -6
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { sleep } from "../../io/sleep";
|
|
2
|
+
import { scanWallets } from "../backgroundWorker";
|
|
3
|
+
while (true) {
|
|
4
|
+
await scanWallets((x) => self.postMessage({ type: "RESULT", payload: x }), undefined, scan_settings_path, pathPrefix);
|
|
5
|
+
console.log("no wallets found to scan in wallet settings, trying again in 1 second");
|
|
6
|
+
await sleep(1000);
|
|
7
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function truncateDecimalString(str: string, decimals?: number): string;
|
|
2
|
+
export declare function convertBigIntAmount(amount: bigint): string;
|
|
3
|
+
export declare function convertAmountBigInt(amount_double: string): bigint;
|
|
4
|
+
export declare function convertAmountBigIntThrows(amount_double: string): bigint;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export function truncateDecimalString(str, decimals = 3) {
|
|
2
|
+
if (!str.includes("."))
|
|
3
|
+
return str;
|
|
4
|
+
const [integer, fraction = ""] = str.split(".");
|
|
5
|
+
const truncatedFraction = fraction.slice(0, decimals);
|
|
6
|
+
return truncatedFraction ? `${integer}.${truncatedFraction}` : integer;
|
|
7
|
+
}
|
|
8
|
+
export function convertBigIntAmount(amount) {
|
|
9
|
+
if (amount < 0)
|
|
10
|
+
amount *= -1n;
|
|
11
|
+
let display_amount = "";
|
|
12
|
+
// to go from atomic units to display amount,
|
|
13
|
+
// we move from the end to the beginning and insert a dot 12 digits in
|
|
14
|
+
// https://www.getmonero.org/resources/moneropedia/atomic-units.html
|
|
15
|
+
let afterDot = amount.toString().padStart(12, "0").slice(-12);
|
|
16
|
+
let beforeDot = amount.toString().padStart(12, "0").slice(0, -12);
|
|
17
|
+
if (!beforeDot || beforeDot.startsWith("0"))
|
|
18
|
+
beforeDot = "0";
|
|
19
|
+
display_amount = beforeDot + ".";
|
|
20
|
+
display_amount += afterDot;
|
|
21
|
+
// remove trailing zeros
|
|
22
|
+
while (display_amount[display_amount.length - 1] === "0") {
|
|
23
|
+
display_amount = display_amount.slice(0, -1);
|
|
24
|
+
}
|
|
25
|
+
const last_char = display_amount.at(-1);
|
|
26
|
+
if (last_char === ".")
|
|
27
|
+
display_amount = display_amount.slice(0, -1);
|
|
28
|
+
// trailing . or , should be removed
|
|
29
|
+
return display_amount;
|
|
30
|
+
}
|
|
31
|
+
export function convertAmountBigInt(amount_double) {
|
|
32
|
+
// accept both dot and comma
|
|
33
|
+
amount_double = amount_double.replaceAll(",", ".");
|
|
34
|
+
const last_char = amount_double.at(-1);
|
|
35
|
+
if (last_char === ".")
|
|
36
|
+
amount_double = amount_double.slice(0, -1);
|
|
37
|
+
// trailing . or , should be removed
|
|
38
|
+
const beforeDot = amount_double.split(".")[0];
|
|
39
|
+
let afterDot = amount_double.split(".")[1];
|
|
40
|
+
if (!afterDot)
|
|
41
|
+
afterDot = "000000000000";
|
|
42
|
+
afterDot = afterDot?.padEnd(12, "0").slice(0, 12);
|
|
43
|
+
let bigIntString = afterDot;
|
|
44
|
+
if (beforeDot?.length && !beforeDot.startsWith("0"))
|
|
45
|
+
bigIntString = beforeDot + afterDot;
|
|
46
|
+
let amount = BigInt("0");
|
|
47
|
+
try {
|
|
48
|
+
amount = BigInt(bigIntString);
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
// in case the input is not a valid number,
|
|
52
|
+
// the amount stays zero. Keeps the UI easy for copy and paste
|
|
53
|
+
}
|
|
54
|
+
return amount;
|
|
55
|
+
}
|
|
56
|
+
export function convertAmountBigIntThrows(amount_double) {
|
|
57
|
+
// accept both dot and comma
|
|
58
|
+
amount_double = amount_double.replaceAll(",", ".");
|
|
59
|
+
const last_char = amount_double.at(-1);
|
|
60
|
+
if (last_char === ".")
|
|
61
|
+
amount_double = amount_double.slice(0, -1);
|
|
62
|
+
// trailing . or , should be removed
|
|
63
|
+
const beforeDot = amount_double.split(".")[0];
|
|
64
|
+
let afterDot = amount_double.split(".")[1];
|
|
65
|
+
if (!afterDot)
|
|
66
|
+
afterDot = "000000000000";
|
|
67
|
+
afterDot = afterDot?.padEnd(12, "0").slice(0, 12);
|
|
68
|
+
let bigIntString = afterDot;
|
|
69
|
+
if (beforeDot?.length && !beforeDot.startsWith("0"))
|
|
70
|
+
bigIntString = beforeDot + afterDot;
|
|
71
|
+
let amount = BigInt("0");
|
|
72
|
+
amount = BigInt(bigIntString);
|
|
73
|
+
// in case the input is not a valid number, throws,
|
|
74
|
+
return amount;
|
|
75
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { GetOutsResponseBuffer, NodeUrl, Output } from "../api";
|
|
2
|
+
import type { SampledDecoys } from "./transactionBuilding";
|
|
3
|
+
export type Payment = {
|
|
4
|
+
address: string;
|
|
5
|
+
amount: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function sumPayments(payments: Payment[]): bigint;
|
|
8
|
+
export type PreparedInput = {
|
|
9
|
+
input: Output;
|
|
10
|
+
sample: SampledDecoys;
|
|
11
|
+
outsResponse: Promise<GetOutsResponseBuffer>;
|
|
12
|
+
};
|
|
13
|
+
export declare function prepareInput(node: NodeUrl, distibution: number[], input: Output, how_many_to_sample?: number): PreparedInput;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export function sumPayments(payments) {
|
|
2
|
+
return payments.reduce((sum, payment) => sum + BigInt(payment.amount), 0n);
|
|
3
|
+
}
|
|
4
|
+
export function prepareInput(node, distibution, input, how_many_to_sample = 20) {
|
|
5
|
+
const sample = node.sampleDecoys(input.index_on_blockchain, distibution, how_many_to_sample);
|
|
6
|
+
const outsResponse = node.getOutsBin(sample.candidates);
|
|
7
|
+
return { input, sample, outsResponse };
|
|
8
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { GetFeeEstimateResult, Output } from "../api";
|
|
2
|
+
import { WasmProcessor } from "../wasm-processing/wasmProcessor";
|
|
3
|
+
export type Input = string;
|
|
4
|
+
export type UnsignedTransaction = string;
|
|
5
|
+
export type SignedTransaction = string;
|
|
6
|
+
export declare function makeInput<T extends WasmProcessor>(processor: T, outputToBeSpent: Output, candidates: number[], get_outs_Response: Uint8Array): Input;
|
|
7
|
+
export type SampledDecoys = {
|
|
8
|
+
candidates: number[];
|
|
9
|
+
};
|
|
10
|
+
export declare function sampleDecoys<T extends WasmProcessor>(processor: T, outputToBeSpentIndex: number, distribution: number[], candidatesLength: number): SampledDecoys;
|
|
11
|
+
export type MakeTransactionParams = {
|
|
12
|
+
inputs: Input[];
|
|
13
|
+
payments: {
|
|
14
|
+
address: string;
|
|
15
|
+
amount: string;
|
|
16
|
+
}[];
|
|
17
|
+
fee_response: GetFeeEstimateResult;
|
|
18
|
+
fee_priority: string;
|
|
19
|
+
outgoing_view_key?: string;
|
|
20
|
+
data?: number[][];
|
|
21
|
+
};
|
|
22
|
+
export type NotEnoughFundsError = {
|
|
23
|
+
inputs: number;
|
|
24
|
+
necessary_fee: number;
|
|
25
|
+
outputs: number;
|
|
26
|
+
};
|
|
27
|
+
export type ErrorDetail = {
|
|
28
|
+
NotEnoughFunds: NotEnoughFundsError;
|
|
29
|
+
};
|
|
30
|
+
export type SendError = {
|
|
31
|
+
error: ErrorDetail;
|
|
32
|
+
message: string;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* this function returns the unsigned transaction, throws {@link SendError}
|
|
36
|
+
* @param processor
|
|
37
|
+
* @param params
|
|
38
|
+
* @returns
|
|
39
|
+
*/
|
|
40
|
+
export declare function makeTransaction<T extends WasmProcessor>(processor: T, params: MakeTransactionParams): UnsignedTransaction;
|
|
41
|
+
export declare function signTransaction(tx: UnsignedTransaction, sender_spend_key: string): Promise<SignedTransaction>;
|
|
42
|
+
export type ParsedAddress = {
|
|
43
|
+
address: string;
|
|
44
|
+
kind: "primary" | "subaddress" | "integrated" | "featured";
|
|
45
|
+
network: "mainnet" | "stagenet" | "testnet";
|
|
46
|
+
payment_id?: string;
|
|
47
|
+
};
|
|
48
|
+
export type ParseAddressError = {
|
|
49
|
+
error: string;
|
|
50
|
+
};
|
|
51
|
+
export declare function parseAddress(address: string): Promise<ParsedAddress | ParseAddressError>;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { WasmProcessor } from "../wasm-processing/wasmProcessor";
|
|
2
|
+
export function makeInput(processor, outputToBeSpent, candidates, get_outs_Response) {
|
|
3
|
+
const makeInputArgs = JSON.stringify({
|
|
4
|
+
serialized_input: outputToBeSpent.serialized,
|
|
5
|
+
candidates,
|
|
6
|
+
});
|
|
7
|
+
processor.writeToWasmMemory = (ptr, len) => {
|
|
8
|
+
processor.writeString(ptr, len, makeInputArgs);
|
|
9
|
+
processor.writeToWasmMemory = (ptr, len) => {
|
|
10
|
+
processor.writeArray(ptr, len, get_outs_Response);
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
let result = null;
|
|
14
|
+
processor.readFromWasmMemory = (ptr, len) => {
|
|
15
|
+
result = JSON.parse(processor.readString(ptr, len));
|
|
16
|
+
};
|
|
17
|
+
//@ts-ignore
|
|
18
|
+
processor.tinywasi.instance.exports.make_input(makeInputArgs.length, get_outs_Response.length);
|
|
19
|
+
if (!result) {
|
|
20
|
+
throw new Error("Failed to make Input (combine output with sampled and verified unlocked decoys)");
|
|
21
|
+
}
|
|
22
|
+
return result["input"];
|
|
23
|
+
}
|
|
24
|
+
export function sampleDecoys(processor, outputToBeSpentIndex, distribution, candidatesLength) {
|
|
25
|
+
const sampleDecoyArgs = JSON.stringify({
|
|
26
|
+
output_being_spent_index: outputToBeSpentIndex,
|
|
27
|
+
distribution,
|
|
28
|
+
candidates_len: candidatesLength,
|
|
29
|
+
});
|
|
30
|
+
processor.writeToWasmMemory = (ptr, len) => {
|
|
31
|
+
processor.writeString(ptr, len, sampleDecoyArgs);
|
|
32
|
+
};
|
|
33
|
+
let result;
|
|
34
|
+
processor.readFromWasmMemory = (ptr, len) => {
|
|
35
|
+
result = JSON.parse(processor.readString(ptr, len));
|
|
36
|
+
};
|
|
37
|
+
//@ts-ignore
|
|
38
|
+
processor.tinywasi.instance.exports.sample_decoys(sampleDecoyArgs.length);
|
|
39
|
+
if (!result) {
|
|
40
|
+
throw new Error("Failed to sample decoys");
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* this function returns the unsigned transaction, throws {@link SendError}
|
|
46
|
+
* @param processor
|
|
47
|
+
* @param params
|
|
48
|
+
* @returns
|
|
49
|
+
*/
|
|
50
|
+
export function makeTransaction(processor, params) {
|
|
51
|
+
const jsonParams = JSON.stringify(params);
|
|
52
|
+
processor.writeToWasmMemory = (ptr, len) => {
|
|
53
|
+
processor.writeString(ptr, len, jsonParams);
|
|
54
|
+
};
|
|
55
|
+
let result = null;
|
|
56
|
+
let error = null;
|
|
57
|
+
processor.readFromWasmMemory = (ptr, len) => {
|
|
58
|
+
result = JSON.parse(processor.readString(ptr, len));
|
|
59
|
+
};
|
|
60
|
+
processor.readErrorFromWasmMemory = (ptr, len) => {
|
|
61
|
+
error = JSON.parse(processor.readString(ptr, len));
|
|
62
|
+
};
|
|
63
|
+
//@ts-ignore
|
|
64
|
+
processor.tinywasi.instance.exports.make_transaction(jsonParams.length);
|
|
65
|
+
if (!result) {
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
return result["signable_transaction"];
|
|
69
|
+
}
|
|
70
|
+
export async function signTransaction(tx, sender_spend_key) {
|
|
71
|
+
const wasmProcessor = await WasmProcessor.init();
|
|
72
|
+
wasmProcessor.writeToWasmMemory = (ptr, len) => {
|
|
73
|
+
wasmProcessor.writeString(ptr, len, tx);
|
|
74
|
+
wasmProcessor.writeToWasmMemory = (ptr, len) => {
|
|
75
|
+
wasmProcessor.writeString(ptr, len, sender_spend_key);
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
let result = null;
|
|
79
|
+
wasmProcessor.readFromWasmMemory = (ptr, len) => {
|
|
80
|
+
result = JSON.parse(wasmProcessor.readString(ptr, len));
|
|
81
|
+
};
|
|
82
|
+
//@ts-ignore
|
|
83
|
+
wasmProcessor.tinywasi.instance.exports.sign_transaction(tx.length, sender_spend_key.length);
|
|
84
|
+
if (!result) {
|
|
85
|
+
throw new Error("Failed to sign transaction");
|
|
86
|
+
}
|
|
87
|
+
return result["signed_transaction"];
|
|
88
|
+
}
|
|
89
|
+
export async function parseAddress(address) {
|
|
90
|
+
const wasmProcessor = await WasmProcessor.init();
|
|
91
|
+
wasmProcessor.writeToWasmMemory = (ptr, len) => {
|
|
92
|
+
wasmProcessor.writeString(ptr, len, address);
|
|
93
|
+
};
|
|
94
|
+
let result = null;
|
|
95
|
+
wasmProcessor.readFromWasmMemory = (ptr, len) => {
|
|
96
|
+
result = JSON.parse(wasmProcessor.readString(ptr, len));
|
|
97
|
+
};
|
|
98
|
+
let error = null;
|
|
99
|
+
wasmProcessor.readErrorFromWasmMemory = (ptr, len) => {
|
|
100
|
+
error = JSON.parse(wasmProcessor.readString(ptr, len));
|
|
101
|
+
};
|
|
102
|
+
//@ts-ignore
|
|
103
|
+
wasmProcessor.tinywasi.instance.exports.parse_address(address.length);
|
|
104
|
+
if (!result) {
|
|
105
|
+
if (!error) {
|
|
106
|
+
throw new Error("Failed to parse address");
|
|
107
|
+
}
|
|
108
|
+
return error;
|
|
109
|
+
}
|
|
110
|
+
return result;
|
|
111
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export declare const TOOL_MAGIC_STRING = "monerochan";
|
|
2
|
+
export declare function parseToolLink(link: string): MoneroTool | null;
|
|
3
|
+
export type ToolInvocationValidity = "valid" | "invalid" | "unverified";
|
|
4
|
+
export type ParsedMoneroToolInvocation = {
|
|
5
|
+
tool: MoneroTool;
|
|
6
|
+
destination_domain: string;
|
|
7
|
+
context_domain: string;
|
|
8
|
+
found_in: "link" | "linkText";
|
|
9
|
+
link: string;
|
|
10
|
+
linkText: string;
|
|
11
|
+
timestamp: number;
|
|
12
|
+
invocation_id: string;
|
|
13
|
+
context_href: string;
|
|
14
|
+
valid: ToolInvocationValidity;
|
|
15
|
+
};
|
|
16
|
+
export declare function parseToolInvocation(link: string, linkText: string, context_location: Location): ParsedMoneroToolInvocation | null;
|
|
17
|
+
export type SendTransactionTool = {
|
|
18
|
+
tool_id: "001";
|
|
19
|
+
payload: SendTransactionToolPayload;
|
|
20
|
+
};
|
|
21
|
+
export type SendTransactionToolPayload = {
|
|
22
|
+
address: string;
|
|
23
|
+
amount: string;
|
|
24
|
+
};
|
|
25
|
+
export declare function parseSendTransactionToolArgs(args: string[]): SendTransactionTool | null;
|
|
26
|
+
export declare function createSendTransactionToolLink(address: string, amount: string): string;
|
|
27
|
+
export declare function make001ToolLink(address: string, amount: string): string;
|
|
28
|
+
export type CreateAndShareViewOnlyWalletTool = {
|
|
29
|
+
tool_id: "002";
|
|
30
|
+
payload: CreateAndShareViewOnlyWalletToolPayload;
|
|
31
|
+
};
|
|
32
|
+
export type CreateAndShareViewOnlyWalletToolPayload = {
|
|
33
|
+
wallet_slot: number;
|
|
34
|
+
};
|
|
35
|
+
export declare function parseCreateAndShareViewOnlyWalletToolArgs(args: string[]): CreateAndShareViewOnlyWalletTool | null;
|
|
36
|
+
export declare function createCreateAndShareViewOnlyWalletToolLink(wallet_slot?: number): string;
|
|
37
|
+
export declare function make002ToolLink(wallet_slot?: number): string;
|
|
38
|
+
export type MoneroTool = SendTransactionTool | CreateAndShareViewOnlyWalletTool;
|
|
39
|
+
export declare function createToolLink(tool: MoneroTool): string;
|
|
40
|
+
export declare function getDomainWithTLD(hostname: string): string;
|
|
41
|
+
export declare function parseDestination(destination: string): string;
|
|
42
|
+
export declare const OPEN_DOMAINS: string[];
|
|
43
|
+
export declare function checkToolInvocationValidity(invo: ParsedMoneroToolInvocation): Promise<ToolInvocationValidity>;
|
|
44
|
+
export declare const ADDRESS_VALID_RESPONSE: {
|
|
45
|
+
valid_address: boolean;
|
|
46
|
+
};
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { convertAmountBigIntThrows } from "../send-functionality/conversion";
|
|
2
|
+
export const TOOL_MAGIC_STRING = "monerochan";
|
|
3
|
+
export function parseToolLink(link) {
|
|
4
|
+
const magic_str_index = link.lastIndexOf(TOOL_MAGIC_STRING);
|
|
5
|
+
if (magic_str_index !== -1) {
|
|
6
|
+
const link_start_index = magic_str_index + TOOL_MAGIC_STRING.length;
|
|
7
|
+
const tool_id = link.substring(link_start_index, link_start_index + 3);
|
|
8
|
+
const args = link
|
|
9
|
+
.substring(link_start_index + 3)
|
|
10
|
+
.split("_")
|
|
11
|
+
.slice(1);
|
|
12
|
+
if (tool_id === "001")
|
|
13
|
+
return parseSendTransactionToolArgs(args);
|
|
14
|
+
if (tool_id === "002")
|
|
15
|
+
return parseCreateAndShareViewOnlyWalletToolArgs(args);
|
|
16
|
+
}
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
export function parseToolInvocation(link, linkText, context_location) {
|
|
20
|
+
const context_domain = getDomainWithTLD(context_location.hostname);
|
|
21
|
+
const context_href = context_location.href;
|
|
22
|
+
const link_parse = parseToolLink(link);
|
|
23
|
+
if (link_parse) {
|
|
24
|
+
const destination_domain = parseDestination(link);
|
|
25
|
+
return {
|
|
26
|
+
tool: link_parse,
|
|
27
|
+
destination_domain,
|
|
28
|
+
context_domain,
|
|
29
|
+
found_in: "link",
|
|
30
|
+
link,
|
|
31
|
+
linkText,
|
|
32
|
+
timestamp: Date.now(),
|
|
33
|
+
invocation_id: crypto.randomUUID(),
|
|
34
|
+
context_href,
|
|
35
|
+
valid: "unverified",
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
const linkText_parse = parseToolLink(linkText);
|
|
40
|
+
if (linkText_parse) {
|
|
41
|
+
const destination_domain = parseDestination(linkText);
|
|
42
|
+
return {
|
|
43
|
+
tool: linkText_parse,
|
|
44
|
+
destination_domain,
|
|
45
|
+
context_domain,
|
|
46
|
+
found_in: "linkText",
|
|
47
|
+
link,
|
|
48
|
+
linkText,
|
|
49
|
+
timestamp: Date.now(),
|
|
50
|
+
invocation_id: crypto.randomUUID(),
|
|
51
|
+
context_href,
|
|
52
|
+
valid: "unverified",
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
export function parseSendTransactionToolArgs(args) {
|
|
59
|
+
const amount = args[1];
|
|
60
|
+
const address = args[3];
|
|
61
|
+
try {
|
|
62
|
+
convertAmountBigIntThrows(amount);
|
|
63
|
+
}
|
|
64
|
+
catch (e) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
if (address && amount) {
|
|
68
|
+
return {
|
|
69
|
+
tool_id: "001",
|
|
70
|
+
payload: {
|
|
71
|
+
address,
|
|
72
|
+
amount,
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
export function createSendTransactionToolLink(address, amount) {
|
|
79
|
+
convertAmountBigIntThrows(amount);
|
|
80
|
+
return `${TOOL_MAGIC_STRING}001_amount_${amount}_address_${address}`;
|
|
81
|
+
}
|
|
82
|
+
export function make001ToolLink(address, amount) {
|
|
83
|
+
return createSendTransactionToolLink(address, amount);
|
|
84
|
+
}
|
|
85
|
+
export function parseCreateAndShareViewOnlyWalletToolArgs(args) {
|
|
86
|
+
const wallet_slot = args[5];
|
|
87
|
+
if (wallet_slot && !isNaN(parseInt(wallet_slot))) {
|
|
88
|
+
return {
|
|
89
|
+
tool_id: "002",
|
|
90
|
+
payload: {
|
|
91
|
+
wallet_slot: parseInt(wallet_slot),
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
export function createCreateAndShareViewOnlyWalletToolLink(wallet_slot) {
|
|
98
|
+
wallet_slot = Number(wallet_slot) || 0;
|
|
99
|
+
return `${TOOL_MAGIC_STRING}002_create_and_share_viewkey_slot_${wallet_slot}`;
|
|
100
|
+
}
|
|
101
|
+
export function make002ToolLink(wallet_slot) {
|
|
102
|
+
return createCreateAndShareViewOnlyWalletToolLink(wallet_slot);
|
|
103
|
+
}
|
|
104
|
+
export function createToolLink(tool) {
|
|
105
|
+
if (tool.tool_id === "001") {
|
|
106
|
+
return createSendTransactionToolLink(tool.payload.address, tool.payload.amount);
|
|
107
|
+
}
|
|
108
|
+
if (tool.tool_id === "002") {
|
|
109
|
+
return createCreateAndShareViewOnlyWalletToolLink(tool.payload.wallet_slot);
|
|
110
|
+
}
|
|
111
|
+
throw new Error("unknown tool");
|
|
112
|
+
}
|
|
113
|
+
export function getDomainWithTLD(hostname) {
|
|
114
|
+
const parts = hostname.split(".");
|
|
115
|
+
// For localhost or single-part hostnames, return as-is
|
|
116
|
+
if (parts.length <= 1)
|
|
117
|
+
return hostname;
|
|
118
|
+
// Take the last 2 parts (domain + tld).
|
|
119
|
+
return parts.slice(-2).join(".");
|
|
120
|
+
}
|
|
121
|
+
export function parseDestination(destination) {
|
|
122
|
+
const url = new URL(destination);
|
|
123
|
+
return getDomainWithTLD(url.hostname);
|
|
124
|
+
}
|
|
125
|
+
export const OPEN_DOMAINS = ["monerochan.city"];
|
|
126
|
+
// this validity check should happen in the contentscript when the link is clicked,
|
|
127
|
+
// not in the background script
|
|
128
|
+
// -> tor circuit is separated & compartmentalized
|
|
129
|
+
export async function checkToolInvocationValidity(invo) {
|
|
130
|
+
// send 001 fetch from destination domain to check if the address is valid
|
|
131
|
+
if (invo.tool.tool_id == "001") {
|
|
132
|
+
const checkUrl = `${invo.destination_domain}/monerochan001/${invo.tool.payload.address}`;
|
|
133
|
+
try {
|
|
134
|
+
if (invo.destination_domain === OPEN_DOMAINS[0]) {
|
|
135
|
+
return "unverified";
|
|
136
|
+
}
|
|
137
|
+
const result = (await (await fetch(checkUrl)).json());
|
|
138
|
+
if (result &&
|
|
139
|
+
typeof result === "object" &&
|
|
140
|
+
"valid_address" in result &&
|
|
141
|
+
result.valid_address === true) {
|
|
142
|
+
return "valid";
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
return "invalid";
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return "invalid";
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
// create view only wallet 002 make sure context + destination domain is the same
|
|
153
|
+
if (invo.tool.tool_id == "002") {
|
|
154
|
+
if (invo.context_domain == invo.destination_domain) {
|
|
155
|
+
return "valid";
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
return "invalid";
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return "unverified";
|
|
162
|
+
}
|
|
163
|
+
export const ADDRESS_VALID_RESPONSE = {
|
|
164
|
+
valid_address: true,
|
|
165
|
+
};
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { type ScanResult } from "../scanning-syncing/scanresult/scanResult";
|
|
2
|
+
export { type ScanResult };
|
|
3
|
+
export { NodeUrl } from "../node-interaction/nodeUrl";
|
|
4
|
+
import { type GetBlocksBinMetaCallback, type GetBlocksBinRequest } from "../node-interaction/binaryEndpoints";
|
|
5
|
+
import { type ScanCache } from "../scanning-syncing/scanresult/scanCache";
|
|
6
|
+
import { type MakeTransactionParams, type UnsignedTransaction } from "../send-functionality/transactionBuilding";
|
|
7
|
+
import { WasmProcessor } from "../wasm-processing/wasmProcessor";
|
|
8
|
+
import { type GetBlockHeadersRangeParams } from "../api";
|
|
9
|
+
import { type CacheChangedCallback } from "../scanning-syncing/scanresult/scanCache";
|
|
10
|
+
export type NETWORKS = "mainnet" | "stagenet" | "testnet";
|
|
11
|
+
/**
|
|
12
|
+
* This class is useful to interact with Moneros DaemonRpc binary requests in a convenient way.
|
|
13
|
+
* (similar to how you would interact with a REST api that gives you json back.)
|
|
14
|
+
* The wasm part will handle the creation of the binary requests and parse the responses and then parse them
|
|
15
|
+
* and return outputs that belong to the ViewPair.
|
|
16
|
+
* {@link https://docs.getmonero.org/rpc-library/monerod-rpc/#get_blocksbin}
|
|
17
|
+
*/
|
|
18
|
+
export declare class ViewPair extends WasmProcessor {
|
|
19
|
+
node_url: string;
|
|
20
|
+
primary_address: string;
|
|
21
|
+
private _network;
|
|
22
|
+
get network(): NETWORKS;
|
|
23
|
+
private _genesis_hash;
|
|
24
|
+
get genesis_hash(): string;
|
|
25
|
+
protected constructor(node_url: string, primary_address: string);
|
|
26
|
+
static create(primary_address: string, secret_view_key: string, subaddress_index?: number, node_url?: string): Promise<ViewPair>;
|
|
27
|
+
/**
|
|
28
|
+
* This function helps with making requests to the get_blocks.bin endpoint of the Monerod nodes. It does the Request and returns the outputs that belong to the ViewPair.
|
|
29
|
+
* (if outputs are found in the blocks that are returned)
|
|
30
|
+
*
|
|
31
|
+
* if params.block_ids is supplied, it will add the genesis hash to the end of the block_ids array.
|
|
32
|
+
* (so you can just supply the block_id you want to start fetching from)
|
|
33
|
+
* @link https://docs.getmonero.org/rpc-library/monerod-rpc/#get_blocksbin
|
|
34
|
+
* @param params params that will be turned into epee (monero lib that does binary serialization)
|
|
35
|
+
* @param metaCallBack contains meta information about the getBlocksbin call (new sync height = start_height param + number of blocks)
|
|
36
|
+
* @param stopSync optional AbortSignal to stop the syncing process
|
|
37
|
+
* @returns The difference to the same method on NodeUrl is: It returns {@link ScanResult} (outputs that belong to viewpair) and not just the blocks as json.
|
|
38
|
+
*/
|
|
39
|
+
getBlocksBin(params: GetBlocksBinRequest, metaCallBack?: GetBlocksBinMetaCallback, stopSync?: AbortSignal): Promise<ScanResult | import("../api").ErrorResponse | undefined>;
|
|
40
|
+
addGenesisHashToBlockIds(params: GetBlocksBinRequest): Promise<GetBlocksBinRequest>;
|
|
41
|
+
/**
|
|
42
|
+
* This function helps with making requests to the get_blocks.bin endpoint of the Monerod nodes.
|
|
43
|
+
* if params.block_ids is supplied, it will add the genesis hash to the end of the block_ids array.
|
|
44
|
+
* (so you can just supply the block_id you want to start fetching from)
|
|
45
|
+
*
|
|
46
|
+
* The difference compared to the getBlocksBin method is that it returns a Uint8Array that still has to be scanned for outputs.
|
|
47
|
+
* This is useful if you want to scan multiple viewpairs at once. You can take the Uint8Array and pass it to another ViewPair to scan for outputs.
|
|
48
|
+
* @param params params that will be turned into epee (monero lib that does binary serialization)
|
|
49
|
+
* @param stopSync optional AbortSignal to stop the syncing process
|
|
50
|
+
* @returns This method will return a Uint8Array that can subsequently be scanned for outputs with the getBlocksBinScanResponse method.
|
|
51
|
+
*/
|
|
52
|
+
getBlocksBinExecuteRequest(params: GetBlocksBinRequest, stopSync?: AbortSignal): Promise<Uint8Array<ArrayBufferLike>>;
|
|
53
|
+
/**
|
|
54
|
+
* This function helps with scanning the response of the getBlocksBinExecuteRequest method.
|
|
55
|
+
* It will parse the Uint8Array and return the outputs that belong to the ViewPair.
|
|
56
|
+
* (if outputs are found in the blocks that are contained in the Uint8Array that was returned by the getBlocksBinExecuteRequest method)
|
|
57
|
+
* @link https://docs.getmonero.org/rpc-library/monerod-rpc/#get_blocksbin
|
|
58
|
+
* @param getBlocksBinResponseBuffer the Uint8Array that was returned by the getBlocksBinExecuteRequest method.(which contains the blocks in binary format, returned from the Monerod node)
|
|
59
|
+
* @param metaCallBack contains meta information about the getBlocksbin call (new sync height = start_height param + number of blocks)
|
|
60
|
+
* @returns It returns {@link ScanResult} (outputs that belong to viewpair)
|
|
61
|
+
*/
|
|
62
|
+
getBlocksBinScanResponse(getBlocksBinResponseBuffer: Uint8Array, metaCallBack?: GetBlocksBinMetaCallback): Promise<ScanResult | import("../api").ErrorResponse | undefined>;
|
|
63
|
+
/**
|
|
64
|
+
* scan
|
|
65
|
+
*/
|
|
66
|
+
scan(cacheChanged?: CacheChangedCallback, stopSync?: AbortSignal, scan_settings_path?: string, pathPrefix?: string): Promise<void>;
|
|
67
|
+
/**
|
|
68
|
+
* This method makes an integrated Address for the Address of the Viewpair it was opened with.
|
|
69
|
+
* The network (mainnet, stagenet, testnet) is the same as the one of the Viewpairaddress.
|
|
70
|
+
* @param paymentId (u64 under the hood) you can use a random number or a primary key of an sqlite db to associate payments with customer sessions.
|
|
71
|
+
* @returns Adressstring
|
|
72
|
+
*/
|
|
73
|
+
makeIntegratedAddress(paymentId: number): string;
|
|
74
|
+
/**
|
|
75
|
+
* This method makes a Subaddress for the Address of the Viewpair it was opened with.
|
|
76
|
+
* The network (mainnet, stagenet, testnet) is the same as the one of the Viewpairaddress.
|
|
77
|
+
* if there is an active scan going on, call this on ScanCacheOpened, so the new subaddress will be scanned
|
|
78
|
+
*
|
|
79
|
+
* @param minor address index, we always set major (also called account index) to 0
|
|
80
|
+
* @returns Adressstring
|
|
81
|
+
*/
|
|
82
|
+
makeSubaddress(minor: number): string;
|
|
83
|
+
private writeSubaddressesToScanCache;
|
|
84
|
+
addSubaddressesToScanCache(cache: ScanCache, scan_settings_path?: string): Promise<void>;
|
|
85
|
+
/**
|
|
86
|
+
* This method makes a Subaddress for the Address of the Viewpair it was opened with.
|
|
87
|
+
* The network (mainnet, stagenet, testnet) is the same as the one of the Viewpairaddress.
|
|
88
|
+
*
|
|
89
|
+
* @param major account index should be set to 0 in most cases
|
|
90
|
+
* @param minor address index starting at 1
|
|
91
|
+
* @returns Adressstring
|
|
92
|
+
*/
|
|
93
|
+
private makeSubaddressRaw;
|
|
94
|
+
/**
|
|
95
|
+
* Creates a signable transaction using the provided parameters.
|
|
96
|
+
* @param params - The transaction parameters.
|
|
97
|
+
* @returns The serialized transaction as an array of numbers.
|
|
98
|
+
*/
|
|
99
|
+
makeTransaction(params: MakeTransactionParams): UnsignedTransaction;
|
|
100
|
+
/**
|
|
101
|
+
* Retrieve block headers for a specified range of heights.
|
|
102
|
+
* @link https://docs.getmonero.org/rpc-library/monerod-rpc/#get_block_headers_range
|
|
103
|
+
* @param params The parameters including start_height, end_height, and optional fill_pow_hash.
|
|
104
|
+
* @returns The result object with headers, status, etc. Throws if the range is invalid:(end_height > daemonheight)
|
|
105
|
+
*/
|
|
106
|
+
getBlockHeadersRange(params: GetBlockHeadersRangeParams): Promise<import("../api").GetBlockHeadersRange>;
|
|
107
|
+
/**
|
|
108
|
+
* Fetch general information about the Monero daemon.
|
|
109
|
+
* @link https://docs.getmonero.org/rpc-library/monerod-rpc/#get_info
|
|
110
|
+
* @returns The result object with daemon info like height, status, etc.
|
|
111
|
+
*/
|
|
112
|
+
getInfo(): Promise<{
|
|
113
|
+
adjusted_time: number;
|
|
114
|
+
alt_blocks_count: number;
|
|
115
|
+
block_size_limit: number;
|
|
116
|
+
block_size_median: number;
|
|
117
|
+
block_weight_limit: number;
|
|
118
|
+
block_weight_median: number;
|
|
119
|
+
bootstrap_daemon_address: string;
|
|
120
|
+
busy_syncing: boolean;
|
|
121
|
+
credits: number;
|
|
122
|
+
cumulative_difficulty: number;
|
|
123
|
+
cumulative_difficulty_top64: number;
|
|
124
|
+
database_size: number;
|
|
125
|
+
difficulty: number;
|
|
126
|
+
difficulty_top64: number;
|
|
127
|
+
free_space: number;
|
|
128
|
+
grey_peerlist_size: number;
|
|
129
|
+
height: number;
|
|
130
|
+
height_without_bootstrap: number;
|
|
131
|
+
incoming_connections_count: number;
|
|
132
|
+
mainnet: boolean;
|
|
133
|
+
nettype: string;
|
|
134
|
+
offline: boolean;
|
|
135
|
+
outgoing_connections_count: number;
|
|
136
|
+
restricted: boolean;
|
|
137
|
+
rpc_connections_count: number;
|
|
138
|
+
stagenet: boolean;
|
|
139
|
+
start_time: number;
|
|
140
|
+
status: string;
|
|
141
|
+
synchronized: boolean;
|
|
142
|
+
target: number;
|
|
143
|
+
target_height: number;
|
|
144
|
+
testnet: boolean;
|
|
145
|
+
top_block_hash: string;
|
|
146
|
+
top_hash: string;
|
|
147
|
+
tx_count: number;
|
|
148
|
+
tx_pool_size: number;
|
|
149
|
+
untrusted: boolean;
|
|
150
|
+
update_available: boolean;
|
|
151
|
+
version: string;
|
|
152
|
+
was_bootstrap_ever_used: boolean;
|
|
153
|
+
white_peerlist_size: number;
|
|
154
|
+
wide_cumulative_difficulty: string;
|
|
155
|
+
wide_difficulty: string;
|
|
156
|
+
}>;
|
|
157
|
+
}
|