@winbit32/wallet-kit 0.1.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.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +117 -0
  3. package/dist/cosign/bytes.d.ts +10 -0
  4. package/dist/cosign/bytes.d.ts.map +1 -0
  5. package/dist/cosign/bytes.js +37 -0
  6. package/dist/cosign/bytes.js.map +1 -0
  7. package/dist/cosign/config.d.ts +58 -0
  8. package/dist/cosign/config.d.ts.map +1 -0
  9. package/dist/cosign/config.js +54 -0
  10. package/dist/cosign/config.js.map +1 -0
  11. package/dist/cosign/cosignSend.d.ts +104 -0
  12. package/dist/cosign/cosignSend.d.ts.map +1 -0
  13. package/dist/cosign/cosignSend.js +157 -0
  14. package/dist/cosign/cosignSend.js.map +1 -0
  15. package/dist/cosign/index.d.ts +33 -0
  16. package/dist/cosign/index.d.ts.map +1 -0
  17. package/dist/cosign/index.js +49 -0
  18. package/dist/cosign/index.js.map +1 -0
  19. package/dist/cosign/initiator.d.ts +121 -0
  20. package/dist/cosign/initiator.d.ts.map +1 -0
  21. package/dist/cosign/initiator.js +270 -0
  22. package/dist/cosign/initiator.js.map +1 -0
  23. package/dist/cosign/orchardFrost.d.ts +140 -0
  24. package/dist/cosign/orchardFrost.d.ts.map +1 -0
  25. package/dist/cosign/orchardFrost.js +227 -0
  26. package/dist/cosign/orchardFrost.js.map +1 -0
  27. package/dist/cosign/relay.d.ts +100 -0
  28. package/dist/cosign/relay.d.ts.map +1 -0
  29. package/dist/cosign/relay.js +359 -0
  30. package/dist/cosign/relay.js.map +1 -0
  31. package/dist/cosign/seed.d.ts +32 -0
  32. package/dist/cosign/seed.d.ts.map +1 -0
  33. package/dist/cosign/seed.js +69 -0
  34. package/dist/cosign/seed.js.map +1 -0
  35. package/dist/cosign/transports.d.ts +127 -0
  36. package/dist/cosign/transports.d.ts.map +1 -0
  37. package/dist/cosign/transports.js +426 -0
  38. package/dist/cosign/transports.js.map +1 -0
  39. package/dist/cosign/vaultShare.d.ts +65 -0
  40. package/dist/cosign/vaultShare.d.ts.map +1 -0
  41. package/dist/cosign/vaultShare.js +157 -0
  42. package/dist/cosign/vaultShare.js.map +1 -0
  43. package/dist/index.d.ts +16 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +43 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/monero/types.d.ts +75 -0
  48. package/dist/monero/types.d.ts.map +1 -0
  49. package/dist/monero/types.js +9 -0
  50. package/dist/monero/types.js.map +1 -0
  51. package/dist/scanner/baseUrl.d.ts +24 -0
  52. package/dist/scanner/baseUrl.d.ts.map +1 -0
  53. package/dist/scanner/baseUrl.js +35 -0
  54. package/dist/scanner/baseUrl.js.map +1 -0
  55. package/dist/scanner/moneroScannerClient.d.ts +97 -0
  56. package/dist/scanner/moneroScannerClient.d.ts.map +1 -0
  57. package/dist/scanner/moneroScannerClient.js +125 -0
  58. package/dist/scanner/moneroScannerClient.js.map +1 -0
  59. package/dist/scanner/zcashScannerClient.d.ts +116 -0
  60. package/dist/scanner/zcashScannerClient.d.ts.map +1 -0
  61. package/dist/scanner/zcashScannerClient.js +150 -0
  62. package/dist/scanner/zcashScannerClient.js.map +1 -0
  63. package/package.json +37 -0
@@ -0,0 +1,157 @@
1
+ "use strict";
2
+ /**
3
+ * @fileoverview Loader for a single WINBIT32 vault co-signing share (`.wult`).
4
+ *
5
+ * Load ONE Orchard FROST share, then co-sign a shielded transaction with a
6
+ * WINBIT32 cosigner ("cosign.exe") on another device over the WB32COSIGN
7
+ * relay the NFPT API hosts at `/api/cosign`. Works in browsers and Node ≥ 18
8
+ * (atob/btoa + WebCrypto are global in both).
9
+ *
10
+ * The on-disk `.wult` format is owned by WINBIT32's `vaultWrapperFormat.js`.
11
+ * This module is a faithful, byte-compatible port of the *load* path so a
12
+ * share exported from WINBIT32 opens here unchanged:
13
+ *
14
+ * {
15
+ * "type": "winbit32-vault-v2",
16
+ * "version": 2,
17
+ * "vaultData": "<base64 Vultisig SDK protobuf export>",
18
+ * "encrypted": <bool>,
19
+ * "crossChainIdentity"?: { "hexChainCode", "publicKeyEcdsa" },
20
+ * "frost": { "orchard"?: <JSON | "salt.iv.ct">, "sapling"?: ... }
21
+ * }
22
+ *
23
+ * When `encrypted` is true each FROST payload is PBKDF2-SHA-256 (600k iters) →
24
+ * AES-GCM-256, packed as `base64(salt).base64(iv).base64(ciphertext)`. These
25
+ * parameters MUST match WINBIT32 exactly, hence the constants below are not
26
+ * configurable.
27
+ *
28
+ * Scope note: native Vultisig `.vult` files (Orchard via the SDK's
29
+ * `chainKeyShares`) need the Vultisig SDK + frozto WASM to unpack and are
30
+ * handled in a later phase; this loader covers the `.wult` wrapper only.
31
+ */
32
+ Object.defineProperty(exports, "__esModule", { value: true });
33
+ exports.__test_internals = exports.unwrapVaultShare = exports.isWrappedVault = exports.VAULT_V2_TYPE = void 0;
34
+ // Must match WINBIT32 vaultWrapperFormat.js — do not change.
35
+ exports.VAULT_V2_TYPE = 'winbit32-vault-v2';
36
+ const FROST_KDF_ITER = 600000;
37
+ // ─── base64 / binary helpers (match WINBIT32 exactly) ───────────────
38
+ const b64Enc = (buf) => {
39
+ const bytes = buf instanceof Uint8Array ? buf : new Uint8Array(buf);
40
+ let bin = '';
41
+ for (let i = 0; i < bytes.length; i++)
42
+ bin += String.fromCharCode(bytes[i]);
43
+ return btoa(bin);
44
+ };
45
+ const b64Dec = (str) => {
46
+ const bin = atob(str);
47
+ const a = new Uint8Array(bin.length);
48
+ for (let i = 0; i < bin.length; i++)
49
+ a[i] = bin.charCodeAt(i);
50
+ return a;
51
+ };
52
+ const getSubtle = () => {
53
+ const c = (typeof window !== 'undefined' ? window.crypto : globalThis.crypto);
54
+ if (!c || !c.subtle) {
55
+ throw new Error('Web Crypto API unavailable — a secure (HTTPS) context is required to open an encrypted share.');
56
+ }
57
+ return c.subtle;
58
+ };
59
+ const getRandomBytes = (n) => {
60
+ const c = (typeof window !== 'undefined' ? window.crypto : globalThis.crypto);
61
+ return c.getRandomValues(new Uint8Array(n));
62
+ };
63
+ // ─── PBKDF2 + AES-GCM payload encryption (match WINBIT32 exactly) ────
64
+ const frostEncrypt = async (jsonStr, password) => {
65
+ const subtle = getSubtle();
66
+ const enc = new TextEncoder();
67
+ const salt = getRandomBytes(16);
68
+ const iv = getRandomBytes(12);
69
+ const km = await subtle.importKey('raw', enc.encode(password), 'PBKDF2', false, ['deriveKey']);
70
+ const key = await subtle.deriveKey({ name: 'PBKDF2', salt, iterations: FROST_KDF_ITER, hash: 'SHA-256' }, km, { name: 'AES-GCM', length: 256 }, false, ['encrypt']);
71
+ const ct = await subtle.encrypt({ name: 'AES-GCM', iv }, key, enc.encode(jsonStr));
72
+ return `${b64Enc(salt)}.${b64Enc(iv)}.${b64Enc(ct)}`;
73
+ };
74
+ const frostDecrypt = async (encoded, password) => {
75
+ const [sB, iB, cB] = encoded.split('.');
76
+ if (!sB || !iB || !cB)
77
+ throw new Error('Malformed encrypted share blob.');
78
+ const subtle = getSubtle();
79
+ const km = await subtle.importKey('raw', new TextEncoder().encode(password), 'PBKDF2', false, ['deriveKey']);
80
+ const key = await subtle.deriveKey({ name: 'PBKDF2', salt: b64Dec(sB), iterations: FROST_KDF_ITER, hash: 'SHA-256' }, km, { name: 'AES-GCM', length: 256 }, false, ['decrypt']);
81
+ let plain;
82
+ try {
83
+ plain = await subtle.decrypt({ name: 'AES-GCM', iv: b64Dec(iB) }, key, b64Dec(cB));
84
+ }
85
+ catch {
86
+ throw new Error('Incorrect password (could not decrypt the share).');
87
+ }
88
+ return new TextDecoder().decode(plain);
89
+ };
90
+ // ─── Public API ─────────────────────────────────────────────────────
91
+ /** Cheap structural sniff for a `.wult` v2 wrapper (never throws). */
92
+ const isWrappedVault = (content) => {
93
+ if (typeof content !== 'string' || content[0] !== '{')
94
+ return false;
95
+ try {
96
+ return JSON.parse(content)?.type === exports.VAULT_V2_TYPE;
97
+ }
98
+ catch {
99
+ return false;
100
+ }
101
+ };
102
+ exports.isWrappedVault = isWrappedVault;
103
+ /**
104
+ * Load a `.wult` share, decrypting its FROST payloads when a password is set.
105
+ * Throws if the content isn't a v2 wrapper or the password is wrong.
106
+ *
107
+ * Individual payload decryption failures (e.g. a corrupt Sapling blob) leave
108
+ * that field null rather than aborting the whole load — matching WINBIT32 — so
109
+ * a usable Orchard share still opens.
110
+ */
111
+ const unwrapVaultShare = async (content, password) => {
112
+ let obj;
113
+ try {
114
+ obj = JSON.parse(content);
115
+ }
116
+ catch {
117
+ throw new Error('This file is not a valid Winbit32 vault share.');
118
+ }
119
+ if (obj?.type !== exports.VAULT_V2_TYPE) {
120
+ throw new Error('Not a Winbit32 co-signing share (.wult).');
121
+ }
122
+ const encrypted = !!obj.encrypted;
123
+ if (encrypted && !password) {
124
+ throw new Error('This share is password-protected. Enter its password to open it.');
125
+ }
126
+ const result = {
127
+ sdkVaultString: obj.vaultData,
128
+ orchardFrost: null,
129
+ saplingBundleBase64: null,
130
+ crossChainIdentity: null,
131
+ encrypted,
132
+ };
133
+ if (obj.crossChainIdentity?.hexChainCode && obj.crossChainIdentity?.publicKeyEcdsa) {
134
+ result.crossChainIdentity = {
135
+ hexChainCode: obj.crossChainIdentity.hexChainCode,
136
+ publicKeyEcdsa: obj.crossChainIdentity.publicKeyEcdsa,
137
+ };
138
+ }
139
+ if (obj.frost?.orchard) {
140
+ const raw = (encrypted && password) ? await frostDecrypt(obj.frost.orchard, password) : obj.frost.orchard;
141
+ result.orchardFrost = typeof raw === 'string' ? JSON.parse(raw) : raw;
142
+ }
143
+ if (obj.frost?.sapling) {
144
+ try {
145
+ const raw = (encrypted && password) ? await frostDecrypt(obj.frost.sapling, password) : obj.frost.sapling;
146
+ result.saplingBundleBase64 = typeof raw === 'string' ? raw : null;
147
+ }
148
+ catch (err) {
149
+ console.warn('Sapling share extraction failed:', err instanceof Error ? err.message : err);
150
+ }
151
+ }
152
+ return result;
153
+ };
154
+ exports.unwrapVaultShare = unwrapVaultShare;
155
+ // Exposed for tests only (build a fixture without a real WINBIT32 export).
156
+ exports.__test_internals = { frostEncrypt, frostDecrypt };
157
+ //# sourceMappingURL=vaultShare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vaultShare.js","sourceRoot":"","sources":["../../src/cosign/vaultShare.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @winbit32/wallet-kit — embeddable Zcash + Monero wallet primitives.
3
+ *
4
+ * Extraction roadmap (see WINBIT32/project_outline.md, "Wallet-kit split
5
+ * + MCP payments processor"): scanner clients (done) → cosign
6
+ * (WB32COSIGN) client incl. headless initiator (done) → shielded
7
+ * send/scan core (mnemonic path) → MCP payment tools (payments-gateway).
8
+ */
9
+ export { DEV_SCANNER_PROXY_BASE, PRODUCTION_SCANNER_BASE, resolveWalletScannerBaseUrl, } from './scanner/baseUrl';
10
+ export { createWalletScannerClient, } from './scanner/zcashScannerClient';
11
+ export type { WalletScannerClientConfig, WalletScannerClientType, } from './scanner/zcashScannerClient';
12
+ export { createMoneroWalletScannerClient, mapScannerBalanceToSnapshot, resolveMoneroScannerBaseUrl, isMoneroBalanceViaScannerEnabled, } from './scanner/moneroScannerClient';
13
+ export type { MoneroWalletScannerClientConfig, MoneroScannerBalanceWire, MoneroScannerJobWire, MoneroWalletScannerClientType, } from './scanner/moneroScannerClient';
14
+ export type { MoneroBalanceSnapshot } from './monero/types';
15
+ export * from './cosign/index';
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EACN,sBAAsB,EACtB,uBAAuB,EACvB,2BAA2B,GAC3B,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACN,yBAAyB,GACzB,MAAM,8BAA8B,CAAC;AACtC,YAAY,EACX,yBAAyB,EACzB,uBAAuB,GACvB,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EACN,+BAA+B,EAC/B,2BAA2B,EAC3B,2BAA2B,EAC3B,gCAAgC,GAChC,MAAM,+BAA+B,CAAC;AACvC,YAAY,EACX,+BAA+B,EAC/B,wBAAwB,EACxB,oBAAoB,EACpB,6BAA6B,GAC7B,MAAM,+BAA+B,CAAC;AAGvC,YAAY,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAI5D,cAAc,gBAAgB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ /**
3
+ * @winbit32/wallet-kit — embeddable Zcash + Monero wallet primitives.
4
+ *
5
+ * Extraction roadmap (see WINBIT32/project_outline.md, "Wallet-kit split
6
+ * + MCP payments processor"): scanner clients (done) → cosign
7
+ * (WB32COSIGN) client incl. headless initiator (done) → shielded
8
+ * send/scan core (mnemonic path) → MCP payment tools (payments-gateway).
9
+ */
10
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ var desc = Object.getOwnPropertyDescriptor(m, k);
13
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
14
+ desc = { enumerable: true, get: function() { return m[k]; } };
15
+ }
16
+ Object.defineProperty(o, k2, desc);
17
+ }) : (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ o[k2] = m[k];
20
+ }));
21
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
22
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
23
+ };
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ exports.isMoneroBalanceViaScannerEnabled = exports.resolveMoneroScannerBaseUrl = exports.mapScannerBalanceToSnapshot = exports.createMoneroWalletScannerClient = exports.createWalletScannerClient = exports.resolveWalletScannerBaseUrl = exports.PRODUCTION_SCANNER_BASE = exports.DEV_SCANNER_PROXY_BASE = void 0;
26
+ // Scanner base-URL resolution (dev proxy vs production API host).
27
+ var baseUrl_1 = require("./scanner/baseUrl");
28
+ Object.defineProperty(exports, "DEV_SCANNER_PROXY_BASE", { enumerable: true, get: function () { return baseUrl_1.DEV_SCANNER_PROXY_BASE; } });
29
+ Object.defineProperty(exports, "PRODUCTION_SCANNER_BASE", { enumerable: true, get: function () { return baseUrl_1.PRODUCTION_SCANNER_BASE; } });
30
+ Object.defineProperty(exports, "resolveWalletScannerBaseUrl", { enumerable: true, get: function () { return baseUrl_1.resolveWalletScannerBaseUrl; } });
31
+ // Zcash Orchard scan-job + UTXO + broadcast client.
32
+ var zcashScannerClient_1 = require("./scanner/zcashScannerClient");
33
+ Object.defineProperty(exports, "createWalletScannerClient", { enumerable: true, get: function () { return zcashScannerClient_1.createWalletScannerClient; } });
34
+ // Monero LWS scan-job client.
35
+ var moneroScannerClient_1 = require("./scanner/moneroScannerClient");
36
+ Object.defineProperty(exports, "createMoneroWalletScannerClient", { enumerable: true, get: function () { return moneroScannerClient_1.createMoneroWalletScannerClient; } });
37
+ Object.defineProperty(exports, "mapScannerBalanceToSnapshot", { enumerable: true, get: function () { return moneroScannerClient_1.mapScannerBalanceToSnapshot; } });
38
+ Object.defineProperty(exports, "resolveMoneroScannerBaseUrl", { enumerable: true, get: function () { return moneroScannerClient_1.resolveMoneroScannerBaseUrl; } });
39
+ Object.defineProperty(exports, "isMoneroBalanceViaScannerEnabled", { enumerable: true, get: function () { return moneroScannerClient_1.isMoneroBalanceViaScannerEnabled; } });
40
+ // WB32COSIGN co-signing client: .wult share loading, Orchard FROST engine
41
+ // bridge, relay/QR ceremony, and the headless send pipeline.
42
+ __exportStar(require("./cosign/index"), exports);
43
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;;;;;;;;;;;;;;;AAEH,kEAAkE;AAClE,6CAI2B;AAH1B,iHAAA,sBAAsB,OAAA;AACtB,kHAAA,uBAAuB,OAAA;AACvB,sHAAA,2BAA2B,OAAA;AAG5B,oDAAoD;AACpD,mEAEsC;AADrC,+HAAA,yBAAyB,OAAA;AAO1B,8BAA8B;AAC9B,qEAKuC;AAJtC,sIAAA,+BAA+B,OAAA;AAC/B,kIAAA,2BAA2B,OAAA;AAC3B,kIAAA,2BAA2B,OAAA;AAC3B,uIAAA,gCAAgC,OAAA;AAYjC,0EAA0E;AAC1E,6DAA6D;AAC7D,iDAA+B"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Monero balance/scan wire types shared between the wallet-kit scanner
3
+ * client and host-app account logic (Winbit32's `moneroAccount.ts`
4
+ * re-exports {@link MoneroBalanceSnapshot} from here so there is one
5
+ * source of truth).
6
+ */
7
+ export interface MoneroBalanceSnapshot {
8
+ /**
9
+ * `info.total_received - info.total_sent`. Can go *negative* when
10
+ * LWS flags ring-decoy hits as spends and the wallet hasn't
11
+ * scanned the matching receives (or never received them at all).
12
+ * Kept for callers that want the raw LWS arithmetic; the receive
13
+ * UI prefers {@link receivedAtomic} which is always >= 0.
14
+ */
15
+ totalAtomic: bigint;
16
+ /**
17
+ * `info.total_received` — every output LWS has detected for this
18
+ * view key. Never negative. Used as the headline "Total received"
19
+ * figure in the receive panel because it doesn't get poisoned by
20
+ * LWS's spend-detection false positives (see
21
+ * {@link lwsObservedSpentAtomic}).
22
+ */
23
+ receivedAtomic: bigint;
24
+ /**
25
+ * `info.total_sent` — the sum of every output amount LWS has ever
26
+ * seen referenced in a transaction's input ring that touches one
27
+ * of this wallet's known outputs.
28
+ *
29
+ * IMPORTANT: monero-lws cannot distinguish a real spend from a
30
+ * ring-decoy hit because the spend-detection path matches on
31
+ * `(amount, global_offset)` rather than computing the real key
32
+ * image. Wallets whose outputs are popular ring members will see
33
+ * this figure climb far above their actual outgoing volume — that
34
+ * is the root cause of the "negative balance" reports in the
35
+ * receive panel. Use this strictly as a diagnostic; the trusted
36
+ * source for spendable funds is {@link spendableAtomic} (which
37
+ * tracks what the LWS believes is unspent after its own filter).
38
+ */
39
+ lwsObservedSpentAtomic: bigint;
40
+ /** Confirmed, currently locked funds (e.g. coinbase outputs). */
41
+ lockedAtomic: bigint;
42
+ /** Pending outgoing (sent but not yet mined) — derived from history. */
43
+ pendingOutAtomic: bigint;
44
+ /** Pending incoming — derived from mempool transactions if present. */
45
+ pendingInAtomic: bigint;
46
+ /**
47
+ * Spendable balance — sum of `/get_unspent_outs` outputs after the
48
+ * host app's key-image filter (`MoneroAccount.filterSpentByKeyImage`
49
+ * for 1-of-1 wallets), minus locked and pending outgoing. NFPT
50
+ * scanner jobs only have the view key; the host's
51
+ * `applySpendableOverlay` patches their spendable figure in the
52
+ * browser. Falls back to arithmetic only when the unspent query
53
+ * fails.
54
+ */
55
+ spendableAtomic: bigint;
56
+ /** Scan progress as a 0–1 fraction; 1 means caught up with monerod. */
57
+ scanProgress: number;
58
+ /** LWS-reported chain head height. */
59
+ chainHeight: number;
60
+ /** Block height the LWS has scanned this account to. */
61
+ scannedHeight: number;
62
+ /**
63
+ * Earliest block the LWS scanned for this account. By default a
64
+ * freshly-registered view key starts at the current chain tip,
65
+ * but `/import_wallet_request` can shift it back. Surfaced so the
66
+ * receive panel can prompt users to rescan older blocks when an
67
+ * imported phrase shows zero balance.
68
+ */
69
+ startHeight: number;
70
+ /** Block height of the most recent transaction touching this account. */
71
+ transactionHeight: number;
72
+ /** Exchange rates served by the LWS, if `--exchange-rate-interval` is on. */
73
+ rates?: Record<string, number>;
74
+ }
75
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/monero/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,qBAAqB;IACrC;;;;;;OAMG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;OAMG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB;;;;;;;;;;;;;;OAcG;IACH,sBAAsB,EAAE,MAAM,CAAC;IAC/B,iEAAiE;IACjE,YAAY,EAAE,MAAM,CAAC;IACrB,wEAAwE;IACxE,gBAAgB,EAAE,MAAM,CAAC;IACzB,uEAAuE;IACvE,eAAe,EAAE,MAAM,CAAC;IACxB;;;;;;;;OAQG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB,uEAAuE;IACvE,YAAY,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,wDAAwD;IACxD,aAAa,EAAE,MAAM,CAAC;IACtB;;;;;;OAMG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B"}
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ /**
3
+ * Monero balance/scan wire types shared between the wallet-kit scanner
4
+ * client and host-app account logic (Winbit32's `moneroAccount.ts`
5
+ * re-exports {@link MoneroBalanceSnapshot} from here so there is one
6
+ * source of truth).
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/monero/types.ts"],"names":[],"mappings":";AAAA;;;;;GAKG"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Canonical NFPT wallet-scanner base-URL resolution.
3
+ *
4
+ * One resolver for every consumer of the NFPT-hosted scanner API
5
+ * (Zcash Orchard scan jobs, Monero LWS scan jobs, the Money Manager NFPT
6
+ * viewer):
7
+ *
8
+ * - Dev (`localhost:3000`): same-origin `/api`, so the host app's dev
9
+ * proxy (Winbit32's `setupProxy.js`) forwards the path (e.g.
10
+ * `/api/wallet-scanner`, `/api/nfpt`) to the API host with no
11
+ * cross-origin preflight.
12
+ * - Production: bundles are typically served from a different host
13
+ * than the API, so a same-origin `/api/...` path has no route.
14
+ * Target the public API host directly; its nginx is CORS-open and
15
+ * injects the upstream X-API-Key, so browsers need no key.
16
+ *
17
+ * `REACT_APP_WALLET_SCANNER_URL` overrides both (staging/test hosts).
18
+ * Embedders not using CRA-style env injection can simply pass an
19
+ * explicit `baseUrl` to the client factories instead.
20
+ */
21
+ export declare const DEV_SCANNER_PROXY_BASE = "/api";
22
+ export declare const PRODUCTION_SCANNER_BASE = "https://api.zcash.winbit32.com/api";
23
+ export declare function resolveWalletScannerBaseUrl(): string;
24
+ //# sourceMappingURL=baseUrl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseUrl.d.ts","sourceRoot":"","sources":["../../src/scanner/baseUrl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,eAAO,MAAM,sBAAsB,SAAS,CAAC;AAC7C,eAAO,MAAM,uBAAuB,uCAAuC,CAAC;AAE5E,wBAAgB,2BAA2B,IAAI,MAAM,CAMpD"}
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ /**
3
+ * Canonical NFPT wallet-scanner base-URL resolution.
4
+ *
5
+ * One resolver for every consumer of the NFPT-hosted scanner API
6
+ * (Zcash Orchard scan jobs, Monero LWS scan jobs, the Money Manager NFPT
7
+ * viewer):
8
+ *
9
+ * - Dev (`localhost:3000`): same-origin `/api`, so the host app's dev
10
+ * proxy (Winbit32's `setupProxy.js`) forwards the path (e.g.
11
+ * `/api/wallet-scanner`, `/api/nfpt`) to the API host with no
12
+ * cross-origin preflight.
13
+ * - Production: bundles are typically served from a different host
14
+ * than the API, so a same-origin `/api/...` path has no route.
15
+ * Target the public API host directly; its nginx is CORS-open and
16
+ * injects the upstream X-API-Key, so browsers need no key.
17
+ *
18
+ * `REACT_APP_WALLET_SCANNER_URL` overrides both (staging/test hosts).
19
+ * Embedders not using CRA-style env injection can simply pass an
20
+ * explicit `baseUrl` to the client factories instead.
21
+ */
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.resolveWalletScannerBaseUrl = exports.PRODUCTION_SCANNER_BASE = exports.DEV_SCANNER_PROXY_BASE = void 0;
24
+ exports.DEV_SCANNER_PROXY_BASE = '/api';
25
+ exports.PRODUCTION_SCANNER_BASE = 'https://api.zcash.winbit32.com/api';
26
+ function resolveWalletScannerBaseUrl() {
27
+ const explicit = (typeof process !== 'undefined' && process.env?.REACT_APP_WALLET_SCANNER_URL) || '';
28
+ if (explicit)
29
+ return explicit.replace(/\/$/, '');
30
+ const isProduction = typeof process !== 'undefined'
31
+ && process.env?.NODE_ENV === 'production';
32
+ return (isProduction ? exports.PRODUCTION_SCANNER_BASE : exports.DEV_SCANNER_PROXY_BASE).replace(/\/$/, '');
33
+ }
34
+ exports.resolveWalletScannerBaseUrl = resolveWalletScannerBaseUrl;
35
+ //# sourceMappingURL=baseUrl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseUrl.js","sourceRoot":"","sources":["../../src/scanner/baseUrl.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;;AAEU,QAAA,sBAAsB,GAAG,MAAM,CAAC;AAChC,QAAA,uBAAuB,GAAG,oCAAoC,CAAC;AAE5E,SAAgB,2BAA2B;IAC1C,MAAM,QAAQ,GAAG,CAAC,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,CAAC,GAAG,EAAE,4BAA4B,CAAC,IAAI,EAAE,CAAC;IACrG,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACjD,MAAM,YAAY,GAAG,OAAO,OAAO,KAAK,WAAW;WAC/C,OAAO,CAAC,GAAG,EAAE,QAAQ,KAAK,YAAY,CAAC;IAC3C,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,+BAAuB,CAAC,CAAC,CAAC,8BAAsB,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAC7F,CAAC;AAND,kEAMC"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * NFPT wallet-scanner client for Monero LWS balance / scan jobs.
3
+ *
4
+ * Mirrors Zcash's orchard scan job flow: the browser polls NFPT every
5
+ * few seconds instead of hammering monero-lws directly.
6
+ *
7
+ * - POST /wallet-scanner/monero/scan/job
8
+ * - GET /wallet-scanner/monero/scan/job/{jobId}
9
+ * - DELETE /wallet-scanner/monero/scan/job/{jobId}
10
+ */
11
+ import type { MoneroBalanceSnapshot } from '../monero/types';
12
+ export interface MoneroWalletScannerClientConfig {
13
+ baseUrl?: string;
14
+ apiKey?: string;
15
+ }
16
+ /** Wire balance from NFPT (atomic values as decimal strings). */
17
+ export interface MoneroScannerBalanceWire {
18
+ totalAtomic: string;
19
+ /**
20
+ * Added in WINBIT32 ≥ v0.x to surface `info.total_received`
21
+ * separately from `total - sent`. Older NFPT builds omit it —
22
+ * the mapper below back-fills from `totalAtomic` so the snapshot
23
+ * still satisfies {@link MoneroBalanceSnapshot}.
24
+ */
25
+ receivedAtomic?: string;
26
+ /** `info.total_sent` (LWS-detected outgoing volume incl. ring decoys). */
27
+ lwsObservedSpentAtomic?: string;
28
+ lockedAtomic: string;
29
+ pendingInAtomic: string;
30
+ pendingOutAtomic: string;
31
+ spendableAtomic: string;
32
+ scanProgress: number;
33
+ chainHeight: number;
34
+ scannedHeight: number;
35
+ startHeight: number;
36
+ transactionHeight: number;
37
+ rates?: Record<string, number>;
38
+ }
39
+ export interface MoneroScannerJobWire {
40
+ jobId: string;
41
+ status: 'running' | 'completed' | 'failed' | 'cancelled';
42
+ startedAt?: string;
43
+ finishedAt?: string | null;
44
+ error?: string | null;
45
+ progress?: {
46
+ scannedHeight: number;
47
+ chainHeight: number;
48
+ scanProgress: number;
49
+ percentComplete: number;
50
+ startHeight?: number;
51
+ };
52
+ balance: MoneroScannerBalanceWire | null;
53
+ }
54
+ export declare function mapScannerBalanceToSnapshot(b: MoneroScannerBalanceWire): MoneroBalanceSnapshot;
55
+ /**
56
+ * Kept as the monero-local name for existing callers/tests; resolution
57
+ * itself lives in the shared {@link resolveWalletScannerBaseUrl} (dev
58
+ * same-origin proxy vs production api.zcash.winbit32.com — see that
59
+ * module for the live-bug rationale).
60
+ */
61
+ export declare function resolveMoneroScannerBaseUrl(): string;
62
+ export declare function isMoneroBalanceViaScannerEnabled(): boolean;
63
+ export declare const createMoneroWalletScannerClient: (config?: MoneroWalletScannerClientConfig) => {
64
+ startMoneroScanJob: (body: {
65
+ address: string;
66
+ viewKey: string;
67
+ fromHeight?: number;
68
+ }) => Promise<{
69
+ success: boolean;
70
+ data?: {
71
+ jobId: string;
72
+ jobToken: string;
73
+ } | undefined;
74
+ error?: string | undefined;
75
+ }>;
76
+ getMoneroScanJob: (jobId: string, auth: {
77
+ jobToken?: string;
78
+ apiKey?: string;
79
+ }) => Promise<{
80
+ success: boolean;
81
+ data?: {
82
+ job: MoneroScannerJobWire;
83
+ } | undefined;
84
+ error?: string | undefined;
85
+ }>;
86
+ cancelMoneroScanJob: (jobId: string, auth: {
87
+ jobToken?: string;
88
+ apiKey?: string;
89
+ }) => Promise<{
90
+ success: boolean;
91
+ data?: {
92
+ cancelled: boolean;
93
+ } | undefined;
94
+ }>;
95
+ };
96
+ export type MoneroWalletScannerClientType = ReturnType<typeof createMoneroWalletScannerClient>;
97
+ //# sourceMappingURL=moneroScannerClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"moneroScannerClient.d.ts","sourceRoot":"","sources":["../../src/scanner/moneroScannerClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAG7D,MAAM,WAAW,+BAA+B;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAkBD,iEAAiE;AACjE,MAAM,WAAW,wBAAwB;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,0EAA0E;IAC1E,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,oBAAoB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE;QACV,aAAa,EAAE,MAAM,CAAC;QACtB,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,eAAe,EAAE,MAAM,CAAC;QACxB,WAAW,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,OAAO,EAAE,wBAAwB,GAAG,IAAI,CAAC;CACzC;AAED,wBAAgB,2BAA2B,CAAC,CAAC,EAAE,wBAAwB,GAAG,qBAAqB,CA6B9F;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,IAAI,MAAM,CAEpD;AAED,wBAAgB,gCAAgC,IAAI,OAAO,CAK1D;AAED,eAAO,MAAM,+BAA+B,YACnC,+BAA+B;+BAYL;QAChC,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,CAAC,EAAE,MAAM,CAAC;KACpB;iBAOU,OAAO;;mBACA,MAAM;sBAAY,MAAM;;;;8BAKV,MAAM,QAAQ;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;iBASzE,OAAO;;iBACF,oBAAoB;;;;iCAKD,MAAM,QAAQ;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;iBAQjD,OAAO;;uBAAsB,OAAO;;;CAG3E,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG,UAAU,CAAC,OAAO,+BAA+B,CAAC,CAAC"}
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ /**
3
+ * NFPT wallet-scanner client for Monero LWS balance / scan jobs.
4
+ *
5
+ * Mirrors Zcash's orchard scan job flow: the browser polls NFPT every
6
+ * few seconds instead of hammering monero-lws directly.
7
+ *
8
+ * - POST /wallet-scanner/monero/scan/job
9
+ * - GET /wallet-scanner/monero/scan/job/{jobId}
10
+ * - DELETE /wallet-scanner/monero/scan/job/{jobId}
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.createMoneroWalletScannerClient = exports.isMoneroBalanceViaScannerEnabled = exports.resolveMoneroScannerBaseUrl = exports.mapScannerBalanceToSnapshot = void 0;
14
+ const baseUrl_1 = require("./baseUrl");
15
+ async function handleJsonResponse(res) {
16
+ let payload = null;
17
+ try {
18
+ payload = await res.json();
19
+ }
20
+ catch {
21
+ throw new Error(`Invalid JSON response (status ${res.status})`);
22
+ }
23
+ if (!res.ok) {
24
+ const msg = payload?.error
25
+ || payload?.message
26
+ || `HTTP ${res.status}`;
27
+ throw new Error(msg);
28
+ }
29
+ return payload;
30
+ }
31
+ function mapScannerBalanceToSnapshot(b) {
32
+ const totalAtomic = BigInt(b.totalAtomic || '0');
33
+ // Back-fill the receive/spend split from `totalAtomic` for legacy
34
+ // NFPT builds that don't surface the fields explicitly. Positive
35
+ // total → assume all receipts, no observed spends; negative total
36
+ // → assume the absolute value is observed spends with no receipts.
37
+ // Real LWS polls overwrite this in seconds, so the back-fill only
38
+ // matters for the very first NFPT response after a job start.
39
+ const receivedAtomic = b.receivedAtomic != null
40
+ ? BigInt(b.receivedAtomic)
41
+ : (totalAtomic > 0n ? totalAtomic : 0n);
42
+ const lwsObservedSpentAtomic = b.lwsObservedSpentAtomic != null
43
+ ? BigInt(b.lwsObservedSpentAtomic)
44
+ : (totalAtomic < 0n ? -totalAtomic : 0n);
45
+ return {
46
+ totalAtomic,
47
+ receivedAtomic,
48
+ lwsObservedSpentAtomic,
49
+ lockedAtomic: BigInt(b.lockedAtomic || '0'),
50
+ pendingInAtomic: BigInt(b.pendingInAtomic || '0'),
51
+ pendingOutAtomic: BigInt(b.pendingOutAtomic || '0'),
52
+ spendableAtomic: BigInt(b.spendableAtomic || '0'),
53
+ scanProgress: b.scanProgress ?? 0,
54
+ chainHeight: b.chainHeight ?? 0,
55
+ scannedHeight: b.scannedHeight ?? 0,
56
+ startHeight: b.startHeight ?? 0,
57
+ transactionHeight: b.transactionHeight ?? 0,
58
+ rates: b.rates,
59
+ };
60
+ }
61
+ exports.mapScannerBalanceToSnapshot = mapScannerBalanceToSnapshot;
62
+ /**
63
+ * Kept as the monero-local name for existing callers/tests; resolution
64
+ * itself lives in the shared {@link resolveWalletScannerBaseUrl} (dev
65
+ * same-origin proxy vs production api.zcash.winbit32.com — see that
66
+ * module for the live-bug rationale).
67
+ */
68
+ function resolveMoneroScannerBaseUrl() {
69
+ return (0, baseUrl_1.resolveWalletScannerBaseUrl)();
70
+ }
71
+ exports.resolveMoneroScannerBaseUrl = resolveMoneroScannerBaseUrl;
72
+ function isMoneroBalanceViaScannerEnabled() {
73
+ if (typeof process !== 'undefined' && process.env?.REACT_APP_MONERO_BALANCE_VIA_SCANNER === 'false') {
74
+ return false;
75
+ }
76
+ return true;
77
+ }
78
+ exports.isMoneroBalanceViaScannerEnabled = isMoneroBalanceViaScannerEnabled;
79
+ const createMoneroWalletScannerClient = (config = {}) => {
80
+ const baseUrl = (config.baseUrl || resolveMoneroScannerBaseUrl()).replace(/\/$/, '');
81
+ const withHeaders = (extra) => {
82
+ const headers = { 'Content-Type': 'application/json' };
83
+ if (config.apiKey)
84
+ headers['X-API-Key'] = config.apiKey;
85
+ if (extra)
86
+ Object.assign(headers, extra);
87
+ return headers;
88
+ };
89
+ return {
90
+ startMoneroScanJob: async (body) => {
91
+ const res = await fetch(`${baseUrl}/wallet-scanner/monero/scan/job`, {
92
+ method: 'POST',
93
+ headers: withHeaders(),
94
+ body: JSON.stringify(body),
95
+ });
96
+ return handleJsonResponse(res);
97
+ },
98
+ getMoneroScanJob: async (jobId, auth) => {
99
+ const headers = withHeaders();
100
+ if (auth.jobToken)
101
+ headers['X-Job-Token'] = auth.jobToken;
102
+ if (auth.apiKey)
103
+ headers['X-API-Key'] = auth.apiKey;
104
+ const res = await fetch(`${baseUrl}/wallet-scanner/monero/scan/job/${jobId}`, {
105
+ method: 'GET',
106
+ headers,
107
+ });
108
+ return handleJsonResponse(res);
109
+ },
110
+ cancelMoneroScanJob: async (jobId, auth) => {
111
+ const headers = withHeaders();
112
+ if (auth.jobToken)
113
+ headers['X-Job-Token'] = auth.jobToken;
114
+ if (auth.apiKey)
115
+ headers['X-API-Key'] = auth.apiKey;
116
+ const res = await fetch(`${baseUrl}/wallet-scanner/monero/scan/job/${jobId}`, {
117
+ method: 'DELETE',
118
+ headers,
119
+ });
120
+ return handleJsonResponse(res);
121
+ },
122
+ };
123
+ };
124
+ exports.createMoneroWalletScannerClient = createMoneroWalletScannerClient;
125
+ //# sourceMappingURL=moneroScannerClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"moneroScannerClient.js","sourceRoot":"","sources":["../../src/scanner/moneroScannerClient.ts"],"names":[],"mappings":"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"}