@cloak.dev/sdk 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { PublicKey, Transaction, Connection, TransactionInstruction, Keypair, SendOptions, AddressLookupTableAccount, VersionedTransaction } from '@solana/web3.js';
1
+ import { PublicKey, Transaction, Connection, AddressLookupTableAccount, TransactionInstruction, Keypair, SendOptions, VersionedTransaction } from '@solana/web3.js';
2
2
 
3
3
  type ComplianceTxType = "deposit" | "withdraw" | "send" | "swap";
4
4
  interface TransactionMetadata {
@@ -1498,6 +1498,85 @@ declare function getExplorerUrl(signature: string, network?: Network): string;
1498
1498
  */
1499
1499
  declare function getAddressExplorerUrl(address: string, network?: Network): string;
1500
1500
 
1501
+ /**
1502
+ * Merkle Tree implementation for computing proofs
1503
+ *
1504
+ * This tree stores all leaves and can compute the correct Merkle path
1505
+ * for any leaf index.
1506
+ */
1507
+ declare const MERKLE_TREE_HEIGHT = 32;
1508
+ /**
1509
+ * Merkle Tree class that stores all leaves and computes proofs
1510
+ */
1511
+ declare class MerkleTree {
1512
+ private levels;
1513
+ private capacity;
1514
+ private layers;
1515
+ private zeros;
1516
+ private poseidon;
1517
+ /**
1518
+ * Create a new Merkle tree
1519
+ * @param levels Number of levels in the tree (height)
1520
+ * @param leaves Initial leaves to insert
1521
+ * @param zeros Precomputed zero values for each level
1522
+ * @param poseidon Pre-initialized Poseidon instance (avoids async in constructor)
1523
+ */
1524
+ constructor(levels: number, leaves: bigint[], zeros: bigint[], poseidon: any);
1525
+ /**
1526
+ * Create a new MerkleTree with async initialization
1527
+ */
1528
+ static create(levels?: number, leaves?: bigint[]): Promise<MerkleTree>;
1529
+ /**
1530
+ * Rebuild the tree from the leaves (synchronous — poseidon must be initialized)
1531
+ */
1532
+ private _rebuildSync;
1533
+ /**
1534
+ * Get the tree root
1535
+ */
1536
+ root(): bigint;
1537
+ /**
1538
+ * Get the number of leaves in the tree
1539
+ */
1540
+ get length(): number;
1541
+ /**
1542
+ * Insert a new leaf into the tree
1543
+ */
1544
+ insert(leaf: bigint): void;
1545
+ /**
1546
+ * Insert multiple leaves
1547
+ */
1548
+ bulkInsert(leaves: bigint[]): void;
1549
+ /**
1550
+ * Update the path from a leaf to the root
1551
+ */
1552
+ private _updatePath;
1553
+ /**
1554
+ * Get the Merkle path for a leaf at the given index
1555
+ * @param index Leaf index
1556
+ * @returns pathElements and pathIndices for the proof
1557
+ */
1558
+ path(index: number): {
1559
+ pathElements: bigint[];
1560
+ pathIndices: number;
1561
+ };
1562
+ /**
1563
+ * Find the index of a leaf in the tree
1564
+ * @param leaf Leaf value to find
1565
+ * @returns Index if found, -1 otherwise
1566
+ */
1567
+ indexOf(leaf: bigint): number;
1568
+ /**
1569
+ * Get all leaves
1570
+ */
1571
+ leaves(): bigint[];
1572
+ }
1573
+ /**
1574
+ * Build a MerkleTree from commitment values
1575
+ * @param commitments Array of commitment bigints
1576
+ * @param height Tree height (default: 32)
1577
+ */
1578
+ declare function buildMerkleTree(commitments: bigint[], height?: number): Promise<MerkleTree>;
1579
+
1501
1580
  /**
1502
1581
  * Error Utilities
1503
1582
  *
@@ -1529,6 +1608,79 @@ declare function parseRelayErrorResponse(responseText: string): {
1529
1608
  isRootNotFound: boolean;
1530
1609
  currentRoot?: string;
1531
1610
  };
1611
+ /**
1612
+ * Raised when a spend attempt hits 0x1020 DoubleSpend on-chain — the input
1613
+ * UTXO's nullifier PDA already exists, meaning the UTXO was spent earlier
1614
+ * (often via another device / session the user forgot about).
1615
+ *
1616
+ * Recovery path: the SDK's pre-flight nullifier check catches this BEFORE
1617
+ * proof generation via `verifyUtxos()`. If thrown after submission (unlikely
1618
+ * once pre-flight is wired in), the caller should call `verifyUtxos()` to
1619
+ * reconcile local state with chain.
1620
+ */
1621
+ declare class UtxoAlreadySpentError extends Error {
1622
+ readonly spentUtxoCommitments: string[];
1623
+ constructor(message: string, spentUtxoCommitments?: string[]);
1624
+ }
1625
+ /**
1626
+ * Base class for Range / sanctions-quote mismatches from the on-chain
1627
+ * program. The relay signs quotes; the program verifies them. When they
1628
+ * don't line up we hit one of three errors:
1629
+ *
1630
+ * 0x10B0 = QuoteExpired — quote's expiry_ts < on-chain clock
1631
+ * 0x10B2 = WalletMismatch — quote wallet != expected_wallet
1632
+ * 0x10B3 = MissingEd25519 — no withdraw-auth / range-quote ix at all
1633
+ *
1634
+ * These are structural mismatches the caller can't fix on their own —
1635
+ * they indicate a relay / program version skew or a config drift
1636
+ * (e.g. pool not initialized with the expected range_signer).
1637
+ */
1638
+ declare class SanctionsQuoteError extends Error {
1639
+ readonly onChainCode: number;
1640
+ readonly subKind: "expired" | "wallet_mismatch" | "missing_ix";
1641
+ constructor(message: string, onChainCode: number, subKind: "expired" | "wallet_mismatch" | "missing_ix");
1642
+ }
1643
+ /**
1644
+ * Generic catch-all for relay 500s that don't map to any structured class.
1645
+ * Preserves the raw relay error text in `relayMessage` so the caller can
1646
+ * log it without having to string-match.
1647
+ */
1648
+ declare class RelayInternalError extends Error {
1649
+ readonly relayMessage?: string | undefined;
1650
+ readonly httpStatus?: number | undefined;
1651
+ /**
1652
+ * Optional pre-built merkle tree rebuilt from chain (Node only).
1653
+ * Populated by the chain-replay fallback in `transact()` when the
1654
+ * relay-tree path fails after all retries. Callers can retry the
1655
+ * spend with `options.cachedMerkleTree = err.cachedTreeFromChain`
1656
+ * without paying the chain-replay cost a second time.
1657
+ *
1658
+ * Typed via `import type` so there's no runtime coupling between
1659
+ * this module and the MerkleTree implementation.
1660
+ */
1661
+ readonly cachedTreeFromChain?: MerkleTree | undefined;
1662
+ constructor(message: string, relayMessage?: string | undefined, httpStatus?: number | undefined,
1663
+ /**
1664
+ * Optional pre-built merkle tree rebuilt from chain (Node only).
1665
+ * Populated by the chain-replay fallback in `transact()` when the
1666
+ * relay-tree path fails after all retries. Callers can retry the
1667
+ * spend with `options.cachedMerkleTree = err.cachedTreeFromChain`
1668
+ * without paying the chain-replay cost a second time.
1669
+ *
1670
+ * Typed via `import type` so there's no runtime coupling between
1671
+ * this module and the MerkleTree implementation.
1672
+ */
1673
+ cachedTreeFromChain?: MerkleTree | undefined);
1674
+ }
1675
+ /**
1676
+ * Classify a relay error (response body text + HTTP status) into one of the
1677
+ * structured error types above, or fall back to RelayInternalError.
1678
+ *
1679
+ * Order matters — more specific first. RootNotFoundError is handled by the
1680
+ * caller separately (existing code path) since it carries `current_root` in
1681
+ * the response body.
1682
+ */
1683
+ declare function classifyRelayError(responseText: string, httpStatus?: number): Error;
1532
1684
  /**
1533
1685
  * Shield Pool Program Error Codes
1534
1686
  *
@@ -1578,609 +1730,853 @@ declare function createCloakError(error: unknown, _context: string): CloakError;
1578
1730
  declare function formatErrorForLogging(error: unknown): string;
1579
1731
 
1580
1732
  /**
1581
- * Structured Logger for Cloak SDK
1582
- *
1583
- * Provides structured logging similar to Rust tracing format:
1584
- * 2026-01-23T00:51:46.489317Z INFO cloak::module: 📥 Message key=value
1733
+ * UTXO (Unspent Transaction Output) Model
1585
1734
  *
1586
- * Enable via:
1587
- * - SDK config: new CloakSDK({ debug: true })
1588
- * - Environment: CLOAK_DEBUG=1 or DEBUG=cloak:*
1589
- */
1590
- type LogLevel = "DEBUG" | "INFO" | "WARN" | "ERROR";
1591
- /**
1592
- * Enable or disable debug logging globally
1593
- */
1594
- declare function setDebugMode(enabled: boolean): void;
1595
- /**
1596
- * Check if debug mode is enabled
1735
+ * This module implements the UTXO model for the Cloak privacy protocol.
1736
+ * UTXOs allow for:
1737
+ * - Shield-to-shield transfers (privacy preserved)
1738
+ * - Partial withdrawals (change stays shielded)
1739
+ * - Combining multiple small deposits
1740
+ * - Multi-token support (SOL + any SPL token)
1597
1741
  */
1598
- declare function isDebugEnabled(): boolean;
1742
+
1743
+ declare const NATIVE_SOL_MINT: PublicKey;
1599
1744
  /**
1600
- * Logger interface
1745
+ * UTXO Keypair for ownership verification
1746
+ *
1747
+ * Uses Poseidon hash for key derivation:
1748
+ * - privateKey: random field element (kept secret)
1749
+ * - publicKey: Poseidon(privateKey, 0) - can be shared
1601
1750
  */
1602
- interface Logger {
1603
- debug: (message: string, kvPairs?: Record<string, unknown>) => void;
1604
- info: (message: string, kvPairs?: Record<string, unknown>) => void;
1605
- warn: (message: string, kvPairs?: Record<string, unknown>) => void;
1606
- error: (message: string, kvPairs?: Record<string, unknown>) => void;
1751
+ interface UtxoKeypair {
1752
+ /** Private key (random 252-bit field element) */
1753
+ privateKey: bigint;
1754
+ /** Public key derived as Poseidon(privateKey, 0) */
1755
+ publicKey: bigint;
1607
1756
  }
1608
1757
  /**
1609
- * Create a logger for a specific module
1610
- *
1611
- * @param module - Module name (e.g., "cloak::sdk", "cloak::indexer")
1612
- * @returns Logger instance with debug, info, warn, error methods
1758
+ * UTXO represents an unspent transaction output
1613
1759
  *
1614
- * @example
1615
- * ```typescript
1616
- * const log = createLogger("cloak::deposit");
1617
- * log.info("Depositing", { amount: 100000000 });
1618
- * // Output: 2026-01-23T00:51:46.489000Z INFO cloak::deposit: Depositing amount=100000000
1619
- * ```
1760
+ * Contains all information needed to spend the UTXO:
1761
+ * - amount: Value in the smallest unit (lamports for SOL)
1762
+ * - keypair: Ownership keys
1763
+ * - blinding: Randomness for hiding
1764
+ * - mintAddress: Token type (SOL or SPL token)
1765
+ * - index: Leaf index in Merkle tree (set after deposit/creation)
1620
1766
  */
1621
- declare function createLogger(module: string): Logger;
1767
+ interface Utxo {
1768
+ /** Amount in the smallest unit (lamports for SOL, token units for SPL) */
1769
+ amount: bigint;
1770
+ /** Keypair for ownership */
1771
+ keypair: UtxoKeypair;
1772
+ /** Random blinding factor */
1773
+ blinding: bigint;
1774
+ /** Token mint address (NATIVE_SOL_MINT for SOL) */
1775
+ mintAddress: PublicKey;
1776
+ /** Leaf index in Merkle tree (set after the UTXO is in the tree) */
1777
+ index?: number;
1778
+ /** Commitment hash (computed from amount, pubkey, blinding, mint) */
1779
+ commitment?: bigint;
1780
+ /** Nullifier hash (computed when spending) */
1781
+ nullifier?: bigint;
1782
+ /**
1783
+ * Sibling commitment at level 0 of the Merkle tree.
1784
+ * Required for Merkle proofs since siblings aren't stored on-chain.
1785
+ * This is the commitment of the other output in the same transaction.
1786
+ */
1787
+ siblingCommitment?: bigint;
1788
+ }
1622
1789
  /**
1623
- * Measure and return duration of an async operation
1790
+ * Encrypted UTXO note for recipient discovery
1624
1791
  *
1625
- * @param _logger - Logger instance (reserved for future debug logging)
1626
- * @param _operation - Operation name (reserved for future debug logging)
1627
- * @param fn - Async function to measure
1628
- * @returns Result and duration in milliseconds
1629
- */
1630
- declare function withTiming<T>(_logger: Logger, _operation: string, fn: () => Promise<T>): Promise<{
1631
- result: T;
1632
- durationMs: number;
1633
- }>;
1634
- /**
1635
- * Format lamports as SOL with proper decimals
1636
- */
1637
- declare function formatSol(lamports: number | bigint): string;
1638
- /**
1639
- * Truncate a string (useful for signatures, hashes)
1640
- */
1641
- declare function truncate(str: string, len?: number): string;
1642
- /**
1643
- * Default SDK logger instance
1792
+ * When creating an output UTXO for someone else, the data is encrypted
1793
+ * so only the recipient can discover and spend it.
1644
1794
  */
1645
- declare const sdkLogger: Logger;
1646
-
1795
+ interface EncryptedNote {
1796
+ /** Encrypted UTXO data (ECIES/ChaCha20 encrypted) */
1797
+ ciphertext: Uint8Array;
1798
+ /** Ephemeral public key for ECDH */
1799
+ ephemeralPubkey: Uint8Array;
1800
+ /** MAC for integrity verification */
1801
+ mac: Uint8Array;
1802
+ }
1647
1803
  /**
1648
- * Result from submitting a withdrawal that includes the request ID
1649
- * for potential recovery/resume scenarios
1804
+ * Transaction parameters for a UTXO transaction
1650
1805
  */
1651
- interface WithdrawSubmissionResult {
1652
- /** The relay request ID - persist this for recovery */
1653
- requestId: string;
1654
- /** The final transaction signature */
1655
- signature: string;
1806
+ interface TransactParams {
1807
+ /** Input UTXOs to spend (max 2) */
1808
+ inputUtxos: Utxo[];
1809
+ /** Output UTXOs to create (max 2) */
1810
+ outputUtxos: Utxo[];
1811
+ /** External recipient for withdrawal (optional) */
1812
+ recipient?: PublicKey;
1813
+ /** Net external amount: positive = deposit, negative = withdraw */
1814
+ externalAmount?: bigint;
1815
+ /** Depositor address (for deposits, the source of funds) */
1816
+ depositor?: PublicKey;
1656
1817
  }
1657
1818
  /**
1658
- * Relay Service Client
1659
- *
1660
- * Handles submission of withdrawal transactions through a relay service
1661
- * that pays for transaction fees and submits the transaction on-chain.
1819
+ * Result from a UTXO transaction
1662
1820
  */
1663
- declare class RelayService {
1664
- private baseUrl;
1821
+ interface TransactResult {
1822
+ /** Transaction signature */
1823
+ signature: string;
1824
+ /** Nullifiers of spent inputs */
1825
+ inputNullifiers: bigint[];
1826
+ /** Commitments of created outputs */
1827
+ outputCommitments: bigint[];
1828
+ /** New Merkle root after the transaction */
1829
+ newRoot: string;
1830
+ /** Merkle tree indices where output commitments were inserted */
1831
+ commitmentIndices: [number, number];
1665
1832
  /**
1666
- * Create a new Relay Service client
1667
- *
1668
- * @param baseUrl - Relay service base URL
1669
- */
1670
- constructor(baseUrl: string);
1671
- /**
1672
- * Submit a withdrawal transaction via relay
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;
1746
- /**
1747
- * Submit a swap transaction via relay
1748
- *
1749
- * Similar to submitWithdraw but includes swap parameters for token swaps.
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
- * ```
1833
+ * Sibling commitments for each output.
1834
+ * For output[0], sibling is output[1] and vice versa.
1835
+ * These are needed for Merkle proofs since siblings aren't stored on-chain.
1772
1836
  */
1773
- submitSwap(params: {
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>;
1837
+ siblingCommitments: [bigint, bigint];
1793
1838
  /**
1794
- * Get transaction status
1795
- *
1796
- * @param requestId - Request ID from previous submission
1797
- * @returns Current status
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
- * ```
1839
+ * Left sibling from before the transaction (for odd-index handling).
1840
+ * When the first output ends up at an odd index due to concurrent access,
1841
+ * its sibling at index-1 comes from a previous transaction.
1842
+ * This value captures subtrees[0] before our transaction to enable
1843
+ * correct Merkle proof computation for odd indices.
1807
1844
  */
1808
- getStatus(requestId: string): Promise<TxStatus>;
1845
+ preTransactionLeftSibling?: bigint;
1809
1846
  /**
1810
- * Register viewing key with relay for compliance decryption.
1811
- * This is a one-time operation - the viewing key is stored by the relay.
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
- * ```
1847
+ * The actual output UTXOs created by this transaction.
1848
+ * These have all the data needed to spend them later (keypair, blinding, etc).
1849
+ * The UTXOs are already updated with their indices and sibling commitments.
1827
1850
  */
1828
- registerViewingKey(userPubkey: string, viewingKey: string, signMessage: (message: Uint8Array) => Promise<Uint8Array>): Promise<boolean>;
1851
+ outputUtxos: Utxo[];
1829
1852
  /**
1830
- * Fetch relay compliance master public key.
1831
- * DEPRECATED: This endpoint is no longer used
1853
+ * Whether the viewing key was registered with the relay for compliance.
1854
+ * True on first transaction when metadataBundle includes viewing_key.
1855
+ * Once registered, subsequent transactions don't need to send metadataBundle.
1832
1856
  */
1833
- getCompliancePublicKey(): Promise<Uint8Array>;
1857
+ viewingKeyRegistered?: boolean;
1834
1858
  /**
1835
- * Convert bytes to base64 string
1859
+ * The Merkle tree used/built for this transaction, with output commitments inserted.
1860
+ * Pass this as `cachedMerkleTree` in the next transaction to skip relay fetching
1861
+ * and avoid needing `waitForCommitmentIndex`.
1836
1862
  */
1837
- private bytesToBase64;
1863
+ merkleTree?: MerkleTree;
1838
1864
  /**
1839
- * Sleep utility
1865
+ * Address lookup table used for v0 transaction (when chain notes or risk oracle require it).
1866
+ * Pass this as `addressLookupTableAccounts` in the next deposit to avoid creating a new ALT.
1840
1867
  */
1841
- private sleep;
1842
- private computeViewingKeyIdentifier;
1868
+ addressLookupTableAccounts?: AddressLookupTableAccount[];
1843
1869
  }
1844
-
1845
1870
  /**
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);
1871
+ * Generate a random field element suitable for BN254
1859
1872
  */
1860
-
1873
+ declare function randomFieldElement(): bigint;
1861
1874
  /**
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.
1875
+ * Generate a new UTXO keypair
1866
1876
  *
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
1877
+ * @returns A new keypair with random private key and derived public key
1871
1878
  */
1872
- declare function fetchRiskQuoteIx(connection: Connection, wallet: PublicKey, rangeApiKey: string): Promise<{
1873
- instruction: TransactionInstruction;
1874
- queue: PublicKey;
1875
- }>;
1876
-
1879
+ declare function generateUtxoKeypair(): Promise<UtxoKeypair>;
1877
1880
  /**
1878
- * Encrypted Output Helpers
1881
+ * Derive a deterministic UTXO keypair from a wallet's spend key.
1882
+ * Use this for deposits and change outputs so all chain notes use the same nk,
1883
+ * enabling the compliance scan (scanTransactions + toComplianceReport) to decrypt them.
1879
1884
  *
1880
- * Functions for creating encrypted outputs that enable note scanning
1885
+ * @param skSpend - 32-byte spend key (from wallet key derivation)
1886
+ * @returns UtxoKeypair with deterministic private/public keys
1881
1887
  */
1882
-
1888
+ declare function deriveUtxoKeypairFromSpendKey(skSpend: Uint8Array): Promise<UtxoKeypair>;
1883
1889
  /**
1884
- * Prepare encrypted output for scanning by wallet owner
1890
+ * Derive public key from private key
1885
1891
  *
1886
- * @param note - Note to encrypt
1887
- * @param cloakKeys - Wallet's Cloak keys (for self-encryption)
1888
- * @returns Base64-encoded encrypted output
1892
+ * @param privateKey The private key
1893
+ * @returns The corresponding public key
1889
1894
  */
1890
- declare function prepareEncryptedOutput(note: CloakNote, cloakKeys: CloakKeyPair): string;
1895
+ declare function derivePublicKey(privateKey: bigint): Promise<bigint>;
1891
1896
  /**
1892
- * Prepare encrypted output for a specific recipient
1897
+ * Create a new UTXO
1893
1898
  *
1894
- * @param note - Note to encrypt
1895
- * @param recipientPvkHex - Recipient's public view key (hex)
1896
- * @returns Base64-encoded encrypted output
1899
+ * @param amount Amount in smallest unit
1900
+ * @param keypair Owner's keypair
1901
+ * @param mintAddress Token mint (defaults to native SOL)
1902
+ * @returns A new UTXO (commitment will be computed)
1897
1903
  */
1898
- declare function prepareEncryptedOutputForRecipient(note: CloakNote, recipientPvkHex: string): string;
1904
+ declare function createUtxo(amount: bigint, keypair: UtxoKeypair, mintAddress?: PublicKey): Promise<Utxo>;
1899
1905
  /**
1900
- * Simple base64 encoding for v1.0 notes (no encryption)
1906
+ * Create a zero/padding UTXO
1901
1907
  *
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
1908
+ * Zero UTXOs are used as padding when we need fewer than 2 inputs/outputs.
1909
+ * They have zero amount and don't require valid Merkle proofs.
1910
+ * Uses salt-based keypair (privateKey = salt) with blinding=0 to match the circuit
1911
+ * test. By default, salt is random to avoid cross-process collisions under concurrency.
1912
+ * Callers can pass an explicit salt for deterministic behavior.
1909
1913
  *
1910
- * Helper functions for working with Solana Wallet Adapters
1914
+ * @param mintAddress Token mint (defaults to native SOL)
1915
+ * @param salt Optional salt; if omitted, uses timestamp+counter for uniqueness
1911
1916
  */
1912
-
1917
+ declare function createZeroUtxo(mintAddress?: PublicKey, salt?: bigint): Promise<Utxo>;
1913
1918
  /**
1914
- * Validate wallet is connected and has public key
1919
+ * Convert PublicKey to field element for circuit
1920
+ *
1921
+ * @param pubkey Solana PublicKey
1922
+ * @returns Field element representation
1915
1923
  */
1916
- declare function validateWalletConnected(wallet: WalletAdapter | Keypair): void;
1924
+ declare function pubkeyToFieldElement(pubkey: PublicKey): bigint;
1917
1925
  /**
1918
- * Get public key from wallet or keypair
1926
+ * Compute the commitment for a UTXO
1927
+ *
1928
+ * commitment = Poseidon(amount, pubkey, blinding, mintAddress)
1929
+ *
1930
+ * @param utxo The UTXO to compute commitment for
1931
+ * @returns The commitment as a bigint
1919
1932
  */
1920
- declare function getPublicKey(wallet: WalletAdapter | Keypair): PublicKey;
1933
+ declare function computeCommitment(utxo: Utxo): Promise<bigint>;
1921
1934
  /**
1922
- * Send transaction using wallet adapter or keypair
1935
+ * Compute the signature for nullifier derivation
1936
+ *
1937
+ * signature = Poseidon(privateKey, commitment, pathIndex)
1938
+ *
1939
+ * @param privateKey Owner's private key
1940
+ * @param commitment The UTXO commitment
1941
+ * @param pathIndex Merkle tree path index
1942
+ * @returns The signature
1923
1943
  */
1924
- declare function sendTransaction(transaction: Transaction, wallet: WalletAdapter | Keypair, connection: Connection, options?: SendOptions): Promise<string>;
1944
+ declare function computeSignature(privateKey: bigint, commitment: bigint, pathIndex: bigint): Promise<bigint>;
1925
1945
  /**
1926
- * Sign transaction using wallet adapter or keypair
1946
+ * Compute the nullifier for a UTXO
1947
+ *
1948
+ * nullifier = Poseidon(commitment, pathIndex, signature)
1949
+ *
1950
+ * The nullifier is a unique identifier that gets recorded on-chain
1951
+ * to prevent double-spending.
1952
+ *
1953
+ * @param utxo The UTXO being spent
1954
+ * @returns The nullifier
1927
1955
  */
1928
- declare function signTransaction<T extends Transaction>(transaction: T, wallet: WalletAdapter | Keypair): Promise<T>;
1956
+ declare function computeNullifier(utxo: Utxo): Promise<bigint>;
1929
1957
  /**
1930
- * Create a keypair adapter for testing
1958
+ * Serialize a UTXO to bytes for encryption
1931
1959
  */
1932
- declare function keypairToAdapter(keypair: Keypair): WalletAdapter;
1933
-
1960
+ declare function serializeUtxo(utxo: Utxo): Uint8Array;
1934
1961
  /**
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
- * ```
1962
+ * Deserialize a UTXO from bytes
1958
1963
  */
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;
1964
+ declare function deserializeUtxo(bytes: Uint8Array): Promise<Utxo>;
1967
1965
  /**
1968
- * Deposit instruction parameters for type safety
1966
+ * Convert bigint to hex string (64 chars, padded)
1969
1967
  */
1970
- interface DepositInstructionParams {
1971
- programId: PublicKey;
1972
- payer: PublicKey;
1973
- pool: PublicKey;
1974
- merkleTree: PublicKey;
1975
- amount: number;
1976
- commitment: Uint8Array;
1977
- }
1968
+ declare function bigintToHex(value: bigint): string;
1978
1969
  /**
1979
- * Validate deposit instruction parameters
1980
- *
1981
- * @param params - Parameters to validate
1982
- * @throws Error if invalid
1970
+ * Convert hex string to bigint
1983
1971
  */
1984
- declare function validateDepositParams(params: DepositInstructionParams): void;
1985
-
1972
+ declare function hexToBigint(hex: string): bigint;
1986
1973
  /**
1987
- * Program Derived Address (PDA) utilities for Shield Pool
1974
+ * Convert bigint to 32-byte array (big-endian for circuits)
1975
+ */
1976
+ declare function bigintToBytes32(value: bigint): Uint8Array;
1977
+ /**
1978
+ * Check if two UTXOs are equal (same commitment)
1979
+ */
1980
+ declare function utxoEquals(a: Utxo, b: Utxo): Promise<boolean>;
1981
+ /**
1982
+ * Calculate total amount from an array of UTXOs
1983
+ */
1984
+ declare function sumUtxoAmounts(utxos: Utxo[]): bigint;
1985
+ /**
1986
+ * Select UTXOs to cover a target amount
1988
1987
  *
1989
- * These functions derive deterministic addresses from the program ID and seeds.
1990
- * This matches the behavior in tooling/test/src/shared.rs::get_pda_addresses()
1988
+ * @param available Available UTXOs (sorted by amount descending)
1989
+ * @param targetAmount Target amount to cover
1990
+ * @returns Selected UTXOs that cover the target, or null if insufficient
1991
1991
  */
1992
+ declare function selectUtxos(available: Utxo[], targetAmount: bigint): Utxo[] | null;
1992
1993
 
1993
- interface ShieldPoolPDAs {
1994
- pool: PublicKey;
1995
- merkleTree: PublicKey;
1996
- vaultAuthority: PublicKey;
1997
- treasury: PublicKey;
1998
- }
1999
1994
  /**
2000
- * Derive all Shield Pool PDAs from program ID + pool mint
1995
+ * UTXO verification reconcile local UTXO state with on-chain nullifier state.
2001
1996
  *
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]
1997
+ * Shipped in 0.1.5 as the structured building block for self-repair flows.
1998
+ * The web app previously composed this out of lower-level SDK primitives
1999
+ * (`computeNullifier` + `getNullifierPDA` + `getMultipleAccountsInfo`); now
2000
+ * it's a first-class SDK export so callers don't re-implement the same
2001
+ * ~40 lines across tools.
2007
2002
  *
2008
- * @param programId - Optional program ID (defaults to CLOAK_PROGRAM_ID)
2009
- * @param mint - Pool mint (defaults to NATIVE_SOL_MINT / WSOL sentinel)
2003
+ * Two entry points:
2004
+ *
2005
+ * 1. `verifyUtxos(utxos, conn, programId)` — pure function. Takes a UTXO
2006
+ * set, does a single batched on-chain lookup of the derived nullifier
2007
+ * PDAs, returns `{ spent, unspent }`. Caller decides what to do.
2008
+ *
2009
+ * 2. `preflightNullifiers(utxos, conn, programId)` — thin wrapper that
2010
+ * throws `UtxoAlreadySpentError` if ANY input is already spent.
2011
+ * Intended for use at the top of spend entry points (transact,
2012
+ * fullWithdraw, swap) so the SDK fails fast with a structured error
2013
+ * instead of burning proof-gen + relay retries on a doomed tx.
2014
+ *
2015
+ * Root-caused from a production incident 2026-04-24: a user's cloak.ag
2016
+ * backup contained a UTXO that had been spent via another session. The
2017
+ * recovery tool generated a valid proof against the correct merkle tree
2018
+ * and submitted it; relay's simulation returned 0x1020 DoubleSpend after
2019
+ * 6 retries over ~60s. Pre-flight catches this class in ~200ms.
2010
2020
  */
2011
- declare function getShieldPoolPDAs(programId?: PublicKey, mint?: PublicKey): ShieldPoolPDAs;
2021
+
2022
+ /** Result of a batch verification — disjoint partition of the input set. */
2023
+ interface VerifyUtxosResult {
2024
+ /** Inputs whose nullifier PDA exists on-chain (already spent). */
2025
+ spent: Utxo[];
2026
+ /** Inputs whose nullifier PDA is absent on-chain (safe to spend). */
2027
+ unspent: Utxo[];
2028
+ /** Inputs we couldn't check — missing commitment / index / mint. */
2029
+ skipped: Utxo[];
2030
+ }
2012
2031
  /**
2013
- * Derive the nullifier PDA for a specific pool + nullifier hash.
2032
+ * Check the on-chain nullifier PDA for each UTXO and partition by state.
2014
2033
  *
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.
2034
+ * Only UTXOs with `commitment`, `mintAddress`, AND a non-null keypair can
2035
+ * be verified the nullifier derivation needs all three. UTXOs lacking any
2036
+ * of these go into `skipped` and the caller must decide how to treat them.
2037
+ * (In practice a missing `commitment` means the UTXO hasn't landed on-chain
2038
+ * yet — those can't be spent anyway.)
2018
2039
  *
2019
- * Seeds: ["nullifier", pool_pubkey, nullifier_hash]
2040
+ * Uses a single batched `getMultipleAccountsInfo` call for efficiency —
2041
+ * one round-trip regardless of UTXO count (up to Solana's 100-key cap,
2042
+ * beyond which we page).
2020
2043
  *
2021
- * @param poolPubkey - Pool PDA that scopes nullifier domain
2022
- * @param nullifier - 32-byte nullifier hash
2023
- * @param programId - Optional program ID (defaults to CLOAK_PROGRAM_ID)
2024
- * @returns [PublicKey, bump] - The nullifier PDA and its bump seed
2044
+ * Typical latency: ~150-300ms on a healthy RPC.
2025
2045
  */
2026
- declare function getNullifierPDA(poolPubkey: PublicKey, nullifier: Uint8Array | Buffer, programId?: PublicKey): [PublicKey, number];
2046
+ declare function verifyUtxos(utxos: Utxo[], connection: Connection, programId: PublicKey, commitment?: "processed" | "confirmed" | "finalized"): Promise<VerifyUtxosResult>;
2027
2047
  /**
2028
- * Derive the swap state PDA for a given pool + nullifier.
2029
- *
2030
- * Seeds: ["swap_state", pool_pubkey, nullifier_hash]
2048
+ * Pre-flight gate: throw `UtxoAlreadySpentError` if any input is already
2049
+ * spent on-chain. Called at the top of spend entry points in core/transact.
2031
2050
  *
2032
- * @param poolPubkey - Pool PDA used for swap state domain separation
2033
- * @param nullifier - 32-byte nullifier hash
2034
- * @param programId - Optional program ID (defaults to CLOAK_PROGRAM_ID)
2035
- * @returns [PublicKey, bump] - The swap state PDA and its bump seed
2051
+ * Browser-safe: uses one batched RPC call.
2036
2052
  */
2037
- declare function getSwapStatePDA(poolPubkey: PublicKey, nullifier: Uint8Array | Buffer, programId?: PublicKey): [PublicKey, number];
2053
+ declare function preflightNullifiers(utxos: Utxo[], connection: Connection, programId: PublicKey, commitment?: "processed" | "confirmed" | "finalized"): Promise<void>;
2038
2054
 
2039
2055
  /**
2040
- * On-chain Merkle proof computation
2056
+ * Structured Logger for Cloak SDK
2041
2057
  *
2042
- * Computes Merkle proofs directly from on-chain tree state,
2043
- * eliminating the need for an indexer for proof generation.
2058
+ * Provides structured logging similar to Rust tracing format:
2059
+ * 2026-01-23T00:51:46.489317Z INFO cloak::module: 📥 Message key=value
2060
+ *
2061
+ * Enable via:
2062
+ * - SDK config: new CloakSDK({ debug: true })
2063
+ * - Environment: CLOAK_DEBUG=1 or DEBUG=cloak:*
2044
2064
  */
2045
-
2065
+ type LogLevel = "DEBUG" | "INFO" | "WARN" | "ERROR";
2046
2066
  /**
2047
- * Merkle proof result
2067
+ * Enable or disable debug logging globally
2048
2068
  */
2049
- interface OnchainMerkleProof {
2050
- pathElements: string[];
2051
- pathIndices: number[];
2052
- root: string;
2053
- }
2054
- interface MerkleTreeState {
2055
- nextIndex: number;
2056
- root: string;
2057
- subtrees: string[];
2058
- }
2069
+ declare function setDebugMode(enabled: boolean): void;
2059
2070
  /**
2060
- * Read the Merkle tree state from on-chain account
2061
- * @param forceConfirmed - If true, forces "confirmed" commitment level for fresh data
2062
- * @param relayUrl - Optional relay URL to query for current root (bypasses RPC caching)
2063
- * @param mint - Optional pool mint used when querying relay /merkle-root
2071
+ * Check if debug mode is enabled
2064
2072
  */
2065
- declare function readMerkleTreeState(connection: Connection, merkleTreePDA: PublicKey, forceConfirmed?: boolean, relayUrl?: string,
2066
- /** When true, skip relay root and use chain directly (avoids stale relay root causing ProofInvalid) */
2067
- skipRelayRoot?: boolean, mint?: PublicKey): Promise<MerkleTreeState>;
2073
+ declare function isDebugEnabled(): boolean;
2068
2074
  /**
2069
- * Compute Merkle proof for a leaf at a given index using on-chain state
2070
- *
2071
- * This works by:
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
2075
+ * Logger interface
2076
+ */
2077
+ interface Logger {
2078
+ debug: (message: string, kvPairs?: Record<string, unknown>) => void;
2079
+ info: (message: string, kvPairs?: Record<string, unknown>) => void;
2080
+ warn: (message: string, kvPairs?: Record<string, unknown>) => void;
2081
+ error: (message: string, kvPairs?: Record<string, unknown>) => void;
2082
+ }
2083
+ /**
2084
+ * Create a logger for a specific module
2076
2085
  *
2077
- * Note: This works best for recent leaves where siblings are zero values.
2078
- * For older leaves with non-zero siblings that aren't stored in subtrees,
2079
- * an indexer may still be needed.
2086
+ * @param module - Module name (e.g., "cloak::sdk", "cloak::indexer")
2087
+ * @returns Logger instance with debug, info, warn, error methods
2080
2088
  *
2081
- * @param connection - Solana connection
2082
- * @param merkleTreePDA - PDA of the merkle tree account
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
2089
+ * @example
2090
+ * ```typescript
2091
+ * const log = createLogger("cloak::deposit");
2092
+ * log.info("Depositing", { amount: 100000000 });
2093
+ * // Output: 2026-01-23T00:51:46.489000Z INFO cloak::deposit: Depositing amount=100000000
2094
+ * ```
2086
2095
  */
2087
- declare function computeProofFromChain(connection: Connection, merkleTreePDA: PublicKey, leafIndex: number, forceConfirmed?: boolean): Promise<OnchainMerkleProof>;
2096
+ declare function createLogger(module: string): Logger;
2088
2097
  /**
2089
- * Compute proof for the most recently inserted leaf
2098
+ * Measure and return duration of an async operation
2090
2099
  *
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.
2100
+ * @param _logger - Logger instance (reserved for future debug logging)
2101
+ * @param _operation - Operation name (reserved for future debug logging)
2102
+ * @param fn - Async function to measure
2103
+ * @returns Result and duration in milliseconds
2094
2104
  */
2095
- declare function computeProofForLatestDeposit(connection: Connection, merkleTreePDA: PublicKey): Promise<OnchainMerkleProof & {
2096
- leafIndex: number;
2105
+ declare function withTiming<T>(_logger: Logger, _operation: string, fn: () => Promise<T>): Promise<{
2106
+ result: T;
2107
+ durationMs: number;
2097
2108
  }>;
2098
-
2099
2109
  /**
2100
- * Merkle Tree implementation for computing proofs
2101
- *
2102
- * This tree stores all leaves and can compute the correct Merkle path
2103
- * for any leaf index.
2110
+ * Format lamports as SOL with proper decimals
2104
2111
  */
2105
- declare const MERKLE_TREE_HEIGHT = 32;
2112
+ declare function formatSol(lamports: number | bigint): string;
2106
2113
  /**
2107
- * Merkle Tree class that stores all leaves and computes proofs
2114
+ * Truncate a string (useful for signatures, hashes)
2108
2115
  */
2109
- declare class MerkleTree {
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);
2116
+ declare function truncate(str: string, len?: number): string;
2117
+ /**
2118
+ * Default SDK logger instance
2119
+ */
2120
+ declare const sdkLogger: Logger;
2121
+
2122
+ /**
2123
+ * Result from submitting a withdrawal that includes the request ID
2124
+ * for potential recovery/resume scenarios
2125
+ */
2126
+ interface WithdrawSubmissionResult {
2127
+ /** The relay request ID - persist this for recovery */
2128
+ requestId: string;
2129
+ /** The final transaction signature */
2130
+ signature: string;
2131
+ }
2132
+ /**
2133
+ * Relay Service Client
2134
+ *
2135
+ * Handles submission of withdrawal transactions through a relay service
2136
+ * that pays for transaction fees and submits the transaction on-chain.
2137
+ */
2138
+ declare class RelayService {
2139
+ private baseUrl;
2123
2140
  /**
2124
- * Create a new MerkleTree with async initialization
2141
+ * Create a new Relay Service client
2142
+ *
2143
+ * @param baseUrl - Relay service base URL
2125
2144
  */
2126
- static create(levels?: number, leaves?: bigint[]): Promise<MerkleTree>;
2145
+ constructor(baseUrl: string);
2127
2146
  /**
2128
- * Rebuild the tree from the leaves (synchronous — poseidon must be initialized)
2147
+ * Submit a withdrawal transaction via relay
2148
+ *
2149
+ * The relay service will validate the proof, pay for transaction fees,
2150
+ * and submit the transaction on-chain.
2151
+ *
2152
+ * @param params - Withdrawal parameters
2153
+ * @param onStatusUpdate - Optional callback for status updates
2154
+ * @param onRequestId - CRITICAL: Callback when request_id is received.
2155
+ * Persist this ID to recover if browser crashes during polling.
2156
+ * @returns Transaction signature when completed
2157
+ *
2158
+ * @example
2159
+ * ```typescript
2160
+ * const signature = await relay.submitWithdraw({
2161
+ * proof: proofHex,
2162
+ * publicInputs: { root, nf, outputs_hash, amount },
2163
+ * outputs: [{ recipient: addr, amount: lamports }],
2164
+ * feeBps: 50
2165
+ * }, (status) => console.log(`Status: ${status}`),
2166
+ * (requestId) => localStorage.setItem('pending_withdraw', requestId));
2167
+ * console.log(`Transaction: ${signature}`);
2168
+ * ```
2129
2169
  */
2130
- private _rebuildSync;
2170
+ submitWithdraw(params: {
2171
+ proof: string;
2172
+ publicInputs: {
2173
+ root: string;
2174
+ nf: string;
2175
+ outputs_hash: string;
2176
+ amount: number;
2177
+ };
2178
+ outputs: Array<{
2179
+ recipient: string;
2180
+ amount: number;
2181
+ }>;
2182
+ feeBps: number;
2183
+ metadataBundle?: EncryptedMetadataBundle;
2184
+ }, onStatusUpdate?: (status: string) => void, onRequestId?: (requestId: string) => void): Promise<string>;
2131
2185
  /**
2132
- * Get the tree root
2186
+ * Resume polling for a withdrawal that was previously started
2187
+ *
2188
+ * Use this after page reload to check status of a pending withdrawal.
2189
+ * The requestId should have been persisted via the onRequestId callback.
2190
+ *
2191
+ * @param requestId - Request ID from a previous submitWithdraw call
2192
+ * @param onStatusUpdate - Optional callback for status updates
2193
+ * @returns Transaction signature if completed, null if still pending/failed
2194
+ *
2195
+ * @example
2196
+ * ```typescript
2197
+ * // On page load, check for pending withdrawal
2198
+ * const pendingId = localStorage.getItem('pending_withdraw');
2199
+ * if (pendingId) {
2200
+ * const result = await relay.resumeWithdraw(pendingId);
2201
+ * if (result.status === 'completed') {
2202
+ * console.log('Withdrawal completed:', result.signature);
2203
+ * localStorage.removeItem('pending_withdraw');
2204
+ * }
2205
+ * }
2206
+ * ```
2133
2207
  */
2134
- root(): bigint;
2208
+ resumeWithdraw(requestId: string, onStatusUpdate?: (status: string) => void): Promise<{
2209
+ status: 'completed' | 'failed' | 'pending';
2210
+ signature?: string;
2211
+ error?: string;
2212
+ }>;
2135
2213
  /**
2136
- * Get the number of leaves in the tree
2214
+ * Poll for withdrawal completion
2215
+ *
2216
+ * @param requestId - Request ID from relay service
2217
+ * @param onStatusUpdate - Optional callback for status updates
2218
+ * @returns Transaction signature when completed
2137
2219
  */
2138
- get length(): number;
2220
+ private pollForCompletion;
2139
2221
  /**
2140
- * Insert a new leaf into the tree
2222
+ * Submit a swap transaction via relay
2223
+ *
2224
+ * Similar to submitWithdraw but includes swap parameters for token swaps.
2225
+ * The relay service will validate the proof, execute the swap, pay for fees,
2226
+ * and submit the transaction on-chain.
2227
+ *
2228
+ * @param params - Swap parameters
2229
+ * @param onStatusUpdate - Optional callback for status updates
2230
+ * @returns Transaction signature when completed
2231
+ *
2232
+ * @example
2233
+ * ```typescript
2234
+ * const signature = await relay.submitSwap({
2235
+ * proof: proofHex,
2236
+ * publicInputs: { root, nf, outputs_hash, amount },
2237
+ * outputs: [{ recipient: addr, amount: lamports }],
2238
+ * feeBps: 50,
2239
+ * swap: {
2240
+ * output_mint: tokenMint.toBase58(),
2241
+ * slippage_bps: 100,
2242
+ * min_output_amount: minAmount
2243
+ * }
2244
+ * }, (status) => console.log(`Status: ${status}`));
2245
+ * console.log(`Transaction: ${signature}`);
2246
+ * ```
2141
2247
  */
2142
- insert(leaf: bigint): void;
2248
+ submitSwap(params: {
2249
+ proof: string;
2250
+ publicInputs: {
2251
+ root: string;
2252
+ nf: string;
2253
+ outputs_hash: string;
2254
+ amount: number;
2255
+ };
2256
+ outputs: Array<{
2257
+ recipient: string;
2258
+ amount: number;
2259
+ }>;
2260
+ feeBps: number;
2261
+ swap: {
2262
+ output_mint: string;
2263
+ slippage_bps: number;
2264
+ min_output_amount: number;
2265
+ };
2266
+ metadataBundle?: EncryptedMetadataBundle;
2267
+ }, onStatusUpdate?: (status: string) => void, onRequestId?: (requestId: string) => void): Promise<string>;
2143
2268
  /**
2144
- * Insert multiple leaves
2269
+ * Get transaction status
2270
+ *
2271
+ * @param requestId - Request ID from previous submission
2272
+ * @returns Current status
2273
+ *
2274
+ * @example
2275
+ * ```typescript
2276
+ * const status = await relay.getStatus(requestId);
2277
+ * console.log(`Status: ${status.status}`);
2278
+ * if (status.status === 'completed') {
2279
+ * console.log(`TX: ${status.txId}`);
2280
+ * }
2281
+ * ```
2145
2282
  */
2146
- bulkInsert(leaves: bigint[]): void;
2283
+ getStatus(requestId: string): Promise<TxStatus>;
2147
2284
  /**
2148
- * Update the path from a leaf to the root
2285
+ * Register viewing key with relay for compliance decryption.
2286
+ * This is a one-time operation - the viewing key is stored by the relay.
2287
+ *
2288
+ * The user must sign a one-time relay challenge proving wallet ownership.
2289
+ *
2290
+ * @param userPubkey - User's wallet public key (base58)
2291
+ * @param viewingKey - Viewing key private key (32 bytes, hex encoded)
2292
+ * @param signMessage - Function to sign challenge message bytes
2293
+ *
2294
+ * @example
2295
+ * ```typescript
2296
+ * await relay.registerViewingKey(
2297
+ * userPublicKey.toBase58(),
2298
+ * viewingKeyHex,
2299
+ * signatureBase64
2300
+ * );
2301
+ * ```
2149
2302
  */
2150
- private _updatePath;
2303
+ registerViewingKey(userPubkey: string, viewingKey: string, signMessage: (message: Uint8Array) => Promise<Uint8Array>): Promise<boolean>;
2151
2304
  /**
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
2305
+ * Fetch relay compliance master public key.
2306
+ * DEPRECATED: This endpoint is no longer used
2155
2307
  */
2156
- path(index: number): {
2157
- pathElements: bigint[];
2158
- pathIndices: number;
2159
- };
2308
+ getCompliancePublicKey(): Promise<Uint8Array>;
2160
2309
  /**
2161
- * Find the index of a leaf in the tree
2162
- * @param leaf Leaf value to find
2163
- * @returns Index if found, -1 otherwise
2310
+ * Convert bytes to base64 string
2164
2311
  */
2165
- indexOf(leaf: bigint): number;
2312
+ private bytesToBase64;
2166
2313
  /**
2167
- * Get all leaves
2314
+ * Sleep utility
2168
2315
  */
2169
- leaves(): bigint[];
2316
+ private sleep;
2317
+ private computeViewingKeyIdentifier;
2170
2318
  }
2319
+
2171
2320
  /**
2172
- * Build a MerkleTree from commitment values
2173
- * @param commitments Array of commitment bigints
2174
- * @param height Tree height (default: 32)
2321
+ * Risk Oracle Service
2322
+ *
2323
+ * Self-contained module for fetching Switchboard risk quote instructions
2324
+ * using the Range Risk API. Eliminates the need for an external web endpoint
2325
+ * (e.g. `/api/risk-quote`) by calling Switchboard directly from the SDK.
2326
+ *
2327
+ * Uses dynamic imports for @switchboard-xyz packages so they are only loaded
2328
+ * when fetchRiskQuoteIx is actually called — not at SDK import time. This
2329
+ * prevents the heavy Node.js-only Switchboard code from being bundled into
2330
+ * browser builds (Next.js, etc.).
2331
+ *
2332
+ * Usage:
2333
+ * const { instruction, queue } = await fetchRiskQuoteIx(connection, wallet, rangeApiKey);
2175
2334
  */
2176
- declare function buildMerkleTree(commitments: bigint[], height?: number): Promise<MerkleTree>;
2177
2335
 
2178
2336
  /**
2179
- * Relay client utilities for fetching data from the relay service
2337
+ * Fetch a Switchboard risk quote instruction directly from Range + Switchboard.
2338
+ *
2339
+ * This removes the need for an external `/api/risk-quote` endpoint. The SDK
2340
+ * calls Switchboard's crossbar oracle network directly with the Range API key.
2341
+ *
2342
+ * @param connection - Solana RPC connection
2343
+ * @param wallet - Depositor's public key (the wallet being risk-scored)
2344
+ * @param rangeApiKey - Range.org API key for the risk score lookup
2345
+ * @returns The Ed25519 sig-verify instruction to prepend at index 0, plus the queue pubkey
2180
2346
  */
2181
-
2182
- interface CommitmentEntry {
2183
- index: number;
2347
+ declare function fetchRiskQuoteIx(connection: Connection, wallet: PublicKey, rangeApiKey: string): Promise<{
2348
+ instruction: TransactionInstruction;
2349
+ queue: PublicKey;
2350
+ }>;
2351
+
2352
+ /**
2353
+ * Encrypted Output Helpers
2354
+ *
2355
+ * Functions for creating encrypted outputs that enable note scanning
2356
+ */
2357
+
2358
+ /**
2359
+ * Prepare encrypted output for scanning by wallet owner
2360
+ *
2361
+ * @param note - Note to encrypt
2362
+ * @param cloakKeys - Wallet's Cloak keys (for self-encryption)
2363
+ * @returns Base64-encoded encrypted output
2364
+ */
2365
+ declare function prepareEncryptedOutput(note: CloakNote, cloakKeys: CloakKeyPair): string;
2366
+ /**
2367
+ * Prepare encrypted output for a specific recipient
2368
+ *
2369
+ * @param note - Note to encrypt
2370
+ * @param recipientPvkHex - Recipient's public view key (hex)
2371
+ * @returns Base64-encoded encrypted output
2372
+ */
2373
+ declare function prepareEncryptedOutputForRecipient(note: CloakNote, recipientPvkHex: string): string;
2374
+ /**
2375
+ * Simple base64 encoding for v1.0 notes (no encryption)
2376
+ *
2377
+ * @param note - Note to encode
2378
+ * @returns Base64-encoded note data
2379
+ */
2380
+ declare function encodeNoteSimple(note: CloakNote): string;
2381
+
2382
+ /**
2383
+ * Wallet Integration Helpers
2384
+ *
2385
+ * Helper functions for working with Solana Wallet Adapters
2386
+ */
2387
+
2388
+ /**
2389
+ * Validate wallet is connected and has public key
2390
+ */
2391
+ declare function validateWalletConnected(wallet: WalletAdapter | Keypair): void;
2392
+ /**
2393
+ * Get public key from wallet or keypair
2394
+ */
2395
+ declare function getPublicKey(wallet: WalletAdapter | Keypair): PublicKey;
2396
+ /**
2397
+ * Send transaction using wallet adapter or keypair
2398
+ */
2399
+ declare function sendTransaction(transaction: Transaction, wallet: WalletAdapter | Keypair, connection: Connection, options?: SendOptions): Promise<string>;
2400
+ /**
2401
+ * Sign transaction using wallet adapter or keypair
2402
+ */
2403
+ declare function signTransaction<T extends Transaction>(transaction: T, wallet: WalletAdapter | Keypair): Promise<T>;
2404
+ /**
2405
+ * Create a keypair adapter for testing
2406
+ */
2407
+ declare function keypairToAdapter(keypair: Keypair): WalletAdapter;
2408
+
2409
+ /**
2410
+ * Create a deposit instruction
2411
+ *
2412
+ * Deposits SOL into the Cloak protocol by creating a commitment.
2413
+ *
2414
+ * Instruction format:
2415
+ * - Byte 0: Discriminant (0x01 for Deposit, per ShieldPoolInstruction enum)
2416
+ * - Bytes 1-8: Amount (u64, little-endian)
2417
+ * - Bytes 9-40: Commitment (32 bytes)
2418
+ *
2419
+ * @param params - Deposit parameters
2420
+ * @returns Transaction instruction
2421
+ *
2422
+ * @example
2423
+ * ```typescript
2424
+ * const instruction = createDepositInstruction({
2425
+ * programId: CLOAK_PROGRAM_ID,
2426
+ * payer: wallet.publicKey,
2427
+ * pool: POOL_ADDRESS,
2428
+ * commitments: COMMITMENTS_ADDRESS,
2429
+ * amount: 1_000_000_000, // 1 SOL
2430
+ * commitment: commitmentBytes
2431
+ * });
2432
+ * ```
2433
+ */
2434
+ declare function createDepositInstruction(params: {
2435
+ programId: PublicKey;
2436
+ payer: PublicKey;
2437
+ pool: PublicKey;
2438
+ merkleTree: PublicKey;
2439
+ amount: number;
2440
+ commitment: Uint8Array;
2441
+ }): TransactionInstruction;
2442
+ /**
2443
+ * Deposit instruction parameters for type safety
2444
+ */
2445
+ interface DepositInstructionParams {
2446
+ programId: PublicKey;
2447
+ payer: PublicKey;
2448
+ pool: PublicKey;
2449
+ merkleTree: PublicKey;
2450
+ amount: number;
2451
+ commitment: Uint8Array;
2452
+ }
2453
+ /**
2454
+ * Validate deposit instruction parameters
2455
+ *
2456
+ * @param params - Parameters to validate
2457
+ * @throws Error if invalid
2458
+ */
2459
+ declare function validateDepositParams(params: DepositInstructionParams): void;
2460
+
2461
+ /**
2462
+ * Program Derived Address (PDA) utilities for Shield Pool
2463
+ *
2464
+ * These functions derive deterministic addresses from the program ID and seeds.
2465
+ * This matches the behavior in tooling/test/src/shared.rs::get_pda_addresses()
2466
+ */
2467
+
2468
+ interface ShieldPoolPDAs {
2469
+ pool: PublicKey;
2470
+ merkleTree: PublicKey;
2471
+ vaultAuthority: PublicKey;
2472
+ treasury: PublicKey;
2473
+ }
2474
+ /**
2475
+ * Derive all Shield Pool PDAs from program ID + pool mint
2476
+ *
2477
+ * Seeds match the on-chain mint-scoped program:
2478
+ * - pool: [b"pool", mint]
2479
+ * - merkle_tree: [b"merkle_tree", mint]
2480
+ * - treasury: [b"treasury", mint]
2481
+ * - vault_authority: [b"vault_authority", mint]
2482
+ *
2483
+ * @param programId - Optional program ID (defaults to CLOAK_PROGRAM_ID)
2484
+ * @param mint - Pool mint (defaults to NATIVE_SOL_MINT / WSOL sentinel)
2485
+ */
2486
+ declare function getShieldPoolPDAs(programId?: PublicKey, mint?: PublicKey): ShieldPoolPDAs;
2487
+ /**
2488
+ * Derive the nullifier PDA for a specific pool + nullifier hash.
2489
+ *
2490
+ * With the new PDA-per-nullifier design, each nullifier has its own PDA
2491
+ * instead of being stored in a shared shard. The PDA is created when
2492
+ * the nullifier is used during withdrawal.
2493
+ *
2494
+ * Seeds: ["nullifier", pool_pubkey, nullifier_hash]
2495
+ *
2496
+ * @param poolPubkey - Pool PDA that scopes nullifier domain
2497
+ * @param nullifier - 32-byte nullifier hash
2498
+ * @param programId - Optional program ID (defaults to CLOAK_PROGRAM_ID)
2499
+ * @returns [PublicKey, bump] - The nullifier PDA and its bump seed
2500
+ */
2501
+ declare function getNullifierPDA(poolPubkey: PublicKey, nullifier: Uint8Array | Buffer, programId?: PublicKey): [PublicKey, number];
2502
+ /**
2503
+ * Derive the swap state PDA for a given pool + nullifier.
2504
+ *
2505
+ * Seeds: ["swap_state", pool_pubkey, nullifier_hash]
2506
+ *
2507
+ * @param poolPubkey - Pool PDA used for swap state domain separation
2508
+ * @param nullifier - 32-byte nullifier hash
2509
+ * @param programId - Optional program ID (defaults to CLOAK_PROGRAM_ID)
2510
+ * @returns [PublicKey, bump] - The swap state PDA and its bump seed
2511
+ */
2512
+ declare function getSwapStatePDA(poolPubkey: PublicKey, nullifier: Uint8Array | Buffer, programId?: PublicKey): [PublicKey, number];
2513
+
2514
+ /**
2515
+ * On-chain Merkle proof computation
2516
+ *
2517
+ * Computes Merkle proofs directly from on-chain tree state,
2518
+ * eliminating the need for an indexer for proof generation.
2519
+ */
2520
+
2521
+ /**
2522
+ * Merkle proof result
2523
+ */
2524
+ interface OnchainMerkleProof {
2525
+ pathElements: string[];
2526
+ pathIndices: number[];
2527
+ root: string;
2528
+ }
2529
+ interface MerkleTreeState {
2530
+ nextIndex: number;
2531
+ root: string;
2532
+ subtrees: string[];
2533
+ }
2534
+ /**
2535
+ * Read the Merkle tree state from on-chain account
2536
+ * @param forceConfirmed - If true, forces "confirmed" commitment level for fresh data
2537
+ * @param relayUrl - Optional relay URL to query for current root (bypasses RPC caching)
2538
+ * @param mint - Optional pool mint used when querying relay /merkle-root
2539
+ */
2540
+ declare function readMerkleTreeState(connection: Connection, merkleTreePDA: PublicKey, forceConfirmed?: boolean, relayUrl?: string,
2541
+ /** When true, skip relay root and use chain directly (avoids stale relay root causing ProofInvalid) */
2542
+ skipRelayRoot?: boolean, mint?: PublicKey): Promise<MerkleTreeState>;
2543
+ /**
2544
+ * Compute Merkle proof for a leaf at a given index using on-chain state
2545
+ *
2546
+ * This works by:
2547
+ * 1. Reading the subtrees (frontier) from the on-chain account
2548
+ * 2. For each level, determining the sibling:
2549
+ * - If index is odd: sibling is the stored subtree (left sibling)
2550
+ * - If index is even: sibling is either a subsequent subtree or zero value
2551
+ *
2552
+ * Note: This works best for recent leaves where siblings are zero values.
2553
+ * For older leaves with non-zero siblings that aren't stored in subtrees,
2554
+ * an indexer may still be needed.
2555
+ *
2556
+ * @param connection - Solana connection
2557
+ * @param merkleTreePDA - PDA of the merkle tree account
2558
+ * @param leafIndex - Index of the leaf to compute proof for
2559
+ * @param forceConfirmed - If true, forces "confirmed" commitment level for fresh data
2560
+ * @returns Merkle proof with path elements and indices
2561
+ */
2562
+ declare function computeProofFromChain(connection: Connection, merkleTreePDA: PublicKey, leafIndex: number, forceConfirmed?: boolean): Promise<OnchainMerkleProof>;
2563
+ /**
2564
+ * Compute proof for the most recently inserted leaf
2565
+ *
2566
+ * This is the most reliable case - immediately after your deposit,
2567
+ * all siblings to the right are zero values, and siblings to the left
2568
+ * are stored in the subtrees.
2569
+ */
2570
+ declare function computeProofForLatestDeposit(connection: Connection, merkleTreePDA: PublicKey): Promise<OnchainMerkleProof & {
2571
+ leafIndex: number;
2572
+ }>;
2573
+
2574
+ /**
2575
+ * Relay client utilities for fetching data from the relay service
2576
+ */
2577
+
2578
+ interface CommitmentEntry {
2579
+ index: number;
2184
2580
  commitment: string;
2185
2581
  }
2186
2582
  interface CommitmentsResponse {
@@ -2316,490 +2712,228 @@ interface WithdrawRegularInputs {
2316
2712
  rem: bigint;
2317
2713
  }
2318
2714
  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;
2341
- }
2342
- /**
2343
- * Generate Groth16 proof for regular withdrawal using Circom WASM
2344
- *
2345
- * This matches the approach in services-new/tests/src/proof.ts
2346
- *
2347
- * @param inputs - Circuit inputs
2348
- * @param circuitsPath - Ignored. Proof generation always uses pinned S3 circuits.
2349
- */
2350
- declare function generateWithdrawRegularProof(inputs: WithdrawRegularInputs, circuitsPath: string): Promise<ProofResult>;
2351
- /**
2352
- * Generate Groth16 proof for swap withdrawal using Circom WASM
2353
- *
2354
- * This matches the approach in services-new/tests/src/proof.ts
2355
- *
2356
- * @param inputs - Circuit inputs
2357
- * @param circuitsPath - Ignored. Proof generation always uses pinned S3 circuits.
2358
- */
2359
- declare function generateWithdrawSwapProof(inputs: WithdrawSwapInputs, circuitsPath: string): Promise<ProofResult>;
2360
- /**
2361
- * Check if circuits are available from the pinned S3 source.
2362
- */
2363
- declare function areCircuitsAvailable(circuitsPath: string): Promise<boolean>;
2364
- /**
2365
- * Get default circuits URL.
2366
- */
2367
- declare function getDefaultCircuitsPath(): Promise<string>;
2368
- /**
2369
- * Pinned circuit artifact hashes (SHA-256).
2370
- *
2371
- * These hashes must be updated whenever the trusted circuit artifacts change.
2372
- */
2373
- declare const EXPECTED_CIRCUIT_HASHES: {
2374
- withdraw_regular_wasm: string;
2375
- withdraw_regular_zkey: string;
2376
- withdraw_swap_wasm: string;
2377
- withdraw_swap_zkey: string;
2378
- };
2379
- /**
2380
- * Circuit verification result
2381
- */
2382
- interface CircuitVerificationResult {
2383
- /** Whether verification passed */
2384
- valid: boolean;
2385
- /** Which circuit was checked */
2386
- circuit: 'withdraw_regular' | 'withdraw_swap';
2387
- /** Error message if verification failed */
2388
- error?: string;
2389
- computed?: {
2390
- wasm: string;
2391
- zkey: string;
2392
- };
2393
- expected?: {
2394
- wasm: string;
2395
- zkey: string;
2396
- };
2397
- }
2398
- /**
2399
- * Verify circuit integrity by checking verification key hashes
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
2410
- *
2411
- * @example
2412
- * ```typescript
2413
- * const result = await verifyCircuitIntegrity('https://cloak-circuits.s3.us-east-1.amazonaws.com/circuits/0.1.0', 'withdraw_regular');
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
2423
- *
2424
- * Call this at SDK initialization to ensure circuits are valid.
2425
- *
2426
- * @param circuitsPath - Ignored. Verification always uses pinned S3 circuits.
2427
- * @returns Array of verification results (one per circuit)
2428
- */
2429
- declare function verifyAllCircuits(circuitsPath: string): Promise<CircuitVerificationResult[]>;
2430
-
2431
- /**
2432
- * Pending Operations Manager
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.
2436
- *
2437
- * IMPORTANT: This uses localStorage by default which has security implications.
2438
- * Notes contain sensitive spending keys - consider using more secure storage
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
2534
- *
2535
- * @param maxAgeMs Maximum age in milliseconds before an operation is removed (default: 24 hours)
2536
- */
2537
- declare function cleanupStalePendingOperations(maxAgeMs?: number): {
2538
- removedDeposits: number;
2539
- removedWithdrawals: number;
2540
- };
2541
-
2542
- /**
2543
- * UTXO (Unspent Transaction Output) Model
2544
- *
2545
- * This module implements the UTXO model for the Cloak privacy protocol.
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)
2551
- */
2552
-
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
- /**
2629
- * Result from a UTXO transaction
2630
- */
2631
- interface TransactResult {
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[];
2715
+ sk_spend: bigint;
2716
+ r: bigint;
2717
+ amount: bigint;
2718
+ leaf_index: bigint;
2719
+ path_elements: bigint[];
2720
+ path_indices: number[];
2721
+ root: bigint;
2722
+ nullifier: bigint;
2723
+ outputs_hash: bigint;
2724
+ public_amount: bigint;
2725
+ input_mint: bigint[];
2726
+ output_mint: bigint[];
2727
+ recipient_ata: bigint[];
2728
+ min_output_amount: bigint;
2729
+ var_fee: bigint;
2730
+ rem: bigint;
2731
+ }
2732
+ interface ProofResult {
2733
+ proof: Groth16Proof;
2734
+ publicSignals: string[];
2735
+ proofBytes: Uint8Array;
2736
+ publicInputsBytes: Uint8Array;
2679
2737
  }
2680
2738
  /**
2681
- * Generate a random field element suitable for BN254
2682
- */
2683
- declare function randomFieldElement(): bigint;
2684
- /**
2685
- * Generate a new UTXO keypair
2739
+ * Generate Groth16 proof for regular withdrawal using Circom WASM
2686
2740
  *
2687
- * @returns A new keypair with random private key and derived public key
2741
+ * This matches the approach in services-new/tests/src/proof.ts
2742
+ *
2743
+ * @param inputs - Circuit inputs
2744
+ * @param circuitsPath - Ignored. Proof generation always uses pinned S3 circuits.
2688
2745
  */
2689
- declare function generateUtxoKeypair(): Promise<UtxoKeypair>;
2746
+ declare function generateWithdrawRegularProof(inputs: WithdrawRegularInputs, circuitsPath: string): Promise<ProofResult>;
2690
2747
  /**
2691
- * Derive a deterministic UTXO keypair from a wallet's spend key.
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.
2748
+ * Generate Groth16 proof for swap withdrawal using Circom WASM
2694
2749
  *
2695
- * @param skSpend - 32-byte spend key (from wallet key derivation)
2696
- * @returns UtxoKeypair with deterministic private/public keys
2750
+ * This matches the approach in services-new/tests/src/proof.ts
2751
+ *
2752
+ * @param inputs - Circuit inputs
2753
+ * @param circuitsPath - Ignored. Proof generation always uses pinned S3 circuits.
2697
2754
  */
2698
- declare function deriveUtxoKeypairFromSpendKey(skSpend: Uint8Array): Promise<UtxoKeypair>;
2755
+ declare function generateWithdrawSwapProof(inputs: WithdrawSwapInputs, circuitsPath: string): Promise<ProofResult>;
2699
2756
  /**
2700
- * Derive public key from private key
2701
- *
2702
- * @param privateKey The private key
2703
- * @returns The corresponding public key
2757
+ * Check if circuits are available from the pinned S3 source.
2704
2758
  */
2705
- declare function derivePublicKey(privateKey: bigint): Promise<bigint>;
2759
+ declare function areCircuitsAvailable(circuitsPath: string): Promise<boolean>;
2706
2760
  /**
2707
- * Create a new UTXO
2708
- *
2709
- * @param amount Amount in smallest unit
2710
- * @param keypair Owner's keypair
2711
- * @param mintAddress Token mint (defaults to native SOL)
2712
- * @returns A new UTXO (commitment will be computed)
2761
+ * Get default circuits URL.
2713
2762
  */
2714
- declare function createUtxo(amount: bigint, keypair: UtxoKeypair, mintAddress?: PublicKey): Promise<Utxo>;
2763
+ declare function getDefaultCircuitsPath(): Promise<string>;
2715
2764
  /**
2716
- * Create a zero/padding UTXO
2717
- *
2718
- * Zero UTXOs are used as padding when we need fewer than 2 inputs/outputs.
2719
- * They have zero amount and don't require valid Merkle proofs.
2720
- * Uses salt-based keypair (privateKey = salt) with blinding=0 to match the circuit
2721
- * test. By default, salt is random to avoid cross-process collisions under concurrency.
2722
- * Callers can pass an explicit salt for deterministic behavior.
2765
+ * Pinned circuit artifact hashes (SHA-256).
2723
2766
  *
2724
- * @param mintAddress Token mint (defaults to native SOL)
2725
- * @param salt Optional salt; if omitted, uses timestamp+counter for uniqueness
2767
+ * These hashes must be updated whenever the trusted circuit artifacts change.
2726
2768
  */
2727
- declare function createZeroUtxo(mintAddress?: PublicKey, salt?: bigint): Promise<Utxo>;
2769
+ declare const EXPECTED_CIRCUIT_HASHES: {
2770
+ withdraw_regular_wasm: string;
2771
+ withdraw_regular_zkey: string;
2772
+ withdraw_swap_wasm: string;
2773
+ withdraw_swap_zkey: string;
2774
+ };
2728
2775
  /**
2729
- * Convert PublicKey to field element for circuit
2730
- *
2731
- * @param pubkey Solana PublicKey
2732
- * @returns Field element representation
2776
+ * Circuit verification result
2733
2777
  */
2734
- declare function pubkeyToFieldElement(pubkey: PublicKey): bigint;
2778
+ interface CircuitVerificationResult {
2779
+ /** Whether verification passed */
2780
+ valid: boolean;
2781
+ /** Which circuit was checked */
2782
+ circuit: 'withdraw_regular' | 'withdraw_swap';
2783
+ /** Error message if verification failed */
2784
+ error?: string;
2785
+ computed?: {
2786
+ wasm: string;
2787
+ zkey: string;
2788
+ };
2789
+ expected?: {
2790
+ wasm: string;
2791
+ zkey: string;
2792
+ };
2793
+ }
2735
2794
  /**
2736
- * Compute the commitment for a UTXO
2795
+ * Verify circuit integrity by checking verification key hashes
2737
2796
  *
2738
- * commitment = Poseidon(amount, pubkey, blinding, mintAddress)
2797
+ * This function fetches the verification key and computes its hash,
2798
+ * then compares against the expected hash embedded in the SDK.
2739
2799
  *
2740
- * @param utxo The UTXO to compute commitment for
2741
- * @returns The commitment as a bigint
2800
+ * IMPORTANT: If the hashes don't match, the circuit may produce proofs
2801
+ * that will be rejected by the on-chain verifier!
2802
+ *
2803
+ * @param circuitsPath - Ignored. Verification always uses pinned S3 circuits.
2804
+ * @param circuit - Which circuit to verify ('withdraw_regular' or 'withdraw_swap')
2805
+ * @returns Verification result
2806
+ *
2807
+ * @example
2808
+ * ```typescript
2809
+ * const result = await verifyCircuitIntegrity('https://cloak-circuits.s3.us-east-1.amazonaws.com/circuits/0.1.0', 'withdraw_regular');
2810
+ * if (!result.valid) {
2811
+ * console.error('Circuit verification failed:', result.error);
2812
+ * // Don't proceed with proof generation!
2813
+ * }
2814
+ * ```
2742
2815
  */
2743
- declare function computeCommitment(utxo: Utxo): Promise<bigint>;
2816
+ declare function verifyCircuitIntegrity(circuitsPath: string, circuit: 'withdraw_regular' | 'withdraw_swap'): Promise<CircuitVerificationResult>;
2744
2817
  /**
2745
- * Compute the signature for nullifier derivation
2818
+ * Verify all circuits before use
2746
2819
  *
2747
- * signature = Poseidon(privateKey, commitment, pathIndex)
2820
+ * Call this at SDK initialization to ensure circuits are valid.
2748
2821
  *
2749
- * @param privateKey Owner's private key
2750
- * @param commitment The UTXO commitment
2751
- * @param pathIndex Merkle tree path index
2752
- * @returns The signature
2822
+ * @param circuitsPath - Ignored. Verification always uses pinned S3 circuits.
2823
+ * @returns Array of verification results (one per circuit)
2753
2824
  */
2754
- declare function computeSignature(privateKey: bigint, commitment: bigint, pathIndex: bigint): Promise<bigint>;
2825
+ declare function verifyAllCircuits(circuitsPath: string): Promise<CircuitVerificationResult[]>;
2826
+
2755
2827
  /**
2756
- * Compute the nullifier for a UTXO
2757
- *
2758
- * nullifier = Poseidon(commitment, pathIndex, signature)
2828
+ * Pending Operations Manager
2759
2829
  *
2760
- * The nullifier is a unique identifier that gets recorded on-chain
2761
- * to prevent double-spending.
2830
+ * Utility for persisting pending deposit/withdrawal operations in browser storage.
2831
+ * This enables recovery if the browser crashes or user navigates away mid-operation.
2762
2832
  *
2763
- * @param utxo The UTXO being spent
2764
- * @returns The nullifier
2833
+ * IMPORTANT: This uses localStorage by default which has security implications.
2834
+ * Notes contain sensitive spending keys - consider using more secure storage
2835
+ * in production (e.g., encrypted IndexedDB, secure enclave).
2765
2836
  */
2766
- declare function computeNullifier(utxo: Utxo): Promise<bigint>;
2837
+
2767
2838
  /**
2768
- * Serialize a UTXO to bytes for encryption
2839
+ * Pending deposit record
2769
2840
  */
2770
- declare function serializeUtxo(utxo: Utxo): Uint8Array;
2841
+ interface PendingDeposit {
2842
+ /** The note (contains spending secrets!) */
2843
+ note: CloakNote;
2844
+ /** When the deposit was initiated */
2845
+ startedAt: number;
2846
+ /** Transaction signature if available */
2847
+ txSignature?: string;
2848
+ /** Status of the deposit */
2849
+ status: "pending" | "tx_sent" | "confirmed" | "failed";
2850
+ /** Error message if failed */
2851
+ error?: string;
2852
+ }
2771
2853
  /**
2772
- * Deserialize a UTXO from bytes
2854
+ * Pending withdrawal record
2773
2855
  */
2774
- declare function deserializeUtxo(bytes: Uint8Array): Promise<Utxo>;
2856
+ interface PendingWithdrawal {
2857
+ /** The relay request ID (for resumption) */
2858
+ requestId: string;
2859
+ /** The note commitment being withdrawn */
2860
+ commitment: string;
2861
+ /** The nullifier being used */
2862
+ nullifier: string;
2863
+ /** When the withdrawal was initiated */
2864
+ startedAt: number;
2865
+ /** Status of the withdrawal */
2866
+ status: "pending" | "processing" | "completed" | "failed";
2867
+ /** Transaction signature if completed */
2868
+ txSignature?: string;
2869
+ /** Error message if failed */
2870
+ error?: string;
2871
+ }
2775
2872
  /**
2776
- * Convert bigint to hex string (64 chars, padded)
2873
+ * Save a pending deposit
2874
+ * Call this BEFORE sending the on-chain transaction to ensure note is persisted
2777
2875
  */
2778
- declare function bigintToHex(value: bigint): string;
2876
+ declare function savePendingDeposit(deposit: PendingDeposit): void;
2779
2877
  /**
2780
- * Convert hex string to bigint
2878
+ * Load all pending deposits
2781
2879
  */
2782
- declare function hexToBigint(hex: string): bigint;
2880
+ declare function loadPendingDeposits(): PendingDeposit[];
2783
2881
  /**
2784
- * Convert bigint to 32-byte array (big-endian for circuits)
2882
+ * Update a pending deposit status
2785
2883
  */
2786
- declare function bigintToBytes32(value: bigint): Uint8Array;
2884
+ declare function updatePendingDeposit(commitment: string, updates: Partial<PendingDeposit>): void;
2787
2885
  /**
2788
- * Check if two UTXOs are equal (same commitment)
2886
+ * Remove a pending deposit (e.g., after successful confirmation)
2789
2887
  */
2790
- declare function utxoEquals(a: Utxo, b: Utxo): Promise<boolean>;
2888
+ declare function removePendingDeposit(commitment: string): void;
2791
2889
  /**
2792
- * Calculate total amount from an array of UTXOs
2890
+ * Clear all pending deposits
2793
2891
  */
2794
- declare function sumUtxoAmounts(utxos: Utxo[]): bigint;
2892
+ declare function clearPendingDeposits(): void;
2795
2893
  /**
2796
- * Select UTXOs to cover a target amount
2894
+ * Save a pending withdrawal
2895
+ * Call this when you receive the request_id from the relay
2896
+ */
2897
+ declare function savePendingWithdrawal(withdrawal: PendingWithdrawal): void;
2898
+ /**
2899
+ * Load all pending withdrawals
2900
+ */
2901
+ declare function loadPendingWithdrawals(): PendingWithdrawal[];
2902
+ /**
2903
+ * Update a pending withdrawal status
2904
+ */
2905
+ declare function updatePendingWithdrawal(requestId: string, updates: Partial<PendingWithdrawal>): void;
2906
+ /**
2907
+ * Remove a pending withdrawal (e.g., after successful completion)
2908
+ */
2909
+ declare function removePendingWithdrawal(requestId: string): void;
2910
+ /**
2911
+ * Clear all pending withdrawals
2912
+ */
2913
+ declare function clearPendingWithdrawals(): void;
2914
+ /**
2915
+ * Check if there are any pending operations that need recovery
2916
+ * Call this on page load to determine if recovery UI should be shown
2917
+ */
2918
+ declare function hasPendingOperations(): boolean;
2919
+ /**
2920
+ * Get summary of pending operations for recovery UI
2921
+ */
2922
+ declare function getPendingOperationsSummary(): {
2923
+ deposits: PendingDeposit[];
2924
+ withdrawals: PendingWithdrawal[];
2925
+ totalPending: number;
2926
+ };
2927
+ /**
2928
+ * Clean up stale pending operations
2929
+ * Call this periodically to remove old failed/completed operations
2797
2930
  *
2798
- * @param available Available UTXOs (sorted by amount descending)
2799
- * @param targetAmount Target amount to cover
2800
- * @returns Selected UTXOs that cover the target, or null if insufficient
2931
+ * @param maxAgeMs Maximum age in milliseconds before an operation is removed (default: 24 hours)
2801
2932
  */
2802
- declare function selectUtxos(available: Utxo[], targetAmount: bigint): Utxo[] | null;
2933
+ declare function cleanupStalePendingOperations(maxAgeMs?: number): {
2934
+ removedDeposits: number;
2935
+ removedWithdrawals: number;
2936
+ };
2803
2937
 
2804
2938
  /**
2805
2939
  * UTXO Transaction Methods
@@ -3426,8 +3560,8 @@ declare class SimpleWallet {
3426
3560
  * @packageDocumentation
3427
3561
  */
3428
3562
 
3429
- declare const VERSION = "1.0.0";
3563
+ declare const VERSION = "0.1.5";
3430
3564
  /** True when scanner supports TransactSwap (tag 1). Check this to verify the correct SDK bundle is loaded. */
3431
3565
  declare const SCANNER_SUPPORTS_TRANSACT_SWAP = true;
3432
3566
 
3433
- export { CLOAK_PROGRAM_ID, type ChainNoteTxType, type CircuitVerificationResult, type CloakConfig, CloakError, type CloakKeyPair, type CloakNote, CloakSDK, type CommitmentEntry, type CommitmentsResponse, type CompactChainNote, type ComplianceReport, type ComplianceTxType, DEFAULT_CIRCUITS_URL, DEFAULT_TRANSACTION_CIRCUITS_URL, type DepositInstructionParams, type DepositOptions, type DepositResult, type DepositStatus, EXPECTED_CIRCUIT_HASHES, type EncryptedMetadataBundle, type EncryptedNote$1 as EncryptedNote, type ErrorCategory, type ExpandedSpendKey, FIXED_FEE_LAMPORTS, type Groth16Proof, LAMPORTS_PER_SOL, LocalStorageAdapter, type LogLevel, type Logger, MERKLE_TREE_HEIGHT, MIN_DEPOSIT_LAMPORTS, type MasterKey, type MaxLengthArray, MemoryStorageAdapter, type MerkleProof, type MerkleRootResponse, MerkleTree, NATIVE_SOL_MINT, type Network, type NoteData, type OnchainMerkleProof, type PendingDeposit, type PendingWithdrawal, type ProofResult, RelayService, type RiskQuoteInstructionResponse, RootNotFoundError, SCANNER_SUPPORTS_TRANSACT_SWAP, SIGN_IN_MESSAGE, type ScanOptions, type ScanResult, type ScanSummary, type ScannedTransaction, ShieldPoolErrors, type ShieldPoolPDAs, SimpleWallet, type SpendKey, type StorageAdapter, type SwapOptions, type SwapParams, type SwapResult, type TransactOptions, type TransactParams, type TransactResult, type TransactionMetadata, type Transfer, type TransferOptions, type TransferResult, type TxStatus, type UserFriendlyError, type Utxo, type EncryptedNote as UtxoEncryptedNote, type UtxoKeypair, type UtxoSwapParams, type UtxoSwapResult, UtxoWallet, VARIABLE_FEE_DENOMINATOR, VARIABLE_FEE_NUMERATOR, VARIABLE_FEE_RATE, VERSION, type ViewKey, type ViewingKeyPair, type WalletAdapter, type WalletUtxo, type WithdrawOptions, type WithdrawRegularInputs, type WithdrawSubmissionResult, type WithdrawSwapInputs, areCircuitsAvailable, bigintToBytes32$1 as bigintToBytes32, bigintToHex, buildMerkleTree, buildMerkleTreeFromChain, buildMerkleTreeFromRelay, buildPublicInputsBytes, bytesToHex, calculateFee, calculateFeeBigint, calculateRelayFee, chainNoteFromBase64, chainNoteToBase64, cleanupStalePendingOperations, clearPendingDeposits, clearPendingWithdrawals, computeChainNoteHash, computeCommitment$1 as computeCommitment, computeExtDataHash, computeMerkleRoot, computeNullifier$1 as computeNullifier, computeNullifierAsync, computeNullifierSync, computeOutputsHash, computeOutputsHashAsync, computeOutputsHashSync, computeProofForLatestDeposit, computeProofFromChain, computeSignature, computeSwapOutputsHash, computeSwapOutputsHashAsync, computeSwapOutputsHashSync, computeCommitment as computeUtxoCommitment, computeNullifier as computeUtxoNullifier, copyNoteToClipboard, createCloakError, createDepositInstruction, createLogger, createUtxo, createZeroUtxo, decryptCompactChainNote, decryptComplianceMetadataWithMasterKey, decryptTransactionMetadata, deriveDiversifiedViewingKey, deriveDiversifier, derivePublicKey, deriveSpendKey, deriveUserCompliancePublicKey, deriveUserComplianceScalar, deriveUtxoKeypairFromSpendKey, deriveViewKey, deriveViewingKeyFromNk, deriveViewingKeyFromSpendKey, deriveViewingKeyFromUtxoPrivateKey, deserializeUtxo, detectNetworkFromRpcUrl, downloadNote, encodeNoteSimple, encryptCompactChainNote, encryptNoteForRecipient, encryptTransactionMetadata, encryptTransactionMetadataBundle, expandSpendKey, exportKeys, exportNote, exportWalletKeys, fetchCommitments, fetchRiskQuoteInstruction, fetchRiskQuoteIx, filterNotesByNetwork, filterWithdrawableNotes, findNoteByCommitment, formatAmount, formatComplianceCsv, formatErrorForLogging, formatSol, fullWithdraw, generateCloakKeys, generateCommitment, generateCommitmentAsync, generateMasterSeed, generateNote, generateNoteFromWallet, generateUtxoKeypair, generateViewingKeyPair, generateWithdrawRegularProof, generateWithdrawSwapProof, getAddressExplorerUrl, getCircuitsPath, getDefaultCircuitsPath, getDistributableAmount, getExplorerUrl, getNkFromUtxoPrivateKey, getNullifierPDA, getPendingOperationsSummary, getPublicKey, getPublicViewKey, getRecipientAmount, getRpcUrlForNetwork, getShieldPoolPDAs, getSwapStatePDA, getViewKey, hasPendingOperations, hexToBigint$1 as hexToBigint, hexToBytes, importKeys, importWalletKeys, isDebugEnabled, isRootNotFoundError, isValidHex, isValidRpcUrl, isValidSolanaAddress, isWithdrawAmountSufficient, isWithdrawable, keypairToAdapter, loadPendingDeposits, loadPendingWithdrawals, parseAmount, parseError, parseNote, parseRelayErrorResponse, parseTransactionError, partialWithdraw, poseidonHash, preflightCheck, prepareEncryptedOutput, prepareEncryptedOutputForRecipient, proofToBytes, pubkeyToFieldElement, pubkeyToLimbs, randomBytes, randomFieldElement, readMerkleTreeState, registerViewingKey, removePendingDeposit, removePendingWithdrawal, savePendingDeposit, savePendingWithdrawal, scanNotesForWallet, scanTransactions, sdkLogger, selectUtxos, sendTransaction, serializeNote, serializeUtxo, setCircuitsPath, setDebugMode, signTransaction, splitTo2Limbs, sumUtxoAmounts, swapUtxo, swapWithChange, toComplianceReport, transact, transfer, truncate, tryDecryptNote, updateNoteWithDeposit, updatePendingDeposit, updatePendingWithdrawal, bigintToBytes32 as utxoBigintToBytes32, utxoEquals, hexToBigint as utxoHexToBigint, validateDepositParams, validateNote, validateOutputsSum, validateRoot, validateTransfers, validateWalletConnected, validateWithdrawableNote, verifyAllCircuits, verifyCircuitIntegrity, waitForRoot, withTiming };
3567
+ export { CLOAK_PROGRAM_ID, type ChainNoteTxType, type CircuitVerificationResult, type CloakConfig, CloakError, type CloakKeyPair, type CloakNote, CloakSDK, type CommitmentEntry, type CommitmentsResponse, type CompactChainNote, type ComplianceReport, type ComplianceTxType, DEFAULT_CIRCUITS_URL, DEFAULT_TRANSACTION_CIRCUITS_URL, type DepositInstructionParams, type DepositOptions, type DepositResult, type DepositStatus, EXPECTED_CIRCUIT_HASHES, type EncryptedMetadataBundle, type EncryptedNote$1 as EncryptedNote, type ErrorCategory, type ExpandedSpendKey, FIXED_FEE_LAMPORTS, type Groth16Proof, LAMPORTS_PER_SOL, LocalStorageAdapter, type LogLevel, type Logger, MERKLE_TREE_HEIGHT, MIN_DEPOSIT_LAMPORTS, type MasterKey, type MaxLengthArray, MemoryStorageAdapter, type MerkleProof, type MerkleRootResponse, MerkleTree, NATIVE_SOL_MINT, type Network, type NoteData, type OnchainMerkleProof, type PendingDeposit, type PendingWithdrawal, type ProofResult, RelayInternalError, RelayService, type RiskQuoteInstructionResponse, RootNotFoundError, SCANNER_SUPPORTS_TRANSACT_SWAP, SIGN_IN_MESSAGE, SanctionsQuoteError, type ScanOptions, type ScanResult, type ScanSummary, type ScannedTransaction, ShieldPoolErrors, type ShieldPoolPDAs, SimpleWallet, type SpendKey, type StorageAdapter, type SwapOptions, type SwapParams, type SwapResult, type TransactOptions, type TransactParams, type TransactResult, type TransactionMetadata, type Transfer, type TransferOptions, type TransferResult, type TxStatus, type UserFriendlyError, type Utxo, UtxoAlreadySpentError, type EncryptedNote as UtxoEncryptedNote, type UtxoKeypair, type UtxoSwapParams, type UtxoSwapResult, UtxoWallet, VARIABLE_FEE_DENOMINATOR, VARIABLE_FEE_NUMERATOR, VARIABLE_FEE_RATE, VERSION, type VerifyUtxosResult, type ViewKey, type ViewingKeyPair, type WalletAdapter, type WalletUtxo, type WithdrawOptions, type WithdrawRegularInputs, type WithdrawSubmissionResult, type WithdrawSwapInputs, areCircuitsAvailable, bigintToBytes32$1 as bigintToBytes32, bigintToHex, buildMerkleTree, buildMerkleTreeFromChain, buildMerkleTreeFromRelay, buildPublicInputsBytes, bytesToHex, calculateFee, calculateFeeBigint, calculateRelayFee, chainNoteFromBase64, chainNoteToBase64, classifyRelayError, cleanupStalePendingOperations, clearPendingDeposits, clearPendingWithdrawals, computeChainNoteHash, computeCommitment$1 as computeCommitment, computeExtDataHash, computeMerkleRoot, computeNullifier$1 as computeNullifier, computeNullifierAsync, computeNullifierSync, computeOutputsHash, computeOutputsHashAsync, computeOutputsHashSync, computeProofForLatestDeposit, computeProofFromChain, computeSignature, computeSwapOutputsHash, computeSwapOutputsHashAsync, computeSwapOutputsHashSync, computeCommitment as computeUtxoCommitment, computeNullifier as computeUtxoNullifier, copyNoteToClipboard, createCloakError, createDepositInstruction, createLogger, createUtxo, createZeroUtxo, decryptCompactChainNote, decryptComplianceMetadataWithMasterKey, decryptTransactionMetadata, deriveDiversifiedViewingKey, deriveDiversifier, derivePublicKey, deriveSpendKey, deriveUserCompliancePublicKey, deriveUserComplianceScalar, deriveUtxoKeypairFromSpendKey, deriveViewKey, deriveViewingKeyFromNk, deriveViewingKeyFromSpendKey, deriveViewingKeyFromUtxoPrivateKey, deserializeUtxo, detectNetworkFromRpcUrl, downloadNote, encodeNoteSimple, encryptCompactChainNote, encryptNoteForRecipient, encryptTransactionMetadata, encryptTransactionMetadataBundle, expandSpendKey, exportKeys, exportNote, exportWalletKeys, fetchCommitments, fetchRiskQuoteInstruction, fetchRiskQuoteIx, filterNotesByNetwork, filterWithdrawableNotes, findNoteByCommitment, formatAmount, formatComplianceCsv, formatErrorForLogging, formatSol, fullWithdraw, generateCloakKeys, generateCommitment, generateCommitmentAsync, generateMasterSeed, generateNote, generateNoteFromWallet, generateUtxoKeypair, generateViewingKeyPair, generateWithdrawRegularProof, generateWithdrawSwapProof, getAddressExplorerUrl, getCircuitsPath, getDefaultCircuitsPath, getDistributableAmount, getExplorerUrl, getNkFromUtxoPrivateKey, getNullifierPDA, getPendingOperationsSummary, getPublicKey, getPublicViewKey, getRecipientAmount, getRpcUrlForNetwork, getShieldPoolPDAs, getSwapStatePDA, getViewKey, hasPendingOperations, hexToBigint$1 as hexToBigint, hexToBytes, importKeys, importWalletKeys, isDebugEnabled, isRootNotFoundError, isValidHex, isValidRpcUrl, isValidSolanaAddress, isWithdrawAmountSufficient, isWithdrawable, keypairToAdapter, loadPendingDeposits, loadPendingWithdrawals, parseAmount, parseError, parseNote, parseRelayErrorResponse, parseTransactionError, partialWithdraw, poseidonHash, preflightCheck, preflightNullifiers, prepareEncryptedOutput, prepareEncryptedOutputForRecipient, proofToBytes, pubkeyToFieldElement, pubkeyToLimbs, randomBytes, randomFieldElement, readMerkleTreeState, registerViewingKey, removePendingDeposit, removePendingWithdrawal, savePendingDeposit, savePendingWithdrawal, scanNotesForWallet, scanTransactions, sdkLogger, selectUtxos, sendTransaction, serializeNote, serializeUtxo, setCircuitsPath, setDebugMode, signTransaction, splitTo2Limbs, sumUtxoAmounts, swapUtxo, swapWithChange, toComplianceReport, transact, transfer, truncate, tryDecryptNote, updateNoteWithDeposit, updatePendingDeposit, updatePendingWithdrawal, bigintToBytes32 as utxoBigintToBytes32, utxoEquals, hexToBigint as utxoHexToBigint, validateDepositParams, validateNote, validateOutputsSum, validateRoot, validateTransfers, validateWalletConnected, validateWithdrawableNote, verifyAllCircuits, verifyCircuitIntegrity, verifyUtxos, waitForRoot, withTiming };