@cloak.dev/sdk 0.1.4 → 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/CHANGELOG.md +173 -0
- package/README.md +183 -96
- package/dist/index.cjs +472 -2258
- package/dist/index.d.cts +1283 -2218
- package/dist/index.d.ts +1283 -2218
- package/dist/index.js +429 -2171
- package/package.json +2 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,375 +1,4 @@
|
|
|
1
|
-
import { PublicKey, Transaction, Connection, TransactionInstruction, Keypair, SendOptions,
|
|
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
|
-
}
|
|
1
|
+
import { PublicKey, Transaction, Connection, AddressLookupTableAccount, TransactionInstruction, Keypair, SendOptions, VersionedTransaction } from '@solana/web3.js';
|
|
373
2
|
|
|
374
3
|
/**
|
|
375
4
|
* Cloak Key Hierarchy (v2.0)
|
|
@@ -455,681 +84,350 @@ declare function exportKeys(keys: CloakKeyPair): string;
|
|
|
455
84
|
declare function importKeys(exported: string): CloakKeyPair;
|
|
456
85
|
|
|
457
86
|
/**
|
|
458
|
-
*
|
|
459
|
-
*
|
|
460
|
-
* Defines a pluggable storage interface for notes and keys.
|
|
461
|
-
* Applications can implement their own storage (localStorage, IndexedDB, file system, etc.)
|
|
87
|
+
* Supported Solana networks.
|
|
462
88
|
*/
|
|
463
|
-
|
|
89
|
+
type Network = "localnet" | "devnet" | "mainnet" | "testnet";
|
|
464
90
|
/**
|
|
465
|
-
*
|
|
466
|
-
*
|
|
467
|
-
* Implement this interface to provide custom storage for notes and keys.
|
|
468
|
-
* The SDK will use this adapter for all persistence operations.
|
|
91
|
+
* Minimal wallet adapter interface — compatible with `@solana/wallet-adapter-base`.
|
|
469
92
|
*/
|
|
470
|
-
interface
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
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;
|
|
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>;
|
|
503
98
|
}
|
|
504
99
|
/**
|
|
505
|
-
*
|
|
506
|
-
*
|
|
507
|
-
* Useful for testing or when storage is handled externally
|
|
100
|
+
* Cloak-specific error with categorization.
|
|
508
101
|
*/
|
|
509
|
-
declare class
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
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;
|
|
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);
|
|
520
107
|
}
|
|
521
108
|
/**
|
|
522
|
-
*
|
|
523
|
-
*
|
|
524
|
-
* Only use this if you're in a browser environment and want localStorage persistence.
|
|
525
|
-
* Import from a separate browser-specific module.
|
|
109
|
+
* Merkle proof for a leaf in the commitment tree.
|
|
526
110
|
*/
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
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;
|
|
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;
|
|
540
118
|
}
|
|
541
|
-
|
|
542
|
-
/** Default Cloak Program ID on Solana */
|
|
543
|
-
declare const CLOAK_PROGRAM_ID: PublicKey;
|
|
544
119
|
/**
|
|
545
|
-
*
|
|
120
|
+
* Snapshot of the active SDK configuration, returned by `CloakSDK.getConfig()`.
|
|
546
121
|
*
|
|
547
|
-
*
|
|
548
|
-
*
|
|
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`.
|
|
549
129
|
*
|
|
550
|
-
*
|
|
551
|
-
* 1. Node.js mode with keypairBytes - for scripts and backend services
|
|
552
|
-
* 2. Wallet adapter mode - for browser applications with wallet integration
|
|
130
|
+
* If you're configuring the SDK at construction, use `CloakSDKOptions`.
|
|
553
131
|
*/
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
/**
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
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>;
|
|
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;
|
|
674
145
|
/**
|
|
675
|
-
*
|
|
146
|
+
* Whether structured debug logging was enabled at construction.
|
|
676
147
|
*
|
|
677
|
-
*
|
|
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
|
-
* ```
|
|
148
|
+
* Can also be enabled via env: `CLOAK_DEBUG=1` or `DEBUG=cloak:*`.
|
|
698
149
|
*/
|
|
699
|
-
|
|
150
|
+
debug?: boolean;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Merkle root response from the relay/indexer.
|
|
154
|
+
*/
|
|
155
|
+
interface MerkleRootResponse {
|
|
156
|
+
root: string;
|
|
157
|
+
next_index: number;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Transaction status returned by the relay.
|
|
161
|
+
*/
|
|
162
|
+
interface TxStatus {
|
|
163
|
+
status: "pending" | "processing" | "completed" | "failed";
|
|
164
|
+
txId?: string;
|
|
165
|
+
error?: string;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
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.
|
|
176
|
+
*/
|
|
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
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* In-memory storage adapter (default; no persistence). Useful for tests or
|
|
188
|
+
* when storage is handled externally.
|
|
189
|
+
*/
|
|
190
|
+
declare class MemoryStorageAdapter implements StorageAdapter {
|
|
191
|
+
private keys;
|
|
192
|
+
saveKeys(keys: CloakKeyPair): void;
|
|
193
|
+
loadKeys(): CloakKeyPair | null;
|
|
194
|
+
deleteKeys(): void;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
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.
|
|
208
|
+
*/
|
|
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;
|
|
700
216
|
/**
|
|
701
|
-
*
|
|
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
|
-
* ```
|
|
217
|
+
* Sentinel key set after the auto-purge runs. Persists across browser
|
|
218
|
+
* sessions so the purge never re-runs on the same origin.
|
|
724
219
|
*/
|
|
725
|
-
|
|
220
|
+
static readonly LEGACY_PURGE_SENTINEL_KEY = "cloak_purged_v0_1_5";
|
|
726
221
|
/**
|
|
727
|
-
*
|
|
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
|
-
* ```
|
|
222
|
+
* Default localStorage key the legacy `<= 0.1.5` SDK used for the
|
|
223
|
+
* plaintext `CloakNote[]` blob.
|
|
759
224
|
*/
|
|
760
|
-
|
|
225
|
+
static readonly LEGACY_NOTES_KEY = "cloak_notes";
|
|
761
226
|
/**
|
|
762
|
-
*
|
|
763
|
-
*
|
|
764
|
-
*
|
|
765
|
-
*
|
|
766
|
-
* @returns New note (not yet deposited)
|
|
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.
|
|
767
231
|
*/
|
|
768
|
-
|
|
232
|
+
static runLegacyPurgeOnce(): void;
|
|
769
233
|
/**
|
|
770
|
-
*
|
|
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.
|
|
771
237
|
*
|
|
772
|
-
*
|
|
773
|
-
*
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
* Export a note to JSON string
|
|
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.
|
|
778
243
|
*
|
|
779
|
-
*
|
|
780
|
-
*
|
|
781
|
-
* @returns JSON string
|
|
782
|
-
*/
|
|
783
|
-
exportNote(note: CloakNote, pretty?: boolean): string;
|
|
784
|
-
/**
|
|
785
|
-
* Check if a note is ready for withdrawal
|
|
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.
|
|
786
246
|
*
|
|
787
|
-
* @param
|
|
788
|
-
*
|
|
247
|
+
* @param notesKey - localStorage key to remove (default `"cloak_notes"`,
|
|
248
|
+
* matching the pre-0.1.6 default).
|
|
789
249
|
*/
|
|
790
|
-
|
|
250
|
+
static purgeLegacyNoteStorage(notesKey?: string): void;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/** Default Cloak Program ID on Solana mainnet. */
|
|
254
|
+
declare const CLOAK_PROGRAM_ID: PublicKey;
|
|
255
|
+
/**
|
|
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.
|
|
263
|
+
*/
|
|
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
|
+
}
|
|
282
|
+
/**
|
|
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.
|
|
327
|
+
*/
|
|
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;
|
|
791
340
|
/**
|
|
792
|
-
*
|
|
793
|
-
*
|
|
794
|
-
* @param connection - Solana connection
|
|
795
|
-
* @param leafIndex - Leaf index in tree
|
|
796
|
-
* @returns Merkle proof computed from on-chain data
|
|
341
|
+
* Compute a Merkle proof for `leafIndex` from on-chain state. No relay /
|
|
342
|
+
* indexer round-trip required.
|
|
797
343
|
*/
|
|
798
344
|
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
|
-
*/
|
|
345
|
+
/** Read the current SOL-pool Merkle root from on-chain state. */
|
|
805
346
|
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
|
-
*/
|
|
347
|
+
/** Poll relay for the status of a previously-submitted request. */
|
|
812
348
|
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
|
-
*/
|
|
349
|
+
/** Import wallet keys from JSON; persists to the configured storage adapter. */
|
|
845
350
|
importWalletKeys(keysJson: string): Promise<void>;
|
|
846
351
|
/**
|
|
847
|
-
* Export wallet keys to JSON
|
|
848
|
-
*
|
|
849
|
-
* WARNING: This exports secret keys! Store securely.
|
|
352
|
+
* Export wallet keys to JSON.
|
|
850
353
|
*
|
|
851
|
-
*
|
|
354
|
+
* WARNING: this exports secret keys. Store securely.
|
|
852
355
|
*/
|
|
853
356
|
exportWalletKeys(): string;
|
|
854
357
|
/**
|
|
855
|
-
*
|
|
856
|
-
*/
|
|
857
|
-
getConfig(): CloakConfig;
|
|
858
|
-
/**
|
|
859
|
-
* Wrap errors with better categorization and user-friendly messages
|
|
358
|
+
* Snapshot of the active SDK configuration.
|
|
860
359
|
*
|
|
861
|
-
* @
|
|
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.
|
|
862
367
|
*/
|
|
863
|
-
|
|
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;
|
|
864
390
|
}
|
|
865
391
|
|
|
392
|
+
interface ViewingKeyPair {
|
|
393
|
+
privateKey: Uint8Array;
|
|
394
|
+
publicKey: Uint8Array;
|
|
395
|
+
}
|
|
396
|
+
/** Zcash-style expanded spend key: ask (auth), nsk (nullifier/nk), ovk (outgoing view) */
|
|
397
|
+
interface ExpandedSpendKey {
|
|
398
|
+
ask: Uint8Array;
|
|
399
|
+
nsk: Uint8Array;
|
|
400
|
+
ovk: Uint8Array;
|
|
401
|
+
}
|
|
866
402
|
/**
|
|
867
|
-
*
|
|
868
|
-
*
|
|
869
|
-
*
|
|
870
|
-
*
|
|
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
|
-
* ```
|
|
403
|
+
* Expand spend key into (ask, nsk, ovk) — Zcash-style.
|
|
404
|
+
* - ask: spend authorization (future)
|
|
405
|
+
* - nsk: base for incoming viewing (nk) — chain note decryption
|
|
406
|
+
* - ovk: outgoing viewing (future)
|
|
879
407
|
*/
|
|
880
|
-
declare function
|
|
408
|
+
declare function expandSpendKey(skSpend: Uint8Array): ExpandedSpendKey;
|
|
881
409
|
/**
|
|
882
|
-
*
|
|
410
|
+
* Derive chain note viewing key from nk (Zcash-style IVK component).
|
|
411
|
+
* Used for trial-decrypting incoming chain notes.
|
|
883
412
|
*
|
|
884
|
-
* @param
|
|
885
|
-
* @param filename - Optional custom filename
|
|
413
|
+
* @param nk 32-byte nk (from expandSpendKey(...).nsk — the incoming view base)
|
|
886
414
|
*/
|
|
887
|
-
declare function
|
|
415
|
+
declare function deriveViewingKeyFromNk(nk: Uint8Array): ViewingKeyPair;
|
|
888
416
|
/**
|
|
889
|
-
*
|
|
890
|
-
*
|
|
891
|
-
* @param note - Note to copy
|
|
892
|
-
* @returns Promise that resolves when copied
|
|
417
|
+
* Derive diversifier for per-output chain note encryption (Phase 3).
|
|
418
|
+
* d = BLAKE3("cloak_div_v1" || nk || commitmentHex || outputIndex)[0:11]
|
|
893
419
|
*/
|
|
894
|
-
declare function
|
|
895
|
-
|
|
420
|
+
declare function deriveDiversifier(nk: Uint8Array, commitmentHex: string, outputIndex: number): Uint8Array;
|
|
896
421
|
/**
|
|
897
|
-
*
|
|
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.
|
|
422
|
+
* Derive per-output viewing key pair from nk + diversifier (Phase 3).
|
|
423
|
+
* sk_d = BLAKE3("cloak_sk_d_v1" || nk || d) → clamp → X25519 keypair
|
|
904
424
|
*/
|
|
905
|
-
|
|
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;
|
|
425
|
+
declare function deriveDiversifiedViewingKey(nk: Uint8Array, diversifier: Uint8Array): ViewingKeyPair;
|
|
917
426
|
/**
|
|
918
|
-
*
|
|
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
|
-
* ```
|
|
427
|
+
* Derive chain note viewing key from spend key (Zcash-style).
|
|
428
|
+
* Expands to (ask, nsk, ovk) and uses nsk (nk) for chain note decryption.
|
|
930
429
|
*/
|
|
931
|
-
declare function
|
|
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
|
-
* ```
|
|
969
|
-
*/
|
|
970
|
-
declare function formatAmount(lamports: number, decimals?: number): string;
|
|
971
|
-
/**
|
|
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
|
-
* ```
|
|
983
|
-
*/
|
|
984
|
-
declare function parseAmount(sol: string): number;
|
|
985
|
-
/**
|
|
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
|
|
991
|
-
*/
|
|
992
|
-
declare function validateOutputsSum(outputs: Array<{
|
|
993
|
-
amount: number;
|
|
994
|
-
}>, expectedTotal: number): boolean;
|
|
995
|
-
/**
|
|
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
|
-
* ```
|
|
1006
|
-
*/
|
|
1007
|
-
declare function calculateRelayFee(amountLamports: number, feeBps: number): number;
|
|
1008
|
-
|
|
1009
|
-
/**
|
|
1010
|
-
* Note Manager
|
|
1011
|
-
*
|
|
1012
|
-
* Standalone note management - no browser dependencies.
|
|
1013
|
-
* Storage is handled externally via StorageAdapter.
|
|
1014
|
-
*
|
|
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)
|
|
1020
|
-
*/
|
|
1021
|
-
|
|
1022
|
-
/**
|
|
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
|
|
1026
|
-
*/
|
|
1027
|
-
declare function generateNote(amountLamports: number, network?: Network): Promise<CloakNote>;
|
|
1028
|
-
/**
|
|
1029
|
-
* Generate a note using wallet's spend key (v2.0 recommended)
|
|
1030
|
-
* Uses Poseidon hashing to match circuit implementation
|
|
1031
|
-
*/
|
|
1032
|
-
declare function generateNoteFromWallet(amountLamports: number, keys: CloakKeyPair, network?: Network): Promise<CloakNote>;
|
|
1033
|
-
/**
|
|
1034
|
-
* Parse and validate a note from JSON string
|
|
1035
|
-
*/
|
|
1036
|
-
declare function parseNote(jsonString: string): CloakNote;
|
|
1037
|
-
/**
|
|
1038
|
-
* Export note to JSON string
|
|
1039
|
-
*/
|
|
1040
|
-
declare function exportNote(note: CloakNote, pretty?: boolean): string;
|
|
1041
|
-
/**
|
|
1042
|
-
* Check if a note is withdrawable (has been deposited)
|
|
1043
|
-
* Note: merkleProof is optional - it may be fetched lazily at withdrawal time
|
|
1044
|
-
*/
|
|
1045
|
-
declare function isWithdrawable(note: CloakNote): boolean;
|
|
1046
|
-
/**
|
|
1047
|
-
* Update note with deposit information
|
|
1048
|
-
* Returns a new note object with deposit info added
|
|
1049
|
-
*/
|
|
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;
|
|
1060
|
-
/**
|
|
1061
|
-
* Find note by commitment from an array
|
|
1062
|
-
*/
|
|
1063
|
-
declare function findNoteByCommitment(notes: CloakNote[], commitment: string): CloakNote | undefined;
|
|
1064
|
-
/**
|
|
1065
|
-
* Filter notes by network
|
|
1066
|
-
*/
|
|
1067
|
-
declare function filterNotesByNetwork(notes: CloakNote[], network: Network): CloakNote[];
|
|
1068
|
-
/**
|
|
1069
|
-
* Filter notes that can be withdrawn
|
|
1070
|
-
*/
|
|
1071
|
-
declare function filterWithdrawableNotes(notes: CloakNote[]): CloakNote[];
|
|
1072
|
-
/**
|
|
1073
|
-
* Export keys to JSON string
|
|
1074
|
-
* WARNING: This exports secret keys! Store securely.
|
|
1075
|
-
*/
|
|
1076
|
-
declare function exportWalletKeys(keys: CloakKeyPair): string;
|
|
1077
|
-
/**
|
|
1078
|
-
* Import keys from JSON string
|
|
1079
|
-
*/
|
|
1080
|
-
declare function importWalletKeys(keysJson: string): CloakKeyPair;
|
|
1081
|
-
/**
|
|
1082
|
-
* Get public view key from keys
|
|
1083
|
-
*/
|
|
1084
|
-
declare function getPublicViewKey(keys: CloakKeyPair): string;
|
|
1085
|
-
/**
|
|
1086
|
-
* Get view key from keys
|
|
1087
|
-
*/
|
|
1088
|
-
declare function getViewKey(keys: CloakKeyPair): ViewKey;
|
|
1089
|
-
/**
|
|
1090
|
-
* Get recipient amount after fees
|
|
1091
|
-
*/
|
|
1092
|
-
declare function getRecipientAmount(amountLamports: number): number;
|
|
1093
|
-
|
|
1094
|
-
interface ViewingKeyPair {
|
|
1095
|
-
privateKey: Uint8Array;
|
|
1096
|
-
publicKey: Uint8Array;
|
|
1097
|
-
}
|
|
1098
|
-
/** Zcash-style expanded spend key: ask (auth), nsk (nullifier/nk), ovk (outgoing view) */
|
|
1099
|
-
interface ExpandedSpendKey {
|
|
1100
|
-
ask: Uint8Array;
|
|
1101
|
-
nsk: Uint8Array;
|
|
1102
|
-
ovk: Uint8Array;
|
|
1103
|
-
}
|
|
1104
|
-
/**
|
|
1105
|
-
* Expand spend key into (ask, nsk, ovk) — Zcash-style.
|
|
1106
|
-
* - ask: spend authorization (future)
|
|
1107
|
-
* - nsk: base for incoming viewing (nk) — chain note decryption
|
|
1108
|
-
* - ovk: outgoing viewing (future)
|
|
1109
|
-
*/
|
|
1110
|
-
declare function expandSpendKey(skSpend: Uint8Array): ExpandedSpendKey;
|
|
1111
|
-
/**
|
|
1112
|
-
* Derive chain note viewing key from nk (Zcash-style IVK component).
|
|
1113
|
-
* Used for trial-decrypting incoming chain notes.
|
|
1114
|
-
*
|
|
1115
|
-
* @param nk 32-byte nk (from expandSpendKey(...).nsk — the incoming view base)
|
|
1116
|
-
*/
|
|
1117
|
-
declare function deriveViewingKeyFromNk(nk: Uint8Array): ViewingKeyPair;
|
|
1118
|
-
/**
|
|
1119
|
-
* Derive diversifier for per-output chain note encryption (Phase 3).
|
|
1120
|
-
* d = BLAKE3("cloak_div_v1" || nk || commitmentHex || outputIndex)[0:11]
|
|
1121
|
-
*/
|
|
1122
|
-
declare function deriveDiversifier(nk: Uint8Array, commitmentHex: string, outputIndex: number): Uint8Array;
|
|
1123
|
-
/**
|
|
1124
|
-
* Derive per-output viewing key pair from nk + diversifier (Phase 3).
|
|
1125
|
-
* sk_d = BLAKE3("cloak_sk_d_v1" || nk || d) → clamp → X25519 keypair
|
|
1126
|
-
*/
|
|
1127
|
-
declare function deriveDiversifiedViewingKey(nk: Uint8Array, diversifier: Uint8Array): ViewingKeyPair;
|
|
1128
|
-
/**
|
|
1129
|
-
* Derive chain note viewing key from spend key (Zcash-style).
|
|
1130
|
-
* Expands to (ask, nsk, ovk) and uses nsk (nk) for chain note decryption.
|
|
1131
|
-
*/
|
|
1132
|
-
declare function deriveViewingKeyFromSpendKey(skSpend: Uint8Array): ViewingKeyPair;
|
|
430
|
+
declare function deriveViewingKeyFromSpendKey(skSpend: Uint8Array): ViewingKeyPair;
|
|
1133
431
|
/**
|
|
1134
432
|
* Derive chain note viewing key from UTXO private key (Zcash-style).
|
|
1135
433
|
* New UTXO (new keypair) => new viewing key.
|
|
@@ -1243,137 +541,6 @@ declare function computeMerkleRoot(leaf: bigint, pathElements: bigint[], pathInd
|
|
|
1243
541
|
* Convert hex string to bigint
|
|
1244
542
|
*/
|
|
1245
543
|
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)
|
|
1361
|
-
*
|
|
1362
|
-
* This matches the withdraw_swap.circom circuit
|
|
1363
|
-
*
|
|
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
|
|
1370
|
-
*/
|
|
1371
|
-
declare function computeSwapOutputsHashAsync(inputMint: PublicKey, outputMint: PublicKey, recipientAta: PublicKey, minOutputAmount: number, amount: number): Promise<bigint>;
|
|
1372
|
-
/**
|
|
1373
|
-
* Compute swap outputs hash (sync wrapper for backward compatibility)
|
|
1374
|
-
* @deprecated Use computeSwapOutputsHashAsync instead
|
|
1375
|
-
*/
|
|
1376
|
-
declare function computeSwapOutputsHashSync(_outputMint: PublicKey, _recipientAta: PublicKey, _minOutputAmount: number, _amount: number): Uint8Array;
|
|
1377
544
|
/**
|
|
1378
545
|
* Convert bigint to 32-byte big-endian Uint8Array
|
|
1379
546
|
*/
|
|
@@ -1436,57 +603,145 @@ 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
|
-
*
|
|
606
|
+
* Fee calculation utilities for Cloak Protocol
|
|
1440
607
|
*
|
|
1441
|
-
*
|
|
1442
|
-
*
|
|
1443
|
-
*/
|
|
1444
|
-
declare function isValidSolanaAddress(address: string): boolean;
|
|
1445
|
-
/**
|
|
1446
|
-
* Validate a Cloak note structure
|
|
608
|
+
* The protocol charges a fixed fee plus a variable percentage fee
|
|
609
|
+
* to prevent sybil attacks and cover operational costs.
|
|
1447
610
|
*
|
|
1448
|
-
*
|
|
1449
|
-
*
|
|
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.
|
|
1450
613
|
*/
|
|
1451
|
-
|
|
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;
|
|
1452
626
|
/**
|
|
1453
|
-
*
|
|
627
|
+
* Calculate the total protocol fee for a given amount
|
|
1454
628
|
*
|
|
1455
|
-
*
|
|
1456
|
-
* @throws Error if note cannot be used for withdrawal
|
|
1457
|
-
*/
|
|
1458
|
-
declare function validateWithdrawableNote(note: CloakNote): void;
|
|
1459
|
-
/**
|
|
1460
|
-
* Validate transfer recipients
|
|
629
|
+
* Formula: FIXED_FEE + floor((amount * VARIABLE_FEE_NUMERATOR) / VARIABLE_FEE_DENOMINATOR)
|
|
1461
630
|
*
|
|
1462
|
-
* @param
|
|
1463
|
-
* @
|
|
1464
|
-
* @throws Error if invalid
|
|
1465
|
-
*/
|
|
1466
|
-
declare function validateTransfers(recipients: Array<{
|
|
1467
|
-
recipient: PublicKey;
|
|
1468
|
-
amount: number;
|
|
1469
|
-
}>, totalAmount: number): void;
|
|
1470
|
-
|
|
1471
|
-
/**
|
|
1472
|
-
* Network Utilities
|
|
631
|
+
* @param amountLamports - Amount in lamports
|
|
632
|
+
* @returns Total fee in lamports
|
|
1473
633
|
*
|
|
1474
|
-
*
|
|
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
|
+
* ```
|
|
1475
639
|
*/
|
|
1476
|
-
|
|
640
|
+
declare function calculateFee(amountLamports: number): number;
|
|
1477
641
|
/**
|
|
1478
|
-
*
|
|
1479
|
-
*
|
|
1480
|
-
* Attempts to detect the Solana network from common RPC URL patterns.
|
|
1481
|
-
* Falls back to devnet if unable to detect.
|
|
642
|
+
* Bigint version of calculateFee (for UTXO flows that use bigint lamports).
|
|
1482
643
|
*/
|
|
1483
|
-
declare function
|
|
644
|
+
declare function calculateFeeBigint(amountLamports: bigint): bigint;
|
|
1484
645
|
/**
|
|
1485
|
-
*
|
|
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.)
|
|
1486
648
|
*/
|
|
1487
|
-
declare function
|
|
649
|
+
declare function isWithdrawAmountSufficient(amountLamports: bigint): boolean;
|
|
1488
650
|
/**
|
|
1489
|
-
*
|
|
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;
|
|
665
|
+
/**
|
|
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")
|
|
671
|
+
*
|
|
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
|
+
* ```
|
|
678
|
+
*/
|
|
679
|
+
declare function formatAmount(lamports: number, decimals?: number): string;
|
|
680
|
+
/**
|
|
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
|
|
686
|
+
*
|
|
687
|
+
* @example
|
|
688
|
+
* ```typescript
|
|
689
|
+
* parseAmount("1.5"); // 1_500_000_000
|
|
690
|
+
* parseAmount("0.001"); // 1_000_000
|
|
691
|
+
* ```
|
|
692
|
+
*/
|
|
693
|
+
declare function parseAmount(sol: string): number;
|
|
694
|
+
/**
|
|
695
|
+
* Validate that outputs sum equals expected amount
|
|
696
|
+
*
|
|
697
|
+
* @param outputs - Array of output amounts
|
|
698
|
+
* @param expectedTotal - Expected total amount
|
|
699
|
+
* @returns True if amounts match
|
|
700
|
+
*/
|
|
701
|
+
declare function validateOutputsSum(outputs: Array<{
|
|
702
|
+
amount: number;
|
|
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;
|
|
725
|
+
|
|
726
|
+
/**
|
|
727
|
+
* Network Utilities
|
|
728
|
+
*
|
|
729
|
+
* Helper functions for network detection and configuration
|
|
730
|
+
*/
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* Detect network from RPC URL
|
|
734
|
+
*
|
|
735
|
+
* Attempts to detect the Solana network from common RPC URL patterns.
|
|
736
|
+
* Falls back to devnet if unable to detect.
|
|
737
|
+
*/
|
|
738
|
+
declare function detectNetworkFromRpcUrl(rpcUrl?: string): Network;
|
|
739
|
+
/**
|
|
740
|
+
* Get the standard RPC URL for a network
|
|
741
|
+
*/
|
|
742
|
+
declare function getRpcUrlForNetwork(network: Network): string;
|
|
743
|
+
/**
|
|
744
|
+
* Validate RPC URL format
|
|
1490
745
|
*/
|
|
1491
746
|
declare function isValidRpcUrl(url: string): boolean;
|
|
1492
747
|
/**
|
|
@@ -1498,6 +753,85 @@ declare function getExplorerUrl(signature: string, network?: Network): string;
|
|
|
1498
753
|
*/
|
|
1499
754
|
declare function getAddressExplorerUrl(address: string, network?: Network): string;
|
|
1500
755
|
|
|
756
|
+
/**
|
|
757
|
+
* Merkle Tree implementation for computing proofs
|
|
758
|
+
*
|
|
759
|
+
* This tree stores all leaves and can compute the correct Merkle path
|
|
760
|
+
* for any leaf index.
|
|
761
|
+
*/
|
|
762
|
+
declare const MERKLE_TREE_HEIGHT = 32;
|
|
763
|
+
/**
|
|
764
|
+
* Merkle Tree class that stores all leaves and computes proofs
|
|
765
|
+
*/
|
|
766
|
+
declare class MerkleTree {
|
|
767
|
+
private levels;
|
|
768
|
+
private capacity;
|
|
769
|
+
private layers;
|
|
770
|
+
private zeros;
|
|
771
|
+
private poseidon;
|
|
772
|
+
/**
|
|
773
|
+
* Create a new Merkle tree
|
|
774
|
+
* @param levels Number of levels in the tree (height)
|
|
775
|
+
* @param leaves Initial leaves to insert
|
|
776
|
+
* @param zeros Precomputed zero values for each level
|
|
777
|
+
* @param poseidon Pre-initialized Poseidon instance (avoids async in constructor)
|
|
778
|
+
*/
|
|
779
|
+
constructor(levels: number, leaves: bigint[], zeros: bigint[], poseidon: any);
|
|
780
|
+
/**
|
|
781
|
+
* Create a new MerkleTree with async initialization
|
|
782
|
+
*/
|
|
783
|
+
static create(levels?: number, leaves?: bigint[]): Promise<MerkleTree>;
|
|
784
|
+
/**
|
|
785
|
+
* Rebuild the tree from the leaves (synchronous — poseidon must be initialized)
|
|
786
|
+
*/
|
|
787
|
+
private _rebuildSync;
|
|
788
|
+
/**
|
|
789
|
+
* Get the tree root
|
|
790
|
+
*/
|
|
791
|
+
root(): bigint;
|
|
792
|
+
/**
|
|
793
|
+
* Get the number of leaves in the tree
|
|
794
|
+
*/
|
|
795
|
+
get length(): number;
|
|
796
|
+
/**
|
|
797
|
+
* Insert a new leaf into the tree
|
|
798
|
+
*/
|
|
799
|
+
insert(leaf: bigint): void;
|
|
800
|
+
/**
|
|
801
|
+
* Insert multiple leaves
|
|
802
|
+
*/
|
|
803
|
+
bulkInsert(leaves: bigint[]): void;
|
|
804
|
+
/**
|
|
805
|
+
* Update the path from a leaf to the root
|
|
806
|
+
*/
|
|
807
|
+
private _updatePath;
|
|
808
|
+
/**
|
|
809
|
+
* Get the Merkle path for a leaf at the given index
|
|
810
|
+
* @param index Leaf index
|
|
811
|
+
* @returns pathElements and pathIndices for the proof
|
|
812
|
+
*/
|
|
813
|
+
path(index: number): {
|
|
814
|
+
pathElements: bigint[];
|
|
815
|
+
pathIndices: number;
|
|
816
|
+
};
|
|
817
|
+
/**
|
|
818
|
+
* Find the index of a leaf in the tree
|
|
819
|
+
* @param leaf Leaf value to find
|
|
820
|
+
* @returns Index if found, -1 otherwise
|
|
821
|
+
*/
|
|
822
|
+
indexOf(leaf: bigint): number;
|
|
823
|
+
/**
|
|
824
|
+
* Get all leaves
|
|
825
|
+
*/
|
|
826
|
+
leaves(): bigint[];
|
|
827
|
+
}
|
|
828
|
+
/**
|
|
829
|
+
* Build a MerkleTree from commitment values
|
|
830
|
+
* @param commitments Array of commitment bigints
|
|
831
|
+
* @param height Tree height (default: 32)
|
|
832
|
+
*/
|
|
833
|
+
declare function buildMerkleTree(commitments: bigint[], height?: number): Promise<MerkleTree>;
|
|
834
|
+
|
|
1501
835
|
/**
|
|
1502
836
|
* Error Utilities
|
|
1503
837
|
*
|
|
@@ -1529,6 +863,79 @@ declare function parseRelayErrorResponse(responseText: string): {
|
|
|
1529
863
|
isRootNotFound: boolean;
|
|
1530
864
|
currentRoot?: string;
|
|
1531
865
|
};
|
|
866
|
+
/**
|
|
867
|
+
* Raised when a spend attempt hits 0x1020 DoubleSpend on-chain — the input
|
|
868
|
+
* UTXO's nullifier PDA already exists, meaning the UTXO was spent earlier
|
|
869
|
+
* (often via another device / session the user forgot about).
|
|
870
|
+
*
|
|
871
|
+
* Recovery path: the SDK's pre-flight nullifier check catches this BEFORE
|
|
872
|
+
* proof generation via `verifyUtxos()`. If thrown after submission (unlikely
|
|
873
|
+
* once pre-flight is wired in), the caller should call `verifyUtxos()` to
|
|
874
|
+
* reconcile local state with chain.
|
|
875
|
+
*/
|
|
876
|
+
declare class UtxoAlreadySpentError extends Error {
|
|
877
|
+
readonly spentUtxoCommitments: string[];
|
|
878
|
+
constructor(message: string, spentUtxoCommitments?: string[]);
|
|
879
|
+
}
|
|
880
|
+
/**
|
|
881
|
+
* Base class for Range / sanctions-quote mismatches from the on-chain
|
|
882
|
+
* program. The relay signs quotes; the program verifies them. When they
|
|
883
|
+
* don't line up we hit one of three errors:
|
|
884
|
+
*
|
|
885
|
+
* 0x10B0 = QuoteExpired — quote's expiry_ts < on-chain clock
|
|
886
|
+
* 0x10B2 = WalletMismatch — quote wallet != expected_wallet
|
|
887
|
+
* 0x10B3 = MissingEd25519 — no withdraw-auth / range-quote ix at all
|
|
888
|
+
*
|
|
889
|
+
* These are structural mismatches the caller can't fix on their own —
|
|
890
|
+
* they indicate a relay / program version skew or a config drift
|
|
891
|
+
* (e.g. pool not initialized with the expected range_signer).
|
|
892
|
+
*/
|
|
893
|
+
declare class SanctionsQuoteError extends Error {
|
|
894
|
+
readonly onChainCode: number;
|
|
895
|
+
readonly subKind: "expired" | "wallet_mismatch" | "missing_ix";
|
|
896
|
+
constructor(message: string, onChainCode: number, subKind: "expired" | "wallet_mismatch" | "missing_ix");
|
|
897
|
+
}
|
|
898
|
+
/**
|
|
899
|
+
* Generic catch-all for relay 500s that don't map to any structured class.
|
|
900
|
+
* Preserves the raw relay error text in `relayMessage` so the caller can
|
|
901
|
+
* log it without having to string-match.
|
|
902
|
+
*/
|
|
903
|
+
declare class RelayInternalError extends Error {
|
|
904
|
+
readonly relayMessage?: string | undefined;
|
|
905
|
+
readonly httpStatus?: number | undefined;
|
|
906
|
+
/**
|
|
907
|
+
* Optional pre-built merkle tree rebuilt from chain (Node only).
|
|
908
|
+
* Populated by the chain-replay fallback in `transact()` when the
|
|
909
|
+
* relay-tree path fails after all retries. Callers can retry the
|
|
910
|
+
* spend with `options.cachedMerkleTree = err.cachedTreeFromChain`
|
|
911
|
+
* without paying the chain-replay cost a second time.
|
|
912
|
+
*
|
|
913
|
+
* Typed via `import type` so there's no runtime coupling between
|
|
914
|
+
* this module and the MerkleTree implementation.
|
|
915
|
+
*/
|
|
916
|
+
readonly cachedTreeFromChain?: MerkleTree | undefined;
|
|
917
|
+
constructor(message: string, relayMessage?: string | undefined, httpStatus?: number | undefined,
|
|
918
|
+
/**
|
|
919
|
+
* Optional pre-built merkle tree rebuilt from chain (Node only).
|
|
920
|
+
* Populated by the chain-replay fallback in `transact()` when the
|
|
921
|
+
* relay-tree path fails after all retries. Callers can retry the
|
|
922
|
+
* spend with `options.cachedMerkleTree = err.cachedTreeFromChain`
|
|
923
|
+
* without paying the chain-replay cost a second time.
|
|
924
|
+
*
|
|
925
|
+
* Typed via `import type` so there's no runtime coupling between
|
|
926
|
+
* this module and the MerkleTree implementation.
|
|
927
|
+
*/
|
|
928
|
+
cachedTreeFromChain?: MerkleTree | undefined);
|
|
929
|
+
}
|
|
930
|
+
/**
|
|
931
|
+
* Classify a relay error (response body text + HTTP status) into one of the
|
|
932
|
+
* structured error types above, or fall back to RelayInternalError.
|
|
933
|
+
*
|
|
934
|
+
* Order matters — more specific first. RootNotFoundError is handled by the
|
|
935
|
+
* caller separately (existing code path) since it carries `current_root` in
|
|
936
|
+
* the response body.
|
|
937
|
+
*/
|
|
938
|
+
declare function classifyRelayError(responseText: string, httpStatus?: number): Error;
|
|
1532
939
|
/**
|
|
1533
940
|
* Shield Pool Program Error Codes
|
|
1534
941
|
*
|
|
@@ -1578,1228 +985,871 @@ declare function createCloakError(error: unknown, _context: string): CloakError;
|
|
|
1578
985
|
declare function formatErrorForLogging(error: unknown): string;
|
|
1579
986
|
|
|
1580
987
|
/**
|
|
1581
|
-
*
|
|
1582
|
-
*
|
|
1583
|
-
* Provides structured logging similar to Rust tracing format:
|
|
1584
|
-
* 2026-01-23T00:51:46.489317Z INFO cloak::module: 📥 Message key=value
|
|
988
|
+
* UTXO (Unspent Transaction Output) Model
|
|
1585
989
|
*
|
|
1586
|
-
*
|
|
1587
|
-
*
|
|
1588
|
-
* -
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
* Enable or disable debug logging globally
|
|
1593
|
-
*/
|
|
1594
|
-
declare function setDebugMode(enabled: boolean): void;
|
|
1595
|
-
/**
|
|
1596
|
-
* Check if debug mode is enabled
|
|
990
|
+
* This module implements the UTXO model for the Cloak privacy protocol.
|
|
991
|
+
* UTXOs allow for:
|
|
992
|
+
* - Shield-to-shield transfers (privacy preserved)
|
|
993
|
+
* - Partial withdrawals (change stays shielded)
|
|
994
|
+
* - Combining multiple small deposits
|
|
995
|
+
* - Multi-token support (SOL + any SPL token)
|
|
1597
996
|
*/
|
|
1598
|
-
|
|
997
|
+
|
|
998
|
+
declare const NATIVE_SOL_MINT: PublicKey;
|
|
1599
999
|
/**
|
|
1600
|
-
*
|
|
1000
|
+
* UTXO Keypair for ownership verification
|
|
1001
|
+
*
|
|
1002
|
+
* Uses Poseidon hash for key derivation:
|
|
1003
|
+
* - privateKey: random field element (kept secret)
|
|
1004
|
+
* - publicKey: Poseidon(privateKey, 0) - can be shared
|
|
1601
1005
|
*/
|
|
1602
|
-
interface
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1006
|
+
interface UtxoKeypair {
|
|
1007
|
+
/** Private key (random 252-bit field element) */
|
|
1008
|
+
privateKey: bigint;
|
|
1009
|
+
/** Public key derived as Poseidon(privateKey, 0) */
|
|
1010
|
+
publicKey: bigint;
|
|
1607
1011
|
}
|
|
1608
1012
|
/**
|
|
1609
|
-
*
|
|
1610
|
-
*
|
|
1611
|
-
* @param module - Module name (e.g., "cloak::sdk", "cloak::indexer")
|
|
1612
|
-
* @returns Logger instance with debug, info, warn, error methods
|
|
1013
|
+
* UTXO represents an unspent transaction output
|
|
1613
1014
|
*
|
|
1614
|
-
*
|
|
1615
|
-
*
|
|
1616
|
-
*
|
|
1617
|
-
*
|
|
1618
|
-
*
|
|
1619
|
-
*
|
|
1015
|
+
* Contains all information needed to spend the UTXO:
|
|
1016
|
+
* - amount: Value in the smallest unit (lamports for SOL)
|
|
1017
|
+
* - keypair: Ownership keys
|
|
1018
|
+
* - blinding: Randomness for hiding
|
|
1019
|
+
* - mintAddress: Token type (SOL or SPL token)
|
|
1020
|
+
* - index: Leaf index in Merkle tree (set after deposit/creation)
|
|
1620
1021
|
*/
|
|
1621
|
-
|
|
1622
|
-
/**
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
/**
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1022
|
+
interface Utxo {
|
|
1023
|
+
/** Amount in the smallest unit (lamports for SOL, token units for SPL) */
|
|
1024
|
+
amount: bigint;
|
|
1025
|
+
/** Keypair for ownership */
|
|
1026
|
+
keypair: UtxoKeypair;
|
|
1027
|
+
/** Random blinding factor */
|
|
1028
|
+
blinding: bigint;
|
|
1029
|
+
/** Token mint address (NATIVE_SOL_MINT for SOL) */
|
|
1030
|
+
mintAddress: PublicKey;
|
|
1031
|
+
/** Leaf index in Merkle tree (set after the UTXO is in the tree) */
|
|
1032
|
+
index?: number;
|
|
1033
|
+
/** Commitment hash (computed from amount, pubkey, blinding, mint) */
|
|
1034
|
+
commitment?: bigint;
|
|
1035
|
+
/** Nullifier hash (computed when spending) */
|
|
1036
|
+
nullifier?: bigint;
|
|
1037
|
+
/**
|
|
1038
|
+
* Sibling commitment at level 0 of the Merkle tree.
|
|
1039
|
+
* Required for Merkle proofs since siblings aren't stored on-chain.
|
|
1040
|
+
* This is the commitment of the other output in the same transaction.
|
|
1041
|
+
*/
|
|
1042
|
+
siblingCommitment?: bigint;
|
|
1043
|
+
}
|
|
1642
1044
|
/**
|
|
1643
|
-
*
|
|
1045
|
+
* Encrypted UTXO note for recipient discovery
|
|
1046
|
+
*
|
|
1047
|
+
* When creating an output UTXO for someone else, the data is encrypted
|
|
1048
|
+
* so only the recipient can discover and spend it.
|
|
1644
1049
|
*/
|
|
1645
|
-
|
|
1646
|
-
|
|
1050
|
+
interface EncryptedNote {
|
|
1051
|
+
/** Encrypted UTXO data (ECIES/ChaCha20 encrypted) */
|
|
1052
|
+
ciphertext: Uint8Array;
|
|
1053
|
+
/** Ephemeral public key for ECDH */
|
|
1054
|
+
ephemeralPubkey: Uint8Array;
|
|
1055
|
+
/** MAC for integrity verification */
|
|
1056
|
+
mac: Uint8Array;
|
|
1057
|
+
}
|
|
1647
1058
|
/**
|
|
1648
|
-
*
|
|
1649
|
-
* for potential recovery/resume scenarios
|
|
1059
|
+
* Transaction parameters for a UTXO transaction
|
|
1650
1060
|
*/
|
|
1651
|
-
interface
|
|
1652
|
-
/**
|
|
1653
|
-
|
|
1654
|
-
/**
|
|
1655
|
-
|
|
1061
|
+
interface TransactParams {
|
|
1062
|
+
/** Input UTXOs to spend (max 2) */
|
|
1063
|
+
inputUtxos: Utxo[];
|
|
1064
|
+
/** Output UTXOs to create (max 2) */
|
|
1065
|
+
outputUtxos: Utxo[];
|
|
1066
|
+
/** External recipient for withdrawal (optional) */
|
|
1067
|
+
recipient?: PublicKey;
|
|
1068
|
+
/** Net external amount: positive = deposit, negative = withdraw */
|
|
1069
|
+
externalAmount?: bigint;
|
|
1070
|
+
/** Depositor address (for deposits, the source of funds) */
|
|
1071
|
+
depositor?: PublicKey;
|
|
1656
1072
|
}
|
|
1657
1073
|
/**
|
|
1658
|
-
*
|
|
1659
|
-
*
|
|
1660
|
-
* Handles submission of withdrawal transactions through a relay service
|
|
1661
|
-
* that pays for transaction fees and submits the transaction on-chain.
|
|
1074
|
+
* Result from a UTXO transaction
|
|
1662
1075
|
*/
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
* The relay service will validate the proof, pay for transaction fees,
|
|
1675
|
-
* and submit the transaction on-chain.
|
|
1676
|
-
*
|
|
1677
|
-
* @param params - Withdrawal parameters
|
|
1678
|
-
* @param onStatusUpdate - Optional callback for status updates
|
|
1679
|
-
* @param onRequestId - CRITICAL: Callback when request_id is received.
|
|
1680
|
-
* Persist this ID to recover if browser crashes during polling.
|
|
1681
|
-
* @returns Transaction signature when completed
|
|
1682
|
-
*
|
|
1683
|
-
* @example
|
|
1684
|
-
* ```typescript
|
|
1685
|
-
* const signature = await relay.submitWithdraw({
|
|
1686
|
-
* proof: proofHex,
|
|
1687
|
-
* publicInputs: { root, nf, outputs_hash, amount },
|
|
1688
|
-
* outputs: [{ recipient: addr, amount: lamports }],
|
|
1689
|
-
* feeBps: 50
|
|
1690
|
-
* }, (status) => console.log(`Status: ${status}`),
|
|
1691
|
-
* (requestId) => localStorage.setItem('pending_withdraw', requestId));
|
|
1692
|
-
* console.log(`Transaction: ${signature}`);
|
|
1693
|
-
* ```
|
|
1694
|
-
*/
|
|
1695
|
-
submitWithdraw(params: {
|
|
1696
|
-
proof: string;
|
|
1697
|
-
publicInputs: {
|
|
1698
|
-
root: string;
|
|
1699
|
-
nf: string;
|
|
1700
|
-
outputs_hash: string;
|
|
1701
|
-
amount: number;
|
|
1702
|
-
};
|
|
1703
|
-
outputs: Array<{
|
|
1704
|
-
recipient: string;
|
|
1705
|
-
amount: number;
|
|
1706
|
-
}>;
|
|
1707
|
-
feeBps: number;
|
|
1708
|
-
metadataBundle?: EncryptedMetadataBundle;
|
|
1709
|
-
}, onStatusUpdate?: (status: string) => void, onRequestId?: (requestId: string) => void): Promise<string>;
|
|
1710
|
-
/**
|
|
1711
|
-
* Resume polling for a withdrawal that was previously started
|
|
1712
|
-
*
|
|
1713
|
-
* Use this after page reload to check status of a pending withdrawal.
|
|
1714
|
-
* The requestId should have been persisted via the onRequestId callback.
|
|
1715
|
-
*
|
|
1716
|
-
* @param requestId - Request ID from a previous submitWithdraw call
|
|
1717
|
-
* @param onStatusUpdate - Optional callback for status updates
|
|
1718
|
-
* @returns Transaction signature if completed, null if still pending/failed
|
|
1719
|
-
*
|
|
1720
|
-
* @example
|
|
1721
|
-
* ```typescript
|
|
1722
|
-
* // On page load, check for pending withdrawal
|
|
1723
|
-
* const pendingId = localStorage.getItem('pending_withdraw');
|
|
1724
|
-
* if (pendingId) {
|
|
1725
|
-
* const result = await relay.resumeWithdraw(pendingId);
|
|
1726
|
-
* if (result.status === 'completed') {
|
|
1727
|
-
* console.log('Withdrawal completed:', result.signature);
|
|
1728
|
-
* localStorage.removeItem('pending_withdraw');
|
|
1729
|
-
* }
|
|
1730
|
-
* }
|
|
1731
|
-
* ```
|
|
1732
|
-
*/
|
|
1733
|
-
resumeWithdraw(requestId: string, onStatusUpdate?: (status: string) => void): Promise<{
|
|
1734
|
-
status: 'completed' | 'failed' | 'pending';
|
|
1735
|
-
signature?: string;
|
|
1736
|
-
error?: string;
|
|
1737
|
-
}>;
|
|
1738
|
-
/**
|
|
1739
|
-
* Poll for withdrawal completion
|
|
1740
|
-
*
|
|
1741
|
-
* @param requestId - Request ID from relay service
|
|
1742
|
-
* @param onStatusUpdate - Optional callback for status updates
|
|
1743
|
-
* @returns Transaction signature when completed
|
|
1744
|
-
*/
|
|
1745
|
-
private pollForCompletion;
|
|
1076
|
+
interface TransactResult {
|
|
1077
|
+
/** Transaction signature */
|
|
1078
|
+
signature: string;
|
|
1079
|
+
/** Nullifiers of spent inputs */
|
|
1080
|
+
inputNullifiers: bigint[];
|
|
1081
|
+
/** Commitments of created outputs */
|
|
1082
|
+
outputCommitments: bigint[];
|
|
1083
|
+
/** New Merkle root after the transaction */
|
|
1084
|
+
newRoot: string;
|
|
1085
|
+
/** Merkle tree indices where output commitments were inserted */
|
|
1086
|
+
commitmentIndices: [number, number];
|
|
1746
1087
|
/**
|
|
1747
|
-
*
|
|
1748
|
-
*
|
|
1749
|
-
*
|
|
1750
|
-
* The relay service will validate the proof, execute the swap, pay for fees,
|
|
1751
|
-
* and submit the transaction on-chain.
|
|
1752
|
-
*
|
|
1753
|
-
* @param params - Swap parameters
|
|
1754
|
-
* @param onStatusUpdate - Optional callback for status updates
|
|
1755
|
-
* @returns Transaction signature when completed
|
|
1756
|
-
*
|
|
1757
|
-
* @example
|
|
1758
|
-
* ```typescript
|
|
1759
|
-
* const signature = await relay.submitSwap({
|
|
1760
|
-
* proof: proofHex,
|
|
1761
|
-
* publicInputs: { root, nf, outputs_hash, amount },
|
|
1762
|
-
* outputs: [{ recipient: addr, amount: lamports }],
|
|
1763
|
-
* feeBps: 50,
|
|
1764
|
-
* swap: {
|
|
1765
|
-
* output_mint: tokenMint.toBase58(),
|
|
1766
|
-
* slippage_bps: 100,
|
|
1767
|
-
* min_output_amount: minAmount
|
|
1768
|
-
* }
|
|
1769
|
-
* }, (status) => console.log(`Status: ${status}`));
|
|
1770
|
-
* console.log(`Transaction: ${signature}`);
|
|
1771
|
-
* ```
|
|
1088
|
+
* Sibling commitments for each output.
|
|
1089
|
+
* For output[0], sibling is output[1] and vice versa.
|
|
1090
|
+
* These are needed for Merkle proofs since siblings aren't stored on-chain.
|
|
1772
1091
|
*/
|
|
1773
|
-
|
|
1774
|
-
proof: string;
|
|
1775
|
-
publicInputs: {
|
|
1776
|
-
root: string;
|
|
1777
|
-
nf: string;
|
|
1778
|
-
outputs_hash: string;
|
|
1779
|
-
amount: number;
|
|
1780
|
-
};
|
|
1781
|
-
outputs: Array<{
|
|
1782
|
-
recipient: string;
|
|
1783
|
-
amount: number;
|
|
1784
|
-
}>;
|
|
1785
|
-
feeBps: number;
|
|
1786
|
-
swap: {
|
|
1787
|
-
output_mint: string;
|
|
1788
|
-
slippage_bps: number;
|
|
1789
|
-
min_output_amount: number;
|
|
1790
|
-
};
|
|
1791
|
-
metadataBundle?: EncryptedMetadataBundle;
|
|
1792
|
-
}, onStatusUpdate?: (status: string) => void, onRequestId?: (requestId: string) => void): Promise<string>;
|
|
1092
|
+
siblingCommitments: [bigint, bigint];
|
|
1793
1093
|
/**
|
|
1794
|
-
*
|
|
1795
|
-
*
|
|
1796
|
-
*
|
|
1797
|
-
*
|
|
1798
|
-
*
|
|
1799
|
-
* @example
|
|
1800
|
-
* ```typescript
|
|
1801
|
-
* const status = await relay.getStatus(requestId);
|
|
1802
|
-
* console.log(`Status: ${status.status}`);
|
|
1803
|
-
* if (status.status === 'completed') {
|
|
1804
|
-
* console.log(`TX: ${status.txId}`);
|
|
1805
|
-
* }
|
|
1806
|
-
* ```
|
|
1094
|
+
* Left sibling from before the transaction (for odd-index handling).
|
|
1095
|
+
* When the first output ends up at an odd index due to concurrent access,
|
|
1096
|
+
* its sibling at index-1 comes from a previous transaction.
|
|
1097
|
+
* This value captures subtrees[0] before our transaction to enable
|
|
1098
|
+
* correct Merkle proof computation for odd indices.
|
|
1807
1099
|
*/
|
|
1808
|
-
|
|
1100
|
+
preTransactionLeftSibling?: bigint;
|
|
1809
1101
|
/**
|
|
1810
|
-
*
|
|
1811
|
-
*
|
|
1812
|
-
*
|
|
1813
|
-
* The user must sign a one-time relay challenge proving wallet ownership.
|
|
1814
|
-
*
|
|
1815
|
-
* @param userPubkey - User's wallet public key (base58)
|
|
1816
|
-
* @param viewingKey - Viewing key private key (32 bytes, hex encoded)
|
|
1817
|
-
* @param signMessage - Function to sign challenge message bytes
|
|
1818
|
-
*
|
|
1819
|
-
* @example
|
|
1820
|
-
* ```typescript
|
|
1821
|
-
* await relay.registerViewingKey(
|
|
1822
|
-
* userPublicKey.toBase58(),
|
|
1823
|
-
* viewingKeyHex,
|
|
1824
|
-
* signatureBase64
|
|
1825
|
-
* );
|
|
1826
|
-
* ```
|
|
1102
|
+
* The actual output UTXOs created by this transaction.
|
|
1103
|
+
* These have all the data needed to spend them later (keypair, blinding, etc).
|
|
1104
|
+
* The UTXOs are already updated with their indices and sibling commitments.
|
|
1827
1105
|
*/
|
|
1828
|
-
|
|
1106
|
+
outputUtxos: Utxo[];
|
|
1829
1107
|
/**
|
|
1830
|
-
*
|
|
1831
|
-
*
|
|
1108
|
+
* Whether the viewing key was registered with the relay for compliance.
|
|
1109
|
+
* True on first transaction when metadataBundle includes viewing_key.
|
|
1110
|
+
* Once registered, subsequent transactions don't need to send metadataBundle.
|
|
1832
1111
|
*/
|
|
1833
|
-
|
|
1112
|
+
viewingKeyRegistered?: boolean;
|
|
1834
1113
|
/**
|
|
1835
|
-
*
|
|
1114
|
+
* The Merkle tree used/built for this transaction, with output commitments inserted.
|
|
1115
|
+
* Pass this as `cachedMerkleTree` in the next transaction to skip relay fetching
|
|
1116
|
+
* and avoid needing `waitForCommitmentIndex`.
|
|
1836
1117
|
*/
|
|
1837
|
-
|
|
1118
|
+
merkleTree?: MerkleTree;
|
|
1838
1119
|
/**
|
|
1839
|
-
*
|
|
1120
|
+
* Address lookup table used for v0 transaction (when chain notes or risk oracle require it).
|
|
1121
|
+
* Pass this as `addressLookupTableAccounts` in the next deposit to avoid creating a new ALT.
|
|
1840
1122
|
*/
|
|
1841
|
-
|
|
1842
|
-
private computeViewingKeyIdentifier;
|
|
1123
|
+
addressLookupTableAccounts?: AddressLookupTableAccount[];
|
|
1843
1124
|
}
|
|
1844
|
-
|
|
1845
|
-
/**
|
|
1846
|
-
* Risk Oracle Service
|
|
1847
|
-
*
|
|
1848
|
-
* Self-contained module for fetching Switchboard risk quote instructions
|
|
1849
|
-
* using the Range Risk API. Eliminates the need for an external web endpoint
|
|
1850
|
-
* (e.g. `/api/risk-quote`) by calling Switchboard directly from the SDK.
|
|
1851
|
-
*
|
|
1852
|
-
* Uses dynamic imports for @switchboard-xyz packages so they are only loaded
|
|
1853
|
-
* when fetchRiskQuoteIx is actually called — not at SDK import time. This
|
|
1854
|
-
* prevents the heavy Node.js-only Switchboard code from being bundled into
|
|
1855
|
-
* browser builds (Next.js, etc.).
|
|
1856
|
-
*
|
|
1857
|
-
* Usage:
|
|
1858
|
-
* const { instruction, queue } = await fetchRiskQuoteIx(connection, wallet, rangeApiKey);
|
|
1859
|
-
*/
|
|
1860
|
-
|
|
1861
|
-
/**
|
|
1862
|
-
* Fetch a Switchboard risk quote instruction directly from Range + Switchboard.
|
|
1863
|
-
*
|
|
1864
|
-
* This removes the need for an external `/api/risk-quote` endpoint. The SDK
|
|
1865
|
-
* calls Switchboard's crossbar oracle network directly with the Range API key.
|
|
1866
|
-
*
|
|
1867
|
-
* @param connection - Solana RPC connection
|
|
1868
|
-
* @param wallet - Depositor's public key (the wallet being risk-scored)
|
|
1869
|
-
* @param rangeApiKey - Range.org API key for the risk score lookup
|
|
1870
|
-
* @returns The Ed25519 sig-verify instruction to prepend at index 0, plus the queue pubkey
|
|
1871
|
-
*/
|
|
1872
|
-
declare function fetchRiskQuoteIx(connection: Connection, wallet: PublicKey, rangeApiKey: string): Promise<{
|
|
1873
|
-
instruction: TransactionInstruction;
|
|
1874
|
-
queue: PublicKey;
|
|
1875
|
-
}>;
|
|
1876
|
-
|
|
1877
|
-
/**
|
|
1878
|
-
* Encrypted Output Helpers
|
|
1879
|
-
*
|
|
1880
|
-
* Functions for creating encrypted outputs that enable note scanning
|
|
1881
|
-
*/
|
|
1882
|
-
|
|
1883
|
-
/**
|
|
1884
|
-
* Prepare encrypted output for scanning by wallet owner
|
|
1885
|
-
*
|
|
1886
|
-
* @param note - Note to encrypt
|
|
1887
|
-
* @param cloakKeys - Wallet's Cloak keys (for self-encryption)
|
|
1888
|
-
* @returns Base64-encoded encrypted output
|
|
1889
|
-
*/
|
|
1890
|
-
declare function prepareEncryptedOutput(note: CloakNote, cloakKeys: CloakKeyPair): string;
|
|
1891
|
-
/**
|
|
1892
|
-
* Prepare encrypted output for a specific recipient
|
|
1893
|
-
*
|
|
1894
|
-
* @param note - Note to encrypt
|
|
1895
|
-
* @param recipientPvkHex - Recipient's public view key (hex)
|
|
1896
|
-
* @returns Base64-encoded encrypted output
|
|
1897
|
-
*/
|
|
1898
|
-
declare function prepareEncryptedOutputForRecipient(note: CloakNote, recipientPvkHex: string): string;
|
|
1899
|
-
/**
|
|
1900
|
-
* Simple base64 encoding for v1.0 notes (no encryption)
|
|
1901
|
-
*
|
|
1902
|
-
* @param note - Note to encode
|
|
1903
|
-
* @returns Base64-encoded note data
|
|
1904
|
-
*/
|
|
1905
|
-
declare function encodeNoteSimple(note: CloakNote): string;
|
|
1906
|
-
|
|
1907
|
-
/**
|
|
1908
|
-
* Wallet Integration Helpers
|
|
1909
|
-
*
|
|
1910
|
-
* Helper functions for working with Solana Wallet Adapters
|
|
1911
|
-
*/
|
|
1912
|
-
|
|
1913
|
-
/**
|
|
1914
|
-
* Validate wallet is connected and has public key
|
|
1915
|
-
*/
|
|
1916
|
-
declare function validateWalletConnected(wallet: WalletAdapter | Keypair): void;
|
|
1917
|
-
/**
|
|
1918
|
-
* Get public key from wallet or keypair
|
|
1919
|
-
*/
|
|
1920
|
-
declare function getPublicKey(wallet: WalletAdapter | Keypair): PublicKey;
|
|
1921
|
-
/**
|
|
1922
|
-
* Send transaction using wallet adapter or keypair
|
|
1923
|
-
*/
|
|
1924
|
-
declare function sendTransaction(transaction: Transaction, wallet: WalletAdapter | Keypair, connection: Connection, options?: SendOptions): Promise<string>;
|
|
1925
|
-
/**
|
|
1926
|
-
* Sign transaction using wallet adapter or keypair
|
|
1927
|
-
*/
|
|
1928
|
-
declare function signTransaction<T extends Transaction>(transaction: T, wallet: WalletAdapter | Keypair): Promise<T>;
|
|
1929
|
-
/**
|
|
1930
|
-
* Create a keypair adapter for testing
|
|
1931
|
-
*/
|
|
1932
|
-
declare function keypairToAdapter(keypair: Keypair): WalletAdapter;
|
|
1933
|
-
|
|
1934
|
-
/**
|
|
1935
|
-
* Create a deposit instruction
|
|
1936
|
-
*
|
|
1937
|
-
* Deposits SOL into the Cloak protocol by creating a commitment.
|
|
1938
|
-
*
|
|
1939
|
-
* Instruction format:
|
|
1940
|
-
* - Byte 0: Discriminant (0x01 for Deposit, per ShieldPoolInstruction enum)
|
|
1941
|
-
* - Bytes 1-8: Amount (u64, little-endian)
|
|
1942
|
-
* - Bytes 9-40: Commitment (32 bytes)
|
|
1943
|
-
*
|
|
1944
|
-
* @param params - Deposit parameters
|
|
1945
|
-
* @returns Transaction instruction
|
|
1946
|
-
*
|
|
1947
|
-
* @example
|
|
1948
|
-
* ```typescript
|
|
1949
|
-
* const instruction = createDepositInstruction({
|
|
1950
|
-
* programId: CLOAK_PROGRAM_ID,
|
|
1951
|
-
* payer: wallet.publicKey,
|
|
1952
|
-
* pool: POOL_ADDRESS,
|
|
1953
|
-
* commitments: COMMITMENTS_ADDRESS,
|
|
1954
|
-
* amount: 1_000_000_000, // 1 SOL
|
|
1955
|
-
* commitment: commitmentBytes
|
|
1956
|
-
* });
|
|
1957
|
-
* ```
|
|
1958
|
-
*/
|
|
1959
|
-
declare function createDepositInstruction(params: {
|
|
1960
|
-
programId: PublicKey;
|
|
1961
|
-
payer: PublicKey;
|
|
1962
|
-
pool: PublicKey;
|
|
1963
|
-
merkleTree: PublicKey;
|
|
1964
|
-
amount: number;
|
|
1965
|
-
commitment: Uint8Array;
|
|
1966
|
-
}): TransactionInstruction;
|
|
1967
1125
|
/**
|
|
1968
|
-
*
|
|
1126
|
+
* Generate a random field element suitable for BN254
|
|
1969
1127
|
*/
|
|
1970
|
-
|
|
1971
|
-
programId: PublicKey;
|
|
1972
|
-
payer: PublicKey;
|
|
1973
|
-
pool: PublicKey;
|
|
1974
|
-
merkleTree: PublicKey;
|
|
1975
|
-
amount: number;
|
|
1976
|
-
commitment: Uint8Array;
|
|
1977
|
-
}
|
|
1128
|
+
declare function randomFieldElement(): bigint;
|
|
1978
1129
|
/**
|
|
1979
|
-
*
|
|
1130
|
+
* Generate a new UTXO keypair
|
|
1980
1131
|
*
|
|
1981
|
-
* @
|
|
1982
|
-
* @throws Error if invalid
|
|
1132
|
+
* @returns A new keypair with random private key and derived public key
|
|
1983
1133
|
*/
|
|
1984
|
-
declare function
|
|
1985
|
-
|
|
1134
|
+
declare function generateUtxoKeypair(): Promise<UtxoKeypair>;
|
|
1986
1135
|
/**
|
|
1987
|
-
*
|
|
1136
|
+
* Derive a deterministic UTXO keypair from a wallet's spend key.
|
|
1137
|
+
* Use this for deposits and change outputs so all chain notes use the same nk,
|
|
1138
|
+
* enabling the compliance scan (scanTransactions + toComplianceReport) to decrypt them.
|
|
1988
1139
|
*
|
|
1989
|
-
*
|
|
1990
|
-
*
|
|
1140
|
+
* @param skSpend - 32-byte spend key (from wallet key derivation)
|
|
1141
|
+
* @returns UtxoKeypair with deterministic private/public keys
|
|
1991
1142
|
*/
|
|
1992
|
-
|
|
1993
|
-
interface ShieldPoolPDAs {
|
|
1994
|
-
pool: PublicKey;
|
|
1995
|
-
merkleTree: PublicKey;
|
|
1996
|
-
vaultAuthority: PublicKey;
|
|
1997
|
-
treasury: PublicKey;
|
|
1998
|
-
}
|
|
1143
|
+
declare function deriveUtxoKeypairFromSpendKey(skSpend: Uint8Array): Promise<UtxoKeypair>;
|
|
1999
1144
|
/**
|
|
2000
|
-
* Derive
|
|
2001
|
-
*
|
|
2002
|
-
* Seeds match the on-chain mint-scoped program:
|
|
2003
|
-
* - pool: [b"pool", mint]
|
|
2004
|
-
* - merkle_tree: [b"merkle_tree", mint]
|
|
2005
|
-
* - treasury: [b"treasury", mint]
|
|
2006
|
-
* - vault_authority: [b"vault_authority", mint]
|
|
1145
|
+
* Derive public key from private key
|
|
2007
1146
|
*
|
|
2008
|
-
* @param
|
|
2009
|
-
* @
|
|
1147
|
+
* @param privateKey The private key
|
|
1148
|
+
* @returns The corresponding public key
|
|
2010
1149
|
*/
|
|
2011
|
-
declare function
|
|
1150
|
+
declare function derivePublicKey(privateKey: bigint): Promise<bigint>;
|
|
2012
1151
|
/**
|
|
2013
|
-
*
|
|
2014
|
-
*
|
|
2015
|
-
* With the new PDA-per-nullifier design, each nullifier has its own PDA
|
|
2016
|
-
* instead of being stored in a shared shard. The PDA is created when
|
|
2017
|
-
* the nullifier is used during withdrawal.
|
|
2018
|
-
*
|
|
2019
|
-
* Seeds: ["nullifier", pool_pubkey, nullifier_hash]
|
|
1152
|
+
* Create a new UTXO
|
|
2020
1153
|
*
|
|
2021
|
-
* @param
|
|
2022
|
-
* @param
|
|
2023
|
-
* @param
|
|
2024
|
-
* @returns
|
|
1154
|
+
* @param amount Amount in smallest unit
|
|
1155
|
+
* @param keypair Owner's keypair
|
|
1156
|
+
* @param mintAddress Token mint (defaults to native SOL)
|
|
1157
|
+
* @returns A new UTXO (commitment will be computed)
|
|
2025
1158
|
*/
|
|
2026
|
-
declare function
|
|
1159
|
+
declare function createUtxo(amount: bigint, keypair: UtxoKeypair, mintAddress?: PublicKey): Promise<Utxo>;
|
|
2027
1160
|
/**
|
|
2028
|
-
*
|
|
1161
|
+
* Create a zero/padding UTXO
|
|
2029
1162
|
*
|
|
2030
|
-
*
|
|
1163
|
+
* Zero UTXOs are used as padding when we need fewer than 2 inputs/outputs.
|
|
1164
|
+
* They have zero amount and don't require valid Merkle proofs.
|
|
1165
|
+
* Uses salt-based keypair (privateKey = salt) with blinding=0 to match the circuit
|
|
1166
|
+
* test. By default, salt is random to avoid cross-process collisions under concurrency.
|
|
1167
|
+
* Callers can pass an explicit salt for deterministic behavior.
|
|
2031
1168
|
*
|
|
2032
|
-
* @param
|
|
2033
|
-
* @param
|
|
2034
|
-
* @param programId - Optional program ID (defaults to CLOAK_PROGRAM_ID)
|
|
2035
|
-
* @returns [PublicKey, bump] - The swap state PDA and its bump seed
|
|
1169
|
+
* @param mintAddress Token mint (defaults to native SOL)
|
|
1170
|
+
* @param salt Optional salt; if omitted, uses timestamp+counter for uniqueness
|
|
2036
1171
|
*/
|
|
2037
|
-
declare function
|
|
2038
|
-
|
|
1172
|
+
declare function createZeroUtxo(mintAddress?: PublicKey, salt?: bigint): Promise<Utxo>;
|
|
2039
1173
|
/**
|
|
2040
|
-
*
|
|
1174
|
+
* Convert PublicKey to field element for circuit
|
|
2041
1175
|
*
|
|
2042
|
-
*
|
|
2043
|
-
*
|
|
1176
|
+
* @param pubkey Solana PublicKey
|
|
1177
|
+
* @returns Field element representation
|
|
2044
1178
|
*/
|
|
2045
|
-
|
|
1179
|
+
declare function pubkeyToFieldElement(pubkey: PublicKey): bigint;
|
|
2046
1180
|
/**
|
|
2047
|
-
*
|
|
1181
|
+
* Compute the commitment for a UTXO
|
|
1182
|
+
*
|
|
1183
|
+
* commitment = Poseidon(amount, pubkey, blinding, mintAddress)
|
|
1184
|
+
*
|
|
1185
|
+
* @param utxo The UTXO to compute commitment for
|
|
1186
|
+
* @returns The commitment as a bigint
|
|
2048
1187
|
*/
|
|
2049
|
-
|
|
2050
|
-
pathElements: string[];
|
|
2051
|
-
pathIndices: number[];
|
|
2052
|
-
root: string;
|
|
2053
|
-
}
|
|
2054
|
-
interface MerkleTreeState {
|
|
2055
|
-
nextIndex: number;
|
|
2056
|
-
root: string;
|
|
2057
|
-
subtrees: string[];
|
|
2058
|
-
}
|
|
1188
|
+
declare function computeCommitment(utxo: Utxo): Promise<bigint>;
|
|
2059
1189
|
/**
|
|
2060
|
-
*
|
|
2061
|
-
*
|
|
2062
|
-
*
|
|
2063
|
-
*
|
|
1190
|
+
* Compute the signature for nullifier derivation
|
|
1191
|
+
*
|
|
1192
|
+
* signature = Poseidon(privateKey, commitment, pathIndex)
|
|
1193
|
+
*
|
|
1194
|
+
* @param privateKey Owner's private key
|
|
1195
|
+
* @param commitment The UTXO commitment
|
|
1196
|
+
* @param pathIndex Merkle tree path index
|
|
1197
|
+
* @returns The signature
|
|
2064
1198
|
*/
|
|
2065
|
-
declare function
|
|
2066
|
-
/** When true, skip relay root and use chain directly (avoids stale relay root causing ProofInvalid) */
|
|
2067
|
-
skipRelayRoot?: boolean, mint?: PublicKey): Promise<MerkleTreeState>;
|
|
1199
|
+
declare function computeSignature(privateKey: bigint, commitment: bigint, pathIndex: bigint): Promise<bigint>;
|
|
2068
1200
|
/**
|
|
2069
|
-
* Compute
|
|
1201
|
+
* Compute the nullifier for a UTXO
|
|
2070
1202
|
*
|
|
2071
|
-
*
|
|
2072
|
-
* 1. Reading the subtrees (frontier) from the on-chain account
|
|
2073
|
-
* 2. For each level, determining the sibling:
|
|
2074
|
-
* - If index is odd: sibling is the stored subtree (left sibling)
|
|
2075
|
-
* - If index is even: sibling is either a subsequent subtree or zero value
|
|
1203
|
+
* nullifier = Poseidon(commitment, pathIndex, signature)
|
|
2076
1204
|
*
|
|
2077
|
-
*
|
|
2078
|
-
*
|
|
2079
|
-
* an indexer may still be needed.
|
|
1205
|
+
* The nullifier is a unique identifier that gets recorded on-chain
|
|
1206
|
+
* to prevent double-spending.
|
|
2080
1207
|
*
|
|
2081
|
-
* @param
|
|
2082
|
-
* @
|
|
2083
|
-
* @param leafIndex - Index of the leaf to compute proof for
|
|
2084
|
-
* @param forceConfirmed - If true, forces "confirmed" commitment level for fresh data
|
|
2085
|
-
* @returns Merkle proof with path elements and indices
|
|
1208
|
+
* @param utxo The UTXO being spent
|
|
1209
|
+
* @returns The nullifier
|
|
2086
1210
|
*/
|
|
2087
|
-
declare function
|
|
1211
|
+
declare function computeNullifier(utxo: Utxo): Promise<bigint>;
|
|
2088
1212
|
/**
|
|
2089
|
-
*
|
|
2090
|
-
*
|
|
2091
|
-
* This is the most reliable case - immediately after your deposit,
|
|
2092
|
-
* all siblings to the right are zero values, and siblings to the left
|
|
2093
|
-
* are stored in the subtrees.
|
|
1213
|
+
* Serialize a UTXO to bytes for encryption
|
|
2094
1214
|
*/
|
|
2095
|
-
declare function
|
|
2096
|
-
leafIndex: number;
|
|
2097
|
-
}>;
|
|
2098
|
-
|
|
1215
|
+
declare function serializeUtxo(utxo: Utxo): Uint8Array;
|
|
2099
1216
|
/**
|
|
2100
|
-
*
|
|
2101
|
-
*
|
|
2102
|
-
* This tree stores all leaves and can compute the correct Merkle path
|
|
2103
|
-
* for any leaf index.
|
|
1217
|
+
* Deserialize a UTXO from bytes
|
|
2104
1218
|
*/
|
|
2105
|
-
declare
|
|
1219
|
+
declare function deserializeUtxo(bytes: Uint8Array): Promise<Utxo>;
|
|
2106
1220
|
/**
|
|
2107
|
-
*
|
|
1221
|
+
* Convert bigint to hex string (64 chars, padded)
|
|
2108
1222
|
*/
|
|
2109
|
-
declare
|
|
2110
|
-
private levels;
|
|
2111
|
-
private capacity;
|
|
2112
|
-
private layers;
|
|
2113
|
-
private zeros;
|
|
2114
|
-
private poseidon;
|
|
2115
|
-
/**
|
|
2116
|
-
* Create a new Merkle tree
|
|
2117
|
-
* @param levels Number of levels in the tree (height)
|
|
2118
|
-
* @param leaves Initial leaves to insert
|
|
2119
|
-
* @param zeros Precomputed zero values for each level
|
|
2120
|
-
* @param poseidon Pre-initialized Poseidon instance (avoids async in constructor)
|
|
2121
|
-
*/
|
|
2122
|
-
constructor(levels: number, leaves: bigint[], zeros: bigint[], poseidon: any);
|
|
2123
|
-
/**
|
|
2124
|
-
* Create a new MerkleTree with async initialization
|
|
2125
|
-
*/
|
|
2126
|
-
static create(levels?: number, leaves?: bigint[]): Promise<MerkleTree>;
|
|
2127
|
-
/**
|
|
2128
|
-
* Rebuild the tree from the leaves (synchronous — poseidon must be initialized)
|
|
2129
|
-
*/
|
|
2130
|
-
private _rebuildSync;
|
|
2131
|
-
/**
|
|
2132
|
-
* Get the tree root
|
|
2133
|
-
*/
|
|
2134
|
-
root(): bigint;
|
|
2135
|
-
/**
|
|
2136
|
-
* Get the number of leaves in the tree
|
|
2137
|
-
*/
|
|
2138
|
-
get length(): number;
|
|
2139
|
-
/**
|
|
2140
|
-
* Insert a new leaf into the tree
|
|
2141
|
-
*/
|
|
2142
|
-
insert(leaf: bigint): void;
|
|
2143
|
-
/**
|
|
2144
|
-
* Insert multiple leaves
|
|
2145
|
-
*/
|
|
2146
|
-
bulkInsert(leaves: bigint[]): void;
|
|
2147
|
-
/**
|
|
2148
|
-
* Update the path from a leaf to the root
|
|
2149
|
-
*/
|
|
2150
|
-
private _updatePath;
|
|
2151
|
-
/**
|
|
2152
|
-
* Get the Merkle path for a leaf at the given index
|
|
2153
|
-
* @param index Leaf index
|
|
2154
|
-
* @returns pathElements and pathIndices for the proof
|
|
2155
|
-
*/
|
|
2156
|
-
path(index: number): {
|
|
2157
|
-
pathElements: bigint[];
|
|
2158
|
-
pathIndices: number;
|
|
2159
|
-
};
|
|
2160
|
-
/**
|
|
2161
|
-
* Find the index of a leaf in the tree
|
|
2162
|
-
* @param leaf Leaf value to find
|
|
2163
|
-
* @returns Index if found, -1 otherwise
|
|
2164
|
-
*/
|
|
2165
|
-
indexOf(leaf: bigint): number;
|
|
2166
|
-
/**
|
|
2167
|
-
* Get all leaves
|
|
2168
|
-
*/
|
|
2169
|
-
leaves(): bigint[];
|
|
2170
|
-
}
|
|
1223
|
+
declare function bigintToHex(value: bigint): string;
|
|
2171
1224
|
/**
|
|
2172
|
-
*
|
|
2173
|
-
* @param commitments Array of commitment bigints
|
|
2174
|
-
* @param height Tree height (default: 32)
|
|
1225
|
+
* Convert hex string to bigint
|
|
2175
1226
|
*/
|
|
2176
|
-
declare function
|
|
2177
|
-
|
|
1227
|
+
declare function hexToBigint(hex: string): bigint;
|
|
2178
1228
|
/**
|
|
2179
|
-
*
|
|
1229
|
+
* Convert bigint to 32-byte array (big-endian for circuits)
|
|
2180
1230
|
*/
|
|
2181
|
-
|
|
2182
|
-
interface CommitmentEntry {
|
|
2183
|
-
index: number;
|
|
2184
|
-
commitment: string;
|
|
2185
|
-
}
|
|
2186
|
-
interface CommitmentsResponse {
|
|
2187
|
-
commitments: CommitmentEntry[];
|
|
2188
|
-
count: number;
|
|
2189
|
-
target_reached?: boolean;
|
|
2190
|
-
canonical?: boolean;
|
|
2191
|
-
canonical_reason?: string | null;
|
|
2192
|
-
}
|
|
2193
|
-
interface FetchCommitmentsOptions {
|
|
2194
|
-
mint?: PublicKey;
|
|
2195
|
-
timeoutMs?: number;
|
|
2196
|
-
maxRetries?: number;
|
|
2197
|
-
sync?: boolean;
|
|
2198
|
-
repair?: boolean;
|
|
2199
|
-
requireTarget?: boolean;
|
|
2200
|
-
requireCanonical?: boolean;
|
|
2201
|
-
fromIndex?: number;
|
|
2202
|
-
limit?: number;
|
|
2203
|
-
waitForIndex?: number;
|
|
2204
|
-
}
|
|
1231
|
+
declare function bigintToBytes32(value: bigint): Uint8Array;
|
|
2205
1232
|
/**
|
|
2206
|
-
*
|
|
2207
|
-
* @param relayUrl Base URL of the relay service (may include cache-busting query params)
|
|
2208
|
-
* @param options Timeout and retry options
|
|
2209
|
-
* @returns Array of commitment entries
|
|
1233
|
+
* Check if two UTXOs are equal (same commitment)
|
|
2210
1234
|
*/
|
|
2211
|
-
declare function
|
|
1235
|
+
declare function utxoEquals(a: Utxo, b: Utxo): Promise<boolean>;
|
|
2212
1236
|
/**
|
|
2213
|
-
*
|
|
2214
|
-
* @param relayUrl Base URL of the relay service
|
|
2215
|
-
* @param options When sync is true, triggers on-demand sync on relay before fetching (for freshness when relay is behind chain)
|
|
2216
|
-
* @returns MerkleTree instance with all commitments loaded
|
|
2217
|
-
*
|
|
2218
|
-
* Supports sparse indices by zero-filling missing leaves, including missing prefixes.
|
|
2219
|
-
* Non-contiguous gaps (e.g. 0,1,2,3,22,23,30,31,32,33) are reconstructed with
|
|
2220
|
-
* zero leaves to match the on-chain Merkle tree structure.
|
|
1237
|
+
* Calculate total amount from an array of UTXOs
|
|
2221
1238
|
*/
|
|
2222
|
-
declare function
|
|
2223
|
-
mint?: PublicKey;
|
|
2224
|
-
sync?: boolean;
|
|
2225
|
-
repair?: boolean;
|
|
2226
|
-
requireTarget?: boolean;
|
|
2227
|
-
requireCanonical?: boolean;
|
|
2228
|
-
timeoutMs?: number;
|
|
2229
|
-
maxRetries?: number;
|
|
2230
|
-
waitForIndex?: number;
|
|
2231
|
-
}): Promise<MerkleTree>;
|
|
2232
|
-
declare function buildMerkleTreeFromChain(connection: Connection, programId: PublicKey, merkleTree: PublicKey, onProgress?: (message: string) => void): Promise<MerkleTree>;
|
|
1239
|
+
declare function sumUtxoAmounts(utxos: Utxo[]): bigint;
|
|
2233
1240
|
/**
|
|
2234
|
-
*
|
|
2235
|
-
*
|
|
2236
|
-
* Validates that a Merkle root is still valid before generating a proof.
|
|
2237
|
-
* This prevents wasted time generating proofs that will fail on-chain.
|
|
1241
|
+
* Select UTXOs to cover a target amount
|
|
2238
1242
|
*
|
|
2239
|
-
* @param
|
|
2240
|
-
* @param
|
|
2241
|
-
* @returns
|
|
1243
|
+
* @param available Available UTXOs (sorted by amount descending)
|
|
1244
|
+
* @param targetAmount Target amount to cover
|
|
1245
|
+
* @returns Selected UTXOs that cover the target, or null if insufficient
|
|
2242
1246
|
*/
|
|
2243
|
-
declare function
|
|
2244
|
-
|
|
2245
|
-
currentRoot?: string;
|
|
2246
|
-
message: string;
|
|
2247
|
-
isRecent: boolean;
|
|
2248
|
-
}>;
|
|
1247
|
+
declare function selectUtxos(available: Utxo[], targetAmount: bigint): Utxo[] | null;
|
|
1248
|
+
|
|
2249
1249
|
/**
|
|
2250
|
-
*
|
|
1250
|
+
* UTXO verification — reconcile local UTXO state with on-chain nullifier state.
|
|
2251
1251
|
*
|
|
2252
|
-
*
|
|
2253
|
-
*
|
|
1252
|
+
* Shipped in 0.1.5 as the structured building block for self-repair flows.
|
|
1253
|
+
* The web app previously composed this out of lower-level SDK primitives
|
|
1254
|
+
* (`computeNullifier` + `getNullifierPDA` + `getMultipleAccountsInfo`); now
|
|
1255
|
+
* it's a first-class SDK export so callers don't re-implement the same
|
|
1256
|
+
* ~40 lines across tools.
|
|
2254
1257
|
*
|
|
2255
|
-
*
|
|
2256
|
-
*
|
|
2257
|
-
*
|
|
2258
|
-
*
|
|
2259
|
-
*
|
|
1258
|
+
* Two entry points:
|
|
1259
|
+
*
|
|
1260
|
+
* 1. `verifyUtxos(utxos, conn, programId)` — pure function. Takes a UTXO
|
|
1261
|
+
* set, does a single batched on-chain lookup of the derived nullifier
|
|
1262
|
+
* PDAs, returns `{ spent, unspent }`. Caller decides what to do.
|
|
1263
|
+
*
|
|
1264
|
+
* 2. `preflightNullifiers(utxos, conn, programId)` — thin wrapper that
|
|
1265
|
+
* throws `UtxoAlreadySpentError` if ANY input is already spent.
|
|
1266
|
+
* Intended for use at the top of spend entry points (transact,
|
|
1267
|
+
* fullWithdraw, swap) so the SDK fails fast with a structured error
|
|
1268
|
+
* instead of burning proof-gen + relay retries on a doomed tx.
|
|
1269
|
+
*
|
|
1270
|
+
* Root-caused from a production incident 2026-04-24: a user's cloak.ag
|
|
1271
|
+
* backup contained a UTXO that had been spent via another session. The
|
|
1272
|
+
* recovery tool generated a valid proof against the correct merkle tree
|
|
1273
|
+
* and submitted it; relay's simulation returned 0x1020 DoubleSpend after
|
|
1274
|
+
* 6 retries over ~60s. Pre-flight catches this class in ~200ms.
|
|
2260
1275
|
*/
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
1276
|
+
|
|
1277
|
+
/** Result of a batch verification — disjoint partition of the input set. */
|
|
1278
|
+
interface VerifyUtxosResult {
|
|
1279
|
+
/** Inputs whose nullifier PDA exists on-chain (already spent). */
|
|
1280
|
+
spent: Utxo[];
|
|
1281
|
+
/** Inputs whose nullifier PDA is absent on-chain (safe to spend). */
|
|
1282
|
+
unspent: Utxo[];
|
|
1283
|
+
/** Inputs we couldn't check — missing commitment / index / mint. */
|
|
1284
|
+
skipped: Utxo[];
|
|
1285
|
+
}
|
|
2266
1286
|
/**
|
|
2267
|
-
*
|
|
1287
|
+
* Check the on-chain nullifier PDA for each UTXO and partition by state.
|
|
2268
1288
|
*
|
|
2269
|
-
*
|
|
2270
|
-
*
|
|
2271
|
-
*
|
|
2272
|
-
*
|
|
1289
|
+
* Only UTXOs with `commitment`, `mintAddress`, AND a non-null keypair can
|
|
1290
|
+
* be verified — the nullifier derivation needs all three. UTXOs lacking any
|
|
1291
|
+
* of these go into `skipped` and the caller must decide how to treat them.
|
|
1292
|
+
* (In practice a missing `commitment` means the UTXO hasn't landed on-chain
|
|
1293
|
+
* yet — those can't be spent anyway.)
|
|
2273
1294
|
*
|
|
2274
|
-
*
|
|
2275
|
-
*
|
|
2276
|
-
*
|
|
1295
|
+
* Uses a single batched `getMultipleAccountsInfo` call for efficiency —
|
|
1296
|
+
* one round-trip regardless of UTXO count (up to Solana's 100-key cap,
|
|
1297
|
+
* beyond which we page).
|
|
1298
|
+
*
|
|
1299
|
+
* Typical latency: ~150-300ms on a healthy RPC.
|
|
2277
1300
|
*/
|
|
2278
|
-
declare function
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
1301
|
+
declare function verifyUtxos(utxos: Utxo[], connection: Connection, programId: PublicKey, commitment?: "processed" | "confirmed" | "finalized"): Promise<VerifyUtxosResult>;
|
|
1302
|
+
/**
|
|
1303
|
+
* Pre-flight gate: throw `UtxoAlreadySpentError` if any input is already
|
|
1304
|
+
* spent on-chain. Called at the top of spend entry points in core/transact.
|
|
1305
|
+
*
|
|
1306
|
+
* Browser-safe: uses one batched RPC call.
|
|
1307
|
+
*/
|
|
1308
|
+
declare function preflightNullifiers(utxos: Utxo[], connection: Connection, programId: PublicKey, commitment?: "processed" | "confirmed" | "finalized"): Promise<void>;
|
|
2284
1309
|
|
|
2285
1310
|
/**
|
|
2286
|
-
*
|
|
1311
|
+
* Structured Logger for Cloak SDK
|
|
2287
1312
|
*
|
|
2288
|
-
*
|
|
2289
|
-
*
|
|
1313
|
+
* Provides structured logging similar to Rust tracing format:
|
|
1314
|
+
* 2026-01-23T00:51:46.489317Z INFO cloak::module: 📥 Message key=value
|
|
2290
1315
|
*
|
|
2291
|
-
*
|
|
2292
|
-
*
|
|
1316
|
+
* Enable via:
|
|
1317
|
+
* - SDK config: new CloakSDK({ debug: true })
|
|
1318
|
+
* - Environment: CLOAK_DEBUG=1 or DEBUG=cloak:*
|
|
2293
1319
|
*/
|
|
2294
|
-
|
|
1320
|
+
type LogLevel = "DEBUG" | "INFO" | "WARN" | "ERROR";
|
|
2295
1321
|
/**
|
|
2296
|
-
*
|
|
2297
|
-
* Hosted in S3 and versioned by build.
|
|
1322
|
+
* Enable or disable debug logging globally
|
|
2298
1323
|
*/
|
|
2299
|
-
declare
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
out_addr: bigint[][];
|
|
2313
|
-
out_amount: bigint[];
|
|
2314
|
-
out_flags: number[];
|
|
2315
|
-
var_fee: bigint;
|
|
2316
|
-
rem: bigint;
|
|
2317
|
-
}
|
|
2318
|
-
interface WithdrawSwapInputs {
|
|
2319
|
-
sk_spend: bigint;
|
|
2320
|
-
r: bigint;
|
|
2321
|
-
amount: bigint;
|
|
2322
|
-
leaf_index: bigint;
|
|
2323
|
-
path_elements: bigint[];
|
|
2324
|
-
path_indices: number[];
|
|
2325
|
-
root: bigint;
|
|
2326
|
-
nullifier: bigint;
|
|
2327
|
-
outputs_hash: bigint;
|
|
2328
|
-
public_amount: bigint;
|
|
2329
|
-
input_mint: bigint[];
|
|
2330
|
-
output_mint: bigint[];
|
|
2331
|
-
recipient_ata: bigint[];
|
|
2332
|
-
min_output_amount: bigint;
|
|
2333
|
-
var_fee: bigint;
|
|
2334
|
-
rem: bigint;
|
|
2335
|
-
}
|
|
2336
|
-
interface ProofResult {
|
|
2337
|
-
proof: Groth16Proof;
|
|
2338
|
-
publicSignals: string[];
|
|
2339
|
-
proofBytes: Uint8Array;
|
|
2340
|
-
publicInputsBytes: Uint8Array;
|
|
1324
|
+
declare function setDebugMode(enabled: boolean): void;
|
|
1325
|
+
/**
|
|
1326
|
+
* Check if debug mode is enabled
|
|
1327
|
+
*/
|
|
1328
|
+
declare function isDebugEnabled(): boolean;
|
|
1329
|
+
/**
|
|
1330
|
+
* Logger interface
|
|
1331
|
+
*/
|
|
1332
|
+
interface Logger {
|
|
1333
|
+
debug: (message: string, kvPairs?: Record<string, unknown>) => void;
|
|
1334
|
+
info: (message: string, kvPairs?: Record<string, unknown>) => void;
|
|
1335
|
+
warn: (message: string, kvPairs?: Record<string, unknown>) => void;
|
|
1336
|
+
error: (message: string, kvPairs?: Record<string, unknown>) => void;
|
|
2341
1337
|
}
|
|
2342
1338
|
/**
|
|
2343
|
-
*
|
|
1339
|
+
* Create a logger for a specific module
|
|
2344
1340
|
*
|
|
2345
|
-
*
|
|
1341
|
+
* @param module - Module name (e.g., "cloak::sdk", "cloak::indexer")
|
|
1342
|
+
* @returns Logger instance with debug, info, warn, error methods
|
|
2346
1343
|
*
|
|
2347
|
-
* @
|
|
2348
|
-
*
|
|
1344
|
+
* @example
|
|
1345
|
+
* ```typescript
|
|
1346
|
+
* const log = createLogger("cloak::deposit");
|
|
1347
|
+
* log.info("Depositing", { amount: 100000000 });
|
|
1348
|
+
* // Output: 2026-01-23T00:51:46.489000Z INFO cloak::deposit: Depositing amount=100000000
|
|
1349
|
+
* ```
|
|
2349
1350
|
*/
|
|
2350
|
-
declare function
|
|
1351
|
+
declare function createLogger(module: string): Logger;
|
|
2351
1352
|
/**
|
|
2352
|
-
*
|
|
2353
|
-
*
|
|
2354
|
-
* This matches the approach in services-new/tests/src/proof.ts
|
|
1353
|
+
* Measure and return duration of an async operation
|
|
2355
1354
|
*
|
|
2356
|
-
* @param
|
|
2357
|
-
* @param
|
|
1355
|
+
* @param _logger - Logger instance (reserved for future debug logging)
|
|
1356
|
+
* @param _operation - Operation name (reserved for future debug logging)
|
|
1357
|
+
* @param fn - Async function to measure
|
|
1358
|
+
* @returns Result and duration in milliseconds
|
|
2358
1359
|
*/
|
|
2359
|
-
declare function
|
|
1360
|
+
declare function withTiming<T>(_logger: Logger, _operation: string, fn: () => Promise<T>): Promise<{
|
|
1361
|
+
result: T;
|
|
1362
|
+
durationMs: number;
|
|
1363
|
+
}>;
|
|
2360
1364
|
/**
|
|
2361
|
-
*
|
|
1365
|
+
* Format lamports as SOL with proper decimals
|
|
2362
1366
|
*/
|
|
2363
|
-
declare function
|
|
1367
|
+
declare function formatSol(lamports: number | bigint): string;
|
|
2364
1368
|
/**
|
|
2365
|
-
*
|
|
1369
|
+
* Truncate a string (useful for signatures, hashes)
|
|
2366
1370
|
*/
|
|
2367
|
-
declare function
|
|
1371
|
+
declare function truncate(str: string, len?: number): string;
|
|
2368
1372
|
/**
|
|
2369
|
-
*
|
|
2370
|
-
*
|
|
2371
|
-
* These hashes must be updated whenever the trusted circuit artifacts change.
|
|
1373
|
+
* Default SDK logger instance
|
|
2372
1374
|
*/
|
|
2373
|
-
declare const
|
|
2374
|
-
|
|
2375
|
-
withdraw_regular_zkey: string;
|
|
2376
|
-
withdraw_swap_wasm: string;
|
|
2377
|
-
withdraw_swap_zkey: string;
|
|
2378
|
-
};
|
|
1375
|
+
declare const sdkLogger: Logger;
|
|
1376
|
+
|
|
2379
1377
|
/**
|
|
2380
|
-
*
|
|
1378
|
+
* Result from submitting a withdrawal that includes the request ID
|
|
1379
|
+
* for potential recovery/resume scenarios
|
|
2381
1380
|
*/
|
|
2382
|
-
interface
|
|
2383
|
-
/**
|
|
2384
|
-
|
|
2385
|
-
/**
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
1381
|
+
interface WithdrawSubmissionResult {
|
|
1382
|
+
/** The relay request ID - persist this for recovery */
|
|
1383
|
+
requestId: string;
|
|
1384
|
+
/** The final transaction signature */
|
|
1385
|
+
signature: string;
|
|
1386
|
+
}
|
|
1387
|
+
/**
|
|
1388
|
+
* Relay Service Client
|
|
1389
|
+
*
|
|
1390
|
+
* Handles submission of withdrawal transactions through a relay service
|
|
1391
|
+
* that pays for transaction fees and submits the transaction on-chain.
|
|
1392
|
+
*/
|
|
1393
|
+
declare class RelayService {
|
|
1394
|
+
private baseUrl;
|
|
1395
|
+
/**
|
|
1396
|
+
* Create a new Relay Service client
|
|
1397
|
+
*
|
|
1398
|
+
* @param baseUrl - Relay service base URL
|
|
1399
|
+
*/
|
|
1400
|
+
constructor(baseUrl: string);
|
|
1401
|
+
/**
|
|
1402
|
+
* Submit a withdrawal transaction via relay
|
|
1403
|
+
*
|
|
1404
|
+
* The relay service will validate the proof, pay for transaction fees,
|
|
1405
|
+
* and submit the transaction on-chain.
|
|
1406
|
+
*
|
|
1407
|
+
* @param params - Withdrawal parameters
|
|
1408
|
+
* @param onStatusUpdate - Optional callback for status updates
|
|
1409
|
+
* @param onRequestId - CRITICAL: Callback when request_id is received.
|
|
1410
|
+
* Persist this ID to recover if browser crashes during polling.
|
|
1411
|
+
* @returns Transaction signature when completed
|
|
1412
|
+
*
|
|
1413
|
+
* @example
|
|
1414
|
+
* ```typescript
|
|
1415
|
+
* const signature = await relay.submitWithdraw({
|
|
1416
|
+
* proof: proofHex,
|
|
1417
|
+
* publicInputs: { root, nf, outputs_hash, amount },
|
|
1418
|
+
* outputs: [{ recipient: addr, amount: lamports }],
|
|
1419
|
+
* feeBps: 50
|
|
1420
|
+
* }, (status) => console.log(`Status: ${status}`),
|
|
1421
|
+
* (requestId) => localStorage.setItem('pending_withdraw', requestId));
|
|
1422
|
+
* console.log(`Transaction: ${signature}`);
|
|
1423
|
+
* ```
|
|
1424
|
+
*/
|
|
1425
|
+
submitWithdraw(params: {
|
|
1426
|
+
proof: string;
|
|
1427
|
+
publicInputs: {
|
|
1428
|
+
root: string;
|
|
1429
|
+
nf: string;
|
|
1430
|
+
outputs_hash: string;
|
|
1431
|
+
amount: number;
|
|
1432
|
+
};
|
|
1433
|
+
outputs: Array<{
|
|
1434
|
+
recipient: string;
|
|
1435
|
+
amount: number;
|
|
1436
|
+
}>;
|
|
1437
|
+
feeBps: number;
|
|
1438
|
+
metadataBundle?: EncryptedMetadataBundle;
|
|
1439
|
+
}, onStatusUpdate?: (status: string) => void, onRequestId?: (requestId: string) => void): Promise<string>;
|
|
1440
|
+
/**
|
|
1441
|
+
* Resume polling for a withdrawal that was previously started
|
|
1442
|
+
*
|
|
1443
|
+
* Use this after page reload to check status of a pending withdrawal.
|
|
1444
|
+
* The requestId should have been persisted via the onRequestId callback.
|
|
1445
|
+
*
|
|
1446
|
+
* @param requestId - Request ID from a previous submitWithdraw call
|
|
1447
|
+
* @param onStatusUpdate - Optional callback for status updates
|
|
1448
|
+
* @returns Transaction signature if completed, null if still pending/failed
|
|
1449
|
+
*
|
|
1450
|
+
* @example
|
|
1451
|
+
* ```typescript
|
|
1452
|
+
* // On page load, check for pending withdrawal
|
|
1453
|
+
* const pendingId = localStorage.getItem('pending_withdraw');
|
|
1454
|
+
* if (pendingId) {
|
|
1455
|
+
* const result = await relay.resumeWithdraw(pendingId);
|
|
1456
|
+
* if (result.status === 'completed') {
|
|
1457
|
+
* console.log('Withdrawal completed:', result.signature);
|
|
1458
|
+
* localStorage.removeItem('pending_withdraw');
|
|
1459
|
+
* }
|
|
1460
|
+
* }
|
|
1461
|
+
* ```
|
|
1462
|
+
*/
|
|
1463
|
+
resumeWithdraw(requestId: string, onStatusUpdate?: (status: string) => void): Promise<{
|
|
1464
|
+
status: 'completed' | 'failed' | 'pending';
|
|
1465
|
+
signature?: string;
|
|
1466
|
+
error?: string;
|
|
1467
|
+
}>;
|
|
1468
|
+
/**
|
|
1469
|
+
* Poll for withdrawal completion
|
|
1470
|
+
*
|
|
1471
|
+
* @param requestId - Request ID from relay service
|
|
1472
|
+
* @param onStatusUpdate - Optional callback for status updates
|
|
1473
|
+
* @returns Transaction signature when completed
|
|
1474
|
+
*/
|
|
1475
|
+
private pollForCompletion;
|
|
1476
|
+
/**
|
|
1477
|
+
* Submit a swap transaction via relay
|
|
1478
|
+
*
|
|
1479
|
+
* Similar to submitWithdraw but includes swap parameters for token swaps.
|
|
1480
|
+
* The relay service will validate the proof, execute the swap, pay for fees,
|
|
1481
|
+
* and submit the transaction on-chain.
|
|
1482
|
+
*
|
|
1483
|
+
* @param params - Swap parameters
|
|
1484
|
+
* @param onStatusUpdate - Optional callback for status updates
|
|
1485
|
+
* @returns Transaction signature when completed
|
|
1486
|
+
*
|
|
1487
|
+
* @example
|
|
1488
|
+
* ```typescript
|
|
1489
|
+
* const signature = await relay.submitSwap({
|
|
1490
|
+
* proof: proofHex,
|
|
1491
|
+
* publicInputs: { root, nf, outputs_hash, amount },
|
|
1492
|
+
* outputs: [{ recipient: addr, amount: lamports }],
|
|
1493
|
+
* feeBps: 50,
|
|
1494
|
+
* swap: {
|
|
1495
|
+
* output_mint: tokenMint.toBase58(),
|
|
1496
|
+
* slippage_bps: 100,
|
|
1497
|
+
* min_output_amount: minAmount
|
|
1498
|
+
* }
|
|
1499
|
+
* }, (status) => console.log(`Status: ${status}`));
|
|
1500
|
+
* console.log(`Transaction: ${signature}`);
|
|
1501
|
+
* ```
|
|
1502
|
+
*/
|
|
1503
|
+
submitSwap(params: {
|
|
1504
|
+
proof: string;
|
|
1505
|
+
publicInputs: {
|
|
1506
|
+
root: string;
|
|
1507
|
+
nf: string;
|
|
1508
|
+
outputs_hash: string;
|
|
1509
|
+
amount: number;
|
|
1510
|
+
};
|
|
1511
|
+
outputs: Array<{
|
|
1512
|
+
recipient: string;
|
|
1513
|
+
amount: number;
|
|
1514
|
+
}>;
|
|
1515
|
+
feeBps: number;
|
|
1516
|
+
swap: {
|
|
1517
|
+
output_mint: string;
|
|
1518
|
+
slippage_bps: number;
|
|
1519
|
+
min_output_amount: number;
|
|
1520
|
+
};
|
|
1521
|
+
metadataBundle?: EncryptedMetadataBundle;
|
|
1522
|
+
}, onStatusUpdate?: (status: string) => void, onRequestId?: (requestId: string) => void): Promise<string>;
|
|
1523
|
+
/**
|
|
1524
|
+
* Get transaction status
|
|
1525
|
+
*
|
|
1526
|
+
* @param requestId - Request ID from previous submission
|
|
1527
|
+
* @returns Current status
|
|
1528
|
+
*
|
|
1529
|
+
* @example
|
|
1530
|
+
* ```typescript
|
|
1531
|
+
* const status = await relay.getStatus(requestId);
|
|
1532
|
+
* console.log(`Status: ${status.status}`);
|
|
1533
|
+
* if (status.status === 'completed') {
|
|
1534
|
+
* console.log(`TX: ${status.txId}`);
|
|
1535
|
+
* }
|
|
1536
|
+
* ```
|
|
1537
|
+
*/
|
|
1538
|
+
getStatus(requestId: string): Promise<TxStatus>;
|
|
1539
|
+
/**
|
|
1540
|
+
* Register viewing key with relay for compliance decryption.
|
|
1541
|
+
* This is a one-time operation - the viewing key is stored by the relay.
|
|
1542
|
+
*
|
|
1543
|
+
* The user must sign a one-time relay challenge proving wallet ownership.
|
|
1544
|
+
*
|
|
1545
|
+
* @param userPubkey - User's wallet public key (base58)
|
|
1546
|
+
* @param viewingKey - Viewing key private key (32 bytes, hex encoded)
|
|
1547
|
+
* @param signMessage - Function to sign challenge message bytes
|
|
1548
|
+
*
|
|
1549
|
+
* @example
|
|
1550
|
+
* ```typescript
|
|
1551
|
+
* await relay.registerViewingKey(
|
|
1552
|
+
* userPublicKey.toBase58(),
|
|
1553
|
+
* viewingKeyHex,
|
|
1554
|
+
* signatureBase64
|
|
1555
|
+
* );
|
|
1556
|
+
* ```
|
|
1557
|
+
*/
|
|
1558
|
+
registerViewingKey(userPubkey: string, viewingKey: string, signMessage: (message: Uint8Array) => Promise<Uint8Array>): Promise<boolean>;
|
|
1559
|
+
/**
|
|
1560
|
+
* Fetch relay compliance master public key.
|
|
1561
|
+
* DEPRECATED: This endpoint is no longer used
|
|
1562
|
+
*/
|
|
1563
|
+
getCompliancePublicKey(): Promise<Uint8Array>;
|
|
1564
|
+
/**
|
|
1565
|
+
* Convert bytes to base64 string
|
|
1566
|
+
*/
|
|
1567
|
+
private bytesToBase64;
|
|
1568
|
+
/**
|
|
1569
|
+
* Sleep utility
|
|
1570
|
+
*/
|
|
1571
|
+
private sleep;
|
|
1572
|
+
private computeViewingKeyIdentifier;
|
|
2397
1573
|
}
|
|
1574
|
+
|
|
2398
1575
|
/**
|
|
2399
|
-
*
|
|
2400
|
-
*
|
|
2401
|
-
* This function fetches the verification key and computes its hash,
|
|
2402
|
-
* then compares against the expected hash embedded in the SDK.
|
|
2403
|
-
*
|
|
2404
|
-
* IMPORTANT: If the hashes don't match, the circuit may produce proofs
|
|
2405
|
-
* that will be rejected by the on-chain verifier!
|
|
2406
|
-
*
|
|
2407
|
-
* @param circuitsPath - Ignored. Verification always uses pinned S3 circuits.
|
|
2408
|
-
* @param circuit - Which circuit to verify ('withdraw_regular' or 'withdraw_swap')
|
|
2409
|
-
* @returns Verification result
|
|
1576
|
+
* Risk Oracle Service
|
|
2410
1577
|
*
|
|
2411
|
-
*
|
|
2412
|
-
*
|
|
2413
|
-
*
|
|
2414
|
-
* if (!result.valid) {
|
|
2415
|
-
* console.error('Circuit verification failed:', result.error);
|
|
2416
|
-
* // Don't proceed with proof generation!
|
|
2417
|
-
* }
|
|
2418
|
-
* ```
|
|
2419
|
-
*/
|
|
2420
|
-
declare function verifyCircuitIntegrity(circuitsPath: string, circuit: 'withdraw_regular' | 'withdraw_swap'): Promise<CircuitVerificationResult>;
|
|
2421
|
-
/**
|
|
2422
|
-
* Verify all circuits before use
|
|
1578
|
+
* Self-contained module for fetching Switchboard risk quote instructions
|
|
1579
|
+
* using the Range Risk API. Eliminates the need for an external web endpoint
|
|
1580
|
+
* (e.g. `/api/risk-quote`) by calling Switchboard directly from the SDK.
|
|
2423
1581
|
*
|
|
2424
|
-
*
|
|
1582
|
+
* Uses dynamic imports for @switchboard-xyz packages so they are only loaded
|
|
1583
|
+
* when fetchRiskQuoteIx is actually called — not at SDK import time. This
|
|
1584
|
+
* prevents the heavy Node.js-only Switchboard code from being bundled into
|
|
1585
|
+
* browser builds (Next.js, etc.).
|
|
2425
1586
|
*
|
|
2426
|
-
*
|
|
2427
|
-
*
|
|
1587
|
+
* Usage:
|
|
1588
|
+
* const { instruction, queue } = await fetchRiskQuoteIx(connection, wallet, rangeApiKey);
|
|
2428
1589
|
*/
|
|
2429
|
-
declare function verifyAllCircuits(circuitsPath: string): Promise<CircuitVerificationResult[]>;
|
|
2430
1590
|
|
|
2431
1591
|
/**
|
|
2432
|
-
*
|
|
2433
|
-
*
|
|
2434
|
-
* Utility for persisting pending deposit/withdrawal operations in browser storage.
|
|
2435
|
-
* This enables recovery if the browser crashes or user navigates away mid-operation.
|
|
1592
|
+
* Fetch a Switchboard risk quote instruction directly from Range + Switchboard.
|
|
2436
1593
|
*
|
|
2437
|
-
*
|
|
2438
|
-
*
|
|
2439
|
-
* in production (e.g., encrypted IndexedDB, secure enclave).
|
|
2440
|
-
*/
|
|
2441
|
-
|
|
2442
|
-
/**
|
|
2443
|
-
* Pending deposit record
|
|
2444
|
-
*/
|
|
2445
|
-
interface PendingDeposit {
|
|
2446
|
-
/** The note (contains spending secrets!) */
|
|
2447
|
-
note: CloakNote;
|
|
2448
|
-
/** When the deposit was initiated */
|
|
2449
|
-
startedAt: number;
|
|
2450
|
-
/** Transaction signature if available */
|
|
2451
|
-
txSignature?: string;
|
|
2452
|
-
/** Status of the deposit */
|
|
2453
|
-
status: "pending" | "tx_sent" | "confirmed" | "failed";
|
|
2454
|
-
/** Error message if failed */
|
|
2455
|
-
error?: string;
|
|
2456
|
-
}
|
|
2457
|
-
/**
|
|
2458
|
-
* Pending withdrawal record
|
|
2459
|
-
*/
|
|
2460
|
-
interface PendingWithdrawal {
|
|
2461
|
-
/** The relay request ID (for resumption) */
|
|
2462
|
-
requestId: string;
|
|
2463
|
-
/** The note commitment being withdrawn */
|
|
2464
|
-
commitment: string;
|
|
2465
|
-
/** The nullifier being used */
|
|
2466
|
-
nullifier: string;
|
|
2467
|
-
/** When the withdrawal was initiated */
|
|
2468
|
-
startedAt: number;
|
|
2469
|
-
/** Status of the withdrawal */
|
|
2470
|
-
status: "pending" | "processing" | "completed" | "failed";
|
|
2471
|
-
/** Transaction signature if completed */
|
|
2472
|
-
txSignature?: string;
|
|
2473
|
-
/** Error message if failed */
|
|
2474
|
-
error?: string;
|
|
2475
|
-
}
|
|
2476
|
-
/**
|
|
2477
|
-
* Save a pending deposit
|
|
2478
|
-
* Call this BEFORE sending the on-chain transaction to ensure note is persisted
|
|
2479
|
-
*/
|
|
2480
|
-
declare function savePendingDeposit(deposit: PendingDeposit): void;
|
|
2481
|
-
/**
|
|
2482
|
-
* Load all pending deposits
|
|
2483
|
-
*/
|
|
2484
|
-
declare function loadPendingDeposits(): PendingDeposit[];
|
|
2485
|
-
/**
|
|
2486
|
-
* Update a pending deposit status
|
|
2487
|
-
*/
|
|
2488
|
-
declare function updatePendingDeposit(commitment: string, updates: Partial<PendingDeposit>): void;
|
|
2489
|
-
/**
|
|
2490
|
-
* Remove a pending deposit (e.g., after successful confirmation)
|
|
2491
|
-
*/
|
|
2492
|
-
declare function removePendingDeposit(commitment: string): void;
|
|
2493
|
-
/**
|
|
2494
|
-
* Clear all pending deposits
|
|
2495
|
-
*/
|
|
2496
|
-
declare function clearPendingDeposits(): void;
|
|
2497
|
-
/**
|
|
2498
|
-
* Save a pending withdrawal
|
|
2499
|
-
* Call this when you receive the request_id from the relay
|
|
2500
|
-
*/
|
|
2501
|
-
declare function savePendingWithdrawal(withdrawal: PendingWithdrawal): void;
|
|
2502
|
-
/**
|
|
2503
|
-
* Load all pending withdrawals
|
|
2504
|
-
*/
|
|
2505
|
-
declare function loadPendingWithdrawals(): PendingWithdrawal[];
|
|
2506
|
-
/**
|
|
2507
|
-
* Update a pending withdrawal status
|
|
2508
|
-
*/
|
|
2509
|
-
declare function updatePendingWithdrawal(requestId: string, updates: Partial<PendingWithdrawal>): void;
|
|
2510
|
-
/**
|
|
2511
|
-
* Remove a pending withdrawal (e.g., after successful completion)
|
|
2512
|
-
*/
|
|
2513
|
-
declare function removePendingWithdrawal(requestId: string): void;
|
|
2514
|
-
/**
|
|
2515
|
-
* Clear all pending withdrawals
|
|
2516
|
-
*/
|
|
2517
|
-
declare function clearPendingWithdrawals(): void;
|
|
2518
|
-
/**
|
|
2519
|
-
* Check if there are any pending operations that need recovery
|
|
2520
|
-
* Call this on page load to determine if recovery UI should be shown
|
|
2521
|
-
*/
|
|
2522
|
-
declare function hasPendingOperations(): boolean;
|
|
2523
|
-
/**
|
|
2524
|
-
* Get summary of pending operations for recovery UI
|
|
2525
|
-
*/
|
|
2526
|
-
declare function getPendingOperationsSummary(): {
|
|
2527
|
-
deposits: PendingDeposit[];
|
|
2528
|
-
withdrawals: PendingWithdrawal[];
|
|
2529
|
-
totalPending: number;
|
|
2530
|
-
};
|
|
2531
|
-
/**
|
|
2532
|
-
* Clean up stale pending operations
|
|
2533
|
-
* Call this periodically to remove old failed/completed operations
|
|
1594
|
+
* This removes the need for an external `/api/risk-quote` endpoint. The SDK
|
|
1595
|
+
* calls Switchboard's crossbar oracle network directly with the Range API key.
|
|
2534
1596
|
*
|
|
2535
|
-
* @param
|
|
1597
|
+
* @param connection - Solana RPC connection
|
|
1598
|
+
* @param wallet - Depositor's public key (the wallet being risk-scored)
|
|
1599
|
+
* @param rangeApiKey - Range.org API key for the risk score lookup
|
|
1600
|
+
* @returns The Ed25519 sig-verify instruction to prepend at index 0, plus the queue pubkey
|
|
2536
1601
|
*/
|
|
2537
|
-
declare function
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
}
|
|
1602
|
+
declare function fetchRiskQuoteIx(connection: Connection, wallet: PublicKey, rangeApiKey: string): Promise<{
|
|
1603
|
+
instruction: TransactionInstruction;
|
|
1604
|
+
queue: PublicKey;
|
|
1605
|
+
}>;
|
|
2541
1606
|
|
|
2542
1607
|
/**
|
|
2543
|
-
*
|
|
1608
|
+
* Wallet Integration Helpers
|
|
2544
1609
|
*
|
|
2545
|
-
*
|
|
2546
|
-
* UTXOs allow for:
|
|
2547
|
-
* - Shield-to-shield transfers (privacy preserved)
|
|
2548
|
-
* - Partial withdrawals (change stays shielded)
|
|
2549
|
-
* - Combining multiple small deposits
|
|
2550
|
-
* - Multi-token support (SOL + any SPL token)
|
|
1610
|
+
* Helper functions for working with Solana Wallet Adapters
|
|
2551
1611
|
*/
|
|
2552
1612
|
|
|
2553
|
-
declare const NATIVE_SOL_MINT: PublicKey;
|
|
2554
|
-
/**
|
|
2555
|
-
* UTXO Keypair for ownership verification
|
|
2556
|
-
*
|
|
2557
|
-
* Uses Poseidon hash for key derivation:
|
|
2558
|
-
* - privateKey: random field element (kept secret)
|
|
2559
|
-
* - publicKey: Poseidon(privateKey, 0) - can be shared
|
|
2560
|
-
*/
|
|
2561
|
-
interface UtxoKeypair {
|
|
2562
|
-
/** Private key (random 252-bit field element) */
|
|
2563
|
-
privateKey: bigint;
|
|
2564
|
-
/** Public key derived as Poseidon(privateKey, 0) */
|
|
2565
|
-
publicKey: bigint;
|
|
2566
|
-
}
|
|
2567
|
-
/**
|
|
2568
|
-
* UTXO represents an unspent transaction output
|
|
2569
|
-
*
|
|
2570
|
-
* Contains all information needed to spend the UTXO:
|
|
2571
|
-
* - amount: Value in the smallest unit (lamports for SOL)
|
|
2572
|
-
* - keypair: Ownership keys
|
|
2573
|
-
* - blinding: Randomness for hiding
|
|
2574
|
-
* - mintAddress: Token type (SOL or SPL token)
|
|
2575
|
-
* - index: Leaf index in Merkle tree (set after deposit/creation)
|
|
2576
|
-
*/
|
|
2577
|
-
interface Utxo {
|
|
2578
|
-
/** Amount in the smallest unit (lamports for SOL, token units for SPL) */
|
|
2579
|
-
amount: bigint;
|
|
2580
|
-
/** Keypair for ownership */
|
|
2581
|
-
keypair: UtxoKeypair;
|
|
2582
|
-
/** Random blinding factor */
|
|
2583
|
-
blinding: bigint;
|
|
2584
|
-
/** Token mint address (NATIVE_SOL_MINT for SOL) */
|
|
2585
|
-
mintAddress: PublicKey;
|
|
2586
|
-
/** Leaf index in Merkle tree (set after the UTXO is in the tree) */
|
|
2587
|
-
index?: number;
|
|
2588
|
-
/** Commitment hash (computed from amount, pubkey, blinding, mint) */
|
|
2589
|
-
commitment?: bigint;
|
|
2590
|
-
/** Nullifier hash (computed when spending) */
|
|
2591
|
-
nullifier?: bigint;
|
|
2592
|
-
/**
|
|
2593
|
-
* Sibling commitment at level 0 of the Merkle tree.
|
|
2594
|
-
* Required for Merkle proofs since siblings aren't stored on-chain.
|
|
2595
|
-
* This is the commitment of the other output in the same transaction.
|
|
2596
|
-
*/
|
|
2597
|
-
siblingCommitment?: bigint;
|
|
2598
|
-
}
|
|
2599
|
-
/**
|
|
2600
|
-
* Encrypted UTXO note for recipient discovery
|
|
2601
|
-
*
|
|
2602
|
-
* When creating an output UTXO for someone else, the data is encrypted
|
|
2603
|
-
* so only the recipient can discover and spend it.
|
|
2604
|
-
*/
|
|
2605
|
-
interface EncryptedNote {
|
|
2606
|
-
/** Encrypted UTXO data (ECIES/ChaCha20 encrypted) */
|
|
2607
|
-
ciphertext: Uint8Array;
|
|
2608
|
-
/** Ephemeral public key for ECDH */
|
|
2609
|
-
ephemeralPubkey: Uint8Array;
|
|
2610
|
-
/** MAC for integrity verification */
|
|
2611
|
-
mac: Uint8Array;
|
|
2612
|
-
}
|
|
2613
|
-
/**
|
|
2614
|
-
* Transaction parameters for a UTXO transaction
|
|
2615
|
-
*/
|
|
2616
|
-
interface TransactParams {
|
|
2617
|
-
/** Input UTXOs to spend (max 2) */
|
|
2618
|
-
inputUtxos: Utxo[];
|
|
2619
|
-
/** Output UTXOs to create (max 2) */
|
|
2620
|
-
outputUtxos: Utxo[];
|
|
2621
|
-
/** External recipient for withdrawal (optional) */
|
|
2622
|
-
recipient?: PublicKey;
|
|
2623
|
-
/** Net external amount: positive = deposit, negative = withdraw */
|
|
2624
|
-
externalAmount?: bigint;
|
|
2625
|
-
/** Depositor address (for deposits, the source of funds) */
|
|
2626
|
-
depositor?: PublicKey;
|
|
2627
|
-
}
|
|
2628
1613
|
/**
|
|
2629
|
-
*
|
|
1614
|
+
* Validate wallet is connected and has public key
|
|
2630
1615
|
*/
|
|
2631
|
-
|
|
2632
|
-
/** Transaction signature */
|
|
2633
|
-
signature: string;
|
|
2634
|
-
/** Nullifiers of spent inputs */
|
|
2635
|
-
inputNullifiers: bigint[];
|
|
2636
|
-
/** Commitments of created outputs */
|
|
2637
|
-
outputCommitments: bigint[];
|
|
2638
|
-
/** New Merkle root after the transaction */
|
|
2639
|
-
newRoot: string;
|
|
2640
|
-
/** Merkle tree indices where output commitments were inserted */
|
|
2641
|
-
commitmentIndices: [number, number];
|
|
2642
|
-
/**
|
|
2643
|
-
* Sibling commitments for each output.
|
|
2644
|
-
* For output[0], sibling is output[1] and vice versa.
|
|
2645
|
-
* These are needed for Merkle proofs since siblings aren't stored on-chain.
|
|
2646
|
-
*/
|
|
2647
|
-
siblingCommitments: [bigint, bigint];
|
|
2648
|
-
/**
|
|
2649
|
-
* Left sibling from before the transaction (for odd-index handling).
|
|
2650
|
-
* When the first output ends up at an odd index due to concurrent access,
|
|
2651
|
-
* its sibling at index-1 comes from a previous transaction.
|
|
2652
|
-
* This value captures subtrees[0] before our transaction to enable
|
|
2653
|
-
* correct Merkle proof computation for odd indices.
|
|
2654
|
-
*/
|
|
2655
|
-
preTransactionLeftSibling?: bigint;
|
|
2656
|
-
/**
|
|
2657
|
-
* The actual output UTXOs created by this transaction.
|
|
2658
|
-
* These have all the data needed to spend them later (keypair, blinding, etc).
|
|
2659
|
-
* The UTXOs are already updated with their indices and sibling commitments.
|
|
2660
|
-
*/
|
|
2661
|
-
outputUtxos: Utxo[];
|
|
2662
|
-
/**
|
|
2663
|
-
* Whether the viewing key was registered with the relay for compliance.
|
|
2664
|
-
* True on first transaction when metadataBundle includes viewing_key.
|
|
2665
|
-
* Once registered, subsequent transactions don't need to send metadataBundle.
|
|
2666
|
-
*/
|
|
2667
|
-
viewingKeyRegistered?: boolean;
|
|
2668
|
-
/**
|
|
2669
|
-
* The Merkle tree used/built for this transaction, with output commitments inserted.
|
|
2670
|
-
* Pass this as `cachedMerkleTree` in the next transaction to skip relay fetching
|
|
2671
|
-
* and avoid needing `waitForCommitmentIndex`.
|
|
2672
|
-
*/
|
|
2673
|
-
merkleTree?: MerkleTree;
|
|
2674
|
-
/**
|
|
2675
|
-
* Address lookup table used for v0 transaction (when chain notes or risk oracle require it).
|
|
2676
|
-
* Pass this as `addressLookupTableAccounts` in the next deposit to avoid creating a new ALT.
|
|
2677
|
-
*/
|
|
2678
|
-
addressLookupTableAccounts?: AddressLookupTableAccount[];
|
|
2679
|
-
}
|
|
1616
|
+
declare function validateWalletConnected(wallet: WalletAdapter | Keypair): void;
|
|
2680
1617
|
/**
|
|
2681
|
-
*
|
|
1618
|
+
* Get public key from wallet or keypair
|
|
2682
1619
|
*/
|
|
2683
|
-
declare function
|
|
1620
|
+
declare function getPublicKey(wallet: WalletAdapter | Keypair): PublicKey;
|
|
2684
1621
|
/**
|
|
2685
|
-
*
|
|
2686
|
-
*
|
|
2687
|
-
* @returns A new keypair with random private key and derived public key
|
|
1622
|
+
* Send transaction using wallet adapter or keypair
|
|
2688
1623
|
*/
|
|
2689
|
-
declare function
|
|
1624
|
+
declare function sendTransaction(transaction: Transaction, wallet: WalletAdapter | Keypair, connection: Connection, options?: SendOptions): Promise<string>;
|
|
2690
1625
|
/**
|
|
2691
|
-
*
|
|
2692
|
-
* Use this for deposits and change outputs so all chain notes use the same nk,
|
|
2693
|
-
* enabling the compliance scan (scanTransactions + toComplianceReport) to decrypt them.
|
|
2694
|
-
*
|
|
2695
|
-
* @param skSpend - 32-byte spend key (from wallet key derivation)
|
|
2696
|
-
* @returns UtxoKeypair with deterministic private/public keys
|
|
1626
|
+
* Sign transaction using wallet adapter or keypair
|
|
2697
1627
|
*/
|
|
2698
|
-
declare function
|
|
1628
|
+
declare function signTransaction<T extends Transaction>(transaction: T, wallet: WalletAdapter | Keypair): Promise<T>;
|
|
2699
1629
|
/**
|
|
2700
|
-
*
|
|
2701
|
-
*
|
|
2702
|
-
* @param privateKey The private key
|
|
2703
|
-
* @returns The corresponding public key
|
|
1630
|
+
* Create a keypair adapter for testing
|
|
2704
1631
|
*/
|
|
2705
|
-
declare function
|
|
1632
|
+
declare function keypairToAdapter(keypair: Keypair): WalletAdapter;
|
|
1633
|
+
|
|
2706
1634
|
/**
|
|
2707
|
-
*
|
|
1635
|
+
* Program Derived Address (PDA) utilities for Shield Pool
|
|
2708
1636
|
*
|
|
2709
|
-
*
|
|
2710
|
-
*
|
|
2711
|
-
* @param mintAddress Token mint (defaults to native SOL)
|
|
2712
|
-
* @returns A new UTXO (commitment will be computed)
|
|
1637
|
+
* These functions derive deterministic addresses from the program ID and seeds.
|
|
1638
|
+
* This matches the behavior in tooling/test/src/shared.rs::get_pda_addresses()
|
|
2713
1639
|
*/
|
|
2714
|
-
|
|
1640
|
+
|
|
1641
|
+
interface ShieldPoolPDAs {
|
|
1642
|
+
pool: PublicKey;
|
|
1643
|
+
merkleTree: PublicKey;
|
|
1644
|
+
vaultAuthority: PublicKey;
|
|
1645
|
+
treasury: PublicKey;
|
|
1646
|
+
}
|
|
2715
1647
|
/**
|
|
2716
|
-
*
|
|
1648
|
+
* Derive all Shield Pool PDAs from program ID + pool mint
|
|
2717
1649
|
*
|
|
2718
|
-
*
|
|
2719
|
-
*
|
|
2720
|
-
*
|
|
2721
|
-
*
|
|
2722
|
-
*
|
|
1650
|
+
* Seeds match the on-chain mint-scoped program:
|
|
1651
|
+
* - pool: [b"pool", mint]
|
|
1652
|
+
* - merkle_tree: [b"merkle_tree", mint]
|
|
1653
|
+
* - treasury: [b"treasury", mint]
|
|
1654
|
+
* - vault_authority: [b"vault_authority", mint]
|
|
2723
1655
|
*
|
|
2724
|
-
* @param
|
|
2725
|
-
* @param
|
|
1656
|
+
* @param programId - Optional program ID (defaults to CLOAK_PROGRAM_ID)
|
|
1657
|
+
* @param mint - Pool mint (defaults to NATIVE_SOL_MINT / WSOL sentinel)
|
|
2726
1658
|
*/
|
|
2727
|
-
declare function
|
|
1659
|
+
declare function getShieldPoolPDAs(programId?: PublicKey, mint?: PublicKey): ShieldPoolPDAs;
|
|
2728
1660
|
/**
|
|
2729
|
-
*
|
|
1661
|
+
* Derive the nullifier PDA for a specific pool + nullifier hash.
|
|
2730
1662
|
*
|
|
2731
|
-
*
|
|
2732
|
-
*
|
|
1663
|
+
* With the new PDA-per-nullifier design, each nullifier has its own PDA
|
|
1664
|
+
* instead of being stored in a shared shard. The PDA is created when
|
|
1665
|
+
* the nullifier is used during withdrawal.
|
|
1666
|
+
*
|
|
1667
|
+
* Seeds: ["nullifier", pool_pubkey, nullifier_hash]
|
|
1668
|
+
*
|
|
1669
|
+
* @param poolPubkey - Pool PDA that scopes nullifier domain
|
|
1670
|
+
* @param nullifier - 32-byte nullifier hash
|
|
1671
|
+
* @param programId - Optional program ID (defaults to CLOAK_PROGRAM_ID)
|
|
1672
|
+
* @returns [PublicKey, bump] - The nullifier PDA and its bump seed
|
|
2733
1673
|
*/
|
|
2734
|
-
declare function
|
|
1674
|
+
declare function getNullifierPDA(poolPubkey: PublicKey, nullifier: Uint8Array | Buffer, programId?: PublicKey): [PublicKey, number];
|
|
2735
1675
|
/**
|
|
2736
|
-
*
|
|
1676
|
+
* Derive the swap state PDA for a given pool + nullifier.
|
|
2737
1677
|
*
|
|
2738
|
-
*
|
|
1678
|
+
* Seeds: ["swap_state", pool_pubkey, nullifier_hash]
|
|
2739
1679
|
*
|
|
2740
|
-
* @param
|
|
2741
|
-
* @
|
|
1680
|
+
* @param poolPubkey - Pool PDA used for swap state domain separation
|
|
1681
|
+
* @param nullifier - 32-byte nullifier hash
|
|
1682
|
+
* @param programId - Optional program ID (defaults to CLOAK_PROGRAM_ID)
|
|
1683
|
+
* @returns [PublicKey, bump] - The swap state PDA and its bump seed
|
|
2742
1684
|
*/
|
|
2743
|
-
declare function
|
|
1685
|
+
declare function getSwapStatePDA(poolPubkey: PublicKey, nullifier: Uint8Array | Buffer, programId?: PublicKey): [PublicKey, number];
|
|
1686
|
+
|
|
2744
1687
|
/**
|
|
2745
|
-
*
|
|
2746
|
-
*
|
|
2747
|
-
* signature = Poseidon(privateKey, commitment, pathIndex)
|
|
1688
|
+
* On-chain Merkle proof computation
|
|
2748
1689
|
*
|
|
2749
|
-
*
|
|
2750
|
-
*
|
|
2751
|
-
* @param pathIndex Merkle tree path index
|
|
2752
|
-
* @returns The signature
|
|
1690
|
+
* Computes Merkle proofs directly from on-chain tree state,
|
|
1691
|
+
* eliminating the need for an indexer for proof generation.
|
|
2753
1692
|
*/
|
|
2754
|
-
|
|
1693
|
+
|
|
2755
1694
|
/**
|
|
2756
|
-
*
|
|
1695
|
+
* Merkle proof result
|
|
1696
|
+
*/
|
|
1697
|
+
interface OnchainMerkleProof {
|
|
1698
|
+
pathElements: string[];
|
|
1699
|
+
pathIndices: number[];
|
|
1700
|
+
root: string;
|
|
1701
|
+
}
|
|
1702
|
+
interface MerkleTreeState {
|
|
1703
|
+
nextIndex: number;
|
|
1704
|
+
root: string;
|
|
1705
|
+
subtrees: string[];
|
|
1706
|
+
}
|
|
1707
|
+
/**
|
|
1708
|
+
* Read the Merkle tree state from on-chain account
|
|
1709
|
+
* @param forceConfirmed - If true, forces "confirmed" commitment level for fresh data
|
|
1710
|
+
* @param relayUrl - Optional relay URL to query for current root (bypasses RPC caching)
|
|
1711
|
+
* @param mint - Optional pool mint used when querying relay /merkle-root
|
|
1712
|
+
*/
|
|
1713
|
+
declare function readMerkleTreeState(connection: Connection, merkleTreePDA: PublicKey, forceConfirmed?: boolean, relayUrl?: string,
|
|
1714
|
+
/** When true, skip relay root and use chain directly (avoids stale relay root causing ProofInvalid) */
|
|
1715
|
+
skipRelayRoot?: boolean, mint?: PublicKey): Promise<MerkleTreeState>;
|
|
1716
|
+
/**
|
|
1717
|
+
* Compute Merkle proof for a leaf at a given index using on-chain state
|
|
2757
1718
|
*
|
|
2758
|
-
*
|
|
1719
|
+
* This works by:
|
|
1720
|
+
* 1. Reading the subtrees (frontier) from the on-chain account
|
|
1721
|
+
* 2. For each level, determining the sibling:
|
|
1722
|
+
* - If index is odd: sibling is the stored subtree (left sibling)
|
|
1723
|
+
* - If index is even: sibling is either a subsequent subtree or zero value
|
|
2759
1724
|
*
|
|
2760
|
-
*
|
|
2761
|
-
*
|
|
1725
|
+
* Note: This works best for recent leaves where siblings are zero values.
|
|
1726
|
+
* For older leaves with non-zero siblings that aren't stored in subtrees,
|
|
1727
|
+
* an indexer may still be needed.
|
|
2762
1728
|
*
|
|
2763
|
-
* @param
|
|
2764
|
-
* @
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
* Serialize a UTXO to bytes for encryption
|
|
1729
|
+
* @param connection - Solana connection
|
|
1730
|
+
* @param merkleTreePDA - PDA of the merkle tree account
|
|
1731
|
+
* @param leafIndex - Index of the leaf to compute proof for
|
|
1732
|
+
* @param forceConfirmed - If true, forces "confirmed" commitment level for fresh data
|
|
1733
|
+
* @returns Merkle proof with path elements and indices
|
|
2769
1734
|
*/
|
|
2770
|
-
declare function
|
|
1735
|
+
declare function computeProofFromChain(connection: Connection, merkleTreePDA: PublicKey, leafIndex: number, forceConfirmed?: boolean): Promise<OnchainMerkleProof>;
|
|
2771
1736
|
/**
|
|
2772
|
-
*
|
|
1737
|
+
* Compute proof for the most recently inserted leaf
|
|
1738
|
+
*
|
|
1739
|
+
* This is the most reliable case - immediately after your deposit,
|
|
1740
|
+
* all siblings to the right are zero values, and siblings to the left
|
|
1741
|
+
* are stored in the subtrees.
|
|
2773
1742
|
*/
|
|
2774
|
-
declare function
|
|
1743
|
+
declare function computeProofForLatestDeposit(connection: Connection, merkleTreePDA: PublicKey): Promise<OnchainMerkleProof & {
|
|
1744
|
+
leafIndex: number;
|
|
1745
|
+
}>;
|
|
1746
|
+
|
|
2775
1747
|
/**
|
|
2776
|
-
*
|
|
1748
|
+
* Relay client utilities for fetching data from the relay service
|
|
2777
1749
|
*/
|
|
2778
|
-
|
|
1750
|
+
|
|
1751
|
+
interface CommitmentEntry {
|
|
1752
|
+
index: number;
|
|
1753
|
+
commitment: string;
|
|
1754
|
+
}
|
|
1755
|
+
interface CommitmentsResponse {
|
|
1756
|
+
commitments: CommitmentEntry[];
|
|
1757
|
+
count: number;
|
|
1758
|
+
target_reached?: boolean;
|
|
1759
|
+
canonical?: boolean;
|
|
1760
|
+
canonical_reason?: string | null;
|
|
1761
|
+
}
|
|
1762
|
+
interface FetchCommitmentsOptions {
|
|
1763
|
+
mint?: PublicKey;
|
|
1764
|
+
timeoutMs?: number;
|
|
1765
|
+
maxRetries?: number;
|
|
1766
|
+
sync?: boolean;
|
|
1767
|
+
repair?: boolean;
|
|
1768
|
+
requireTarget?: boolean;
|
|
1769
|
+
requireCanonical?: boolean;
|
|
1770
|
+
fromIndex?: number;
|
|
1771
|
+
limit?: number;
|
|
1772
|
+
waitForIndex?: number;
|
|
1773
|
+
}
|
|
2779
1774
|
/**
|
|
2780
|
-
*
|
|
1775
|
+
* Fetch all commitments from the relay
|
|
1776
|
+
* @param relayUrl Base URL of the relay service (may include cache-busting query params)
|
|
1777
|
+
* @param options Timeout and retry options
|
|
1778
|
+
* @returns Array of commitment entries
|
|
2781
1779
|
*/
|
|
2782
|
-
declare function
|
|
1780
|
+
declare function fetchCommitments(relayUrl: string, options?: FetchCommitmentsOptions): Promise<CommitmentEntry[]>;
|
|
2783
1781
|
/**
|
|
2784
|
-
*
|
|
1782
|
+
* Build a Merkle tree from relay commitments
|
|
1783
|
+
* @param relayUrl Base URL of the relay service
|
|
1784
|
+
* @param options When sync is true, triggers on-demand sync on relay before fetching (for freshness when relay is behind chain)
|
|
1785
|
+
* @returns MerkleTree instance with all commitments loaded
|
|
1786
|
+
*
|
|
1787
|
+
* Supports sparse indices by zero-filling missing leaves, including missing prefixes.
|
|
1788
|
+
* Non-contiguous gaps (e.g. 0,1,2,3,22,23,30,31,32,33) are reconstructed with
|
|
1789
|
+
* zero leaves to match the on-chain Merkle tree structure.
|
|
2785
1790
|
*/
|
|
2786
|
-
declare function
|
|
1791
|
+
declare function buildMerkleTreeFromRelay(relayUrl: string, options?: {
|
|
1792
|
+
mint?: PublicKey;
|
|
1793
|
+
sync?: boolean;
|
|
1794
|
+
repair?: boolean;
|
|
1795
|
+
requireTarget?: boolean;
|
|
1796
|
+
requireCanonical?: boolean;
|
|
1797
|
+
timeoutMs?: number;
|
|
1798
|
+
maxRetries?: number;
|
|
1799
|
+
waitForIndex?: number;
|
|
1800
|
+
}): Promise<MerkleTree>;
|
|
1801
|
+
declare function buildMerkleTreeFromChain(connection: Connection, programId: PublicKey, merkleTree: PublicKey, onProgress?: (message: string) => void): Promise<MerkleTree>;
|
|
2787
1802
|
/**
|
|
2788
|
-
*
|
|
1803
|
+
* Pre-flight root validation
|
|
1804
|
+
*
|
|
1805
|
+
* Validates that a Merkle root is still valid before generating a proof.
|
|
1806
|
+
* This prevents wasted time generating proofs that will fail on-chain.
|
|
1807
|
+
*
|
|
1808
|
+
* @param relayUrl Relay service URL
|
|
1809
|
+
* @param rootHex Root to validate (hex string, with or without 0x prefix)
|
|
1810
|
+
* @returns Validation result with status and helpful message
|
|
2789
1811
|
*/
|
|
2790
|
-
declare function
|
|
1812
|
+
declare function validateRoot(relayUrl: string, rootHex: string): Promise<{
|
|
1813
|
+
valid: boolean;
|
|
1814
|
+
currentRoot?: string;
|
|
1815
|
+
message: string;
|
|
1816
|
+
isRecent: boolean;
|
|
1817
|
+
}>;
|
|
2791
1818
|
/**
|
|
2792
|
-
*
|
|
1819
|
+
* Wait for root to be valid
|
|
1820
|
+
*
|
|
1821
|
+
* Polls the relay until the given root is accepted or timeout.
|
|
1822
|
+
* Useful when you know a transaction is being processed but root hasn't updated yet.
|
|
1823
|
+
*
|
|
1824
|
+
* @param relayUrl Relay service URL
|
|
1825
|
+
* @param rootHex Root to wait for
|
|
1826
|
+
* @param timeoutMs Maximum time to wait (default: 30000ms)
|
|
1827
|
+
* @param pollIntervalMs Polling interval (default: 1000ms)
|
|
1828
|
+
* @returns Whether root became valid in time
|
|
2793
1829
|
*/
|
|
2794
|
-
declare function
|
|
1830
|
+
declare function waitForRoot(relayUrl: string, rootHex: string, timeoutMs?: number, pollIntervalMs?: number): Promise<{
|
|
1831
|
+
success: boolean;
|
|
1832
|
+
currentRoot?: string;
|
|
1833
|
+
waitedMs: number;
|
|
1834
|
+
}>;
|
|
2795
1835
|
/**
|
|
2796
|
-
*
|
|
1836
|
+
* Smart pre-flight check with automatic retry suggestion
|
|
2797
1837
|
*
|
|
2798
|
-
*
|
|
2799
|
-
*
|
|
2800
|
-
*
|
|
1838
|
+
* Checks root validity and provides actionable guidance:
|
|
1839
|
+
* - If root is current: proceed
|
|
1840
|
+
* - If root is old: suggest fetching fresh Merkle proofs
|
|
1841
|
+
* - If root is very old: suggest full tree rebuild
|
|
1842
|
+
*
|
|
1843
|
+
* @param relayUrl Relay service URL
|
|
1844
|
+
* @param rootHex Root to check
|
|
1845
|
+
* @returns Action recommendation
|
|
2801
1846
|
*/
|
|
2802
|
-
declare function
|
|
1847
|
+
declare function preflightCheck(relayUrl: string, rootHex: string): Promise<{
|
|
1848
|
+
shouldProceed: boolean;
|
|
1849
|
+
action: "proceed" | "refresh_proofs" | "rebuild_tree" | "wait";
|
|
1850
|
+
message: string;
|
|
1851
|
+
estimatedWaitMs?: number;
|
|
1852
|
+
}>;
|
|
2803
1853
|
|
|
2804
1854
|
/**
|
|
2805
1855
|
* UTXO Transaction Methods
|
|
@@ -3424,10 +2474,25 @@ declare class SimpleWallet {
|
|
|
3424
2474
|
* Cloak SDK - TypeScript SDK for Private Transactions on Solana
|
|
3425
2475
|
*
|
|
3426
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.
|
|
3427
2492
|
*/
|
|
3428
2493
|
|
|
3429
|
-
declare const VERSION = "1.
|
|
3430
|
-
/** True when scanner supports TransactSwap (tag 1).
|
|
2494
|
+
declare const VERSION = "0.1.6";
|
|
2495
|
+
/** True when scanner supports TransactSwap (tag 1). */
|
|
3431
2496
|
declare const SCANNER_SUPPORTS_TRANSACT_SWAP = true;
|
|
3432
2497
|
|
|
3433
|
-
export { CLOAK_PROGRAM_ID, type ChainNoteTxType, type
|
|
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 };
|