@cloak.ag/sdk 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -34,13 +34,14 @@ __export(index_exports, {
34
34
  CloakError: () => CloakError,
35
35
  CloakSDK: () => CloakSDK,
36
36
  DepositRecoveryService: () => DepositRecoveryService,
37
+ EXPECTED_CIRCUIT_HASHES: () => EXPECTED_CIRCUIT_HASHES,
37
38
  FIXED_FEE_LAMPORTS: () => FIXED_FEE_LAMPORTS,
38
39
  IndexerService: () => IndexerService,
39
40
  LAMPORTS_PER_SOL: () => LAMPORTS_PER_SOL,
40
41
  LocalStorageAdapter: () => LocalStorageAdapter,
41
42
  MemoryStorageAdapter: () => MemoryStorageAdapter,
42
- ProverService: () => ProverService,
43
43
  RelayService: () => RelayService,
44
+ ShieldPoolErrors: () => ShieldPoolErrors,
44
45
  VARIABLE_FEE_RATE: () => VARIABLE_FEE_RATE,
45
46
  VERSION: () => VERSION,
46
47
  bigintToBytes32: () => bigintToBytes32,
@@ -48,6 +49,9 @@ __export(index_exports, {
48
49
  bytesToHex: () => bytesToHex,
49
50
  calculateFee: () => calculateFee2,
50
51
  calculateRelayFee: () => calculateRelayFee,
52
+ cleanupStalePendingOperations: () => cleanupStalePendingOperations,
53
+ clearPendingDeposits: () => clearPendingDeposits,
54
+ clearPendingWithdrawals: () => clearPendingWithdrawals,
51
55
  computeCommitment: () => computeCommitment,
52
56
  computeMerkleRoot: () => computeMerkleRoot,
53
57
  computeNullifier: () => computeNullifier,
@@ -87,12 +91,14 @@ __export(index_exports, {
87
91
  getAddressExplorerUrl: () => getAddressExplorerUrl,
88
92
  getDistributableAmount: () => getDistributableAmount2,
89
93
  getExplorerUrl: () => getExplorerUrl,
94
+ getPendingOperationsSummary: () => getPendingOperationsSummary,
90
95
  getPublicKey: () => getPublicKey,
91
96
  getPublicViewKey: () => getPublicViewKey,
92
97
  getRecipientAmount: () => getRecipientAmount,
93
98
  getRpcUrlForNetwork: () => getRpcUrlForNetwork,
94
99
  getShieldPoolPDAs: () => getShieldPoolPDAs,
95
100
  getViewKey: () => getViewKey,
101
+ hasPendingOperations: () => hasPendingOperations,
96
102
  hexToBigint: () => hexToBigint,
97
103
  hexToBytes: () => hexToBytes,
98
104
  importKeys: () => importKeys,
@@ -102,7 +108,10 @@ __export(index_exports, {
102
108
  isValidSolanaAddress: () => isValidSolanaAddress,
103
109
  isWithdrawable: () => isWithdrawable,
104
110
  keypairToAdapter: () => keypairToAdapter,
111
+ loadPendingDeposits: () => loadPendingDeposits,
112
+ loadPendingWithdrawals: () => loadPendingWithdrawals,
105
113
  parseAmount: () => parseAmount,
114
+ parseError: () => parseError,
106
115
  parseNote: () => parseNote,
107
116
  parseTransactionError: () => parseTransactionError,
108
117
  poseidonHash: () => poseidonHash,
@@ -111,6 +120,10 @@ __export(index_exports, {
111
120
  proofToBytes: () => proofToBytes,
112
121
  pubkeyToLimbs: () => pubkeyToLimbs,
113
122
  randomBytes: () => randomBytes,
123
+ removePendingDeposit: () => removePendingDeposit,
124
+ removePendingWithdrawal: () => removePendingWithdrawal,
125
+ savePendingDeposit: () => savePendingDeposit,
126
+ savePendingWithdrawal: () => savePendingWithdrawal,
114
127
  scanNotesForWallet: () => scanNotesForWallet,
115
128
  sendTransaction: () => sendTransaction,
116
129
  serializeNote: () => serializeNote,
@@ -118,12 +131,16 @@ __export(index_exports, {
118
131
  splitTo2Limbs: () => splitTo2Limbs,
119
132
  tryDecryptNote: () => tryDecryptNote,
120
133
  updateNoteWithDeposit: () => updateNoteWithDeposit,
134
+ updatePendingDeposit: () => updatePendingDeposit,
135
+ updatePendingWithdrawal: () => updatePendingWithdrawal,
121
136
  validateDepositParams: () => validateDepositParams,
122
137
  validateNote: () => validateNote,
123
138
  validateOutputsSum: () => validateOutputsSum,
124
139
  validateTransfers: () => validateTransfers,
125
140
  validateWalletConnected: () => validateWalletConnected,
126
- validateWithdrawableNote: () => validateWithdrawableNote
141
+ validateWithdrawableNote: () => validateWithdrawableNote,
142
+ verifyAllCircuits: () => verifyAllCircuits,
143
+ verifyCircuitIntegrity: () => verifyCircuitIntegrity
127
144
  });
128
145
  module.exports = __toCommonJS(index_exports);
129
146
 
@@ -290,14 +307,14 @@ function randomBytes(length) {
290
307
  } catch {
291
308
  }
292
309
  try {
293
- const nodeCrypto = require("crypto");
294
- if (nodeCrypto?.randomBytes) {
295
- const buffer = nodeCrypto.randomBytes(length);
310
+ const nodeCrypto2 = require("crypto");
311
+ if (nodeCrypto2?.randomBytes) {
312
+ const buffer = nodeCrypto2.randomBytes(length);
296
313
  bytes.set(buffer);
297
314
  return bytes;
298
315
  }
299
- if (nodeCrypto?.webcrypto?.getRandomValues) {
300
- nodeCrypto.webcrypto.getRandomValues(bytes);
316
+ if (nodeCrypto2?.webcrypto?.getRandomValues) {
317
+ nodeCrypto2.webcrypto.getRandomValues(bytes);
301
318
  return bytes;
302
319
  }
303
320
  } catch {
@@ -419,8 +436,8 @@ function generateMasterSeed() {
419
436
  cryptoObj.getRandomValues(seed);
420
437
  } else {
421
438
  try {
422
- const nodeCrypto = require("crypto");
423
- const buffer = nodeCrypto.randomBytes(32);
439
+ const nodeCrypto2 = require("crypto");
440
+ const buffer = nodeCrypto2.randomBytes(32);
424
441
  seed.set(buffer);
425
442
  } catch {
426
443
  throw new Error("No secure random number generator available");
@@ -1161,6 +1178,8 @@ var RelayService = class {
1161
1178
  *
1162
1179
  * @param params - Withdrawal parameters
1163
1180
  * @param onStatusUpdate - Optional callback for status updates
1181
+ * @param onRequestId - CRITICAL: Callback when request_id is received.
1182
+ * Persist this ID to recover if browser crashes during polling.
1164
1183
  * @returns Transaction signature when completed
1165
1184
  *
1166
1185
  * @example
@@ -1170,11 +1189,12 @@ var RelayService = class {
1170
1189
  * publicInputs: { root, nf, outputs_hash, amount },
1171
1190
  * outputs: [{ recipient: addr, amount: lamports }],
1172
1191
  * feeBps: 50
1173
- * }, (status) => console.log(`Status: ${status}`));
1192
+ * }, (status) => console.log(`Status: ${status}`),
1193
+ * (requestId) => localStorage.setItem('pending_withdraw', requestId));
1174
1194
  * console.log(`Transaction: ${signature}`);
1175
1195
  * ```
1176
1196
  */
1177
- async submitWithdraw(params, onStatusUpdate) {
1197
+ async submitWithdraw(params, onStatusUpdate, onRequestId) {
1178
1198
  const proofBytes = hexToBytes(params.proof);
1179
1199
  const proofBase64 = this.bytesToBase64(proofBytes);
1180
1200
  const requestBody = {
@@ -1215,8 +1235,55 @@ var RelayService = class {
1215
1235
  if (!requestId) {
1216
1236
  throw new Error("Relay response missing request_id");
1217
1237
  }
1238
+ if (onRequestId) {
1239
+ onRequestId(requestId);
1240
+ }
1218
1241
  return this.pollForCompletion(requestId, onStatusUpdate);
1219
1242
  }
1243
+ /**
1244
+ * Resume polling for a withdrawal that was previously started
1245
+ *
1246
+ * Use this after page reload to check status of a pending withdrawal.
1247
+ * The requestId should have been persisted via the onRequestId callback.
1248
+ *
1249
+ * @param requestId - Request ID from a previous submitWithdraw call
1250
+ * @param onStatusUpdate - Optional callback for status updates
1251
+ * @returns Transaction signature if completed, null if still pending/failed
1252
+ *
1253
+ * @example
1254
+ * ```typescript
1255
+ * // On page load, check for pending withdrawal
1256
+ * const pendingId = localStorage.getItem('pending_withdraw');
1257
+ * if (pendingId) {
1258
+ * const result = await relay.resumeWithdraw(pendingId);
1259
+ * if (result.status === 'completed') {
1260
+ * console.log('Withdrawal completed:', result.signature);
1261
+ * localStorage.removeItem('pending_withdraw');
1262
+ * }
1263
+ * }
1264
+ * ```
1265
+ */
1266
+ async resumeWithdraw(requestId, onStatusUpdate) {
1267
+ try {
1268
+ const status = await this.getStatus(requestId);
1269
+ if (onStatusUpdate) {
1270
+ onStatusUpdate(status.status);
1271
+ }
1272
+ if (status.status === "completed") {
1273
+ return { status: "completed", signature: status.txId };
1274
+ } else if (status.status === "failed") {
1275
+ return { status: "failed", error: status.error };
1276
+ } else {
1277
+ const signature = await this.pollForCompletion(requestId, onStatusUpdate);
1278
+ return { status: "completed", signature };
1279
+ }
1280
+ } catch (error) {
1281
+ return {
1282
+ status: "failed",
1283
+ error: error instanceof Error ? error.message : String(error)
1284
+ };
1285
+ }
1286
+ }
1220
1287
  /**
1221
1288
  * Poll for withdrawal completion
1222
1289
  *
@@ -1289,7 +1356,7 @@ var RelayService = class {
1289
1356
  * console.log(`Transaction: ${signature}`);
1290
1357
  * ```
1291
1358
  */
1292
- async submitSwap(params, onStatusUpdate) {
1359
+ async submitSwap(params, onStatusUpdate, onRequestId) {
1293
1360
  const proofBytes = hexToBytes(params.proof);
1294
1361
  const proofBase64 = this.bytesToBase64(proofBytes);
1295
1362
  const requestBody = {
@@ -1331,6 +1398,9 @@ var RelayService = class {
1331
1398
  if (!requestId) {
1332
1399
  throw new Error("Relay response missing request_id");
1333
1400
  }
1401
+ if (onRequestId) {
1402
+ onRequestId(requestId);
1403
+ }
1334
1404
  return this.pollForCompletion(requestId, onStatusUpdate);
1335
1405
  }
1336
1406
  /**
@@ -1567,29 +1637,94 @@ var DepositRecoveryService = class {
1567
1637
  }
1568
1638
  /**
1569
1639
  * Check if a deposit already exists in the indexer
1640
+ * Uses the enhanced deposit lookup endpoint with include_proof=true
1570
1641
  *
1571
1642
  * @private
1572
1643
  */
1573
- async checkExistingDeposit(_commitment) {
1644
+ async checkExistingDeposit(commitment) {
1574
1645
  try {
1575
- const { next_index } = await this.indexer.getMerkleRoot();
1576
- const batchSize = 100;
1577
- for (let i = 0; i < next_index; i += batchSize) {
1578
- const end = Math.min(i + batchSize - 1, next_index - 1);
1579
- const { notes } = await this.indexer.getNotesRange(i, end, batchSize);
1580
- for (let j = 0; j < notes.length; j++) {
1581
- try {
1582
- return null;
1583
- } catch (e) {
1584
- continue;
1585
- }
1646
+ const cleanCommit = commitment.replace(/^0x/, "").toLowerCase();
1647
+ const response = await fetch(
1648
+ `${this.apiUrl}/api/v1/deposit/${cleanCommit}?include_proof=true`
1649
+ );
1650
+ if (!response.ok) {
1651
+ if (response.status === 404) {
1652
+ return null;
1586
1653
  }
1654
+ throw new Error(`Failed to check deposit: ${response.status}`);
1587
1655
  }
1588
- return null;
1656
+ const data = await response.json();
1657
+ if (!data.merkle_proof) {
1658
+ const merkleProof = await this.indexer.getMerkleProof(data.leaf_index);
1659
+ return {
1660
+ leafIndex: data.leaf_index,
1661
+ root: merkleProof.root || "",
1662
+ slot: data.slot,
1663
+ merkleProof: {
1664
+ pathElements: merkleProof.pathElements,
1665
+ pathIndices: merkleProof.pathIndices
1666
+ }
1667
+ };
1668
+ }
1669
+ return {
1670
+ leafIndex: data.leaf_index,
1671
+ root: data.merkle_proof.root,
1672
+ slot: data.slot,
1673
+ merkleProof: {
1674
+ pathElements: data.merkle_proof.path_elements,
1675
+ pathIndices: data.merkle_proof.path_indices
1676
+ }
1677
+ };
1589
1678
  } catch (error) {
1590
1679
  return null;
1591
1680
  }
1592
1681
  }
1682
+ /**
1683
+ * Recover deposit by transaction signature
1684
+ * Uses the indexer's signature lookup endpoint
1685
+ */
1686
+ async recoverBySignature(signature) {
1687
+ try {
1688
+ const response = await fetch(
1689
+ `${this.apiUrl}/api/v1/deposit/tx/${signature}?include_proof=true`
1690
+ );
1691
+ if (!response.ok) {
1692
+ if (response.status === 404) {
1693
+ return {
1694
+ success: false,
1695
+ error: "Deposit not found for this transaction signature"
1696
+ };
1697
+ }
1698
+ const errorText = await response.text();
1699
+ return {
1700
+ success: false,
1701
+ error: `Failed to recover deposit: ${errorText}`
1702
+ };
1703
+ }
1704
+ const data = await response.json();
1705
+ if (!data.merkle_proof) {
1706
+ return {
1707
+ success: false,
1708
+ error: "Deposit found but merkle proof not available"
1709
+ };
1710
+ }
1711
+ return {
1712
+ success: true,
1713
+ leafIndex: data.leaf_index,
1714
+ root: data.merkle_proof.root,
1715
+ slot: data.slot,
1716
+ merkleProof: {
1717
+ pathElements: data.merkle_proof.path_elements,
1718
+ pathIndices: data.merkle_proof.path_indices
1719
+ }
1720
+ };
1721
+ } catch (error) {
1722
+ return {
1723
+ success: false,
1724
+ error: error instanceof Error ? error.message : String(error)
1725
+ };
1726
+ }
1727
+ }
1593
1728
  /**
1594
1729
  * Finalize a deposit via server API (alternative recovery method)
1595
1730
  *
@@ -1745,39 +1880,15 @@ function getShieldPoolPDAs(programId, mint) {
1745
1880
 
1746
1881
  // src/utils/proof-generation.ts
1747
1882
  var snarkjs = __toESM(require("snarkjs"), 1);
1748
- var path = null;
1749
- var fs = null;
1750
- async function loadNodeModules() {
1751
- const isBrowser = typeof window !== "undefined" || typeof globalThis !== "undefined" && globalThis.window;
1752
- if (!isBrowser && typeof process !== "undefined" && process.versions?.node) {
1753
- if (!path) {
1754
- path = await import("path");
1755
- }
1756
- if (!fs) {
1757
- fs = await import("fs");
1758
- }
1759
- return { path, fs };
1760
- }
1761
- return { path: null, fs: null };
1762
- }
1883
+ var IS_BROWSER = typeof window !== "undefined" || typeof globalThis !== "undefined" && typeof globalThis.document !== "undefined";
1763
1884
  function joinPath(...parts) {
1764
- const isBrowser = typeof window !== "undefined" || typeof globalThis !== "undefined" && globalThis.window;
1765
- if (!isBrowser && path) {
1766
- return path.join(...parts);
1885
+ if (IS_BROWSER) {
1886
+ return parts.join("/").replace(/\/+/g, "/");
1767
1887
  }
1768
1888
  return parts.join("/").replace(/\/+/g, "/");
1769
1889
  }
1770
1890
  async function fileExists(filePath) {
1771
- const { fs: fs2 } = await loadNodeModules();
1772
- if (fs2) {
1773
- try {
1774
- return fs2.existsSync(filePath);
1775
- } catch {
1776
- return false;
1777
- }
1778
- }
1779
- const isBrowser = typeof window !== "undefined" || typeof globalThis !== "undefined" && globalThis.window;
1780
- if (isBrowser) {
1891
+ if (IS_BROWSER) {
1781
1892
  try {
1782
1893
  const response = await fetch(filePath, { method: "HEAD" });
1783
1894
  return response.ok;
@@ -1785,18 +1896,26 @@ async function fileExists(filePath) {
1785
1896
  return false;
1786
1897
  }
1787
1898
  }
1788
- return false;
1899
+ try {
1900
+ const nodeFs2 = globalThis.require?.("fs") || (typeof require !== "undefined" ? require("fs") : null);
1901
+ if (nodeFs2) {
1902
+ return nodeFs2.existsSync(filePath);
1903
+ }
1904
+ const fsModule = await import("fs");
1905
+ return fsModule.existsSync(filePath);
1906
+ } catch {
1907
+ return false;
1908
+ }
1789
1909
  }
1790
- async function generateWithdrawRegularProof(inputs, circuitsPath) {
1791
- const isBrowser = typeof window !== "undefined" || typeof globalThis !== "undefined" && globalThis.window;
1910
+ async function generateWithdrawRegularProof(inputs, circuitsPath2) {
1792
1911
  let wasmPath;
1793
1912
  let zkeyPath;
1794
- if (isBrowser) {
1795
- wasmPath = `${circuitsPath}/withdraw_regular_js/withdraw_regular.wasm`;
1796
- zkeyPath = `${circuitsPath}/withdraw_regular_final.zkey`;
1913
+ if (IS_BROWSER) {
1914
+ wasmPath = `${circuitsPath2}/withdraw_regular_js/withdraw_regular.wasm`;
1915
+ zkeyPath = `${circuitsPath2}/withdraw_regular_final.zkey`;
1797
1916
  } else {
1798
- wasmPath = joinPath(circuitsPath, "build", "withdraw_regular_js", "withdraw_regular.wasm");
1799
- zkeyPath = joinPath(circuitsPath, "build", "withdraw_regular_final.zkey");
1917
+ wasmPath = joinPath(circuitsPath2, "build", "withdraw_regular_js", "withdraw_regular.wasm");
1918
+ zkeyPath = joinPath(circuitsPath2, "build", "withdraw_regular_final.zkey");
1800
1919
  const wasmExists = await fileExists(wasmPath);
1801
1920
  const zkeyExists = await fileExists(zkeyPath);
1802
1921
  if (!wasmExists) {
@@ -1828,11 +1947,7 @@ async function generateWithdrawRegularProof(inputs, circuitsPath) {
1828
1947
  var_fee: inputs.var_fee.toString(),
1829
1948
  rem: inputs.rem.toString()
1830
1949
  };
1831
- const { proof, publicSignals } = await snarkjs.groth16.fullProve(
1832
- circuitInputs,
1833
- wasmPath,
1834
- zkeyPath
1835
- );
1950
+ const { proof, publicSignals } = await snarkjs.groth16.fullProve(circuitInputs, wasmPath, zkeyPath);
1836
1951
  const proofBytes = proofToBytes(proof);
1837
1952
  return {
1838
1953
  proof,
@@ -1842,16 +1957,15 @@ async function generateWithdrawRegularProof(inputs, circuitsPath) {
1842
1957
  // Not used, kept for compatibility
1843
1958
  };
1844
1959
  }
1845
- async function generateWithdrawSwapProof(inputs, circuitsPath) {
1846
- const isBrowser = typeof window !== "undefined" || typeof globalThis !== "undefined" && globalThis.window;
1960
+ async function generateWithdrawSwapProof(inputs, circuitsPath2) {
1847
1961
  let wasmPath;
1848
1962
  let zkeyPath;
1849
- if (isBrowser) {
1850
- wasmPath = `${circuitsPath}/withdraw_swap_js/withdraw_swap.wasm`;
1851
- zkeyPath = `${circuitsPath}/withdraw_swap_final.zkey`;
1963
+ if (IS_BROWSER) {
1964
+ wasmPath = `${circuitsPath2}/withdraw_swap_js/withdraw_swap.wasm`;
1965
+ zkeyPath = `${circuitsPath2}/withdraw_swap_final.zkey`;
1852
1966
  } else {
1853
- wasmPath = joinPath(circuitsPath, "build", "withdraw_swap_js", "withdraw_swap.wasm");
1854
- zkeyPath = joinPath(circuitsPath, "build", "withdraw_swap_final.zkey");
1967
+ wasmPath = joinPath(circuitsPath2, "build", "withdraw_swap_js", "withdraw_swap.wasm");
1968
+ zkeyPath = joinPath(circuitsPath2, "build", "withdraw_swap_final.zkey");
1855
1969
  const wasmExists = await fileExists(wasmPath);
1856
1970
  const zkeyExists = await fileExists(zkeyPath);
1857
1971
  if (!wasmExists) {
@@ -1900,32 +2014,35 @@ async function generateWithdrawSwapProof(inputs, circuitsPath) {
1900
2014
  // Not used, kept for compatibility
1901
2015
  };
1902
2016
  }
1903
- async function areCircuitsAvailable(circuitsPath) {
1904
- const isBrowser = typeof window !== "undefined" || typeof globalThis !== "undefined" && globalThis.window;
1905
- if (isBrowser) {
1906
- return Boolean(circuitsPath && circuitsPath !== "");
2017
+ async function areCircuitsAvailable(circuitsPath2) {
2018
+ if (IS_BROWSER) {
2019
+ return Boolean(circuitsPath2 && circuitsPath2 !== "");
1907
2020
  }
1908
- const wasmPath = joinPath(circuitsPath, "build", "withdraw_regular_js", "withdraw_regular.wasm");
1909
- const zkeyPath = joinPath(circuitsPath, "build", "withdraw_regular_final.zkey");
2021
+ const wasmPath = joinPath(circuitsPath2, "build", "withdraw_regular_js", "withdraw_regular.wasm");
2022
+ const zkeyPath = joinPath(circuitsPath2, "build", "withdraw_regular_final.zkey");
1910
2023
  const wasmExists = await fileExists(wasmPath);
1911
2024
  const zkeyExists = await fileExists(zkeyPath);
1912
2025
  return wasmExists && zkeyExists;
1913
2026
  }
1914
2027
  async function getDefaultCircuitsPath() {
1915
- const isBrowser = typeof window !== "undefined" || typeof globalThis !== "undefined" && globalThis.window;
1916
- if (isBrowser) {
2028
+ if (IS_BROWSER) {
2029
+ return "/circuits";
2030
+ }
2031
+ if (typeof process === "undefined" || !process.cwd) {
1917
2032
  return "/circuits";
1918
2033
  }
1919
- const { path: path2 } = await loadNodeModules();
1920
- if (!path2 || typeof process === "undefined" || !process.cwd) {
2034
+ let nodePath;
2035
+ try {
2036
+ nodePath = eval("require")("path");
2037
+ } catch {
1921
2038
  return "/circuits";
1922
2039
  }
1923
2040
  const possiblePaths = [
1924
- path2.resolve(process.cwd(), "../../packages-new/circuits"),
1925
- path2.resolve(process.cwd(), "../packages-new/circuits"),
1926
- path2.resolve(process.cwd(), "packages-new/circuits"),
1927
- path2.resolve(process.cwd(), "../../circuits"),
1928
- path2.resolve(process.cwd(), "../circuits")
2041
+ nodePath.resolve(process.cwd(), "../../packages-new/circuits"),
2042
+ nodePath.resolve(process.cwd(), "../packages-new/circuits"),
2043
+ nodePath.resolve(process.cwd(), "packages-new/circuits"),
2044
+ nodePath.resolve(process.cwd(), "../../circuits"),
2045
+ nodePath.resolve(process.cwd(), "../circuits")
1929
2046
  ];
1930
2047
  for (const p of possiblePaths) {
1931
2048
  if (await areCircuitsAvailable(p)) {
@@ -1934,6 +2051,90 @@ async function getDefaultCircuitsPath() {
1934
2051
  }
1935
2052
  return possiblePaths[0];
1936
2053
  }
2054
+ var EXPECTED_CIRCUIT_HASHES = {
2055
+ // SHA-256 of the verification key JSON from withdraw_regular circuit
2056
+ withdraw_regular_vkey: null,
2057
+ // Set to null to skip check during development
2058
+ // SHA-256 of the verification key JSON from withdraw_swap circuit
2059
+ withdraw_swap_vkey: null
2060
+ // Set to null to skip check during development
2061
+ };
2062
+ async function verifyCircuitIntegrity(circuitsPath, circuit) {
2063
+ const expectedHash = circuit === "withdraw_regular" ? EXPECTED_CIRCUIT_HASHES.withdraw_regular_vkey : EXPECTED_CIRCUIT_HASHES.withdraw_swap_vkey;
2064
+ if (!expectedHash) {
2065
+ return {
2066
+ valid: true,
2067
+ circuit,
2068
+ error: "Verification skipped (no expected hash configured)"
2069
+ };
2070
+ }
2071
+ try {
2072
+ const vkeyPath = IS_BROWSER ? `${circuitsPath}/${circuit}_verification_key.json` : joinPath(circuitsPath, "build", `${circuit}_verification_key.json`);
2073
+ let vkeyData;
2074
+ if (IS_BROWSER) {
2075
+ const response = await fetch(vkeyPath);
2076
+ if (!response.ok) {
2077
+ return {
2078
+ valid: false,
2079
+ circuit,
2080
+ error: `Failed to fetch verification key: ${response.status}`
2081
+ };
2082
+ }
2083
+ vkeyData = await response.text();
2084
+ } else {
2085
+ try {
2086
+ const nodeFs = eval("require")("fs");
2087
+ vkeyData = nodeFs.readFileSync(vkeyPath, "utf8");
2088
+ } catch (e) {
2089
+ return {
2090
+ valid: false,
2091
+ circuit,
2092
+ error: `Failed to read verification key: ${e}`
2093
+ };
2094
+ }
2095
+ }
2096
+ let computedHash;
2097
+ if (IS_BROWSER) {
2098
+ const encoder = new TextEncoder();
2099
+ const data = encoder.encode(vkeyData);
2100
+ const hashBuffer = await crypto.subtle.digest("SHA-256", data);
2101
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
2102
+ computedHash = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
2103
+ } else {
2104
+ const nodeCrypto = eval("require")("crypto");
2105
+ computedHash = nodeCrypto.createHash("sha256").update(vkeyData).digest("hex");
2106
+ }
2107
+ if (computedHash === expectedHash) {
2108
+ return {
2109
+ valid: true,
2110
+ circuit,
2111
+ computedHash,
2112
+ expectedHash
2113
+ };
2114
+ } else {
2115
+ return {
2116
+ valid: false,
2117
+ circuit,
2118
+ error: `Verification key hash mismatch! This circuit may produce invalid proofs.`,
2119
+ computedHash,
2120
+ expectedHash
2121
+ };
2122
+ }
2123
+ } catch (error) {
2124
+ return {
2125
+ valid: false,
2126
+ circuit,
2127
+ error: `Circuit verification failed: ${error instanceof Error ? error.message : String(error)}`
2128
+ };
2129
+ }
2130
+ }
2131
+ async function verifyAllCircuits(circuitsPath2) {
2132
+ const results = await Promise.all([
2133
+ verifyCircuitIntegrity(circuitsPath2, "withdraw_regular"),
2134
+ verifyCircuitIntegrity(circuitsPath2, "withdraw_swap")
2135
+ ]);
2136
+ return results;
2137
+ }
1937
2138
 
1938
2139
  // src/core/CloakSDK.ts
1939
2140
  var CLOAK_PROGRAM_ID = new import_web35.PublicKey("c1oak6tetxYnNfvXKFkpn1d98FxtK7B68vBQLYQpWKp");
@@ -2048,14 +2249,35 @@ var CloakSDK = class {
2048
2249
  async deposit(connection, amountOrNote, options) {
2049
2250
  try {
2050
2251
  let note;
2252
+ let isNewNote = false;
2051
2253
  if (typeof amountOrNote === "number") {
2254
+ options?.onProgress?.("generating_note", { message: "Generating note with secrets..." });
2052
2255
  note = await generateNote(amountOrNote, this.config.network);
2256
+ isNewNote = true;
2053
2257
  } else {
2054
2258
  note = amountOrNote;
2055
2259
  if (note.depositSignature) {
2056
2260
  throw new Error("Note has already been deposited");
2057
2261
  }
2058
2262
  }
2263
+ if (isNewNote) {
2264
+ await this.storage.saveNote(note);
2265
+ if (options?.onNoteGenerated) {
2266
+ options?.onProgress?.("awaiting_note_acknowledgment", {
2267
+ message: "Waiting for note to be saved before proceeding with deposit..."
2268
+ });
2269
+ try {
2270
+ await options.onNoteGenerated(note);
2271
+ } catch (error) {
2272
+ throw new Error(
2273
+ `Failed to save note before deposit: ${error instanceof Error ? error.message : String(error)}. For your safety, the deposit has been aborted. Your funds are safe.`
2274
+ );
2275
+ }
2276
+ }
2277
+ options?.onProgress?.("note_saved", {
2278
+ message: "Note saved. Proceeding with on-chain deposit..."
2279
+ });
2280
+ }
2059
2281
  const payerPubkey = this.getPublicKey();
2060
2282
  const balance = await connection.getBalance(payerPubkey);
2061
2283
  const requiredAmount = note.amount + 5e3;
@@ -2247,6 +2469,16 @@ var CloakSDK = class {
2247
2469
  pathIndices: merkleProof.pathIndices
2248
2470
  }
2249
2471
  });
2472
+ await this.storage.updateNote(note.commitment, {
2473
+ depositSignature: signature,
2474
+ depositSlot,
2475
+ leafIndex,
2476
+ root,
2477
+ merkleProof: {
2478
+ pathElements: merkleProof.pathElements,
2479
+ pathIndices: merkleProof.pathIndices
2480
+ }
2481
+ });
2250
2482
  return {
2251
2483
  note: updatedNote,
2252
2484
  signature,
@@ -2308,17 +2540,10 @@ var CloakSDK = class {
2308
2540
  const feeBps = Math.ceil(protocolFee * 1e4 / note.amount);
2309
2541
  const distributableAmount = getDistributableAmount2(note.amount);
2310
2542
  validateTransfers(recipients, distributableAmount);
2311
- let merkleProof;
2312
- let merkleRoot;
2313
- if (note.merkleProof && note.root) {
2314
- merkleProof = {
2315
- pathElements: note.merkleProof.pathElements,
2316
- pathIndices: note.merkleProof.pathIndices
2317
- };
2318
- merkleRoot = note.root;
2319
- } else {
2320
- merkleProof = await this.indexer.getMerkleProof(note.leafIndex);
2321
- merkleRoot = merkleProof.root || (await this.indexer.getMerkleRoot()).root;
2543
+ const merkleProof = await this.indexer.getMerkleProof(note.leafIndex);
2544
+ const merkleRoot = merkleProof.root || (await this.indexer.getMerkleRoot()).root;
2545
+ if (!merkleRoot) {
2546
+ throw new Error("Failed to get Merkle root from indexer");
2322
2547
  }
2323
2548
  const nullifier = await computeNullifierAsync(note.sk_spend, note.leafIndex);
2324
2549
  const nullifierHex = nullifier.toString(16).padStart(64, "0");
@@ -2355,8 +2580,8 @@ var CloakSDK = class {
2355
2580
  }
2356
2581
  }
2357
2582
  const isBrowser = typeof window !== "undefined" || typeof globalThis !== "undefined" && globalThis.window;
2358
- const circuitsPath = isBrowser ? "/circuits" : typeof process !== "undefined" && process.env?.CIRCUITS_PATH || await getDefaultCircuitsPath();
2359
- const useDirectProof = await areCircuitsAvailable(circuitsPath);
2583
+ const circuitsPath2 = isBrowser ? "/circuits" : typeof process !== "undefined" && process.env?.CIRCUITS_PATH || await getDefaultCircuitsPath();
2584
+ const useDirectProof = await areCircuitsAvailable(circuitsPath2);
2360
2585
  let proofHex;
2361
2586
  let finalPublicInputs;
2362
2587
  if (useDirectProof) {
@@ -2392,6 +2617,13 @@ var CloakSDK = class {
2392
2617
  }
2393
2618
  const sk = splitTo2Limbs(sk_spend_bigint);
2394
2619
  const r = splitTo2Limbs(r_bigint);
2620
+ const computedCommitment = await computeCommitment(amount_bigint, r_bigint, sk_spend_bigint);
2621
+ const noteCommitment = BigInt("0x" + note.commitment);
2622
+ if (computedCommitment !== noteCommitment) {
2623
+ throw new Error(
2624
+ `Commitment mismatch! Computed: ${computedCommitment.toString(16)}, Note: ${note.commitment}. This means the note's sk_spend, r, or amount doesn't match what was deposited.`
2625
+ );
2626
+ }
2395
2627
  const proofInputs = {
2396
2628
  root: root_bigint,
2397
2629
  nullifier: nullifier_bigint,
@@ -2410,7 +2642,9 @@ var CloakSDK = class {
2410
2642
  var_fee: varFee,
2411
2643
  rem
2412
2644
  };
2413
- const proofResult = await generateWithdrawRegularProof(proofInputs, circuitsPath);
2645
+ options?.onProgress?.("proof_generating");
2646
+ const proofResult = await generateWithdrawRegularProof(proofInputs, circuitsPath2);
2647
+ options?.onProgress?.("proof_complete");
2414
2648
  proofHex = Buffer.from(proofResult.proofBytes).toString("hex");
2415
2649
  finalPublicInputs = {
2416
2650
  root: merkleRoot,
@@ -2420,7 +2654,7 @@ var CloakSDK = class {
2420
2654
  };
2421
2655
  } else {
2422
2656
  throw new Error(
2423
- `Circuits not available at ${circuitsPath}. Make sure circuits are built and accessible. In browser, circuits should be served from /circuits. In Node.js, set CIRCUITS_PATH environment variable or ensure circuits are in the expected location.`
2657
+ `Circuits not available at ${circuitsPath2}. Make sure circuits are built and accessible. In browser, circuits should be served from /circuits. In Node.js, set CIRCUITS_PATH environment variable or ensure circuits are in the expected location.`
2424
2658
  );
2425
2659
  }
2426
2660
  const signature = await this.relay.submitWithdraw(
@@ -2576,30 +2810,27 @@ var CloakSDK = class {
2576
2810
  );
2577
2811
  }
2578
2812
  let recipientAta;
2579
- try {
2580
- const splTokenModule = await import("@solana/spl-token");
2581
- const getAssociatedTokenAddress = splTokenModule.getAssociatedTokenAddress;
2582
- if (!getAssociatedTokenAddress) {
2583
- throw new Error("getAssociatedTokenAddress not found");
2813
+ if (options.recipientAta) {
2814
+ recipientAta = new import_web35.PublicKey(options.recipientAta);
2815
+ } else {
2816
+ try {
2817
+ const splTokenModule = await import("@solana/spl-token");
2818
+ const getAssociatedTokenAddress = splTokenModule.getAssociatedTokenAddress;
2819
+ if (!getAssociatedTokenAddress) {
2820
+ throw new Error("getAssociatedTokenAddress not found");
2821
+ }
2822
+ const outputMint2 = new import_web35.PublicKey(options.outputMint);
2823
+ recipientAta = await getAssociatedTokenAddress(outputMint2, recipient);
2824
+ } catch (error) {
2825
+ throw new Error(
2826
+ `Failed to get associated token account: ${error instanceof Error ? error.message : String(error)}. Please install @solana/spl-token or provide recipientAta in options.`
2827
+ );
2584
2828
  }
2585
- const outputMint2 = new import_web35.PublicKey(options.outputMint);
2586
- recipientAta = await getAssociatedTokenAddress(outputMint2, recipient);
2587
- } catch (error) {
2588
- throw new Error(
2589
- `Failed to get associated token account: ${error instanceof Error ? error.message : String(error)}. Please install @solana/spl-token or provide recipientAta in options.`
2590
- );
2591
2829
  }
2592
- let merkleProof;
2593
- let merkleRoot;
2594
- if (note.merkleProof && note.root) {
2595
- merkleProof = {
2596
- pathElements: note.merkleProof.pathElements,
2597
- pathIndices: note.merkleProof.pathIndices
2598
- };
2599
- merkleRoot = note.root;
2600
- } else {
2601
- merkleProof = await this.indexer.getMerkleProof(note.leafIndex);
2602
- merkleRoot = merkleProof.root || (await this.indexer.getMerkleRoot()).root;
2830
+ const merkleProof = await this.indexer.getMerkleProof(note.leafIndex);
2831
+ const merkleRoot = merkleProof.root || (await this.indexer.getMerkleRoot()).root;
2832
+ if (!merkleRoot) {
2833
+ throw new Error("Failed to get Merkle root from indexer");
2603
2834
  }
2604
2835
  const nullifier = await computeNullifierAsync(note.sk_spend, note.leafIndex);
2605
2836
  const nullifierHex = nullifier.toString(16).padStart(64, "0");
@@ -2620,8 +2851,8 @@ var CloakSDK = class {
2620
2851
  throw new Error("Merkle proof is invalid: missing path elements");
2621
2852
  }
2622
2853
  const envCircuitsPath = typeof window !== "undefined" ? typeof process !== "undefined" && process.env?.NEXT_PUBLIC_CIRCUITS_PATH || void 0 : typeof process !== "undefined" && process.env?.CIRCUITS_PATH || void 0;
2623
- const circuitsPath = envCircuitsPath || await getDefaultCircuitsPath();
2624
- const useDirectProof = await areCircuitsAvailable(circuitsPath);
2854
+ const circuitsPath2 = envCircuitsPath || await getDefaultCircuitsPath();
2855
+ const useDirectProof = await areCircuitsAvailable(circuitsPath2);
2625
2856
  let proofHex;
2626
2857
  let finalPublicInputs;
2627
2858
  if (useDirectProof) {
@@ -2635,6 +2866,13 @@ var CloakSDK = class {
2635
2866
  const inputMintLimbs = pubkeyToLimbs(inputMint.toBytes());
2636
2867
  const outputMintLimbs = pubkeyToLimbs(outputMint.toBytes());
2637
2868
  const recipientAtaLimbs = pubkeyToLimbs(recipientAta.toBytes());
2869
+ const computedCommitment = await computeCommitment(amount_bigint, r_bigint, sk_spend_bigint);
2870
+ const noteCommitment = BigInt("0x" + note.commitment);
2871
+ if (computedCommitment !== noteCommitment) {
2872
+ throw new Error(
2873
+ `Commitment mismatch! Computed: ${computedCommitment.toString(16)}, Note: ${note.commitment}. This means the note's sk_spend, r, or amount doesn't match what was deposited.`
2874
+ );
2875
+ }
2638
2876
  const t = amount_bigint * 5n;
2639
2877
  const varFee = t / 1000n;
2640
2878
  const rem = t % 1000n;
@@ -2656,7 +2894,9 @@ var CloakSDK = class {
2656
2894
  var_fee: varFee,
2657
2895
  rem
2658
2896
  };
2659
- const proofResult = await generateWithdrawSwapProof(proofInputs, circuitsPath);
2897
+ options?.onProgress?.("proof_generating");
2898
+ const proofResult = await generateWithdrawSwapProof(proofInputs, circuitsPath2);
2899
+ options?.onProgress?.("proof_complete");
2660
2900
  proofHex = Buffer.from(proofResult.proofBytes).toString("hex");
2661
2901
  finalPublicInputs = {
2662
2902
  root: merkleRoot,
@@ -2666,7 +2906,7 @@ var CloakSDK = class {
2666
2906
  };
2667
2907
  } else {
2668
2908
  throw new Error(
2669
- `Circuits not available at ${circuitsPath}. Make sure circuits are built and accessible. In browser, circuits should be served from /circuits. In Node.js, set CIRCUITS_PATH environment variable or ensure circuits are in the expected location.`
2909
+ `Circuits not available at ${circuitsPath2}. Make sure circuits are built and accessible. In browser, circuits should be served from /circuits. In Node.js, set CIRCUITS_PATH environment variable or ensure circuits are in the expected location.`
2670
2910
  );
2671
2911
  }
2672
2912
  const signature = await this.relay.submitSwap(
@@ -3041,6 +3281,63 @@ async function copyNoteToClipboard(note) {
3041
3281
  }
3042
3282
 
3043
3283
  // src/utils/errors.ts
3284
+ var ShieldPoolErrors = {
3285
+ // Root management errors
3286
+ 4096: "Invalid Merkle root",
3287
+ 4097: "Root not found in the roots ring",
3288
+ 4098: "Roots ring is full",
3289
+ // Proof verification errors
3290
+ 4112: "Zero-knowledge proof is invalid",
3291
+ 4113: "Invalid proof size (expected 260 bytes)",
3292
+ 4114: "Invalid public inputs",
3293
+ 4115: "Verification key mismatch",
3294
+ // Nullifier errors
3295
+ 4128: "Double spend detected - this note has already been spent",
3296
+ 4129: "Nullifier shard is full",
3297
+ 4130: "Invalid nullifier",
3298
+ // Transaction validation errors
3299
+ 4144: "Output addresses or amounts don't match the proof",
3300
+ 4145: "Amount conservation failed - outputs + fee must equal input amount",
3301
+ 4146: "Invalid outputs hash",
3302
+ 4147: "Invalid amount (must be greater than zero)",
3303
+ 4148: "Invalid recipient address",
3304
+ 4149: "Commitment already exists in the tree",
3305
+ 4150: "Commitment log is full",
3306
+ // Math errors
3307
+ 4160: "Math overflow occurred",
3308
+ 4161: "Division by zero",
3309
+ // Account errors
3310
+ 4176: "Account validation failed - please check your wallet balance and try again",
3311
+ 4177: "Pool account owner mismatch",
3312
+ 4178: "Treasury account owner mismatch",
3313
+ 4179: "Roots ring account owner mismatch",
3314
+ 4180: "Nullifier shard account owner mismatch",
3315
+ 4181: "Pool account is not writable",
3316
+ 4182: "Treasury account is not writable",
3317
+ 4183: "Recipient account is not writable",
3318
+ 4184: "Insufficient lamports in pool or account",
3319
+ 4185: "Invalid account owner",
3320
+ 4186: "Invalid account size",
3321
+ 4187: "Commitments account is not writable",
3322
+ 4188: "Invalid admin authority",
3323
+ // Instruction errors
3324
+ 4192: "Invalid instruction data length",
3325
+ 4193: "Invalid instruction data format",
3326
+ 4194: "Missing required accounts",
3327
+ 4195: "Invalid instruction tag",
3328
+ // PoW/Scrambler errors
3329
+ 4196: "Invalid miner account",
3330
+ 4197: "Invalid claim account",
3331
+ 4198: "Failed to consume claim",
3332
+ // Groth16 verifier errors
3333
+ 4208: "Invalid G1 point length",
3334
+ 4209: "Invalid G2 point length",
3335
+ 4210: "Invalid public inputs length",
3336
+ 4211: "Public input exceeds field size",
3337
+ 4212: "G1 multiplication failed during proof preparation",
3338
+ 4213: "G1 addition failed during proof preparation",
3339
+ 4214: "Proof verification failed"
3340
+ };
3044
3341
  var PROGRAM_ERRORS = {
3045
3342
  // Nullifier errors
3046
3343
  "NullifierAlreadyUsed": "This note has already been withdrawn. Each note can only be spent once.",
@@ -3069,6 +3366,438 @@ var PROGRAM_ERRORS = {
3069
3366
  "AccountNotFound": "Required account not found.",
3070
3367
  "InvalidInstruction": "Invalid instruction data."
3071
3368
  };
3369
+ var ErrorPatterns = [
3370
+ // Wallet/User action errors
3371
+ {
3372
+ patterns: [
3373
+ "User rejected",
3374
+ "user rejected",
3375
+ "User denied",
3376
+ "user denied",
3377
+ "Transaction cancelled",
3378
+ "Transaction rejected",
3379
+ /code.*4001/i
3380
+ ],
3381
+ result: {
3382
+ title: "Transaction Cancelled",
3383
+ message: "You cancelled the transaction.",
3384
+ category: "wallet",
3385
+ recoverable: true
3386
+ }
3387
+ },
3388
+ {
3389
+ patterns: [
3390
+ "Wallet not connected",
3391
+ "wallet not connected",
3392
+ "Please connect wallet",
3393
+ "No wallet connected"
3394
+ ],
3395
+ result: {
3396
+ title: "Wallet Not Connected",
3397
+ message: "Please connect your wallet to continue.",
3398
+ category: "wallet",
3399
+ suggestion: "Click the wallet button to connect.",
3400
+ recoverable: true
3401
+ }
3402
+ },
3403
+ {
3404
+ patterns: [
3405
+ "SDK not initialized",
3406
+ "sdk not initialized"
3407
+ ],
3408
+ result: {
3409
+ title: "Wallet Connection Required",
3410
+ message: "Your wallet connection was interrupted.",
3411
+ category: "wallet",
3412
+ suggestion: "Please reconnect your wallet and try again.",
3413
+ recoverable: true
3414
+ }
3415
+ },
3416
+ {
3417
+ patterns: [
3418
+ "Wallet does not support signing",
3419
+ "signTransaction"
3420
+ ],
3421
+ result: {
3422
+ title: "Wallet Feature Not Supported",
3423
+ message: "Your wallet doesn't support the required signing method.",
3424
+ category: "wallet",
3425
+ suggestion: "Try using a different wallet like Phantom or Solflare.",
3426
+ recoverable: true
3427
+ }
3428
+ },
3429
+ // Balance errors
3430
+ {
3431
+ patterns: [
3432
+ "insufficient lamports",
3433
+ "Insufficient lamports",
3434
+ "insufficient balance",
3435
+ "Insufficient balance",
3436
+ "Insufficient SOL",
3437
+ "not enough SOL",
3438
+ "Attempt to debit an account but found no record",
3439
+ /0x1$/
3440
+ ],
3441
+ result: {
3442
+ title: "Insufficient Balance",
3443
+ message: "You don't have enough SOL for this transaction.",
3444
+ category: "validation",
3445
+ suggestion: "Add more SOL to your wallet or reduce the amount.",
3446
+ recoverable: true
3447
+ }
3448
+ },
3449
+ {
3450
+ patterns: [
3451
+ "Insufficient funds",
3452
+ "insufficient funds"
3453
+ ],
3454
+ result: {
3455
+ title: "Insufficient Funds",
3456
+ message: "Your wallet doesn't have enough funds for this transaction.",
3457
+ category: "validation",
3458
+ suggestion: "Add more funds to your wallet and try again.",
3459
+ recoverable: true
3460
+ }
3461
+ },
3462
+ // Network errors
3463
+ {
3464
+ patterns: [
3465
+ "fetch failed",
3466
+ "Failed to fetch",
3467
+ "Network error",
3468
+ "network error",
3469
+ "ECONNREFUSED",
3470
+ "ETIMEDOUT",
3471
+ "ENOTFOUND",
3472
+ "NetworkError",
3473
+ "net::ERR",
3474
+ "Failed to load"
3475
+ ],
3476
+ result: {
3477
+ title: "Connection Error",
3478
+ message: "Unable to connect to the network.",
3479
+ category: "network",
3480
+ suggestion: "Check your internet connection and try again.",
3481
+ recoverable: true
3482
+ }
3483
+ },
3484
+ {
3485
+ patterns: [
3486
+ "timeout",
3487
+ "Timeout",
3488
+ "TIMEOUT",
3489
+ "timed out",
3490
+ "Timed out"
3491
+ ],
3492
+ result: {
3493
+ title: "Request Timed Out",
3494
+ message: "The request took too long to complete.",
3495
+ category: "network",
3496
+ suggestion: "The network may be congested. Please try again in a moment.",
3497
+ recoverable: true
3498
+ }
3499
+ },
3500
+ {
3501
+ patterns: [
3502
+ "blockhash not found",
3503
+ "Blockhash not found",
3504
+ "block height exceeded"
3505
+ ],
3506
+ result: {
3507
+ title: "Transaction Expired",
3508
+ message: "The transaction took too long and expired.",
3509
+ category: "network",
3510
+ suggestion: "Please try again. If this persists, the network may be congested.",
3511
+ recoverable: true
3512
+ }
3513
+ },
3514
+ // Service errors (Indexer/Relay)
3515
+ {
3516
+ patterns: [
3517
+ "Indexer",
3518
+ "indexer",
3519
+ /indexer.*unavailable/i,
3520
+ /failed.*indexer/i
3521
+ ],
3522
+ result: {
3523
+ title: "Service Temporarily Unavailable",
3524
+ message: "The privacy service is temporarily unavailable.",
3525
+ category: "service",
3526
+ suggestion: "Please wait a moment and try again.",
3527
+ recoverable: true
3528
+ }
3529
+ },
3530
+ {
3531
+ patterns: [
3532
+ "Relay",
3533
+ "relay",
3534
+ /relay.*unavailable/i,
3535
+ /failed.*relay/i,
3536
+ "failed to submit",
3537
+ "Failed to submit"
3538
+ ],
3539
+ result: {
3540
+ title: "Processing Service Busy",
3541
+ message: "The transaction processing service is busy.",
3542
+ category: "service",
3543
+ suggestion: "Please wait a moment and try again.",
3544
+ recoverable: true
3545
+ }
3546
+ },
3547
+ {
3548
+ patterns: [
3549
+ "429",
3550
+ "Too Many Requests",
3551
+ "rate limit",
3552
+ "Rate limit"
3553
+ ],
3554
+ result: {
3555
+ title: "Too Many Requests",
3556
+ message: "You're making requests too quickly.",
3557
+ category: "service",
3558
+ suggestion: "Please wait a moment before trying again.",
3559
+ recoverable: true
3560
+ }
3561
+ },
3562
+ {
3563
+ patterns: [
3564
+ "503",
3565
+ "Service Unavailable",
3566
+ "502",
3567
+ "Bad Gateway"
3568
+ ],
3569
+ result: {
3570
+ title: "Service Temporarily Unavailable",
3571
+ message: "Our servers are temporarily unavailable.",
3572
+ category: "service",
3573
+ suggestion: "Please try again in a few minutes.",
3574
+ recoverable: true
3575
+ }
3576
+ },
3577
+ // Proof/ZK errors
3578
+ {
3579
+ patterns: [
3580
+ "Circuits not available",
3581
+ "circuits not available",
3582
+ "Failed to load circuit",
3583
+ "WASM",
3584
+ "wasm",
3585
+ /circuit.*not.*found/i
3586
+ ],
3587
+ result: {
3588
+ title: "Loading Error",
3589
+ message: "Failed to load required cryptographic components.",
3590
+ category: "service",
3591
+ suggestion: "Try refreshing the page. If the problem persists, clear your browser cache.",
3592
+ recoverable: true
3593
+ }
3594
+ },
3595
+ {
3596
+ patterns: [
3597
+ "proof generation",
3598
+ "Proof generation",
3599
+ "Failed to generate proof",
3600
+ "proving error"
3601
+ ],
3602
+ result: {
3603
+ title: "Proof Generation Failed",
3604
+ message: "Failed to generate the privacy proof.",
3605
+ category: "service",
3606
+ suggestion: "Try again with a smaller amount or refresh the page.",
3607
+ recoverable: true
3608
+ }
3609
+ },
3610
+ // Validation errors
3611
+ {
3612
+ patterns: [
3613
+ "Invalid amount",
3614
+ "invalid amount",
3615
+ "Amount must be",
3616
+ "amount must be",
3617
+ "Amount too small"
3618
+ ],
3619
+ result: {
3620
+ title: "Invalid Amount",
3621
+ message: "The amount you entered is not valid.",
3622
+ category: "validation",
3623
+ suggestion: "Enter an amount greater than the minimum required.",
3624
+ recoverable: true
3625
+ }
3626
+ },
3627
+ {
3628
+ patterns: [
3629
+ "Invalid recipient",
3630
+ "invalid recipient",
3631
+ "Invalid address",
3632
+ "invalid address",
3633
+ "Invalid Solana address"
3634
+ ],
3635
+ result: {
3636
+ title: "Invalid Address",
3637
+ message: "The recipient address is not valid.",
3638
+ category: "validation",
3639
+ suggestion: "Check the address and make sure it's a valid Solana address.",
3640
+ recoverable: true
3641
+ }
3642
+ },
3643
+ {
3644
+ patterns: [
3645
+ "Invalid token",
3646
+ "invalid token",
3647
+ "Unsupported token"
3648
+ ],
3649
+ result: {
3650
+ title: "Unsupported Token",
3651
+ message: "This token is not supported.",
3652
+ category: "validation",
3653
+ suggestion: "Select a supported token and try again.",
3654
+ recoverable: true
3655
+ }
3656
+ },
3657
+ // Swap errors
3658
+ {
3659
+ patterns: [
3660
+ "Failed to get quote",
3661
+ "failed to get quote",
3662
+ "No route found",
3663
+ "no route found",
3664
+ "Insufficient liquidity",
3665
+ "insufficient liquidity"
3666
+ ],
3667
+ result: {
3668
+ title: "Swap Quote Unavailable",
3669
+ message: "Unable to get a price quote for this swap.",
3670
+ category: "service",
3671
+ suggestion: "Try a different amount or wait for better liquidity.",
3672
+ recoverable: true
3673
+ }
3674
+ },
3675
+ {
3676
+ patterns: [
3677
+ "Slippage",
3678
+ "slippage",
3679
+ "Price impact",
3680
+ "price impact"
3681
+ ],
3682
+ result: {
3683
+ title: "Price Changed",
3684
+ message: "The price changed too much during the transaction.",
3685
+ category: "transaction",
3686
+ suggestion: "Try again or increase your slippage tolerance.",
3687
+ recoverable: true
3688
+ }
3689
+ },
3690
+ // Transaction errors
3691
+ {
3692
+ patterns: [
3693
+ "Double spend",
3694
+ "double spend",
3695
+ "already been spent",
3696
+ "already spent"
3697
+ ],
3698
+ result: {
3699
+ title: "Already Spent",
3700
+ message: "This note has already been used.",
3701
+ category: "transaction",
3702
+ suggestion: "This funds have already been withdrawn.",
3703
+ recoverable: false
3704
+ }
3705
+ },
3706
+ {
3707
+ patterns: [
3708
+ "simulation failed",
3709
+ "Simulation failed",
3710
+ "Transaction simulation"
3711
+ ],
3712
+ result: {
3713
+ title: "Transaction Failed",
3714
+ message: "The transaction could not be completed.",
3715
+ category: "transaction",
3716
+ suggestion: "Please try again. If the problem persists, check your balance.",
3717
+ recoverable: true
3718
+ }
3719
+ },
3720
+ {
3721
+ patterns: [
3722
+ "confirmation timeout",
3723
+ "Confirmation timeout",
3724
+ "not confirmed"
3725
+ ],
3726
+ result: {
3727
+ title: "Confirmation Pending",
3728
+ message: "Transaction confirmation is taking longer than expected.",
3729
+ category: "network",
3730
+ suggestion: "Your transaction may still complete. Check your wallet or try again.",
3731
+ recoverable: true
3732
+ }
3733
+ }
3734
+ ];
3735
+ function parseError(error) {
3736
+ let errorMessage = "";
3737
+ let originalError = "";
3738
+ if (error instanceof Error) {
3739
+ errorMessage = error.message;
3740
+ originalError = error.stack || error.message;
3741
+ } else if (typeof error === "string") {
3742
+ errorMessage = error;
3743
+ originalError = error;
3744
+ } else if (error && typeof error === "object") {
3745
+ const err = error;
3746
+ errorMessage = String(err.message || err.error || err.msg || JSON.stringify(error));
3747
+ originalError = JSON.stringify(error);
3748
+ } else {
3749
+ errorMessage = String(error);
3750
+ originalError = String(error);
3751
+ }
3752
+ for (const { patterns, result } of ErrorPatterns) {
3753
+ for (const pattern of patterns) {
3754
+ if (typeof pattern === "string") {
3755
+ if (errorMessage.includes(pattern)) {
3756
+ return { ...result, originalError };
3757
+ }
3758
+ } else if (pattern instanceof RegExp) {
3759
+ if (pattern.test(errorMessage)) {
3760
+ return { ...result, originalError };
3761
+ }
3762
+ }
3763
+ }
3764
+ }
3765
+ const programError = tryParseProgramError(errorMessage);
3766
+ if (programError) {
3767
+ return { ...programError, originalError };
3768
+ }
3769
+ return {
3770
+ title: "Something Went Wrong",
3771
+ message: "An unexpected error occurred.",
3772
+ category: "unknown",
3773
+ suggestion: "Please try again. If the problem persists, refresh the page.",
3774
+ recoverable: true,
3775
+ originalError
3776
+ };
3777
+ }
3778
+ function tryParseProgramError(message) {
3779
+ const match = message.match(/\{"InstructionError":\[(\d+),\{"Custom":(\d+)\}\]\}/);
3780
+ if (match) {
3781
+ const errorCode = parseInt(match[2]);
3782
+ const friendlyMessage = ShieldPoolErrors[errorCode];
3783
+ if (friendlyMessage) {
3784
+ return {
3785
+ title: "Transaction Failed",
3786
+ message: friendlyMessage,
3787
+ category: "transaction",
3788
+ recoverable: !friendlyMessage.toLowerCase().includes("double spend")
3789
+ };
3790
+ }
3791
+ return {
3792
+ title: "Transaction Failed",
3793
+ message: `Transaction failed with error code ${errorCode}.`,
3794
+ category: "transaction",
3795
+ suggestion: "Please try again or contact support if this persists.",
3796
+ recoverable: true
3797
+ };
3798
+ }
3799
+ return null;
3800
+ }
3072
3801
  function parseTransactionError(error) {
3073
3802
  if (!error) return "An unknown error occurred";
3074
3803
  const errorStr = typeof error === "string" ? error : error.message || error.toString();
@@ -3176,188 +3905,6 @@ function formatErrorForLogging(error) {
3176
3905
  return String(error);
3177
3906
  }
3178
3907
 
3179
- // src/services/ProverService.ts
3180
- var ProverService = class {
3181
- /**
3182
- * Create a new Prover Service client
3183
- *
3184
- * @param indexerUrl - Indexer/Prover service base URL
3185
- * @param timeout - Proof generation timeout in ms (default: 5 minutes)
3186
- */
3187
- constructor(indexerUrl, timeout = 5 * 60 * 1e3) {
3188
- this.indexerUrl = indexerUrl.replace(/\/$/, "");
3189
- this.timeout = timeout;
3190
- }
3191
- /**
3192
- * Generate a zero-knowledge proof for withdrawal
3193
- *
3194
- * This process typically takes 30-180 seconds depending on the backend.
3195
- *
3196
- * @param inputs - Circuit inputs (private + public + outputs)
3197
- * @param options - Optional progress tracking and callbacks
3198
- * @returns Proof result with hex-encoded proof and public inputs
3199
- *
3200
- * @example
3201
- * ```typescript
3202
- * const result = await prover.generateProof(inputs);
3203
- * if (result.success) {
3204
- * console.log(`Proof: ${result.proof}`);
3205
- * }
3206
- * ```
3207
- *
3208
- * @example
3209
- * ```typescript
3210
- * // With progress tracking
3211
- * const result = await prover.generateProof(inputs, {
3212
- * onProgress: (progress) => console.log(`Progress: ${progress}%`),
3213
- * onStart: () => console.log("Starting proof generation..."),
3214
- * onSuccess: (result) => console.log("Proof generated!"),
3215
- * onError: (error) => console.error("Failed:", error)
3216
- * });
3217
- * ```
3218
- */
3219
- async generateProof(inputs, options) {
3220
- const startTime = Date.now();
3221
- const actualTimeout = options?.timeout || this.timeout;
3222
- options?.onStart?.();
3223
- let progressInterval;
3224
- try {
3225
- const requestBody = {
3226
- private_inputs: JSON.stringify(inputs.privateInputs),
3227
- public_inputs: JSON.stringify(inputs.publicInputs),
3228
- outputs: JSON.stringify(inputs.outputs)
3229
- };
3230
- if (inputs.swapParams) {
3231
- requestBody.swap_params = inputs.swapParams;
3232
- }
3233
- const controller = new AbortController();
3234
- const timeoutId = setTimeout(() => controller.abort(), actualTimeout);
3235
- if (options?.onProgress) {
3236
- let progress = 0;
3237
- progressInterval = setInterval(() => {
3238
- progress = Math.min(90, progress + Math.random() * 10);
3239
- options.onProgress(Math.floor(progress));
3240
- }, 2e3);
3241
- }
3242
- const response = await fetch(`${this.indexerUrl}/api/v1/prove`, {
3243
- method: "POST",
3244
- headers: {
3245
- "Content-Type": "application/json"
3246
- },
3247
- body: JSON.stringify(requestBody),
3248
- signal: controller.signal
3249
- });
3250
- clearTimeout(timeoutId);
3251
- if (progressInterval) clearInterval(progressInterval);
3252
- if (!response.ok) {
3253
- let errorMessage = `${response.status} ${response.statusText}`;
3254
- try {
3255
- const errorText = await response.text();
3256
- try {
3257
- const errorJson = JSON.parse(errorText);
3258
- errorMessage = errorJson.error || errorJson.message || errorText;
3259
- } catch {
3260
- errorMessage = errorText || errorMessage;
3261
- }
3262
- } catch {
3263
- }
3264
- options?.onError?.(errorMessage);
3265
- return {
3266
- success: false,
3267
- generationTimeMs: Date.now() - startTime,
3268
- error: errorMessage
3269
- };
3270
- }
3271
- options?.onProgress?.(100);
3272
- const rawData = await response.json();
3273
- const result = {
3274
- success: rawData.success,
3275
- proof: rawData.proof,
3276
- publicInputs: rawData.public_inputs,
3277
- // Map snake_case
3278
- generationTimeMs: rawData.generation_time_ms || Date.now() - startTime,
3279
- error: rawData.error
3280
- };
3281
- if (!result.success && rawData.execution_report) {
3282
- }
3283
- if (!result.success && result.error) {
3284
- try {
3285
- const errorObj = typeof result.error === "string" ? JSON.parse(result.error) : result.error;
3286
- if (errorObj?.error && typeof errorObj.error === "string") {
3287
- result.error = errorObj.error;
3288
- } else if (typeof errorObj === "string") {
3289
- result.error = errorObj;
3290
- }
3291
- if (errorObj?.execution_report && typeof errorObj.execution_report === "string") {
3292
- result.error += `
3293
- Execution report: ${errorObj.execution_report}`;
3294
- }
3295
- if (errorObj?.total_cycles !== void 0) {
3296
- result.error += `
3297
- Total cycles: ${errorObj.total_cycles}`;
3298
- }
3299
- if (errorObj?.total_syscalls !== void 0) {
3300
- result.error += `
3301
- Total syscalls: ${errorObj.total_syscalls}`;
3302
- }
3303
- } catch {
3304
- }
3305
- }
3306
- if (result.success) {
3307
- options?.onSuccess?.(result);
3308
- } else if (result.error) {
3309
- options?.onError?.(result.error);
3310
- }
3311
- return result;
3312
- } catch (error) {
3313
- const totalTime = Date.now() - startTime;
3314
- if (progressInterval) clearInterval(progressInterval);
3315
- let errorMessage;
3316
- if (error instanceof Error && error.name === "AbortError") {
3317
- errorMessage = `Proof generation timed out after ${actualTimeout}ms`;
3318
- } else {
3319
- errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
3320
- }
3321
- options?.onError?.(errorMessage);
3322
- return {
3323
- success: false,
3324
- generationTimeMs: totalTime,
3325
- error: errorMessage
3326
- };
3327
- }
3328
- }
3329
- /**
3330
- * Check if the prover service is available
3331
- *
3332
- * @returns True if service is healthy
3333
- */
3334
- async healthCheck() {
3335
- try {
3336
- const response = await fetch(`${this.indexerUrl}/health`, {
3337
- method: "GET"
3338
- });
3339
- return response.ok;
3340
- } catch {
3341
- return false;
3342
- }
3343
- }
3344
- /**
3345
- * Get the configured timeout
3346
- */
3347
- getTimeout() {
3348
- return this.timeout;
3349
- }
3350
- /**
3351
- * Set a new timeout
3352
- */
3353
- setTimeout(timeout) {
3354
- if (timeout <= 0) {
3355
- throw new Error("Timeout must be positive");
3356
- }
3357
- this.timeout = timeout;
3358
- }
3359
- };
3360
-
3361
3908
  // src/helpers/wallet-integration.ts
3362
3909
  var import_web36 = require("@solana/web3.js");
3363
3910
  function validateWalletConnected(wallet) {
@@ -3430,6 +3977,173 @@ function keypairToAdapter(keypair) {
3430
3977
  };
3431
3978
  }
3432
3979
 
3980
+ // src/utils/pending-operations.ts
3981
+ var PENDING_DEPOSITS_KEY = "cloak_pending_deposits";
3982
+ var PENDING_WITHDRAWALS_KEY = "cloak_pending_withdrawals";
3983
+ function getStorage() {
3984
+ if (typeof globalThis !== "undefined" && globalThis.localStorage) {
3985
+ return globalThis.localStorage;
3986
+ }
3987
+ return null;
3988
+ }
3989
+ function savePendingDeposit(deposit) {
3990
+ const storage = getStorage();
3991
+ if (!storage) {
3992
+ console.warn("localStorage not available - pending deposit not persisted");
3993
+ return;
3994
+ }
3995
+ const deposits = loadPendingDeposits();
3996
+ const index = deposits.findIndex((d) => d.note.commitment === deposit.note.commitment);
3997
+ if (index >= 0) {
3998
+ deposits[index] = deposit;
3999
+ } else {
4000
+ deposits.push(deposit);
4001
+ }
4002
+ storage.setItem(PENDING_DEPOSITS_KEY, JSON.stringify(deposits));
4003
+ }
4004
+ function loadPendingDeposits() {
4005
+ const storage = getStorage();
4006
+ if (!storage) return [];
4007
+ const stored = storage.getItem(PENDING_DEPOSITS_KEY);
4008
+ if (!stored) return [];
4009
+ try {
4010
+ return JSON.parse(stored);
4011
+ } catch {
4012
+ return [];
4013
+ }
4014
+ }
4015
+ function updatePendingDeposit(commitment, updates) {
4016
+ const storage = getStorage();
4017
+ if (!storage) return;
4018
+ const deposits = loadPendingDeposits();
4019
+ const index = deposits.findIndex((d) => d.note.commitment === commitment);
4020
+ if (index >= 0) {
4021
+ deposits[index] = { ...deposits[index], ...updates };
4022
+ storage.setItem(PENDING_DEPOSITS_KEY, JSON.stringify(deposits));
4023
+ }
4024
+ }
4025
+ function removePendingDeposit(commitment) {
4026
+ const storage = getStorage();
4027
+ if (!storage) return;
4028
+ const deposits = loadPendingDeposits();
4029
+ const filtered = deposits.filter((d) => d.note.commitment !== commitment);
4030
+ storage.setItem(PENDING_DEPOSITS_KEY, JSON.stringify(filtered));
4031
+ }
4032
+ function clearPendingDeposits() {
4033
+ const storage = getStorage();
4034
+ if (storage) {
4035
+ storage.removeItem(PENDING_DEPOSITS_KEY);
4036
+ }
4037
+ }
4038
+ function savePendingWithdrawal(withdrawal) {
4039
+ const storage = getStorage();
4040
+ if (!storage) {
4041
+ console.warn("localStorage not available - pending withdrawal not persisted");
4042
+ return;
4043
+ }
4044
+ const withdrawals = loadPendingWithdrawals();
4045
+ const index = withdrawals.findIndex((w) => w.requestId === withdrawal.requestId);
4046
+ if (index >= 0) {
4047
+ withdrawals[index] = withdrawal;
4048
+ } else {
4049
+ withdrawals.push(withdrawal);
4050
+ }
4051
+ storage.setItem(PENDING_WITHDRAWALS_KEY, JSON.stringify(withdrawals));
4052
+ }
4053
+ function loadPendingWithdrawals() {
4054
+ const storage = getStorage();
4055
+ if (!storage) return [];
4056
+ const stored = storage.getItem(PENDING_WITHDRAWALS_KEY);
4057
+ if (!stored) return [];
4058
+ try {
4059
+ return JSON.parse(stored);
4060
+ } catch {
4061
+ return [];
4062
+ }
4063
+ }
4064
+ function updatePendingWithdrawal(requestId, updates) {
4065
+ const storage = getStorage();
4066
+ if (!storage) return;
4067
+ const withdrawals = loadPendingWithdrawals();
4068
+ const index = withdrawals.findIndex((w) => w.requestId === requestId);
4069
+ if (index >= 0) {
4070
+ withdrawals[index] = { ...withdrawals[index], ...updates };
4071
+ storage.setItem(PENDING_WITHDRAWALS_KEY, JSON.stringify(withdrawals));
4072
+ }
4073
+ }
4074
+ function removePendingWithdrawal(requestId) {
4075
+ const storage = getStorage();
4076
+ if (!storage) return;
4077
+ const withdrawals = loadPendingWithdrawals();
4078
+ const filtered = withdrawals.filter((w) => w.requestId !== requestId);
4079
+ storage.setItem(PENDING_WITHDRAWALS_KEY, JSON.stringify(filtered));
4080
+ }
4081
+ function clearPendingWithdrawals() {
4082
+ const storage = getStorage();
4083
+ if (storage) {
4084
+ storage.removeItem(PENDING_WITHDRAWALS_KEY);
4085
+ }
4086
+ }
4087
+ function hasPendingOperations() {
4088
+ const deposits = loadPendingDeposits();
4089
+ const withdrawals = loadPendingWithdrawals();
4090
+ const pendingDeposits = deposits.filter(
4091
+ (d) => d.status === "pending" || d.status === "tx_sent"
4092
+ );
4093
+ const pendingWithdrawals = withdrawals.filter(
4094
+ (w) => w.status === "pending" || w.status === "processing"
4095
+ );
4096
+ return pendingDeposits.length > 0 || pendingWithdrawals.length > 0;
4097
+ }
4098
+ function getPendingOperationsSummary() {
4099
+ const deposits = loadPendingDeposits().filter(
4100
+ (d) => d.status === "pending" || d.status === "tx_sent"
4101
+ );
4102
+ const withdrawals = loadPendingWithdrawals().filter(
4103
+ (w) => w.status === "pending" || w.status === "processing"
4104
+ );
4105
+ return {
4106
+ deposits,
4107
+ withdrawals,
4108
+ totalPending: deposits.length + withdrawals.length
4109
+ };
4110
+ }
4111
+ function cleanupStalePendingOperations(maxAgeMs = 24 * 60 * 60 * 1e3) {
4112
+ const now = Date.now();
4113
+ let removedDeposits = 0;
4114
+ let removedWithdrawals = 0;
4115
+ const deposits = loadPendingDeposits();
4116
+ const activeDeposits = deposits.filter((d) => {
4117
+ const age = now - d.startedAt;
4118
+ const isStale = age > maxAgeMs;
4119
+ const isTerminal = d.status === "confirmed" || d.status === "failed";
4120
+ if (isStale || isTerminal) {
4121
+ removedDeposits++;
4122
+ return false;
4123
+ }
4124
+ return true;
4125
+ });
4126
+ const storage = getStorage();
4127
+ if (storage) {
4128
+ storage.setItem(PENDING_DEPOSITS_KEY, JSON.stringify(activeDeposits));
4129
+ }
4130
+ const withdrawals = loadPendingWithdrawals();
4131
+ const activeWithdrawals = withdrawals.filter((w) => {
4132
+ const age = now - w.startedAt;
4133
+ const isStale = age > maxAgeMs;
4134
+ const isTerminal = w.status === "completed" || w.status === "failed";
4135
+ if (isStale || isTerminal) {
4136
+ removedWithdrawals++;
4137
+ return false;
4138
+ }
4139
+ return true;
4140
+ });
4141
+ if (storage) {
4142
+ storage.setItem(PENDING_WITHDRAWALS_KEY, JSON.stringify(activeWithdrawals));
4143
+ }
4144
+ return { removedDeposits, removedWithdrawals };
4145
+ }
4146
+
3433
4147
  // src/index.ts
3434
4148
  var VERSION = "1.0.0";
3435
4149
  // Annotate the CommonJS export names for ESM import in node:
@@ -3438,13 +4152,14 @@ var VERSION = "1.0.0";
3438
4152
  CloakError,
3439
4153
  CloakSDK,
3440
4154
  DepositRecoveryService,
4155
+ EXPECTED_CIRCUIT_HASHES,
3441
4156
  FIXED_FEE_LAMPORTS,
3442
4157
  IndexerService,
3443
4158
  LAMPORTS_PER_SOL,
3444
4159
  LocalStorageAdapter,
3445
4160
  MemoryStorageAdapter,
3446
- ProverService,
3447
4161
  RelayService,
4162
+ ShieldPoolErrors,
3448
4163
  VARIABLE_FEE_RATE,
3449
4164
  VERSION,
3450
4165
  bigintToBytes32,
@@ -3452,6 +4167,9 @@ var VERSION = "1.0.0";
3452
4167
  bytesToHex,
3453
4168
  calculateFee,
3454
4169
  calculateRelayFee,
4170
+ cleanupStalePendingOperations,
4171
+ clearPendingDeposits,
4172
+ clearPendingWithdrawals,
3455
4173
  computeCommitment,
3456
4174
  computeMerkleRoot,
3457
4175
  computeNullifier,
@@ -3491,12 +4209,14 @@ var VERSION = "1.0.0";
3491
4209
  getAddressExplorerUrl,
3492
4210
  getDistributableAmount,
3493
4211
  getExplorerUrl,
4212
+ getPendingOperationsSummary,
3494
4213
  getPublicKey,
3495
4214
  getPublicViewKey,
3496
4215
  getRecipientAmount,
3497
4216
  getRpcUrlForNetwork,
3498
4217
  getShieldPoolPDAs,
3499
4218
  getViewKey,
4219
+ hasPendingOperations,
3500
4220
  hexToBigint,
3501
4221
  hexToBytes,
3502
4222
  importKeys,
@@ -3506,7 +4226,10 @@ var VERSION = "1.0.0";
3506
4226
  isValidSolanaAddress,
3507
4227
  isWithdrawable,
3508
4228
  keypairToAdapter,
4229
+ loadPendingDeposits,
4230
+ loadPendingWithdrawals,
3509
4231
  parseAmount,
4232
+ parseError,
3510
4233
  parseNote,
3511
4234
  parseTransactionError,
3512
4235
  poseidonHash,
@@ -3515,6 +4238,10 @@ var VERSION = "1.0.0";
3515
4238
  proofToBytes,
3516
4239
  pubkeyToLimbs,
3517
4240
  randomBytes,
4241
+ removePendingDeposit,
4242
+ removePendingWithdrawal,
4243
+ savePendingDeposit,
4244
+ savePendingWithdrawal,
3518
4245
  scanNotesForWallet,
3519
4246
  sendTransaction,
3520
4247
  serializeNote,
@@ -3522,10 +4249,14 @@ var VERSION = "1.0.0";
3522
4249
  splitTo2Limbs,
3523
4250
  tryDecryptNote,
3524
4251
  updateNoteWithDeposit,
4252
+ updatePendingDeposit,
4253
+ updatePendingWithdrawal,
3525
4254
  validateDepositParams,
3526
4255
  validateNote,
3527
4256
  validateOutputsSum,
3528
4257
  validateTransfers,
3529
4258
  validateWalletConnected,
3530
- validateWithdrawableNote
4259
+ validateWithdrawableNote,
4260
+ verifyAllCircuits,
4261
+ verifyCircuitIntegrity
3531
4262
  });