@cloak.dev/sdk 0.1.5 → 0.1.6

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
@@ -36,8 +36,8 @@ __export(utxo_exports, {
36
36
  NATIVE_SOL_MINT: () => NATIVE_SOL_MINT,
37
37
  bigintToBytes32: () => bigintToBytes322,
38
38
  bigintToHex: () => bigintToHex,
39
- computeCommitment: () => computeCommitment2,
40
- computeNullifier: () => computeNullifier2,
39
+ computeCommitment: () => computeCommitment,
40
+ computeNullifier: () => computeNullifier,
41
41
  computeSignature: () => computeSignature,
42
42
  createUtxo: () => createUtxo,
43
43
  createZeroUtxo: () => createZeroUtxo,
@@ -112,7 +112,7 @@ async function createUtxo(amount, keypair, mintAddress = NATIVE_SOL_MINT) {
112
112
  blinding,
113
113
  mintAddress
114
114
  };
115
- utxo.commitment = await computeCommitment2(utxo);
115
+ utxo.commitment = await computeCommitment(utxo);
116
116
  return utxo;
117
117
  }
118
118
  async function createZeroUtxo(mintAddress = NATIVE_SOL_MINT, salt) {
@@ -127,7 +127,7 @@ async function createZeroUtxo(mintAddress = NATIVE_SOL_MINT, salt) {
127
127
  blinding: BigInt(0),
128
128
  mintAddress
129
129
  };
130
- utxo.commitment = await computeCommitment2(utxo);
130
+ utxo.commitment = await computeCommitment(utxo);
131
131
  utxo.index = 0;
132
132
  return utxo;
133
133
  }
@@ -139,7 +139,7 @@ function pubkeyToFieldElement(pubkey) {
139
139
  }
140
140
  return value % FIELD_MODULUS;
141
141
  }
142
- async function computeCommitment2(utxo) {
142
+ async function computeCommitment(utxo) {
143
143
  const poseidon3 = await getPoseidon2();
144
144
  const mintField = pubkeyToFieldElement(utxo.mintAddress);
145
145
  const hash = poseidon3([
@@ -155,12 +155,12 @@ async function computeSignature(privateKey, commitment, pathIndex) {
155
155
  const hash = poseidon3([privateKey, commitment, pathIndex]);
156
156
  return poseidon3.F.toObject(hash);
157
157
  }
158
- async function computeNullifier2(utxo) {
158
+ async function computeNullifier(utxo) {
159
159
  if (utxo.index === void 0) {
160
160
  throw new Error("UTXO must have an index to compute nullifier");
161
161
  }
162
162
  const poseidon3 = await getPoseidon2();
163
- const commitment = utxo.commitment ?? await computeCommitment2(utxo);
163
+ const commitment = utxo.commitment ?? await computeCommitment(utxo);
164
164
  const pathIndex = BigInt(utxo.index);
165
165
  const signature = await computeSignature(
166
166
  utxo.keypair.privateKey,
@@ -202,7 +202,7 @@ async function deserializeUtxo(bytes) {
202
202
  const blindingBytes = bytes.slice(40, 72);
203
203
  const blinding = bytesToBigint(blindingBytes);
204
204
  const mintBytes = bytes.slice(72, 104);
205
- const mintAddress = new import_web33.PublicKey(mintBytes);
205
+ const mintAddress = new import_web3.PublicKey(mintBytes);
206
206
  const index = view.getUint32(104, true);
207
207
  const utxo = {
208
208
  amount,
@@ -211,7 +211,7 @@ async function deserializeUtxo(bytes) {
211
211
  mintAddress,
212
212
  index: index > 0 ? index : void 0
213
213
  };
214
- utxo.commitment = await computeCommitment2(utxo);
214
+ utxo.commitment = await computeCommitment(utxo);
215
215
  return utxo;
216
216
  }
217
217
  function bigintToBytes(value, length) {
@@ -247,8 +247,8 @@ function bigintToBytes322(value) {
247
247
  return result;
248
248
  }
249
249
  async function utxoEquals(a, b) {
250
- const commitmentA = a.commitment ?? await computeCommitment2(a);
251
- const commitmentB = b.commitment ?? await computeCommitment2(b);
250
+ const commitmentA = a.commitment ?? await computeCommitment(a);
251
+ const commitmentB = b.commitment ?? await computeCommitment(b);
252
252
  return commitmentA === commitmentB;
253
253
  }
254
254
  function sumUtxoAmounts(utxos) {
@@ -270,16 +270,16 @@ function selectUtxos(available, targetAmount) {
270
270
  }
271
271
  return selected;
272
272
  }
273
- var import_web33, import_circomlibjs2, import_blake32, FIELD_MODULUS, UTXO_KEY_DOMAIN, NATIVE_SOL_MINT, poseidonInstance;
273
+ var import_web3, import_circomlibjs2, import_blake32, FIELD_MODULUS, UTXO_KEY_DOMAIN, NATIVE_SOL_MINT, poseidonInstance;
274
274
  var init_utxo = __esm({
275
275
  "src/core/utxo.ts"() {
276
276
  "use strict";
277
- import_web33 = require("@solana/web3.js");
277
+ import_web3 = require("@solana/web3.js");
278
278
  import_circomlibjs2 = require("circomlibjs");
279
279
  import_blake32 = require("@noble/hashes/blake3");
280
280
  FIELD_MODULUS = BigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
281
281
  UTXO_KEY_DOMAIN = new TextEncoder().encode("cloak_utxo_priv_v1");
282
- NATIVE_SOL_MINT = new import_web33.PublicKey("So11111111111111111111111111111111111111112");
282
+ NATIVE_SOL_MINT = new import_web3.PublicKey("So11111111111111111111111111111111111111112");
283
283
  poseidonInstance = null;
284
284
  }
285
285
  });
@@ -290,9 +290,7 @@ __export(index_exports, {
290
290
  CLOAK_PROGRAM_ID: () => CLOAK_PROGRAM_ID,
291
291
  CloakError: () => CloakError,
292
292
  CloakSDK: () => CloakSDK,
293
- DEFAULT_CIRCUITS_URL: () => DEFAULT_CIRCUITS_URL,
294
293
  DEFAULT_TRANSACTION_CIRCUITS_URL: () => DEFAULT_TRANSACTION_CIRCUITS_URL,
295
- EXPECTED_CIRCUIT_HASHES: () => EXPECTED_CIRCUIT_HASHES,
296
294
  FIXED_FEE_LAMPORTS: () => FIXED_FEE_LAMPORTS,
297
295
  LAMPORTS_PER_SOL: () => LAMPORTS_PER_SOL,
298
296
  LocalStorageAdapter: () => LocalStorageAdapter,
@@ -315,7 +313,6 @@ __export(index_exports, {
315
313
  VARIABLE_FEE_NUMERATOR: () => VARIABLE_FEE_NUMERATOR,
316
314
  VARIABLE_FEE_RATE: () => VARIABLE_FEE_RATE,
317
315
  VERSION: () => VERSION,
318
- areCircuitsAvailable: () => areCircuitsAvailable,
319
316
  bigintToBytes32: () => bigintToBytes32,
320
317
  bigintToHex: () => bigintToHex,
321
318
  buildMerkleTree: () => buildMerkleTree,
@@ -329,30 +326,15 @@ __export(index_exports, {
329
326
  chainNoteFromBase64: () => chainNoteFromBase64,
330
327
  chainNoteToBase64: () => chainNoteToBase64,
331
328
  classifyRelayError: () => classifyRelayError,
332
- cleanupStalePendingOperations: () => cleanupStalePendingOperations,
333
- clearPendingDeposits: () => clearPendingDeposits,
334
- clearPendingWithdrawals: () => clearPendingWithdrawals,
335
329
  computeChainNoteHash: () => computeChainNoteHash,
336
- computeCommitment: () => computeCommitment,
337
330
  computeExtDataHash: () => computeExtDataHash,
338
331
  computeMerkleRoot: () => computeMerkleRoot,
339
- computeNullifier: () => computeNullifier,
340
- computeNullifierAsync: () => computeNullifierAsync,
341
- computeNullifierSync: () => computeNullifierSync,
342
- computeOutputsHash: () => computeOutputsHash,
343
- computeOutputsHashAsync: () => computeOutputsHashAsync,
344
- computeOutputsHashSync: () => computeOutputsHashSync,
345
332
  computeProofForLatestDeposit: () => computeProofForLatestDeposit,
346
333
  computeProofFromChain: () => computeProofFromChain,
347
334
  computeSignature: () => computeSignature,
348
- computeSwapOutputsHash: () => computeSwapOutputsHash,
349
- computeSwapOutputsHashAsync: () => computeSwapOutputsHashAsync,
350
- computeSwapOutputsHashSync: () => computeSwapOutputsHashSync,
351
- computeUtxoCommitment: () => computeCommitment2,
352
- computeUtxoNullifier: () => computeNullifier2,
353
- copyNoteToClipboard: () => copyNoteToClipboard,
335
+ computeUtxoCommitment: () => computeCommitment,
336
+ computeUtxoNullifier: () => computeNullifier,
354
337
  createCloakError: () => createCloakError,
355
- createDepositInstruction: () => createDepositInstruction,
356
338
  createLogger: () => createLogger,
357
339
  createUtxo: () => createUtxo,
358
340
  createZeroUtxo: () => createZeroUtxo,
@@ -372,78 +354,52 @@ __export(index_exports, {
372
354
  deriveViewingKeyFromUtxoPrivateKey: () => deriveViewingKeyFromUtxoPrivateKey,
373
355
  deserializeUtxo: () => deserializeUtxo,
374
356
  detectNetworkFromRpcUrl: () => detectNetworkFromRpcUrl,
375
- downloadNote: () => downloadNote,
376
- encodeNoteSimple: () => encodeNoteSimple,
377
357
  encryptCompactChainNote: () => encryptCompactChainNote,
378
358
  encryptNoteForRecipient: () => encryptNoteForRecipient,
379
359
  encryptTransactionMetadata: () => encryptTransactionMetadata,
380
360
  encryptTransactionMetadataBundle: () => encryptTransactionMetadataBundle,
381
361
  expandSpendKey: () => expandSpendKey,
382
362
  exportKeys: () => exportKeys,
383
- exportNote: () => exportNote,
384
- exportWalletKeys: () => exportWalletKeys,
385
363
  fetchCommitments: () => fetchCommitments,
386
364
  fetchRiskQuoteInstruction: () => fetchRiskQuoteInstruction,
387
365
  fetchRiskQuoteIx: () => fetchRiskQuoteIx,
388
- filterNotesByNetwork: () => filterNotesByNetwork,
389
- filterWithdrawableNotes: () => filterWithdrawableNotes,
390
- findNoteByCommitment: () => findNoteByCommitment,
391
366
  formatAmount: () => formatAmount,
392
367
  formatComplianceCsv: () => formatComplianceCsv,
393
368
  formatErrorForLogging: () => formatErrorForLogging,
394
369
  formatSol: () => formatSol,
395
370
  fullWithdraw: () => fullWithdraw,
396
371
  generateCloakKeys: () => generateCloakKeys,
397
- generateCommitment: () => generateCommitment,
398
- generateCommitmentAsync: () => generateCommitmentAsync,
399
372
  generateMasterSeed: () => generateMasterSeed,
400
- generateNote: () => generateNote,
401
- generateNoteFromWallet: () => generateNoteFromWallet,
402
373
  generateUtxoKeypair: () => generateUtxoKeypair,
403
374
  generateViewingKeyPair: () => generateViewingKeyPair,
404
- generateWithdrawRegularProof: () => generateWithdrawRegularProof,
405
- generateWithdrawSwapProof: () => generateWithdrawSwapProof,
406
375
  getAddressExplorerUrl: () => getAddressExplorerUrl,
407
376
  getCircuitsPath: () => getCircuitsPath,
408
- getDefaultCircuitsPath: () => getDefaultCircuitsPath,
409
377
  getDistributableAmount: () => getDistributableAmount,
410
378
  getExplorerUrl: () => getExplorerUrl,
411
379
  getNkFromUtxoPrivateKey: () => getNkFromUtxoPrivateKey,
412
380
  getNullifierPDA: () => getNullifierPDA,
413
- getPendingOperationsSummary: () => getPendingOperationsSummary,
414
381
  getPublicKey: () => getPublicKey,
415
- getPublicViewKey: () => getPublicViewKey,
416
- getRecipientAmount: () => getRecipientAmount,
417
382
  getRpcUrlForNetwork: () => getRpcUrlForNetwork,
418
383
  getShieldPoolPDAs: () => getShieldPoolPDAs,
419
384
  getSwapStatePDA: () => getSwapStatePDA,
420
- getViewKey: () => getViewKey,
421
- hasPendingOperations: () => hasPendingOperations,
422
385
  hexToBigint: () => hexToBigint,
423
386
  hexToBytes: () => hexToBytes,
424
387
  importKeys: () => importKeys,
425
- importWalletKeys: () => importWalletKeys,
426
388
  isDebugEnabled: () => isDebugEnabled,
427
389
  isRootNotFoundError: () => isRootNotFoundError,
428
390
  isValidHex: () => isValidHex,
429
391
  isValidRpcUrl: () => isValidRpcUrl,
430
392
  isValidSolanaAddress: () => isValidSolanaAddress,
431
393
  isWithdrawAmountSufficient: () => isWithdrawAmountSufficient,
432
- isWithdrawable: () => isWithdrawable,
433
394
  keypairToAdapter: () => keypairToAdapter,
434
- loadPendingDeposits: () => loadPendingDeposits,
435
- loadPendingWithdrawals: () => loadPendingWithdrawals,
436
395
  parseAmount: () => parseAmount,
437
396
  parseError: () => parseError,
438
- parseNote: () => parseNote,
439
397
  parseRelayErrorResponse: () => parseRelayErrorResponse,
440
398
  parseTransactionError: () => parseTransactionError,
441
399
  partialWithdraw: () => partialWithdraw,
442
400
  poseidonHash: () => poseidonHash,
443
401
  preflightCheck: () => preflightCheck,
444
402
  preflightNullifiers: () => preflightNullifiers,
445
- prepareEncryptedOutput: () => prepareEncryptedOutput,
446
- prepareEncryptedOutputForRecipient: () => prepareEncryptedOutputForRecipient,
447
403
  proofToBytes: () => proofToBytes,
448
404
  pubkeyToFieldElement: () => pubkeyToFieldElement,
449
405
  pubkeyToLimbs: () => pubkeyToLimbs,
@@ -451,16 +407,11 @@ __export(index_exports, {
451
407
  randomFieldElement: () => randomFieldElement,
452
408
  readMerkleTreeState: () => readMerkleTreeState,
453
409
  registerViewingKey: () => registerViewingKey,
454
- removePendingDeposit: () => removePendingDeposit,
455
- removePendingWithdrawal: () => removePendingWithdrawal,
456
- savePendingDeposit: () => savePendingDeposit,
457
- savePendingWithdrawal: () => savePendingWithdrawal,
458
410
  scanNotesForWallet: () => scanNotesForWallet,
459
411
  scanTransactions: () => scanTransactions,
460
412
  sdkLogger: () => sdkLogger,
461
413
  selectUtxos: () => selectUtxos,
462
414
  sendTransaction: () => sendTransaction,
463
- serializeNote: () => serializeNote,
464
415
  serializeUtxo: () => serializeUtxo,
465
416
  setCircuitsPath: () => setCircuitsPath,
466
417
  setDebugMode: () => setDebugMode,
@@ -474,21 +425,12 @@ __export(index_exports, {
474
425
  transfer: () => transfer,
475
426
  truncate: () => truncate,
476
427
  tryDecryptNote: () => tryDecryptNote,
477
- updateNoteWithDeposit: () => updateNoteWithDeposit,
478
- updatePendingDeposit: () => updatePendingDeposit,
479
- updatePendingWithdrawal: () => updatePendingWithdrawal,
480
428
  utxoBigintToBytes32: () => bigintToBytes322,
481
429
  utxoEquals: () => utxoEquals,
482
430
  utxoHexToBigint: () => hexToBigint2,
483
- validateDepositParams: () => validateDepositParams,
484
- validateNote: () => validateNote,
485
431
  validateOutputsSum: () => validateOutputsSum,
486
432
  validateRoot: () => validateRoot,
487
- validateTransfers: () => validateTransfers,
488
433
  validateWalletConnected: () => validateWalletConnected,
489
- validateWithdrawableNote: () => validateWithdrawableNote,
490
- verifyAllCircuits: () => verifyAllCircuits,
491
- verifyCircuitIntegrity: () => verifyCircuitIntegrity,
492
434
  verifyUtxos: () => verifyUtxos,
493
435
  waitForRoot: () => waitForRoot,
494
436
  withTiming: () => withTiming
@@ -496,7 +438,7 @@ __export(index_exports, {
496
438
  module.exports = __toCommonJS(index_exports);
497
439
 
498
440
  // src/core/CloakSDK.ts
499
- var import_web35 = require("@solana/web3.js");
441
+ var import_web33 = require("@solana/web3.js");
500
442
 
501
443
  // src/core/types.ts
502
444
  var CloakError = class extends Error {
@@ -553,79 +495,6 @@ function hexToBigint(hex) {
553
495
  const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
554
496
  return BigInt("0x" + cleanHex);
555
497
  }
556
- async function computeCommitment(amount, r, sk_spend) {
557
- const [sk0, sk1] = splitTo2Limbs(sk_spend);
558
- const [r0, r1] = splitTo2Limbs(r);
559
- const pk_spend = await poseidonHash([sk0, sk1]);
560
- return await poseidonHash([amount, r0, r1, pk_spend]);
561
- }
562
- async function generateCommitmentAsync(amountLamports, r, skSpend) {
563
- const amount = BigInt(amountLamports);
564
- const rValue = hexToBigint(bytesToHex(r));
565
- const skValue = hexToBigint(bytesToHex(skSpend));
566
- return await computeCommitment(amount, rValue, skValue);
567
- }
568
- function generateCommitment(_amountLamports, _r, _skSpend) {
569
- throw new Error("generateCommitment is deprecated. Use generateCommitmentAsync instead.");
570
- }
571
- async function computeNullifier(sk_spend, leafIndex) {
572
- const [sk0, sk1] = splitTo2Limbs(sk_spend);
573
- return await poseidonHash([sk0, sk1, leafIndex]);
574
- }
575
- async function computeNullifierAsync(skSpend, leafIndex) {
576
- const skValue = typeof skSpend === "string" ? hexToBigint(skSpend) : hexToBigint(bytesToHex(skSpend));
577
- return await computeNullifier(skValue, BigInt(leafIndex));
578
- }
579
- function computeNullifierSync(_skSpend, _leafIndex) {
580
- throw new Error("computeNullifierSync is deprecated. Use computeNullifierAsync instead.");
581
- }
582
- async function computeOutputsHashAsync(outputs) {
583
- let hash = 0n;
584
- for (const output of outputs) {
585
- const [lo, hi] = pubkeyToLimbs(output.recipient);
586
- hash = await poseidonHash([hash, lo, hi, BigInt(output.amount)]);
587
- }
588
- return hash;
589
- }
590
- async function computeOutputsHash(outAddr, outAmount, outFlags) {
591
- let hash = 0n;
592
- for (let i = 0; i < 5; i++) {
593
- if (outFlags[i] === 1) {
594
- hash = await poseidonHash([hash, outAddr[i][0], outAddr[i][1], outAmount[i]]);
595
- }
596
- }
597
- return hash;
598
- }
599
- function computeOutputsHashSync(_outputs) {
600
- throw new Error("computeOutputsHashSync is deprecated. Use computeOutputsHashAsync instead.");
601
- }
602
- async function computeSwapOutputsHash(inputMintLimbs, outputMintLimbs, recipientAtaLimbs, minOutputAmount, publicAmount) {
603
- return await poseidonHash([
604
- inputMintLimbs[0],
605
- inputMintLimbs[1],
606
- outputMintLimbs[0],
607
- outputMintLimbs[1],
608
- recipientAtaLimbs[0],
609
- recipientAtaLimbs[1],
610
- minOutputAmount,
611
- publicAmount
612
- ]);
613
- }
614
- async function computeSwapOutputsHashAsync(inputMint, outputMint, recipientAta, minOutputAmount, amount) {
615
- const inputMintLimbs = pubkeyToLimbs(inputMint);
616
- const outputMintLimbs = pubkeyToLimbs(outputMint);
617
- const recipientAtaLimbs = pubkeyToLimbs(recipientAta);
618
- return await computeSwapOutputsHash(
619
- inputMintLimbs,
620
- outputMintLimbs,
621
- recipientAtaLimbs,
622
- BigInt(minOutputAmount),
623
- BigInt(amount)
624
- );
625
- }
626
- function computeSwapOutputsHashSync(_outputMint, _recipientAta, _minOutputAmount, _amount) {
627
- throw new Error("computeSwapOutputsHashSync is deprecated. Use computeSwapOutputsHashAsync instead.");
628
- }
629
498
  function bigintToBytes32(n) {
630
499
  const hex = n.toString(16).padStart(64, "0");
631
500
  const bytes = new Uint8Array(32);
@@ -898,223 +767,11 @@ function importKeys(exported) {
898
767
  return generateCloakKeys(masterSeed);
899
768
  }
900
769
 
901
- // src/utils/network.ts
902
- function detectNetworkFromRpcUrl(rpcUrl) {
903
- const url = rpcUrl || process.env.NEXT_PUBLIC_SOLANA_RPC_URL || "";
904
- const lowerUrl = url.toLowerCase();
905
- if (lowerUrl.includes("mainnet") || lowerUrl.includes("api.mainnet-beta") || lowerUrl.includes("mainnet-beta")) {
906
- return "mainnet";
907
- }
908
- if (lowerUrl.includes("testnet") || lowerUrl.includes("api.testnet")) {
909
- return "testnet";
910
- }
911
- if (lowerUrl.includes("devnet") || lowerUrl.includes("api.devnet")) {
912
- return "devnet";
913
- }
914
- if (lowerUrl.includes("localhost") || lowerUrl.includes("127.0.0.1") || lowerUrl.includes("local")) {
915
- return "localnet";
916
- }
917
- return "mainnet";
918
- }
919
- function getRpcUrlForNetwork(network) {
920
- switch (network) {
921
- case "mainnet":
922
- return "https://api.mainnet-beta.solana.com";
923
- case "devnet":
924
- return "https://api.devnet.solana.com";
925
- case "localnet":
926
- return "http://localhost:8899";
927
- default:
928
- return "https://api.mainnet-beta.solana.com";
929
- }
930
- }
931
- function isValidRpcUrl(url) {
932
- try {
933
- const parsed = new URL(url);
934
- return parsed.protocol === "http:" || parsed.protocol === "https:";
935
- } catch {
936
- return false;
937
- }
938
- }
939
- function getExplorerUrl(signature, network = "devnet") {
940
- const cluster = network === "mainnet" ? "" : `?cluster=${network}`;
941
- return `https://explorer.solana.com/tx/${signature}${cluster}`;
942
- }
943
- function getAddressExplorerUrl(address, network = "devnet") {
944
- const cluster = network === "mainnet" ? "" : `?cluster=${network}`;
945
- return `https://explorer.solana.com/address/${address}${cluster}`;
946
- }
947
-
948
- // src/utils/fees.ts
949
- var LAMPORTS_PER_SOL = 1e9;
950
- var FIXED_FEE_LAMPORTS = 5e6;
951
- var VARIABLE_FEE_NUMERATOR = 3;
952
- var VARIABLE_FEE_DENOMINATOR = 1e3;
953
- var VARIABLE_FEE_RATE = VARIABLE_FEE_NUMERATOR / VARIABLE_FEE_DENOMINATOR;
954
- var MIN_DEPOSIT_LAMPORTS = 1e7;
955
- function calculateFee(amountLamports) {
956
- const variableFee = Math.floor(amountLamports * VARIABLE_FEE_NUMERATOR / VARIABLE_FEE_DENOMINATOR);
957
- return FIXED_FEE_LAMPORTS + variableFee;
958
- }
959
- function calculateFeeBigint(amountLamports) {
960
- const fixed = BigInt(FIXED_FEE_LAMPORTS);
961
- const variable = amountLamports * BigInt(VARIABLE_FEE_NUMERATOR) / BigInt(VARIABLE_FEE_DENOMINATOR);
962
- return fixed + variable;
963
- }
964
- function isWithdrawAmountSufficient(amountLamports) {
965
- return amountLamports > calculateFeeBigint(amountLamports);
966
- }
967
- function getDistributableAmount(amountLamports) {
968
- return amountLamports - calculateFee(amountLamports);
969
- }
970
- function formatAmount(lamports, decimals = 9) {
971
- return (lamports / LAMPORTS_PER_SOL).toFixed(decimals);
972
- }
973
- function parseAmount(sol) {
974
- const num = parseFloat(sol);
975
- if (isNaN(num) || num < 0) {
976
- throw new Error(`Invalid SOL amount: ${sol}`);
977
- }
978
- return Math.floor(num * LAMPORTS_PER_SOL);
979
- }
980
- function validateOutputsSum(outputs, expectedTotal) {
981
- const sum = outputs.reduce((acc, out) => acc + out.amount, 0);
982
- return sum === expectedTotal;
983
- }
984
- function calculateRelayFee(amountLamports, feeBps) {
985
- if (feeBps < 0 || feeBps > 1e4) {
986
- throw new Error("Fee basis points must be between 0 and 10000");
987
- }
988
- return Math.floor(amountLamports * feeBps / 1e4);
989
- }
990
-
991
- // src/core/note-manager.ts
992
- async function generateNote(amountLamports, network) {
993
- const actualNetwork = network || detectNetworkFromRpcUrl();
994
- const skSpend = randomBytes(32);
995
- const rBytes = randomBytes(32);
996
- const commitmentBigint = await generateCommitmentAsync(amountLamports, rBytes, skSpend);
997
- const commitmentHex = commitmentBigint.toString(16).padStart(64, "0");
998
- const skSpendHex = bytesToHex(skSpend);
999
- const rHex = bytesToHex(rBytes);
1000
- return {
1001
- version: "1.0",
1002
- amount: amountLamports,
1003
- commitment: commitmentHex,
1004
- sk_spend: skSpendHex,
1005
- r: rHex,
1006
- timestamp: Date.now(),
1007
- network: actualNetwork
1008
- };
1009
- }
1010
- async function generateNoteFromWallet(amountLamports, keys, network) {
1011
- const actualNetwork = network || detectNetworkFromRpcUrl();
1012
- const rBytes = randomBytes(32);
1013
- const sk_spend = hexToBytes(keys.spend.sk_spend_hex);
1014
- const commitmentBigint = await generateCommitmentAsync(amountLamports, rBytes, sk_spend);
1015
- const commitmentHex = commitmentBigint.toString(16).padStart(64, "0");
1016
- return {
1017
- version: "2.0",
1018
- amount: amountLamports,
1019
- commitment: commitmentHex,
1020
- sk_spend: keys.spend.sk_spend_hex,
1021
- r: bytesToHex(rBytes),
1022
- timestamp: Date.now(),
1023
- network: actualNetwork
1024
- };
1025
- }
1026
- function parseNote(jsonString) {
1027
- const note = JSON.parse(jsonString);
1028
- if (!note.version || !note.amount || !note.commitment || !note.sk_spend || !note.r) {
1029
- throw new CloakError(
1030
- "Invalid note format: missing required fields",
1031
- "validation",
1032
- false
1033
- );
1034
- }
1035
- if (!/^[0-9a-f]{64}$/i.test(note.commitment)) {
1036
- throw new CloakError("Invalid commitment format", "validation", false);
1037
- }
1038
- if (!/^[0-9a-f]{64}$/i.test(note.sk_spend)) {
1039
- throw new CloakError("Invalid sk_spend format", "validation", false);
1040
- }
1041
- if (!/^[0-9a-f]{64}$/i.test(note.r)) {
1042
- throw new CloakError("Invalid r format", "validation", false);
1043
- }
1044
- return note;
1045
- }
1046
- function exportNote(note, pretty = false) {
1047
- return pretty ? JSON.stringify(note, null, 2) : JSON.stringify(note);
1048
- }
1049
- function isWithdrawable(note) {
1050
- return !!(note.depositSignature && note.leafIndex !== void 0 && note.root);
1051
- }
1052
- function updateNoteWithDeposit(note, depositInfo) {
1053
- const updated = {
1054
- ...note,
1055
- depositSignature: depositInfo.signature,
1056
- depositSlot: depositInfo.slot,
1057
- leafIndex: depositInfo.leafIndex,
1058
- root: depositInfo.root
1059
- };
1060
- if (depositInfo.merkleProof) {
1061
- updated.merkleProof = depositInfo.merkleProof;
1062
- }
1063
- return updated;
1064
- }
1065
- function findNoteByCommitment(notes, commitment) {
1066
- return notes.find((n) => n.commitment === commitment);
1067
- }
1068
- function filterNotesByNetwork(notes, network) {
1069
- return notes.filter((n) => n.network === network);
1070
- }
1071
- function filterWithdrawableNotes(notes) {
1072
- return notes.filter(isWithdrawable);
1073
- }
1074
- function exportWalletKeys(keys) {
1075
- return exportKeys(keys);
1076
- }
1077
- function importWalletKeys(keysJson) {
1078
- return importKeys(keysJson);
1079
- }
1080
- function getPublicViewKey(keys) {
1081
- return keys.view.pvk_hex;
1082
- }
1083
- function getViewKey(keys) {
1084
- return keys.view;
1085
- }
1086
- var calculateFee2 = calculateFee;
1087
- function getDistributableAmount2(amountLamports) {
1088
- return amountLamports - calculateFee2(amountLamports);
1089
- }
1090
- function getRecipientAmount(amountLamports) {
1091
- return getDistributableAmount2(amountLamports);
1092
- }
1093
-
1094
770
  // src/core/storage.ts
1095
771
  var MemoryStorageAdapter = class {
1096
772
  constructor() {
1097
- this.notes = /* @__PURE__ */ new Map();
1098
773
  this.keys = null;
1099
774
  }
1100
- saveNote(note) {
1101
- this.notes.set(note.commitment, note);
1102
- }
1103
- loadAllNotes() {
1104
- return Array.from(this.notes.values());
1105
- }
1106
- updateNote(commitment, updates) {
1107
- const existing = this.notes.get(commitment);
1108
- if (existing) {
1109
- this.notes.set(commitment, { ...existing, ...updates });
1110
- }
1111
- }
1112
- deleteNote(commitment) {
1113
- this.notes.delete(commitment);
1114
- }
1115
- clearAllNotes() {
1116
- this.notes.clear();
1117
- }
1118
775
  saveKeys(keys) {
1119
776
  this.keys = keys;
1120
777
  }
@@ -1125,10 +782,10 @@ var MemoryStorageAdapter = class {
1125
782
  this.keys = null;
1126
783
  }
1127
784
  };
1128
- var LocalStorageAdapter = class {
1129
- constructor(notesKey = "cloak_notes", keysKey = "cloak_wallet_keys") {
1130
- this.notesKey = notesKey;
785
+ var _LocalStorageAdapter = class _LocalStorageAdapter {
786
+ constructor(keysKey = "cloak_wallet_keys") {
1131
787
  this.keysKey = keysKey;
788
+ _LocalStorageAdapter.runLegacyPurgeOnce();
1132
789
  }
1133
790
  getStorage() {
1134
791
  if (typeof globalThis !== "undefined" && globalThis.localStorage) {
@@ -1136,47 +793,6 @@ var LocalStorageAdapter = class {
1136
793
  }
1137
794
  return null;
1138
795
  }
1139
- saveNote(note) {
1140
- const storage = this.getStorage();
1141
- if (!storage) throw new Error("localStorage not available");
1142
- const notes = this.loadAllNotes();
1143
- notes.push(note);
1144
- storage.setItem(this.notesKey, JSON.stringify(notes));
1145
- }
1146
- loadAllNotes() {
1147
- const storage = this.getStorage();
1148
- if (!storage) return [];
1149
- const stored = storage.getItem(this.notesKey);
1150
- if (!stored) return [];
1151
- try {
1152
- return JSON.parse(stored);
1153
- } catch {
1154
- return [];
1155
- }
1156
- }
1157
- updateNote(commitment, updates) {
1158
- const storage = this.getStorage();
1159
- if (!storage) return;
1160
- const notes = this.loadAllNotes();
1161
- const index = notes.findIndex((n) => n.commitment === commitment);
1162
- if (index !== -1) {
1163
- notes[index] = { ...notes[index], ...updates };
1164
- storage.setItem(this.notesKey, JSON.stringify(notes));
1165
- }
1166
- }
1167
- deleteNote(commitment) {
1168
- const storage = this.getStorage();
1169
- if (!storage) return;
1170
- const notes = this.loadAllNotes();
1171
- const filtered = notes.filter((n) => n.commitment !== commitment);
1172
- storage.setItem(this.notesKey, JSON.stringify(filtered));
1173
- }
1174
- clearAllNotes() {
1175
- const storage = this.getStorage();
1176
- if (storage) {
1177
- storage.removeItem(this.notesKey);
1178
- }
1179
- }
1180
796
  saveKeys(keys) {
1181
797
  const storage = this.getStorage();
1182
798
  if (!storage) throw new Error("localStorage not available");
@@ -1199,126 +815,64 @@ var LocalStorageAdapter = class {
1199
815
  storage.removeItem(this.keysKey);
1200
816
  }
1201
817
  }
1202
- };
1203
-
1204
- // src/utils/validation.ts
1205
- var import_web3 = require("@solana/web3.js");
1206
- function isValidSolanaAddress(address) {
1207
- try {
1208
- new import_web3.PublicKey(address);
1209
- return true;
1210
- } catch {
1211
- return false;
1212
- }
1213
- }
1214
- function validateNote(note) {
1215
- if (!note || typeof note !== "object") {
1216
- throw new Error("Note must be an object");
1217
- }
1218
- const requiredFields = ["version", "amount", "commitment", "sk_spend", "r", "timestamp", "network"];
1219
- for (const field of requiredFields) {
1220
- if (!(field in note)) {
1221
- throw new Error(`Missing required field: ${field}`);
1222
- }
1223
- }
1224
- if (typeof note.version !== "string") {
1225
- throw new Error("Version must be a string");
1226
- }
1227
- if (typeof note.amount !== "number" || note.amount <= 0) {
1228
- throw new Error("Amount must be a positive number");
1229
- }
1230
- if (!isValidHex(note.commitment, 32)) {
1231
- throw new Error("Invalid commitment format (expected 64 hex characters)");
1232
- }
1233
- if (!isValidHex(note.sk_spend, 32)) {
1234
- throw new Error("Invalid sk_spend format (expected 64 hex characters)");
1235
- }
1236
- if (!isValidHex(note.r, 32)) {
1237
- throw new Error("Invalid r format (expected 64 hex characters)");
1238
- }
1239
- if (typeof note.timestamp !== "number" || note.timestamp <= 0) {
1240
- throw new Error("Timestamp must be a positive number");
1241
- }
1242
- if (!["localnet", "devnet", "testnet", "mainnet"].includes(note.network)) {
1243
- throw new Error("Network must be localnet, devnet, testnet, or mainnet");
1244
- }
1245
- if (note.depositSignature !== void 0 && typeof note.depositSignature !== "string") {
1246
- throw new Error("Deposit signature must be a string");
1247
- }
1248
- if (note.depositSlot !== void 0 && typeof note.depositSlot !== "number") {
1249
- throw new Error("Deposit slot must be a number");
1250
- }
1251
- if (note.leafIndex !== void 0) {
1252
- if (typeof note.leafIndex !== "number" || note.leafIndex < 0) {
1253
- throw new Error("Leaf index must be a non-negative number");
1254
- }
1255
- }
1256
- if (note.root !== void 0 && !isValidHex(note.root, 32)) {
1257
- throw new Error("Invalid root format (expected 64 hex characters)");
1258
- }
1259
- if (note.merkleProof !== void 0) {
1260
- if (!Array.isArray(note.merkleProof.pathElements)) {
1261
- throw new Error("Merkle proof pathElements must be an array");
818
+ /**
819
+ * Runs the legacy-purge exactly once per browser origin. Invoked
820
+ * automatically by the constructor; exposed as a static for tests and
821
+ * for callers who want to force the check before the first adapter
822
+ * instantiation.
823
+ */
824
+ static runLegacyPurgeOnce() {
825
+ if (typeof globalThis === "undefined" || !globalThis.localStorage) {
826
+ return;
1262
827
  }
1263
- if (!Array.isArray(note.merkleProof.pathIndices)) {
1264
- throw new Error("Merkle proof pathIndices must be an array");
828
+ const storage = globalThis.localStorage;
829
+ if (storage.getItem(_LocalStorageAdapter.LEGACY_PURGE_SENTINEL_KEY)) {
830
+ return;
1265
831
  }
1266
- if (note.merkleProof.pathElements.length !== note.merkleProof.pathIndices.length) {
1267
- throw new Error("Merkle proof pathElements and pathIndices must have same length");
832
+ storage.removeItem(_LocalStorageAdapter.LEGACY_NOTES_KEY);
833
+ try {
834
+ storage.setItem(_LocalStorageAdapter.LEGACY_PURGE_SENTINEL_KEY, "1");
835
+ } catch {
1268
836
  }
1269
837
  }
1270
- }
1271
- function parseNote2(jsonString) {
1272
- let parsed;
1273
- try {
1274
- parsed = JSON.parse(jsonString);
1275
- } catch (error) {
1276
- throw new Error("Invalid JSON format");
1277
- }
1278
- validateNote(parsed);
1279
- return parsed;
1280
- }
1281
- function validateWithdrawableNote(note) {
1282
- if (!note.depositSignature) {
1283
- throw new Error("Note must be deposited before withdrawal (missing depositSignature)");
1284
- }
1285
- if (note.leafIndex === void 0) {
1286
- throw new Error("Note must be deposited before withdrawal (missing leafIndex)");
1287
- }
1288
- if (!note.root) {
1289
- throw new Error("Note must have historical root for withdrawal");
1290
- }
1291
- if (!note.merkleProof) {
1292
- throw new Error("Note must have Merkle proof for withdrawal");
1293
- }
1294
- if (note.merkleProof.pathElements.length === 0) {
1295
- throw new Error("Merkle proof is empty");
1296
- }
1297
- }
1298
- function validateTransfers(recipients, totalAmount) {
1299
- if (recipients.length === 0) {
1300
- throw new Error("At least one recipient is required");
1301
- }
1302
- if (recipients.length > 5) {
1303
- throw new Error("Maximum 5 recipients allowed");
1304
- }
1305
- for (let i = 0; i < recipients.length; i++) {
1306
- const transfer2 = recipients[i];
1307
- const isPublicKeyLike = transfer2.recipient && typeof transfer2.recipient.toBase58 === "function" && typeof transfer2.recipient.toBuffer === "function";
1308
- if (!isPublicKeyLike) {
1309
- throw new Error(`Recipient ${i} must be a PublicKey (got ${typeof transfer2.recipient})`);
1310
- }
1311
- if (typeof transfer2.amount !== "number" || transfer2.amount <= 0) {
1312
- throw new Error(`Recipient ${i} amount must be a positive number`);
838
+ /**
839
+ * Manual cleanup helper for callers that stored notes under a non-default
840
+ * key. The auto-purge in the constructor only handles the canonical
841
+ * `cloak_notes` slot; pass the custom key here.
842
+ *
843
+ * Pre-0.1.6 versions stored the user's `CloakNote[]` (including
844
+ * `r` randomness and `sk_spend` secret-key hex) as JSON plaintext.
845
+ * Those notes are no longer usable (the OLD `withdraw_regular.circom`
846
+ * flow is incompatible with the deployed UTXO program) but the plaintext
847
+ * would otherwise linger indefinitely.
848
+ *
849
+ * Idempotent; safe to call when the key doesn't exist or when running
850
+ * outside a browser (no-op). Does NOT update the auto-purge sentinel.
851
+ *
852
+ * @param notesKey - localStorage key to remove (default `"cloak_notes"`,
853
+ * matching the pre-0.1.6 default).
854
+ */
855
+ static purgeLegacyNoteStorage(notesKey = _LocalStorageAdapter.LEGACY_NOTES_KEY) {
856
+ if (typeof globalThis === "undefined" || !globalThis.localStorage) {
857
+ return;
1313
858
  }
859
+ globalThis.localStorage.removeItem(notesKey);
1314
860
  }
1315
- const sum = recipients.reduce((acc, t) => acc + t.amount, 0);
1316
- if (sum !== totalAmount) {
1317
- throw new Error(
1318
- `Recipients sum (${sum}) does not match expected total (${totalAmount})`
1319
- );
1320
- }
1321
- }
861
+ };
862
+ /**
863
+ * Sentinel key set after the auto-purge runs. Persists across browser
864
+ * sessions so the purge never re-runs on the same origin.
865
+ */
866
+ _LocalStorageAdapter.LEGACY_PURGE_SENTINEL_KEY = "cloak_purged_v0_1_5";
867
+ /**
868
+ * Default localStorage key the legacy `<= 0.1.5` SDK used for the
869
+ * plaintext `CloakNote[]` blob.
870
+ */
871
+ _LocalStorageAdapter.LEGACY_NOTES_KEY = "cloak_notes";
872
+ var LocalStorageAdapter = _LocalStorageAdapter;
873
+
874
+ // src/services/RelayService.ts
875
+ var import_sha2 = require("@noble/hashes/sha2");
1322
876
 
1323
877
  // src/utils/errors.ts
1324
878
  var RootNotFoundError = class extends Error {
@@ -2214,7 +1768,6 @@ function formatErrorForLogging(error) {
2214
1768
  }
2215
1769
 
2216
1770
  // src/services/RelayService.ts
2217
- var import_sha2 = require("@noble/hashes/sha2");
2218
1771
  var RelayService = class {
2219
1772
  /**
2220
1773
  * Create a new Relay Service client
@@ -2583,88 +2136,24 @@ var RelayService = class {
2583
2136
  }
2584
2137
  };
2585
2138
 
2586
- // src/solana/instructions.ts
2587
- var import_web32 = require("@solana/web3.js");
2588
- function createDepositInstruction(params) {
2589
- if (params.commitment.length !== 32) {
2590
- throw new Error(
2591
- `Invalid commitment length: ${params.commitment.length} (expected 32 bytes)`
2592
- );
2593
- }
2594
- if (params.amount <= 0) {
2595
- throw new Error("Amount must be positive");
2596
- }
2597
- const discriminant = new Uint8Array([1]);
2598
- const amountBytes = new Uint8Array(8);
2599
- new DataView(amountBytes.buffer).setBigUint64(
2600
- 0,
2601
- BigInt(params.amount),
2602
- true
2603
- // little-endian
2604
- );
2605
- const data = new Uint8Array(41);
2606
- data.set(discriminant, 0);
2607
- data.set(amountBytes, 1);
2608
- data.set(params.commitment, 9);
2609
- return new import_web32.TransactionInstruction({
2610
- programId: params.programId,
2611
- keys: [
2612
- // Account 0: Payer (signer, writable) - pays for transaction
2613
- { pubkey: params.payer, isSigner: true, isWritable: true },
2614
- // Account 1: Pool (writable) - receives SOL
2615
- { pubkey: params.pool, isSigner: false, isWritable: true },
2616
- // Account 2: System Program (readonly) - for transfers
2617
- { pubkey: import_web32.SystemProgram.programId, isSigner: false, isWritable: false },
2618
- // Account 3: Merkle Tree (writable) - stores on-chain Merkle tree
2619
- { pubkey: params.merkleTree, isSigner: false, isWritable: true }
2620
- ],
2621
- data: Buffer.from(data)
2622
- });
2623
- }
2624
- function validateDepositParams(params) {
2625
- if (!(params.programId instanceof import_web32.PublicKey)) {
2626
- throw new Error("programId must be a PublicKey");
2627
- }
2628
- if (!(params.payer instanceof import_web32.PublicKey)) {
2629
- throw new Error("payer must be a PublicKey");
2630
- }
2631
- if (!(params.pool instanceof import_web32.PublicKey)) {
2632
- throw new Error("pool must be a PublicKey");
2633
- }
2634
- if (!(params.merkleTree instanceof import_web32.PublicKey)) {
2635
- throw new Error("merkleTree must be a PublicKey");
2636
- }
2637
- if (typeof params.amount !== "number" || params.amount <= 0) {
2638
- throw new Error("amount must be a positive number");
2639
- }
2640
- if (!(params.commitment instanceof Uint8Array)) {
2641
- throw new Error("commitment must be a Uint8Array");
2642
- }
2643
- if (params.commitment.length !== 32) {
2644
- throw new Error(
2645
- `commitment must be 32 bytes (got ${params.commitment.length})`
2646
- );
2647
- }
2648
- }
2649
-
2650
2139
  // src/utils/pda.ts
2651
- var import_web34 = require("@solana/web3.js");
2140
+ var import_web32 = require("@solana/web3.js");
2652
2141
  init_utxo();
2653
2142
  function getShieldPoolPDAs(programId, mint = NATIVE_SOL_MINT) {
2654
2143
  const pid = programId || CLOAK_PROGRAM_ID;
2655
- const [pool] = import_web34.PublicKey.findProgramAddressSync(
2144
+ const [pool] = import_web32.PublicKey.findProgramAddressSync(
2656
2145
  [Buffer.from("pool"), mint.toBuffer()],
2657
2146
  pid
2658
2147
  );
2659
- const [merkleTree] = import_web34.PublicKey.findProgramAddressSync(
2148
+ const [merkleTree] = import_web32.PublicKey.findProgramAddressSync(
2660
2149
  [Buffer.from("merkle_tree"), mint.toBuffer()],
2661
2150
  pid
2662
2151
  );
2663
- const [treasury] = import_web34.PublicKey.findProgramAddressSync(
2152
+ const [treasury] = import_web32.PublicKey.findProgramAddressSync(
2664
2153
  [Buffer.from("treasury"), mint.toBuffer()],
2665
2154
  pid
2666
2155
  );
2667
- const [vaultAuthority] = import_web34.PublicKey.findProgramAddressSync(
2156
+ const [vaultAuthority] = import_web32.PublicKey.findProgramAddressSync(
2668
2157
  [Buffer.from("vault_authority"), mint.toBuffer()],
2669
2158
  pid
2670
2159
  );
@@ -2680,7 +2169,7 @@ function getNullifierPDA(poolPubkey, nullifier, programId) {
2680
2169
  if (nullifier.length !== 32) {
2681
2170
  throw new Error(`Nullifier must be 32 bytes, got ${nullifier.length}`);
2682
2171
  }
2683
- return import_web34.PublicKey.findProgramAddressSync(
2172
+ return import_web32.PublicKey.findProgramAddressSync(
2684
2173
  [Buffer.from("nullifier"), poolPubkey.toBuffer(), Buffer.from(nullifier)],
2685
2174
  pid
2686
2175
  );
@@ -2690,270 +2179,26 @@ function getSwapStatePDA(poolPubkey, nullifier, programId) {
2690
2179
  if (nullifier.length !== 32) {
2691
2180
  throw new Error(`Nullifier must be 32 bytes, got ${nullifier.length}`);
2692
2181
  }
2693
- return import_web34.PublicKey.findProgramAddressSync(
2182
+ return import_web32.PublicKey.findProgramAddressSync(
2694
2183
  [Buffer.from("swap_state"), poolPubkey.toBuffer(), Buffer.from(nullifier)],
2695
2184
  pid
2696
2185
  );
2697
2186
  }
2698
2187
 
2699
- // src/utils/proof-generation.ts
2700
- var snarkjs = __toESM(require("snarkjs"), 1);
2701
- var IS_REACT_NATIVE = typeof navigator !== "undefined" && navigator.product === "ReactNative";
2702
- var IS_BROWSER = IS_REACT_NATIVE || typeof window !== "undefined" || typeof globalThis !== "undefined" && typeof globalThis.document !== "undefined";
2703
- var DEFAULT_CIRCUITS_URL = "https://cloak-circuits.s3.us-east-1.amazonaws.com/circuits/0.1.0";
2704
- var SKIP_CIRCUIT_VERIFY_ENV = typeof process !== "undefined" && process.env && process.env.CLOAK_SKIP_CIRCUIT_INTEGRITY_CHECK === "1";
2705
- function isUrl(path) {
2706
- return path.startsWith("http://") || path.startsWith("https://");
2707
- }
2708
- function resolveCircuitsUrl(circuitsPath2) {
2709
- if (circuitsPath2.trim() !== "" && circuitsPath2.trim() !== DEFAULT_CIRCUITS_URL) {
2710
- return DEFAULT_CIRCUITS_URL;
2188
+ // src/core/CloakSDK.ts
2189
+ init_utxo();
2190
+
2191
+ // src/utils/logger.ts
2192
+ var globalDebugEnabled = false;
2193
+ function checkEnvDebug() {
2194
+ if (typeof process !== "undefined" && process.env) {
2195
+ return !!(process.env.CLOAK_DEBUG === "1" || process.env.CLOAK_DEBUG === "true" || process.env.DEBUG?.includes("cloak"));
2711
2196
  }
2712
- return DEFAULT_CIRCUITS_URL;
2197
+ return false;
2713
2198
  }
2714
- async function fetchFileAsBuffer(url) {
2715
- const response = await fetch(url);
2716
- if (!response.ok) {
2717
- throw new Error(`Failed to fetch ${url}: ${response.status} ${response.statusText}`);
2718
- }
2719
- const arrayBuffer = await response.arrayBuffer();
2720
- return new Uint8Array(arrayBuffer);
2721
- }
2722
- async function sha256Hex(data) {
2723
- if (IS_BROWSER) {
2724
- const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data;
2725
- const buffer = bytes.buffer.slice(
2726
- bytes.byteOffset,
2727
- bytes.byteOffset + bytes.byteLength
2728
- );
2729
- const hashBuffer = await crypto.subtle.digest("SHA-256", buffer);
2730
- return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
2731
- }
2732
- const nodeCrypto = await getNodeCrypto();
2733
- return nodeCrypto.createHash("sha256").update(data).digest("hex");
2734
- }
2735
- var _nodeCrypto = null;
2736
- function nodeRequire(moduleName) {
2737
- if (IS_BROWSER) {
2738
- throw new Error(`Node.js ${moduleName} module not available in browser/React Native`);
2739
- }
2740
- try {
2741
- const requireFunc = new Function("moduleName", "return require(moduleName)");
2742
- return requireFunc(moduleName);
2743
- } catch {
2744
- throw new Error(`Cannot load Node.js module ${moduleName} synchronously in ESM.`);
2745
- }
2746
- }
2747
- async function getNodeCrypto() {
2748
- if (_nodeCrypto) return _nodeCrypto;
2749
- _nodeCrypto = nodeRequire("crypto");
2750
- return _nodeCrypto;
2751
- }
2752
- async function generateWithdrawRegularProof(inputs, circuitsPath2) {
2753
- const circuitsUrl = resolveCircuitsUrl(circuitsPath2);
2754
- let wasmInput;
2755
- let zkeyInput;
2756
- if (IS_BROWSER) {
2757
- wasmInput = `${circuitsUrl}/withdraw_regular_js/withdraw_regular.wasm`;
2758
- zkeyInput = `${circuitsUrl}/withdraw_regular_final.zkey`;
2759
- } else {
2760
- const wasmUrl = `${circuitsUrl}/withdraw_regular_js/withdraw_regular.wasm`;
2761
- const zkeyUrl = `${circuitsUrl}/withdraw_regular_final.zkey`;
2762
- const [wasmData, zkeyData] = await Promise.all([
2763
- fetchFileAsBuffer(wasmUrl),
2764
- fetchFileAsBuffer(zkeyUrl)
2765
- ]);
2766
- wasmInput = wasmData;
2767
- zkeyInput = zkeyData;
2768
- }
2769
- const verification = await verifyCircuitIntegrity(circuitsUrl, "withdraw_regular");
2770
- if (!verification.valid) {
2771
- throw new Error(
2772
- `withdraw_regular circuit integrity verification failed: ${verification.error ?? "hash mismatch"}`
2773
- );
2774
- }
2775
- const circuitInputs = {
2776
- // Public signals
2777
- root: inputs.root.toString(),
2778
- nullifier: inputs.nullifier.toString(),
2779
- outputs_hash: inputs.outputs_hash.toString(),
2780
- public_amount: inputs.public_amount.toString(),
2781
- // Private common inputs
2782
- amount: inputs.amount.toString(),
2783
- leaf_index: inputs.leaf_index.toString(),
2784
- sk: inputs.sk.map((x) => x.toString()),
2785
- r: inputs.r.map((x) => x.toString()),
2786
- pathElements: inputs.pathElements.map((x) => x.toString()),
2787
- pathIndices: inputs.pathIndices,
2788
- // Outputs
2789
- num_outputs: inputs.num_outputs,
2790
- out_addr: inputs.out_addr.map((addr) => addr.map((x) => x.toString())),
2791
- out_amount: inputs.out_amount.map((x) => x.toString()),
2792
- out_flags: inputs.out_flags,
2793
- // Fee calculation
2794
- var_fee: inputs.var_fee.toString(),
2795
- rem: inputs.rem.toString()
2796
- };
2797
- const { proof, publicSignals } = await snarkjs.groth16.fullProve(circuitInputs, wasmInput, zkeyInput);
2798
- const proofBytes = proofToBytes(proof);
2799
- return {
2800
- proof,
2801
- publicSignals,
2802
- proofBytes,
2803
- publicInputsBytes: new Uint8Array(0)
2804
- // Not used, kept for compatibility
2805
- };
2806
- }
2807
- async function generateWithdrawSwapProof(inputs, circuitsPath2) {
2808
- const circuitsUrl = resolveCircuitsUrl(circuitsPath2);
2809
- let wasmInput;
2810
- let zkeyInput;
2811
- if (IS_BROWSER) {
2812
- wasmInput = `${circuitsUrl}/withdraw_swap_js/withdraw_swap.wasm`;
2813
- zkeyInput = `${circuitsUrl}/withdraw_swap_final.zkey`;
2814
- } else {
2815
- const wasmUrl = `${circuitsUrl}/withdraw_swap_js/withdraw_swap.wasm`;
2816
- const zkeyUrl = `${circuitsUrl}/withdraw_swap_final.zkey`;
2817
- const [wasmData, zkeyData] = await Promise.all([
2818
- fetchFileAsBuffer(wasmUrl),
2819
- fetchFileAsBuffer(zkeyUrl)
2820
- ]);
2821
- wasmInput = wasmData;
2822
- zkeyInput = zkeyData;
2823
- }
2824
- const verification = await verifyCircuitIntegrity(circuitsUrl, "withdraw_swap");
2825
- if (!verification.valid) {
2826
- throw new Error(
2827
- `withdraw_swap circuit integrity verification failed: ${verification.error ?? "hash mismatch"}`
2828
- );
2829
- }
2830
- const sk = splitTo2Limbs(inputs.sk_spend);
2831
- const r = splitTo2Limbs(inputs.r);
2832
- const circuitInputs = {
2833
- // Public signals (must be provided for witness generation)
2834
- root: inputs.root.toString(),
2835
- nullifier: inputs.nullifier.toString(),
2836
- outputs_hash: inputs.outputs_hash.toString(),
2837
- public_amount: inputs.public_amount.toString(),
2838
- // Private inputs
2839
- sk: sk.map((x) => x.toString()),
2840
- r: r.map((x) => x.toString()),
2841
- amount: inputs.amount.toString(),
2842
- leaf_index: inputs.leaf_index.toString(),
2843
- pathElements: inputs.path_elements.map((x) => x.toString()),
2844
- pathIndices: inputs.path_indices,
2845
- input_mint: inputs.input_mint.map((x) => x.toString()),
2846
- output_mint: inputs.output_mint.map((x) => x.toString()),
2847
- recipient_ata: inputs.recipient_ata.map((x) => x.toString()),
2848
- min_output_amount: inputs.min_output_amount.toString(),
2849
- // Note: fee is computed off-chain and validated on-chain:
2850
- // - fixed_fee is 5000000 (0.005 SOL)
2851
- // - var_fee and rem are computed from amount * 3 / 1000 (0.3%)
2852
- var_fee: inputs.var_fee.toString(),
2853
- rem: inputs.rem.toString()
2854
- };
2855
- const { proof, publicSignals } = await snarkjs.groth16.fullProve(
2856
- circuitInputs,
2857
- wasmInput,
2858
- zkeyInput
2859
- );
2860
- const proofBytes = proofToBytes(proof);
2861
- return {
2862
- proof,
2863
- publicSignals,
2864
- proofBytes,
2865
- publicInputsBytes: new Uint8Array(0)
2866
- // Not used, kept for compatibility
2867
- };
2868
- }
2869
- async function areCircuitsAvailable(circuitsPath2) {
2870
- if (!circuitsPath2 || circuitsPath2 === "") {
2871
- return false;
2872
- }
2873
- return isUrl(resolveCircuitsUrl(circuitsPath2));
2874
- }
2875
- async function getDefaultCircuitsPath() {
2876
- return DEFAULT_CIRCUITS_URL;
2877
- }
2878
- var EXPECTED_CIRCUIT_HASHES = {
2879
- withdraw_regular_wasm: "b80c364c926332111945ef437b07a71720fae774e08206cb11b6171f2a2420a3",
2880
- withdraw_regular_zkey: "6dbca2612f7cc257b897d93384ae9dd09c1617fd1668f8287efb1b124488d144",
2881
- withdraw_swap_wasm: "a296badc0047c211a4724c96a4e64a77cd75fbde7cfa4cf23af3640a723e5686",
2882
- withdraw_swap_zkey: "95251954feaac80396651d12a0df3288630fa75db9410aebecb8aaee17a4f6ea"
2883
- };
2884
- async function verifyCircuitIntegrity(circuitsPath2, circuit) {
2885
- const circuitsUrl = resolveCircuitsUrl(circuitsPath2);
2886
- if (SKIP_CIRCUIT_VERIFY_ENV) {
2887
- return {
2888
- valid: true,
2889
- circuit,
2890
- error: "Verification skipped (CLOAK_SKIP_CIRCUIT_INTEGRITY_CHECK=1)"
2891
- };
2892
- }
2893
- const expected = circuit === "withdraw_regular" ? {
2894
- wasm: EXPECTED_CIRCUIT_HASHES.withdraw_regular_wasm,
2895
- zkey: EXPECTED_CIRCUIT_HASHES.withdraw_regular_zkey
2896
- } : {
2897
- wasm: EXPECTED_CIRCUIT_HASHES.withdraw_swap_wasm,
2898
- zkey: EXPECTED_CIRCUIT_HASHES.withdraw_swap_zkey
2899
- };
2900
- const wasmPath = `${circuitsUrl}/${circuit}_js/${circuit}.wasm`;
2901
- const zkeyPath = `${circuitsUrl}/${circuit}_final.zkey`;
2902
- try {
2903
- const [wasmBytes, zkeyBytes] = await Promise.all([
2904
- fetchFileAsBuffer(wasmPath),
2905
- fetchFileAsBuffer(zkeyPath)
2906
- ]);
2907
- const computed = {
2908
- wasm: await sha256Hex(wasmBytes),
2909
- zkey: await sha256Hex(zkeyBytes)
2910
- };
2911
- if (computed.wasm === expected.wasm && computed.zkey === expected.zkey) {
2912
- return {
2913
- valid: true,
2914
- circuit,
2915
- computed,
2916
- expected
2917
- };
2918
- }
2919
- return {
2920
- valid: false,
2921
- circuit,
2922
- error: `Circuit artifact hash mismatch for ${circuit}`,
2923
- computed,
2924
- expected
2925
- };
2926
- } catch (error) {
2927
- return {
2928
- valid: false,
2929
- circuit,
2930
- error: `Circuit verification failed: ${error instanceof Error ? error.message : String(error)}`
2931
- };
2932
- }
2933
- }
2934
- async function verifyAllCircuits(circuitsPath2) {
2935
- const circuitsUrl = resolveCircuitsUrl(circuitsPath2);
2936
- const results = await Promise.all([
2937
- verifyCircuitIntegrity(circuitsUrl, "withdraw_regular"),
2938
- verifyCircuitIntegrity(circuitsUrl, "withdraw_swap")
2939
- ]);
2940
- return results;
2941
- }
2942
-
2943
- // src/core/CloakSDK.ts
2944
- init_utxo();
2945
-
2946
- // src/utils/logger.ts
2947
- var globalDebugEnabled = false;
2948
- function checkEnvDebug() {
2949
- if (typeof process !== "undefined" && process.env) {
2950
- return !!(process.env.CLOAK_DEBUG === "1" || process.env.CLOAK_DEBUG === "true" || process.env.DEBUG?.includes("cloak"));
2951
- }
2952
- return false;
2953
- }
2954
- globalDebugEnabled = checkEnvDebug();
2955
- function setDebugMode(enabled) {
2956
- globalDebugEnabled = enabled;
2199
+ globalDebugEnabled = checkEnvDebug();
2200
+ function setDebugMode(enabled) {
2201
+ globalDebugEnabled = enabled;
2957
2202
  }
2958
2203
  function isDebugEnabled() {
2959
2204
  return globalDebugEnabled;
@@ -3159,50 +2404,22 @@ async function computeProofInternal(leafIndex, _nextIndex, subtrees) {
3159
2404
  }
3160
2405
 
3161
2406
  // src/core/CloakSDK.ts
3162
- var COMPUTE_BUDGET_PROGRAM_ID = new import_web35.PublicKey("ComputeBudget111111111111111111111111111111");
3163
- function createSetLoadedAccountsDataSizeLimitInstruction(bytes) {
3164
- const data = Buffer.alloc(5);
3165
- data.writeUInt8(4, 0);
3166
- data.writeUInt32LE(bytes, 1);
3167
- return new import_web35.TransactionInstruction({
3168
- keys: [],
3169
- programId: COMPUTE_BUDGET_PROGRAM_ID,
3170
- data
3171
- });
3172
- }
3173
- var CLOAK_PROGRAM_ID = new import_web35.PublicKey("zh1eLd6rSphLejbFfJEneUwzHRfMKxgzrgkfwA6qRkW");
2407
+ var CLOAK_PROGRAM_ID = new import_web33.PublicKey("zh1eLd6rSphLejbFfJEneUwzHRfMKxgzrgkfwA6qRkW");
3174
2408
  var CLOAK_API_URL = "https://api.cloak.ag";
3175
2409
  var CloakSDK = class {
3176
- /**
3177
- * Create a new Cloak SDK client
3178
- *
3179
- * @param config - Client configuration
3180
- *
3181
- * @example Node.js mode (with keypair)
3182
- * ```typescript
3183
- * const sdk = new CloakSDK({
3184
- * keypairBytes: keypair.secretKey,
3185
- * network: "devnet"
3186
- * });
3187
- * ```
3188
- *
3189
- * @example Browser mode (with wallet adapter)
3190
- * ```typescript
3191
- * const sdk = new CloakSDK({
3192
- * wallet: walletAdapter,
3193
- * network: "devnet"
3194
- * });
3195
- * ```
3196
- */
3197
2410
  constructor(config) {
3198
2411
  if (!config.keypairBytes && !config.wallet) {
3199
- throw new Error("Must provide either keypairBytes (Node.js) or wallet (Browser)");
2412
+ throw new CloakError(
2413
+ "Must provide either keypairBytes (Node.js) or wallet (Browser)",
2414
+ "validation",
2415
+ false
2416
+ );
3200
2417
  }
3201
2418
  if (config.debug) {
3202
2419
  setDebugMode(true);
3203
2420
  }
3204
2421
  if (config.keypairBytes) {
3205
- this.keypair = import_web35.Keypair.fromSecretKey(config.keypairBytes);
2422
+ this.keypair = import_web33.Keypair.fromSecretKey(config.keypairBytes);
3206
2423
  }
3207
2424
  this.wallet = config.wallet;
3208
2425
  this.cloakKeys = config.cloakKeys;
@@ -3216,902 +2433,42 @@ var CloakSDK = class {
3216
2433
  }
3217
2434
  }
3218
2435
  const programId = config.programId || CLOAK_PROGRAM_ID;
3219
- const { pool, merkleTree, treasury } = getShieldPoolPDAs(
3220
- programId,
3221
- NATIVE_SOL_MINT
3222
- );
2436
+ const { pool, merkleTree, treasury } = getShieldPoolPDAs(programId, NATIVE_SOL_MINT);
3223
2437
  this.config = {
3224
2438
  network: config.network || "mainnet",
3225
- keypairBytes: config.keypairBytes,
3226
2439
  cloakKeys: config.cloakKeys,
3227
2440
  programId,
3228
- poolAddress: pool,
3229
- merkleTreeAddress: merkleTree,
3230
- treasuryAddress: treasury,
3231
- debug: config.debug
3232
- };
3233
- }
3234
- /**
3235
- * Get the public key for deposits (from keypair or wallet)
3236
- */
3237
- getPublicKey() {
3238
- if (this.keypair) {
3239
- return this.keypair.publicKey;
3240
- }
3241
- if (this.wallet?.publicKey) {
3242
- return this.wallet.publicKey;
3243
- }
3244
- throw new Error("No public key available - wallet not connected or keypair not provided");
3245
- }
3246
- /**
3247
- * Check if the SDK is using a wallet adapter
3248
- */
3249
- isWalletMode() {
3250
- return !!this.wallet && !this.keypair;
3251
- }
3252
- /**
3253
- * Deposit SOL into the Cloak protocol
3254
- *
3255
- * Creates a new note (or uses a provided one), submits a deposit transaction,
3256
- * and registers with the indexer.
3257
- *
3258
- * @param connection - Solana connection
3259
- * @param payer - Payer wallet with sendTransaction method
3260
- * @param amountOrNote - Amount in lamports OR an existing note to deposit
3261
- * @param options - Optional configuration
3262
- * @returns Deposit result with note and transaction info
3263
- *
3264
- * @example
3265
- * ```typescript
3266
- * // Generate and deposit in one step
3267
- * const result = await client.deposit(
3268
- * connection,
3269
- * wallet,
3270
- * 1_000_000_000,
3271
- * {
3272
- * onProgress: (status) => console.log(status)
3273
- * }
3274
- * );
3275
- *
3276
- * // Or deposit a pre-generated note
3277
- * const note = client.generateNote(1_000_000_000);
3278
- * const result = await client.deposit(connection, wallet, note);
3279
- * ```
3280
- */
3281
- async deposit(connection, amountOrNote, options) {
3282
- try {
3283
- let note;
3284
- let isNewNote = false;
3285
- if (typeof amountOrNote === "number") {
3286
- options?.onProgress?.("generating_note", { message: "Generating note with secrets..." });
3287
- note = await generateNote(amountOrNote, this.config.network);
3288
- isNewNote = true;
3289
- } else {
3290
- note = amountOrNote;
3291
- if (note.depositSignature) {
3292
- throw new Error("Note has already been deposited");
3293
- }
3294
- }
3295
- if (isNewNote) {
3296
- await this.storage.saveNote(note);
3297
- if (options?.onNoteGenerated) {
3298
- options?.onProgress?.("awaiting_note_acknowledgment", {
3299
- message: "Waiting for note to be saved before proceeding with deposit..."
3300
- });
3301
- try {
3302
- await options.onNoteGenerated(note);
3303
- } catch (error) {
3304
- throw new Error(
3305
- `Failed to save note before deposit: ${error instanceof Error ? error.message : String(error)}. For your safety, the deposit has been aborted. Your funds are safe.`
3306
- );
3307
- }
3308
- }
3309
- options?.onProgress?.("note_saved", {
3310
- message: "Note saved. Proceeding with on-chain deposit..."
3311
- });
3312
- }
3313
- const payerPubkey = this.getPublicKey();
3314
- const balance = await connection.getBalance(payerPubkey);
3315
- const requiredAmount = note.amount + 5e3;
3316
- if (balance < requiredAmount) {
3317
- throw new Error(
3318
- `Insufficient balance. Required: ${requiredAmount} lamports (${note.amount} + fees), Available: ${balance} lamports`
3319
- );
3320
- }
3321
- const commitmentBytes = hexToBytes(note.commitment);
3322
- const programId = this.config.programId || CLOAK_PROGRAM_ID;
3323
- const depositIx = createDepositInstruction({
3324
- programId,
3325
- payer: payerPubkey,
3326
- pool: this.config.poolAddress,
3327
- merkleTree: this.config.merkleTreeAddress,
3328
- amount: note.amount,
3329
- commitment: commitmentBytes
3330
- });
3331
- const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
3332
- const priorityFee = options?.priorityFee ?? 1e4;
3333
- const cuPriceIx = import_web35.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: priorityFee });
3334
- const dataSizeLimit = options?.loadedAccountsDataSizeLimit ?? 256 * 1024;
3335
- const dataSizeLimitIx = dataSizeLimit > 0 ? createSetLoadedAccountsDataSizeLimitInstruction(dataSizeLimit) : null;
3336
- let computeUnits;
3337
- if (options?.optimizeCU && this.keypair) {
3338
- options?.onProgress?.("simulating", { message: "Simulating transaction for optimal CU..." });
3339
- const simCuLimitIx = import_web35.ComputeBudgetProgram.setComputeUnitLimit({ units: 2e5 });
3340
- const simTransaction = new import_web35.Transaction({
3341
- feePayer: payerPubkey,
3342
- recentBlockhash: blockhash
3343
- }).add(simCuLimitIx).add(cuPriceIx);
3344
- if (dataSizeLimitIx) {
3345
- simTransaction.add(dataSizeLimitIx);
3346
- }
3347
- simTransaction.add(depositIx);
3348
- try {
3349
- const simulation = await connection.simulateTransaction(simTransaction, [this.keypair]);
3350
- if (simulation.value.err) {
3351
- console.warn("Simulation failed, using default CU:", simulation.value.err);
3352
- computeUnits = 4e4;
3353
- } else {
3354
- const simulatedCU = simulation.value.unitsConsumed ?? 3e4;
3355
- computeUnits = Math.ceil(simulatedCU * 1.2);
3356
- console.log(`CU optimization: ${simulatedCU} simulated \u2192 ${computeUnits} limit`);
3357
- }
3358
- } catch (simError) {
3359
- console.warn("Simulation RPC error, using default CU:", simError);
3360
- computeUnits = 4e4;
3361
- }
3362
- } else if (options?.optimizeCU && this.wallet) {
3363
- console.warn("CU optimization via simulation not available in wallet mode (would require double signing). Using default.");
3364
- computeUnits = options?.computeUnits ?? 4e4;
3365
- } else {
3366
- computeUnits = options?.computeUnits ?? 4e4;
3367
- }
3368
- const cuLimitIx = import_web35.ComputeBudgetProgram.setComputeUnitLimit({ units: computeUnits });
3369
- const transaction = new import_web35.Transaction({
3370
- feePayer: payerPubkey,
3371
- recentBlockhash: blockhash
3372
- }).add(cuLimitIx).add(cuPriceIx);
3373
- if (dataSizeLimitIx) {
3374
- transaction.add(dataSizeLimitIx);
3375
- }
3376
- transaction.add(depositIx);
3377
- if (!transaction.feePayer) {
3378
- throw new Error("Transaction feePayer is not set");
3379
- }
3380
- if (!transaction.recentBlockhash) {
3381
- throw new Error("Transaction recentBlockhash is not set");
3382
- }
3383
- let signature;
3384
- if (this.wallet) {
3385
- if (!this.wallet.publicKey) {
3386
- throw new Error("Wallet not connected - publicKey is null");
3387
- }
3388
- if (this.wallet.signTransaction) {
3389
- try {
3390
- const signedTransaction = await this.wallet.signTransaction(transaction);
3391
- const rawTransaction = signedTransaction.serialize();
3392
- signature = await connection.sendRawTransaction(rawTransaction, {
3393
- skipPreflight: options?.skipPreflight || false,
3394
- preflightCommitment: "confirmed",
3395
- maxRetries: 3
3396
- });
3397
- } catch (signError) {
3398
- if (this.wallet.sendTransaction) {
3399
- signature = await this.wallet.sendTransaction(transaction, connection, {
3400
- skipPreflight: options?.skipPreflight || false,
3401
- preflightCommitment: "confirmed",
3402
- maxRetries: 3
3403
- });
3404
- } else {
3405
- throw signError;
3406
- }
3407
- }
3408
- } else if (this.wallet.sendTransaction) {
3409
- signature = await this.wallet.sendTransaction(transaction, connection, {
3410
- skipPreflight: options?.skipPreflight || false,
3411
- preflightCommitment: "confirmed",
3412
- maxRetries: 3
3413
- });
3414
- } else {
3415
- throw new Error("Wallet adapter must provide either sendTransaction or signTransaction");
3416
- }
3417
- } else if (this.keypair) {
3418
- signature = await connection.sendTransaction(transaction, [this.keypair], {
3419
- skipPreflight: options?.skipPreflight || false,
3420
- preflightCommitment: "confirmed",
3421
- maxRetries: 3
3422
- });
3423
- } else {
3424
- throw new Error("No signing method available - provide keypair or wallet");
3425
- }
3426
- const confirmation = await connection.confirmTransaction({
3427
- signature,
3428
- blockhash,
3429
- lastValidBlockHeight
3430
- });
3431
- if (confirmation.value.err) {
3432
- throw new Error(
3433
- `Transaction failed: ${JSON.stringify(confirmation.value.err)}`
3434
- );
3435
- }
3436
- const txDetails = await connection.getTransaction(signature, {
3437
- commitment: "confirmed",
3438
- maxSupportedTransactionVersion: 0
3439
- });
3440
- const depositSlot = txDetails?.slot ?? 0;
3441
- let leafIndex = null;
3442
- let root = null;
3443
- try {
3444
- if (txDetails?.meta?.logMessages) {
3445
- for (const log of txDetails.meta.logMessages) {
3446
- if (log.includes("Program data:")) {
3447
- try {
3448
- const parts = log.split("Program data:");
3449
- if (parts.length > 1) {
3450
- const base64Data = parts[1].trim();
3451
- const eventData = Buffer.from(base64Data, "base64");
3452
- if (eventData.length >= 81 && eventData[0] === 1) {
3453
- const parsedLeafIndex = Number(eventData.readBigUInt64LE(1));
3454
- const loggedCommitment = eventData.slice(9, 41);
3455
- if (Buffer.compare(loggedCommitment, Buffer.from(commitmentBytes)) === 0) {
3456
- leafIndex = parsedLeafIndex;
3457
- const loggedRoot = eventData.slice(49, 81);
3458
- root = Buffer.from(loggedRoot).toString("hex");
3459
- break;
3460
- }
3461
- }
3462
- }
3463
- } catch (e) {
3464
- continue;
3465
- }
3466
- }
3467
- }
3468
- }
3469
- } catch (e) {
3470
- }
3471
- if (leafIndex === null) {
3472
- const programId2 = this.config.programId || CLOAK_PROGRAM_ID;
3473
- const mintForSOL = NATIVE_SOL_MINT;
3474
- const { merkleTree } = getShieldPoolPDAs(programId2, mintForSOL);
3475
- const merkleTreeAccount = await connection.getAccountInfo(merkleTree);
3476
- if (!merkleTreeAccount) {
3477
- throw new Error("Failed to fetch merkle tree account");
3478
- }
3479
- const nextIndex = Number(merkleTreeAccount.data.readBigUInt64LE(32));
3480
- leafIndex = nextIndex - 1;
3481
- const rootBytes = merkleTreeAccount.data.slice(1064, 1096);
3482
- root = Buffer.from(rootBytes).toString("hex");
3483
- }
3484
- if (leafIndex === null || root === null) {
3485
- throw new Error("Failed to get leaf index and root from transaction logs or on-chain state");
3486
- }
3487
- let merkleProof;
3488
- try {
3489
- const programId2 = this.config.programId || CLOAK_PROGRAM_ID;
3490
- const mintForSOL = NATIVE_SOL_MINT;
3491
- const { merkleTree: merkleTreePDA } = getShieldPoolPDAs(programId2, mintForSOL);
3492
- const chainProof = await computeProofFromChain(connection, merkleTreePDA, leafIndex);
3493
- merkleProof = {
3494
- pathElements: chainProof.pathElements,
3495
- pathIndices: chainProof.pathIndices
3496
- };
3497
- root = chainProof.root;
3498
- } catch (proofError) {
3499
- console.warn("[SDK] Could not compute proof from chain, will fetch at withdrawal:", proofError);
3500
- }
3501
- const updatedNote = updateNoteWithDeposit(note, {
3502
- signature,
3503
- slot: depositSlot,
3504
- leafIndex,
3505
- root,
3506
- merkleProof
3507
- });
3508
- await this.storage.updateNote(note.commitment, {
3509
- depositSignature: signature,
3510
- depositSlot,
3511
- leafIndex,
3512
- root,
3513
- merkleProof
3514
- });
3515
- return {
3516
- note: updatedNote,
3517
- signature,
3518
- leafIndex,
3519
- root
3520
- };
3521
- } catch (error) {
3522
- throw this.wrapError(error, "Deposit failed");
3523
- }
3524
- }
3525
- /**
3526
- * Private transfer with up to 5 recipients
3527
- *
3528
- * Handles the complete private transfer flow:
3529
- * 1. If note is not deposited, deposits it first and waits for confirmation
3530
- * 2. Generates a zero-knowledge proof
3531
- * 3. Submits the withdrawal via relay service to recipients
3532
- *
3533
- * This is the main method for performing private transfers - it handles everything!
3534
- *
3535
- * @param connection - Solana connection (required for deposit if not already deposited)
3536
- * @param payer - Payer wallet (required for deposit if not already deposited)
3537
- * @param note - Note to spend (can be deposited or not)
3538
- * @param recipients - Array of 1-5 recipients with amounts
3539
- * @param options - Optional configuration
3540
- * @returns Transfer result with signature and outputs
3541
- *
3542
- * @example
3543
- * ```typescript
3544
- * // Create a note (not deposited yet)
3545
- * const note = client.generateNote(1_000_000_000);
3546
- *
3547
- * // privateTransfer handles the full flow: deposit + withdraw
3548
- * const result = await client.privateTransfer(
3549
- * connection,
3550
- * wallet,
3551
- * note,
3552
- * [
3553
- * { recipient: new PublicKey("..."), amount: 500_000_000 },
3554
- * { recipient: new PublicKey("..."), amount: 492_500_000 }
3555
- * ],
3556
- * {
3557
- * relayFeeBps: 50, // 0.5%
3558
- * onProgress: (status) => console.log(status),
3559
- * onProofProgress: (pct) => console.log(`Proof: ${pct}%`)
3560
- * }
3561
- * );
3562
- * console.log(`Success! TX: ${result.signature}`);
3563
- * ```
3564
- */
3565
- async privateTransfer(connection, note, recipients, options) {
3566
- if (!isWithdrawable(note)) {
3567
- const depositResult = await this.deposit(connection, note, {
3568
- skipPreflight: false
3569
- });
3570
- note = depositResult.note;
3571
- }
3572
- const protocolFee = note.amount - getDistributableAmount(note.amount);
3573
- const feeBps = Math.ceil(protocolFee * 1e4 / note.amount);
3574
- const distributableAmount = getDistributableAmount(note.amount);
3575
- validateTransfers(recipients, distributableAmount);
3576
- if (!note.leafIndex && note.leafIndex !== 0) {
3577
- throw new Error("Note must have a leaf index (note must be deposited)");
3578
- }
3579
- if (!isValidHex(note.r, 32)) {
3580
- throw new Error("Note r must be 64 hex characters (32 bytes)");
3581
- }
3582
- if (!isValidHex(note.sk_spend, 32)) {
3583
- throw new Error("Note sk_spend must be 64 hex characters (32 bytes)");
3584
- }
3585
- const nullifier = await computeNullifierAsync(note.sk_spend, note.leafIndex);
3586
- const nullifierHex = nullifier.toString(16).padStart(64, "0");
3587
- const outputsHash = await computeOutputsHashAsync(recipients);
3588
- const outputsHashHex = outputsHash.toString(16).padStart(64, "0");
3589
- const circuitsPath2 = await getDefaultCircuitsPath();
3590
- const useDirectProof = await areCircuitsAvailable(circuitsPath2);
3591
- if (!useDirectProof) {
3592
- throw new Error(
3593
- `Circuits not available at ${circuitsPath2}. Make sure circuits are built and accessible. Circuit artifacts are pinned to S3 and must be reachable from this environment.`
3594
- );
3595
- }
3596
- const MAX_PROOF_RETRIES = 3;
3597
- let lastError = null;
3598
- for (let attempt = 0; attempt < MAX_PROOF_RETRIES; attempt++) {
3599
- try {
3600
- if (attempt > 0) {
3601
- options?.onProgress?.(`proof_refresh_${attempt + 1}`);
3602
- await new Promise((resolve) => setTimeout(resolve, 1e3));
3603
- }
3604
- let merkleProof;
3605
- let merkleRoot;
3606
- const hasStoredProof = note.merkleProof && note.root && note.merkleProof.pathElements && note.merkleProof.pathElements.length > 0;
3607
- if (attempt === 0 && hasStoredProof) {
3608
- merkleProof = note.merkleProof;
3609
- merkleRoot = note.root;
3610
- } else {
3611
- const programId = this.config.programId || CLOAK_PROGRAM_ID;
3612
- const mintForSOL = NATIVE_SOL_MINT;
3613
- const { merkleTree: merkleTreePDA } = getShieldPoolPDAs(programId, mintForSOL);
3614
- const chainProof = await computeProofFromChain(
3615
- connection,
3616
- merkleTreePDA,
3617
- note.leafIndex
3618
- );
3619
- merkleProof = {
3620
- pathElements: chainProof.pathElements,
3621
- pathIndices: chainProof.pathIndices,
3622
- root: chainProof.root
3623
- };
3624
- merkleRoot = chainProof.root;
3625
- note.merkleProof = merkleProof;
3626
- note.root = merkleRoot;
3627
- }
3628
- if (!merkleProof || !merkleRoot) {
3629
- throw new Error("Failed to get Merkle proof from chain");
3630
- }
3631
- if (!merkleProof.pathElements || merkleProof.pathElements.length === 0) {
3632
- throw new Error("Merkle proof is invalid: missing path elements");
3633
- }
3634
- if (merkleProof.pathElements.length !== merkleProof.pathIndices.length) {
3635
- throw new Error("Merkle proof is invalid: path elements and indices length mismatch");
3636
- }
3637
- for (let i = 0; i < merkleProof.pathIndices.length; i++) {
3638
- const idx = merkleProof.pathIndices[i];
3639
- if (idx !== 0 && idx !== 1) {
3640
- throw new Error(`Merkle proof path index at position ${i} must be 0 or 1, got ${idx}`);
3641
- }
3642
- }
3643
- if (!isValidHex(merkleRoot, 32)) {
3644
- throw new Error("Merkle root must be 64 hex characters (32 bytes)");
3645
- }
3646
- for (let i = 0; i < merkleProof.pathElements.length; i++) {
3647
- const element = merkleProof.pathElements[i];
3648
- if (typeof element !== "string" || !isValidHex(element, 32)) {
3649
- throw new Error(`Merkle proof path element at position ${i} must be 64 hex characters (32 bytes)`);
3650
- }
3651
- }
3652
- const sk_spend_bigint = BigInt("0x" + note.sk_spend);
3653
- const r_bigint = BigInt("0x" + note.r);
3654
- const root_bigint = BigInt("0x" + merkleRoot);
3655
- const nullifier_bigint = BigInt("0x" + nullifierHex);
3656
- const outputs_hash_bigint = BigInt("0x" + outputsHashHex);
3657
- const amount_bigint = BigInt(note.amount);
3658
- const pathElements = merkleProof.pathElements.map((p) => BigInt("0x" + p));
3659
- const outAddr = [];
3660
- for (let i = 0; i < 5; i++) {
3661
- if (i < recipients.length) {
3662
- const [lo, hi] = pubkeyToLimbs(recipients[i].recipient.toBytes());
3663
- outAddr.push([lo, hi]);
3664
- } else {
3665
- outAddr.push([0n, 0n]);
3666
- }
3667
- }
3668
- const t = amount_bigint * 3n;
3669
- const varFee = t / 1000n;
3670
- const rem = t % 1000n;
3671
- const outAmount = [];
3672
- const outFlags = [];
3673
- for (let i = 0; i < 5; i++) {
3674
- if (i < recipients.length) {
3675
- outAmount.push(BigInt(recipients[i].amount));
3676
- outFlags.push(1);
3677
- } else {
3678
- outAmount.push(0n);
3679
- outFlags.push(0);
3680
- }
3681
- }
3682
- const sk = splitTo2Limbs(sk_spend_bigint);
3683
- const r = splitTo2Limbs(r_bigint);
3684
- if (attempt === 0) {
3685
- const computedCommitment = await computeCommitment(amount_bigint, r_bigint, sk_spend_bigint);
3686
- const noteCommitment = BigInt("0x" + note.commitment);
3687
- if (computedCommitment !== noteCommitment) {
3688
- throw new Error(
3689
- `Commitment mismatch! Computed: ${computedCommitment.toString(16)}, Note: ${note.commitment}. This means the note's sk_spend, r, or amount doesn't match what was deposited.`
3690
- );
3691
- }
3692
- }
3693
- const proofInputs = {
3694
- root: root_bigint,
3695
- nullifier: nullifier_bigint,
3696
- outputs_hash: outputs_hash_bigint,
3697
- public_amount: amount_bigint,
3698
- amount: amount_bigint,
3699
- leaf_index: BigInt(note.leafIndex),
3700
- sk,
3701
- r,
3702
- pathElements,
3703
- pathIndices: merkleProof.pathIndices,
3704
- num_outputs: recipients.length,
3705
- out_addr: outAddr,
3706
- out_amount: outAmount,
3707
- out_flags: outFlags,
3708
- var_fee: varFee,
3709
- rem
3710
- };
3711
- options?.onProgress?.("proof_generating");
3712
- const proofResult = await generateWithdrawRegularProof(proofInputs, circuitsPath2);
3713
- options?.onProgress?.("proof_complete");
3714
- const proofHex = Buffer.from(proofResult.proofBytes).toString("hex");
3715
- const finalPublicInputs = {
3716
- root: merkleRoot,
3717
- nf: nullifierHex,
3718
- outputs_hash: outputsHashHex,
3719
- amount: note.amount
3720
- };
3721
- const metadataBundle = options?.metadataBundle;
3722
- const signature = await this.relay.submitWithdraw(
3723
- {
3724
- proof: proofHex,
3725
- publicInputs: finalPublicInputs,
3726
- outputs: recipients.map((r2) => ({
3727
- recipient: r2.recipient.toBase58(),
3728
- amount: r2.amount
3729
- })),
3730
- feeBps,
3731
- // Use calculated protocol fee BPS
3732
- metadataBundle
3733
- },
3734
- options?.onProgress
3735
- );
3736
- return {
3737
- signature,
3738
- outputs: recipients.map((r2) => ({
3739
- recipient: r2.recipient.toBase58(),
3740
- amount: r2.amount
3741
- })),
3742
- nullifier: nullifierHex,
3743
- root: merkleRoot
3744
- };
3745
- } catch (error) {
3746
- lastError = error instanceof Error ? error : new Error(String(error));
3747
- if (error instanceof RootNotFoundError) {
3748
- console.warn(
3749
- `[Cloak SDK] Merkle root expired (attempt ${attempt + 1}/${MAX_PROOF_RETRIES}). Regenerating proof with fresh root...`
3750
- );
3751
- continue;
3752
- }
3753
- throw error;
3754
- }
3755
- }
3756
- throw new Error(
3757
- `Withdrawal failed after ${MAX_PROOF_RETRIES} proof refresh attempts. The Merkle tree is updating too rapidly. Last error: ${lastError?.message}`
3758
- );
3759
- }
3760
- /**
3761
- * Withdraw to a single recipient
3762
- *
3763
- * Convenience method for withdrawing to one address.
3764
- * Handles the complete flow: deposits if needed, then withdraws.
3765
- *
3766
- * @param connection - Solana connection
3767
- * @param payer - Payer wallet
3768
- * @param note - Note to spend
3769
- * @param recipient - Recipient address
3770
- * @param options - Optional configuration
3771
- * @returns Transfer result
3772
- *
3773
- * @example
3774
- * ```typescript
3775
- * const note = client.generateNote(1_000_000_000);
3776
- * const result = await client.withdraw(
3777
- * connection,
3778
- * wallet,
3779
- * note,
3780
- * new PublicKey("..."),
3781
- * { withdrawAll: true }
3782
- * );
3783
- * ```
3784
- */
3785
- async withdraw(connection, note, recipient, options) {
3786
- const withdrawAll = options?.withdrawAll ?? true;
3787
- const amount = withdrawAll ? getDistributableAmount(note.amount) : options?.amount || note.amount;
3788
- if (!withdrawAll && !options?.amount) {
3789
- throw new Error("Must specify amount or set withdrawAll: true");
3790
- }
3791
- return this.privateTransfer(
3792
- connection,
3793
- note,
3794
- [{ recipient, amount }],
3795
- options
3796
- );
3797
- }
3798
- /**
3799
- * Send SOL privately to multiple recipients
3800
- *
3801
- * Convenience method that wraps privateTransfer with a simpler API.
3802
- * Handles the complete flow: deposits if needed, then sends to recipients.
3803
- *
3804
- * @param connection - Solana connection
3805
- * @param note - Note to spend
3806
- * @param recipients - Array of 1-5 recipients with amounts
3807
- * @param options - Optional configuration
3808
- * @returns Transfer result
3809
- *
3810
- * @example
3811
- * ```typescript
3812
- * const note = client.generateNote(1_000_000_000);
3813
- * const result = await client.send(
3814
- * connection,
3815
- * note,
3816
- * [
3817
- * { recipient: new PublicKey("..."), amount: 500_000_000 },
3818
- * { recipient: new PublicKey("..."), amount: 492_500_000 }
3819
- * ]
3820
- * );
3821
- * ```
3822
- */
3823
- async send(connection, note, recipients, options) {
3824
- return this.privateTransfer(connection, note, recipients, options);
3825
- }
3826
- /**
3827
- * Swap SOL for tokens privately
3828
- *
3829
- * Withdraws SOL from a note and swaps it for tokens via the relay service.
3830
- * Handles the complete flow: deposits if needed, generates proof, and submits swap.
3831
- *
3832
- * @param connection - Solana connection
3833
- * @param note - Note to spend
3834
- * @param recipient - Recipient address (will receive tokens)
3835
- * @param options - Swap configuration
3836
- * @returns Swap result with transaction signature
3837
- *
3838
- * @example
3839
- * ```typescript
3840
- * const note = client.generateNote(1_000_000_000);
3841
- * const result = await client.swap(
3842
- * connection,
3843
- * note,
3844
- * new PublicKey("..."), // recipient
3845
- * {
3846
- * outputMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC
3847
- * slippageBps: 100, // 1%
3848
- * getQuote: async (amount, mint, slippage) => {
3849
- * // Fetch quote from your swap API
3850
- * const quote = await fetchSwapQuote(amount, mint, slippage);
3851
- * return {
3852
- * outAmount: quote.outAmount,
3853
- * minOutputAmount: quote.minOutputAmount
3854
- * };
3855
- * }
3856
- * }
3857
- * );
3858
- * ```
3859
- */
3860
- async swap(connection, note, recipient, options) {
3861
- try {
3862
- if (!isWithdrawable(note)) {
3863
- const depositResult = await this.deposit(connection, note, {
3864
- skipPreflight: false
3865
- });
3866
- note = depositResult.note;
3867
- }
3868
- const variableFee = Math.floor(note.amount * 3 / 1e3);
3869
- const feeBps = note.amount === 0 ? 0 : Math.min(Math.floor((variableFee * 1e4 + note.amount - 1) / note.amount), 65535);
3870
- const withdrawAmountLamports = getDistributableAmount(note.amount);
3871
- if (withdrawAmountLamports <= 0) {
3872
- throw new Error("Amount too small after fees");
3873
- }
3874
- let minOutputAmount;
3875
- if (options.minOutputAmount !== void 0) {
3876
- minOutputAmount = options.minOutputAmount;
3877
- } else if (options.getQuote) {
3878
- const quote = await options.getQuote(
3879
- withdrawAmountLamports,
3880
- options.outputMint,
3881
- options.slippageBps || 100
3882
- );
3883
- minOutputAmount = quote.minOutputAmount;
3884
- } else {
3885
- throw new Error(
3886
- "Must provide either minOutputAmount or getQuote function"
3887
- );
3888
- }
3889
- let recipientAta;
3890
- if (options.recipientAta) {
3891
- recipientAta = new import_web35.PublicKey(options.recipientAta);
3892
- } else {
3893
- try {
3894
- const splTokenModule = await import("@solana/spl-token");
3895
- const getAssociatedTokenAddress = splTokenModule.getAssociatedTokenAddress;
3896
- if (!getAssociatedTokenAddress) {
3897
- throw new Error("getAssociatedTokenAddress not found");
3898
- }
3899
- const outputMint2 = new import_web35.PublicKey(options.outputMint);
3900
- recipientAta = await getAssociatedTokenAddress(outputMint2, recipient);
3901
- } catch (error) {
3902
- throw new Error(
3903
- `Failed to get associated token account: ${error instanceof Error ? error.message : String(error)}. Please install @solana/spl-token or provide recipientAta in options.`
3904
- );
3905
- }
3906
- }
3907
- if (!note.leafIndex && note.leafIndex !== 0) {
3908
- throw new Error("Note must have a leaf index (note must be deposited)");
3909
- }
3910
- const nullifier = await computeNullifierAsync(note.sk_spend, note.leafIndex);
3911
- const nullifierHex = nullifier.toString(16).padStart(64, "0");
3912
- const inputMint = new import_web35.PublicKey("11111111111111111111111111111111");
3913
- const outputMint = new import_web35.PublicKey(options.outputMint);
3914
- const outputsHash = await computeSwapOutputsHashAsync(
3915
- inputMint,
3916
- outputMint,
3917
- recipientAta,
3918
- minOutputAmount,
3919
- note.amount
3920
- );
3921
- const outputsHashHex = outputsHash.toString(16).padStart(64, "0");
3922
- const circuitsPath2 = await getDefaultCircuitsPath();
3923
- const useDirectProof = await areCircuitsAvailable(circuitsPath2);
3924
- if (!useDirectProof) {
3925
- throw new Error(
3926
- `Circuits not available at ${circuitsPath2}. Make sure circuits are built and accessible. Circuit artifacts are pinned to S3 and must be reachable from this environment.`
3927
- );
3928
- }
3929
- const MAX_PROOF_RETRIES = 3;
3930
- let lastError = null;
3931
- for (let attempt = 0; attempt < MAX_PROOF_RETRIES; attempt++) {
3932
- try {
3933
- if (attempt > 0) {
3934
- options?.onProgress?.(`proof_refresh_${attempt + 1}`);
3935
- await new Promise((resolve) => setTimeout(resolve, 1e3));
3936
- }
3937
- const programId = this.config.programId || CLOAK_PROGRAM_ID;
3938
- const mintForSOL = NATIVE_SOL_MINT;
3939
- const { merkleTree: merkleTreePDA } = getShieldPoolPDAs(programId, mintForSOL);
3940
- const chainProof = await computeProofFromChain(connection, merkleTreePDA, note.leafIndex);
3941
- const merkleProof = {
3942
- pathElements: chainProof.pathElements,
3943
- pathIndices: chainProof.pathIndices
3944
- };
3945
- const merkleRoot = chainProof.root;
3946
- if (!merkleRoot) {
3947
- throw new Error("Failed to get Merkle root from chain");
3948
- }
3949
- if (!merkleProof.pathElements || merkleProof.pathElements.length === 0) {
3950
- throw new Error("Merkle proof is invalid: missing path elements");
3951
- }
3952
- const sk_spend_bigint = BigInt("0x" + note.sk_spend);
3953
- const r_bigint = BigInt("0x" + note.r);
3954
- const root_bigint = BigInt("0x" + merkleRoot);
3955
- const nullifier_bigint = BigInt("0x" + nullifierHex);
3956
- const outputs_hash_bigint = BigInt("0x" + outputsHashHex);
3957
- const amount_bigint = BigInt(note.amount);
3958
- const pathElements = merkleProof.pathElements.map((p) => BigInt("0x" + p));
3959
- const inputMintLimbs = pubkeyToLimbs(inputMint.toBytes());
3960
- const outputMintLimbs = pubkeyToLimbs(outputMint.toBytes());
3961
- const recipientAtaLimbs = pubkeyToLimbs(recipientAta.toBytes());
3962
- if (attempt === 0) {
3963
- const computedCommitment = await computeCommitment(amount_bigint, r_bigint, sk_spend_bigint);
3964
- const noteCommitment = BigInt("0x" + note.commitment);
3965
- if (computedCommitment !== noteCommitment) {
3966
- throw new Error(
3967
- `Commitment mismatch! Computed: ${computedCommitment.toString(16)}, Note: ${note.commitment}. This means the note's sk_spend, r, or amount doesn't match what was deposited.`
3968
- );
3969
- }
3970
- }
3971
- const t = amount_bigint * 3n;
3972
- const varFee = t / 1000n;
3973
- const rem = t % 1000n;
3974
- const proofInputs = {
3975
- sk_spend: sk_spend_bigint,
3976
- r: r_bigint,
3977
- amount: amount_bigint,
3978
- leaf_index: BigInt(note.leafIndex),
3979
- path_elements: pathElements,
3980
- path_indices: merkleProof.pathIndices,
3981
- root: root_bigint,
3982
- nullifier: nullifier_bigint,
3983
- outputs_hash: outputs_hash_bigint,
3984
- public_amount: amount_bigint,
3985
- input_mint: inputMintLimbs,
3986
- output_mint: outputMintLimbs,
3987
- recipient_ata: recipientAtaLimbs,
3988
- min_output_amount: BigInt(minOutputAmount),
3989
- var_fee: varFee,
3990
- rem
3991
- };
3992
- options?.onProgress?.("proof_generating");
3993
- const proofResult = await generateWithdrawSwapProof(proofInputs, circuitsPath2);
3994
- options?.onProgress?.("proof_complete");
3995
- const proofHex = Buffer.from(proofResult.proofBytes).toString("hex");
3996
- const finalPublicInputs = {
3997
- root: merkleRoot,
3998
- nf: nullifierHex,
3999
- outputs_hash: outputsHashHex,
4000
- amount: note.amount
4001
- };
4002
- const metadataBundle = options?.metadataBundle;
4003
- const signature = await this.relay.submitSwap(
4004
- {
4005
- proof: proofHex,
4006
- publicInputs: finalPublicInputs,
4007
- outputs: [
4008
- {
4009
- recipient: recipient.toBase58(),
4010
- amount: withdrawAmountLamports
4011
- }
4012
- ],
4013
- feeBps,
4014
- swap: {
4015
- output_mint: options.outputMint,
4016
- slippage_bps: options.slippageBps || 100,
4017
- min_output_amount: minOutputAmount
4018
- },
4019
- metadataBundle
4020
- },
4021
- options.onProgress
4022
- );
4023
- return {
4024
- signature,
4025
- outputs: [
4026
- {
4027
- recipient: recipient.toBase58(),
4028
- amount: withdrawAmountLamports
4029
- }
4030
- ],
4031
- nullifier: nullifierHex,
4032
- root: merkleRoot,
4033
- outputMint: options.outputMint,
4034
- minOutputAmount
4035
- };
4036
- } catch (error) {
4037
- lastError = error instanceof Error ? error : new Error(String(error));
4038
- if (error instanceof RootNotFoundError) {
4039
- console.warn(
4040
- `[Cloak SDK] Merkle root expired (attempt ${attempt + 1}/${MAX_PROOF_RETRIES}). Regenerating swap proof with fresh root...`
4041
- );
4042
- continue;
4043
- }
4044
- throw error;
4045
- }
4046
- }
4047
- throw new Error(
4048
- `Swap failed after ${MAX_PROOF_RETRIES} proof refresh attempts. The Merkle tree is updating too rapidly. Last error: ${lastError?.message}`
4049
- );
4050
- } catch (error) {
4051
- throw this.wrapError(error, "Swap failed");
4052
- }
4053
- }
4054
- /**
4055
- * Generate a new note without depositing
4056
- *
4057
- * @param amountLamports - Amount for the note
4058
- * @param useWalletKeys - Whether to use wallet keys (v2.0 recommended)
4059
- * @returns New note (not yet deposited)
4060
- */
4061
- async generateNote(amountLamports, useWalletKeys = false) {
4062
- if (useWalletKeys && this.cloakKeys) {
4063
- return await generateNoteFromWallet(amountLamports, this.cloakKeys, this.config.network);
4064
- } else if (useWalletKeys) {
4065
- const keys = generateCloakKeys();
4066
- this.cloakKeys = keys;
4067
- const result = this.storage.saveKeys(keys);
4068
- if (result instanceof Promise) {
4069
- result.catch(() => {
4070
- });
4071
- }
4072
- return await generateNoteFromWallet(amountLamports, keys, this.config.network);
4073
- }
4074
- return await generateNote(amountLamports, this.config.network);
4075
- }
4076
- /**
4077
- * Parse a note from JSON string
4078
- *
4079
- * @param jsonString - JSON representation
4080
- * @returns Parsed note
4081
- */
4082
- parseNote(jsonString) {
4083
- return parseNote2(jsonString);
2441
+ poolAddress: pool,
2442
+ merkleTreeAddress: merkleTree,
2443
+ treasuryAddress: treasury,
2444
+ debug: config.debug
2445
+ };
4084
2446
  }
4085
- /**
4086
- * Export a note to JSON string
4087
- *
4088
- * @param note - Note to export
4089
- * @param pretty - Format with indentation
4090
- * @returns JSON string
4091
- */
4092
- exportNote(note, pretty = false) {
4093
- return pretty ? JSON.stringify(note, null, 2) : JSON.stringify(note);
2447
+ /** Public key of the configured signer (keypair or wallet). */
2448
+ getPublicKey() {
2449
+ if (this.keypair) {
2450
+ return this.keypair.publicKey;
2451
+ }
2452
+ if (this.wallet?.publicKey) {
2453
+ return this.wallet.publicKey;
2454
+ }
2455
+ throw new CloakError(
2456
+ "No public key available - wallet not connected and no keypair provided",
2457
+ "wallet",
2458
+ false
2459
+ );
4094
2460
  }
4095
- /**
4096
- * Check if a note is ready for withdrawal
4097
- *
4098
- * @param note - Note to check
4099
- * @returns True if withdrawable
4100
- */
4101
- isWithdrawable(note) {
4102
- return isWithdrawable(note);
2461
+ /** True when the SDK was constructed with a wallet adapter (browser). */
2462
+ isWalletMode() {
2463
+ return !!this.wallet && !this.keypair;
4103
2464
  }
4104
2465
  /**
4105
- * Get Merkle proof for a leaf index directly from on-chain state
4106
- *
4107
- * @param connection - Solana connection
4108
- * @param leafIndex - Leaf index in tree
4109
- * @returns Merkle proof computed from on-chain data
2466
+ * Compute a Merkle proof for `leafIndex` from on-chain state. No relay /
2467
+ * indexer round-trip required.
4110
2468
  */
4111
2469
  async getMerkleProof(connection, leafIndex) {
4112
2470
  const programId = this.config.programId || CLOAK_PROGRAM_ID;
4113
- const mintForSOL = NATIVE_SOL_MINT;
4114
- const { merkleTree: merkleTreePDA } = getShieldPoolPDAs(programId, mintForSOL);
2471
+ const { merkleTree: merkleTreePDA } = getShieldPoolPDAs(programId, NATIVE_SOL_MINT);
4115
2472
  const chainProof = await computeProofFromChain(connection, merkleTreePDA, leafIndex);
4116
2473
  return {
4117
2474
  pathElements: chainProof.pathElements,
@@ -4119,72 +2476,20 @@ var CloakSDK = class {
4119
2476
  root: chainProof.root
4120
2477
  };
4121
2478
  }
4122
- /**
4123
- * Get current Merkle root directly from on-chain state
4124
- *
4125
- * @param connection - Solana connection
4126
- * @returns Current root hash from on-chain tree
4127
- */
2479
+ /** Read the current SOL-pool Merkle root from on-chain state. */
4128
2480
  async getCurrentRoot(connection) {
4129
2481
  const programId = this.config.programId || CLOAK_PROGRAM_ID;
4130
- const mintForSOL = NATIVE_SOL_MINT;
4131
- const { merkleTree: merkleTreePDA } = getShieldPoolPDAs(programId, mintForSOL);
2482
+ const { merkleTree: merkleTreePDA } = getShieldPoolPDAs(programId, NATIVE_SOL_MINT);
4132
2483
  const state = await readMerkleTreeState(connection, merkleTreePDA);
4133
2484
  return state.root;
4134
2485
  }
4135
- /**
4136
- * Get transaction status from relay service
4137
- *
4138
- * @param requestId - Request ID from previous submission
4139
- * @returns Current status
4140
- */
2486
+ /** Poll relay for the status of a previously-submitted request. */
4141
2487
  async getTransactionStatus(requestId) {
4142
2488
  return this.relay.getStatus(requestId);
4143
2489
  }
4144
- /**
4145
- * Fetch and decrypt this user's transaction metadata history.
4146
- * DEPRECATED: This functionality is no longer supported
4147
- */
4148
- async getTransactionMetadata(_options) {
4149
- throw new Error("getTransactionMetadata is deprecated - use compliance export API instead");
4150
- }
4151
- /**
4152
- * Load all notes from storage
4153
- *
4154
- * @returns Array of saved notes
4155
- */
4156
- async loadNotes() {
4157
- const notes = this.storage.loadAllNotes();
4158
- return Array.isArray(notes) ? notes : await notes;
4159
- }
4160
- /**
4161
- * Save a note to storage
4162
- *
4163
- * @param note - Note to save
4164
- */
4165
- async saveNote(note) {
4166
- const result = this.storage.saveNote(note);
4167
- if (result instanceof Promise) {
4168
- await result;
4169
- }
4170
- }
4171
- /**
4172
- * Find a note by its commitment
4173
- *
4174
- * @param commitment - Commitment hash
4175
- * @returns Note if found
4176
- */
4177
- async findNote(commitment) {
4178
- const notes = await this.loadNotes();
4179
- return findNoteByCommitment(notes, commitment);
4180
- }
4181
- /**
4182
- * Import wallet keys from JSON
4183
- *
4184
- * @param keysJson - JSON string containing keys
4185
- */
2490
+ /** Import wallet keys from JSON; persists to the configured storage adapter. */
4186
2491
  async importWalletKeys(keysJson) {
4187
- const keys = importWalletKeys(keysJson);
2492
+ const keys = importKeys(keysJson);
4188
2493
  this.cloakKeys = keys;
4189
2494
  const result = this.storage.saveKeys(keys);
4190
2495
  if (result instanceof Promise) {
@@ -4192,134 +2497,32 @@ var CloakSDK = class {
4192
2497
  }
4193
2498
  }
4194
2499
  /**
4195
- * Export wallet keys to JSON
4196
- *
4197
- * WARNING: This exports secret keys! Store securely.
4198
- *
4199
- * @returns JSON string with keys
2500
+ * Export wallet keys to JSON.
2501
+ *
2502
+ * WARNING: this exports secret keys. Store securely.
4200
2503
  */
4201
2504
  exportWalletKeys() {
4202
2505
  if (!this.cloakKeys) {
4203
2506
  throw new CloakError("No wallet keys available", "wallet", false);
4204
2507
  }
4205
- return exportWalletKeys(this.cloakKeys);
2508
+ return exportKeys(this.cloakKeys);
4206
2509
  }
4207
2510
  /**
4208
- * Get the configuration
2511
+ * Snapshot of the active SDK configuration.
2512
+ *
2513
+ * The return type ({@link CloakConfig}) is structurally narrower than the
2514
+ * constructor input ({@link CloakSDKOptions}): `keypairBytes`, `wallet`,
2515
+ * and `storage` are intentionally absent from the snapshot. The secrets
2516
+ * are consumed into private SDK state at construction time and are not
2517
+ * re-exposable through this method — the type system enforces it. To
2518
+ * sign, pass a `Keypair` / `WalletAdapter` directly to the standalone
2519
+ * `transact` / `partialWithdraw` / `fullWithdraw` / `swapUtxo` helpers.
4209
2520
  */
4210
2521
  getConfig() {
4211
2522
  return { ...this.config };
4212
2523
  }
4213
- // Note: scanNotes was removed - it required the indexer to store encrypted outputs.
4214
- // Users should maintain their own note storage. This is more privacy-preserving.
4215
- /**
4216
- * Wrap errors with better categorization and user-friendly messages
4217
- *
4218
- * @private
4219
- */
4220
- wrapError(error, context) {
4221
- if (error instanceof CloakError) {
4222
- return error;
4223
- }
4224
- const errorMessage = error instanceof Error ? error.message : String(error);
4225
- if (errorMessage.includes("duplicate key") || errorMessage.includes("already deposited")) {
4226
- return new CloakError(
4227
- "This note was already deposited. Generate a new note to continue.",
4228
- "validation",
4229
- false,
4230
- error instanceof Error ? error : void 0
4231
- );
4232
- }
4233
- if (errorMessage.includes("insufficient funds") || errorMessage.includes("insufficient lamports")) {
4234
- return new CloakError(
4235
- "Insufficient funds for this transaction. Please check your wallet balance.",
4236
- "wallet",
4237
- false,
4238
- error instanceof Error ? error : void 0
4239
- );
4240
- }
4241
- if (errorMessage.includes("Merkle tree") || errorMessage.includes("merkle")) {
4242
- return new CloakError(
4243
- "Failed to read on-chain Merkle tree state. Please try again.",
4244
- "network",
4245
- true,
4246
- error instanceof Error ? error : void 0
4247
- );
4248
- }
4249
- if (errorMessage.includes("timeout") || errorMessage.includes("timed out")) {
4250
- return new CloakError(
4251
- "Network timeout. Please check your connection and try again.",
4252
- "network",
4253
- true,
4254
- error instanceof Error ? error : void 0
4255
- );
4256
- }
4257
- if (errorMessage.includes("not connected") || errorMessage.includes("wallet")) {
4258
- return new CloakError(
4259
- "Wallet not connected. Please connect your wallet first.",
4260
- "wallet",
4261
- false,
4262
- error instanceof Error ? error : void 0
4263
- );
4264
- }
4265
- if (errorMessage.includes("proof") && (errorMessage.includes("failed") || errorMessage.includes("error"))) {
4266
- return new CloakError(
4267
- "Zero-knowledge proof generation failed. This is usually temporary - please try again.",
4268
- "prover",
4269
- true,
4270
- error instanceof Error ? error : void 0
4271
- );
4272
- }
4273
- if (errorMessage.includes("relay") || errorMessage.includes("withdraw")) {
4274
- return new CloakError(
4275
- "Relay service error. Please try again later.",
4276
- "relay",
4277
- true,
4278
- error instanceof Error ? error : void 0
4279
- );
4280
- }
4281
- return new CloakError(
4282
- `${context}: ${errorMessage}`,
4283
- "network",
4284
- false,
4285
- error instanceof Error ? error : void 0
4286
- );
4287
- }
4288
2524
  };
4289
2525
 
4290
- // src/core/note.ts
4291
- function serializeNote(note, pretty = false) {
4292
- validateNote(note);
4293
- return pretty ? JSON.stringify(note, null, 2) : JSON.stringify(note);
4294
- }
4295
- function downloadNote(note, filename) {
4296
- const g = globalThis;
4297
- const doc = g?.document;
4298
- const URL_ = g?.URL;
4299
- const Blob_ = g?.Blob;
4300
- if (!doc || !URL_ || !Blob_) {
4301
- throw new Error("downloadNote is only available in browser environments");
4302
- }
4303
- const json = serializeNote(note, true);
4304
- const blob = new Blob_([json], { type: "application/json" });
4305
- const url = URL_.createObjectURL(blob);
4306
- const defaultFilename = `cloak-note-${note.commitment.slice(0, 8)}.json`;
4307
- const link = doc.createElement("a");
4308
- link.href = url;
4309
- link.download = filename || defaultFilename;
4310
- link.click();
4311
- URL_.revokeObjectURL(url);
4312
- }
4313
- async function copyNoteToClipboard(note) {
4314
- const g = globalThis;
4315
- const nav = g?.navigator;
4316
- if (!nav || !nav.clipboard) {
4317
- throw new Error("Clipboard API not available");
4318
- }
4319
- const json = serializeNote(note, true);
4320
- await nav.clipboard.writeText(json);
4321
- }
4322
-
4323
2526
  // src/core/compliance-keys.ts
4324
2527
  var import_tweetnacl2 = __toESM(require("tweetnacl"), 1);
4325
2528
  var import_blake33 = require("@noble/hashes/blake3");
@@ -4706,6 +2909,107 @@ async function decryptComplianceMetadataWithMasterKey(encrypted, masterComplianc
4706
2909
  return decryptWithSharedSecret(payload, sharedSecret);
4707
2910
  }
4708
2911
 
2912
+ // src/utils/fees.ts
2913
+ var LAMPORTS_PER_SOL = 1e9;
2914
+ var FIXED_FEE_LAMPORTS = 5e6;
2915
+ var VARIABLE_FEE_NUMERATOR = 3;
2916
+ var VARIABLE_FEE_DENOMINATOR = 1e3;
2917
+ var VARIABLE_FEE_RATE = VARIABLE_FEE_NUMERATOR / VARIABLE_FEE_DENOMINATOR;
2918
+ var MIN_DEPOSIT_LAMPORTS = 1e7;
2919
+ function calculateFee(amountLamports) {
2920
+ const variableFee = Math.floor(amountLamports * VARIABLE_FEE_NUMERATOR / VARIABLE_FEE_DENOMINATOR);
2921
+ return FIXED_FEE_LAMPORTS + variableFee;
2922
+ }
2923
+ function calculateFeeBigint(amountLamports) {
2924
+ const fixed = BigInt(FIXED_FEE_LAMPORTS);
2925
+ const variable = amountLamports * BigInt(VARIABLE_FEE_NUMERATOR) / BigInt(VARIABLE_FEE_DENOMINATOR);
2926
+ return fixed + variable;
2927
+ }
2928
+ function isWithdrawAmountSufficient(amountLamports) {
2929
+ return amountLamports > calculateFeeBigint(amountLamports);
2930
+ }
2931
+ function getDistributableAmount(amountLamports) {
2932
+ return amountLamports - calculateFee(amountLamports);
2933
+ }
2934
+ function formatAmount(lamports, decimals = 9) {
2935
+ return (lamports / LAMPORTS_PER_SOL).toFixed(decimals);
2936
+ }
2937
+ function parseAmount(sol) {
2938
+ const num = parseFloat(sol);
2939
+ if (isNaN(num) || num < 0) {
2940
+ throw new Error(`Invalid SOL amount: ${sol}`);
2941
+ }
2942
+ return Math.floor(num * LAMPORTS_PER_SOL);
2943
+ }
2944
+ function validateOutputsSum(outputs, expectedTotal) {
2945
+ const sum = outputs.reduce((acc, out) => acc + out.amount, 0);
2946
+ return sum === expectedTotal;
2947
+ }
2948
+ function calculateRelayFee(amountLamports, feeBps) {
2949
+ if (feeBps < 0 || feeBps > 1e4) {
2950
+ throw new Error("Fee basis points must be between 0 and 10000");
2951
+ }
2952
+ return Math.floor(amountLamports * feeBps / 1e4);
2953
+ }
2954
+
2955
+ // src/utils/validation.ts
2956
+ var import_web34 = require("@solana/web3.js");
2957
+ function isValidSolanaAddress(address) {
2958
+ try {
2959
+ new import_web34.PublicKey(address);
2960
+ return true;
2961
+ } catch {
2962
+ return false;
2963
+ }
2964
+ }
2965
+
2966
+ // src/utils/network.ts
2967
+ function detectNetworkFromRpcUrl(rpcUrl) {
2968
+ const url = rpcUrl || process.env.NEXT_PUBLIC_SOLANA_RPC_URL || "";
2969
+ const lowerUrl = url.toLowerCase();
2970
+ if (lowerUrl.includes("mainnet") || lowerUrl.includes("api.mainnet-beta") || lowerUrl.includes("mainnet-beta")) {
2971
+ return "mainnet";
2972
+ }
2973
+ if (lowerUrl.includes("testnet") || lowerUrl.includes("api.testnet")) {
2974
+ return "testnet";
2975
+ }
2976
+ if (lowerUrl.includes("devnet") || lowerUrl.includes("api.devnet")) {
2977
+ return "devnet";
2978
+ }
2979
+ if (lowerUrl.includes("localhost") || lowerUrl.includes("127.0.0.1") || lowerUrl.includes("local")) {
2980
+ return "localnet";
2981
+ }
2982
+ return "mainnet";
2983
+ }
2984
+ function getRpcUrlForNetwork(network) {
2985
+ switch (network) {
2986
+ case "mainnet":
2987
+ return "https://api.mainnet-beta.solana.com";
2988
+ case "devnet":
2989
+ return "https://api.devnet.solana.com";
2990
+ case "localnet":
2991
+ return "http://localhost:8899";
2992
+ default:
2993
+ return "https://api.mainnet-beta.solana.com";
2994
+ }
2995
+ }
2996
+ function isValidRpcUrl(url) {
2997
+ try {
2998
+ const parsed = new URL(url);
2999
+ return parsed.protocol === "http:" || parsed.protocol === "https:";
3000
+ } catch {
3001
+ return false;
3002
+ }
3003
+ }
3004
+ function getExplorerUrl(signature, network = "devnet") {
3005
+ const cluster = network === "mainnet" ? "" : `?cluster=${network}`;
3006
+ return `https://explorer.solana.com/tx/${signature}${cluster}`;
3007
+ }
3008
+ function getAddressExplorerUrl(address, network = "devnet") {
3009
+ const cluster = network === "mainnet" ? "" : `?cluster=${network}`;
3010
+ return `https://explorer.solana.com/address/${address}${cluster}`;
3011
+ }
3012
+
4709
3013
  // src/utils/verify-utxos.ts
4710
3014
  init_utxo();
4711
3015
  async function verifyUtxos(utxos, connection, programId, commitment = "confirmed") {
@@ -4717,7 +3021,7 @@ async function verifyUtxos(utxos, connection, programId, commitment = "confirmed
4717
3021
  continue;
4718
3022
  }
4719
3023
  try {
4720
- const nullifierBig = await computeNullifier2(utxo);
3024
+ const nullifierBig = await computeNullifier(utxo);
4721
3025
  const nullifierHex = nullifierBig.toString(16).padStart(64, "0");
4722
3026
  const nullifierBytes = Buffer.from(nullifierHex, "hex");
4723
3027
  const { pool } = getShieldPoolPDAs(programId, utxo.mintAddress);
@@ -4835,49 +3139,10 @@ async function fetchRiskQuoteIx(connection, wallet, rangeApiKey) {
4835
3139
  };
4836
3140
  }
4837
3141
 
4838
- // src/helpers/encrypted-output.ts
4839
- function prepareEncryptedOutput(note, cloakKeys) {
4840
- const noteData = {
4841
- amount: note.amount,
4842
- r: note.r,
4843
- sk_spend: note.sk_spend,
4844
- commitment: note.commitment
4845
- };
4846
- const encrypted = encryptNoteForRecipient(noteData, cloakKeys.view.pvk);
4847
- return btoa(JSON.stringify(encrypted));
4848
- }
4849
- function prepareEncryptedOutputForRecipient(note, recipientPvkHex) {
4850
- const noteData = {
4851
- amount: note.amount,
4852
- r: note.r,
4853
- sk_spend: note.sk_spend,
4854
- commitment: note.commitment
4855
- };
4856
- const recipientPvk = hexToBytes(recipientPvkHex);
4857
- const encrypted = encryptNoteForRecipient(noteData, recipientPvk);
4858
- return btoa(JSON.stringify(encrypted));
4859
- }
4860
- function encodeNoteSimple(note) {
4861
- const data = {
4862
- amount: note.amount,
4863
- r: note.r,
4864
- sk_spend: note.sk_spend,
4865
- commitment: note.commitment
4866
- };
4867
- const json = JSON.stringify(data);
4868
- if (typeof Buffer !== "undefined") {
4869
- return Buffer.from(json).toString("base64");
4870
- } else if (typeof btoa !== "undefined") {
4871
- return btoa(json);
4872
- } else {
4873
- throw new Error("No base64 encoding method available");
4874
- }
4875
- }
4876
-
4877
3142
  // src/helpers/wallet-integration.ts
4878
- var import_web36 = require("@solana/web3.js");
3143
+ var import_web35 = require("@solana/web3.js");
4879
3144
  function validateWalletConnected(wallet) {
4880
- if (wallet instanceof import_web36.Keypair) {
3145
+ if (wallet instanceof import_web35.Keypair) {
4881
3146
  return;
4882
3147
  }
4883
3148
  if (!wallet.publicKey) {
@@ -4889,7 +3154,7 @@ function validateWalletConnected(wallet) {
4889
3154
  }
4890
3155
  }
4891
3156
  function getPublicKey(wallet) {
4892
- if (wallet instanceof import_web36.Keypair) {
3157
+ if (wallet instanceof import_web35.Keypair) {
4893
3158
  return wallet.publicKey;
4894
3159
  }
4895
3160
  if (!wallet.publicKey) {
@@ -4902,7 +3167,7 @@ function getPublicKey(wallet) {
4902
3167
  return wallet.publicKey;
4903
3168
  }
4904
3169
  async function sendTransaction(transaction, wallet, connection, options) {
4905
- if (wallet instanceof import_web36.Keypair) {
3170
+ if (wallet instanceof import_web35.Keypair) {
4906
3171
  return await connection.sendTransaction(transaction, [wallet], options);
4907
3172
  }
4908
3173
  if (wallet.sendTransaction) {
@@ -4919,7 +3184,7 @@ async function sendTransaction(transaction, wallet, connection, options) {
4919
3184
  }
4920
3185
  }
4921
3186
  async function signTransaction(transaction, wallet) {
4922
- if (wallet instanceof import_web36.Keypair) {
3187
+ if (wallet instanceof import_web35.Keypair) {
4923
3188
  transaction.sign(wallet);
4924
3189
  return transaction;
4925
3190
  }
@@ -5383,180 +3648,13 @@ async function preflightCheck(relayUrl, rootHex) {
5383
3648
  };
5384
3649
  }
5385
3650
 
5386
- // src/utils/pending-operations.ts
5387
- var PENDING_DEPOSITS_KEY = "cloak_pending_deposits";
5388
- var PENDING_WITHDRAWALS_KEY = "cloak_pending_withdrawals";
5389
- function getStorage() {
5390
- if (typeof globalThis !== "undefined" && globalThis.localStorage) {
5391
- return globalThis.localStorage;
5392
- }
5393
- return null;
5394
- }
5395
- function savePendingDeposit(deposit) {
5396
- const storage = getStorage();
5397
- if (!storage) {
5398
- console.warn("localStorage not available - pending deposit not persisted");
5399
- return;
5400
- }
5401
- const deposits = loadPendingDeposits();
5402
- const index = deposits.findIndex((d) => d.note.commitment === deposit.note.commitment);
5403
- if (index >= 0) {
5404
- deposits[index] = deposit;
5405
- } else {
5406
- deposits.push(deposit);
5407
- }
5408
- storage.setItem(PENDING_DEPOSITS_KEY, JSON.stringify(deposits));
5409
- }
5410
- function loadPendingDeposits() {
5411
- const storage = getStorage();
5412
- if (!storage) return [];
5413
- const stored = storage.getItem(PENDING_DEPOSITS_KEY);
5414
- if (!stored) return [];
5415
- try {
5416
- return JSON.parse(stored);
5417
- } catch {
5418
- return [];
5419
- }
5420
- }
5421
- function updatePendingDeposit(commitment, updates) {
5422
- const storage = getStorage();
5423
- if (!storage) return;
5424
- const deposits = loadPendingDeposits();
5425
- const index = deposits.findIndex((d) => d.note.commitment === commitment);
5426
- if (index >= 0) {
5427
- deposits[index] = { ...deposits[index], ...updates };
5428
- storage.setItem(PENDING_DEPOSITS_KEY, JSON.stringify(deposits));
5429
- }
5430
- }
5431
- function removePendingDeposit(commitment) {
5432
- const storage = getStorage();
5433
- if (!storage) return;
5434
- const deposits = loadPendingDeposits();
5435
- const filtered = deposits.filter((d) => d.note.commitment !== commitment);
5436
- storage.setItem(PENDING_DEPOSITS_KEY, JSON.stringify(filtered));
5437
- }
5438
- function clearPendingDeposits() {
5439
- const storage = getStorage();
5440
- if (storage) {
5441
- storage.removeItem(PENDING_DEPOSITS_KEY);
5442
- }
5443
- }
5444
- function savePendingWithdrawal(withdrawal) {
5445
- const storage = getStorage();
5446
- if (!storage) {
5447
- console.warn("localStorage not available - pending withdrawal not persisted");
5448
- return;
5449
- }
5450
- const withdrawals = loadPendingWithdrawals();
5451
- const index = withdrawals.findIndex((w) => w.requestId === withdrawal.requestId);
5452
- if (index >= 0) {
5453
- withdrawals[index] = withdrawal;
5454
- } else {
5455
- withdrawals.push(withdrawal);
5456
- }
5457
- storage.setItem(PENDING_WITHDRAWALS_KEY, JSON.stringify(withdrawals));
5458
- }
5459
- function loadPendingWithdrawals() {
5460
- const storage = getStorage();
5461
- if (!storage) return [];
5462
- const stored = storage.getItem(PENDING_WITHDRAWALS_KEY);
5463
- if (!stored) return [];
5464
- try {
5465
- return JSON.parse(stored);
5466
- } catch {
5467
- return [];
5468
- }
5469
- }
5470
- function updatePendingWithdrawal(requestId, updates) {
5471
- const storage = getStorage();
5472
- if (!storage) return;
5473
- const withdrawals = loadPendingWithdrawals();
5474
- const index = withdrawals.findIndex((w) => w.requestId === requestId);
5475
- if (index >= 0) {
5476
- withdrawals[index] = { ...withdrawals[index], ...updates };
5477
- storage.setItem(PENDING_WITHDRAWALS_KEY, JSON.stringify(withdrawals));
5478
- }
5479
- }
5480
- function removePendingWithdrawal(requestId) {
5481
- const storage = getStorage();
5482
- if (!storage) return;
5483
- const withdrawals = loadPendingWithdrawals();
5484
- const filtered = withdrawals.filter((w) => w.requestId !== requestId);
5485
- storage.setItem(PENDING_WITHDRAWALS_KEY, JSON.stringify(filtered));
5486
- }
5487
- function clearPendingWithdrawals() {
5488
- const storage = getStorage();
5489
- if (storage) {
5490
- storage.removeItem(PENDING_WITHDRAWALS_KEY);
5491
- }
5492
- }
5493
- function hasPendingOperations() {
5494
- const deposits = loadPendingDeposits();
5495
- const withdrawals = loadPendingWithdrawals();
5496
- const pendingDeposits = deposits.filter(
5497
- (d) => d.status === "pending" || d.status === "tx_sent"
5498
- );
5499
- const pendingWithdrawals = withdrawals.filter(
5500
- (w) => w.status === "pending" || w.status === "processing"
5501
- );
5502
- return pendingDeposits.length > 0 || pendingWithdrawals.length > 0;
5503
- }
5504
- function getPendingOperationsSummary() {
5505
- const deposits = loadPendingDeposits().filter(
5506
- (d) => d.status === "pending" || d.status === "tx_sent"
5507
- );
5508
- const withdrawals = loadPendingWithdrawals().filter(
5509
- (w) => w.status === "pending" || w.status === "processing"
5510
- );
5511
- return {
5512
- deposits,
5513
- withdrawals,
5514
- totalPending: deposits.length + withdrawals.length
5515
- };
5516
- }
5517
- function cleanupStalePendingOperations(maxAgeMs = 24 * 60 * 60 * 1e3) {
5518
- const now = Date.now();
5519
- let removedDeposits = 0;
5520
- let removedWithdrawals = 0;
5521
- const deposits = loadPendingDeposits();
5522
- const activeDeposits = deposits.filter((d) => {
5523
- const age = now - d.startedAt;
5524
- const isStale = age > maxAgeMs;
5525
- const isTerminal = d.status === "confirmed" || d.status === "failed";
5526
- if (isStale || isTerminal) {
5527
- removedDeposits++;
5528
- return false;
5529
- }
5530
- return true;
5531
- });
5532
- const storage = getStorage();
5533
- if (storage) {
5534
- storage.setItem(PENDING_DEPOSITS_KEY, JSON.stringify(activeDeposits));
5535
- }
5536
- const withdrawals = loadPendingWithdrawals();
5537
- const activeWithdrawals = withdrawals.filter((w) => {
5538
- const age = now - w.startedAt;
5539
- const isStale = age > maxAgeMs;
5540
- const isTerminal = w.status === "completed" || w.status === "failed";
5541
- if (isStale || isTerminal) {
5542
- removedWithdrawals++;
5543
- return false;
5544
- }
5545
- return true;
5546
- });
5547
- if (storage) {
5548
- storage.setItem(PENDING_WITHDRAWALS_KEY, JSON.stringify(activeWithdrawals));
5549
- }
5550
- return { removedDeposits, removedWithdrawals };
5551
- }
5552
-
5553
3651
  // src/index.ts
5554
3652
  init_utxo();
5555
3653
 
5556
3654
  // src/core/transact.ts
5557
- var import_web37 = require("@solana/web3.js");
3655
+ var import_web36 = require("@solana/web3.js");
5558
3656
  var import_spl_token = require("@solana/spl-token");
5559
- var snarkjs2 = __toESM(require("snarkjs"), 1);
3657
+ var snarkjs = __toESM(require("snarkjs"), 1);
5560
3658
  init_utxo();
5561
3659
 
5562
3660
  // src/core/chain-note.ts
@@ -5707,7 +3805,7 @@ function chainNoteFromBase64(base64) {
5707
3805
  // src/core/transact.ts
5708
3806
  var import_circomlibjs4 = require("circomlibjs");
5709
3807
  var import_tweetnacl4 = __toESM(require("tweetnacl"), 1);
5710
- var IS_BROWSER2 = typeof window !== "undefined" || typeof globalThis.document !== "undefined";
3808
+ var IS_BROWSER = typeof window !== "undefined" || typeof globalThis.document !== "undefined";
5711
3809
  var DEFAULT_TRANSACTION_CIRCUITS_URL = "https://cloak-circuits.s3.us-east-1.amazonaws.com/circuits/0.1.0";
5712
3810
  var DEFAULT_CLOAK_RELAY_URL = "https://api.cloak.ag";
5713
3811
  function resolveDefaultTransactionCircuitsPath() {
@@ -5720,7 +3818,7 @@ async function resolveTransactionCircuitFiles() {
5720
3818
  const baseNorm = base.endsWith("/") ? base : `${base}/`;
5721
3819
  const wasmUrl = `${baseNorm}transaction_js/transaction.wasm`;
5722
3820
  const zkeyUrl = `${baseNorm}transaction_final.zkey`;
5723
- if (IS_BROWSER2) {
3821
+ if (IS_BROWSER) {
5724
3822
  return { wasmPath: wasmUrl, zkeyPath: zkeyUrl };
5725
3823
  }
5726
3824
  if (_remoteTxCircuitsCache?.base === baseNorm) {
@@ -5857,7 +3955,7 @@ async function resolveAddressLookupTableAccounts(connection, relayUrl, altAddres
5857
3955
  const fetched = await Promise.all(
5858
3956
  altAddresses.map(async (addr) => {
5859
3957
  try {
5860
- const pubkey = new import_web37.PublicKey(addr);
3958
+ const pubkey = new import_web36.PublicKey(addr);
5861
3959
  const result = await connection.getAddressLookupTable(pubkey);
5862
3960
  return result.value ?? null;
5863
3961
  } catch {
@@ -6019,7 +4117,7 @@ async function generateTransactionProof(inputs, onProgress) {
6019
4117
  onProgress?.(10);
6020
4118
  const { wasmPath: wasmInput, zkeyPath: zkeyInput } = await resolveTransactionCircuitFiles();
6021
4119
  onProgress?.(30);
6022
- const { proof, publicSignals } = await snarkjs2.groth16.fullProve(
4120
+ const { proof, publicSignals } = await snarkjs.groth16.fullProve(
6023
4121
  inputs,
6024
4122
  wasmInput,
6025
4123
  zkeyInput
@@ -6099,7 +4197,7 @@ function buildPublicInputsBytesFromSignals(publicSignals) {
6099
4197
  }
6100
4198
  var TRANSACT_DISCRIMINATOR = 0;
6101
4199
  function deriveNullifierPDA(programId, poolPDA, nullifier) {
6102
- return import_web37.PublicKey.findProgramAddressSync(
4200
+ return import_web36.PublicKey.findProgramAddressSync(
6103
4201
  [Buffer.from("nullifier"), poolPDA.toBuffer(), Buffer.from(nullifier)],
6104
4202
  programId
6105
4203
  );
@@ -6142,7 +4240,7 @@ function buildTransactInstruction(programId, payer, poolPDA, treasuryPDA, merkle
6142
4240
  // 4. nullifier PDA 0 (writable)
6143
4241
  { pubkey: nullifierPDA1, isSigner: false, isWritable: true },
6144
4242
  // 5. nullifier PDA 1 (writable)
6145
- { pubkey: import_web37.SystemProgram.programId, isSigner: false, isWritable: false }
4243
+ { pubkey: import_web36.SystemProgram.programId, isSigner: false, isWritable: false }
6146
4244
  // 6. system_program
6147
4245
  ];
6148
4246
  if (splAccounts) {
@@ -6151,23 +4249,23 @@ function buildTransactInstruction(programId, payer, poolPDA, treasuryPDA, merkle
6151
4249
  accounts.push({ pubkey: splAccounts.tokenProgram, isSigner: false, isWritable: false });
6152
4250
  if (splAccounts.payerAta) {
6153
4251
  if (enableRiskCheck) {
6154
- accounts.push({ pubkey: import_web37.SYSVAR_INSTRUCTIONS_PUBKEY, isSigner: false, isWritable: false });
4252
+ accounts.push({ pubkey: import_web36.SYSVAR_INSTRUCTIONS_PUBKEY, isSigner: false, isWritable: false });
6155
4253
  }
6156
4254
  accounts.push({ pubkey: splAccounts.payerAta, isSigner: false, isWritable: true });
6157
4255
  } else if (enableRiskCheck && !recipient) {
6158
- accounts.push({ pubkey: import_web37.SYSVAR_INSTRUCTIONS_PUBKEY, isSigner: false, isWritable: false });
4256
+ accounts.push({ pubkey: import_web36.SYSVAR_INSTRUCTIONS_PUBKEY, isSigner: false, isWritable: false });
6159
4257
  }
6160
4258
  } else {
6161
4259
  if (recipient) {
6162
4260
  accounts.push({ pubkey: recipient, isSigner: false, isWritable: true });
6163
4261
  if (enableRiskCheck) {
6164
- accounts.push({ pubkey: import_web37.SYSVAR_INSTRUCTIONS_PUBKEY, isSigner: false, isWritable: false });
4262
+ accounts.push({ pubkey: import_web36.SYSVAR_INSTRUCTIONS_PUBKEY, isSigner: false, isWritable: false });
6165
4263
  }
6166
4264
  } else if (enableRiskCheck) {
6167
- accounts.push({ pubkey: import_web37.SYSVAR_INSTRUCTIONS_PUBKEY, isSigner: false, isWritable: false });
4265
+ accounts.push({ pubkey: import_web36.SYSVAR_INSTRUCTIONS_PUBKEY, isSigner: false, isWritable: false });
6168
4266
  }
6169
4267
  }
6170
- return new import_web37.TransactionInstruction({
4268
+ return new import_web36.TransactionInstruction({
6171
4269
  programId,
6172
4270
  keys: accounts,
6173
4271
  data
@@ -6175,10 +4273,10 @@ function buildTransactInstruction(programId, payer, poolPDA, treasuryPDA, merkle
6175
4273
  }
6176
4274
  function getCommonALTAddresses() {
6177
4275
  return [
6178
- import_web37.SystemProgram.programId,
6179
- import_web37.SYSVAR_SLOT_HASHES_PUBKEY,
6180
- import_web37.SYSVAR_INSTRUCTIONS_PUBKEY,
6181
- import_web37.ComputeBudgetProgram.programId
4276
+ import_web36.SystemProgram.programId,
4277
+ import_web36.SYSVAR_SLOT_HASHES_PUBKEY,
4278
+ import_web36.SYSVAR_INSTRUCTIONS_PUBKEY,
4279
+ import_web36.ComputeBudgetProgram.programId
6182
4280
  ];
6183
4281
  }
6184
4282
  function dedupePubkeys(addresses) {
@@ -6228,23 +4326,23 @@ async function createEphemeralALT(connection, depositor, onProgress, additionalA
6228
4326
  for (let altAttempt = 0; altAttempt < MAX_ALT_CREATE_RETRIES; altAttempt++) {
6229
4327
  try {
6230
4328
  const slot = await connection.getSlot("finalized");
6231
- const [createIx, altAddress] = import_web37.AddressLookupTableProgram.createLookupTable({
4329
+ const [createIx, altAddress] = import_web36.AddressLookupTableProgram.createLookupTable({
6232
4330
  authority: depositor.publicKey,
6233
4331
  payer: depositor.publicKey,
6234
4332
  recentSlot: slot
6235
4333
  });
6236
- const extendIx = import_web37.AddressLookupTableProgram.extendLookupTable({
4334
+ const extendIx = import_web36.AddressLookupTableProgram.extendLookupTable({
6237
4335
  payer: depositor.publicKey,
6238
4336
  authority: depositor.publicKey,
6239
4337
  lookupTable: altAddress,
6240
4338
  addresses: addressesForCreate
6241
4339
  });
6242
- const tx = new import_web37.Transaction().add(createIx).add(extendIx);
4340
+ const tx = new import_web36.Transaction().add(createIx).add(extendIx);
6243
4341
  const { blockhash } = await connection.getLatestBlockhash();
6244
4342
  tx.recentBlockhash = blockhash;
6245
4343
  tx.feePayer = depositor.publicKey;
6246
4344
  if (depositor.keypair) {
6247
- await (0, import_web37.sendAndConfirmTransaction)(connection, tx, [depositor.keypair], { commitment: "confirmed" });
4345
+ await (0, import_web36.sendAndConfirmTransaction)(connection, tx, [depositor.keypair], { commitment: "confirmed" });
6248
4346
  } else if (depositor.signTransaction) {
6249
4347
  const signedTx = await depositor.signTransaction(tx);
6250
4348
  const sig = await connection.sendRawTransaction(signedTx.serialize());
@@ -6405,8 +4503,8 @@ async function submitTransactionDirect(connection, programId, depositor, proofBy
6405
4503
  if (riskQuoteIx) {
6406
4504
  baseInstructions.unshift(riskQuoteIx);
6407
4505
  }
6408
- const cuLimitIx = import_web37.ComputeBudgetProgram.setComputeUnitLimit({ units: 4e5 });
6409
- const cuPriceIx = import_web37.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1e5 });
4506
+ const cuLimitIx = import_web36.ComputeBudgetProgram.setComputeUnitLimit({ units: 4e5 });
4507
+ const cuPriceIx = import_web36.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1e5 });
6410
4508
  const fullInstructions = [...baseInstructions, cuLimitIx, cuPriceIx, transactIx];
6411
4509
  const compactInstructions = [...baseInstructions, cuLimitIx, transactIx];
6412
4510
  const minimalInstructions = [...baseInstructions, transactIx];
@@ -6417,7 +4515,7 @@ async function submitTransactionDirect(connection, programId, depositor, proofBy
6417
4515
  if (useV0) {
6418
4516
  const estimateV0Size = (ixs) => {
6419
4517
  try {
6420
- const messageV0 = new import_web37.TransactionMessage({
4518
+ const messageV0 = new import_web36.TransactionMessage({
6421
4519
  payerKey: depositor.publicKey,
6422
4520
  recentBlockhash: blockhash,
6423
4521
  instructions: ixs
@@ -6477,12 +4575,12 @@ async function submitTransactionDirect(connection, programId, depositor, proofBy
6477
4575
  }
6478
4576
  let transportAttempt = 0;
6479
4577
  while (true) {
6480
- const messageV0 = new import_web37.TransactionMessage({
4578
+ const messageV0 = new import_web36.TransactionMessage({
6481
4579
  payerKey: depositor.publicKey,
6482
4580
  recentBlockhash: blockhash,
6483
4581
  instructions: ixs
6484
4582
  }).compileToV0Message(addressLookupTableAccounts);
6485
- const versionedTx = new import_web37.VersionedTransaction(messageV0);
4583
+ const versionedTx = new import_web36.VersionedTransaction(messageV0);
6486
4584
  try {
6487
4585
  if (depositor.keypair) {
6488
4586
  onProgress?.("Signing and sending transaction...");
@@ -6615,7 +4713,7 @@ async function submitTransactionDirect(connection, programId, depositor, proofBy
6615
4713
  let legacyTransportAttempt = 0;
6616
4714
  while (true) {
6617
4715
  try {
6618
- const tx = new import_web37.Transaction();
4716
+ const tx = new import_web36.Transaction();
6619
4717
  for (const ix of instructions) {
6620
4718
  tx.add(ix);
6621
4719
  }
@@ -6623,7 +4721,7 @@ async function submitTransactionDirect(connection, programId, depositor, proofBy
6623
4721
  tx.feePayer = depositor.publicKey;
6624
4722
  if (depositor.keypair) {
6625
4723
  onProgress?.("Signing and sending transaction...");
6626
- signature = await (0, import_web37.sendAndConfirmTransaction)(
4724
+ signature = await (0, import_web36.sendAndConfirmTransaction)(
6627
4725
  connection,
6628
4726
  tx,
6629
4727
  [depositor.keypair],
@@ -6797,7 +4895,7 @@ async function fetchRiskQuoteInstruction(riskQuoteUrl, wallet, options) {
6797
4895
  const signerB58 = signerKey;
6798
4896
  const signatureBuf = Buffer.from(signatureB64, "base64");
6799
4897
  const messageArr = hexToBytes2(messageHex);
6800
- const publicKeyBytes = new import_web37.PublicKey(signerB58).toBytes();
4898
+ const publicKeyBytes = new import_web36.PublicKey(signerB58).toBytes();
6801
4899
  if (signatureBuf.length !== 64 || messageArr.length !== 33 && messageArr.length !== 41 && messageArr.length !== 50 || publicKeyBytes.length !== 32) {
6802
4900
  throw new Error(
6803
4901
  `Invalid risk quote response: invalid lengths (sig=${signatureBuf.length}, msg=${messageArr.length}, pk=${publicKeyBytes.length})`
@@ -6806,7 +4904,7 @@ async function fetchRiskQuoteInstruction(riskQuoteUrl, wallet, options) {
6806
4904
  const signature = new Uint8Array(signatureBuf);
6807
4905
  const message = new Uint8Array(messageArr);
6808
4906
  const publicKey = new Uint8Array(publicKeyBytes);
6809
- return import_web37.Ed25519Program.createInstructionWithPublicKey({
4907
+ return import_web36.Ed25519Program.createInstructionWithPublicKey({
6810
4908
  publicKey,
6811
4909
  message,
6812
4910
  signature
@@ -6819,10 +4917,10 @@ async function fetchRiskQuoteInstruction(riskQuoteUrl, wallet, options) {
6819
4917
  `Invalid risk quote response: expected relay format { signature, message, signer_pubkey } or { instruction }. Received keys: ${keys}`
6820
4918
  );
6821
4919
  }
6822
- return new import_web37.TransactionInstruction({
6823
- programId: new import_web37.PublicKey(raw.programId),
4920
+ return new import_web36.TransactionInstruction({
4921
+ programId: new import_web36.PublicKey(raw.programId),
6824
4922
  keys: raw.keys.map((k) => ({
6825
- pubkey: new import_web37.PublicKey(k.pubkey),
4923
+ pubkey: new import_web36.PublicKey(k.pubkey),
6826
4924
  isSigner: k.isSigner,
6827
4925
  isWritable: k.isWritable
6828
4926
  })),
@@ -7192,7 +5290,7 @@ async function transact(params, options) {
7192
5290
  const outputCommitments = [];
7193
5291
  for (let i = 0; i < paddedOutputs.length; i++) {
7194
5292
  const utxo = paddedOutputs[i];
7195
- const commitment = await computeCommitment2(utxo);
5293
+ const commitment = await computeCommitment(utxo);
7196
5294
  outputCommitments.push(commitment);
7197
5295
  }
7198
5296
  onProgress?.("Computing external data hash...");
@@ -7273,7 +5371,7 @@ async function transact(params, options) {
7273
5371
  }
7274
5372
  inputNullifiers = [];
7275
5373
  for (const utxo of paddedInputs) {
7276
- inputNullifiers.push(await computeNullifier2(utxo));
5374
+ inputNullifiers.push(await computeNullifier(utxo));
7277
5375
  }
7278
5376
  if (nextIndex !== null) {
7279
5377
  onProgress?.(`[Submit ${submissionAttempts + 1}/${maxRootRetries + 1}] Root: ${rootHex.substring(0, 16)}..., nextIndex: ${nextIndex}`);
@@ -7706,12 +5804,12 @@ async function transact(params, options) {
7706
5804
  if (lastError) {
7707
5805
  const classified = classifyRelayError(lastError.message);
7708
5806
  const isMerkleClass = !(classified instanceof UtxoAlreadySpentError) && !(classified instanceof SanctionsQuoteError) && !isRootNotFoundError2(lastError);
7709
- if (!IS_BROWSER2 && isMerkleClass && relayUrl) {
5807
+ if (!IS_BROWSER && isMerkleClass && relayUrl) {
7710
5808
  onProgress?.(
7711
5809
  "All relay-tree attempts failed. Rebuilding merkle tree from chain as last resort..."
7712
5810
  );
7713
5811
  try {
7714
- const [merkleTreePda] = import_web37.PublicKey.findProgramAddressSync(
5812
+ const [merkleTreePda] = import_web36.PublicKey.findProgramAddressSync(
7715
5813
  [Buffer.from("merkle_tree"), mint.toBuffer()],
7716
5814
  programId
7717
5815
  );
@@ -8355,7 +6453,7 @@ async function swapUtxo(params, options) {
8355
6453
  let inputNullifiers = [];
8356
6454
  const outputCommitments = [];
8357
6455
  for (const utxo of paddedOutputs) {
8358
- outputCommitments.push(await computeCommitment2(utxo));
6456
+ outputCommitments.push(await computeCommitment(utxo));
8359
6457
  }
8360
6458
  const chainNoteTimestamp = BigInt(Date.now());
8361
6459
  onProgress?.("Computing external data hash...");
@@ -8435,7 +6533,7 @@ async function swapUtxo(params, options) {
8435
6533
  }
8436
6534
  inputNullifiers = [];
8437
6535
  for (const utxo of paddedInputs) {
8438
- inputNullifiers.push(await computeNullifier2(utxo));
6536
+ inputNullifiers.push(await computeNullifier(utxo));
8439
6537
  }
8440
6538
  if (merkleState) {
8441
6539
  onProgress?.(`[Attempt ${attempt + 1}/${maxRootRetries + 1}] Root: ${rootHex.substring(0, 16)}..., nextIndex: ${merkleState.nextIndex}`);
@@ -8779,7 +6877,7 @@ async function swapWithChange(inputUtxos, swapAmount, outputMint, recipientAta,
8779
6877
 
8780
6878
  // src/core/scanner.ts
8781
6879
  var import_bs582 = __toESM(require("bs58"), 1);
8782
- var import_web38 = require("@solana/web3.js");
6880
+ var import_web37 = require("@solana/web3.js");
8783
6881
  var import_spl_token2 = require("@solana/spl-token");
8784
6882
  var bs582 = import_bs582.default.default || import_bs582.default;
8785
6883
  var TRANSACT_TAG2 = 0;
@@ -8866,7 +6964,7 @@ function parseSwapOutputMint(data) {
8866
6964
  const mintBytes = data.slice(SWAP_OUTPUT_MINT_OFFSET, end);
8867
6965
  if (mintBytes.every((byte) => byte === 0)) return void 0;
8868
6966
  try {
8869
- return new import_web38.PublicKey(mintBytes).toBase58();
6967
+ return new import_web37.PublicKey(mintBytes).toBase58();
8870
6968
  } catch {
8871
6969
  return void 0;
8872
6970
  }
@@ -8956,7 +7054,7 @@ function parseSwapRecipientAta(data) {
8956
7054
  const recipientAtaBytes = data.slice(recipientAtaStart, recipientAtaEnd);
8957
7055
  if (recipientAtaBytes.every((byte) => byte === 0)) return void 0;
8958
7056
  try {
8959
- return new import_web38.PublicKey(recipientAtaBytes).toBase58();
7057
+ return new import_web37.PublicKey(recipientAtaBytes).toBase58();
8960
7058
  } catch {
8961
7059
  return void 0;
8962
7060
  }
@@ -9271,8 +7369,8 @@ async function scanTransactions(opts) {
9271
7369
  if (onChainAta) {
9272
7370
  try {
9273
7371
  const expectedAta = (0, import_spl_token2.getAssociatedTokenAddressSync)(
9274
- new import_web38.PublicKey(asset.mint),
9275
- new import_web38.PublicKey(walletPublicKey)
7372
+ new import_web37.PublicKey(asset.mint),
7373
+ new import_web37.PublicKey(walletPublicKey)
9276
7374
  ).toBase58();
9277
7375
  if (onChainAta === expectedAta) {
9278
7376
  isOurs = true;
@@ -9575,7 +7673,7 @@ function formatComplianceCsv(report) {
9575
7673
  }
9576
7674
 
9577
7675
  // src/core/wallet.ts
9578
- var import_web39 = require("@solana/web3.js");
7676
+ var import_web38 = require("@solana/web3.js");
9579
7677
  init_utxo();
9580
7678
  var UtxoWallet = class _UtxoWallet {
9581
7679
  constructor(viewingKey) {
@@ -9788,7 +7886,7 @@ var UtxoWallet = class _UtxoWallet {
9788
7886
  data.viewingKey ? new Uint8Array(data.viewingKey) : void 0
9789
7887
  );
9790
7888
  for (const w of data.wallets) {
9791
- const mint = new import_web39.PublicKey(w.mint);
7889
+ const mint = new import_web38.PublicKey(w.mint);
9792
7890
  for (const u of w.utxos) {
9793
7891
  wallet.addUtxo({
9794
7892
  amount: BigInt(u.amount),
@@ -9871,16 +7969,14 @@ var SimpleWallet = class {
9871
7969
  };
9872
7970
 
9873
7971
  // src/index.ts
9874
- var VERSION = "0.1.5";
7972
+ var VERSION = "0.1.6";
9875
7973
  var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
9876
7974
  // Annotate the CommonJS export names for ESM import in node:
9877
7975
  0 && (module.exports = {
9878
7976
  CLOAK_PROGRAM_ID,
9879
7977
  CloakError,
9880
7978
  CloakSDK,
9881
- DEFAULT_CIRCUITS_URL,
9882
7979
  DEFAULT_TRANSACTION_CIRCUITS_URL,
9883
- EXPECTED_CIRCUIT_HASHES,
9884
7980
  FIXED_FEE_LAMPORTS,
9885
7981
  LAMPORTS_PER_SOL,
9886
7982
  LocalStorageAdapter,
@@ -9903,7 +7999,6 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
9903
7999
  VARIABLE_FEE_NUMERATOR,
9904
8000
  VARIABLE_FEE_RATE,
9905
8001
  VERSION,
9906
- areCircuitsAvailable,
9907
8002
  bigintToBytes32,
9908
8003
  bigintToHex,
9909
8004
  buildMerkleTree,
@@ -9917,30 +8012,15 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
9917
8012
  chainNoteFromBase64,
9918
8013
  chainNoteToBase64,
9919
8014
  classifyRelayError,
9920
- cleanupStalePendingOperations,
9921
- clearPendingDeposits,
9922
- clearPendingWithdrawals,
9923
8015
  computeChainNoteHash,
9924
- computeCommitment,
9925
8016
  computeExtDataHash,
9926
8017
  computeMerkleRoot,
9927
- computeNullifier,
9928
- computeNullifierAsync,
9929
- computeNullifierSync,
9930
- computeOutputsHash,
9931
- computeOutputsHashAsync,
9932
- computeOutputsHashSync,
9933
8018
  computeProofForLatestDeposit,
9934
8019
  computeProofFromChain,
9935
8020
  computeSignature,
9936
- computeSwapOutputsHash,
9937
- computeSwapOutputsHashAsync,
9938
- computeSwapOutputsHashSync,
9939
8021
  computeUtxoCommitment,
9940
8022
  computeUtxoNullifier,
9941
- copyNoteToClipboard,
9942
8023
  createCloakError,
9943
- createDepositInstruction,
9944
8024
  createLogger,
9945
8025
  createUtxo,
9946
8026
  createZeroUtxo,
@@ -9960,78 +8040,52 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
9960
8040
  deriveViewingKeyFromUtxoPrivateKey,
9961
8041
  deserializeUtxo,
9962
8042
  detectNetworkFromRpcUrl,
9963
- downloadNote,
9964
- encodeNoteSimple,
9965
8043
  encryptCompactChainNote,
9966
8044
  encryptNoteForRecipient,
9967
8045
  encryptTransactionMetadata,
9968
8046
  encryptTransactionMetadataBundle,
9969
8047
  expandSpendKey,
9970
8048
  exportKeys,
9971
- exportNote,
9972
- exportWalletKeys,
9973
8049
  fetchCommitments,
9974
8050
  fetchRiskQuoteInstruction,
9975
8051
  fetchRiskQuoteIx,
9976
- filterNotesByNetwork,
9977
- filterWithdrawableNotes,
9978
- findNoteByCommitment,
9979
8052
  formatAmount,
9980
8053
  formatComplianceCsv,
9981
8054
  formatErrorForLogging,
9982
8055
  formatSol,
9983
8056
  fullWithdraw,
9984
8057
  generateCloakKeys,
9985
- generateCommitment,
9986
- generateCommitmentAsync,
9987
8058
  generateMasterSeed,
9988
- generateNote,
9989
- generateNoteFromWallet,
9990
8059
  generateUtxoKeypair,
9991
8060
  generateViewingKeyPair,
9992
- generateWithdrawRegularProof,
9993
- generateWithdrawSwapProof,
9994
8061
  getAddressExplorerUrl,
9995
8062
  getCircuitsPath,
9996
- getDefaultCircuitsPath,
9997
8063
  getDistributableAmount,
9998
8064
  getExplorerUrl,
9999
8065
  getNkFromUtxoPrivateKey,
10000
8066
  getNullifierPDA,
10001
- getPendingOperationsSummary,
10002
8067
  getPublicKey,
10003
- getPublicViewKey,
10004
- getRecipientAmount,
10005
8068
  getRpcUrlForNetwork,
10006
8069
  getShieldPoolPDAs,
10007
8070
  getSwapStatePDA,
10008
- getViewKey,
10009
- hasPendingOperations,
10010
8071
  hexToBigint,
10011
8072
  hexToBytes,
10012
8073
  importKeys,
10013
- importWalletKeys,
10014
8074
  isDebugEnabled,
10015
8075
  isRootNotFoundError,
10016
8076
  isValidHex,
10017
8077
  isValidRpcUrl,
10018
8078
  isValidSolanaAddress,
10019
8079
  isWithdrawAmountSufficient,
10020
- isWithdrawable,
10021
8080
  keypairToAdapter,
10022
- loadPendingDeposits,
10023
- loadPendingWithdrawals,
10024
8081
  parseAmount,
10025
8082
  parseError,
10026
- parseNote,
10027
8083
  parseRelayErrorResponse,
10028
8084
  parseTransactionError,
10029
8085
  partialWithdraw,
10030
8086
  poseidonHash,
10031
8087
  preflightCheck,
10032
8088
  preflightNullifiers,
10033
- prepareEncryptedOutput,
10034
- prepareEncryptedOutputForRecipient,
10035
8089
  proofToBytes,
10036
8090
  pubkeyToFieldElement,
10037
8091
  pubkeyToLimbs,
@@ -10039,16 +8093,11 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
10039
8093
  randomFieldElement,
10040
8094
  readMerkleTreeState,
10041
8095
  registerViewingKey,
10042
- removePendingDeposit,
10043
- removePendingWithdrawal,
10044
- savePendingDeposit,
10045
- savePendingWithdrawal,
10046
8096
  scanNotesForWallet,
10047
8097
  scanTransactions,
10048
8098
  sdkLogger,
10049
8099
  selectUtxos,
10050
8100
  sendTransaction,
10051
- serializeNote,
10052
8101
  serializeUtxo,
10053
8102
  setCircuitsPath,
10054
8103
  setDebugMode,
@@ -10062,21 +8111,12 @@ var SCANNER_SUPPORTS_TRANSACT_SWAP = true;
10062
8111
  transfer,
10063
8112
  truncate,
10064
8113
  tryDecryptNote,
10065
- updateNoteWithDeposit,
10066
- updatePendingDeposit,
10067
- updatePendingWithdrawal,
10068
8114
  utxoBigintToBytes32,
10069
8115
  utxoEquals,
10070
8116
  utxoHexToBigint,
10071
- validateDepositParams,
10072
- validateNote,
10073
8117
  validateOutputsSum,
10074
8118
  validateRoot,
10075
- validateTransfers,
10076
8119
  validateWalletConnected,
10077
- validateWithdrawableNote,
10078
- verifyAllCircuits,
10079
- verifyCircuitIntegrity,
10080
8120
  verifyUtxos,
10081
8121
  waitForRoot,
10082
8122
  withTiming