@cloak.dev/sdk 0.1.5 → 0.1.7

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.d.ts CHANGED
@@ -1,376 +1,5 @@
1
1
  import { PublicKey, Transaction, Connection, AddressLookupTableAccount, TransactionInstruction, Keypair, SendOptions, VersionedTransaction } from '@solana/web3.js';
2
2
 
3
- type ComplianceTxType = "deposit" | "withdraw" | "send" | "swap";
4
- interface TransactionMetadata {
5
- amount: number;
6
- recipient: string;
7
- timestamp: number;
8
- txType: ComplianceTxType;
9
- commitment: string;
10
- signature?: string;
11
- outputMint?: string;
12
- }
13
- interface EncryptedMetadataBundle {
14
- encrypted_user: string;
15
- encrypted_compliance: string;
16
- user_pubkey: string;
17
- commitment: string;
18
- timestamp: number;
19
- tx_type?: ComplianceTxType;
20
- wallet_signature?: string;
21
- viewing_key?: string;
22
- }
23
-
24
- /**
25
- * Supported Solana networks
26
- */
27
- type Network = "localnet" | "devnet" | "mainnet" | "testnet";
28
- /**
29
- * Minimal wallet adapter interface
30
- * Compatible with @solana/wallet-adapter-base
31
- */
32
- interface WalletAdapter {
33
- publicKey: PublicKey | null;
34
- signTransaction?<T extends Transaction>(transaction: T): Promise<T>;
35
- signAllTransactions?<T extends Transaction>(transactions: T[]): Promise<T[]>;
36
- sendTransaction?(transaction: Transaction, connection: any, options?: any): Promise<string>;
37
- }
38
- /**
39
- * Cloak-specific error with categorization
40
- */
41
- declare class CloakError extends Error {
42
- category: "network" | "indexer" | "prover" | "relay" | "validation" | "wallet" | "environment" | "service";
43
- retryable: boolean;
44
- originalError?: Error | undefined;
45
- constructor(message: string, category: "network" | "indexer" | "prover" | "relay" | "validation" | "wallet" | "environment" | "service", retryable?: boolean, originalError?: Error | undefined);
46
- }
47
- /**
48
- * Cloak Note - Represents a private transaction commitment
49
- *
50
- * A note contains all the information needed to withdraw funds from the Cloak protocol.
51
- * Keep this safe and secret - anyone with access to this note can withdraw the funds!
52
- */
53
- interface CloakNote {
54
- /** Protocol version */
55
- version: string;
56
- /** Amount in lamports */
57
- amount: number;
58
- /** Commitment hash (hex) */
59
- commitment: string;
60
- /** Spending secret key (hex, 64 chars) */
61
- sk_spend: string;
62
- /** Randomness value (hex, 64 chars) */
63
- r: string;
64
- /** Transaction signature from deposit (optional until deposited) */
65
- depositSignature?: string;
66
- /** Solana slot when deposited (optional until deposited) */
67
- depositSlot?: number;
68
- /** Index in the Merkle tree (optional until deposited) */
69
- leafIndex?: number;
70
- /** Historical Merkle root at time of deposit (optional until deposited) */
71
- root?: string;
72
- /** Merkle proof at time of deposit (optional until deposited) */
73
- merkleProof?: MerkleProof;
74
- /** Creation timestamp */
75
- timestamp: number;
76
- /** Network where this note was created */
77
- network: Network;
78
- }
79
- /**
80
- * Merkle proof for a leaf in the commitment tree
81
- */
82
- interface MerkleProof {
83
- /** Sibling hashes along the path (hex strings) */
84
- pathElements: string[];
85
- /** Path directions (0 = left, 1 = right) */
86
- pathIndices: number[];
87
- /** Optional root for backward compatibility */
88
- root?: string;
89
- }
90
- /**
91
- * Transfer recipient - used in privateTransfer
92
- */
93
- interface Transfer {
94
- /** Recipient's Solana public key */
95
- recipient: PublicKey;
96
- /** Amount to send in lamports */
97
- amount: number;
98
- }
99
- /**
100
- * Type-safe array with maximum length constraint
101
- * Used to enforce 1-5 recipients in privateTransfer
102
- */
103
- type MaxLengthArray<T, Max extends number, A extends T[] = []> = A['length'] extends Max ? A : A | MaxLengthArray<T, Max, [T, ...A]>;
104
- /**
105
- * Result from a private transfer
106
- */
107
- interface TransferResult {
108
- /** Solana transaction signature */
109
- signature: string;
110
- /** Recipients and amounts that were sent */
111
- outputs: Array<{
112
- recipient: string;
113
- amount: number;
114
- }>;
115
- /** Nullifier used (prevents double-spending) */
116
- nullifier: string;
117
- /** Merkle root that was proven against */
118
- root: string;
119
- }
120
- /**
121
- * Result from a deposit operation
122
- */
123
- interface DepositResult {
124
- /** The created note (save this securely!) */
125
- note: CloakNote;
126
- /** Solana transaction signature */
127
- signature: string;
128
- /** Leaf index in the Merkle tree */
129
- leafIndex: number;
130
- /** Current Merkle root */
131
- root: string;
132
- }
133
- /**
134
- * Configuration for the Cloak SDK
135
- */
136
- interface CloakConfig {
137
- /** Solana network */
138
- network?: Network;
139
- /**
140
- * Keypair bytes for signing (deprecated - use wallet instead)
141
- * @deprecated Use wallet parameter for better integration
142
- */
143
- keypairBytes?: Uint8Array;
144
- /**
145
- * Wallet adapter for signing transactions
146
- * Required unless using keypairBytes
147
- */
148
- wallet?: WalletAdapter;
149
- /**
150
- * Cloak key pair for v2.0 features (note scanning, encryption)
151
- * Optional but recommended for full functionality
152
- */
153
- cloakKeys?: any;
154
- /** Optional: Proof generation timeout in milliseconds (default: 5 minutes) */
155
- proofTimeout?: number;
156
- /** Optional: Program ID (defaults to Cloak mainnet program) */
157
- programId?: PublicKey;
158
- /** Optional: Pool account address (auto-derived from program ID if not provided) */
159
- poolAddress?: PublicKey;
160
- /** Optional: Merkle tree account address (auto-derived if not provided) */
161
- merkleTreeAddress?: PublicKey;
162
- /** Optional: Treasury account address (auto-derived if not provided) */
163
- treasuryAddress?: PublicKey;
164
- /**
165
- * Enable debug logging with structured output similar to Rust tracing.
166
- *
167
- * When enabled, logs SDK operations with timestamps, module paths,
168
- * and key-value pairs for context:
169
- *
170
- * ```
171
- * 2026-01-23T00:51:46.489000Z INFO cloak::sdk: 📥 Deposit completed signature=42XB... leaf_index=757
172
- * ```
173
- *
174
- * Can also be enabled via environment variable:
175
- * - `CLOAK_DEBUG=1`
176
- * - `DEBUG=cloak:*`
177
- *
178
- * Default: false
179
- */
180
- debug?: boolean;
181
- }
182
- /**
183
- * Deposit progress status
184
- */
185
- type DepositStatus = "generating_note" | "awaiting_note_acknowledgment" | "note_saved" | "creating_transaction" | "simulating" | "sending" | "confirming" | "submitting_to_indexer" | "fetching_proof" | "complete";
186
- /**
187
- * Options for deposit operation
188
- */
189
- interface DepositOptions {
190
- /** Optional callback for progress updates with detailed status */
191
- onProgress?: (status: DepositStatus | string, details?: {
192
- message?: string;
193
- step?: number;
194
- totalSteps?: number;
195
- retryAttempt?: number;
196
- }) => void;
197
- /** Callback when transaction is sent (before confirmation) */
198
- onTransactionSent?: (signature: string) => void;
199
- /** Callback when transaction is confirmed */
200
- onConfirmed?: (signature: string, slot: number) => void;
201
- /**
202
- * CRITICAL: Callback when note is generated, BEFORE any on-chain transaction.
203
- *
204
- * This is your chance to safely persist the note. If you don't save the note
205
- * and the deposit succeeds but the browser crashes, your funds could be lost!
206
- *
207
- * The callback receives the note with all secrets needed for withdrawal.
208
- * The deposit will NOT proceed until this callback completes.
209
- *
210
- * @example
211
- * ```typescript
212
- * onNoteGenerated: async (note) => {
213
- * // Save to secure storage BEFORE deposit proceeds
214
- * await localStorage.setItem(`pending_note_${note.commitment}`, JSON.stringify(note));
215
- * // Or show user a modal to copy/download the note
216
- * }
217
- * ```
218
- */
219
- onNoteGenerated?: (note: CloakNote) => Promise<void> | void;
220
- /**
221
- * If true, require user to acknowledge the note before proceeding with deposit.
222
- * When enabled with onNoteGenerated, the deposit will wait for the callback to complete.
223
- * Default: true when onNoteGenerated is provided
224
- */
225
- requireNoteAcknowledgment?: boolean;
226
- /** Skip simulation (default: false) */
227
- skipPreflight?: boolean;
228
- /**
229
- * Compute units to request.
230
- * - If `optimizeCU` is true, this is ignored and CU is determined via simulation
231
- * - Otherwise defaults to 40,000 (suitable for typical deposits)
232
- */
233
- computeUnits?: number;
234
- /**
235
- * Enable simulation-based CU optimization.
236
- * When true, simulates the transaction first to determine actual CU usage,
237
- * then sets an optimal limit (simulated + 20% buffer).
238
- *
239
- * **Note: Only works in keypair mode (Node.js/scripts).**
240
- * In wallet/browser mode, this is ignored because simulation would require
241
- * the user to sign twice (simulation + actual tx) which is bad UX.
242
- *
243
- * Trade-offs:
244
- * - ✅ Optimal block scheduling priority
245
- * - ❌ Adds ~200-500ms latency (extra RPC call)
246
- * - ❌ Only available in keypair mode
247
- *
248
- * Default: false (uses fixed 40K CU which is ~75% efficient for typical deposits)
249
- */
250
- optimizeCU?: boolean;
251
- /** Priority fee in micro-lamports (default: 10,000) */
252
- priorityFee?: number;
253
- /**
254
- * Loaded accounts data size limit in bytes.
255
- *
256
- * Without this, Solana defaults to 64MB which incurs CU overhead
257
- * (charged at 8 CU per 32KB). Setting a lower limit improves priority.
258
- *
259
- * **Note for Cloak deposits:**
260
- * The Shield Pool program is ~104KB, so the minimum practical limit is ~128KB.
261
- *
262
- * Default: 256 * 1024 (256KB) - provides safety margin above program size.
263
- * Set to 0 to disable (use Solana 64MB default).
264
- *
265
- * @see https://www.anza.xyz/blog/cu-optimization-with-setloadedaccountsdatasizelimit
266
- */
267
- loadedAccountsDataSizeLimit?: number;
268
- /**
269
- * Optional: Encrypt output for specific recipient's view key
270
- * If not provided, encrypts for the wallet's own view key (for self-scanning)
271
- */
272
- recipientViewKey?: string;
273
- /**
274
- * Skip privacy warning on testnet (default: false)
275
- * Warning: Only skip if you understand the privacy limitations
276
- */
277
- skipPrivacyWarning?: boolean;
278
- }
279
- /**
280
- * Options for private transfer/withdraw operation
281
- */
282
- interface TransferOptions {
283
- /**
284
- * Optional callback for progress updates
285
- * Note: relayFeeBps is automatically calculated from protocol fees
286
- */
287
- onProgress?: (status: string) => void;
288
- /** Optional callback for proof generation progress (0-100) */
289
- onProofProgress?: (percent: number) => void;
290
- /**
291
- * Metadata bundle for compliance tracking.
292
- * On first transaction, should include viewing_key for compliance registration.
293
- */
294
- metadataBundle?: {
295
- encrypted_user: string;
296
- encrypted_compliance: string;
297
- user_pubkey: string;
298
- commitment: string;
299
- timestamp: number;
300
- tx_type?: ComplianceTxType;
301
- viewing_key?: string;
302
- };
303
- }
304
- /**
305
- * Options for withdrawal (convenience method with single recipient)
306
- */
307
- interface WithdrawOptions extends TransferOptions {
308
- /** Whether to withdraw full amount minus fees (default: true) */
309
- withdrawAll?: boolean;
310
- /** Specific amount to withdraw in lamports (if not withdrawing all) */
311
- amount?: number;
312
- }
313
- /**
314
- * Merkle root response from indexer
315
- */
316
- interface MerkleRootResponse {
317
- root: string;
318
- next_index: number;
319
- }
320
- /**
321
- * Transaction status from relay service
322
- */
323
- interface TxStatus {
324
- status: "pending" | "processing" | "completed" | "failed";
325
- txId?: string;
326
- error?: string;
327
- }
328
- /**
329
- * Swap parameters for token swaps
330
- */
331
- interface SwapParams {
332
- /** Output token mint address */
333
- output_mint: string;
334
- /** Slippage tolerance in basis points (e.g., 100 = 1%) */
335
- slippage_bps: number;
336
- /** Minimum output amount in token's smallest unit */
337
- min_output_amount: number;
338
- }
339
- /**
340
- * Options for swap operation
341
- */
342
- interface SwapOptions extends TransferOptions {
343
- /** Output token mint address */
344
- outputMint: string;
345
- /** Slippage tolerance in basis points (default: 100 = 1%) */
346
- slippageBps?: number;
347
- /** Minimum output amount (will be calculated from quote if not provided) */
348
- minOutputAmount?: number;
349
- /** Optional callback to get swap quote */
350
- getQuote?: (amountLamports: number, outputMint: string, slippageBps: number) => Promise<{
351
- outAmount: number;
352
- minOutputAmount: number;
353
- }>;
354
- /**
355
- * Recipient's associated token account for the output token.
356
- * If not provided, will be computed automatically (requires @solana/spl-token).
357
- * For browser environments, it's recommended to compute this in the frontend
358
- * where @solana/spl-token is properly bundled.
359
- */
360
- recipientAta?: string;
361
- }
362
- /**
363
- * Result from a swap operation
364
- */
365
- interface SwapResult extends TransferResult {
366
- /** Output token mint address */
367
- outputMint: string;
368
- /** Minimum output amount that was guaranteed */
369
- minOutputAmount: number;
370
- /** Actual output amount received (may be higher than min) */
371
- actualOutputAmount?: number;
372
- }
373
-
374
3
  /**
375
4
  * Cloak Key Hierarchy (v2.0)
376
5
  *
@@ -412,684 +41,353 @@ interface NoteData {
412
41
  commitment: string;
413
42
  }
414
43
  /**
415
- * Generate a new master seed from secure randomness
416
- */
417
- declare function generateMasterSeed(): MasterKey;
418
- /**
419
- * Derive spend key from master seed
420
- */
421
- declare function deriveSpendKey(masterSeed: Uint8Array): SpendKey;
422
- /**
423
- * Derive view key from spend key
424
- */
425
- declare function deriveViewKey(sk_spend: Uint8Array): ViewKey;
426
- /**
427
- * Generate complete key hierarchy from master seed
428
- */
429
- declare function generateCloakKeys(masterSeed?: Uint8Array): CloakKeyPair;
430
- /**
431
- * Encrypt note data for a recipient using their public view key
432
- *
433
- * Uses X25519 ECDH + XSalsa20-Poly1305 authenticated encryption
434
- */
435
- declare function encryptNoteForRecipient(noteData: NoteData, recipientPvk: Uint8Array): EncryptedNote$1;
436
- /**
437
- * Attempt to decrypt an encrypted note using view key
438
- *
439
- * Returns null if decryption fails (note doesn't belong to this wallet)
440
- * Returns NoteData if successful
441
- */
442
- declare function tryDecryptNote(encryptedNote: EncryptedNote$1, viewKey: ViewKey): NoteData | null;
443
- /**
444
- * Scan a batch of encrypted outputs and return notes belonging to this wallet
445
- */
446
- declare function scanNotesForWallet(encryptedOutputs: string[], // Base64 encoded encrypted note JSON
447
- viewKey: ViewKey): NoteData[];
448
- /**
449
- * Export keys for backup (WARNING: contains secrets!)
450
- */
451
- declare function exportKeys(keys: CloakKeyPair): string;
452
- /**
453
- * Import keys from backup
454
- */
455
- declare function importKeys(exported: string): CloakKeyPair;
456
-
457
- /**
458
- * Storage Interface
459
- *
460
- * Defines a pluggable storage interface for notes and keys.
461
- * Applications can implement their own storage (localStorage, IndexedDB, file system, etc.)
462
- */
463
-
464
- /**
465
- * Storage adapter interface
466
- *
467
- * Implement this interface to provide custom storage for notes and keys.
468
- * The SDK will use this adapter for all persistence operations.
469
- */
470
- interface StorageAdapter {
471
- /**
472
- * Save a note
473
- */
474
- saveNote(note: CloakNote): Promise<void> | void;
475
- /**
476
- * Load all notes
477
- */
478
- loadAllNotes(): Promise<CloakNote[]> | CloakNote[];
479
- /**
480
- * Update a note
481
- */
482
- updateNote(commitment: string, updates: Partial<CloakNote>): Promise<void> | void;
483
- /**
484
- * Delete a note
485
- */
486
- deleteNote(commitment: string): Promise<void> | void;
487
- /**
488
- * Clear all notes
489
- */
490
- clearAllNotes(): Promise<void> | void;
491
- /**
492
- * Save wallet keys
493
- */
494
- saveKeys(keys: CloakKeyPair): Promise<void> | void;
495
- /**
496
- * Load wallet keys
497
- */
498
- loadKeys(): Promise<CloakKeyPair | null> | CloakKeyPair | null;
499
- /**
500
- * Delete wallet keys
501
- */
502
- deleteKeys(): Promise<void> | void;
503
- }
504
- /**
505
- * In-memory storage adapter (default, no persistence)
506
- *
507
- * Useful for testing or when storage is handled externally
508
- */
509
- declare class MemoryStorageAdapter implements StorageAdapter {
510
- private notes;
511
- private keys;
512
- saveNote(note: CloakNote): void;
513
- loadAllNotes(): CloakNote[];
514
- updateNote(commitment: string, updates: Partial<CloakNote>): void;
515
- deleteNote(commitment: string): void;
516
- clearAllNotes(): void;
517
- saveKeys(keys: CloakKeyPair): void;
518
- loadKeys(): CloakKeyPair | null;
519
- deleteKeys(): void;
520
- }
521
- /**
522
- * Browser localStorage adapter (optional, for browser environments)
523
- *
524
- * Only use this if you're in a browser environment and want localStorage persistence.
525
- * Import from a separate browser-specific module.
526
- */
527
- declare class LocalStorageAdapter implements StorageAdapter {
528
- private notesKey;
529
- private keysKey;
530
- constructor(notesKey?: string, keysKey?: string);
531
- private getStorage;
532
- saveNote(note: CloakNote): void;
533
- loadAllNotes(): CloakNote[];
534
- updateNote(commitment: string, updates: Partial<CloakNote>): void;
535
- deleteNote(commitment: string): void;
536
- clearAllNotes(): void;
537
- saveKeys(keys: CloakKeyPair): void;
538
- loadKeys(): CloakKeyPair | null;
539
- deleteKeys(): void;
540
- }
541
-
542
- /** Default Cloak Program ID on Solana */
543
- declare const CLOAK_PROGRAM_ID: PublicKey;
544
- /**
545
- * Main Cloak SDK
546
- *
547
- * Provides high-level API for interacting with the Cloak protocol,
548
- * including deposits, withdrawals, and private transfers.
549
- *
550
- * Supports two modes:
551
- * 1. Node.js mode with keypairBytes - for scripts and backend services
552
- * 2. Wallet adapter mode - for browser applications with wallet integration
553
- */
554
- declare class CloakSDK {
555
- private config;
556
- private keypair?;
557
- private wallet?;
558
- private cloakKeys?;
559
- private relay;
560
- private storage;
561
- /**
562
- * Create a new Cloak SDK client
563
- *
564
- * @param config - Client configuration
565
- *
566
- * @example Node.js mode (with keypair)
567
- * ```typescript
568
- * const sdk = new CloakSDK({
569
- * keypairBytes: keypair.secretKey,
570
- * network: "devnet"
571
- * });
572
- * ```
573
- *
574
- * @example Browser mode (with wallet adapter)
575
- * ```typescript
576
- * const sdk = new CloakSDK({
577
- * wallet: walletAdapter,
578
- * network: "devnet"
579
- * });
580
- * ```
581
- */
582
- constructor(config: {
583
- /** Keypair bytes for signing (Node.js mode) */
584
- keypairBytes?: Uint8Array;
585
- /** Wallet adapter for signing (Browser mode) */
586
- wallet?: WalletAdapter;
587
- network?: Network;
588
- cloakKeys?: CloakKeyPair;
589
- storage?: StorageAdapter;
590
- programId?: PublicKey;
591
- relayUrl?: string;
592
- /** Enable debug logging with structured output */
593
- debug?: boolean;
594
- });
595
- /**
596
- * Get the public key for deposits (from keypair or wallet)
597
- */
598
- getPublicKey(): PublicKey;
599
- /**
600
- * Check if the SDK is using a wallet adapter
601
- */
602
- isWalletMode(): boolean;
603
- /**
604
- * Deposit SOL into the Cloak protocol
605
- *
606
- * Creates a new note (or uses a provided one), submits a deposit transaction,
607
- * and registers with the indexer.
608
- *
609
- * @param connection - Solana connection
610
- * @param payer - Payer wallet with sendTransaction method
611
- * @param amountOrNote - Amount in lamports OR an existing note to deposit
612
- * @param options - Optional configuration
613
- * @returns Deposit result with note and transaction info
614
- *
615
- * @example
616
- * ```typescript
617
- * // Generate and deposit in one step
618
- * const result = await client.deposit(
619
- * connection,
620
- * wallet,
621
- * 1_000_000_000,
622
- * {
623
- * onProgress: (status) => console.log(status)
624
- * }
625
- * );
626
- *
627
- * // Or deposit a pre-generated note
628
- * const note = client.generateNote(1_000_000_000);
629
- * const result = await client.deposit(connection, wallet, note);
630
- * ```
631
- */
632
- deposit(connection: Connection, amountOrNote: number | CloakNote, options?: DepositOptions): Promise<DepositResult>;
633
- /**
634
- * Private transfer with up to 5 recipients
635
- *
636
- * Handles the complete private transfer flow:
637
- * 1. If note is not deposited, deposits it first and waits for confirmation
638
- * 2. Generates a zero-knowledge proof
639
- * 3. Submits the withdrawal via relay service to recipients
640
- *
641
- * This is the main method for performing private transfers - it handles everything!
642
- *
643
- * @param connection - Solana connection (required for deposit if not already deposited)
644
- * @param payer - Payer wallet (required for deposit if not already deposited)
645
- * @param note - Note to spend (can be deposited or not)
646
- * @param recipients - Array of 1-5 recipients with amounts
647
- * @param options - Optional configuration
648
- * @returns Transfer result with signature and outputs
649
- *
650
- * @example
651
- * ```typescript
652
- * // Create a note (not deposited yet)
653
- * const note = client.generateNote(1_000_000_000);
654
- *
655
- * // privateTransfer handles the full flow: deposit + withdraw
656
- * const result = await client.privateTransfer(
657
- * connection,
658
- * wallet,
659
- * note,
660
- * [
661
- * { recipient: new PublicKey("..."), amount: 500_000_000 },
662
- * { recipient: new PublicKey("..."), amount: 492_500_000 }
663
- * ],
664
- * {
665
- * relayFeeBps: 50, // 0.5%
666
- * onProgress: (status) => console.log(status),
667
- * onProofProgress: (pct) => console.log(`Proof: ${pct}%`)
668
- * }
669
- * );
670
- * console.log(`Success! TX: ${result.signature}`);
671
- * ```
672
- */
673
- privateTransfer(connection: Connection, note: CloakNote, recipients: MaxLengthArray<Transfer, 5>, options?: TransferOptions): Promise<TransferResult>;
674
- /**
675
- * Withdraw to a single recipient
676
- *
677
- * Convenience method for withdrawing to one address.
678
- * Handles the complete flow: deposits if needed, then withdraws.
679
- *
680
- * @param connection - Solana connection
681
- * @param payer - Payer wallet
682
- * @param note - Note to spend
683
- * @param recipient - Recipient address
684
- * @param options - Optional configuration
685
- * @returns Transfer result
686
- *
687
- * @example
688
- * ```typescript
689
- * const note = client.generateNote(1_000_000_000);
690
- * const result = await client.withdraw(
691
- * connection,
692
- * wallet,
693
- * note,
694
- * new PublicKey("..."),
695
- * { withdrawAll: true }
696
- * );
697
- * ```
698
- */
699
- withdraw(connection: Connection, note: CloakNote, recipient: PublicKey, options?: WithdrawOptions): Promise<TransferResult>;
700
- /**
701
- * Send SOL privately to multiple recipients
702
- *
703
- * Convenience method that wraps privateTransfer with a simpler API.
704
- * Handles the complete flow: deposits if needed, then sends to recipients.
705
- *
706
- * @param connection - Solana connection
707
- * @param note - Note to spend
708
- * @param recipients - Array of 1-5 recipients with amounts
709
- * @param options - Optional configuration
710
- * @returns Transfer result
711
- *
712
- * @example
713
- * ```typescript
714
- * const note = client.generateNote(1_000_000_000);
715
- * const result = await client.send(
716
- * connection,
717
- * note,
718
- * [
719
- * { recipient: new PublicKey("..."), amount: 500_000_000 },
720
- * { recipient: new PublicKey("..."), amount: 492_500_000 }
721
- * ]
722
- * );
723
- * ```
724
- */
725
- send(connection: Connection, note: CloakNote, recipients: MaxLengthArray<Transfer, 5>, options?: TransferOptions): Promise<TransferResult>;
726
- /**
727
- * Swap SOL for tokens privately
728
- *
729
- * Withdraws SOL from a note and swaps it for tokens via the relay service.
730
- * Handles the complete flow: deposits if needed, generates proof, and submits swap.
731
- *
732
- * @param connection - Solana connection
733
- * @param note - Note to spend
734
- * @param recipient - Recipient address (will receive tokens)
735
- * @param options - Swap configuration
736
- * @returns Swap result with transaction signature
737
- *
738
- * @example
739
- * ```typescript
740
- * const note = client.generateNote(1_000_000_000);
741
- * const result = await client.swap(
742
- * connection,
743
- * note,
744
- * new PublicKey("..."), // recipient
745
- * {
746
- * outputMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC
747
- * slippageBps: 100, // 1%
748
- * getQuote: async (amount, mint, slippage) => {
749
- * // Fetch quote from your swap API
750
- * const quote = await fetchSwapQuote(amount, mint, slippage);
751
- * return {
752
- * outAmount: quote.outAmount,
753
- * minOutputAmount: quote.minOutputAmount
754
- * };
755
- * }
756
- * }
757
- * );
758
- * ```
759
- */
760
- swap(connection: Connection, note: CloakNote, recipient: PublicKey, options: SwapOptions): Promise<SwapResult>;
761
- /**
762
- * Generate a new note without depositing
763
- *
764
- * @param amountLamports - Amount for the note
765
- * @param useWalletKeys - Whether to use wallet keys (v2.0 recommended)
766
- * @returns New note (not yet deposited)
767
- */
768
- generateNote(amountLamports: number, useWalletKeys?: boolean): Promise<CloakNote>;
769
- /**
770
- * Parse a note from JSON string
771
- *
772
- * @param jsonString - JSON representation
773
- * @returns Parsed note
774
- */
775
- parseNote(jsonString: string): CloakNote;
776
- /**
777
- * Export a note to JSON string
778
- *
779
- * @param note - Note to export
780
- * @param pretty - Format with indentation
781
- * @returns JSON string
782
- */
783
- exportNote(note: CloakNote, pretty?: boolean): string;
784
- /**
785
- * Check if a note is ready for withdrawal
786
- *
787
- * @param note - Note to check
788
- * @returns True if withdrawable
789
- */
790
- isWithdrawable(note: CloakNote): boolean;
791
- /**
792
- * Get Merkle proof for a leaf index directly from on-chain state
793
- *
794
- * @param connection - Solana connection
795
- * @param leafIndex - Leaf index in tree
796
- * @returns Merkle proof computed from on-chain data
797
- */
798
- getMerkleProof(connection: Connection, leafIndex: number): Promise<MerkleProof>;
799
- /**
800
- * Get current Merkle root directly from on-chain state
801
- *
802
- * @param connection - Solana connection
803
- * @returns Current root hash from on-chain tree
804
- */
805
- getCurrentRoot(connection: Connection): Promise<string>;
806
- /**
807
- * Get transaction status from relay service
808
- *
809
- * @param requestId - Request ID from previous submission
810
- * @returns Current status
811
- */
812
- getTransactionStatus(requestId: string): Promise<TxStatus>;
813
- /**
814
- * Fetch and decrypt this user's transaction metadata history.
815
- * DEPRECATED: This functionality is no longer supported
816
- */
817
- getTransactionMetadata(_options?: {
818
- _after?: number;
819
- _before?: number;
820
- }): Promise<TransactionMetadata[]>;
821
- /**
822
- * Load all notes from storage
823
- *
824
- * @returns Array of saved notes
825
- */
826
- loadNotes(): Promise<CloakNote[]>;
827
- /**
828
- * Save a note to storage
829
- *
830
- * @param note - Note to save
831
- */
832
- saveNote(note: CloakNote): Promise<void>;
833
- /**
834
- * Find a note by its commitment
835
- *
836
- * @param commitment - Commitment hash
837
- * @returns Note if found
838
- */
839
- findNote(commitment: string): Promise<CloakNote | undefined>;
840
- /**
841
- * Import wallet keys from JSON
842
- *
843
- * @param keysJson - JSON string containing keys
844
- */
845
- importWalletKeys(keysJson: string): Promise<void>;
846
- /**
847
- * Export wallet keys to JSON
848
- *
849
- * WARNING: This exports secret keys! Store securely.
850
- *
851
- * @returns JSON string with keys
852
- */
853
- exportWalletKeys(): string;
854
- /**
855
- * Get the configuration
856
- */
857
- getConfig(): CloakConfig;
858
- /**
859
- * Wrap errors with better categorization and user-friendly messages
860
- *
861
- * @private
862
- */
863
- private wrapError;
864
- }
865
-
866
- /**
867
- * Serialize a note to JSON string
868
- *
869
- * @param note - Note to serialize
870
- * @param pretty - Whether to format with indentation (default: false)
871
- * @returns JSON string
872
- *
873
- * @example
874
- * ```typescript
875
- * const json = serializeNote(note, true);
876
- * console.log(json);
877
- * // Or save to file, copy to clipboard, etc.
878
- * ```
879
- */
880
- declare function serializeNote(note: CloakNote, pretty?: boolean): string;
881
- /**
882
- * Export note as downloadable JSON (browser only)
883
- *
884
- * @param note - Note to export
885
- * @param filename - Optional custom filename
886
- */
887
- declare function downloadNote(note: CloakNote, filename?: string): void;
888
- /**
889
- * Copy note to clipboard as JSON (browser only)
890
- *
891
- * @param note - Note to copy
892
- * @returns Promise that resolves when copied
893
- */
894
- declare function copyNoteToClipboard(note: CloakNote): Promise<void>;
895
-
896
- /**
897
- * Fee calculation utilities for Cloak Protocol
898
- *
899
- * The protocol charges a fixed fee plus a variable percentage fee
900
- * to prevent sybil attacks and cover operational costs.
901
- *
902
- * IMPORTANT: These constants are the single source of truth for fee calculations.
903
- * When updating fees, only change these values - all other code should import from here.
904
- */
905
- /** Lamports per SOL */
906
- declare const LAMPORTS_PER_SOL = 1000000000;
907
- /** Fixed fee: 0.005 SOL (5M lamports) */
908
- declare const FIXED_FEE_LAMPORTS = 5000000;
909
- /** Variable fee numerator (3 = 0.3%) */
910
- declare const VARIABLE_FEE_NUMERATOR = 3;
911
- /** Variable fee denominator (1000 = divide by 1000) */
912
- declare const VARIABLE_FEE_DENOMINATOR = 1000;
913
- /** Variable fee rate as decimal: 0.3% = 0.003 */
914
- declare const VARIABLE_FEE_RATE: number;
915
- /** Minimum deposit amount to prevent dust/UX footguns (0.01 SOL). */
916
- declare const MIN_DEPOSIT_LAMPORTS = 10000000;
917
- /**
918
- * Calculate the total protocol fee for a given amount
919
- *
920
- * Formula: FIXED_FEE + floor((amount * VARIABLE_FEE_NUMERATOR) / VARIABLE_FEE_DENOMINATOR)
921
- *
922
- * @param amountLamports - Amount in lamports
923
- * @returns Total fee in lamports
924
- *
925
- * @example
926
- * ```typescript
927
- * const fee = calculateFee(1_000_000_000); // 1 SOL
928
- * // Returns: 5_000_000 (fixed) + 3_000_000 (0.3%) = 8_000_000 lamports
929
- * ```
930
- */
931
- declare function calculateFee(amountLamports: number): number;
932
- /**
933
- * Bigint version of calculateFee (for UTXO flows that use bigint lamports).
934
- */
935
- declare function calculateFeeBigint(amountLamports: bigint): bigint;
936
- /**
937
- * Returns true if a withdrawal amount can pay fees and still leave >0 lamports.
938
- * (On-chain uses the same integer math and enforces this as well.)
939
- */
940
- declare function isWithdrawAmountSufficient(amountLamports: bigint): boolean;
941
- /**
942
- * Calculate the distributable amount after protocol fees
943
- *
944
- * This is the amount available to send to recipients.
945
- *
946
- * @param amountLamports - Total note amount in lamports
947
- * @returns Amount available for recipients in lamports
948
- *
949
- * @example
950
- * ```typescript
951
- * const distributable = getDistributableAmount(1_000_000_000);
952
- * // Returns: 1_000_000_000 - 7_500_000 = 992_500_000 lamports
953
- * ```
954
- */
955
- declare function getDistributableAmount(amountLamports: number): number;
956
- /**
957
- * Format lamports as SOL string
958
- *
959
- * @param lamports - Amount in lamports
960
- * @param decimals - Number of decimal places (default: 9)
961
- * @returns Formatted string (e.g., "1.000000000")
962
- *
963
- * @example
964
- * ```typescript
965
- * formatAmount(1_000_000_000); // "1.000000000"
966
- * formatAmount(1_500_000_000); // "1.500000000"
967
- * formatAmount(123_456_789, 4); // "0.1235"
968
- * ```
44
+ * Generate a new master seed from secure randomness
969
45
  */
970
- declare function formatAmount(lamports: number, decimals?: number): string;
46
+ declare function generateMasterSeed(): MasterKey;
971
47
  /**
972
- * Parse SOL string to lamports
973
- *
974
- * @param sol - SOL amount as string (e.g., "1.5")
975
- * @returns Amount in lamports
976
- * @throws Error if invalid format
977
- *
978
- * @example
979
- * ```typescript
980
- * parseAmount("1.5"); // 1_500_000_000
981
- * parseAmount("0.001"); // 1_000_000
982
- * ```
48
+ * Derive spend key from master seed
983
49
  */
984
- declare function parseAmount(sol: string): number;
50
+ declare function deriveSpendKey(masterSeed: Uint8Array): SpendKey;
985
51
  /**
986
- * Validate that outputs sum equals expected amount
987
- *
988
- * @param outputs - Array of output amounts
989
- * @param expectedTotal - Expected total amount
990
- * @returns True if amounts match
52
+ * Derive view key from spend key
991
53
  */
992
- declare function validateOutputsSum(outputs: Array<{
993
- amount: number;
994
- }>, expectedTotal: number): boolean;
54
+ declare function deriveViewKey(sk_spend: Uint8Array): ViewKey;
995
55
  /**
996
- * Calculate relay fee from basis points
997
- *
998
- * @param amountLamports - Amount in lamports
999
- * @param feeBps - Fee in basis points (100 bps = 1%)
1000
- * @returns Relay fee in lamports
1001
- *
1002
- * @example
1003
- * ```typescript
1004
- * calculateRelayFee(1_000_000_000, 50); // 0.5% = 5_000_000 lamports
1005
- * ```
56
+ * Generate complete key hierarchy from master seed
1006
57
  */
1007
- declare function calculateRelayFee(amountLamports: number, feeBps: number): number;
1008
-
58
+ declare function generateCloakKeys(masterSeed?: Uint8Array): CloakKeyPair;
1009
59
  /**
1010
- * Note Manager
60
+ * Encrypt note data for a recipient using their public view key
1011
61
  *
1012
- * Standalone note management - no browser dependencies.
1013
- * Storage is handled externally via StorageAdapter.
62
+ * Uses X25519 ECDH + XSalsa20-Poly1305 authenticated encryption
63
+ */
64
+ declare function encryptNoteForRecipient(noteData: NoteData, recipientPvk: Uint8Array): EncryptedNote$1;
65
+ /**
66
+ * Attempt to decrypt an encrypted note using view key
1014
67
  *
1015
- * Core functionality:
1016
- * - Generate notes (v1.0 and v2.0)
1017
- * - Parse and validate notes
1018
- * - Note utilities (formatting, fees, etc.)
1019
- * - Key management (without storage)
68
+ * Returns null if decryption fails (note doesn't belong to this wallet)
69
+ * Returns NoteData if successful
1020
70
  */
1021
-
71
+ declare function tryDecryptNote(encryptedNote: EncryptedNote$1, viewKey: ViewKey): NoteData | null;
72
+ /**
73
+ * Scan a batch of encrypted outputs and return notes belonging to this wallet
74
+ */
75
+ declare function scanNotesForWallet(encryptedOutputs: string[], // Base64 encoded encrypted note JSON
76
+ viewKey: ViewKey): NoteData[];
1022
77
  /**
1023
- * Generate a new note without wallet keys (legacy v1.0)
1024
- * Uses Poseidon hashing to match circuit implementation
1025
- * @deprecated Use generateNoteFromWallet instead for enhanced security
78
+ * Export keys for backup (WARNING: contains secrets!)
1026
79
  */
1027
- declare function generateNote(amountLamports: number, network?: Network): Promise<CloakNote>;
80
+ declare function exportKeys(keys: CloakKeyPair): string;
1028
81
  /**
1029
- * Generate a note using wallet's spend key (v2.0 recommended)
1030
- * Uses Poseidon hashing to match circuit implementation
82
+ * Import keys from backup
1031
83
  */
1032
- declare function generateNoteFromWallet(amountLamports: number, keys: CloakKeyPair, network?: Network): Promise<CloakNote>;
84
+ declare function importKeys(exported: string): CloakKeyPair;
85
+
1033
86
  /**
1034
- * Parse and validate a note from JSON string
87
+ * Supported Solana networks.
1035
88
  */
1036
- declare function parseNote(jsonString: string): CloakNote;
89
+ type Network = "localnet" | "devnet" | "mainnet" | "testnet";
1037
90
  /**
1038
- * Export note to JSON string
91
+ * Minimal wallet adapter interface — compatible with `@solana/wallet-adapter-base`.
1039
92
  */
1040
- declare function exportNote(note: CloakNote, pretty?: boolean): string;
93
+ interface WalletAdapter {
94
+ publicKey: PublicKey | null;
95
+ signTransaction?<T extends Transaction>(transaction: T): Promise<T>;
96
+ signAllTransactions?<T extends Transaction>(transactions: T[]): Promise<T[]>;
97
+ sendTransaction?(transaction: Transaction, connection: any, options?: any): Promise<string>;
98
+ }
1041
99
  /**
1042
- * Check if a note is withdrawable (has been deposited)
1043
- * Note: merkleProof is optional - it may be fetched lazily at withdrawal time
100
+ * Cloak-specific error with categorization.
1044
101
  */
1045
- declare function isWithdrawable(note: CloakNote): boolean;
102
+ declare class CloakError extends Error {
103
+ category: "network" | "indexer" | "prover" | "relay" | "validation" | "wallet" | "environment" | "service";
104
+ retryable: boolean;
105
+ originalError?: Error | undefined;
106
+ constructor(message: string, category: "network" | "indexer" | "prover" | "relay" | "validation" | "wallet" | "environment" | "service", retryable?: boolean, originalError?: Error | undefined);
107
+ }
1046
108
  /**
1047
- * Update note with deposit information
1048
- * Returns a new note object with deposit info added
109
+ * Merkle proof for a leaf in the commitment tree.
1049
110
  */
1050
- declare function updateNoteWithDeposit(note: CloakNote, depositInfo: {
1051
- signature: string;
1052
- slot: number;
1053
- leafIndex: number;
1054
- root: string;
1055
- merkleProof?: {
1056
- pathElements: string[];
1057
- pathIndices: number[];
1058
- };
1059
- }): CloakNote;
111
+ interface MerkleProof {
112
+ /** Sibling hashes along the path (hex strings) */
113
+ pathElements: string[];
114
+ /** Path directions (0 = left, 1 = right) */
115
+ pathIndices: number[];
116
+ /** Optional root for backward compatibility */
117
+ root?: string;
118
+ }
1060
119
  /**
1061
- * Find note by commitment from an array
120
+ * Snapshot of the active SDK configuration, returned by `CloakSDK.getConfig()`.
121
+ *
122
+ * This type is intentionally narrower than the constructor input
123
+ * (`CloakSDKOptions` in `core/CloakSDK.ts`): it omits `keypairBytes`,
124
+ * `wallet`, and `storage` because those are consumed into private SDK
125
+ * state (`this.keypair`, `this.wallet`, `this.storage`) at construction
126
+ * time and are never persisted on the config object. The type system
127
+ * therefore enforces the same invariant exercised at runtime by
128
+ * `cloak-sdk.test.ts`.
129
+ *
130
+ * If you're configuring the SDK at construction, use `CloakSDKOptions`.
1062
131
  */
1063
- declare function findNoteByCommitment(notes: CloakNote[], commitment: string): CloakNote | undefined;
132
+ interface CloakConfig {
133
+ /** Network the SDK was constructed for. Defaults to `"mainnet"`. */
134
+ network?: Network;
135
+ /** Cloak key pair for note scanning / encryption (when provided). */
136
+ cloakKeys?: CloakKeyPair;
137
+ /** Resolved program ID (defaults to the mainnet shield-pool). */
138
+ programId?: PublicKey;
139
+ /** Pool PDA derived from `programId` + native SOL mint. */
140
+ poolAddress?: PublicKey;
141
+ /** Merkle-tree PDA. */
142
+ merkleTreeAddress?: PublicKey;
143
+ /** Treasury PDA. */
144
+ treasuryAddress?: PublicKey;
145
+ /**
146
+ * Whether structured debug logging was enabled at construction.
147
+ *
148
+ * Can also be enabled via env: `CLOAK_DEBUG=1` or `DEBUG=cloak:*`.
149
+ */
150
+ debug?: boolean;
151
+ }
1064
152
  /**
1065
- * Filter notes by network
153
+ * Merkle root response from the relay/indexer.
1066
154
  */
1067
- declare function filterNotesByNetwork(notes: CloakNote[], network: Network): CloakNote[];
155
+ interface MerkleRootResponse {
156
+ root: string;
157
+ next_index: number;
158
+ }
1068
159
  /**
1069
- * Filter notes that can be withdrawn
160
+ * Transaction status returned by the relay.
1070
161
  */
1071
- declare function filterWithdrawableNotes(notes: CloakNote[]): CloakNote[];
162
+ interface TxStatus {
163
+ status: "pending" | "processing" | "completed" | "failed";
164
+ txId?: string;
165
+ error?: string;
166
+ }
167
+
1072
168
  /**
1073
- * Export keys to JSON string
1074
- * WARNING: This exports secret keys! Store securely.
169
+ * Storage Interface
170
+ *
171
+ * Pluggable storage for Cloak wallet keys (master seed / spend / view keys).
172
+ *
173
+ * As of `0.1.6`, note persistence is the consumer's responsibility: the OLD
174
+ * `CloakNote` model was retired (see `CloakSDK` jsdoc), and UTXO persistence
175
+ * in the new flow is owned by callers.
1075
176
  */
1076
- declare function exportWalletKeys(keys: CloakKeyPair): string;
177
+
178
+ interface StorageAdapter {
179
+ /** Save wallet keys. */
180
+ saveKeys(keys: CloakKeyPair): Promise<void> | void;
181
+ /** Load wallet keys (`null` when none stored). */
182
+ loadKeys(): Promise<CloakKeyPair | null> | CloakKeyPair | null;
183
+ /** Delete wallet keys. */
184
+ deleteKeys(): Promise<void> | void;
185
+ }
1077
186
  /**
1078
- * Import keys from JSON string
187
+ * In-memory storage adapter (default; no persistence). Useful for tests or
188
+ * when storage is handled externally.
1079
189
  */
1080
- declare function importWalletKeys(keysJson: string): CloakKeyPair;
190
+ declare class MemoryStorageAdapter implements StorageAdapter {
191
+ private keys;
192
+ saveKeys(keys: CloakKeyPair): void;
193
+ loadKeys(): CloakKeyPair | null;
194
+ deleteKeys(): void;
195
+ }
1081
196
  /**
1082
- * Get public view key from keys
197
+ * Browser `localStorage` adapter only safe in browser environments.
198
+ *
199
+ * **Auto-purge on construction:** the first time any `LocalStorageAdapter`
200
+ * is constructed in a given browser, it removes the legacy `cloak_notes`
201
+ * localStorage entry (pre-0.1.6 plaintext `r` + `sk_spend` blob) and writes
202
+ * a sentinel under {@link LEGACY_PURGE_SENTINEL_KEY} so subsequent
203
+ * constructions skip the work. This closes the upgrade-time security gap
204
+ * without requiring every consumer to explicitly call
205
+ * {@link LocalStorageAdapter.purgeLegacyNoteStorage}. Consumers using a
206
+ * non-default legacy key can still call the static helper with their own
207
+ * key name.
1083
208
  */
1084
- declare function getPublicViewKey(keys: CloakKeyPair): string;
209
+ declare class LocalStorageAdapter implements StorageAdapter {
210
+ private keysKey;
211
+ constructor(keysKey?: string);
212
+ private getStorage;
213
+ saveKeys(keys: CloakKeyPair): void;
214
+ loadKeys(): CloakKeyPair | null;
215
+ deleteKeys(): void;
216
+ /**
217
+ * Sentinel key set after the auto-purge runs. Persists across browser
218
+ * sessions so the purge never re-runs on the same origin.
219
+ */
220
+ static readonly LEGACY_PURGE_SENTINEL_KEY = "cloak_purged_v0_1_5";
221
+ /**
222
+ * Default localStorage key the legacy `<= 0.1.5` SDK used for the
223
+ * plaintext `CloakNote[]` blob.
224
+ */
225
+ static readonly LEGACY_NOTES_KEY = "cloak_notes";
226
+ /**
227
+ * Runs the legacy-purge exactly once per browser origin. Invoked
228
+ * automatically by the constructor; exposed as a static for tests and
229
+ * for callers who want to force the check before the first adapter
230
+ * instantiation.
231
+ */
232
+ static runLegacyPurgeOnce(): void;
233
+ /**
234
+ * Manual cleanup helper for callers that stored notes under a non-default
235
+ * key. The auto-purge in the constructor only handles the canonical
236
+ * `cloak_notes` slot; pass the custom key here.
237
+ *
238
+ * Pre-0.1.6 versions stored the user's `CloakNote[]` (including
239
+ * `r` randomness and `sk_spend` secret-key hex) as JSON plaintext.
240
+ * Those notes are no longer usable (the OLD `withdraw_regular.circom`
241
+ * flow is incompatible with the deployed UTXO program) but the plaintext
242
+ * would otherwise linger indefinitely.
243
+ *
244
+ * Idempotent; safe to call when the key doesn't exist or when running
245
+ * outside a browser (no-op). Does NOT update the auto-purge sentinel.
246
+ *
247
+ * @param notesKey - localStorage key to remove (default `"cloak_notes"`,
248
+ * matching the pre-0.1.6 default).
249
+ */
250
+ static purgeLegacyNoteStorage(notesKey?: string): void;
251
+ }
252
+
253
+ /** Default Cloak Program ID on Solana mainnet. */
254
+ declare const CLOAK_PROGRAM_ID: PublicKey;
1085
255
  /**
1086
- * Get view key from keys
256
+ * Constructor options for {@link CloakSDK}.
257
+ *
258
+ * Contains *all* the settings a caller can supply at construction time —
259
+ * including the secret-bearing fields (`keypairBytes`, `wallet`, `cloakKeys`).
260
+ * Those secrets are consumed into private SDK state and are NOT persisted on
261
+ * the snapshot returned by {@link CloakSDK.getConfig}; see
262
+ * {@link CloakConfig} for the (narrower) snapshot shape.
1087
263
  */
1088
- declare function getViewKey(keys: CloakKeyPair): ViewKey;
264
+ interface CloakSDKOptions {
265
+ /** Keypair bytes for signing (Node.js mode). Consumed into a `Keypair`; not retained. */
266
+ keypairBytes?: Uint8Array;
267
+ /** Wallet adapter for signing (browser mode). */
268
+ wallet?: WalletAdapter;
269
+ /** Network the SDK targets. Defaults to `"mainnet"`. */
270
+ network?: Network;
271
+ /** Cloak key pair for note scanning / encryption. */
272
+ cloakKeys?: CloakKeyPair;
273
+ /** Storage adapter for wallet keys (defaults to in-memory). */
274
+ storage?: StorageAdapter;
275
+ /** Program ID override (defaults to the mainnet shield-pool). */
276
+ programId?: PublicKey;
277
+ /** Relay URL override (defaults to `https://api.cloak.ag`). */
278
+ relayUrl?: string;
279
+ /** Enable structured debug logging. Also via env `CLOAK_DEBUG=1` / `DEBUG=cloak:*`. */
280
+ debug?: boolean;
281
+ }
1089
282
  /**
1090
- * Get recipient amount after fees
283
+ * Lightweight Cloak client.
284
+ *
285
+ * Holds program/relay/storage configuration and exposes a small set of
286
+ * read-only chain helpers. **All transaction-emitting methods (deposit,
287
+ * privateTransfer, withdraw, send, swap) were removed in 0.1.6** — they
288
+ * shipped a legacy `[discriminator: 1, amount: u64, commitment: 32]` deposit
289
+ * instruction (`createDepositInstruction`) that the on-chain program no
290
+ * longer understands. Tag `1` is now `TransactSwap`, not `Deposit`, so every
291
+ * call hit `0x1063 MissingAccounts`. The OLD note model
292
+ * (3-input `Poseidon(amount, r0, r1, pk_spend)` for `withdraw_regular.circom`)
293
+ * is also incompatible with the deployed `transaction.circom` UTXO circuit.
294
+ *
295
+ * The supported flow is the functional UTXO API:
296
+ *
297
+ * ```ts
298
+ * import {
299
+ * transact,
300
+ * createUtxo,
301
+ * createZeroUtxo,
302
+ * generateUtxoKeypair,
303
+ * CLOAK_PROGRAM_ID,
304
+ * NATIVE_SOL_MINT,
305
+ * } from "@cloak.dev/sdk";
306
+ *
307
+ * const outputKeypair = await generateUtxoKeypair();
308
+ * const outputUtxo = await createUtxo(amountLamports, outputKeypair);
309
+ * const result = await transact(
310
+ * {
311
+ * inputUtxos: [await createZeroUtxo(), await createZeroUtxo()],
312
+ * outputUtxos: [outputUtxo, await createZeroUtxo()],
313
+ * externalAmount: amountLamports, // positive = deposit
314
+ * depositor: payer.publicKey,
315
+ * },
316
+ * {
317
+ * connection,
318
+ * programId: CLOAK_PROGRAM_ID,
319
+ * relayUrl: "https://api.cloak.ag",
320
+ * depositorKeypair: payer,
321
+ * },
322
+ * );
323
+ * ```
324
+ *
325
+ * See `transfer`, `partialWithdraw`, `fullWithdraw`, `swapUtxo` for the
326
+ * non-deposit flows.
1091
327
  */
1092
- declare function getRecipientAmount(amountLamports: number): number;
328
+ declare class CloakSDK {
329
+ private config;
330
+ private keypair?;
331
+ private wallet?;
332
+ private cloakKeys?;
333
+ private relay;
334
+ private storage;
335
+ constructor(config: CloakSDKOptions);
336
+ /** Public key of the configured signer (keypair or wallet). */
337
+ getPublicKey(): PublicKey;
338
+ /** True when the SDK was constructed with a wallet adapter (browser). */
339
+ isWalletMode(): boolean;
340
+ /**
341
+ * Compute a Merkle proof for `leafIndex` from on-chain state. No relay /
342
+ * indexer round-trip required.
343
+ */
344
+ getMerkleProof(connection: Connection, leafIndex: number): Promise<MerkleProof>;
345
+ /** Read the current SOL-pool Merkle root from on-chain state. */
346
+ getCurrentRoot(connection: Connection): Promise<string>;
347
+ /** Poll relay for the status of a previously-submitted request. */
348
+ getTransactionStatus(requestId: string): Promise<TxStatus>;
349
+ /** Import wallet keys from JSON; persists to the configured storage adapter. */
350
+ importWalletKeys(keysJson: string): Promise<void>;
351
+ /**
352
+ * Export wallet keys to JSON.
353
+ *
354
+ * WARNING: this exports secret keys. Store securely.
355
+ */
356
+ exportWalletKeys(): string;
357
+ /**
358
+ * Snapshot of the active SDK configuration.
359
+ *
360
+ * The return type ({@link CloakConfig}) is structurally narrower than the
361
+ * constructor input ({@link CloakSDKOptions}): `keypairBytes`, `wallet`,
362
+ * and `storage` are intentionally absent from the snapshot. The secrets
363
+ * are consumed into private SDK state at construction time and are not
364
+ * re-exposable through this method — the type system enforces it. To
365
+ * sign, pass a `Keypair` / `WalletAdapter` directly to the standalone
366
+ * `transact` / `partialWithdraw` / `fullWithdraw` / `swapUtxo` helpers.
367
+ */
368
+ getConfig(): CloakConfig;
369
+ }
370
+
371
+ type ComplianceTxType = "deposit" | "withdraw" | "send" | "swap";
372
+ interface TransactionMetadata {
373
+ amount: number;
374
+ recipient: string;
375
+ timestamp: number;
376
+ txType: ComplianceTxType;
377
+ commitment: string;
378
+ signature?: string;
379
+ outputMint?: string;
380
+ }
381
+ interface EncryptedMetadataBundle {
382
+ encrypted_user: string;
383
+ encrypted_compliance: string;
384
+ user_pubkey: string;
385
+ commitment: string;
386
+ timestamp: number;
387
+ tx_type?: ComplianceTxType;
388
+ wallet_signature?: string;
389
+ viewing_key?: string;
390
+ }
1093
391
 
1094
392
  interface ViewingKeyPair {
1095
393
  privateKey: Uint8Array;
@@ -1229,151 +527,20 @@ declare function pubkeyToLimbs(pubkey: Uint8Array | PublicKey | {
1229
527
  toBytes: () => Uint8Array;
1230
528
  }): [bigint, bigint];
1231
529
  /**
1232
- * Compute Merkle root from leaf and path
1233
- *
1234
- * This matches the test implementation
1235
- *
1236
- * @param leaf - Leaf value as bigint
1237
- * @param pathElements - Sibling hashes along the path
1238
- * @param pathIndices - Path directions (0 = left, 1 = right)
1239
- * @returns Merkle root as bigint
1240
- */
1241
- declare function computeMerkleRoot(leaf: bigint, pathElements: bigint[], pathIndices: number[]): Promise<bigint>;
1242
- /**
1243
- * Convert hex string to bigint
1244
- */
1245
- declare function hexToBigint$1(hex: string): bigint;
1246
- /**
1247
- * Compute commitment = Poseidon(amount, r0, r1, pk_spend)
1248
- * where pk_spend = Poseidon(sk0, sk1)
1249
- * (matching withdraw_regular.circom)
1250
- *
1251
- * This is the test-style function that takes bigints directly
1252
- *
1253
- * @param amount - Amount as bigint
1254
- * @param r - Randomness as bigint
1255
- * @param sk_spend - Spending secret key as bigint
1256
- * @returns Commitment hash as bigint
1257
- */
1258
- declare function computeCommitment$1(amount: bigint, r: bigint, sk_spend: bigint): Promise<bigint>;
1259
- /**
1260
- * Generate a Poseidon commitment for a note
1261
- *
1262
- * Formula: Poseidon(amount, r0, r1, pk_spend)
1263
- * where pk_spend = Poseidon(sk0, sk1)
1264
- *
1265
- * This matches the withdraw_regular.circom circuit
1266
- *
1267
- * @param amountLamports - Amount in lamports
1268
- * @param r - Randomness bytes (32 bytes)
1269
- * @param skSpend - Spending secret key bytes (32 bytes)
1270
- * @returns Commitment hash as bigint
1271
- */
1272
- declare function generateCommitmentAsync(amountLamports: number, r: Uint8Array, skSpend: Uint8Array): Promise<bigint>;
1273
- /**
1274
- * Generate a Poseidon commitment for a note (sync wrapper)
1275
- * Returns bytes instead of bigint for backward compatibility
1276
- *
1277
- * @deprecated Use generateCommitmentAsync instead
1278
- */
1279
- declare function generateCommitment(_amountLamports: number, _r: Uint8Array, _skSpend: Uint8Array): Uint8Array;
1280
- /**
1281
- * Compute nullifier = Poseidon(sk0, sk1, leaf_index)
1282
- * (matching withdraw_regular.circom)
1283
- *
1284
- * This is the test-style function that takes bigint directly
1285
- *
1286
- * @param sk_spend - Spending secret key as bigint
1287
- * @param leafIndex - Index in the Merkle tree as bigint
1288
- * @returns Nullifier as bigint
1289
- */
1290
- declare function computeNullifier$1(sk_spend: bigint, leafIndex: bigint): Promise<bigint>;
1291
- /**
1292
- * Compute nullifier from spending key and leaf index
1293
- *
1294
- * Formula: Poseidon(sk0, sk1, leaf_index)
1295
- *
1296
- * This matches the circuit's nullifier computation
1297
- *
1298
- * @param skSpend - Spending secret key bytes (32 bytes) or hex string
1299
- * @param leafIndex - Index in the Merkle tree
1300
- * @returns Nullifier as bigint
1301
- */
1302
- declare function computeNullifierAsync(skSpend: Uint8Array | string, leafIndex: number): Promise<bigint>;
1303
- /**
1304
- * Compute nullifier (sync wrapper for backward compatibility)
1305
- * @deprecated Use computeNullifierAsync instead
1306
- */
1307
- declare function computeNullifierSync(_skSpend: Uint8Array, _leafIndex: number): Uint8Array;
1308
- /**
1309
- * Compute outputs hash from recipients and amounts
1310
- *
1311
- * Formula: Chain of Poseidon(prev_hash, addr_lo, addr_hi, amount) for each active output
1312
- *
1313
- * This matches the withdraw_regular.circom circuit's outputs hash computation
1314
- *
1315
- * @param outputs - Array of {recipient: PublicKey, amount: number}
1316
- * @returns Outputs hash as bigint
1317
- */
1318
- declare function computeOutputsHashAsync(outputs: Array<{
1319
- recipient: PublicKey;
1320
- amount: number;
1321
- }>): Promise<bigint>;
1322
- /**
1323
- * Compute outputs hash for withdraw_regular circuit
1324
- * outputs_hash = chain of Poseidon(prev_hash, addr_lo, addr_hi, amount) for each active output
1325
- *
1326
- * This is the test-style function that takes raw limbs
1327
- *
1328
- * @param outAddr - Array of [lo, hi] limb pairs for each address (5x2 array)
1329
- * @param outAmount - Array of amounts as bigints (5 elements)
1330
- * @param outFlags - Array of flags (1 = active, 0 = inactive) (5 elements)
1331
- * @returns Outputs hash as bigint
1332
- */
1333
- declare function computeOutputsHash(outAddr: bigint[][], outAmount: bigint[], outFlags: number[]): Promise<bigint>;
1334
- /**
1335
- * Compute outputs hash (sync wrapper for backward compatibility)
1336
- * @deprecated Use computeOutputsHashAsync instead
1337
- */
1338
- declare function computeOutputsHashSync(_outputs: Array<{
1339
- recipient: PublicKey;
1340
- amount: number;
1341
- }>): Uint8Array;
1342
- /**
1343
- * Compute outputs hash for withdraw_swap circuit
1344
- * outputs_hash = Poseidon(input_mint limbs, output_mint limbs, recipient_ata limbs, min_output_amount, public_amount)
1345
- *
1346
- * This is the test-style function that takes raw limbs
1347
- *
1348
- * @param inputMintLimbs - Input mint address as [lo, hi] limbs
1349
- * @param outputMintLimbs - Output mint address as [lo, hi] limbs
1350
- * @param recipientAtaLimbs - Recipient ATA as [lo, hi] limbs
1351
- * @param minOutputAmount - Minimum output amount as bigint
1352
- * @param publicAmount - Public amount as bigint
1353
- * @returns Outputs hash as bigint
1354
- */
1355
- declare function computeSwapOutputsHash(inputMintLimbs: [bigint, bigint], outputMintLimbs: [bigint, bigint], recipientAtaLimbs: [bigint, bigint], minOutputAmount: bigint, publicAmount: bigint): Promise<bigint>;
1356
- /**
1357
- * Compute outputs hash for swap transactions
1358
- *
1359
- * Formula: Poseidon(input_mint_lo, input_mint_hi, output_mint_lo, output_mint_hi,
1360
- * recipient_ata_lo, recipient_ata_hi, min_output_amount, public_amount)
530
+ * Compute Merkle root from leaf and path
1361
531
  *
1362
- * This matches the withdraw_swap.circom circuit
532
+ * This matches the test implementation
1363
533
  *
1364
- * @param inputMint - Input token mint address (SOL = SystemProgram)
1365
- * @param outputMint - Output token mint address
1366
- * @param recipientAta - Recipient's associated token account
1367
- * @param minOutputAmount - Minimum output amount in token's smallest unit
1368
- * @param amount - Note amount in lamports (public_amount)
1369
- * @returns Outputs hash as bigint
534
+ * @param leaf - Leaf value as bigint
535
+ * @param pathElements - Sibling hashes along the path
536
+ * @param pathIndices - Path directions (0 = left, 1 = right)
537
+ * @returns Merkle root as bigint
1370
538
  */
1371
- declare function computeSwapOutputsHashAsync(inputMint: PublicKey, outputMint: PublicKey, recipientAta: PublicKey, minOutputAmount: number, amount: number): Promise<bigint>;
539
+ declare function computeMerkleRoot(leaf: bigint, pathElements: bigint[], pathIndices: number[]): Promise<bigint>;
1372
540
  /**
1373
- * Compute swap outputs hash (sync wrapper for backward compatibility)
1374
- * @deprecated Use computeSwapOutputsHashAsync instead
541
+ * Convert hex string to bigint
1375
542
  */
1376
- declare function computeSwapOutputsHashSync(_outputMint: PublicKey, _recipientAta: PublicKey, _minOutputAmount: number, _amount: number): Uint8Array;
543
+ declare function hexToBigint$1(hex: string): bigint;
1377
544
  /**
1378
545
  * Convert bigint to 32-byte big-endian Uint8Array
1379
546
  */
@@ -1436,37 +603,125 @@ declare function proofToBytes(proof: Groth16Proof): Uint8Array;
1436
603
  declare function buildPublicInputsBytes(root: bigint, nullifier: bigint, outputsHash: bigint, publicAmount: bigint): Uint8Array;
1437
604
 
1438
605
  /**
1439
- * Validate a Solana public key
606
+ * Fee calculation utilities for Cloak Protocol
1440
607
  *
1441
- * @param address - Address string to validate
1442
- * @returns True if valid Solana address
608
+ * The protocol charges a fixed fee plus a variable percentage fee
609
+ * to prevent sybil attacks and cover operational costs.
610
+ *
611
+ * IMPORTANT: These constants are the single source of truth for fee calculations.
612
+ * When updating fees, only change these values - all other code should import from here.
1443
613
  */
1444
- declare function isValidSolanaAddress(address: string): boolean;
614
+ /** Lamports per SOL */
615
+ declare const LAMPORTS_PER_SOL = 1000000000;
616
+ /** Fixed fee: 0.005 SOL (5M lamports) */
617
+ declare const FIXED_FEE_LAMPORTS = 5000000;
618
+ /** Variable fee numerator (3 = 0.3%) */
619
+ declare const VARIABLE_FEE_NUMERATOR = 3;
620
+ /** Variable fee denominator (1000 = divide by 1000) */
621
+ declare const VARIABLE_FEE_DENOMINATOR = 1000;
622
+ /** Variable fee rate as decimal: 0.3% = 0.003 */
623
+ declare const VARIABLE_FEE_RATE: number;
624
+ /** Minimum deposit amount to prevent dust/UX footguns (0.01 SOL). */
625
+ declare const MIN_DEPOSIT_LAMPORTS = 10000000;
626
+ /**
627
+ * Calculate the total protocol fee for a given amount
628
+ *
629
+ * Formula: FIXED_FEE + floor((amount * VARIABLE_FEE_NUMERATOR) / VARIABLE_FEE_DENOMINATOR)
630
+ *
631
+ * @param amountLamports - Amount in lamports
632
+ * @returns Total fee in lamports
633
+ *
634
+ * @example
635
+ * ```typescript
636
+ * const fee = calculateFee(1_000_000_000); // 1 SOL
637
+ * // Returns: 5_000_000 (fixed) + 3_000_000 (0.3%) = 8_000_000 lamports
638
+ * ```
639
+ */
640
+ declare function calculateFee(amountLamports: number): number;
641
+ /**
642
+ * Bigint version of calculateFee (for UTXO flows that use bigint lamports).
643
+ */
644
+ declare function calculateFeeBigint(amountLamports: bigint): bigint;
645
+ /**
646
+ * Returns true if a withdrawal amount can pay fees and still leave >0 lamports.
647
+ * (On-chain uses the same integer math and enforces this as well.)
648
+ */
649
+ declare function isWithdrawAmountSufficient(amountLamports: bigint): boolean;
650
+ /**
651
+ * Calculate the distributable amount after protocol fees
652
+ *
653
+ * This is the amount available to send to recipients.
654
+ *
655
+ * @param amountLamports - Total note amount in lamports
656
+ * @returns Amount available for recipients in lamports
657
+ *
658
+ * @example
659
+ * ```typescript
660
+ * const distributable = getDistributableAmount(1_000_000_000);
661
+ * // Returns: 1_000_000_000 - 7_500_000 = 992_500_000 lamports
662
+ * ```
663
+ */
664
+ declare function getDistributableAmount(amountLamports: number): number;
1445
665
  /**
1446
- * Validate a Cloak note structure
666
+ * Format lamports as SOL string
667
+ *
668
+ * @param lamports - Amount in lamports
669
+ * @param decimals - Number of decimal places (default: 9)
670
+ * @returns Formatted string (e.g., "1.000000000")
1447
671
  *
1448
- * @param note - Note object to validate
1449
- * @throws Error if invalid
672
+ * @example
673
+ * ```typescript
674
+ * formatAmount(1_000_000_000); // "1.000000000"
675
+ * formatAmount(1_500_000_000); // "1.500000000"
676
+ * formatAmount(123_456_789, 4); // "0.1235"
677
+ * ```
1450
678
  */
1451
- declare function validateNote(note: any): asserts note is CloakNote;
679
+ declare function formatAmount(lamports: number, decimals?: number): string;
1452
680
  /**
1453
- * Validate that a note is ready for withdrawal
681
+ * Parse SOL string to lamports
682
+ *
683
+ * @param sol - SOL amount as string (e.g., "1.5")
684
+ * @returns Amount in lamports
685
+ * @throws Error if invalid format
1454
686
  *
1455
- * @param note - Note to validate
1456
- * @throws Error if note cannot be used for withdrawal
687
+ * @example
688
+ * ```typescript
689
+ * parseAmount("1.5"); // 1_500_000_000
690
+ * parseAmount("0.001"); // 1_000_000
691
+ * ```
1457
692
  */
1458
- declare function validateWithdrawableNote(note: CloakNote): void;
693
+ declare function parseAmount(sol: string): number;
1459
694
  /**
1460
- * Validate transfer recipients
695
+ * Validate that outputs sum equals expected amount
1461
696
  *
1462
- * @param recipients - Array of transfers to validate
1463
- * @param totalAmount - Total amount available
1464
- * @throws Error if invalid
697
+ * @param outputs - Array of output amounts
698
+ * @param expectedTotal - Expected total amount
699
+ * @returns True if amounts match
1465
700
  */
1466
- declare function validateTransfers(recipients: Array<{
1467
- recipient: PublicKey;
701
+ declare function validateOutputsSum(outputs: Array<{
1468
702
  amount: number;
1469
- }>, totalAmount: number): void;
703
+ }>, expectedTotal: number): boolean;
704
+ /**
705
+ * Calculate relay fee from basis points
706
+ *
707
+ * @param amountLamports - Amount in lamports
708
+ * @param feeBps - Fee in basis points (100 bps = 1%)
709
+ * @returns Relay fee in lamports
710
+ *
711
+ * @example
712
+ * ```typescript
713
+ * calculateRelayFee(1_000_000_000, 50); // 0.5% = 5_000_000 lamports
714
+ * ```
715
+ */
716
+ declare function calculateRelayFee(amountLamports: number, feeBps: number): number;
717
+
718
+ /**
719
+ * Validate that a string is a valid Solana public key.
720
+ *
721
+ * @param address - Address string to validate
722
+ * @returns True if valid Solana address
723
+ */
724
+ declare function isValidSolanaAddress(address: string): boolean;
1470
725
 
1471
726
  /**
1472
727
  * Network Utilities
@@ -2349,36 +1604,6 @@ declare function fetchRiskQuoteIx(connection: Connection, wallet: PublicKey, ran
2349
1604
  queue: PublicKey;
2350
1605
  }>;
2351
1606
 
2352
- /**
2353
- * Encrypted Output Helpers
2354
- *
2355
- * Functions for creating encrypted outputs that enable note scanning
2356
- */
2357
-
2358
- /**
2359
- * Prepare encrypted output for scanning by wallet owner
2360
- *
2361
- * @param note - Note to encrypt
2362
- * @param cloakKeys - Wallet's Cloak keys (for self-encryption)
2363
- * @returns Base64-encoded encrypted output
2364
- */
2365
- declare function prepareEncryptedOutput(note: CloakNote, cloakKeys: CloakKeyPair): string;
2366
- /**
2367
- * Prepare encrypted output for a specific recipient
2368
- *
2369
- * @param note - Note to encrypt
2370
- * @param recipientPvkHex - Recipient's public view key (hex)
2371
- * @returns Base64-encoded encrypted output
2372
- */
2373
- declare function prepareEncryptedOutputForRecipient(note: CloakNote, recipientPvkHex: string): string;
2374
- /**
2375
- * Simple base64 encoding for v1.0 notes (no encryption)
2376
- *
2377
- * @param note - Note to encode
2378
- * @returns Base64-encoded note data
2379
- */
2380
- declare function encodeNoteSimple(note: CloakNote): string;
2381
-
2382
1607
  /**
2383
1608
  * Wallet Integration Helpers
2384
1609
  *
@@ -2406,58 +1631,6 @@ declare function signTransaction<T extends Transaction>(transaction: T, wallet:
2406
1631
  */
2407
1632
  declare function keypairToAdapter(keypair: Keypair): WalletAdapter;
2408
1633
 
2409
- /**
2410
- * Create a deposit instruction
2411
- *
2412
- * Deposits SOL into the Cloak protocol by creating a commitment.
2413
- *
2414
- * Instruction format:
2415
- * - Byte 0: Discriminant (0x01 for Deposit, per ShieldPoolInstruction enum)
2416
- * - Bytes 1-8: Amount (u64, little-endian)
2417
- * - Bytes 9-40: Commitment (32 bytes)
2418
- *
2419
- * @param params - Deposit parameters
2420
- * @returns Transaction instruction
2421
- *
2422
- * @example
2423
- * ```typescript
2424
- * const instruction = createDepositInstruction({
2425
- * programId: CLOAK_PROGRAM_ID,
2426
- * payer: wallet.publicKey,
2427
- * pool: POOL_ADDRESS,
2428
- * commitments: COMMITMENTS_ADDRESS,
2429
- * amount: 1_000_000_000, // 1 SOL
2430
- * commitment: commitmentBytes
2431
- * });
2432
- * ```
2433
- */
2434
- declare function createDepositInstruction(params: {
2435
- programId: PublicKey;
2436
- payer: PublicKey;
2437
- pool: PublicKey;
2438
- merkleTree: PublicKey;
2439
- amount: number;
2440
- commitment: Uint8Array;
2441
- }): TransactionInstruction;
2442
- /**
2443
- * Deposit instruction parameters for type safety
2444
- */
2445
- interface DepositInstructionParams {
2446
- programId: PublicKey;
2447
- payer: PublicKey;
2448
- pool: PublicKey;
2449
- merkleTree: PublicKey;
2450
- amount: number;
2451
- commitment: Uint8Array;
2452
- }
2453
- /**
2454
- * Validate deposit instruction parameters
2455
- *
2456
- * @param params - Parameters to validate
2457
- * @throws Error if invalid
2458
- */
2459
- declare function validateDepositParams(params: DepositInstructionParams): void;
2460
-
2461
1634
  /**
2462
1635
  * Program Derived Address (PDA) utilities for Shield Pool
2463
1636
  *
@@ -2678,263 +1851,6 @@ declare function preflightCheck(relayUrl: string, rootHex: string): Promise<{
2678
1851
  estimatedWaitMs?: number;
2679
1852
  }>;
2680
1853
 
2681
- /**
2682
- * Direct Circom WASM Proof Generation
2683
- *
2684
- * This module provides direct proof generation using snarkjs and Circom WASM,
2685
- * matching the approach used in services-new/tests/src/proof.ts
2686
- *
2687
- * This uses pinned S3-hosted circuit artifacts and does not require
2688
- * a backend prover service.
2689
- */
2690
-
2691
- /**
2692
- * Default URL for fetching circuit artifacts
2693
- * Hosted in S3 and versioned by build.
2694
- */
2695
- declare const DEFAULT_CIRCUITS_URL = "https://cloak-circuits.s3.us-east-1.amazonaws.com/circuits/0.1.0";
2696
- interface WithdrawRegularInputs {
2697
- root: bigint;
2698
- nullifier: bigint;
2699
- outputs_hash: bigint;
2700
- public_amount: bigint;
2701
- amount: bigint;
2702
- leaf_index: bigint;
2703
- sk: [bigint, bigint];
2704
- r: [bigint, bigint];
2705
- pathElements: bigint[];
2706
- pathIndices: number[];
2707
- num_outputs: number;
2708
- out_addr: bigint[][];
2709
- out_amount: bigint[];
2710
- out_flags: number[];
2711
- var_fee: bigint;
2712
- rem: bigint;
2713
- }
2714
- interface WithdrawSwapInputs {
2715
- sk_spend: bigint;
2716
- r: bigint;
2717
- amount: bigint;
2718
- leaf_index: bigint;
2719
- path_elements: bigint[];
2720
- path_indices: number[];
2721
- root: bigint;
2722
- nullifier: bigint;
2723
- outputs_hash: bigint;
2724
- public_amount: bigint;
2725
- input_mint: bigint[];
2726
- output_mint: bigint[];
2727
- recipient_ata: bigint[];
2728
- min_output_amount: bigint;
2729
- var_fee: bigint;
2730
- rem: bigint;
2731
- }
2732
- interface ProofResult {
2733
- proof: Groth16Proof;
2734
- publicSignals: string[];
2735
- proofBytes: Uint8Array;
2736
- publicInputsBytes: Uint8Array;
2737
- }
2738
- /**
2739
- * Generate Groth16 proof for regular withdrawal using Circom WASM
2740
- *
2741
- * This matches the approach in services-new/tests/src/proof.ts
2742
- *
2743
- * @param inputs - Circuit inputs
2744
- * @param circuitsPath - Ignored. Proof generation always uses pinned S3 circuits.
2745
- */
2746
- declare function generateWithdrawRegularProof(inputs: WithdrawRegularInputs, circuitsPath: string): Promise<ProofResult>;
2747
- /**
2748
- * Generate Groth16 proof for swap withdrawal using Circom WASM
2749
- *
2750
- * This matches the approach in services-new/tests/src/proof.ts
2751
- *
2752
- * @param inputs - Circuit inputs
2753
- * @param circuitsPath - Ignored. Proof generation always uses pinned S3 circuits.
2754
- */
2755
- declare function generateWithdrawSwapProof(inputs: WithdrawSwapInputs, circuitsPath: string): Promise<ProofResult>;
2756
- /**
2757
- * Check if circuits are available from the pinned S3 source.
2758
- */
2759
- declare function areCircuitsAvailable(circuitsPath: string): Promise<boolean>;
2760
- /**
2761
- * Get default circuits URL.
2762
- */
2763
- declare function getDefaultCircuitsPath(): Promise<string>;
2764
- /**
2765
- * Pinned circuit artifact hashes (SHA-256).
2766
- *
2767
- * These hashes must be updated whenever the trusted circuit artifacts change.
2768
- */
2769
- declare const EXPECTED_CIRCUIT_HASHES: {
2770
- withdraw_regular_wasm: string;
2771
- withdraw_regular_zkey: string;
2772
- withdraw_swap_wasm: string;
2773
- withdraw_swap_zkey: string;
2774
- };
2775
- /**
2776
- * Circuit verification result
2777
- */
2778
- interface CircuitVerificationResult {
2779
- /** Whether verification passed */
2780
- valid: boolean;
2781
- /** Which circuit was checked */
2782
- circuit: 'withdraw_regular' | 'withdraw_swap';
2783
- /** Error message if verification failed */
2784
- error?: string;
2785
- computed?: {
2786
- wasm: string;
2787
- zkey: string;
2788
- };
2789
- expected?: {
2790
- wasm: string;
2791
- zkey: string;
2792
- };
2793
- }
2794
- /**
2795
- * Verify circuit integrity by checking verification key hashes
2796
- *
2797
- * This function fetches the verification key and computes its hash,
2798
- * then compares against the expected hash embedded in the SDK.
2799
- *
2800
- * IMPORTANT: If the hashes don't match, the circuit may produce proofs
2801
- * that will be rejected by the on-chain verifier!
2802
- *
2803
- * @param circuitsPath - Ignored. Verification always uses pinned S3 circuits.
2804
- * @param circuit - Which circuit to verify ('withdraw_regular' or 'withdraw_swap')
2805
- * @returns Verification result
2806
- *
2807
- * @example
2808
- * ```typescript
2809
- * const result = await verifyCircuitIntegrity('https://cloak-circuits.s3.us-east-1.amazonaws.com/circuits/0.1.0', 'withdraw_regular');
2810
- * if (!result.valid) {
2811
- * console.error('Circuit verification failed:', result.error);
2812
- * // Don't proceed with proof generation!
2813
- * }
2814
- * ```
2815
- */
2816
- declare function verifyCircuitIntegrity(circuitsPath: string, circuit: 'withdraw_regular' | 'withdraw_swap'): Promise<CircuitVerificationResult>;
2817
- /**
2818
- * Verify all circuits before use
2819
- *
2820
- * Call this at SDK initialization to ensure circuits are valid.
2821
- *
2822
- * @param circuitsPath - Ignored. Verification always uses pinned S3 circuits.
2823
- * @returns Array of verification results (one per circuit)
2824
- */
2825
- declare function verifyAllCircuits(circuitsPath: string): Promise<CircuitVerificationResult[]>;
2826
-
2827
- /**
2828
- * Pending Operations Manager
2829
- *
2830
- * Utility for persisting pending deposit/withdrawal operations in browser storage.
2831
- * This enables recovery if the browser crashes or user navigates away mid-operation.
2832
- *
2833
- * IMPORTANT: This uses localStorage by default which has security implications.
2834
- * Notes contain sensitive spending keys - consider using more secure storage
2835
- * in production (e.g., encrypted IndexedDB, secure enclave).
2836
- */
2837
-
2838
- /**
2839
- * Pending deposit record
2840
- */
2841
- interface PendingDeposit {
2842
- /** The note (contains spending secrets!) */
2843
- note: CloakNote;
2844
- /** When the deposit was initiated */
2845
- startedAt: number;
2846
- /** Transaction signature if available */
2847
- txSignature?: string;
2848
- /** Status of the deposit */
2849
- status: "pending" | "tx_sent" | "confirmed" | "failed";
2850
- /** Error message if failed */
2851
- error?: string;
2852
- }
2853
- /**
2854
- * Pending withdrawal record
2855
- */
2856
- interface PendingWithdrawal {
2857
- /** The relay request ID (for resumption) */
2858
- requestId: string;
2859
- /** The note commitment being withdrawn */
2860
- commitment: string;
2861
- /** The nullifier being used */
2862
- nullifier: string;
2863
- /** When the withdrawal was initiated */
2864
- startedAt: number;
2865
- /** Status of the withdrawal */
2866
- status: "pending" | "processing" | "completed" | "failed";
2867
- /** Transaction signature if completed */
2868
- txSignature?: string;
2869
- /** Error message if failed */
2870
- error?: string;
2871
- }
2872
- /**
2873
- * Save a pending deposit
2874
- * Call this BEFORE sending the on-chain transaction to ensure note is persisted
2875
- */
2876
- declare function savePendingDeposit(deposit: PendingDeposit): void;
2877
- /**
2878
- * Load all pending deposits
2879
- */
2880
- declare function loadPendingDeposits(): PendingDeposit[];
2881
- /**
2882
- * Update a pending deposit status
2883
- */
2884
- declare function updatePendingDeposit(commitment: string, updates: Partial<PendingDeposit>): void;
2885
- /**
2886
- * Remove a pending deposit (e.g., after successful confirmation)
2887
- */
2888
- declare function removePendingDeposit(commitment: string): void;
2889
- /**
2890
- * Clear all pending deposits
2891
- */
2892
- declare function clearPendingDeposits(): void;
2893
- /**
2894
- * Save a pending withdrawal
2895
- * Call this when you receive the request_id from the relay
2896
- */
2897
- declare function savePendingWithdrawal(withdrawal: PendingWithdrawal): void;
2898
- /**
2899
- * Load all pending withdrawals
2900
- */
2901
- declare function loadPendingWithdrawals(): PendingWithdrawal[];
2902
- /**
2903
- * Update a pending withdrawal status
2904
- */
2905
- declare function updatePendingWithdrawal(requestId: string, updates: Partial<PendingWithdrawal>): void;
2906
- /**
2907
- * Remove a pending withdrawal (e.g., after successful completion)
2908
- */
2909
- declare function removePendingWithdrawal(requestId: string): void;
2910
- /**
2911
- * Clear all pending withdrawals
2912
- */
2913
- declare function clearPendingWithdrawals(): void;
2914
- /**
2915
- * Check if there are any pending operations that need recovery
2916
- * Call this on page load to determine if recovery UI should be shown
2917
- */
2918
- declare function hasPendingOperations(): boolean;
2919
- /**
2920
- * Get summary of pending operations for recovery UI
2921
- */
2922
- declare function getPendingOperationsSummary(): {
2923
- deposits: PendingDeposit[];
2924
- withdrawals: PendingWithdrawal[];
2925
- totalPending: number;
2926
- };
2927
- /**
2928
- * Clean up stale pending operations
2929
- * Call this periodically to remove old failed/completed operations
2930
- *
2931
- * @param maxAgeMs Maximum age in milliseconds before an operation is removed (default: 24 hours)
2932
- */
2933
- declare function cleanupStalePendingOperations(maxAgeMs?: number): {
2934
- removedDeposits: number;
2935
- removedWithdrawals: number;
2936
- };
2937
-
2938
1854
  /**
2939
1855
  * UTXO Transaction Methods
2940
1856
  *
@@ -2944,7 +1860,7 @@ declare function cleanupStalePendingOperations(maxAgeMs?: number): {
2944
1860
  * - partialWithdraw(): Withdraw with change
2945
1861
  */
2946
1862
 
2947
- declare const DEFAULT_TRANSACTION_CIRCUITS_URL = "https://cloak-circuits.s3.us-east-1.amazonaws.com/circuits/0.1.0";
1863
+ declare const DEFAULT_TRANSACTION_CIRCUITS_URL = "https://storage.googleapis.com/cloak-circuits/circuits/0.1.0";
2948
1864
  /**
2949
1865
  * Set circuits base path: local directory containing `transaction_js/` and `transaction_final.zkey`,
2950
1866
  * or an `http(s)` base URL to those artifacts (Node will download once per process to a temp dir).
@@ -3558,10 +2474,25 @@ declare class SimpleWallet {
3558
2474
  * Cloak SDK - TypeScript SDK for Private Transactions on Solana
3559
2475
  *
3560
2476
  * @packageDocumentation
2477
+ *
2478
+ * # 0.1.6 — breaking changes
2479
+ *
2480
+ * The legacy `CloakNote` API (`CloakSDK.deposit/privateTransfer/withdraw/
2481
+ * send/swap`, `createDepositInstruction`, `generateNote`, `withdraw_regular`
2482
+ * proofs, etc.) was removed because every code path eventually emitted a
2483
+ * legacy `[discriminator: 1, amount: u64, commitment: 32]` instruction that
2484
+ * the deployed shield-pool program no longer accepts (tag `1` is now
2485
+ * `TransactSwap`, not `Deposit`). The OLD 3-input commitment scheme is
2486
+ * also incompatible with the deployed `transaction.circom` UTXO circuit.
2487
+ *
2488
+ * Use the functional UTXO API instead — `transact`, `transfer`,
2489
+ * `partialWithdraw`, `fullWithdraw`, `swapUtxo`, `createUtxo`,
2490
+ * `createZeroUtxo`, `generateUtxoKeypair`. The `CloakSDK` class is kept as
2491
+ * a thin config + read-only chain helper.
3561
2492
  */
3562
2493
 
3563
- declare const VERSION = "0.1.5";
3564
- /** True when scanner supports TransactSwap (tag 1). Check this to verify the correct SDK bundle is loaded. */
2494
+ declare const VERSION = "0.1.6";
2495
+ /** True when scanner supports TransactSwap (tag 1). */
3565
2496
  declare const SCANNER_SUPPORTS_TRANSACT_SWAP = true;
3566
2497
 
3567
- export { CLOAK_PROGRAM_ID, type ChainNoteTxType, type CircuitVerificationResult, type CloakConfig, CloakError, type CloakKeyPair, type CloakNote, CloakSDK, type CommitmentEntry, type CommitmentsResponse, type CompactChainNote, type ComplianceReport, type ComplianceTxType, DEFAULT_CIRCUITS_URL, DEFAULT_TRANSACTION_CIRCUITS_URL, type DepositInstructionParams, type DepositOptions, type DepositResult, type DepositStatus, EXPECTED_CIRCUIT_HASHES, type EncryptedMetadataBundle, type EncryptedNote$1 as EncryptedNote, type ErrorCategory, type ExpandedSpendKey, FIXED_FEE_LAMPORTS, type Groth16Proof, LAMPORTS_PER_SOL, LocalStorageAdapter, type LogLevel, type Logger, MERKLE_TREE_HEIGHT, MIN_DEPOSIT_LAMPORTS, type MasterKey, type MaxLengthArray, MemoryStorageAdapter, type MerkleProof, type MerkleRootResponse, MerkleTree, NATIVE_SOL_MINT, type Network, type NoteData, type OnchainMerkleProof, type PendingDeposit, type PendingWithdrawal, type ProofResult, RelayInternalError, RelayService, type RiskQuoteInstructionResponse, RootNotFoundError, SCANNER_SUPPORTS_TRANSACT_SWAP, SIGN_IN_MESSAGE, SanctionsQuoteError, type ScanOptions, type ScanResult, type ScanSummary, type ScannedTransaction, ShieldPoolErrors, type ShieldPoolPDAs, SimpleWallet, type SpendKey, type StorageAdapter, type SwapOptions, type SwapParams, type SwapResult, type TransactOptions, type TransactParams, type TransactResult, type TransactionMetadata, type Transfer, type TransferOptions, type TransferResult, type TxStatus, type UserFriendlyError, type Utxo, UtxoAlreadySpentError, type EncryptedNote as UtxoEncryptedNote, type UtxoKeypair, type UtxoSwapParams, type UtxoSwapResult, UtxoWallet, VARIABLE_FEE_DENOMINATOR, VARIABLE_FEE_NUMERATOR, VARIABLE_FEE_RATE, VERSION, type VerifyUtxosResult, type ViewKey, type ViewingKeyPair, type WalletAdapter, type WalletUtxo, type WithdrawOptions, type WithdrawRegularInputs, type WithdrawSubmissionResult, type WithdrawSwapInputs, areCircuitsAvailable, bigintToBytes32$1 as bigintToBytes32, bigintToHex, buildMerkleTree, buildMerkleTreeFromChain, buildMerkleTreeFromRelay, buildPublicInputsBytes, bytesToHex, calculateFee, calculateFeeBigint, calculateRelayFee, chainNoteFromBase64, chainNoteToBase64, classifyRelayError, cleanupStalePendingOperations, clearPendingDeposits, clearPendingWithdrawals, computeChainNoteHash, computeCommitment$1 as computeCommitment, computeExtDataHash, computeMerkleRoot, computeNullifier$1 as computeNullifier, computeNullifierAsync, computeNullifierSync, computeOutputsHash, computeOutputsHashAsync, computeOutputsHashSync, computeProofForLatestDeposit, computeProofFromChain, computeSignature, computeSwapOutputsHash, computeSwapOutputsHashAsync, computeSwapOutputsHashSync, computeCommitment as computeUtxoCommitment, computeNullifier as computeUtxoNullifier, copyNoteToClipboard, createCloakError, createDepositInstruction, createLogger, createUtxo, createZeroUtxo, decryptCompactChainNote, decryptComplianceMetadataWithMasterKey, decryptTransactionMetadata, deriveDiversifiedViewingKey, deriveDiversifier, derivePublicKey, deriveSpendKey, deriveUserCompliancePublicKey, deriveUserComplianceScalar, deriveUtxoKeypairFromSpendKey, deriveViewKey, deriveViewingKeyFromNk, deriveViewingKeyFromSpendKey, deriveViewingKeyFromUtxoPrivateKey, deserializeUtxo, detectNetworkFromRpcUrl, downloadNote, encodeNoteSimple, encryptCompactChainNote, encryptNoteForRecipient, encryptTransactionMetadata, encryptTransactionMetadataBundle, expandSpendKey, exportKeys, exportNote, exportWalletKeys, fetchCommitments, fetchRiskQuoteInstruction, fetchRiskQuoteIx, filterNotesByNetwork, filterWithdrawableNotes, findNoteByCommitment, formatAmount, formatComplianceCsv, formatErrorForLogging, formatSol, fullWithdraw, generateCloakKeys, generateCommitment, generateCommitmentAsync, generateMasterSeed, generateNote, generateNoteFromWallet, generateUtxoKeypair, generateViewingKeyPair, generateWithdrawRegularProof, generateWithdrawSwapProof, getAddressExplorerUrl, getCircuitsPath, getDefaultCircuitsPath, getDistributableAmount, getExplorerUrl, getNkFromUtxoPrivateKey, getNullifierPDA, getPendingOperationsSummary, getPublicKey, getPublicViewKey, getRecipientAmount, getRpcUrlForNetwork, getShieldPoolPDAs, getSwapStatePDA, getViewKey, hasPendingOperations, hexToBigint$1 as hexToBigint, hexToBytes, importKeys, importWalletKeys, isDebugEnabled, isRootNotFoundError, isValidHex, isValidRpcUrl, isValidSolanaAddress, isWithdrawAmountSufficient, isWithdrawable, keypairToAdapter, loadPendingDeposits, loadPendingWithdrawals, parseAmount, parseError, parseNote, parseRelayErrorResponse, parseTransactionError, partialWithdraw, poseidonHash, preflightCheck, preflightNullifiers, prepareEncryptedOutput, prepareEncryptedOutputForRecipient, proofToBytes, pubkeyToFieldElement, pubkeyToLimbs, randomBytes, randomFieldElement, readMerkleTreeState, registerViewingKey, removePendingDeposit, removePendingWithdrawal, savePendingDeposit, savePendingWithdrawal, scanNotesForWallet, scanTransactions, sdkLogger, selectUtxos, sendTransaction, serializeNote, serializeUtxo, setCircuitsPath, setDebugMode, signTransaction, splitTo2Limbs, sumUtxoAmounts, swapUtxo, swapWithChange, toComplianceReport, transact, transfer, truncate, tryDecryptNote, updateNoteWithDeposit, updatePendingDeposit, updatePendingWithdrawal, bigintToBytes32 as utxoBigintToBytes32, utxoEquals, hexToBigint as utxoHexToBigint, validateDepositParams, validateNote, validateOutputsSum, validateRoot, validateTransfers, validateWalletConnected, validateWithdrawableNote, verifyAllCircuits, verifyCircuitIntegrity, verifyUtxos, waitForRoot, withTiming };
2498
+ export { CLOAK_PROGRAM_ID, type ChainNoteTxType, type CloakConfig, CloakError, type CloakKeyPair, CloakSDK, type CloakSDKOptions, type CommitmentEntry, type CommitmentsResponse, type CompactChainNote, type ComplianceReport, type ComplianceTxType, DEFAULT_TRANSACTION_CIRCUITS_URL, type EncryptedMetadataBundle, type EncryptedNote$1 as EncryptedNote, type ErrorCategory, type ExpandedSpendKey, FIXED_FEE_LAMPORTS, type Groth16Proof, LAMPORTS_PER_SOL, LocalStorageAdapter, type LogLevel, type Logger, MERKLE_TREE_HEIGHT, MIN_DEPOSIT_LAMPORTS, type MasterKey, MemoryStorageAdapter, type MerkleProof, type MerkleRootResponse, MerkleTree, NATIVE_SOL_MINT, type Network, type NoteData, type OnchainMerkleProof, RelayInternalError, RelayService, type RiskQuoteInstructionResponse, RootNotFoundError, SCANNER_SUPPORTS_TRANSACT_SWAP, SIGN_IN_MESSAGE, SanctionsQuoteError, type ScanOptions, type ScanResult, type ScanSummary, type ScannedTransaction, ShieldPoolErrors, type ShieldPoolPDAs, SimpleWallet, type SpendKey, type StorageAdapter, type TransactOptions, type TransactParams, type TransactResult, type TransactionMetadata, type TxStatus, type UserFriendlyError, type Utxo, UtxoAlreadySpentError, type EncryptedNote as UtxoEncryptedNote, type UtxoKeypair, type UtxoSwapParams, type UtxoSwapResult, UtxoWallet, VARIABLE_FEE_DENOMINATOR, VARIABLE_FEE_NUMERATOR, VARIABLE_FEE_RATE, VERSION, type VerifyUtxosResult, type ViewKey, type ViewingKeyPair, type WalletAdapter, type WalletUtxo, type WithdrawSubmissionResult, bigintToBytes32$1 as bigintToBytes32, bigintToHex, buildMerkleTree, buildMerkleTreeFromChain, buildMerkleTreeFromRelay, buildPublicInputsBytes, bytesToHex, calculateFee, calculateFeeBigint, calculateRelayFee, chainNoteFromBase64, chainNoteToBase64, classifyRelayError, computeChainNoteHash, computeExtDataHash, computeMerkleRoot, computeProofForLatestDeposit, computeProofFromChain, computeSignature, computeCommitment as computeUtxoCommitment, computeNullifier as computeUtxoNullifier, createCloakError, createLogger, createUtxo, createZeroUtxo, decryptCompactChainNote, decryptComplianceMetadataWithMasterKey, decryptTransactionMetadata, deriveDiversifiedViewingKey, deriveDiversifier, derivePublicKey, deriveSpendKey, deriveUserCompliancePublicKey, deriveUserComplianceScalar, deriveUtxoKeypairFromSpendKey, deriveViewKey, deriveViewingKeyFromNk, deriveViewingKeyFromSpendKey, deriveViewingKeyFromUtxoPrivateKey, deserializeUtxo, detectNetworkFromRpcUrl, encryptCompactChainNote, encryptNoteForRecipient, encryptTransactionMetadata, encryptTransactionMetadataBundle, expandSpendKey, exportKeys, fetchCommitments, fetchRiskQuoteInstruction, fetchRiskQuoteIx, formatAmount, formatComplianceCsv, formatErrorForLogging, formatSol, fullWithdraw, generateCloakKeys, generateMasterSeed, generateUtxoKeypair, generateViewingKeyPair, getAddressExplorerUrl, getCircuitsPath, getDistributableAmount, getExplorerUrl, getNkFromUtxoPrivateKey, getNullifierPDA, getPublicKey, getRpcUrlForNetwork, getShieldPoolPDAs, getSwapStatePDA, hexToBigint$1 as hexToBigint, hexToBytes, importKeys, isDebugEnabled, isRootNotFoundError, isValidHex, isValidRpcUrl, isValidSolanaAddress, isWithdrawAmountSufficient, keypairToAdapter, parseAmount, parseError, parseRelayErrorResponse, parseTransactionError, partialWithdraw, poseidonHash, preflightCheck, preflightNullifiers, proofToBytes, pubkeyToFieldElement, pubkeyToLimbs, randomBytes, randomFieldElement, readMerkleTreeState, registerViewingKey, scanNotesForWallet, scanTransactions, sdkLogger, selectUtxos, sendTransaction, serializeUtxo, setCircuitsPath, setDebugMode, signTransaction, splitTo2Limbs, sumUtxoAmounts, swapUtxo, swapWithChange, toComplianceReport, transact, transfer, truncate, tryDecryptNote, bigintToBytes32 as utxoBigintToBytes32, utxoEquals, hexToBigint as utxoHexToBigint, validateOutputsSum, validateRoot, validateWalletConnected, verifyUtxos, waitForRoot, withTiming };