@cloak.ag/sdk 1.0.7 → 1.0.8

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
@@ -407,6 +407,7 @@ __export(index_exports, {
407
407
  CLOAK_PROGRAM_ID: () => CLOAK_PROGRAM_ID,
408
408
  CloakError: () => CloakError,
409
409
  CloakSDK: () => CloakSDK,
410
+ DEFAULT_CIRCUITS_URL: () => DEFAULT_CIRCUITS_URL,
410
411
  EXPECTED_CIRCUIT_HASHES: () => EXPECTED_CIRCUIT_HASHES,
411
412
  FIXED_FEE_LAMPORTS: () => FIXED_FEE_LAMPORTS,
412
413
  LAMPORTS_PER_SOL: () => LAMPORTS_PER_SOL,
@@ -417,6 +418,7 @@ __export(index_exports, {
417
418
  ShieldPoolErrors: () => ShieldPoolErrors,
418
419
  VARIABLE_FEE_RATE: () => VARIABLE_FEE_RATE,
419
420
  VERSION: () => VERSION,
421
+ areCircuitsAvailable: () => areCircuitsAvailable,
420
422
  bigintToBytes32: () => bigintToBytes32,
421
423
  buildPublicInputsBytes: () => buildPublicInputsBytes,
422
424
  bytesToHex: () => bytesToHex,
@@ -466,14 +468,17 @@ __export(index_exports, {
466
468
  generateWithdrawRegularProof: () => generateWithdrawRegularProof,
467
469
  generateWithdrawSwapProof: () => generateWithdrawSwapProof,
468
470
  getAddressExplorerUrl: () => getAddressExplorerUrl,
471
+ getDefaultCircuitsPath: () => getDefaultCircuitsPath,
469
472
  getDistributableAmount: () => getDistributableAmount2,
470
473
  getExplorerUrl: () => getExplorerUrl,
474
+ getNullifierPDA: () => getNullifierPDA,
471
475
  getPendingOperationsSummary: () => getPendingOperationsSummary,
472
476
  getPublicKey: () => getPublicKey,
473
477
  getPublicViewKey: () => getPublicViewKey,
474
478
  getRecipientAmount: () => getRecipientAmount,
475
479
  getRpcUrlForNetwork: () => getRpcUrlForNetwork,
476
480
  getShieldPoolPDAs: () => getShieldPoolPDAs,
481
+ getSwapStatePDA: () => getSwapStatePDA,
477
482
  getViewKey: () => getViewKey,
478
483
  hasPendingOperations: () => hasPendingOperations,
479
484
  hexToBigint: () => hexToBigint,
@@ -2129,30 +2134,85 @@ function getShieldPoolPDAs(programId, mint) {
2129
2134
  treasury
2130
2135
  };
2131
2136
  }
2137
+ function getNullifierPDA(nullifier, programId) {
2138
+ const pid = programId || CLOAK_PROGRAM_ID;
2139
+ if (nullifier.length !== 32) {
2140
+ throw new Error(`Nullifier must be 32 bytes, got ${nullifier.length}`);
2141
+ }
2142
+ return import_web33.PublicKey.findProgramAddressSync(
2143
+ [Buffer.from("nullifier"), Buffer.from(nullifier)],
2144
+ pid
2145
+ );
2146
+ }
2147
+ function getSwapStatePDA(nullifier, programId) {
2148
+ const pid = programId || CLOAK_PROGRAM_ID;
2149
+ if (nullifier.length !== 32) {
2150
+ throw new Error(`Nullifier must be 32 bytes, got ${nullifier.length}`);
2151
+ }
2152
+ return import_web33.PublicKey.findProgramAddressSync(
2153
+ [Buffer.from("swap_state"), Buffer.from(nullifier)],
2154
+ pid
2155
+ );
2156
+ }
2132
2157
 
2133
2158
  // src/utils/proof-generation.ts
2134
2159
  var snarkjs = __toESM(require("snarkjs"), 1);
2135
2160
  init_crypto();
2136
2161
  var IS_REACT_NATIVE = typeof navigator !== "undefined" && navigator.product === "ReactNative";
2137
2162
  var IS_BROWSER = IS_REACT_NATIVE || typeof window !== "undefined" || typeof globalThis !== "undefined" && typeof globalThis.document !== "undefined";
2163
+ var DEFAULT_CIRCUITS_URL = "https://www.cloak.ag/circuits";
2164
+ function isUrl(path) {
2165
+ return path.startsWith("http://") || path.startsWith("https://");
2166
+ }
2167
+ async function fetchFileAsBuffer(url) {
2168
+ const response = await fetch(url);
2169
+ if (!response.ok) {
2170
+ throw new Error(`Failed to fetch ${url}: ${response.status} ${response.statusText}`);
2171
+ }
2172
+ const arrayBuffer = await response.arrayBuffer();
2173
+ return new Uint8Array(arrayBuffer);
2174
+ }
2138
2175
  var _nodePath = null;
2139
2176
  var _nodeFs = null;
2140
2177
  var _nodeCrypto = null;
2178
+ var _fs = null;
2179
+ var _path = null;
2180
+ async function loadNodeModules() {
2181
+ if (_fs && _path) {
2182
+ return { fs: _fs, path: _path };
2183
+ }
2184
+ if (IS_BROWSER) {
2185
+ throw new Error("Node.js modules not available in browser/React Native");
2186
+ }
2187
+ const [fsModule, pathModule] = await Promise.all([
2188
+ import("fs"),
2189
+ import("path")
2190
+ ]);
2191
+ _fs = fsModule;
2192
+ _path = pathModule;
2193
+ return { fs: _fs, path: _path };
2194
+ }
2141
2195
  function nodeRequire(moduleName) {
2142
2196
  if (IS_BROWSER) {
2143
2197
  throw new Error(`Node.js ${moduleName} module not available in browser/React Native`);
2144
2198
  }
2145
- const requireFunc = new Function("moduleName", "return require(moduleName)");
2146
- return requireFunc(moduleName);
2199
+ try {
2200
+ const requireFunc = new Function("moduleName", "return require(moduleName)");
2201
+ return requireFunc(moduleName);
2202
+ } catch {
2203
+ throw new Error(`Cannot load Node.js module ${moduleName} synchronously in ESM. Use async loadNodeModules() instead.`);
2204
+ }
2147
2205
  }
2148
2206
  async function getNodePath() {
2149
2207
  if (_nodePath) return _nodePath;
2150
- _nodePath = nodeRequire("path");
2208
+ const { path } = await loadNodeModules();
2209
+ _nodePath = path;
2151
2210
  return _nodePath;
2152
2211
  }
2153
2212
  async function getNodeFs() {
2154
2213
  if (_nodeFs) return _nodeFs;
2155
- _nodeFs = nodeRequire("fs");
2214
+ const { fs } = await loadNodeModules();
2215
+ _nodeFs = fs;
2156
2216
  return _nodeFs;
2157
2217
  }
2158
2218
  async function getNodeCrypto() {
@@ -2173,29 +2233,41 @@ async function fileExists(filePath) {
2173
2233
  }
2174
2234
  }
2175
2235
  try {
2176
- const nodeFs = nodeRequire("fs");
2177
- return nodeFs.existsSync(filePath);
2236
+ const { fs } = await loadNodeModules();
2237
+ return fs.existsSync(filePath);
2178
2238
  } catch {
2179
2239
  return false;
2180
2240
  }
2181
2241
  }
2182
2242
  async function generateWithdrawRegularProof(inputs, circuitsPath) {
2183
- let wasmPath;
2184
- let zkeyPath;
2243
+ let wasmInput;
2244
+ let zkeyInput;
2245
+ const useUrl = isUrl(circuitsPath);
2185
2246
  if (IS_BROWSER) {
2186
- wasmPath = `${circuitsPath}/withdraw_regular_js/withdraw_regular.wasm`;
2187
- zkeyPath = `${circuitsPath}/withdraw_regular_final.zkey`;
2247
+ wasmInput = `${circuitsPath}/withdraw_regular_js/withdraw_regular.wasm`;
2248
+ zkeyInput = `${circuitsPath}/withdraw_regular_final.zkey`;
2249
+ } else if (useUrl) {
2250
+ const wasmUrl = `${circuitsPath}/withdraw_regular_js/withdraw_regular.wasm`;
2251
+ const zkeyUrl = `${circuitsPath}/withdraw_regular_final.zkey`;
2252
+ const [wasmData, zkeyData] = await Promise.all([
2253
+ fetchFileAsBuffer(wasmUrl),
2254
+ fetchFileAsBuffer(zkeyUrl)
2255
+ ]);
2256
+ wasmInput = wasmData;
2257
+ zkeyInput = zkeyData;
2188
2258
  } else {
2189
- wasmPath = joinPath(circuitsPath, "build", "withdraw_regular_js", "withdraw_regular.wasm");
2190
- zkeyPath = joinPath(circuitsPath, "build", "withdraw_regular_final.zkey");
2259
+ const wasmPath = joinPath(circuitsPath, "build", "withdraw_regular_js", "withdraw_regular.wasm");
2260
+ const zkeyPath = joinPath(circuitsPath, "build", "withdraw_regular_final.zkey");
2191
2261
  const wasmExists = await fileExists(wasmPath);
2192
2262
  const zkeyExists = await fileExists(zkeyPath);
2193
2263
  if (!wasmExists) {
2194
- throw new Error(`Circuit WASM not found at ${wasmPath}. Run 'just circuits-compile' in packages-new/circuits first.`);
2264
+ throw new Error(`Circuit WASM not found at ${wasmPath}. Run 'just circuits-compile' in packages/ first.`);
2195
2265
  }
2196
2266
  if (!zkeyExists) {
2197
2267
  throw new Error(`Circuit zkey not found at ${zkeyPath}. Run circuit setup first.`);
2198
2268
  }
2269
+ wasmInput = wasmPath;
2270
+ zkeyInput = zkeyPath;
2199
2271
  }
2200
2272
  const circuitInputs = {
2201
2273
  // Public signals
@@ -2219,7 +2291,7 @@ async function generateWithdrawRegularProof(inputs, circuitsPath) {
2219
2291
  var_fee: inputs.var_fee.toString(),
2220
2292
  rem: inputs.rem.toString()
2221
2293
  };
2222
- const { proof, publicSignals } = await snarkjs.groth16.fullProve(circuitInputs, wasmPath, zkeyPath);
2294
+ const { proof, publicSignals } = await snarkjs.groth16.fullProve(circuitInputs, wasmInput, zkeyInput);
2223
2295
  const proofBytes = proofToBytes(proof);
2224
2296
  return {
2225
2297
  proof,
@@ -2230,22 +2302,34 @@ async function generateWithdrawRegularProof(inputs, circuitsPath) {
2230
2302
  };
2231
2303
  }
2232
2304
  async function generateWithdrawSwapProof(inputs, circuitsPath) {
2233
- let wasmPath;
2234
- let zkeyPath;
2305
+ let wasmInput;
2306
+ let zkeyInput;
2307
+ const useUrl = isUrl(circuitsPath);
2235
2308
  if (IS_BROWSER) {
2236
- wasmPath = `${circuitsPath}/withdraw_swap_js/withdraw_swap.wasm`;
2237
- zkeyPath = `${circuitsPath}/withdraw_swap_final.zkey`;
2309
+ wasmInput = `${circuitsPath}/withdraw_swap_js/withdraw_swap.wasm`;
2310
+ zkeyInput = `${circuitsPath}/withdraw_swap_final.zkey`;
2311
+ } else if (useUrl) {
2312
+ const wasmUrl = `${circuitsPath}/withdraw_swap_js/withdraw_swap.wasm`;
2313
+ const zkeyUrl = `${circuitsPath}/withdraw_swap_final.zkey`;
2314
+ const [wasmData, zkeyData] = await Promise.all([
2315
+ fetchFileAsBuffer(wasmUrl),
2316
+ fetchFileAsBuffer(zkeyUrl)
2317
+ ]);
2318
+ wasmInput = wasmData;
2319
+ zkeyInput = zkeyData;
2238
2320
  } else {
2239
- wasmPath = joinPath(circuitsPath, "build", "withdraw_swap_js", "withdraw_swap.wasm");
2240
- zkeyPath = joinPath(circuitsPath, "build", "withdraw_swap_final.zkey");
2321
+ const wasmPath = joinPath(circuitsPath, "build", "withdraw_swap_js", "withdraw_swap.wasm");
2322
+ const zkeyPath = joinPath(circuitsPath, "build", "withdraw_swap_final.zkey");
2241
2323
  const wasmExists = await fileExists(wasmPath);
2242
2324
  const zkeyExists = await fileExists(zkeyPath);
2243
2325
  if (!wasmExists) {
2244
- throw new Error(`Circuit WASM not found at ${wasmPath}. Run 'just circuits-compile' in packages-new/circuits first.`);
2326
+ throw new Error(`Circuit WASM not found at ${wasmPath}. Run 'just circuits-compile' in packages/ first.`);
2245
2327
  }
2246
2328
  if (!zkeyExists) {
2247
2329
  throw new Error(`Circuit zkey not found at ${zkeyPath}. Run circuit setup first.`);
2248
2330
  }
2331
+ wasmInput = wasmPath;
2332
+ zkeyInput = zkeyPath;
2249
2333
  }
2250
2334
  const sk = splitTo2Limbs(inputs.sk_spend);
2251
2335
  const r = splitTo2Limbs(inputs.r);
@@ -2274,8 +2358,8 @@ async function generateWithdrawSwapProof(inputs, circuitsPath) {
2274
2358
  };
2275
2359
  const { proof, publicSignals } = await snarkjs.groth16.fullProve(
2276
2360
  circuitInputs,
2277
- wasmPath,
2278
- zkeyPath
2361
+ wasmInput,
2362
+ zkeyInput
2279
2363
  );
2280
2364
  const proofBytes = proofToBytes(proof);
2281
2365
  return {
@@ -2287,8 +2371,14 @@ async function generateWithdrawSwapProof(inputs, circuitsPath) {
2287
2371
  };
2288
2372
  }
2289
2373
  async function areCircuitsAvailable(circuitsPath) {
2374
+ if (!circuitsPath || circuitsPath === "") {
2375
+ return false;
2376
+ }
2377
+ if (isUrl(circuitsPath)) {
2378
+ return true;
2379
+ }
2290
2380
  if (IS_BROWSER) {
2291
- return Boolean(circuitsPath && circuitsPath !== "");
2381
+ return true;
2292
2382
  }
2293
2383
  const wasmPath = joinPath(circuitsPath, "build", "withdraw_regular_js", "withdraw_regular.wasm");
2294
2384
  const zkeyPath = joinPath(circuitsPath, "build", "withdraw_regular_final.zkey");
@@ -2297,22 +2387,25 @@ async function areCircuitsAvailable(circuitsPath) {
2297
2387
  return wasmExists && zkeyExists;
2298
2388
  }
2299
2389
  async function getDefaultCircuitsPath() {
2390
+ if (typeof process !== "undefined" && process.env?.CIRCUITS_PATH) {
2391
+ return process.env.CIRCUITS_PATH;
2392
+ }
2300
2393
  if (IS_BROWSER) {
2301
2394
  return "/circuits";
2302
2395
  }
2303
2396
  if (typeof process === "undefined" || !process.cwd) {
2304
- return "/circuits";
2397
+ return DEFAULT_CIRCUITS_URL;
2305
2398
  }
2306
2399
  let nodePath;
2307
2400
  try {
2308
2401
  nodePath = await getNodePath();
2309
- } catch {
2310
- return "/circuits";
2402
+ } catch (e) {
2403
+ return DEFAULT_CIRCUITS_URL;
2311
2404
  }
2312
2405
  const possiblePaths = [
2313
- nodePath.resolve(process.cwd(), "../../packages-new/circuits"),
2314
- nodePath.resolve(process.cwd(), "../packages-new/circuits"),
2315
- nodePath.resolve(process.cwd(), "packages-new/circuits"),
2406
+ nodePath.resolve(process.cwd(), "../../packages/circuits"),
2407
+ nodePath.resolve(process.cwd(), "../packages/circuits"),
2408
+ nodePath.resolve(process.cwd(), "packages/circuits"),
2316
2409
  nodePath.resolve(process.cwd(), "../../circuits"),
2317
2410
  nodePath.resolve(process.cwd(), "../circuits")
2318
2411
  ];
@@ -2321,7 +2414,7 @@ async function getDefaultCircuitsPath() {
2321
2414
  return p;
2322
2415
  }
2323
2416
  }
2324
- return possiblePaths[0];
2417
+ return DEFAULT_CIRCUITS_URL;
2325
2418
  }
2326
2419
  var EXPECTED_CIRCUIT_HASHES = {
2327
2420
  // SHA-256 of the verification key JSON from withdraw_regular circuit
@@ -3949,6 +4042,7 @@ var VERSION = "1.0.0";
3949
4042
  CLOAK_PROGRAM_ID,
3950
4043
  CloakError,
3951
4044
  CloakSDK,
4045
+ DEFAULT_CIRCUITS_URL,
3952
4046
  EXPECTED_CIRCUIT_HASHES,
3953
4047
  FIXED_FEE_LAMPORTS,
3954
4048
  LAMPORTS_PER_SOL,
@@ -3959,6 +4053,7 @@ var VERSION = "1.0.0";
3959
4053
  ShieldPoolErrors,
3960
4054
  VARIABLE_FEE_RATE,
3961
4055
  VERSION,
4056
+ areCircuitsAvailable,
3962
4057
  bigintToBytes32,
3963
4058
  buildPublicInputsBytes,
3964
4059
  bytesToHex,
@@ -4008,14 +4103,17 @@ var VERSION = "1.0.0";
4008
4103
  generateWithdrawRegularProof,
4009
4104
  generateWithdrawSwapProof,
4010
4105
  getAddressExplorerUrl,
4106
+ getDefaultCircuitsPath,
4011
4107
  getDistributableAmount,
4012
4108
  getExplorerUrl,
4109
+ getNullifierPDA,
4013
4110
  getPendingOperationsSummary,
4014
4111
  getPublicKey,
4015
4112
  getPublicViewKey,
4016
4113
  getRecipientAmount,
4017
4114
  getRpcUrlForNetwork,
4018
4115
  getShieldPoolPDAs,
4116
+ getSwapStatePDA,
4019
4117
  getViewKey,
4020
4118
  hasPendingOperations,
4021
4119
  hexToBigint,
package/dist/index.d.cts CHANGED
@@ -1753,6 +1753,7 @@ interface ShieldPoolPDAs {
1753
1753
  merkleTree: PublicKey;
1754
1754
  commitments: PublicKey;
1755
1755
  rootsRing: PublicKey;
1756
+ /** @deprecated Use getNullifierPDA() for the new per-nullifier PDA design */
1756
1757
  nullifierShard: PublicKey;
1757
1758
  treasury: PublicKey;
1758
1759
  }
@@ -1774,6 +1775,30 @@ interface ShieldPoolPDAs {
1774
1775
  * @param mint - Optional mint address (defaults to 32 zero bytes for native SOL)
1775
1776
  */
1776
1777
  declare function getShieldPoolPDAs(programId?: PublicKey, mint?: PublicKey): ShieldPoolPDAs;
1778
+ /**
1779
+ * Derive the nullifier PDA for a specific nullifier hash.
1780
+ *
1781
+ * With the new PDA-per-nullifier design, each nullifier has its own PDA
1782
+ * instead of being stored in a shared shard. The PDA is created when
1783
+ * the nullifier is used during withdrawal.
1784
+ *
1785
+ * Seeds: ["nullifier", nullifier_hash]
1786
+ *
1787
+ * @param nullifier - 32-byte nullifier hash
1788
+ * @param programId - Optional program ID (defaults to CLOAK_PROGRAM_ID)
1789
+ * @returns [PublicKey, bump] - The nullifier PDA and its bump seed
1790
+ */
1791
+ declare function getNullifierPDA(nullifier: Uint8Array | Buffer, programId?: PublicKey): [PublicKey, number];
1792
+ /**
1793
+ * Derive the swap state PDA for a given nullifier.
1794
+ *
1795
+ * Seeds: ["swap_state", nullifier_hash]
1796
+ *
1797
+ * @param nullifier - 32-byte nullifier hash
1798
+ * @param programId - Optional program ID (defaults to CLOAK_PROGRAM_ID)
1799
+ * @returns [PublicKey, bump] - The swap state PDA and its bump seed
1800
+ */
1801
+ declare function getSwapStatePDA(nullifier: Uint8Array | Buffer, programId?: PublicKey): [PublicKey, number];
1777
1802
 
1778
1803
  /**
1779
1804
  * On-chain Merkle proof computation
@@ -1838,6 +1863,11 @@ declare function computeProofForLatestDeposit(connection: Connection, merkleTree
1838
1863
  * as it doesn't require a backend prover service.
1839
1864
  */
1840
1865
 
1866
+ /**
1867
+ * Default URL for fetching circuit artifacts
1868
+ * These are served from the Cloak web app at https://cloak.ag
1869
+ */
1870
+ declare const DEFAULT_CIRCUITS_URL = "https://www.cloak.ag/circuits";
1841
1871
  interface WithdrawRegularInputs {
1842
1872
  root: bigint;
1843
1873
  nullifier: bigint;
@@ -1898,6 +1928,23 @@ declare function generateWithdrawRegularProof(inputs: WithdrawRegularInputs, cir
1898
1928
  * @param circuitsPath - Path or URL to circuits directory. In browser, use URL like '/circuits' or full URL.
1899
1929
  */
1900
1930
  declare function generateWithdrawSwapProof(inputs: WithdrawSwapInputs, circuitsPath: string): Promise<ProofResult>;
1931
+ /**
1932
+ * Check if circuits are available at the given path or URL
1933
+ * Supports both local file paths and remote URLs
1934
+ *
1935
+ * Note: For remote URLs, this returns true without checking (snarkjs will handle loading).
1936
+ * For local paths, it checks if the files exist on disk.
1937
+ */
1938
+ declare function areCircuitsAvailable(circuitsPath: string): Promise<boolean>;
1939
+ /**
1940
+ * Get default circuits path or URL
1941
+ *
1942
+ * Priority:
1943
+ * 1. CIRCUITS_PATH environment variable (if set)
1944
+ * 2. Local file paths (if available)
1945
+ * 3. Default remote URL (https://cloak.ag/circuits)
1946
+ */
1947
+ declare function getDefaultCircuitsPath(): Promise<string>;
1901
1948
  /**
1902
1949
  * Expected circuit hashes for verification
1903
1950
  * These are computed from the verification key files to ensure circuits match on-chain vkeys
@@ -2076,4 +2123,4 @@ declare function cleanupStalePendingOperations(maxAgeMs?: number): {
2076
2123
 
2077
2124
  declare const VERSION = "1.0.0";
2078
2125
 
2079
- export { CLOAK_PROGRAM_ID, type CircuitVerificationResult, type CloakConfig, CloakError, type CloakKeyPair, type CloakNote, CloakSDK, type DepositInstructionParams, type DepositOptions, type DepositResult, type DepositStatus, EXPECTED_CIRCUIT_HASHES, type EncryptedNote, type ErrorCategory, FIXED_FEE_LAMPORTS, type Groth16Proof, LAMPORTS_PER_SOL, LocalStorageAdapter, type LogLevel, type Logger, type MasterKey, type MaxLengthArray, MemoryStorageAdapter, type MerkleProof, type MerkleRootResponse, type Network, type NoteData, type OnchainMerkleProof, type PendingDeposit, type PendingWithdrawal, type ProofResult, RelayService, RootNotFoundError, ShieldPoolErrors, type ShieldPoolPDAs, type SpendKey, type StorageAdapter, type SwapOptions, type SwapParams, type SwapResult, type Transfer, type TransferOptions, type TransferResult, type TxStatus, type UserFriendlyError, VARIABLE_FEE_RATE, VERSION, type ViewKey, type WalletAdapter, type WithdrawOptions, type WithdrawRegularInputs, type WithdrawSubmissionResult, type WithdrawSwapInputs, bigintToBytes32, buildPublicInputsBytes, bytesToHex, calculateFee, calculateRelayFee, cleanupStalePendingOperations, clearPendingDeposits, clearPendingWithdrawals, computeCommitment, computeMerkleRoot, computeNullifier, computeNullifierAsync, computeNullifierSync, computeOutputsHash, computeOutputsHashAsync, computeOutputsHashSync, computeProofForLatestDeposit, computeProofFromChain, computeSwapOutputsHash, computeSwapOutputsHashAsync, computeSwapOutputsHashSync, copyNoteToClipboard, createCloakError, createDepositInstruction, createLogger, deriveSpendKey, deriveViewKey, detectNetworkFromRpcUrl, downloadNote, encodeNoteSimple, encryptNoteForRecipient, exportKeys, exportNote, exportWalletKeys, filterNotesByNetwork, filterWithdrawableNotes, findNoteByCommitment, formatAmount, formatErrorForLogging, formatSol, generateCloakKeys, generateCommitment, generateCommitmentAsync, generateMasterSeed, generateNote, generateNoteFromWallet, generateWithdrawRegularProof, generateWithdrawSwapProof, getAddressExplorerUrl, getDistributableAmount, getExplorerUrl, getPendingOperationsSummary, getPublicKey, getPublicViewKey, getRecipientAmount, getRpcUrlForNetwork, getShieldPoolPDAs, getViewKey, hasPendingOperations, hexToBigint, hexToBytes, importKeys, importWalletKeys, isDebugEnabled, isRootNotFoundError, isValidHex, isValidRpcUrl, isValidSolanaAddress, isWithdrawable, keypairToAdapter, loadPendingDeposits, loadPendingWithdrawals, parseAmount, parseError, parseNote, parseTransactionError, poseidonHash, prepareEncryptedOutput, prepareEncryptedOutputForRecipient, proofToBytes, pubkeyToLimbs, randomBytes, readMerkleTreeState, removePendingDeposit, removePendingWithdrawal, savePendingDeposit, savePendingWithdrawal, scanNotesForWallet, sdkLogger, sendTransaction, serializeNote, setDebugMode, signTransaction, splitTo2Limbs, truncate, tryDecryptNote, updateNoteWithDeposit, updatePendingDeposit, updatePendingWithdrawal, validateDepositParams, validateNote, validateOutputsSum, validateTransfers, validateWalletConnected, validateWithdrawableNote, verifyAllCircuits, verifyCircuitIntegrity, withTiming };
2126
+ export { CLOAK_PROGRAM_ID, type CircuitVerificationResult, type CloakConfig, CloakError, type CloakKeyPair, type CloakNote, CloakSDK, DEFAULT_CIRCUITS_URL, type DepositInstructionParams, type DepositOptions, type DepositResult, type DepositStatus, EXPECTED_CIRCUIT_HASHES, type EncryptedNote, type ErrorCategory, FIXED_FEE_LAMPORTS, type Groth16Proof, LAMPORTS_PER_SOL, LocalStorageAdapter, type LogLevel, type Logger, type MasterKey, type MaxLengthArray, MemoryStorageAdapter, type MerkleProof, type MerkleRootResponse, type Network, type NoteData, type OnchainMerkleProof, type PendingDeposit, type PendingWithdrawal, type ProofResult, RelayService, RootNotFoundError, ShieldPoolErrors, type ShieldPoolPDAs, type SpendKey, type StorageAdapter, type SwapOptions, type SwapParams, type SwapResult, type Transfer, type TransferOptions, type TransferResult, type TxStatus, type UserFriendlyError, VARIABLE_FEE_RATE, VERSION, type ViewKey, type WalletAdapter, type WithdrawOptions, type WithdrawRegularInputs, type WithdrawSubmissionResult, type WithdrawSwapInputs, areCircuitsAvailable, bigintToBytes32, buildPublicInputsBytes, bytesToHex, calculateFee, calculateRelayFee, cleanupStalePendingOperations, clearPendingDeposits, clearPendingWithdrawals, computeCommitment, computeMerkleRoot, computeNullifier, computeNullifierAsync, computeNullifierSync, computeOutputsHash, computeOutputsHashAsync, computeOutputsHashSync, computeProofForLatestDeposit, computeProofFromChain, computeSwapOutputsHash, computeSwapOutputsHashAsync, computeSwapOutputsHashSync, copyNoteToClipboard, createCloakError, createDepositInstruction, createLogger, deriveSpendKey, deriveViewKey, detectNetworkFromRpcUrl, downloadNote, encodeNoteSimple, encryptNoteForRecipient, exportKeys, exportNote, exportWalletKeys, filterNotesByNetwork, filterWithdrawableNotes, findNoteByCommitment, formatAmount, formatErrorForLogging, formatSol, generateCloakKeys, generateCommitment, generateCommitmentAsync, generateMasterSeed, generateNote, generateNoteFromWallet, generateWithdrawRegularProof, generateWithdrawSwapProof, getAddressExplorerUrl, getDefaultCircuitsPath, getDistributableAmount, getExplorerUrl, getNullifierPDA, getPendingOperationsSummary, getPublicKey, getPublicViewKey, getRecipientAmount, getRpcUrlForNetwork, getShieldPoolPDAs, getSwapStatePDA, getViewKey, hasPendingOperations, hexToBigint, hexToBytes, importKeys, importWalletKeys, isDebugEnabled, isRootNotFoundError, isValidHex, isValidRpcUrl, isValidSolanaAddress, isWithdrawable, keypairToAdapter, loadPendingDeposits, loadPendingWithdrawals, parseAmount, parseError, parseNote, parseTransactionError, poseidonHash, prepareEncryptedOutput, prepareEncryptedOutputForRecipient, proofToBytes, pubkeyToLimbs, randomBytes, readMerkleTreeState, removePendingDeposit, removePendingWithdrawal, savePendingDeposit, savePendingWithdrawal, scanNotesForWallet, sdkLogger, sendTransaction, serializeNote, setDebugMode, signTransaction, splitTo2Limbs, truncate, tryDecryptNote, updateNoteWithDeposit, updatePendingDeposit, updatePendingWithdrawal, validateDepositParams, validateNote, validateOutputsSum, validateTransfers, validateWalletConnected, validateWithdrawableNote, verifyAllCircuits, verifyCircuitIntegrity, withTiming };
package/dist/index.d.ts CHANGED
@@ -1753,6 +1753,7 @@ interface ShieldPoolPDAs {
1753
1753
  merkleTree: PublicKey;
1754
1754
  commitments: PublicKey;
1755
1755
  rootsRing: PublicKey;
1756
+ /** @deprecated Use getNullifierPDA() for the new per-nullifier PDA design */
1756
1757
  nullifierShard: PublicKey;
1757
1758
  treasury: PublicKey;
1758
1759
  }
@@ -1774,6 +1775,30 @@ interface ShieldPoolPDAs {
1774
1775
  * @param mint - Optional mint address (defaults to 32 zero bytes for native SOL)
1775
1776
  */
1776
1777
  declare function getShieldPoolPDAs(programId?: PublicKey, mint?: PublicKey): ShieldPoolPDAs;
1778
+ /**
1779
+ * Derive the nullifier PDA for a specific nullifier hash.
1780
+ *
1781
+ * With the new PDA-per-nullifier design, each nullifier has its own PDA
1782
+ * instead of being stored in a shared shard. The PDA is created when
1783
+ * the nullifier is used during withdrawal.
1784
+ *
1785
+ * Seeds: ["nullifier", nullifier_hash]
1786
+ *
1787
+ * @param nullifier - 32-byte nullifier hash
1788
+ * @param programId - Optional program ID (defaults to CLOAK_PROGRAM_ID)
1789
+ * @returns [PublicKey, bump] - The nullifier PDA and its bump seed
1790
+ */
1791
+ declare function getNullifierPDA(nullifier: Uint8Array | Buffer, programId?: PublicKey): [PublicKey, number];
1792
+ /**
1793
+ * Derive the swap state PDA for a given nullifier.
1794
+ *
1795
+ * Seeds: ["swap_state", nullifier_hash]
1796
+ *
1797
+ * @param nullifier - 32-byte nullifier hash
1798
+ * @param programId - Optional program ID (defaults to CLOAK_PROGRAM_ID)
1799
+ * @returns [PublicKey, bump] - The swap state PDA and its bump seed
1800
+ */
1801
+ declare function getSwapStatePDA(nullifier: Uint8Array | Buffer, programId?: PublicKey): [PublicKey, number];
1777
1802
 
1778
1803
  /**
1779
1804
  * On-chain Merkle proof computation
@@ -1838,6 +1863,11 @@ declare function computeProofForLatestDeposit(connection: Connection, merkleTree
1838
1863
  * as it doesn't require a backend prover service.
1839
1864
  */
1840
1865
 
1866
+ /**
1867
+ * Default URL for fetching circuit artifacts
1868
+ * These are served from the Cloak web app at https://cloak.ag
1869
+ */
1870
+ declare const DEFAULT_CIRCUITS_URL = "https://www.cloak.ag/circuits";
1841
1871
  interface WithdrawRegularInputs {
1842
1872
  root: bigint;
1843
1873
  nullifier: bigint;
@@ -1898,6 +1928,23 @@ declare function generateWithdrawRegularProof(inputs: WithdrawRegularInputs, cir
1898
1928
  * @param circuitsPath - Path or URL to circuits directory. In browser, use URL like '/circuits' or full URL.
1899
1929
  */
1900
1930
  declare function generateWithdrawSwapProof(inputs: WithdrawSwapInputs, circuitsPath: string): Promise<ProofResult>;
1931
+ /**
1932
+ * Check if circuits are available at the given path or URL
1933
+ * Supports both local file paths and remote URLs
1934
+ *
1935
+ * Note: For remote URLs, this returns true without checking (snarkjs will handle loading).
1936
+ * For local paths, it checks if the files exist on disk.
1937
+ */
1938
+ declare function areCircuitsAvailable(circuitsPath: string): Promise<boolean>;
1939
+ /**
1940
+ * Get default circuits path or URL
1941
+ *
1942
+ * Priority:
1943
+ * 1. CIRCUITS_PATH environment variable (if set)
1944
+ * 2. Local file paths (if available)
1945
+ * 3. Default remote URL (https://cloak.ag/circuits)
1946
+ */
1947
+ declare function getDefaultCircuitsPath(): Promise<string>;
1901
1948
  /**
1902
1949
  * Expected circuit hashes for verification
1903
1950
  * These are computed from the verification key files to ensure circuits match on-chain vkeys
@@ -2076,4 +2123,4 @@ declare function cleanupStalePendingOperations(maxAgeMs?: number): {
2076
2123
 
2077
2124
  declare const VERSION = "1.0.0";
2078
2125
 
2079
- export { CLOAK_PROGRAM_ID, type CircuitVerificationResult, type CloakConfig, CloakError, type CloakKeyPair, type CloakNote, CloakSDK, type DepositInstructionParams, type DepositOptions, type DepositResult, type DepositStatus, EXPECTED_CIRCUIT_HASHES, type EncryptedNote, type ErrorCategory, FIXED_FEE_LAMPORTS, type Groth16Proof, LAMPORTS_PER_SOL, LocalStorageAdapter, type LogLevel, type Logger, type MasterKey, type MaxLengthArray, MemoryStorageAdapter, type MerkleProof, type MerkleRootResponse, type Network, type NoteData, type OnchainMerkleProof, type PendingDeposit, type PendingWithdrawal, type ProofResult, RelayService, RootNotFoundError, ShieldPoolErrors, type ShieldPoolPDAs, type SpendKey, type StorageAdapter, type SwapOptions, type SwapParams, type SwapResult, type Transfer, type TransferOptions, type TransferResult, type TxStatus, type UserFriendlyError, VARIABLE_FEE_RATE, VERSION, type ViewKey, type WalletAdapter, type WithdrawOptions, type WithdrawRegularInputs, type WithdrawSubmissionResult, type WithdrawSwapInputs, bigintToBytes32, buildPublicInputsBytes, bytesToHex, calculateFee, calculateRelayFee, cleanupStalePendingOperations, clearPendingDeposits, clearPendingWithdrawals, computeCommitment, computeMerkleRoot, computeNullifier, computeNullifierAsync, computeNullifierSync, computeOutputsHash, computeOutputsHashAsync, computeOutputsHashSync, computeProofForLatestDeposit, computeProofFromChain, computeSwapOutputsHash, computeSwapOutputsHashAsync, computeSwapOutputsHashSync, copyNoteToClipboard, createCloakError, createDepositInstruction, createLogger, deriveSpendKey, deriveViewKey, detectNetworkFromRpcUrl, downloadNote, encodeNoteSimple, encryptNoteForRecipient, exportKeys, exportNote, exportWalletKeys, filterNotesByNetwork, filterWithdrawableNotes, findNoteByCommitment, formatAmount, formatErrorForLogging, formatSol, generateCloakKeys, generateCommitment, generateCommitmentAsync, generateMasterSeed, generateNote, generateNoteFromWallet, generateWithdrawRegularProof, generateWithdrawSwapProof, getAddressExplorerUrl, getDistributableAmount, getExplorerUrl, getPendingOperationsSummary, getPublicKey, getPublicViewKey, getRecipientAmount, getRpcUrlForNetwork, getShieldPoolPDAs, getViewKey, hasPendingOperations, hexToBigint, hexToBytes, importKeys, importWalletKeys, isDebugEnabled, isRootNotFoundError, isValidHex, isValidRpcUrl, isValidSolanaAddress, isWithdrawable, keypairToAdapter, loadPendingDeposits, loadPendingWithdrawals, parseAmount, parseError, parseNote, parseTransactionError, poseidonHash, prepareEncryptedOutput, prepareEncryptedOutputForRecipient, proofToBytes, pubkeyToLimbs, randomBytes, readMerkleTreeState, removePendingDeposit, removePendingWithdrawal, savePendingDeposit, savePendingWithdrawal, scanNotesForWallet, sdkLogger, sendTransaction, serializeNote, setDebugMode, signTransaction, splitTo2Limbs, truncate, tryDecryptNote, updateNoteWithDeposit, updatePendingDeposit, updatePendingWithdrawal, validateDepositParams, validateNote, validateOutputsSum, validateTransfers, validateWalletConnected, validateWithdrawableNote, verifyAllCircuits, verifyCircuitIntegrity, withTiming };
2126
+ export { CLOAK_PROGRAM_ID, type CircuitVerificationResult, type CloakConfig, CloakError, type CloakKeyPair, type CloakNote, CloakSDK, DEFAULT_CIRCUITS_URL, type DepositInstructionParams, type DepositOptions, type DepositResult, type DepositStatus, EXPECTED_CIRCUIT_HASHES, type EncryptedNote, type ErrorCategory, FIXED_FEE_LAMPORTS, type Groth16Proof, LAMPORTS_PER_SOL, LocalStorageAdapter, type LogLevel, type Logger, type MasterKey, type MaxLengthArray, MemoryStorageAdapter, type MerkleProof, type MerkleRootResponse, type Network, type NoteData, type OnchainMerkleProof, type PendingDeposit, type PendingWithdrawal, type ProofResult, RelayService, RootNotFoundError, ShieldPoolErrors, type ShieldPoolPDAs, type SpendKey, type StorageAdapter, type SwapOptions, type SwapParams, type SwapResult, type Transfer, type TransferOptions, type TransferResult, type TxStatus, type UserFriendlyError, VARIABLE_FEE_RATE, VERSION, type ViewKey, type WalletAdapter, type WithdrawOptions, type WithdrawRegularInputs, type WithdrawSubmissionResult, type WithdrawSwapInputs, areCircuitsAvailable, bigintToBytes32, buildPublicInputsBytes, bytesToHex, calculateFee, calculateRelayFee, cleanupStalePendingOperations, clearPendingDeposits, clearPendingWithdrawals, computeCommitment, computeMerkleRoot, computeNullifier, computeNullifierAsync, computeNullifierSync, computeOutputsHash, computeOutputsHashAsync, computeOutputsHashSync, computeProofForLatestDeposit, computeProofFromChain, computeSwapOutputsHash, computeSwapOutputsHashAsync, computeSwapOutputsHashSync, copyNoteToClipboard, createCloakError, createDepositInstruction, createLogger, deriveSpendKey, deriveViewKey, detectNetworkFromRpcUrl, downloadNote, encodeNoteSimple, encryptNoteForRecipient, exportKeys, exportNote, exportWalletKeys, filterNotesByNetwork, filterWithdrawableNotes, findNoteByCommitment, formatAmount, formatErrorForLogging, formatSol, generateCloakKeys, generateCommitment, generateCommitmentAsync, generateMasterSeed, generateNote, generateNoteFromWallet, generateWithdrawRegularProof, generateWithdrawSwapProof, getAddressExplorerUrl, getDefaultCircuitsPath, getDistributableAmount, getExplorerUrl, getNullifierPDA, getPendingOperationsSummary, getPublicKey, getPublicViewKey, getRecipientAmount, getRpcUrlForNetwork, getShieldPoolPDAs, getSwapStatePDA, getViewKey, hasPendingOperations, hexToBigint, hexToBytes, importKeys, importWalletKeys, isDebugEnabled, isRootNotFoundError, isValidHex, isValidRpcUrl, isValidSolanaAddress, isWithdrawable, keypairToAdapter, loadPendingDeposits, loadPendingWithdrawals, parseAmount, parseError, parseNote, parseTransactionError, poseidonHash, prepareEncryptedOutput, prepareEncryptedOutputForRecipient, proofToBytes, pubkeyToLimbs, randomBytes, readMerkleTreeState, removePendingDeposit, removePendingWithdrawal, savePendingDeposit, savePendingWithdrawal, scanNotesForWallet, sdkLogger, sendTransaction, serializeNote, setDebugMode, signTransaction, splitTo2Limbs, truncate, tryDecryptNote, updateNoteWithDeposit, updatePendingDeposit, updatePendingWithdrawal, validateDepositParams, validateNote, validateOutputsSum, validateTransfers, validateWalletConnected, validateWithdrawableNote, verifyAllCircuits, verifyCircuitIntegrity, withTiming };
package/dist/index.js CHANGED
@@ -1633,29 +1633,84 @@ function getShieldPoolPDAs(programId, mint) {
1633
1633
  treasury
1634
1634
  };
1635
1635
  }
1636
+ function getNullifierPDA(nullifier, programId) {
1637
+ const pid = programId || CLOAK_PROGRAM_ID;
1638
+ if (nullifier.length !== 32) {
1639
+ throw new Error(`Nullifier must be 32 bytes, got ${nullifier.length}`);
1640
+ }
1641
+ return PublicKey3.findProgramAddressSync(
1642
+ [Buffer.from("nullifier"), Buffer.from(nullifier)],
1643
+ pid
1644
+ );
1645
+ }
1646
+ function getSwapStatePDA(nullifier, programId) {
1647
+ const pid = programId || CLOAK_PROGRAM_ID;
1648
+ if (nullifier.length !== 32) {
1649
+ throw new Error(`Nullifier must be 32 bytes, got ${nullifier.length}`);
1650
+ }
1651
+ return PublicKey3.findProgramAddressSync(
1652
+ [Buffer.from("swap_state"), Buffer.from(nullifier)],
1653
+ pid
1654
+ );
1655
+ }
1636
1656
 
1637
1657
  // src/utils/proof-generation.ts
1638
1658
  import * as snarkjs from "snarkjs";
1639
1659
  var IS_REACT_NATIVE = typeof navigator !== "undefined" && navigator.product === "ReactNative";
1640
1660
  var IS_BROWSER = IS_REACT_NATIVE || typeof window !== "undefined" || typeof globalThis !== "undefined" && typeof globalThis.document !== "undefined";
1661
+ var DEFAULT_CIRCUITS_URL = "https://www.cloak.ag/circuits";
1662
+ function isUrl(path) {
1663
+ return path.startsWith("http://") || path.startsWith("https://");
1664
+ }
1665
+ async function fetchFileAsBuffer(url) {
1666
+ const response = await fetch(url);
1667
+ if (!response.ok) {
1668
+ throw new Error(`Failed to fetch ${url}: ${response.status} ${response.statusText}`);
1669
+ }
1670
+ const arrayBuffer = await response.arrayBuffer();
1671
+ return new Uint8Array(arrayBuffer);
1672
+ }
1641
1673
  var _nodePath = null;
1642
1674
  var _nodeFs = null;
1643
1675
  var _nodeCrypto = null;
1676
+ var _fs = null;
1677
+ var _path = null;
1678
+ async function loadNodeModules() {
1679
+ if (_fs && _path) {
1680
+ return { fs: _fs, path: _path };
1681
+ }
1682
+ if (IS_BROWSER) {
1683
+ throw new Error("Node.js modules not available in browser/React Native");
1684
+ }
1685
+ const [fsModule, pathModule] = await Promise.all([
1686
+ import("fs"),
1687
+ import("path")
1688
+ ]);
1689
+ _fs = fsModule;
1690
+ _path = pathModule;
1691
+ return { fs: _fs, path: _path };
1692
+ }
1644
1693
  function nodeRequire(moduleName) {
1645
1694
  if (IS_BROWSER) {
1646
1695
  throw new Error(`Node.js ${moduleName} module not available in browser/React Native`);
1647
1696
  }
1648
- const requireFunc = new Function("moduleName", "return require(moduleName)");
1649
- return requireFunc(moduleName);
1697
+ try {
1698
+ const requireFunc = new Function("moduleName", "return require(moduleName)");
1699
+ return requireFunc(moduleName);
1700
+ } catch {
1701
+ throw new Error(`Cannot load Node.js module ${moduleName} synchronously in ESM. Use async loadNodeModules() instead.`);
1702
+ }
1650
1703
  }
1651
1704
  async function getNodePath() {
1652
1705
  if (_nodePath) return _nodePath;
1653
- _nodePath = nodeRequire("path");
1706
+ const { path } = await loadNodeModules();
1707
+ _nodePath = path;
1654
1708
  return _nodePath;
1655
1709
  }
1656
1710
  async function getNodeFs() {
1657
1711
  if (_nodeFs) return _nodeFs;
1658
- _nodeFs = nodeRequire("fs");
1712
+ const { fs } = await loadNodeModules();
1713
+ _nodeFs = fs;
1659
1714
  return _nodeFs;
1660
1715
  }
1661
1716
  async function getNodeCrypto() {
@@ -1676,29 +1731,41 @@ async function fileExists(filePath) {
1676
1731
  }
1677
1732
  }
1678
1733
  try {
1679
- const nodeFs = nodeRequire("fs");
1680
- return nodeFs.existsSync(filePath);
1734
+ const { fs } = await loadNodeModules();
1735
+ return fs.existsSync(filePath);
1681
1736
  } catch {
1682
1737
  return false;
1683
1738
  }
1684
1739
  }
1685
1740
  async function generateWithdrawRegularProof(inputs, circuitsPath) {
1686
- let wasmPath;
1687
- let zkeyPath;
1741
+ let wasmInput;
1742
+ let zkeyInput;
1743
+ const useUrl = isUrl(circuitsPath);
1688
1744
  if (IS_BROWSER) {
1689
- wasmPath = `${circuitsPath}/withdraw_regular_js/withdraw_regular.wasm`;
1690
- zkeyPath = `${circuitsPath}/withdraw_regular_final.zkey`;
1745
+ wasmInput = `${circuitsPath}/withdraw_regular_js/withdraw_regular.wasm`;
1746
+ zkeyInput = `${circuitsPath}/withdraw_regular_final.zkey`;
1747
+ } else if (useUrl) {
1748
+ const wasmUrl = `${circuitsPath}/withdraw_regular_js/withdraw_regular.wasm`;
1749
+ const zkeyUrl = `${circuitsPath}/withdraw_regular_final.zkey`;
1750
+ const [wasmData, zkeyData] = await Promise.all([
1751
+ fetchFileAsBuffer(wasmUrl),
1752
+ fetchFileAsBuffer(zkeyUrl)
1753
+ ]);
1754
+ wasmInput = wasmData;
1755
+ zkeyInput = zkeyData;
1691
1756
  } else {
1692
- wasmPath = joinPath(circuitsPath, "build", "withdraw_regular_js", "withdraw_regular.wasm");
1693
- zkeyPath = joinPath(circuitsPath, "build", "withdraw_regular_final.zkey");
1757
+ const wasmPath = joinPath(circuitsPath, "build", "withdraw_regular_js", "withdraw_regular.wasm");
1758
+ const zkeyPath = joinPath(circuitsPath, "build", "withdraw_regular_final.zkey");
1694
1759
  const wasmExists = await fileExists(wasmPath);
1695
1760
  const zkeyExists = await fileExists(zkeyPath);
1696
1761
  if (!wasmExists) {
1697
- throw new Error(`Circuit WASM not found at ${wasmPath}. Run 'just circuits-compile' in packages-new/circuits first.`);
1762
+ throw new Error(`Circuit WASM not found at ${wasmPath}. Run 'just circuits-compile' in packages/ first.`);
1698
1763
  }
1699
1764
  if (!zkeyExists) {
1700
1765
  throw new Error(`Circuit zkey not found at ${zkeyPath}. Run circuit setup first.`);
1701
1766
  }
1767
+ wasmInput = wasmPath;
1768
+ zkeyInput = zkeyPath;
1702
1769
  }
1703
1770
  const circuitInputs = {
1704
1771
  // Public signals
@@ -1722,7 +1789,7 @@ async function generateWithdrawRegularProof(inputs, circuitsPath) {
1722
1789
  var_fee: inputs.var_fee.toString(),
1723
1790
  rem: inputs.rem.toString()
1724
1791
  };
1725
- const { proof, publicSignals } = await snarkjs.groth16.fullProve(circuitInputs, wasmPath, zkeyPath);
1792
+ const { proof, publicSignals } = await snarkjs.groth16.fullProve(circuitInputs, wasmInput, zkeyInput);
1726
1793
  const proofBytes = proofToBytes(proof);
1727
1794
  return {
1728
1795
  proof,
@@ -1733,22 +1800,34 @@ async function generateWithdrawRegularProof(inputs, circuitsPath) {
1733
1800
  };
1734
1801
  }
1735
1802
  async function generateWithdrawSwapProof(inputs, circuitsPath) {
1736
- let wasmPath;
1737
- let zkeyPath;
1803
+ let wasmInput;
1804
+ let zkeyInput;
1805
+ const useUrl = isUrl(circuitsPath);
1738
1806
  if (IS_BROWSER) {
1739
- wasmPath = `${circuitsPath}/withdraw_swap_js/withdraw_swap.wasm`;
1740
- zkeyPath = `${circuitsPath}/withdraw_swap_final.zkey`;
1807
+ wasmInput = `${circuitsPath}/withdraw_swap_js/withdraw_swap.wasm`;
1808
+ zkeyInput = `${circuitsPath}/withdraw_swap_final.zkey`;
1809
+ } else if (useUrl) {
1810
+ const wasmUrl = `${circuitsPath}/withdraw_swap_js/withdraw_swap.wasm`;
1811
+ const zkeyUrl = `${circuitsPath}/withdraw_swap_final.zkey`;
1812
+ const [wasmData, zkeyData] = await Promise.all([
1813
+ fetchFileAsBuffer(wasmUrl),
1814
+ fetchFileAsBuffer(zkeyUrl)
1815
+ ]);
1816
+ wasmInput = wasmData;
1817
+ zkeyInput = zkeyData;
1741
1818
  } else {
1742
- wasmPath = joinPath(circuitsPath, "build", "withdraw_swap_js", "withdraw_swap.wasm");
1743
- zkeyPath = joinPath(circuitsPath, "build", "withdraw_swap_final.zkey");
1819
+ const wasmPath = joinPath(circuitsPath, "build", "withdraw_swap_js", "withdraw_swap.wasm");
1820
+ const zkeyPath = joinPath(circuitsPath, "build", "withdraw_swap_final.zkey");
1744
1821
  const wasmExists = await fileExists(wasmPath);
1745
1822
  const zkeyExists = await fileExists(zkeyPath);
1746
1823
  if (!wasmExists) {
1747
- throw new Error(`Circuit WASM not found at ${wasmPath}. Run 'just circuits-compile' in packages-new/circuits first.`);
1824
+ throw new Error(`Circuit WASM not found at ${wasmPath}. Run 'just circuits-compile' in packages/ first.`);
1748
1825
  }
1749
1826
  if (!zkeyExists) {
1750
1827
  throw new Error(`Circuit zkey not found at ${zkeyPath}. Run circuit setup first.`);
1751
1828
  }
1829
+ wasmInput = wasmPath;
1830
+ zkeyInput = zkeyPath;
1752
1831
  }
1753
1832
  const sk = splitTo2Limbs(inputs.sk_spend);
1754
1833
  const r = splitTo2Limbs(inputs.r);
@@ -1777,8 +1856,8 @@ async function generateWithdrawSwapProof(inputs, circuitsPath) {
1777
1856
  };
1778
1857
  const { proof, publicSignals } = await snarkjs.groth16.fullProve(
1779
1858
  circuitInputs,
1780
- wasmPath,
1781
- zkeyPath
1859
+ wasmInput,
1860
+ zkeyInput
1782
1861
  );
1783
1862
  const proofBytes = proofToBytes(proof);
1784
1863
  return {
@@ -1790,8 +1869,14 @@ async function generateWithdrawSwapProof(inputs, circuitsPath) {
1790
1869
  };
1791
1870
  }
1792
1871
  async function areCircuitsAvailable(circuitsPath) {
1872
+ if (!circuitsPath || circuitsPath === "") {
1873
+ return false;
1874
+ }
1875
+ if (isUrl(circuitsPath)) {
1876
+ return true;
1877
+ }
1793
1878
  if (IS_BROWSER) {
1794
- return Boolean(circuitsPath && circuitsPath !== "");
1879
+ return true;
1795
1880
  }
1796
1881
  const wasmPath = joinPath(circuitsPath, "build", "withdraw_regular_js", "withdraw_regular.wasm");
1797
1882
  const zkeyPath = joinPath(circuitsPath, "build", "withdraw_regular_final.zkey");
@@ -1800,22 +1885,25 @@ async function areCircuitsAvailable(circuitsPath) {
1800
1885
  return wasmExists && zkeyExists;
1801
1886
  }
1802
1887
  async function getDefaultCircuitsPath() {
1888
+ if (typeof process !== "undefined" && process.env?.CIRCUITS_PATH) {
1889
+ return process.env.CIRCUITS_PATH;
1890
+ }
1803
1891
  if (IS_BROWSER) {
1804
1892
  return "/circuits";
1805
1893
  }
1806
1894
  if (typeof process === "undefined" || !process.cwd) {
1807
- return "/circuits";
1895
+ return DEFAULT_CIRCUITS_URL;
1808
1896
  }
1809
1897
  let nodePath;
1810
1898
  try {
1811
1899
  nodePath = await getNodePath();
1812
- } catch {
1813
- return "/circuits";
1900
+ } catch (e) {
1901
+ return DEFAULT_CIRCUITS_URL;
1814
1902
  }
1815
1903
  const possiblePaths = [
1816
- nodePath.resolve(process.cwd(), "../../packages-new/circuits"),
1817
- nodePath.resolve(process.cwd(), "../packages-new/circuits"),
1818
- nodePath.resolve(process.cwd(), "packages-new/circuits"),
1904
+ nodePath.resolve(process.cwd(), "../../packages/circuits"),
1905
+ nodePath.resolve(process.cwd(), "../packages/circuits"),
1906
+ nodePath.resolve(process.cwd(), "packages/circuits"),
1819
1907
  nodePath.resolve(process.cwd(), "../../circuits"),
1820
1908
  nodePath.resolve(process.cwd(), "../circuits")
1821
1909
  ];
@@ -1824,7 +1912,7 @@ async function getDefaultCircuitsPath() {
1824
1912
  return p;
1825
1913
  }
1826
1914
  }
1827
- return possiblePaths[0];
1915
+ return DEFAULT_CIRCUITS_URL;
1828
1916
  }
1829
1917
  var EXPECTED_CIRCUIT_HASHES = {
1830
1918
  // SHA-256 of the verification key JSON from withdraw_regular circuit
@@ -3442,6 +3530,7 @@ export {
3442
3530
  CLOAK_PROGRAM_ID,
3443
3531
  CloakError,
3444
3532
  CloakSDK,
3533
+ DEFAULT_CIRCUITS_URL,
3445
3534
  EXPECTED_CIRCUIT_HASHES,
3446
3535
  FIXED_FEE_LAMPORTS,
3447
3536
  LAMPORTS_PER_SOL,
@@ -3452,6 +3541,7 @@ export {
3452
3541
  ShieldPoolErrors,
3453
3542
  VARIABLE_FEE_RATE,
3454
3543
  VERSION,
3544
+ areCircuitsAvailable,
3455
3545
  bigintToBytes32,
3456
3546
  buildPublicInputsBytes,
3457
3547
  bytesToHex,
@@ -3501,14 +3591,17 @@ export {
3501
3591
  generateWithdrawRegularProof,
3502
3592
  generateWithdrawSwapProof,
3503
3593
  getAddressExplorerUrl,
3594
+ getDefaultCircuitsPath,
3504
3595
  getDistributableAmount2 as getDistributableAmount,
3505
3596
  getExplorerUrl,
3597
+ getNullifierPDA,
3506
3598
  getPendingOperationsSummary,
3507
3599
  getPublicKey,
3508
3600
  getPublicViewKey,
3509
3601
  getRecipientAmount,
3510
3602
  getRpcUrlForNetwork,
3511
3603
  getShieldPoolPDAs,
3604
+ getSwapStatePDA,
3512
3605
  getViewKey,
3513
3606
  hasPendingOperations,
3514
3607
  hexToBigint,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloak.ag/sdk",
3
3
  "description": "TypeScript SDK for Cloak",
4
- "version": "1.0.7",
4
+ "version": "1.0.8",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
7
7
  "module": "dist/index.js",