@cloak.ag/sdk 1.0.0 → 1.0.2

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/README.md CHANGED
@@ -56,23 +56,6 @@ const withdrawResult = await sdk.withdraw(
56
56
  console.log("Withdrawn! TX:", withdrawResult.signature);
57
57
  ```
58
58
 
59
- ## API Configuration
60
-
61
- The SDK connects to `https://api.cloak.ag` by default. You can override this:
62
-
63
- ```typescript
64
- const sdk = new CloakSDK({
65
- keypairBytes: keypair.secretKey,
66
- network: "devnet",
67
- indexerUrl: "http://localhost:3001", // Custom indexer
68
- relayUrl: "http://localhost:3002", // Custom relay
69
- });
70
- ```
71
-
72
- Or use environment variables:
73
- - `CLOAK_INDEXER_URL` - Override indexer URL
74
- - `CLOAK_RELAY_URL` - Override relay URL
75
-
76
59
  ## Core Methods
77
60
 
78
61
  ### Deposit
@@ -173,7 +156,7 @@ try {
173
156
 
174
157
  - Website: [https://cloak.ag](https://cloak.ag)
175
158
  - Documentation: [https://docs.cloak.ag](https://docs.cloak.ag)
176
- - GitHub: [https://github.com/cloak-labs/sdk](https://github.com/cloak-labs/sdk)
159
+ - GitHub: [https://github.com/cloak-ag/sdk](https://github.com/cloak-ag/sdk)
177
160
 
178
161
  ## License
179
162
 
package/dist/index.cjs CHANGED
@@ -83,6 +83,8 @@ __export(index_exports, {
83
83
  generateMasterSeed: () => generateMasterSeed,
84
84
  generateNote: () => generateNote,
85
85
  generateNoteFromWallet: () => generateNoteFromWallet,
86
+ generateWithdrawRegularProof: () => generateWithdrawRegularProof,
87
+ generateWithdrawSwapProof: () => generateWithdrawSwapProof,
86
88
  getAddressExplorerUrl: () => getAddressExplorerUrl,
87
89
  getDistributableAmount: () => getDistributableAmount2,
88
90
  getExplorerUrl: () => getExplorerUrl,
@@ -1333,7 +1335,7 @@ var ArtifactProverService = class {
1333
1335
  lastProgress = progress;
1334
1336
  options?.onProgress?.(progress);
1335
1337
  }
1336
- await new Promise((resolve2) => setTimeout(resolve2, pollInterval));
1338
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
1337
1339
  }
1338
1340
  const errorMessage = `Proof generation timed out after ${actualTimeout}ms`;
1339
1341
  options?.onError?.(errorMessage);
@@ -1627,7 +1629,7 @@ var RelayService = class {
1627
1629
  * Sleep utility
1628
1630
  */
1629
1631
  sleep(ms) {
1630
- return new Promise((resolve2) => setTimeout(resolve2, ms));
1632
+ return new Promise((resolve) => setTimeout(resolve, ms));
1631
1633
  }
1632
1634
  };
1633
1635
 
@@ -1992,16 +1994,57 @@ function getShieldPoolPDAs(programId, mint) {
1992
1994
 
1993
1995
  // src/utils/proof-generation.ts
1994
1996
  var snarkjs = __toESM(require("snarkjs"), 1);
1995
- var path = __toESM(require("path"), 1);
1996
- var fs = __toESM(require("fs"), 1);
1997
- async function generateWithdrawRegularProof(inputs, circuitsPath) {
1998
- const wasmPath = path.join(circuitsPath, "build", "withdraw_regular_js", "withdraw_regular.wasm");
1999
- const zkeyPath = path.join(circuitsPath, "build", "withdraw_regular_final.zkey");
2000
- if (!fs.existsSync(wasmPath)) {
2001
- throw new Error(`Circuit WASM not found at ${wasmPath}. Run 'just circuits-compile' in packages-new/circuits first.`);
1997
+ var path = null;
1998
+ var fs = null;
1999
+ async function loadNodeModules() {
2000
+ const isBrowser = typeof window !== "undefined" || typeof globalThis !== "undefined" && globalThis.window;
2001
+ if (!isBrowser && typeof process !== "undefined" && process.versions?.node) {
2002
+ if (!path) {
2003
+ path = await import("path");
2004
+ }
2005
+ if (!fs) {
2006
+ fs = await import("fs");
2007
+ }
2008
+ return { path, fs };
2002
2009
  }
2003
- if (!fs.existsSync(zkeyPath)) {
2004
- throw new Error(`Circuit zkey not found at ${zkeyPath}. Run circuit setup first.`);
2010
+ return { path: null, fs: null };
2011
+ }
2012
+ function joinPath(...parts) {
2013
+ const isBrowser = typeof window !== "undefined" || typeof globalThis !== "undefined" && globalThis.window;
2014
+ if (!isBrowser && path) {
2015
+ return path.join(...parts);
2016
+ }
2017
+ return parts.join("/").replace(/\/+/g, "/");
2018
+ }
2019
+ async function fileExists(filePath) {
2020
+ const { fs: fs2 } = await loadNodeModules();
2021
+ if (fs2) {
2022
+ try {
2023
+ return fs2.existsSync(filePath);
2024
+ } catch {
2025
+ return false;
2026
+ }
2027
+ }
2028
+ return false;
2029
+ }
2030
+ async function generateWithdrawRegularProof(inputs, circuitsPath) {
2031
+ const isBrowser = typeof window !== "undefined" || typeof globalThis !== "undefined" && globalThis.window;
2032
+ let wasmPath;
2033
+ let zkeyPath;
2034
+ if (isBrowser) {
2035
+ wasmPath = `${circuitsPath}/withdraw_regular_js/withdraw_regular.wasm`;
2036
+ zkeyPath = `${circuitsPath}/withdraw_regular_final.zkey`;
2037
+ } else {
2038
+ wasmPath = joinPath(circuitsPath, "build", "withdraw_regular_js", "withdraw_regular.wasm");
2039
+ zkeyPath = joinPath(circuitsPath, "build", "withdraw_regular_final.zkey");
2040
+ const wasmExists = await fileExists(wasmPath);
2041
+ const zkeyExists = await fileExists(zkeyPath);
2042
+ if (!wasmExists) {
2043
+ throw new Error(`Circuit WASM not found at ${wasmPath}. Run 'just circuits-compile' in packages-new/circuits first.`);
2044
+ }
2045
+ if (!zkeyExists) {
2046
+ throw new Error(`Circuit zkey not found at ${zkeyPath}. Run circuit setup first.`);
2047
+ }
2005
2048
  }
2006
2049
  const circuitInputs = {
2007
2050
  // Public signals
@@ -2040,13 +2083,23 @@ async function generateWithdrawRegularProof(inputs, circuitsPath) {
2040
2083
  };
2041
2084
  }
2042
2085
  async function generateWithdrawSwapProof(inputs, circuitsPath) {
2043
- const wasmPath = path.join(circuitsPath, "build", "withdraw_swap_js", "withdraw_swap.wasm");
2044
- const zkeyPath = path.join(circuitsPath, "build", "withdraw_swap_final.zkey");
2045
- if (!fs.existsSync(wasmPath)) {
2046
- throw new Error(`Circuit WASM not found at ${wasmPath}. Run 'just circuits-compile' in packages-new/circuits first.`);
2047
- }
2048
- if (!fs.existsSync(zkeyPath)) {
2049
- throw new Error(`Circuit zkey not found at ${zkeyPath}. Run circuit setup first.`);
2086
+ const isBrowser = typeof window !== "undefined" || typeof globalThis !== "undefined" && globalThis.window;
2087
+ let wasmPath;
2088
+ let zkeyPath;
2089
+ if (isBrowser) {
2090
+ wasmPath = `${circuitsPath}/withdraw_swap_js/withdraw_swap.wasm`;
2091
+ zkeyPath = `${circuitsPath}/withdraw_swap_final.zkey`;
2092
+ } else {
2093
+ wasmPath = joinPath(circuitsPath, "build", "withdraw_swap_js", "withdraw_swap.wasm");
2094
+ zkeyPath = joinPath(circuitsPath, "build", "withdraw_swap_final.zkey");
2095
+ const wasmExists = await fileExists(wasmPath);
2096
+ const zkeyExists = await fileExists(zkeyPath);
2097
+ if (!wasmExists) {
2098
+ throw new Error(`Circuit WASM not found at ${wasmPath}. Run 'just circuits-compile' in packages-new/circuits first.`);
2099
+ }
2100
+ if (!zkeyExists) {
2101
+ throw new Error(`Circuit zkey not found at ${zkeyPath}. Run circuit setup first.`);
2102
+ }
2050
2103
  }
2051
2104
  const sk = splitTo2Limbs(inputs.sk_spend);
2052
2105
  const r = splitTo2Limbs(inputs.r);
@@ -2087,21 +2140,31 @@ async function generateWithdrawSwapProof(inputs, circuitsPath) {
2087
2140
  // Not used, kept for compatibility
2088
2141
  };
2089
2142
  }
2090
- function areCircuitsAvailable(circuitsPath) {
2091
- const wasmPath = path.join(circuitsPath, "build", "withdraw_regular_js", "withdraw_regular.wasm");
2092
- const zkeyPath = path.join(circuitsPath, "build", "withdraw_regular_final.zkey");
2093
- return fs.existsSync(wasmPath) && fs.existsSync(zkeyPath);
2143
+ async function areCircuitsAvailable(circuitsPath) {
2144
+ const wasmPath = joinPath(circuitsPath, "build", "withdraw_regular_js", "withdraw_regular.wasm");
2145
+ const zkeyPath = joinPath(circuitsPath, "build", "withdraw_regular_final.zkey");
2146
+ const wasmExists = await fileExists(wasmPath);
2147
+ const zkeyExists = await fileExists(zkeyPath);
2148
+ return wasmExists && zkeyExists;
2094
2149
  }
2095
- function getDefaultCircuitsPath() {
2150
+ async function getDefaultCircuitsPath() {
2151
+ const isBrowser = typeof window !== "undefined" || typeof globalThis !== "undefined" && globalThis.window;
2152
+ if (isBrowser) {
2153
+ return "/circuits";
2154
+ }
2155
+ const { path: path2 } = await loadNodeModules();
2156
+ if (!path2 || typeof process === "undefined" || !process.cwd) {
2157
+ return "/circuits";
2158
+ }
2096
2159
  const possiblePaths = [
2097
- path.resolve(process.cwd(), "../../packages-new/circuits"),
2098
- path.resolve(process.cwd(), "../packages-new/circuits"),
2099
- path.resolve(process.cwd(), "packages-new/circuits"),
2100
- path.resolve(process.cwd(), "../../circuits"),
2101
- path.resolve(process.cwd(), "../circuits")
2160
+ path2.resolve(process.cwd(), "../../packages-new/circuits"),
2161
+ path2.resolve(process.cwd(), "../packages-new/circuits"),
2162
+ path2.resolve(process.cwd(), "packages-new/circuits"),
2163
+ path2.resolve(process.cwd(), "../../circuits"),
2164
+ path2.resolve(process.cwd(), "../circuits")
2102
2165
  ];
2103
2166
  for (const p of possiblePaths) {
2104
- if (areCircuitsAvailable(p)) {
2167
+ if (await areCircuitsAvailable(p)) {
2105
2168
  return p;
2106
2169
  }
2107
2170
  }
@@ -2113,23 +2176,38 @@ var CLOAK_PROGRAM_ID = new import_web36.PublicKey("c1oak6tetxYnNfvXKFkpn1d98FxtK
2113
2176
  var CLOAK_API_URL = "https://api.cloak.ag";
2114
2177
  var CloakSDK = class {
2115
2178
  /**
2116
- * Create a new Cloak SDK client
2179
+ * Create a new Cloak SDK client
2117
2180
  *
2118
2181
  * @param config - Client configuration
2119
2182
  *
2120
- * @example
2183
+ * @example Node.js mode (with keypair)
2121
2184
  * ```typescript
2122
2185
  * const sdk = new CloakSDK({
2123
2186
  * keypairBytes: keypair.secretKey,
2124
2187
  * network: "devnet"
2125
- * });
2188
+ * });
2189
+ * ```
2190
+ *
2191
+ * @example Browser mode (with wallet adapter)
2192
+ * ```typescript
2193
+ * const sdk = new CloakSDK({
2194
+ * wallet: walletAdapter,
2195
+ * network: "devnet"
2196
+ * });
2197
+ * ```
2126
2198
  */
2127
2199
  constructor(config) {
2128
- this.keypair = import_web36.Keypair.fromSecretKey(config.keypairBytes);
2200
+ if (!config.keypairBytes && !config.wallet) {
2201
+ throw new Error("Must provide either keypairBytes (Node.js) or wallet (Browser)");
2202
+ }
2203
+ if (config.keypairBytes) {
2204
+ this.keypair = import_web36.Keypair.fromSecretKey(config.keypairBytes);
2205
+ }
2206
+ this.wallet = config.wallet;
2129
2207
  this.cloakKeys = config.cloakKeys;
2130
2208
  this.storage = config.storage || new MemoryStorageAdapter();
2131
- const indexerUrl = config.indexerUrl || process.env.CLOAK_INDEXER_URL || CLOAK_API_URL;
2132
- const relayUrl = config.relayUrl || process.env.CLOAK_RELAY_URL || CLOAK_API_URL;
2209
+ const indexerUrl = config.indexerUrl || typeof process !== "undefined" && process.env?.CLOAK_INDEXER_URL || CLOAK_API_URL;
2210
+ const relayUrl = config.relayUrl || typeof process !== "undefined" && process.env?.CLOAK_RELAY_URL || CLOAK_API_URL;
2133
2211
  this.indexer = new IndexerService(indexerUrl);
2134
2212
  this.artifactProver = new ArtifactProverService(indexerUrl, 5 * 60 * 1e3, 2e3);
2135
2213
  this.relay = new RelayService(relayUrl);
@@ -2157,6 +2235,24 @@ var CloakSDK = class {
2157
2235
  treasuryAddress: treasury
2158
2236
  };
2159
2237
  }
2238
+ /**
2239
+ * Get the public key for deposits (from keypair or wallet)
2240
+ */
2241
+ getPublicKey() {
2242
+ if (this.keypair) {
2243
+ return this.keypair.publicKey;
2244
+ }
2245
+ if (this.wallet?.publicKey) {
2246
+ return this.wallet.publicKey;
2247
+ }
2248
+ throw new Error("No public key available - wallet not connected or keypair not provided");
2249
+ }
2250
+ /**
2251
+ * Check if the SDK is using a wallet adapter
2252
+ */
2253
+ isWalletMode() {
2254
+ return !!this.wallet && !this.keypair;
2255
+ }
2160
2256
  /**
2161
2257
  * Deposit SOL into the Cloak protocol
2162
2258
  *
@@ -2197,7 +2293,8 @@ var CloakSDK = class {
2197
2293
  throw new Error("Note has already been deposited");
2198
2294
  }
2199
2295
  }
2200
- const balance = await connection.getBalance(this.keypair.publicKey);
2296
+ const payerPubkey = this.getPublicKey();
2297
+ const balance = await connection.getBalance(payerPubkey);
2201
2298
  const requiredAmount = note.amount + 5e3;
2202
2299
  if (balance < requiredAmount) {
2203
2300
  throw new Error(
@@ -2208,7 +2305,7 @@ var CloakSDK = class {
2208
2305
  const programId = this.config.programId || CLOAK_PROGRAM_ID;
2209
2306
  const depositIx = createDepositInstruction({
2210
2307
  programId,
2211
- payer: this.keypair.publicKey,
2308
+ payer: payerPubkey,
2212
2309
  pool: this.config.poolAddress,
2213
2310
  merkleTree: this.config.merkleTreeAddress,
2214
2311
  amount: note.amount,
@@ -2216,7 +2313,7 @@ var CloakSDK = class {
2216
2313
  });
2217
2314
  const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
2218
2315
  const transaction = new import_web36.Transaction({
2219
- feePayer: this.keypair.publicKey,
2316
+ feePayer: payerPubkey,
2220
2317
  blockhash,
2221
2318
  lastValidBlockHeight
2222
2319
  }).add(depositIx);
@@ -2231,11 +2328,22 @@ ${logs}`
2231
2328
  );
2232
2329
  }
2233
2330
  }
2234
- const signature = await connection.sendTransaction(transaction, [this.keypair], {
2235
- skipPreflight: options?.skipPreflight || false,
2236
- preflightCommitment: "confirmed",
2237
- maxRetries: 3
2238
- });
2331
+ let signature;
2332
+ if (this.wallet?.sendTransaction) {
2333
+ signature = await this.wallet.sendTransaction(transaction, connection, {
2334
+ skipPreflight: options?.skipPreflight || false,
2335
+ preflightCommitment: "confirmed",
2336
+ maxRetries: 3
2337
+ });
2338
+ } else if (this.keypair) {
2339
+ signature = await connection.sendTransaction(transaction, [this.keypair], {
2340
+ skipPreflight: options?.skipPreflight || false,
2341
+ preflightCommitment: "confirmed",
2342
+ maxRetries: 3
2343
+ });
2344
+ } else {
2345
+ throw new Error("No signing method available - provide keypair or wallet");
2346
+ }
2239
2347
  const confirmation = await connection.confirmTransaction({
2240
2348
  signature,
2241
2349
  blockhash,
@@ -2297,13 +2405,13 @@ ${logs}`
2297
2405
  break;
2298
2406
  } else if (response.status === 404 && attempt < maxRetries2 - 1) {
2299
2407
  const delay = Math.min(initialRetryDelay2 * (attempt + 1), 2e3);
2300
- await new Promise((resolve2) => setTimeout(resolve2, delay));
2408
+ await new Promise((resolve) => setTimeout(resolve, delay));
2301
2409
  continue;
2302
2410
  }
2303
2411
  } catch (e) {
2304
2412
  if (attempt < maxRetries2 - 1) {
2305
2413
  const delay = Math.min(initialRetryDelay2 * (attempt + 1), 2e3);
2306
- await new Promise((resolve2) => setTimeout(resolve2, delay));
2414
+ await new Promise((resolve) => setTimeout(resolve, delay));
2307
2415
  continue;
2308
2416
  }
2309
2417
  }
@@ -2336,7 +2444,7 @@ ${logs}`
2336
2444
  const errorMessage = error instanceof Error ? error.message : String(error);
2337
2445
  if (errorMessage.includes("404") && attempt < maxRetries - 1) {
2338
2446
  const delay = Math.min(initialRetryDelay * (attempt + 1), 2e3);
2339
- await new Promise((resolve2) => setTimeout(resolve2, delay));
2447
+ await new Promise((resolve) => setTimeout(resolve, delay));
2340
2448
  continue;
2341
2449
  }
2342
2450
  throw error;
@@ -2462,8 +2570,8 @@ ${logs}`
2462
2570
  throw new Error(`Merkle proof path element at position ${i} must be 64 hex characters (32 bytes)`);
2463
2571
  }
2464
2572
  }
2465
- const circuitsPath = process.env.CIRCUITS_PATH || getDefaultCircuitsPath();
2466
- const useDirectProof = areCircuitsAvailable(circuitsPath);
2573
+ const circuitsPath = typeof process !== "undefined" && process.env?.CIRCUITS_PATH || await getDefaultCircuitsPath();
2574
+ const useDirectProof = await areCircuitsAvailable(circuitsPath);
2467
2575
  let proofHex;
2468
2576
  let finalPublicInputs;
2469
2577
  if (useDirectProof) {
@@ -2760,8 +2868,8 @@ Note details: leafIndex=${note.leafIndex}, root=${merkleRoot.slice(0, 16)}..., n
2760
2868
  if (!merkleProof.pathElements || merkleProof.pathElements.length === 0) {
2761
2869
  throw new Error("Merkle proof is invalid: missing path elements");
2762
2870
  }
2763
- const circuitsPath = process.env.CIRCUITS_PATH || getDefaultCircuitsPath();
2764
- const useDirectProof = areCircuitsAvailable(circuitsPath);
2871
+ const circuitsPath = typeof process !== "undefined" && process.env?.CIRCUITS_PATH || await getDefaultCircuitsPath();
2872
+ const useDirectProof = await areCircuitsAvailable(circuitsPath);
2765
2873
  let proofHex;
2766
2874
  let finalPublicInputs;
2767
2875
  if (useDirectProof) {
@@ -3664,6 +3772,8 @@ var VERSION = "1.0.0";
3664
3772
  generateMasterSeed,
3665
3773
  generateNote,
3666
3774
  generateNoteFromWallet,
3775
+ generateWithdrawRegularProof,
3776
+ generateWithdrawSwapProof,
3667
3777
  getAddressExplorerUrl,
3668
3778
  getDistributableAmount,
3669
3779
  getExplorerUrl,
package/dist/index.d.cts CHANGED
@@ -505,10 +505,15 @@ declare const CLOAK_PROGRAM_ID: PublicKey;
505
505
  *
506
506
  * Provides high-level API for interacting with the Cloak protocol,
507
507
  * including deposits, withdrawals, and private transfers.
508
+ *
509
+ * Supports two modes:
510
+ * 1. Node.js mode with keypairBytes - for scripts and backend services
511
+ * 2. Wallet adapter mode - for browser applications with wallet integration
508
512
  */
509
513
  declare class CloakSDK {
510
514
  private config;
511
- private keypair;
515
+ private keypair?;
516
+ private wallet?;
512
517
  private cloakKeys?;
513
518
  private indexer;
514
519
  private artifactProver;
@@ -516,19 +521,31 @@ declare class CloakSDK {
516
521
  private depositRecovery;
517
522
  private storage;
518
523
  /**
519
- * Create a new Cloak SDK client
524
+ * Create a new Cloak SDK client
520
525
  *
521
526
  * @param config - Client configuration
522
527
  *
523
- * @example
528
+ * @example Node.js mode (with keypair)
524
529
  * ```typescript
525
530
  * const sdk = new CloakSDK({
526
531
  * keypairBytes: keypair.secretKey,
527
532
  * network: "devnet"
528
533
  * });
534
+ * ```
535
+ *
536
+ * @example Browser mode (with wallet adapter)
537
+ * ```typescript
538
+ * const sdk = new CloakSDK({
539
+ * wallet: walletAdapter,
540
+ * network: "devnet"
541
+ * });
542
+ * ```
529
543
  */
530
544
  constructor(config: {
531
- keypairBytes: Uint8Array;
545
+ /** Keypair bytes for signing (Node.js mode) */
546
+ keypairBytes?: Uint8Array;
547
+ /** Wallet adapter for signing (Browser mode) */
548
+ wallet?: WalletAdapter;
532
549
  network?: Network;
533
550
  cloakKeys?: CloakKeyPair;
534
551
  storage?: StorageAdapter;
@@ -536,6 +553,14 @@ declare class CloakSDK {
536
553
  indexerUrl?: string;
537
554
  relayUrl?: string;
538
555
  });
556
+ /**
557
+ * Get the public key for deposits (from keypair or wallet)
558
+ */
559
+ getPublicKey(): PublicKey;
560
+ /**
561
+ * Check if the SDK is using a wallet adapter
562
+ */
563
+ isWalletMode(): boolean;
539
564
  /**
540
565
  * Deposit SOL into the Cloak protocol
541
566
  *
@@ -1979,6 +2004,77 @@ interface ShieldPoolPDAs {
1979
2004
  */
1980
2005
  declare function getShieldPoolPDAs(programId?: PublicKey, mint?: PublicKey): ShieldPoolPDAs;
1981
2006
 
2007
+ /**
2008
+ * Direct Circom WASM Proof Generation
2009
+ *
2010
+ * This module provides direct proof generation using snarkjs and Circom WASM,
2011
+ * matching the approach used in services-new/tests/src/proof.ts
2012
+ *
2013
+ * This is the preferred method when circuits are available locally,
2014
+ * as it doesn't require a backend prover service.
2015
+ */
2016
+
2017
+ interface WithdrawRegularInputs {
2018
+ root: bigint;
2019
+ nullifier: bigint;
2020
+ outputs_hash: bigint;
2021
+ public_amount: bigint;
2022
+ amount: bigint;
2023
+ leaf_index: bigint;
2024
+ sk: [bigint, bigint];
2025
+ r: [bigint, bigint];
2026
+ pathElements: bigint[];
2027
+ pathIndices: number[];
2028
+ num_outputs: number;
2029
+ out_addr: bigint[][];
2030
+ out_amount: bigint[];
2031
+ out_flags: number[];
2032
+ var_fee: bigint;
2033
+ rem: bigint;
2034
+ }
2035
+ interface WithdrawSwapInputs {
2036
+ sk_spend: bigint;
2037
+ r: bigint;
2038
+ amount: bigint;
2039
+ leaf_index: bigint;
2040
+ path_elements: bigint[];
2041
+ path_indices: number[];
2042
+ root: bigint;
2043
+ nullifier: bigint;
2044
+ outputs_hash: bigint;
2045
+ public_amount: bigint;
2046
+ input_mint: bigint[];
2047
+ output_mint: bigint[];
2048
+ recipient_ata: bigint[];
2049
+ min_output_amount: bigint;
2050
+ var_fee: bigint;
2051
+ rem: bigint;
2052
+ }
2053
+ interface ProofResult {
2054
+ proof: Groth16Proof;
2055
+ publicSignals: string[];
2056
+ proofBytes: Uint8Array;
2057
+ publicInputsBytes: Uint8Array;
2058
+ }
2059
+ /**
2060
+ * Generate Groth16 proof for regular withdrawal using Circom WASM
2061
+ *
2062
+ * This matches the approach in services-new/tests/src/proof.ts
2063
+ *
2064
+ * @param inputs - Circuit inputs
2065
+ * @param circuitsPath - Path or URL to circuits directory. In browser, use URL like '/circuits' or full URL.
2066
+ */
2067
+ declare function generateWithdrawRegularProof(inputs: WithdrawRegularInputs, circuitsPath: string): Promise<ProofResult>;
2068
+ /**
2069
+ * Generate Groth16 proof for swap withdrawal using Circom WASM
2070
+ *
2071
+ * This matches the approach in services-new/tests/src/proof.ts
2072
+ *
2073
+ * @param inputs - Circuit inputs
2074
+ * @param circuitsPath - Path or URL to circuits directory. In browser, use URL like '/circuits' or full URL.
2075
+ */
2076
+ declare function generateWithdrawSwapProof(inputs: WithdrawSwapInputs, circuitsPath: string): Promise<ProofResult>;
2077
+
1982
2078
  /**
1983
2079
  * Cloak SDK - TypeScript SDK for Private Transactions on Solana
1984
2080
  *
@@ -1987,4 +2083,4 @@ declare function getShieldPoolPDAs(programId?: PublicKey, mint?: PublicKey): Shi
1987
2083
 
1988
2084
  declare const VERSION = "1.0.0";
1989
2085
 
1990
- export { type ArtifactProofGenerationOptions, ArtifactProverService, CLOAK_PROGRAM_ID, type CloakConfig, CloakError, type CloakKeyPair, type CloakNote, CloakSDK, type DepositInstructionParams, type DepositOptions, DepositRecoveryService, type DepositResult, type DepositStatus, type EncryptedNote, FIXED_FEE_LAMPORTS, type Groth16Proof, IndexerService, LAMPORTS_PER_SOL, LocalStorageAdapter, type MasterKey, type MaxLengthArray, MemoryStorageAdapter, type MerkleProof, type MerkleRootResponse, type Network, type NoteData, type NotesRangeResponse, type ProofGenerationOptions, ProverService, type RecoveryOptions, type RecoveryResult, RelayService, type SP1ProofInputs, type SP1ProofResult, type ScanNotesOptions, type ScannedNote, type ShieldPoolPDAs, type SpendKey, type StorageAdapter, type SwapOptions, type SwapParams, type SwapResult, type Transfer, type TransferOptions, type TransferResult, type TxStatus, VARIABLE_FEE_RATE, VERSION, type ViewKey, type WalletAdapter, type WithdrawOptions, bigintToBytes32, buildPublicInputsBytes, bytesToHex, calculateFee, calculateRelayFee, computeCommitment, computeMerkleRoot, computeNullifier, computeNullifierAsync, computeNullifierSync, computeOutputsHash, computeOutputsHashAsync, computeOutputsHashSync, computeSwapOutputsHash, computeSwapOutputsHashAsync, computeSwapOutputsHashSync, copyNoteToClipboard, createCloakError, createDepositInstruction, deriveSpendKey, deriveViewKey, detectNetworkFromRpcUrl, downloadNote, encodeNoteSimple, encryptNoteForRecipient, exportKeys, exportNote, exportWalletKeys, filterNotesByNetwork, filterWithdrawableNotes, findNoteByCommitment, formatAmount, formatErrorForLogging, generateCloakKeys, generateCommitment, generateCommitmentAsync, generateMasterSeed, generateNote, generateNoteFromWallet, getAddressExplorerUrl, getDistributableAmount, getExplorerUrl, getPublicKey, getPublicViewKey, getRecipientAmount, getRpcUrlForNetwork, getShieldPoolPDAs, getViewKey, hexToBigint, hexToBytes, importKeys, importWalletKeys, isValidHex, isValidRpcUrl, isValidSolanaAddress, isWithdrawable, keypairToAdapter, parseAmount, parseNote, parseTransactionError, poseidonHash, prepareEncryptedOutput, prepareEncryptedOutputForRecipient, proofToBytes, pubkeyToLimbs, randomBytes, scanNotesForWallet, sendTransaction, serializeNote, signTransaction, splitTo2Limbs, tryDecryptNote, updateNoteWithDeposit, validateDepositParams, validateNote, validateOutputsSum, validateTransfers, validateWalletConnected, validateWithdrawableNote };
2086
+ export { type ArtifactProofGenerationOptions, ArtifactProverService, CLOAK_PROGRAM_ID, type CloakConfig, CloakError, type CloakKeyPair, type CloakNote, CloakSDK, type DepositInstructionParams, type DepositOptions, DepositRecoveryService, type DepositResult, type DepositStatus, type EncryptedNote, FIXED_FEE_LAMPORTS, type Groth16Proof, IndexerService, LAMPORTS_PER_SOL, LocalStorageAdapter, type MasterKey, type MaxLengthArray, MemoryStorageAdapter, type MerkleProof, type MerkleRootResponse, type Network, type NoteData, type NotesRangeResponse, type ProofGenerationOptions, type ProofResult, ProverService, type RecoveryOptions, type RecoveryResult, RelayService, type SP1ProofInputs, type SP1ProofResult, type ScanNotesOptions, type ScannedNote, type ShieldPoolPDAs, type SpendKey, type StorageAdapter, type SwapOptions, type SwapParams, type SwapResult, type Transfer, type TransferOptions, type TransferResult, type TxStatus, VARIABLE_FEE_RATE, VERSION, type ViewKey, type WalletAdapter, type WithdrawOptions, type WithdrawRegularInputs, type WithdrawSwapInputs, bigintToBytes32, buildPublicInputsBytes, bytesToHex, calculateFee, calculateRelayFee, computeCommitment, computeMerkleRoot, computeNullifier, computeNullifierAsync, computeNullifierSync, computeOutputsHash, computeOutputsHashAsync, computeOutputsHashSync, computeSwapOutputsHash, computeSwapOutputsHashAsync, computeSwapOutputsHashSync, copyNoteToClipboard, createCloakError, createDepositInstruction, deriveSpendKey, deriveViewKey, detectNetworkFromRpcUrl, downloadNote, encodeNoteSimple, encryptNoteForRecipient, exportKeys, exportNote, exportWalletKeys, filterNotesByNetwork, filterWithdrawableNotes, findNoteByCommitment, formatAmount, formatErrorForLogging, generateCloakKeys, generateCommitment, generateCommitmentAsync, generateMasterSeed, generateNote, generateNoteFromWallet, generateWithdrawRegularProof, generateWithdrawSwapProof, getAddressExplorerUrl, getDistributableAmount, getExplorerUrl, getPublicKey, getPublicViewKey, getRecipientAmount, getRpcUrlForNetwork, getShieldPoolPDAs, getViewKey, hexToBigint, hexToBytes, importKeys, importWalletKeys, isValidHex, isValidRpcUrl, isValidSolanaAddress, isWithdrawable, keypairToAdapter, parseAmount, parseNote, parseTransactionError, poseidonHash, prepareEncryptedOutput, prepareEncryptedOutputForRecipient, proofToBytes, pubkeyToLimbs, randomBytes, scanNotesForWallet, sendTransaction, serializeNote, signTransaction, splitTo2Limbs, tryDecryptNote, updateNoteWithDeposit, validateDepositParams, validateNote, validateOutputsSum, validateTransfers, validateWalletConnected, validateWithdrawableNote };
package/dist/index.d.ts CHANGED
@@ -505,10 +505,15 @@ declare const CLOAK_PROGRAM_ID: PublicKey;
505
505
  *
506
506
  * Provides high-level API for interacting with the Cloak protocol,
507
507
  * including deposits, withdrawals, and private transfers.
508
+ *
509
+ * Supports two modes:
510
+ * 1. Node.js mode with keypairBytes - for scripts and backend services
511
+ * 2. Wallet adapter mode - for browser applications with wallet integration
508
512
  */
509
513
  declare class CloakSDK {
510
514
  private config;
511
- private keypair;
515
+ private keypair?;
516
+ private wallet?;
512
517
  private cloakKeys?;
513
518
  private indexer;
514
519
  private artifactProver;
@@ -516,19 +521,31 @@ declare class CloakSDK {
516
521
  private depositRecovery;
517
522
  private storage;
518
523
  /**
519
- * Create a new Cloak SDK client
524
+ * Create a new Cloak SDK client
520
525
  *
521
526
  * @param config - Client configuration
522
527
  *
523
- * @example
528
+ * @example Node.js mode (with keypair)
524
529
  * ```typescript
525
530
  * const sdk = new CloakSDK({
526
531
  * keypairBytes: keypair.secretKey,
527
532
  * network: "devnet"
528
533
  * });
534
+ * ```
535
+ *
536
+ * @example Browser mode (with wallet adapter)
537
+ * ```typescript
538
+ * const sdk = new CloakSDK({
539
+ * wallet: walletAdapter,
540
+ * network: "devnet"
541
+ * });
542
+ * ```
529
543
  */
530
544
  constructor(config: {
531
- keypairBytes: Uint8Array;
545
+ /** Keypair bytes for signing (Node.js mode) */
546
+ keypairBytes?: Uint8Array;
547
+ /** Wallet adapter for signing (Browser mode) */
548
+ wallet?: WalletAdapter;
532
549
  network?: Network;
533
550
  cloakKeys?: CloakKeyPair;
534
551
  storage?: StorageAdapter;
@@ -536,6 +553,14 @@ declare class CloakSDK {
536
553
  indexerUrl?: string;
537
554
  relayUrl?: string;
538
555
  });
556
+ /**
557
+ * Get the public key for deposits (from keypair or wallet)
558
+ */
559
+ getPublicKey(): PublicKey;
560
+ /**
561
+ * Check if the SDK is using a wallet adapter
562
+ */
563
+ isWalletMode(): boolean;
539
564
  /**
540
565
  * Deposit SOL into the Cloak protocol
541
566
  *
@@ -1979,6 +2004,77 @@ interface ShieldPoolPDAs {
1979
2004
  */
1980
2005
  declare function getShieldPoolPDAs(programId?: PublicKey, mint?: PublicKey): ShieldPoolPDAs;
1981
2006
 
2007
+ /**
2008
+ * Direct Circom WASM Proof Generation
2009
+ *
2010
+ * This module provides direct proof generation using snarkjs and Circom WASM,
2011
+ * matching the approach used in services-new/tests/src/proof.ts
2012
+ *
2013
+ * This is the preferred method when circuits are available locally,
2014
+ * as it doesn't require a backend prover service.
2015
+ */
2016
+
2017
+ interface WithdrawRegularInputs {
2018
+ root: bigint;
2019
+ nullifier: bigint;
2020
+ outputs_hash: bigint;
2021
+ public_amount: bigint;
2022
+ amount: bigint;
2023
+ leaf_index: bigint;
2024
+ sk: [bigint, bigint];
2025
+ r: [bigint, bigint];
2026
+ pathElements: bigint[];
2027
+ pathIndices: number[];
2028
+ num_outputs: number;
2029
+ out_addr: bigint[][];
2030
+ out_amount: bigint[];
2031
+ out_flags: number[];
2032
+ var_fee: bigint;
2033
+ rem: bigint;
2034
+ }
2035
+ interface WithdrawSwapInputs {
2036
+ sk_spend: bigint;
2037
+ r: bigint;
2038
+ amount: bigint;
2039
+ leaf_index: bigint;
2040
+ path_elements: bigint[];
2041
+ path_indices: number[];
2042
+ root: bigint;
2043
+ nullifier: bigint;
2044
+ outputs_hash: bigint;
2045
+ public_amount: bigint;
2046
+ input_mint: bigint[];
2047
+ output_mint: bigint[];
2048
+ recipient_ata: bigint[];
2049
+ min_output_amount: bigint;
2050
+ var_fee: bigint;
2051
+ rem: bigint;
2052
+ }
2053
+ interface ProofResult {
2054
+ proof: Groth16Proof;
2055
+ publicSignals: string[];
2056
+ proofBytes: Uint8Array;
2057
+ publicInputsBytes: Uint8Array;
2058
+ }
2059
+ /**
2060
+ * Generate Groth16 proof for regular withdrawal using Circom WASM
2061
+ *
2062
+ * This matches the approach in services-new/tests/src/proof.ts
2063
+ *
2064
+ * @param inputs - Circuit inputs
2065
+ * @param circuitsPath - Path or URL to circuits directory. In browser, use URL like '/circuits' or full URL.
2066
+ */
2067
+ declare function generateWithdrawRegularProof(inputs: WithdrawRegularInputs, circuitsPath: string): Promise<ProofResult>;
2068
+ /**
2069
+ * Generate Groth16 proof for swap withdrawal using Circom WASM
2070
+ *
2071
+ * This matches the approach in services-new/tests/src/proof.ts
2072
+ *
2073
+ * @param inputs - Circuit inputs
2074
+ * @param circuitsPath - Path or URL to circuits directory. In browser, use URL like '/circuits' or full URL.
2075
+ */
2076
+ declare function generateWithdrawSwapProof(inputs: WithdrawSwapInputs, circuitsPath: string): Promise<ProofResult>;
2077
+
1982
2078
  /**
1983
2079
  * Cloak SDK - TypeScript SDK for Private Transactions on Solana
1984
2080
  *
@@ -1987,4 +2083,4 @@ declare function getShieldPoolPDAs(programId?: PublicKey, mint?: PublicKey): Shi
1987
2083
 
1988
2084
  declare const VERSION = "1.0.0";
1989
2085
 
1990
- export { type ArtifactProofGenerationOptions, ArtifactProverService, CLOAK_PROGRAM_ID, type CloakConfig, CloakError, type CloakKeyPair, type CloakNote, CloakSDK, type DepositInstructionParams, type DepositOptions, DepositRecoveryService, type DepositResult, type DepositStatus, type EncryptedNote, FIXED_FEE_LAMPORTS, type Groth16Proof, IndexerService, LAMPORTS_PER_SOL, LocalStorageAdapter, type MasterKey, type MaxLengthArray, MemoryStorageAdapter, type MerkleProof, type MerkleRootResponse, type Network, type NoteData, type NotesRangeResponse, type ProofGenerationOptions, ProverService, type RecoveryOptions, type RecoveryResult, RelayService, type SP1ProofInputs, type SP1ProofResult, type ScanNotesOptions, type ScannedNote, type ShieldPoolPDAs, type SpendKey, type StorageAdapter, type SwapOptions, type SwapParams, type SwapResult, type Transfer, type TransferOptions, type TransferResult, type TxStatus, VARIABLE_FEE_RATE, VERSION, type ViewKey, type WalletAdapter, type WithdrawOptions, bigintToBytes32, buildPublicInputsBytes, bytesToHex, calculateFee, calculateRelayFee, computeCommitment, computeMerkleRoot, computeNullifier, computeNullifierAsync, computeNullifierSync, computeOutputsHash, computeOutputsHashAsync, computeOutputsHashSync, computeSwapOutputsHash, computeSwapOutputsHashAsync, computeSwapOutputsHashSync, copyNoteToClipboard, createCloakError, createDepositInstruction, deriveSpendKey, deriveViewKey, detectNetworkFromRpcUrl, downloadNote, encodeNoteSimple, encryptNoteForRecipient, exportKeys, exportNote, exportWalletKeys, filterNotesByNetwork, filterWithdrawableNotes, findNoteByCommitment, formatAmount, formatErrorForLogging, generateCloakKeys, generateCommitment, generateCommitmentAsync, generateMasterSeed, generateNote, generateNoteFromWallet, getAddressExplorerUrl, getDistributableAmount, getExplorerUrl, getPublicKey, getPublicViewKey, getRecipientAmount, getRpcUrlForNetwork, getShieldPoolPDAs, getViewKey, hexToBigint, hexToBytes, importKeys, importWalletKeys, isValidHex, isValidRpcUrl, isValidSolanaAddress, isWithdrawable, keypairToAdapter, parseAmount, parseNote, parseTransactionError, poseidonHash, prepareEncryptedOutput, prepareEncryptedOutputForRecipient, proofToBytes, pubkeyToLimbs, randomBytes, scanNotesForWallet, sendTransaction, serializeNote, signTransaction, splitTo2Limbs, tryDecryptNote, updateNoteWithDeposit, validateDepositParams, validateNote, validateOutputsSum, validateTransfers, validateWalletConnected, validateWithdrawableNote };
2086
+ export { type ArtifactProofGenerationOptions, ArtifactProverService, CLOAK_PROGRAM_ID, type CloakConfig, CloakError, type CloakKeyPair, type CloakNote, CloakSDK, type DepositInstructionParams, type DepositOptions, DepositRecoveryService, type DepositResult, type DepositStatus, type EncryptedNote, FIXED_FEE_LAMPORTS, type Groth16Proof, IndexerService, LAMPORTS_PER_SOL, LocalStorageAdapter, type MasterKey, type MaxLengthArray, MemoryStorageAdapter, type MerkleProof, type MerkleRootResponse, type Network, type NoteData, type NotesRangeResponse, type ProofGenerationOptions, type ProofResult, ProverService, type RecoveryOptions, type RecoveryResult, RelayService, type SP1ProofInputs, type SP1ProofResult, type ScanNotesOptions, type ScannedNote, type ShieldPoolPDAs, type SpendKey, type StorageAdapter, type SwapOptions, type SwapParams, type SwapResult, type Transfer, type TransferOptions, type TransferResult, type TxStatus, VARIABLE_FEE_RATE, VERSION, type ViewKey, type WalletAdapter, type WithdrawOptions, type WithdrawRegularInputs, type WithdrawSwapInputs, bigintToBytes32, buildPublicInputsBytes, bytesToHex, calculateFee, calculateRelayFee, computeCommitment, computeMerkleRoot, computeNullifier, computeNullifierAsync, computeNullifierSync, computeOutputsHash, computeOutputsHashAsync, computeOutputsHashSync, computeSwapOutputsHash, computeSwapOutputsHashAsync, computeSwapOutputsHashSync, copyNoteToClipboard, createCloakError, createDepositInstruction, deriveSpendKey, deriveViewKey, detectNetworkFromRpcUrl, downloadNote, encodeNoteSimple, encryptNoteForRecipient, exportKeys, exportNote, exportWalletKeys, filterNotesByNetwork, filterWithdrawableNotes, findNoteByCommitment, formatAmount, formatErrorForLogging, generateCloakKeys, generateCommitment, generateCommitmentAsync, generateMasterSeed, generateNote, generateNoteFromWallet, generateWithdrawRegularProof, generateWithdrawSwapProof, getAddressExplorerUrl, getDistributableAmount, getExplorerUrl, getPublicKey, getPublicViewKey, getRecipientAmount, getRpcUrlForNetwork, getShieldPoolPDAs, getViewKey, hexToBigint, hexToBytes, importKeys, importWalletKeys, isValidHex, isValidRpcUrl, isValidSolanaAddress, isWithdrawable, keypairToAdapter, parseAmount, parseNote, parseTransactionError, poseidonHash, prepareEncryptedOutput, prepareEncryptedOutputForRecipient, proofToBytes, pubkeyToLimbs, randomBytes, scanNotesForWallet, sendTransaction, serializeNote, signTransaction, splitTo2Limbs, tryDecryptNote, updateNoteWithDeposit, validateDepositParams, validateNote, validateOutputsSum, validateTransfers, validateWalletConnected, validateWithdrawableNote };
package/dist/index.js CHANGED
@@ -1216,7 +1216,7 @@ var ArtifactProverService = class {
1216
1216
  lastProgress = progress;
1217
1217
  options?.onProgress?.(progress);
1218
1218
  }
1219
- await new Promise((resolve2) => setTimeout(resolve2, pollInterval));
1219
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
1220
1220
  }
1221
1221
  const errorMessage = `Proof generation timed out after ${actualTimeout}ms`;
1222
1222
  options?.onError?.(errorMessage);
@@ -1510,7 +1510,7 @@ var RelayService = class {
1510
1510
  * Sleep utility
1511
1511
  */
1512
1512
  sleep(ms) {
1513
- return new Promise((resolve2) => setTimeout(resolve2, ms));
1513
+ return new Promise((resolve) => setTimeout(resolve, ms));
1514
1514
  }
1515
1515
  };
1516
1516
 
@@ -1879,16 +1879,57 @@ function getShieldPoolPDAs(programId, mint) {
1879
1879
 
1880
1880
  // src/utils/proof-generation.ts
1881
1881
  import * as snarkjs from "snarkjs";
1882
- import * as path from "path";
1883
- import * as fs from "fs";
1884
- async function generateWithdrawRegularProof(inputs, circuitsPath) {
1885
- const wasmPath = path.join(circuitsPath, "build", "withdraw_regular_js", "withdraw_regular.wasm");
1886
- const zkeyPath = path.join(circuitsPath, "build", "withdraw_regular_final.zkey");
1887
- if (!fs.existsSync(wasmPath)) {
1888
- throw new Error(`Circuit WASM not found at ${wasmPath}. Run 'just circuits-compile' in packages-new/circuits first.`);
1882
+ var path = null;
1883
+ var fs = null;
1884
+ async function loadNodeModules() {
1885
+ const isBrowser = typeof window !== "undefined" || typeof globalThis !== "undefined" && globalThis.window;
1886
+ if (!isBrowser && typeof process !== "undefined" && process.versions?.node) {
1887
+ if (!path) {
1888
+ path = await import("path");
1889
+ }
1890
+ if (!fs) {
1891
+ fs = await import("fs");
1892
+ }
1893
+ return { path, fs };
1889
1894
  }
1890
- if (!fs.existsSync(zkeyPath)) {
1891
- throw new Error(`Circuit zkey not found at ${zkeyPath}. Run circuit setup first.`);
1895
+ return { path: null, fs: null };
1896
+ }
1897
+ function joinPath(...parts) {
1898
+ const isBrowser = typeof window !== "undefined" || typeof globalThis !== "undefined" && globalThis.window;
1899
+ if (!isBrowser && path) {
1900
+ return path.join(...parts);
1901
+ }
1902
+ return parts.join("/").replace(/\/+/g, "/");
1903
+ }
1904
+ async function fileExists(filePath) {
1905
+ const { fs: fs2 } = await loadNodeModules();
1906
+ if (fs2) {
1907
+ try {
1908
+ return fs2.existsSync(filePath);
1909
+ } catch {
1910
+ return false;
1911
+ }
1912
+ }
1913
+ return false;
1914
+ }
1915
+ async function generateWithdrawRegularProof(inputs, circuitsPath) {
1916
+ const isBrowser = typeof window !== "undefined" || typeof globalThis !== "undefined" && globalThis.window;
1917
+ let wasmPath;
1918
+ let zkeyPath;
1919
+ if (isBrowser) {
1920
+ wasmPath = `${circuitsPath}/withdraw_regular_js/withdraw_regular.wasm`;
1921
+ zkeyPath = `${circuitsPath}/withdraw_regular_final.zkey`;
1922
+ } else {
1923
+ wasmPath = joinPath(circuitsPath, "build", "withdraw_regular_js", "withdraw_regular.wasm");
1924
+ zkeyPath = joinPath(circuitsPath, "build", "withdraw_regular_final.zkey");
1925
+ const wasmExists = await fileExists(wasmPath);
1926
+ const zkeyExists = await fileExists(zkeyPath);
1927
+ if (!wasmExists) {
1928
+ throw new Error(`Circuit WASM not found at ${wasmPath}. Run 'just circuits-compile' in packages-new/circuits first.`);
1929
+ }
1930
+ if (!zkeyExists) {
1931
+ throw new Error(`Circuit zkey not found at ${zkeyPath}. Run circuit setup first.`);
1932
+ }
1892
1933
  }
1893
1934
  const circuitInputs = {
1894
1935
  // Public signals
@@ -1927,13 +1968,23 @@ async function generateWithdrawRegularProof(inputs, circuitsPath) {
1927
1968
  };
1928
1969
  }
1929
1970
  async function generateWithdrawSwapProof(inputs, circuitsPath) {
1930
- const wasmPath = path.join(circuitsPath, "build", "withdraw_swap_js", "withdraw_swap.wasm");
1931
- const zkeyPath = path.join(circuitsPath, "build", "withdraw_swap_final.zkey");
1932
- if (!fs.existsSync(wasmPath)) {
1933
- throw new Error(`Circuit WASM not found at ${wasmPath}. Run 'just circuits-compile' in packages-new/circuits first.`);
1934
- }
1935
- if (!fs.existsSync(zkeyPath)) {
1936
- throw new Error(`Circuit zkey not found at ${zkeyPath}. Run circuit setup first.`);
1971
+ const isBrowser = typeof window !== "undefined" || typeof globalThis !== "undefined" && globalThis.window;
1972
+ let wasmPath;
1973
+ let zkeyPath;
1974
+ if (isBrowser) {
1975
+ wasmPath = `${circuitsPath}/withdraw_swap_js/withdraw_swap.wasm`;
1976
+ zkeyPath = `${circuitsPath}/withdraw_swap_final.zkey`;
1977
+ } else {
1978
+ wasmPath = joinPath(circuitsPath, "build", "withdraw_swap_js", "withdraw_swap.wasm");
1979
+ zkeyPath = joinPath(circuitsPath, "build", "withdraw_swap_final.zkey");
1980
+ const wasmExists = await fileExists(wasmPath);
1981
+ const zkeyExists = await fileExists(zkeyPath);
1982
+ if (!wasmExists) {
1983
+ throw new Error(`Circuit WASM not found at ${wasmPath}. Run 'just circuits-compile' in packages-new/circuits first.`);
1984
+ }
1985
+ if (!zkeyExists) {
1986
+ throw new Error(`Circuit zkey not found at ${zkeyPath}. Run circuit setup first.`);
1987
+ }
1937
1988
  }
1938
1989
  const sk = splitTo2Limbs(inputs.sk_spend);
1939
1990
  const r = splitTo2Limbs(inputs.r);
@@ -1974,21 +2025,31 @@ async function generateWithdrawSwapProof(inputs, circuitsPath) {
1974
2025
  // Not used, kept for compatibility
1975
2026
  };
1976
2027
  }
1977
- function areCircuitsAvailable(circuitsPath) {
1978
- const wasmPath = path.join(circuitsPath, "build", "withdraw_regular_js", "withdraw_regular.wasm");
1979
- const zkeyPath = path.join(circuitsPath, "build", "withdraw_regular_final.zkey");
1980
- return fs.existsSync(wasmPath) && fs.existsSync(zkeyPath);
2028
+ async function areCircuitsAvailable(circuitsPath) {
2029
+ const wasmPath = joinPath(circuitsPath, "build", "withdraw_regular_js", "withdraw_regular.wasm");
2030
+ const zkeyPath = joinPath(circuitsPath, "build", "withdraw_regular_final.zkey");
2031
+ const wasmExists = await fileExists(wasmPath);
2032
+ const zkeyExists = await fileExists(zkeyPath);
2033
+ return wasmExists && zkeyExists;
1981
2034
  }
1982
- function getDefaultCircuitsPath() {
2035
+ async function getDefaultCircuitsPath() {
2036
+ const isBrowser = typeof window !== "undefined" || typeof globalThis !== "undefined" && globalThis.window;
2037
+ if (isBrowser) {
2038
+ return "/circuits";
2039
+ }
2040
+ const { path: path2 } = await loadNodeModules();
2041
+ if (!path2 || typeof process === "undefined" || !process.cwd) {
2042
+ return "/circuits";
2043
+ }
1983
2044
  const possiblePaths = [
1984
- path.resolve(process.cwd(), "../../packages-new/circuits"),
1985
- path.resolve(process.cwd(), "../packages-new/circuits"),
1986
- path.resolve(process.cwd(), "packages-new/circuits"),
1987
- path.resolve(process.cwd(), "../../circuits"),
1988
- path.resolve(process.cwd(), "../circuits")
2045
+ path2.resolve(process.cwd(), "../../packages-new/circuits"),
2046
+ path2.resolve(process.cwd(), "../packages-new/circuits"),
2047
+ path2.resolve(process.cwd(), "packages-new/circuits"),
2048
+ path2.resolve(process.cwd(), "../../circuits"),
2049
+ path2.resolve(process.cwd(), "../circuits")
1989
2050
  ];
1990
2051
  for (const p of possiblePaths) {
1991
- if (areCircuitsAvailable(p)) {
2052
+ if (await areCircuitsAvailable(p)) {
1992
2053
  return p;
1993
2054
  }
1994
2055
  }
@@ -2000,23 +2061,38 @@ var CLOAK_PROGRAM_ID = new PublicKey5("c1oak6tetxYnNfvXKFkpn1d98FxtK7B68vBQLYQpW
2000
2061
  var CLOAK_API_URL = "https://api.cloak.ag";
2001
2062
  var CloakSDK = class {
2002
2063
  /**
2003
- * Create a new Cloak SDK client
2064
+ * Create a new Cloak SDK client
2004
2065
  *
2005
2066
  * @param config - Client configuration
2006
2067
  *
2007
- * @example
2068
+ * @example Node.js mode (with keypair)
2008
2069
  * ```typescript
2009
2070
  * const sdk = new CloakSDK({
2010
2071
  * keypairBytes: keypair.secretKey,
2011
2072
  * network: "devnet"
2012
- * });
2073
+ * });
2074
+ * ```
2075
+ *
2076
+ * @example Browser mode (with wallet adapter)
2077
+ * ```typescript
2078
+ * const sdk = new CloakSDK({
2079
+ * wallet: walletAdapter,
2080
+ * network: "devnet"
2081
+ * });
2082
+ * ```
2013
2083
  */
2014
2084
  constructor(config) {
2015
- this.keypair = Keypair.fromSecretKey(config.keypairBytes);
2085
+ if (!config.keypairBytes && !config.wallet) {
2086
+ throw new Error("Must provide either keypairBytes (Node.js) or wallet (Browser)");
2087
+ }
2088
+ if (config.keypairBytes) {
2089
+ this.keypair = Keypair.fromSecretKey(config.keypairBytes);
2090
+ }
2091
+ this.wallet = config.wallet;
2016
2092
  this.cloakKeys = config.cloakKeys;
2017
2093
  this.storage = config.storage || new MemoryStorageAdapter();
2018
- const indexerUrl = config.indexerUrl || process.env.CLOAK_INDEXER_URL || CLOAK_API_URL;
2019
- const relayUrl = config.relayUrl || process.env.CLOAK_RELAY_URL || CLOAK_API_URL;
2094
+ const indexerUrl = config.indexerUrl || typeof process !== "undefined" && process.env?.CLOAK_INDEXER_URL || CLOAK_API_URL;
2095
+ const relayUrl = config.relayUrl || typeof process !== "undefined" && process.env?.CLOAK_RELAY_URL || CLOAK_API_URL;
2020
2096
  this.indexer = new IndexerService(indexerUrl);
2021
2097
  this.artifactProver = new ArtifactProverService(indexerUrl, 5 * 60 * 1e3, 2e3);
2022
2098
  this.relay = new RelayService(relayUrl);
@@ -2044,6 +2120,24 @@ var CloakSDK = class {
2044
2120
  treasuryAddress: treasury
2045
2121
  };
2046
2122
  }
2123
+ /**
2124
+ * Get the public key for deposits (from keypair or wallet)
2125
+ */
2126
+ getPublicKey() {
2127
+ if (this.keypair) {
2128
+ return this.keypair.publicKey;
2129
+ }
2130
+ if (this.wallet?.publicKey) {
2131
+ return this.wallet.publicKey;
2132
+ }
2133
+ throw new Error("No public key available - wallet not connected or keypair not provided");
2134
+ }
2135
+ /**
2136
+ * Check if the SDK is using a wallet adapter
2137
+ */
2138
+ isWalletMode() {
2139
+ return !!this.wallet && !this.keypair;
2140
+ }
2047
2141
  /**
2048
2142
  * Deposit SOL into the Cloak protocol
2049
2143
  *
@@ -2084,7 +2178,8 @@ var CloakSDK = class {
2084
2178
  throw new Error("Note has already been deposited");
2085
2179
  }
2086
2180
  }
2087
- const balance = await connection.getBalance(this.keypair.publicKey);
2181
+ const payerPubkey = this.getPublicKey();
2182
+ const balance = await connection.getBalance(payerPubkey);
2088
2183
  const requiredAmount = note.amount + 5e3;
2089
2184
  if (balance < requiredAmount) {
2090
2185
  throw new Error(
@@ -2095,7 +2190,7 @@ var CloakSDK = class {
2095
2190
  const programId = this.config.programId || CLOAK_PROGRAM_ID;
2096
2191
  const depositIx = createDepositInstruction({
2097
2192
  programId,
2098
- payer: this.keypair.publicKey,
2193
+ payer: payerPubkey,
2099
2194
  pool: this.config.poolAddress,
2100
2195
  merkleTree: this.config.merkleTreeAddress,
2101
2196
  amount: note.amount,
@@ -2103,7 +2198,7 @@ var CloakSDK = class {
2103
2198
  });
2104
2199
  const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
2105
2200
  const transaction = new Transaction({
2106
- feePayer: this.keypair.publicKey,
2201
+ feePayer: payerPubkey,
2107
2202
  blockhash,
2108
2203
  lastValidBlockHeight
2109
2204
  }).add(depositIx);
@@ -2118,11 +2213,22 @@ ${logs}`
2118
2213
  );
2119
2214
  }
2120
2215
  }
2121
- const signature = await connection.sendTransaction(transaction, [this.keypair], {
2122
- skipPreflight: options?.skipPreflight || false,
2123
- preflightCommitment: "confirmed",
2124
- maxRetries: 3
2125
- });
2216
+ let signature;
2217
+ if (this.wallet?.sendTransaction) {
2218
+ signature = await this.wallet.sendTransaction(transaction, connection, {
2219
+ skipPreflight: options?.skipPreflight || false,
2220
+ preflightCommitment: "confirmed",
2221
+ maxRetries: 3
2222
+ });
2223
+ } else if (this.keypair) {
2224
+ signature = await connection.sendTransaction(transaction, [this.keypair], {
2225
+ skipPreflight: options?.skipPreflight || false,
2226
+ preflightCommitment: "confirmed",
2227
+ maxRetries: 3
2228
+ });
2229
+ } else {
2230
+ throw new Error("No signing method available - provide keypair or wallet");
2231
+ }
2126
2232
  const confirmation = await connection.confirmTransaction({
2127
2233
  signature,
2128
2234
  blockhash,
@@ -2184,13 +2290,13 @@ ${logs}`
2184
2290
  break;
2185
2291
  } else if (response.status === 404 && attempt < maxRetries2 - 1) {
2186
2292
  const delay = Math.min(initialRetryDelay2 * (attempt + 1), 2e3);
2187
- await new Promise((resolve2) => setTimeout(resolve2, delay));
2293
+ await new Promise((resolve) => setTimeout(resolve, delay));
2188
2294
  continue;
2189
2295
  }
2190
2296
  } catch (e) {
2191
2297
  if (attempt < maxRetries2 - 1) {
2192
2298
  const delay = Math.min(initialRetryDelay2 * (attempt + 1), 2e3);
2193
- await new Promise((resolve2) => setTimeout(resolve2, delay));
2299
+ await new Promise((resolve) => setTimeout(resolve, delay));
2194
2300
  continue;
2195
2301
  }
2196
2302
  }
@@ -2223,7 +2329,7 @@ ${logs}`
2223
2329
  const errorMessage = error instanceof Error ? error.message : String(error);
2224
2330
  if (errorMessage.includes("404") && attempt < maxRetries - 1) {
2225
2331
  const delay = Math.min(initialRetryDelay * (attempt + 1), 2e3);
2226
- await new Promise((resolve2) => setTimeout(resolve2, delay));
2332
+ await new Promise((resolve) => setTimeout(resolve, delay));
2227
2333
  continue;
2228
2334
  }
2229
2335
  throw error;
@@ -2349,8 +2455,8 @@ ${logs}`
2349
2455
  throw new Error(`Merkle proof path element at position ${i} must be 64 hex characters (32 bytes)`);
2350
2456
  }
2351
2457
  }
2352
- const circuitsPath = process.env.CIRCUITS_PATH || getDefaultCircuitsPath();
2353
- const useDirectProof = areCircuitsAvailable(circuitsPath);
2458
+ const circuitsPath = typeof process !== "undefined" && process.env?.CIRCUITS_PATH || await getDefaultCircuitsPath();
2459
+ const useDirectProof = await areCircuitsAvailable(circuitsPath);
2354
2460
  let proofHex;
2355
2461
  let finalPublicInputs;
2356
2462
  if (useDirectProof) {
@@ -2647,8 +2753,8 @@ Note details: leafIndex=${note.leafIndex}, root=${merkleRoot.slice(0, 16)}..., n
2647
2753
  if (!merkleProof.pathElements || merkleProof.pathElements.length === 0) {
2648
2754
  throw new Error("Merkle proof is invalid: missing path elements");
2649
2755
  }
2650
- const circuitsPath = process.env.CIRCUITS_PATH || getDefaultCircuitsPath();
2651
- const useDirectProof = areCircuitsAvailable(circuitsPath);
2756
+ const circuitsPath = typeof process !== "undefined" && process.env?.CIRCUITS_PATH || await getDefaultCircuitsPath();
2757
+ const useDirectProof = await areCircuitsAvailable(circuitsPath);
2652
2758
  let proofHex;
2653
2759
  let finalPublicInputs;
2654
2760
  if (useDirectProof) {
@@ -3552,6 +3658,8 @@ export {
3552
3658
  generateMasterSeed,
3553
3659
  generateNote,
3554
3660
  generateNoteFromWallet,
3661
+ generateWithdrawRegularProof,
3662
+ generateWithdrawSwapProof,
3555
3663
  getAddressExplorerUrl,
3556
3664
  getDistributableAmount2 as getDistributableAmount,
3557
3665
  getExplorerUrl,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloak.ag/sdk",
3
- "version": "1.0.0",
4
- "description": "TypeScript SDK for Cloak Protocol - Private transactions on Solana",
3
+ "description": "TypeScript SDK for Cloak",
4
+ "version": "1.0.2",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
7
7
  "module": "dist/index.js",
@@ -14,7 +14,7 @@
14
14
  }
15
15
  },
16
16
  "scripts": {
17
- "build": "tsup src/index.ts --format cjs,esm --dts",
17
+ "build": "tsup src/index.ts --format cjs,esm --dts --external fs --external path",
18
18
  "lint": "tsc --noEmit",
19
19
  "test": "NODE_OPTIONS=--experimental-vm-modules jest",
20
20
  "test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch",
@@ -49,11 +49,11 @@
49
49
  "@noble/hashes": "^2.0.1",
50
50
  "@solana/spl-token": "^0.4.0",
51
51
  "@solana/web3.js": "^1.95.0",
52
+ "blake3": "^2.1.7",
52
53
  "bs58": "^6.0.0",
53
54
  "circomlibjs": "^0.1.7",
54
55
  "ffjavascript": "^0.3.0",
55
56
  "snarkjs": "^0.7.4",
56
- "blake3": "^2.1.7",
57
57
  "tweetnacl": "^1.0.3",
58
58
  "tweetnacl-util": "^0.15.1"
59
59
  },