dop-wallet-v6 1.3.36 β†’ 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"]}
@@ -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.36",
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",