dop-wallet-v6 1.3.35 β†’ 1.3.37

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.
@@ -2,3 +2,5 @@ import { DopEngine } from 'dop-engine-v3';
2
2
  export declare const getEngine: () => DopEngine;
3
3
  export declare const hasEngine: () => boolean;
4
4
  export declare const setEngine: (engine: Optional<DopEngine>) => void;
5
+ export declare const getDatabase: () => Optional<any>;
6
+ export declare const setDatabase: (db: Optional<any>) => void;
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.setEngine = exports.hasEngine = exports.getEngine = void 0;
3
+ exports.setDatabase = exports.getDatabase = exports.setEngine = exports.hasEngine = exports.getEngine = void 0;
4
4
  const dop_sharedmodels_v3_1 = require("dop-sharedmodels-v3");
5
5
  let savedEngine;
6
+ let savedDatabase; // Can be LevelDOWN or ReactNativeLevelDB
6
7
  const getEngine = () => {
7
8
  if (!savedEngine) {
8
9
  throw new Error('DOP Engine not yet initialized.');
@@ -18,4 +19,12 @@ const setEngine = (engine) => {
18
19
  savedEngine = engine;
19
20
  };
20
21
  exports.setEngine = setEngine;
22
+ const getDatabase = () => {
23
+ return savedDatabase;
24
+ };
25
+ exports.getDatabase = getDatabase;
26
+ const setDatabase = (db) => {
27
+ savedDatabase = db;
28
+ };
29
+ exports.setDatabase = setDatabase;
21
30
  //# sourceMappingURL=engine.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../../src/services/dop/core/engine.ts"],"names":[],"mappings":";;;AACA,6DAAgD;AAEhD,IAAI,WAAgC,CAAC;AAE9B,MAAM,SAAS,GAAG,GAAc,EAAE;IACvC,IAAI,CAAC,WAAW,EAAE;QAChB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;KACpD;IACD,OAAO,WAAW,CAAC;AACrB,CAAC,CAAC;AALW,QAAA,SAAS,aAKpB;AAEK,MAAM,SAAS,GAAG,GAAY,EAAE;IACrC,OAAO,IAAA,+BAAS,EAAC,WAAW,CAAC,CAAC;AAChC,CAAC,CAAC;AAFW,QAAA,SAAS,aAEpB;AAEK,MAAM,SAAS,GAAG,CAAC,MAA2B,EAAE,EAAE;IACvD,WAAW,GAAG,MAAM,CAAC;AACvB,CAAC,CAAC;AAFW,QAAA,SAAS,aAEpB","sourcesContent":["import { DopEngine } from 'dop-engine-v3';\nimport { isDefined } from 'dop-sharedmodels-v3';\n\nlet savedEngine: Optional<DopEngine>;\n\nexport const getEngine = (): DopEngine => {\n if (!savedEngine) {\n throw new Error('DOP Engine not yet initialized.');\n }\n return savedEngine;\n};\n\nexport const hasEngine = (): boolean => {\n return isDefined(savedEngine);\n};\n\nexport const setEngine = (engine: Optional<DopEngine>) => {\n savedEngine = engine;\n};\n"]}
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../../src/services/dop/core/engine.ts"],"names":[],"mappings":";;;AACA,6DAAgD;AAGhD,IAAI,WAAgC,CAAC;AACrC,IAAI,aAA4B,CAAC,CAAC,yCAAyC;AAEpE,MAAM,SAAS,GAAG,GAAc,EAAE;IACvC,IAAI,CAAC,WAAW,EAAE;QAChB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;KACpD;IACD,OAAO,WAAW,CAAC;AACrB,CAAC,CAAC;AALW,QAAA,SAAS,aAKpB;AAEK,MAAM,SAAS,GAAG,GAAY,EAAE;IACrC,OAAO,IAAA,+BAAS,EAAC,WAAW,CAAC,CAAC;AAChC,CAAC,CAAC;AAFW,QAAA,SAAS,aAEpB;AAEK,MAAM,SAAS,GAAG,CAAC,MAA2B,EAAE,EAAE;IACvD,WAAW,GAAG,MAAM,CAAC;AACvB,CAAC,CAAC;AAFW,QAAA,SAAS,aAEpB;AAEK,MAAM,WAAW,GAAG,GAAkB,EAAE;IAC7C,OAAO,aAAa,CAAC;AACvB,CAAC,CAAC;AAFW,QAAA,WAAW,eAEtB;AAEK,MAAM,WAAW,GAAG,CAAC,EAAiB,EAAE,EAAE;IAC/C,aAAa,GAAG,EAAE,CAAC;AACrB,CAAC,CAAC;AAFW,QAAA,WAAW,eAEtB","sourcesContent":["import { DopEngine } from 'dop-engine-v3';\nimport { isDefined } from 'dop-sharedmodels-v3';\nimport type { ReactNativeLevelDB } from './react-native-init';\n\nlet savedEngine: Optional<DopEngine>;\nlet savedDatabase: Optional<any>; // Can be LevelDOWN or ReactNativeLevelDB\n\nexport const getEngine = (): DopEngine => {\n if (!savedEngine) {\n throw new Error('DOP Engine not yet initialized.');\n }\n return savedEngine;\n};\n\nexport const hasEngine = (): boolean => {\n return isDefined(savedEngine);\n};\n\nexport const setEngine = (engine: Optional<DopEngine>) => {\n savedEngine = engine;\n};\n\nexport const getDatabase = (): Optional<any> => {\n return savedDatabase;\n};\n\nexport const setDatabase = (db: Optional<any>) => {\n savedDatabase = db;\n};\n"]}
@@ -1,6 +1,6 @@
1
1
  import type { AbstractLevelDOWN } from 'abstract-leveldown';
2
2
  import { POIList, POIListType } from 'dop-engine-v3';
3
- import { MerkletreeScanUpdateEvent } from 'dop-sharedmodels-v3';
3
+ import { MerkletreeScanUpdateEvent, type Chain, TXIDVersion } from 'dop-sharedmodels-v3';
4
4
  import { ArtifactStore } from '../../artifacts/artifact-store';
5
5
  export type EngineDebugger = {
6
6
  log: (msg: string) => void;
@@ -9,6 +9,26 @@ export type EngineDebugger = {
9
9
  };
10
10
  export declare const setOnUTXOMerkletreeScanCallback: (onUTXOMerkletreeScanCallback: (scanData: MerkletreeScanUpdateEvent) => void) => void;
11
11
  export declare const setOnTXIDMerkletreeScanCallback: (onTXIDMerkletreeScanCallback: (scanData: MerkletreeScanUpdateEvent) => void) => void;
12
+ /**
13
+ * Wait for complete scan including balance updates and persistence.
14
+ * This waits for the merkletree scan Complete status AFTER:
15
+ * - Merkletree scanning completes
16
+ * - Balances are decrypted and updated (if any new transactions)
17
+ * - Database is persisted to storage
18
+ *
19
+ * @param chain - The chain to wait for
20
+ * @param txidVersion - The TXID version being scanned
21
+ * @param timeout - Timeout in milliseconds (default: 600000 = 10 minutes)
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * const engine = getEngine();
26
+ * engine.scanContractHistory(chain, [walletID]);
27
+ * await awaitScanHistoryComplete(chain, TXIDVersion.V3_PoseidonMerkle);
28
+ * // Now ALL data is persisted and ready!
29
+ * ```
30
+ */
31
+ export declare const awaitScanHistoryComplete: (chain: Chain, txidVersion: TXIDVersion, timeout?: number) => Promise<void>;
12
32
  /**
13
33
  *
14
34
  * @param walletSource - Name for your wallet implementation. Encrypted and viewable in private transaction history. Maximum of 16 characters, lowercase.
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.POIListType = exports.stopDopEngine = exports.startDopEngine = exports.setOnTXIDMerkletreeScanCallback = exports.setOnUTXOMerkletreeScanCallback = void 0;
3
+ exports.POIListType = exports.stopDopEngine = exports.startDopEngine = exports.awaitScanHistoryComplete = exports.setOnTXIDMerkletreeScanCallback = exports.setOnUTXOMerkletreeScanCallback = void 0;
4
4
  const dop_engine_v3_1 = require("dop-engine-v3");
5
5
  Object.defineProperty(exports, "POIListType", { enumerable: true, get: function () { return dop_engine_v3_1.POIListType; } });
6
6
  const dop_sharedmodels_v3_1 = require("dop-sharedmodels-v3");
@@ -36,23 +36,139 @@ const setOnTXIDMerkletreeScanCallback = (onTXIDMerkletreeScanCallback) => {
36
36
  }));
37
37
  };
38
38
  exports.setOnTXIDMerkletreeScanCallback = setOnTXIDMerkletreeScanCallback;
39
+ // Track which chains have completed scans to avoid duplicate emissions
40
+ const scanCompletedKeys = new Set();
41
+ // Store resolve functions for pending scan completion promises
42
+ const scanCompletionPromises = new Map();
43
+ const setOnUTXOMerkletreeScanCompletionListener = () => {
44
+ const engine = (0, engine_1.getEngine)();
45
+ engine.on(dop_engine_v3_1.EngineEvent.UTXOMerkletreeHistoryScanUpdate, ({ chain, scanStatus, txidVersion }) => {
46
+ // Only handle the FIRST "Complete" status for this scan
47
+ if (scanStatus === 'Complete') {
48
+ const key = `${txidVersion}-${chain.type}-${chain.id}`;
49
+ // If we've already handled completion for this scan, ignore
50
+ if (scanCompletedKeys.has(key)) {
51
+ return;
52
+ }
53
+ // Mark this scan as completed
54
+ scanCompletedKeys.add(key);
55
+ (0, logger_1.sendMessage)(`πŸ“Š UTXO Merkletree scan completed for ${key}`);
56
+ (0, logger_1.sendMessage)(`πŸ” [TRACE] About to handle completion for ${key}`);
57
+ // Emit scan complete event after merkletree finishes
58
+ // This handles case where there are NO new transactions to decrypt
59
+ // (UTXOScanDecryptBalancesComplete won't fire in that case)
60
+ const handleCompletion = async () => {
61
+ (0, logger_1.sendMessage)(`πŸ” [TRACE] Inside handleCompletion for ${key}`);
62
+ // Force persistence even if no new balances
63
+ const db = (0, engine_1.getDatabase)();
64
+ (0, logger_1.sendMessage)(`πŸ” [TRACE] Got database: ${(0, dop_sharedmodels_v3_1.isDefined)(db) ? 'YES' : 'NO'}`);
65
+ if ((0, dop_sharedmodels_v3_1.isDefined)(db) && typeof db.forcePersist === 'function') {
66
+ try {
67
+ (0, logger_1.sendMessage)(`πŸ” [TRACE] Calling forcePersist...`);
68
+ await db.forcePersist();
69
+ (0, logger_1.sendMessage)('βœ… Database persisted after merkletree scan completion');
70
+ }
71
+ catch (error) {
72
+ (0, logger_1.sendErrorMessage)(new Error(`Failed to persist database: ${error instanceof Error ? error.message : String(error)}`));
73
+ }
74
+ }
75
+ else {
76
+ (0, logger_1.sendMessage)(`⚠️ [TRACE] Database or forcePersist not available, skipping persist`);
77
+ }
78
+ // Resolve any pending promises waiting for this scan to complete
79
+ const resolveFunc = scanCompletionPromises.get(key);
80
+ if ((0, dop_sharedmodels_v3_1.isDefined)(resolveFunc)) {
81
+ (0, logger_1.sendMessage)(`πŸ” [TRACE] Resolving promise for ${key}`);
82
+ resolveFunc();
83
+ scanCompletionPromises.delete(key);
84
+ }
85
+ else {
86
+ (0, logger_1.sendMessage)(`⚠️ [TRACE] No promise waiting for ${key}`);
87
+ }
88
+ };
89
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
90
+ handleCompletion();
91
+ }
92
+ });
93
+ };
39
94
  const setOnUTXOScanDecryptBalancesCompleteListener = () => {
40
95
  const engine = (0, engine_1.getEngine)();
41
96
  engine.on(dop_engine_v3_1.EngineEvent.UTXOScanDecryptBalancesComplete, ({ txidVersion, chain, walletIdFilter, }) => {
42
97
  const updateWalletBalances = async () => {
98
+ const key = `${txidVersion}-${chain.type}-${chain.id}`;
99
+ (0, logger_1.sendMessage)(`πŸ’° Balance decrypt complete for ${key}, updating wallets...`);
43
100
  let walletsToUpdate = Object.values(engine.wallets);
44
101
  if ((0, dop_sharedmodels_v3_1.isDefined)(walletIdFilter)) {
45
102
  walletsToUpdate = walletsToUpdate.filter(wallet => walletIdFilter.includes(wallet.id));
46
103
  }
47
104
  // await onBalancesUpdate calls for each wallet
48
105
  await Promise.all(walletsToUpdate.map(wallet => (0, balance_update_1.onBalancesUpdate)(txidVersion, wallet, chain)));
49
- // emit event to notify listeners that UTXOMerkletreeHistoryScan is complete
50
- engine.emitScanEventHistoryComplete(txidVersion, chain);
106
+ // Force immediate persistence to AsyncStorage/disk after balance updates
107
+ // This ensures balance data is saved before potential app crash/restart
108
+ const db = (0, engine_1.getDatabase)();
109
+ if ((0, dop_sharedmodels_v3_1.isDefined)(db) && typeof db.forcePersist === 'function') {
110
+ try {
111
+ await db.forcePersist();
112
+ (0, logger_1.sendMessage)('βœ… Database persisted after balance updates');
113
+ }
114
+ catch (error) {
115
+ (0, logger_1.sendErrorMessage)(new Error(`Failed to persist database after balance update: ${error instanceof Error ? error.message : String(error)}`));
116
+ }
117
+ }
118
+ // The scan completion will be triggered by the merkletree Complete status event
119
+ // OR we can resolve the promise here since balance updates are done
120
+ (0, logger_1.sendMessage)(`βœ… Balance updates and persistence complete for ${key}`);
121
+ // Resolve promise immediately after balance updates - data is ready!
122
+ const resolveFunc = scanCompletionPromises.get(key);
123
+ if ((0, dop_sharedmodels_v3_1.isDefined)(resolveFunc)) {
124
+ (0, logger_1.sendMessage)(`πŸ” [TRACE] Resolving promise after balance updates for ${key}`);
125
+ resolveFunc();
126
+ scanCompletionPromises.delete(key);
127
+ scanCompletedKeys.add(key); // Mark as completed
128
+ }
51
129
  };
52
130
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
53
131
  updateWalletBalances();
54
132
  });
55
133
  };
134
+ /**
135
+ * Wait for complete scan including balance updates and persistence.
136
+ * This waits for the merkletree scan Complete status AFTER:
137
+ * - Merkletree scanning completes
138
+ * - Balances are decrypted and updated (if any new transactions)
139
+ * - Database is persisted to storage
140
+ *
141
+ * @param chain - The chain to wait for
142
+ * @param txidVersion - The TXID version being scanned
143
+ * @param timeout - Timeout in milliseconds (default: 600000 = 10 minutes)
144
+ *
145
+ * @example
146
+ * ```typescript
147
+ * const engine = getEngine();
148
+ * engine.scanContractHistory(chain, [walletID]);
149
+ * await awaitScanHistoryComplete(chain, TXIDVersion.V3_PoseidonMerkle);
150
+ * // Now ALL data is persisted and ready!
151
+ * ```
152
+ */
153
+ const awaitScanHistoryComplete = (chain, txidVersion, timeout = 600000) => {
154
+ const key = `${txidVersion}-${chain.type}-${chain.id}`;
155
+ (0, logger_1.sendMessage)(`πŸ” [TRACE] Setting up promise for scan completion: ${key}`);
156
+ return new Promise((resolve, reject) => {
157
+ const timeoutId = setTimeout(() => {
158
+ scanCompletionPromises.delete(key);
159
+ reject(new Error(`Scan history completion timeout after ${timeout}ms for chain ${chain.type}:${chain.id}`));
160
+ }, timeout);
161
+ // Store the resolve function so the completion listener can call it
162
+ const resolveFunc = () => {
163
+ (0, logger_1.sendMessage)(`πŸŽ‰ [TRACE] Promise resolved for ${key}`);
164
+ clearTimeout(timeoutId);
165
+ resolve();
166
+ };
167
+ scanCompletionPromises.set(key, resolveFunc);
168
+ (0, logger_1.sendMessage)(`βœ… [TRACE] Promise registered for ${key}`);
169
+ });
170
+ };
171
+ exports.awaitScanHistoryComplete = awaitScanHistoryComplete;
56
172
  /**
57
173
  *
58
174
  * @param walletSource - Name for your wallet implementation. Encrypted and viewable in private transaction history. Maximum of 16 characters, lowercase.
@@ -74,6 +190,8 @@ const startDopEngine = async (walletSource, db, shouldDebug, artifactStore, useN
74
190
  (0, artifacts_1.setUseNativeArtifacts)(useNativeArtifacts);
75
191
  const engine = await dop_engine_v3_1.DopEngine.initForWallet(walletSource, db, artifacts_1.artifactGetterDownloadJustInTime, quick_sync_events_1.quickSyncEventsGraph, dop_txid_sync_graph_v2_1.quickSyncDopTransactionsV2, shouldDebug ? createEngineDebugger(verboseScanLogging) : undefined, skipMerkletreeScans);
76
192
  (0, engine_1.setEngine)(engine);
193
+ (0, engine_1.setDatabase)(db); // Store database instance for force persist access
194
+ setOnUTXOMerkletreeScanCompletionListener();
77
195
  setOnUTXOScanDecryptBalancesCompleteListener();
78
196
  }
79
197
  catch (err) {
@@ -87,6 +205,9 @@ const stopDopEngine = async () => {
87
205
  }
88
206
  await (0, engine_1.getEngine)()?.unload();
89
207
  (0, engine_1.setEngine)(undefined);
208
+ (0, engine_1.setDatabase)(undefined); // Clear database reference
209
+ scanCompletedKeys.clear(); // Clear completion tracking for next engine start
90
210
  };
91
211
  exports.stopDopEngine = stopDopEngine;
212
+ scanCompletionPromises.clear(); // Clear pending promises
92
213
  //# sourceMappingURL=init.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../../../../src/services/dop/core/init.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AbstractLevelDOWN } from 'abstract-leveldown';\nimport {\n DopEngine,\n EngineEvent,\n MerkletreeHistoryScanEventData,\n POIList,\n POIListType,\n UTXOScanDecryptBalancesCompleteEventData,\n AbstractWallet,\n POIMerklerootsValidator,\n} from 'dop-engine-v3';\nimport {\n MerkletreeScanUpdateEvent,\n isDefined,\n type Chain,\n} from 'dop-sharedmodels-v3';\nimport { sendErrorMessage, sendMessage } from '../../../utils/logger';\nimport {\n artifactGetterDownloadJustInTime,\n setArtifactStore,\n setUseNativeArtifacts,\n} from './artifacts';\nimport { ArtifactStore } from '../../artifacts/artifact-store';\nimport { reportAndSanitizeError } from '../../../utils/error';\nimport { quickSyncEventsGraph } from '../quick-sync/quick-sync-events';\nimport { quickSyncDopTransactionsV2 } from '../dop-txids/dop-txid-sync-graph-v2';\nimport { setEngine, getEngine, hasEngine } from './engine';\nimport { onBalancesUpdate } from '../wallets/balance-update';\n\nexport type EngineDebugger = {\n log: (msg: string) => void;\n error: (error: Error) => void;\n verboseScanLogging: boolean;\n};\n\nconst createEngineDebugger = (verboseScanLogging: boolean): EngineDebugger => {\n return {\n log: (msg: string) => sendMessage(msg),\n error: (error: Error) => sendErrorMessage(error),\n verboseScanLogging,\n };\n};\n\nexport const setOnUTXOMerkletreeScanCallback = (\n onUTXOMerkletreeScanCallback: (scanData: MerkletreeScanUpdateEvent) => void,\n) => {\n const engine = getEngine();\n engine.on(\n EngineEvent.UTXOMerkletreeHistoryScanUpdate,\n ({ chain, scanStatus, progress }: MerkletreeHistoryScanEventData) =>\n onUTXOMerkletreeScanCallback({\n scanStatus,\n chain,\n progress: progress ?? 0.0,\n }),\n );\n};\n\nexport const setOnTXIDMerkletreeScanCallback = (\n onTXIDMerkletreeScanCallback: (scanData: MerkletreeScanUpdateEvent) => void,\n) => {\n const engine = getEngine();\n engine.on(\n EngineEvent.TXIDMerkletreeHistoryScanUpdate,\n ({ chain, scanStatus, progress }: MerkletreeHistoryScanEventData) =>\n onTXIDMerkletreeScanCallback({\n scanStatus,\n chain,\n progress: progress ?? 0.0,\n }),\n );\n};\n\nconst setOnUTXOScanDecryptBalancesCompleteListener = () => {\n const engine = getEngine();\n engine.on(\n EngineEvent.UTXOScanDecryptBalancesComplete,\n ({\n txidVersion,\n chain,\n walletIdFilter,\n }: UTXOScanDecryptBalancesCompleteEventData) => {\n const updateWalletBalances = async () => {\n let walletsToUpdate: AbstractWallet[] = Object.values(engine.wallets);\n if (isDefined(walletIdFilter)) {\n walletsToUpdate = walletsToUpdate.filter(wallet =>\n walletIdFilter.includes(wallet.id),\n );\n }\n\n // await onBalancesUpdate calls for each wallet\n await Promise.all(\n walletsToUpdate.map(wallet =>\n onBalancesUpdate(txidVersion, wallet, chain),\n ),\n );\n\n // emit event to notify listeners that UTXOMerkletreeHistoryScan is complete\n engine.emitScanEventHistoryComplete(txidVersion, chain);\n };\n\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n updateWalletBalances();\n },\n );\n};\n\n/**\n *\n * @param walletSource - Name for your wallet implementation. Encrypted and viewable in private transaction history. Maximum of 16 characters, lowercase.\n * @param db - LevelDOWN compatible database for storing encrypted wallets.\n * @param shouldDebug - Whether to forward Engine debug logs to Logger.\n * @param artifactStore - Persistent store for downloading large artifact files. See Wallet SDK Developer Guide for platform implementations.\n * @param useNativeArtifacts - Whether to download native C++ or web-assembly artifacts. TRUE for mobile. FALSE for nodejs and browser.\n * @param skipMerkletreeScans - Whether to skip merkletree syncs and private balance scans. Only set to TRUE in encrypt-only applications that don't load private wallets or balances.\n * @param poiNodeURLs - List of POI aggregator node URLs, in order of priority.\n * @param customPOILists - POI lists to use for additional wallet protections after default lists.\n * @returns\n */\nexport const startDopEngine = async (\n walletSource: string,\n db: AbstractLevelDOWN,\n shouldDebug: boolean,\n artifactStore: ArtifactStore,\n useNativeArtifacts: boolean,\n skipMerkletreeScans: boolean,\n verboseScanLogging = false,\n): Promise<void> => {\n if (hasEngine()) {\n return;\n }\n try {\n setArtifactStore(artifactStore);\n setUseNativeArtifacts(useNativeArtifacts);\n\n const engine = await DopEngine.initForWallet(\n walletSource,\n db,\n artifactGetterDownloadJustInTime,\n quickSyncEventsGraph,\n quickSyncDopTransactionsV2,\n shouldDebug ? createEngineDebugger(verboseScanLogging) : undefined,\n skipMerkletreeScans,\n );\n setEngine(engine);\n\n setOnUTXOScanDecryptBalancesCompleteListener();\n } catch (err) {\n throw reportAndSanitizeError(startDopEngine.name, err);\n }\n};\n\nexport const stopDopEngine = async () => {\n if (!hasEngine()) {\n return;\n }\n await getEngine()?.unload();\n setEngine(undefined);\n};\n\nexport { POIList, POIListType };\n"]}
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../../../src/services/dop/core/init.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AbstractLevelDOWN } from 'abstract-leveldown';\nimport {\n DopEngine,\n EngineEvent,\n MerkletreeHistoryScanEventData,\n POIList,\n POIListType,\n UTXOScanDecryptBalancesCompleteEventData,\n AbstractWallet,\n POIMerklerootsValidator,\n} from 'dop-engine-v3';\nimport {\n MerkletreeScanUpdateEvent,\n MerkletreeScanStatus,\n isDefined,\n type Chain,\n TXIDVersion,\n} from 'dop-sharedmodels-v3';\nimport { sendErrorMessage, sendMessage } from '../../../utils/logger';\nimport {\n artifactGetterDownloadJustInTime,\n setArtifactStore,\n setUseNativeArtifacts,\n} from './artifacts';\nimport { ArtifactStore } from '../../artifacts/artifact-store';\nimport { reportAndSanitizeError } from '../../../utils/error';\nimport { quickSyncEventsGraph } from '../quick-sync/quick-sync-events';\nimport { quickSyncDopTransactionsV2 } from '../dop-txids/dop-txid-sync-graph-v2';\nimport { setEngine, getEngine, hasEngine, setDatabase, getDatabase } from './engine';\nimport { onBalancesUpdate } from '../wallets/balance-update';\n\nexport type EngineDebugger = {\n log: (msg: string) => void;\n error: (error: Error) => void;\n verboseScanLogging: boolean;\n};\n\nconst createEngineDebugger = (verboseScanLogging: boolean): EngineDebugger => {\n return {\n log: (msg: string) => sendMessage(msg),\n error: (error: Error) => sendErrorMessage(error),\n verboseScanLogging,\n };\n};\n\nexport const setOnUTXOMerkletreeScanCallback = (\n onUTXOMerkletreeScanCallback: (scanData: MerkletreeScanUpdateEvent) => void,\n) => {\n const engine = getEngine();\n engine.on(\n EngineEvent.UTXOMerkletreeHistoryScanUpdate,\n ({ chain, scanStatus, progress }: MerkletreeHistoryScanEventData) =>\n onUTXOMerkletreeScanCallback({\n scanStatus,\n chain,\n progress: progress ?? 0.0,\n }),\n );\n};\n\nexport const setOnTXIDMerkletreeScanCallback = (\n onTXIDMerkletreeScanCallback: (scanData: MerkletreeScanUpdateEvent) => void,\n) => {\n const engine = getEngine();\n engine.on(\n EngineEvent.TXIDMerkletreeHistoryScanUpdate,\n ({ chain, scanStatus, progress }: MerkletreeHistoryScanEventData) =>\n onTXIDMerkletreeScanCallback({\n scanStatus,\n chain,\n progress: progress ?? 0.0,\n }),\n );\n};\n\n// Track which chains have completed scans to avoid duplicate emissions\nconst scanCompletedKeys = new Set<string>();\n// Store resolve functions for pending scan completion promises\nconst scanCompletionPromises = new Map<string, () => void>();\n\nconst setOnUTXOMerkletreeScanCompletionListener = () => {\n const engine = getEngine();\n engine.on(\n EngineEvent.UTXOMerkletreeHistoryScanUpdate,\n ({ chain, scanStatus, txidVersion }: MerkletreeHistoryScanEventData) => {\n // Only handle the FIRST \"Complete\" status for this scan\n if (scanStatus === 'Complete') {\n const key = `${txidVersion}-${chain.type}-${chain.id}`;\n \n // If we've already handled completion for this scan, ignore\n if (scanCompletedKeys.has(key)) {\n return;\n }\n \n // Mark this scan as completed\n scanCompletedKeys.add(key);\n \n sendMessage(`πŸ“Š UTXO Merkletree scan completed for ${key}`);\n sendMessage(`πŸ” [TRACE] About to handle completion for ${key}`);\n \n // Emit scan complete event after merkletree finishes\n // This handles case where there are NO new transactions to decrypt\n // (UTXOScanDecryptBalancesComplete won't fire in that case)\n const handleCompletion = async () => {\n sendMessage(`πŸ” [TRACE] Inside handleCompletion for ${key}`);\n \n // Force persistence even if no new balances\n const db = getDatabase();\n sendMessage(`πŸ” [TRACE] Got database: ${isDefined(db) ? 'YES' : 'NO'}`);\n \n if (isDefined(db) && typeof db.forcePersist === 'function') {\n try {\n sendMessage(`πŸ” [TRACE] Calling forcePersist...`);\n await db.forcePersist();\n sendMessage('βœ… Database persisted after merkletree scan completion');\n } catch (error) {\n sendErrorMessage(\n new Error(`Failed to persist database: ${error instanceof Error ? error.message : String(error)}`)\n );\n }\n } else {\n sendMessage(`⚠️ [TRACE] Database or forcePersist not available, skipping persist`);\n }\n \n // Resolve any pending promises waiting for this scan to complete\n const resolveFunc = scanCompletionPromises.get(key);\n if (isDefined(resolveFunc)) {\n sendMessage(`πŸ” [TRACE] Resolving promise for ${key}`);\n resolveFunc();\n scanCompletionPromises.delete(key);\n } else {\n sendMessage(`⚠️ [TRACE] No promise waiting for ${key}`);\n }\n };\n \n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n handleCompletion();\n }\n },\n );\n};\n\nconst setOnUTXOScanDecryptBalancesCompleteListener = () => {\n const engine = getEngine();\n engine.on(\n EngineEvent.UTXOScanDecryptBalancesComplete,\n ({\n txidVersion,\n chain,\n walletIdFilter,\n }: UTXOScanDecryptBalancesCompleteEventData) => {\n const updateWalletBalances = async () => {\n const key = `${txidVersion}-${chain.type}-${chain.id}`;\n sendMessage(`πŸ’° Balance decrypt complete for ${key}, updating wallets...`);\n \n let walletsToUpdate: AbstractWallet[] = Object.values(engine.wallets);\n if (isDefined(walletIdFilter)) {\n walletsToUpdate = walletsToUpdate.filter(wallet =>\n walletIdFilter.includes(wallet.id),\n );\n }\n\n // await onBalancesUpdate calls for each wallet\n await Promise.all(\n walletsToUpdate.map(wallet =>\n onBalancesUpdate(txidVersion, wallet, chain),\n ),\n );\n\n // Force immediate persistence to AsyncStorage/disk after balance updates\n // This ensures balance data is saved before potential app crash/restart\n const db = getDatabase();\n if (isDefined(db) && typeof db.forcePersist === 'function') {\n try {\n await db.forcePersist();\n sendMessage('βœ… Database persisted after balance updates');\n } catch (error) {\n sendErrorMessage(\n new Error(`Failed to persist database after balance update: ${error instanceof Error ? error.message : String(error)}`)\n );\n }\n }\n\n // The scan completion will be triggered by the merkletree Complete status event\n // OR we can resolve the promise here since balance updates are done\n sendMessage(`βœ… Balance updates and persistence complete for ${key}`);\n \n // Resolve promise immediately after balance updates - data is ready!\n const resolveFunc = scanCompletionPromises.get(key);\n if (isDefined(resolveFunc)) {\n sendMessage(`πŸ” [TRACE] Resolving promise after balance updates for ${key}`);\n resolveFunc();\n scanCompletionPromises.delete(key);\n scanCompletedKeys.add(key); // Mark as completed\n }\n };\n\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n updateWalletBalances();\n },\n );\n};\n\n/**\n * Wait for complete scan including balance updates and persistence.\n * This waits for the merkletree scan Complete status AFTER:\n * - Merkletree scanning completes\n * - Balances are decrypted and updated (if any new transactions)\n * - Database is persisted to storage\n * \n * @param chain - The chain to wait for\n * @param txidVersion - The TXID version being scanned\n * @param timeout - Timeout in milliseconds (default: 600000 = 10 minutes)\n * \n * @example\n * ```typescript\n * const engine = getEngine();\n * engine.scanContractHistory(chain, [walletID]);\n * await awaitScanHistoryComplete(chain, TXIDVersion.V3_PoseidonMerkle);\n * // Now ALL data is persisted and ready!\n * ```\n */\nexport const awaitScanHistoryComplete = (\n chain: Chain,\n txidVersion: TXIDVersion,\n timeout = 600000,\n): Promise<void> => {\n const key = `${txidVersion}-${chain.type}-${chain.id}`;\n \n sendMessage(`πŸ” [TRACE] Setting up promise for scan completion: ${key}`);\n \n return new Promise((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n scanCompletionPromises.delete(key);\n reject(new Error(`Scan history completion timeout after ${timeout}ms for chain ${chain.type}:${chain.id}`));\n }, timeout);\n\n // Store the resolve function so the completion listener can call it\n const resolveFunc = () => {\n sendMessage(`πŸŽ‰ [TRACE] Promise resolved for ${key}`);\n clearTimeout(timeoutId);\n resolve();\n };\n \n scanCompletionPromises.set(key, resolveFunc);\n sendMessage(`βœ… [TRACE] Promise registered for ${key}`);\n });\n};\n\n/**\n *\n * @param walletSource - Name for your wallet implementation. Encrypted and viewable in private transaction history. Maximum of 16 characters, lowercase.\n * @param db - LevelDOWN compatible database for storing encrypted wallets.\n * @param shouldDebug - Whether to forward Engine debug logs to Logger.\n * @param artifactStore - Persistent store for downloading large artifact files. See Wallet SDK Developer Guide for platform implementations.\n * @param useNativeArtifacts - Whether to download native C++ or web-assembly artifacts. TRUE for mobile. FALSE for nodejs and browser.\n * @param skipMerkletreeScans - Whether to skip merkletree syncs and private balance scans. Only set to TRUE in encrypt-only applications that don't load private wallets or balances.\n * @param poiNodeURLs - List of POI aggregator node URLs, in order of priority.\n * @param customPOILists - POI lists to use for additional wallet protections after default lists.\n * @returns\n */\nexport const startDopEngine = async (\n walletSource: string,\n db: AbstractLevelDOWN,\n shouldDebug: boolean,\n artifactStore: ArtifactStore,\n useNativeArtifacts: boolean,\n skipMerkletreeScans: boolean,\n verboseScanLogging = false,\n): Promise<void> => {\n if (hasEngine()) {\n return;\n }\n try {\n setArtifactStore(artifactStore);\n setUseNativeArtifacts(useNativeArtifacts);\n\n const engine = await DopEngine.initForWallet(\n walletSource,\n db,\n artifactGetterDownloadJustInTime,\n quickSyncEventsGraph,\n quickSyncDopTransactionsV2,\n shouldDebug ? createEngineDebugger(verboseScanLogging) : undefined,\n skipMerkletreeScans,\n );\n setEngine(engine);\n setDatabase(db); // Store database instance for force persist access\n\n setOnUTXOMerkletreeScanCompletionListener();\n setOnUTXOScanDecryptBalancesCompleteListener();\n } catch (err) {\n throw reportAndSanitizeError(startDopEngine.name, err);\n }\n};\n\nexport const stopDopEngine = async () => {\n if (!hasEngine()) {\n return;\n }\n await getEngine()?.unload();\n setEngine(undefined);\n setDatabase(undefined); // Clear database reference\n scanCompletedKeys.clear(); // Clear completion tracking for next engine start\n};\n\n scanCompletionPromises.clear(); // Clear pending promises\nexport { POIList, POIListType };\n"]}
@@ -3,12 +3,61 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getProver = void 0;
4
4
  const engine_1 = require("./engine");
5
5
  const dop_sharedmodels_v3_1 = require("dop-sharedmodels-v3");
6
+ const custom_prover_1 = require("../crypto/custom-prover");
7
+ /**
8
+ * Determines circuitId from formatted inputs
9
+ * DOP circuits are named like "3x2" (3 nullifiers, 2 commitments)
10
+ */
11
+ function getCircuitIdFromInputs(formattedInputs) {
12
+ // Count nullifiers (non-zero entries)
13
+ const nullifierCount = formattedInputs.nullifiers?.filter((n) => n !== undefined && n !== null && BigInt(n) !== BigInt(0)).length || 0;
14
+ // Count commitments (non-zero entries)
15
+ const commitmentCount = formattedInputs.commitmentsOut?.filter((c) => c !== undefined && c !== null && BigInt(c) !== BigInt(0)).length || 0;
16
+ return `${nullifierCount}x${commitmentCount}`;
17
+ }
18
+ let proverIntercepted = false;
6
19
  const getProver = () => {
7
20
  const engine = (0, engine_1.getEngine)();
8
21
  if (!(0, dop_sharedmodels_v3_1.isDefined)(engine)) {
9
22
  throw new Error('DOP Engine not yet init. Please reload your app or try again.');
10
23
  }
11
- return engine.prover;
24
+ const prover = engine.prover;
25
+ // Intercept groth16.fullProveDop only once
26
+ if (!proverIntercepted && prover.groth16) {
27
+ proverIntercepted = true;
28
+ const originalFullProveDop = prover.groth16.fullProveDop;
29
+ // Wrap fullProveDop to check for custom prover
30
+ prover.groth16.fullProveDop = async (formattedInputs, wasm, zkey, logger, dat, progressCallback) => {
31
+ // Check if custom prover is available
32
+ if ((0, custom_prover_1.hasCustomRapidsnarkProver)()) {
33
+ const customProver = (0, custom_prover_1.getCustomRapidsnarkProver)();
34
+ if (!customProver) {
35
+ throw new Error('Custom prover is null');
36
+ }
37
+ try {
38
+ // Determine circuit ID from inputs
39
+ const circuitId = getCircuitIdFromInputs(formattedInputs);
40
+ logger.debug(`[Custom Prover] Using custom prover for circuit ${circuitId}`);
41
+ // Call custom prover (e.g., backend server)
42
+ const proof = await customProver.generateProof(circuitId, new Uint8Array(zkey), formattedInputs, progressCallback);
43
+ logger.debug(`[Custom Prover] Proof generated successfully via custom prover`);
44
+ // Return in expected format
45
+ return {
46
+ proof,
47
+ publicSignals: proof.publicSignals ?? []
48
+ };
49
+ }
50
+ catch (error) {
51
+ const errorMessage = error instanceof Error ? error.message : String(error);
52
+ logger.debug(`[Custom Prover] Error: ${errorMessage}`);
53
+ throw error;
54
+ }
55
+ }
56
+ // No custom prover - use original implementation
57
+ return originalFullProveDop(formattedInputs, wasm, zkey, logger, dat, progressCallback);
58
+ };
59
+ }
60
+ return prover;
12
61
  };
13
62
  exports.getProver = getProver;
14
63
  //# sourceMappingURL=prover.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"prover.js","sourceRoot":"","sources":["../../../../src/services/dop/core/prover.ts"],"names":[],"mappings":";;;AAMA,qCAAqC;AACrC,6DAAgD;AAEzC,MAAM,SAAS,GAAG,GAAW,EAAE;IACpC,MAAM,MAAM,GAAG,IAAA,kBAAS,GAAE,CAAC;IAC3B,IAAI,CAAC,IAAA,+BAAS,EAAC,MAAM,CAAC,EAAE;QACtB,MAAM,IAAI,KAAK,CACb,+DAA+D,CAChE,CAAC;KACH;IACD,OAAO,MAAM,CAAC,MAAM,CAAC;AACvB,CAAC,CAAC;AARW,QAAA,SAAS,aAQpB","sourcesContent":["import {\n FormattedCircuitInputsDop,\n SnarkJSGroth16,\n Proof,\n Prover,\n} from 'dop-engine-v3';\nimport { getEngine } from './engine';\nimport { isDefined } from 'dop-sharedmodels-v3';\n\nexport const getProver = (): Prover => {\n const engine = getEngine();\n if (!isDefined(engine)) {\n throw new Error(\n 'DOP Engine not yet init. Please reload your app or try again.',\n );\n }\n return engine.prover;\n};\n\nexport { FormattedCircuitInputsDop, Proof, SnarkJSGroth16 };\n"]}
1
+ {"version":3,"file":"prover.js","sourceRoot":"","sources":["../../../../src/services/dop/core/prover.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n FormattedCircuitInputsDop,\n SnarkJSGroth16,\n Proof,\n Prover,\n} from 'dop-engine-v3';\nimport { getEngine } from './engine';\nimport { isDefined } from 'dop-sharedmodels-v3';\nimport { \n hasCustomRapidsnarkProver, \n getCustomRapidsnarkProver \n} from '../crypto/custom-prover';\n\ntype ProverProgressCallback = (progress: number) => void;\n\n/**\n * Determines circuitId from formatted inputs\n * DOP circuits are named like \"3x2\" (3 nullifiers, 2 commitments)\n */\nfunction getCircuitIdFromInputs(formattedInputs: FormattedCircuitInputsDop): string {\n // Count nullifiers (non-zero entries)\n const nullifierCount = formattedInputs.nullifiers?.filter(\n (n: any) => n !== undefined && n !== null && BigInt(n) !== BigInt(0)\n ).length || 0;\n \n // Count commitments (non-zero entries)\n const commitmentCount = formattedInputs.commitmentsOut?.filter(\n (c: any) => c !== undefined && c !== null && BigInt(c) !== BigInt(0)\n ).length || 0;\n \n return `${nullifierCount}x${commitmentCount}`;\n}\n\nlet proverIntercepted = false;\n\nexport const getProver = (): Prover => {\n const engine = getEngine();\n if (!isDefined(engine)) {\n throw new Error(\n 'DOP Engine not yet init. Please reload your app or try again.',\n );\n }\n \n const prover = engine.prover;\n \n // Intercept groth16.fullProveDop only once\n if (!proverIntercepted && prover.groth16) {\n proverIntercepted = true;\n \n const originalFullProveDop = prover.groth16.fullProveDop;\n \n // Wrap fullProveDop to check for custom prover\n prover.groth16.fullProveDop = async (\n formattedInputs: FormattedCircuitInputsDop,\n wasm: any,\n zkey: ArrayLike<number>,\n logger: { debug: (log: string) => void },\n dat: any,\n progressCallback: ProverProgressCallback\n ) => {\n // Check if custom prover is available\n if (hasCustomRapidsnarkProver()) {\n const customProver = getCustomRapidsnarkProver();\n \n if (!customProver) {\n throw new Error('Custom prover is null');\n }\n \n try {\n // Determine circuit ID from inputs\n const circuitId = getCircuitIdFromInputs(formattedInputs);\n \n logger.debug(`[Custom Prover] Using custom prover for circuit ${circuitId}`);\n \n // Call custom prover (e.g., backend server)\n const proof = await customProver.generateProof(\n circuitId,\n new Uint8Array(zkey),\n formattedInputs,\n progressCallback\n );\n \n logger.debug(`[Custom Prover] Proof generated successfully via custom prover`);\n \n // Return in expected format\n return {\n proof,\n publicSignals: (proof as any).publicSignals ?? []\n };\n } catch (error: unknown) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n logger.debug(`[Custom Prover] Error: ${errorMessage}`);\n throw error;\n }\n }\n \n // No custom prover - use original implementation\n return originalFullProveDop(\n formattedInputs,\n wasm,\n zkey,\n logger,\n dat,\n progressCallback\n );\n };\n }\n \n return prover;\n};\n\nexport { FormattedCircuitInputsDop, Proof, SnarkJSGroth16 };\n"]}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Custom Prover Hook
3
+ *
4
+ * Allows applications (especially React Native) to provide their own proof generation
5
+ * implementation, such as a backend server prover instead of local proving.
6
+ */
7
+ import { FormattedCircuitInputsDop, Proof } from 'dop-engine-v3';
8
+ /**
9
+ * Custom prover interface that applications can implement
10
+ *
11
+ * Example: Backend server prover for React Native that offloads
12
+ * heavy ZK proof computation to a remote server
13
+ */
14
+ export interface UserRapidsnarkProver {
15
+ /**
16
+ * Generate a ZK proof for the given circuit and inputs
17
+ *
18
+ * @param circuitId - Circuit identifier (e.g., "3x2" for 3 nullifiers, 2 commitments)
19
+ * @param zkeyBuffer - Circuit zkey file content (may not be needed for backend provers)
20
+ * @param jsonInputs - Formatted circuit inputs (auto-generated by DOP Engine)
21
+ * @param progressCallback - Optional callback for progress updates (0-100)
22
+ * @returns Promise resolving to proof object with pi_a, pi_b, pi_c, and publicSignals
23
+ */
24
+ generateProof(circuitId: string, zkeyBuffer: Uint8Array, jsonInputs: FormattedCircuitInputsDop, progressCallback?: (progress: number) => void): Promise<Proof>;
25
+ }
26
+ /**
27
+ * Set a custom proof generator
28
+ *
29
+ * This allows applications to provide their own proof generation implementation.
30
+ * Common use case: React Native apps using a backend server for proof generation
31
+ * instead of local proving.
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * // Backend prover for React Native
36
+ * const backendProver: UserRapidsnarkProver = {
37
+ * async generateProof(circuitId, zkeyBuffer, jsonInputs, progressCallback) {
38
+ * const response = await fetch('https://your-server.com/api/generate-proof', {
39
+ * method: 'POST',
40
+ * headers: {
41
+ * 'Authorization': 'Bearer YOUR_TOKEN',
42
+ * 'Content-Type': 'application/json',
43
+ * },
44
+ * body: JSON.stringify({
45
+ * circuitId,
46
+ * inputs: jsonInputs,
47
+ * }),
48
+ * });
49
+ *
50
+ * const result = await response.json();
51
+ * return {
52
+ * pi_a: result.proof.pi_a,
53
+ * pi_b: result.proof.pi_b,
54
+ * pi_c: result.proof.pi_c,
55
+ * publicSignals: result.publicSignals,
56
+ * };
57
+ * },
58
+ * };
59
+ *
60
+ * // Set it after DOP Engine initialization
61
+ * setCustomRapidsnarkProver(backendProver);
62
+ * ```
63
+ *
64
+ * @param prover - Custom prover implementation or null to clear
65
+ */
66
+ export declare const setCustomRapidsnarkProver: (prover: UserRapidsnarkProver | null) => void;
67
+ /**
68
+ * Get the currently registered custom prover
69
+ *
70
+ * @returns Custom prover if set, null otherwise
71
+ */
72
+ export declare const getCustomRapidsnarkProver: () => UserRapidsnarkProver | null;
73
+ /**
74
+ * Check if a custom prover is currently registered
75
+ *
76
+ * @returns True if custom prover is set, false otherwise
77
+ */
78
+ export declare const hasCustomRapidsnarkProver: () => boolean;
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ /**
3
+ * Custom Prover Hook
4
+ *
5
+ * Allows applications (especially React Native) to provide their own proof generation
6
+ * implementation, such as a backend server prover instead of local proving.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.hasCustomRapidsnarkProver = exports.getCustomRapidsnarkProver = exports.setCustomRapidsnarkProver = void 0;
10
+ /**
11
+ * Global custom prover storage
12
+ * Set this via setCustomRapidsnarkProver()
13
+ */
14
+ let customProver = null;
15
+ /**
16
+ * Set a custom proof generator
17
+ *
18
+ * This allows applications to provide their own proof generation implementation.
19
+ * Common use case: React Native apps using a backend server for proof generation
20
+ * instead of local proving.
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * // Backend prover for React Native
25
+ * const backendProver: UserRapidsnarkProver = {
26
+ * async generateProof(circuitId, zkeyBuffer, jsonInputs, progressCallback) {
27
+ * const response = await fetch('https://your-server.com/api/generate-proof', {
28
+ * method: 'POST',
29
+ * headers: {
30
+ * 'Authorization': 'Bearer YOUR_TOKEN',
31
+ * 'Content-Type': 'application/json',
32
+ * },
33
+ * body: JSON.stringify({
34
+ * circuitId,
35
+ * inputs: jsonInputs,
36
+ * }),
37
+ * });
38
+ *
39
+ * const result = await response.json();
40
+ * return {
41
+ * pi_a: result.proof.pi_a,
42
+ * pi_b: result.proof.pi_b,
43
+ * pi_c: result.proof.pi_c,
44
+ * publicSignals: result.publicSignals,
45
+ * };
46
+ * },
47
+ * };
48
+ *
49
+ * // Set it after DOP Engine initialization
50
+ * setCustomRapidsnarkProver(backendProver);
51
+ * ```
52
+ *
53
+ * @param prover - Custom prover implementation or null to clear
54
+ */
55
+ const setCustomRapidsnarkProver = (prover) => {
56
+ customProver = prover;
57
+ console.log(prover ? 'βœ… Custom prover registered' : 'πŸ”„ Custom prover cleared');
58
+ };
59
+ exports.setCustomRapidsnarkProver = setCustomRapidsnarkProver;
60
+ /**
61
+ * Get the currently registered custom prover
62
+ *
63
+ * @returns Custom prover if set, null otherwise
64
+ */
65
+ const getCustomRapidsnarkProver = () => {
66
+ return customProver;
67
+ };
68
+ exports.getCustomRapidsnarkProver = getCustomRapidsnarkProver;
69
+ /**
70
+ * Check if a custom prover is currently registered
71
+ *
72
+ * @returns True if custom prover is set, false otherwise
73
+ */
74
+ const hasCustomRapidsnarkProver = () => {
75
+ return customProver !== null;
76
+ };
77
+ exports.hasCustomRapidsnarkProver = hasCustomRapidsnarkProver;
78
+ //# sourceMappingURL=custom-prover.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom-prover.js","sourceRoot":"","sources":["../../../../src/services/dop/crypto/custom-prover.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AA4BH;;;GAGG;AACH,IAAI,YAAY,GAAgC,IAAI,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACI,MAAM,yBAAyB,GAAG,CAAC,MAAmC,EAAQ,EAAE;IACrF,YAAY,GAAG,MAAM,CAAC;IACtB,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC;AAClF,CAAC,CAAC;AAHW,QAAA,yBAAyB,6BAGpC;AAEF;;;;GAIG;AACI,MAAM,yBAAyB,GAAG,GAAgC,EAAE;IACzE,OAAO,YAAY,CAAC;AACtB,CAAC,CAAC;AAFW,QAAA,yBAAyB,6BAEpC;AAEF;;;;GAIG;AACI,MAAM,yBAAyB,GAAG,GAAY,EAAE;IACrD,OAAO,YAAY,KAAK,IAAI,CAAC;AAC/B,CAAC,CAAC;AAFW,QAAA,yBAAyB,6BAEpC","sourcesContent":["/**\n * Custom Prover Hook\n * \n * Allows applications (especially React Native) to provide their own proof generation\n * implementation, such as a backend server prover instead of local proving.\n */\n\nimport { FormattedCircuitInputsDop, Proof } from 'dop-engine-v3';\n\n/**\n * Custom prover interface that applications can implement\n * \n * Example: Backend server prover for React Native that offloads\n * heavy ZK proof computation to a remote server\n */\nexport interface UserRapidsnarkProver {\n /**\n * Generate a ZK proof for the given circuit and inputs\n * \n * @param circuitId - Circuit identifier (e.g., \"3x2\" for 3 nullifiers, 2 commitments)\n * @param zkeyBuffer - Circuit zkey file content (may not be needed for backend provers)\n * @param jsonInputs - Formatted circuit inputs (auto-generated by DOP Engine)\n * @param progressCallback - Optional callback for progress updates (0-100)\n * @returns Promise resolving to proof object with pi_a, pi_b, pi_c, and publicSignals\n */\n generateProof(\n circuitId: string,\n zkeyBuffer: Uint8Array,\n jsonInputs: FormattedCircuitInputsDop,\n progressCallback?: (progress: number) => void\n ): Promise<Proof>;\n}\n\n/**\n * Global custom prover storage\n * Set this via setCustomRapidsnarkProver()\n */\nlet customProver: UserRapidsnarkProver | null = null;\n\n/**\n * Set a custom proof generator\n * \n * This allows applications to provide their own proof generation implementation.\n * Common use case: React Native apps using a backend server for proof generation\n * instead of local proving.\n * \n * @example\n * ```typescript\n * // Backend prover for React Native\n * const backendProver: UserRapidsnarkProver = {\n * async generateProof(circuitId, zkeyBuffer, jsonInputs, progressCallback) {\n * const response = await fetch('https://your-server.com/api/generate-proof', {\n * method: 'POST',\n * headers: {\n * 'Authorization': 'Bearer YOUR_TOKEN',\n * 'Content-Type': 'application/json',\n * },\n * body: JSON.stringify({\n * circuitId,\n * inputs: jsonInputs,\n * }),\n * });\n * \n * const result = await response.json();\n * return {\n * pi_a: result.proof.pi_a,\n * pi_b: result.proof.pi_b,\n * pi_c: result.proof.pi_c,\n * publicSignals: result.publicSignals,\n * };\n * },\n * };\n * \n * // Set it after DOP Engine initialization\n * setCustomRapidsnarkProver(backendProver);\n * ```\n * \n * @param prover - Custom prover implementation or null to clear\n */\nexport const setCustomRapidsnarkProver = (prover: UserRapidsnarkProver | null): void => {\n customProver = prover;\n console.log(prover ? 'βœ… Custom prover registered' : 'πŸ”„ Custom prover cleared');\n};\n\n/**\n * Get the currently registered custom prover\n * \n * @returns Custom prover if set, null otherwise\n */\nexport const getCustomRapidsnarkProver = (): UserRapidsnarkProver | null => {\n return customProver;\n};\n\n/**\n * Check if a custom prover is currently registered\n * \n * @returns True if custom prover is set, false otherwise\n */\nexport const hasCustomRapidsnarkProver = (): boolean => {\n return customProver !== null;\n};\n"]}
@@ -0,0 +1 @@
1
+ export * from './custom-prover';
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./custom-prover"), exports);
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/services/dop/crypto/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,kDAAgC","sourcesContent":["export * from './custom-prover';\n"]}
@@ -4,3 +4,4 @@ export * from './dop-txids';
4
4
  export * from './wallets';
5
5
  export * from './process';
6
6
  export * from './profile';
7
+ export * from './crypto';
@@ -20,4 +20,5 @@ __exportStar(require("./dop-txids"), exports);
20
20
  __exportStar(require("./wallets"), exports);
21
21
  __exportStar(require("./process"), exports);
22
22
  __exportStar(require("./profile"), exports);
23
+ __exportStar(require("./crypto"), exports);
23
24
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/services/dop/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yCAAuB;AACvB,yCAAuB;AACvB,8CAA4B;AAC5B,4CAA0B;AAC1B,4CAA0B;AAC1B,4CAA0B","sourcesContent":["export * from './core';\nexport * from './util';\nexport * from './dop-txids';\nexport * from './wallets';\nexport * from './process';\nexport * from './profile';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/services/dop/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yCAAuB;AACvB,yCAAuB;AACvB,8CAA4B;AAC5B,4CAA0B;AAC1B,4CAA0B;AAC1B,4CAA0B;AAC1B,2CAAyB","sourcesContent":["export * from './core';\nexport * from './util';\nexport * from './dop-txids';\nexport * from './wallets';\nexport * from './process';\nexport * from './profile';\nexport * from './crypto';\n"]}
@@ -21,13 +21,11 @@ const refreshBalances = async (chain, walletIdFilter) => {
21
21
  return;
22
22
  }
23
23
  try {
24
- // Wallet will trigger .emit('scanned', {chain}) event when finished,
25
- // which calls `onBalancesUpdate` (balance-update.ts).
26
- // Kick off a background merkletree scan.
27
- // This will call wallet.scanBalances when it's done, but may take some time.
28
24
  console.log(`πŸ”„ Starting new scan for chain ${chainKey}...`);
29
25
  const engine = (0, engine_1.getEngine)();
30
- // Create the scan promise and store it
26
+ // scanContractHistory triggers the scan and returns immediately
27
+ // The actual completion is signaled via EngineEvent.UTXOScanDecryptBalancesComplete
28
+ // which then triggers balance updates and database persistence
31
29
  const scanPromise = engine.scanContractHistory(chain, walletIdFilter);
32
30
  ongoingScans.set(chainKey, scanPromise);
33
31
  // Wait for the scan to complete
@@ -57,14 +55,12 @@ const rescanFullUTXOMerkletreesAndWallets = async (chain, walletIdFilter) => {
57
55
  try {
58
56
  console.log(`πŸ”„ Starting full rescan for chain ${chainKey}...`);
59
57
  const engine = (0, engine_1.getEngine)();
60
- // Create the rescan promise and store it
58
+ // Start the rescan (this returns immediately, doesn't wait for completion)
61
59
  const rescanPromise = engine.fullRescanUTXOMerkletreesAndWallets(chain, walletIdFilter);
62
60
  ongoingScans.set(chainKey, rescanPromise);
63
61
  // Wait for the rescan to complete
64
62
  await rescanPromise;
65
63
  console.log(`βœ… Full rescan completed successfully for chain ${chainKey}`);
66
- // Wallet will trigger .emit('scanned', {chain}) event when finished,
67
- // which calls `onBalancesUpdate` (balance-update.ts).
68
64
  }
69
65
  catch (err) {
70
66
  console.error(`❌ Full rescan failed for chain ${chainKey}:`, err);
@@ -1 +1 @@
1
- {"version":3,"file":"balances.js","sourceRoot":"","sources":["../../../../src/services/dop/wallets/balances.ts"],"names":[],"mappings":"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","sourcesContent":["import { Chain } from 'dop-engine-v3';\nimport { TXIDVersion } from 'dop-sharedmodels-v3';\nimport { reportAndSanitizeError } from '../../../utils/error';\nimport { getEngine } from '../core/engine';\n\n// Track ongoing scans per chain to prevent concurrent scanning\nconst ongoingScans = new Map<string, Promise<void>>();\n\n// Helper to create unique chain key\nconst getChainKey = (chain: Chain): string => {\n return `${chain.type}:${chain.id}`;\n};\n\nexport const refreshBalances = async (\n chain: Chain,\n walletIdFilter: Optional<string[]>,\n): Promise<void> => {\n const chainKey = getChainKey(chain);\n \n // Check if a scan is already in progress for this chain\n const existingScan = ongoingScans.get(chainKey);\n if (existingScan) {\n console.log(`⏸️ Scan already in progress for chain ${chainKey}, waiting for it to complete...`);\n // Wait for the existing scan to complete instead of starting a new one\n await existingScan;\n console.log(`βœ… Existing scan completed for chain ${chainKey}`);\n return;\n }\n\n try {\n // Wallet will trigger .emit('scanned', {chain}) event when finished,\n // which calls `onBalancesUpdate` (balance-update.ts).\n\n // Kick off a background merkletree scan.\n // This will call wallet.scanBalances when it's done, but may take some time.\n\n console.log(`πŸ”„ Starting new scan for chain ${chainKey}...`);\n const engine = getEngine();\n \n // Create the scan promise and store it\n const scanPromise = engine.scanContractHistory(chain, walletIdFilter);\n ongoingScans.set(chainKey, scanPromise);\n \n // Wait for the scan to complete\n await scanPromise;\n \n console.log(`βœ… Scan completed successfully for chain ${chainKey}`);\n } catch (err) {\n console.error(`❌ Scan failed for chain ${chainKey}:`, err);\n throw reportAndSanitizeError(refreshBalances.name, err);\n } finally {\n // Always remove the scan from tracking when done (success or failure)\n ongoingScans.delete(chainKey);\n }\n};\n\nexport const rescanFullUTXOMerkletreesAndWallets = async (\n chain: Chain,\n walletIdFilter: Optional<string[]>,\n): Promise<void> => {\n const chainKey = getChainKey(chain);\n \n // Check if a scan is already in progress for this chain\n const existingScan = ongoingScans.get(chainKey);\n if (existingScan) {\n console.log(`⏸️ Full rescan already in progress for chain ${chainKey}, waiting for it to complete...`);\n await existingScan;\n console.log(`βœ… Existing full rescan completed for chain ${chainKey}`);\n return;\n }\n\n try {\n console.log(`πŸ”„ Starting full rescan for chain ${chainKey}...`);\n const engine = getEngine();\n \n // Create the rescan promise and store it\n const rescanPromise = engine.fullRescanUTXOMerkletreesAndWallets(chain, walletIdFilter);\n ongoingScans.set(chainKey, rescanPromise);\n \n // Wait for the rescan to complete\n await rescanPromise;\n\n console.log(`βœ… Full rescan completed successfully for chain ${chainKey}`);\n \n // Wallet will trigger .emit('scanned', {chain}) event when finished,\n // which calls `onBalancesUpdate` (balance-update.ts).\n } catch (err) {\n console.error(`❌ Full rescan failed for chain ${chainKey}:`, err);\n throw reportAndSanitizeError(rescanFullUTXOMerkletreesAndWallets.name, err);\n } finally {\n // Always remove the rescan from tracking when done\n ongoingScans.delete(chainKey);\n }\n};\n\nexport const resetFullTXIDMerkletreesV2 = async (\n chain: Chain,\n): Promise<void> => {\n try {\n const engine = getEngine();\n await engine.fullResetTXIDMerkletreesV2(chain);\n } catch (err) {\n throw reportAndSanitizeError(resetFullTXIDMerkletreesV2.name, err);\n }\n};\n"]}
1
+ {"version":3,"file":"balances.js","sourceRoot":"","sources":["../../../../src/services/dop/wallets/balances.ts"],"names":[],"mappings":"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","sourcesContent":["import { Chain } from 'dop-engine-v3';\nimport { TXIDVersion } from 'dop-sharedmodels-v3';\nimport { reportAndSanitizeError } from '../../../utils/error';\nimport { getEngine } from '../core/engine';\n\n// Track ongoing scans per chain to prevent concurrent scanning\nconst ongoingScans = new Map<string, Promise<void>>();\n\n// Helper to create unique chain key\nconst getChainKey = (chain: Chain): string => {\n return `${chain.type}:${chain.id}`;\n};\n\nexport const refreshBalances = async (\n chain: Chain,\n walletIdFilter: Optional<string[]>,\n): Promise<void> => {\n const chainKey = getChainKey(chain);\n \n // Check if a scan is already in progress for this chain\n const existingScan = ongoingScans.get(chainKey);\n if (existingScan) {\n console.log(`⏸️ Scan already in progress for chain ${chainKey}, waiting for it to complete...`);\n // Wait for the existing scan to complete instead of starting a new one\n await existingScan;\n console.log(`βœ… Existing scan completed for chain ${chainKey}`);\n return;\n }\n\n try {\n console.log(`πŸ”„ Starting new scan for chain ${chainKey}...`);\n const engine = getEngine();\n \n // scanContractHistory triggers the scan and returns immediately\n // The actual completion is signaled via EngineEvent.UTXOScanDecryptBalancesComplete\n // which then triggers balance updates and database persistence\n const scanPromise = engine.scanContractHistory(chain, walletIdFilter);\n ongoingScans.set(chainKey, scanPromise);\n \n // Wait for the scan to complete\n await scanPromise;\n \n console.log(`βœ… Scan completed successfully for chain ${chainKey}`);\n } catch (err) {\n console.error(`❌ Scan failed for chain ${chainKey}:`, err);\n throw reportAndSanitizeError(refreshBalances.name, err);\n } finally {\n // Always remove the scan from tracking when done (success or failure)\n ongoingScans.delete(chainKey);\n }\n};\n\nexport const rescanFullUTXOMerkletreesAndWallets = async (\n chain: Chain,\n walletIdFilter: Optional<string[]>,\n): Promise<void> => {\n const chainKey = getChainKey(chain);\n \n // Check if a scan is already in progress for this chain\n const existingScan = ongoingScans.get(chainKey);\n if (existingScan) {\n console.log(`⏸️ Full rescan already in progress for chain ${chainKey}, waiting for it to complete...`);\n await existingScan;\n console.log(`βœ… Existing full rescan completed for chain ${chainKey}`);\n return;\n }\n\n try {\n console.log(`πŸ”„ Starting full rescan for chain ${chainKey}...`);\n const engine = getEngine();\n \n // Start the rescan (this returns immediately, doesn't wait for completion)\n const rescanPromise = engine.fullRescanUTXOMerkletreesAndWallets(chain, walletIdFilter);\n \n ongoingScans.set(chainKey, rescanPromise);\n \n // Wait for the rescan to complete\n await rescanPromise;\n\n console.log(`βœ… Full rescan completed successfully for chain ${chainKey}`);\n } catch (err) {\n console.error(`❌ Full rescan failed for chain ${chainKey}:`, err);\n throw reportAndSanitizeError(rescanFullUTXOMerkletreesAndWallets.name, err);\n } finally {\n // Always remove the rescan from tracking when done\n ongoingScans.delete(chainKey);\n }\n};\n\nexport const resetFullTXIDMerkletreesV2 = async (\n chain: Chain,\n): Promise<void> => {\n try {\n const engine = getEngine();\n await engine.fullResetTXIDMerkletreesV2(chain);\n } catch (err) {\n throw reportAndSanitizeError(resetFullTXIDMerkletreesV2.name, err);\n }\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dop-wallet-v6",
3
- "version": "1.3.35",
3
+ "version": "1.3.37",
4
4
  "description": "DOP Wallet SDK, compatible with mobile, browser and nodejs environments.",
5
5
  "main": "dist/index.js",
6
6
  "license": "MIT",