@cloak.dev/sdk 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +189 -51
- package/dist/{chunk-YX5SCAMR.js → chunk-KNM6K5NG.js} +8 -95
- package/dist/index.cjs +3565 -4351
- package/dist/index.d.cts +732 -807
- package/dist/index.d.ts +732 -807
- package/dist/index.js +3452 -4182
- package/dist/{utxo-PFJT3ETR.js → utxo-XPEGGWZ6.js} +3 -3
- package/package.json +50 -20
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,24 @@
|
|
|
1
|
-
import { PublicKey, Transaction,
|
|
1
|
+
import { PublicKey, Transaction, AddressLookupTableAccount, Connection, TransactionInstruction, Keypair, SendOptions, VersionedTransaction } from '@solana/web3.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The deployed Cloak program.
|
|
5
|
+
*
|
|
6
|
+
* This lived in `core/CloakSDK.ts` until that class was removed. It is protocol
|
|
7
|
+
* configuration, not client state: every PDA derivation, every scan and every
|
|
8
|
+
* `transact()` submission is addressed to it, so it belongs beside the other
|
|
9
|
+
* pinned protocol facts in `config/` rather than inside one client object.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Address of the Cloak shield-pool program on Solana mainnet.
|
|
14
|
+
*
|
|
15
|
+
* The same address is used by every environment the SDK talks to (a local
|
|
16
|
+
* Surfpool fork mirrors mainnet, so it carries the same program id). Callers
|
|
17
|
+
* that need a different deployment pass an explicit `programId` to the function
|
|
18
|
+
* they are calling — `getShieldPoolPDAs`, `transact`, `scanTransactions` and
|
|
19
|
+
* friends all take one.
|
|
20
|
+
*/
|
|
21
|
+
declare const CLOAK_PROGRAM_ID: PublicKey;
|
|
2
22
|
|
|
3
23
|
type ComplianceTxType = "deposit" | "withdraw" | "send" | "swap";
|
|
4
24
|
interface TransactionMetadata {
|
|
@@ -454,415 +474,6 @@ declare function exportKeys(keys: CloakKeyPair): string;
|
|
|
454
474
|
*/
|
|
455
475
|
declare function importKeys(exported: string): CloakKeyPair;
|
|
456
476
|
|
|
457
|
-
/**
|
|
458
|
-
* Storage Interface
|
|
459
|
-
*
|
|
460
|
-
* Defines a pluggable storage interface for notes and keys.
|
|
461
|
-
* Applications can implement their own storage (localStorage, IndexedDB, file system, etc.)
|
|
462
|
-
*/
|
|
463
|
-
|
|
464
|
-
/**
|
|
465
|
-
* Storage adapter interface
|
|
466
|
-
*
|
|
467
|
-
* Implement this interface to provide custom storage for notes and keys.
|
|
468
|
-
* The SDK will use this adapter for all persistence operations.
|
|
469
|
-
*/
|
|
470
|
-
interface StorageAdapter {
|
|
471
|
-
/**
|
|
472
|
-
* Save a note
|
|
473
|
-
*/
|
|
474
|
-
saveNote(note: CloakNote): Promise<void> | void;
|
|
475
|
-
/**
|
|
476
|
-
* Load all notes
|
|
477
|
-
*/
|
|
478
|
-
loadAllNotes(): Promise<CloakNote[]> | CloakNote[];
|
|
479
|
-
/**
|
|
480
|
-
* Update a note
|
|
481
|
-
*/
|
|
482
|
-
updateNote(commitment: string, updates: Partial<CloakNote>): Promise<void> | void;
|
|
483
|
-
/**
|
|
484
|
-
* Delete a note
|
|
485
|
-
*/
|
|
486
|
-
deleteNote(commitment: string): Promise<void> | void;
|
|
487
|
-
/**
|
|
488
|
-
* Clear all notes
|
|
489
|
-
*/
|
|
490
|
-
clearAllNotes(): Promise<void> | void;
|
|
491
|
-
/**
|
|
492
|
-
* Save wallet keys
|
|
493
|
-
*/
|
|
494
|
-
saveKeys(keys: CloakKeyPair): Promise<void> | void;
|
|
495
|
-
/**
|
|
496
|
-
* Load wallet keys
|
|
497
|
-
*/
|
|
498
|
-
loadKeys(): Promise<CloakKeyPair | null> | CloakKeyPair | null;
|
|
499
|
-
/**
|
|
500
|
-
* Delete wallet keys
|
|
501
|
-
*/
|
|
502
|
-
deleteKeys(): Promise<void> | void;
|
|
503
|
-
}
|
|
504
|
-
/**
|
|
505
|
-
* In-memory storage adapter (default, no persistence)
|
|
506
|
-
*
|
|
507
|
-
* Useful for testing or when storage is handled externally
|
|
508
|
-
*/
|
|
509
|
-
declare class MemoryStorageAdapter implements StorageAdapter {
|
|
510
|
-
private notes;
|
|
511
|
-
private keys;
|
|
512
|
-
saveNote(note: CloakNote): void;
|
|
513
|
-
loadAllNotes(): CloakNote[];
|
|
514
|
-
updateNote(commitment: string, updates: Partial<CloakNote>): void;
|
|
515
|
-
deleteNote(commitment: string): void;
|
|
516
|
-
clearAllNotes(): void;
|
|
517
|
-
saveKeys(keys: CloakKeyPair): void;
|
|
518
|
-
loadKeys(): CloakKeyPair | null;
|
|
519
|
-
deleteKeys(): void;
|
|
520
|
-
}
|
|
521
|
-
/**
|
|
522
|
-
* Browser localStorage adapter (optional, for browser environments)
|
|
523
|
-
*
|
|
524
|
-
* Only use this if you're in a browser environment and want localStorage persistence.
|
|
525
|
-
* Import from a separate browser-specific module.
|
|
526
|
-
*/
|
|
527
|
-
declare class LocalStorageAdapter implements StorageAdapter {
|
|
528
|
-
private notesKey;
|
|
529
|
-
private keysKey;
|
|
530
|
-
constructor(notesKey?: string, keysKey?: string);
|
|
531
|
-
private getStorage;
|
|
532
|
-
saveNote(note: CloakNote): void;
|
|
533
|
-
loadAllNotes(): CloakNote[];
|
|
534
|
-
updateNote(commitment: string, updates: Partial<CloakNote>): void;
|
|
535
|
-
deleteNote(commitment: string): void;
|
|
536
|
-
clearAllNotes(): void;
|
|
537
|
-
saveKeys(keys: CloakKeyPair): void;
|
|
538
|
-
loadKeys(): CloakKeyPair | null;
|
|
539
|
-
deleteKeys(): void;
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
/** Default Cloak Program ID on Solana */
|
|
543
|
-
declare const CLOAK_PROGRAM_ID: PublicKey;
|
|
544
|
-
/**
|
|
545
|
-
* Main Cloak SDK
|
|
546
|
-
*
|
|
547
|
-
* Provides high-level API for interacting with the Cloak protocol,
|
|
548
|
-
* including deposits, withdrawals, and private transfers.
|
|
549
|
-
*
|
|
550
|
-
* Supports two modes:
|
|
551
|
-
* 1. Node.js mode with keypairBytes - for scripts and backend services
|
|
552
|
-
* 2. Wallet adapter mode - for browser applications with wallet integration
|
|
553
|
-
*/
|
|
554
|
-
declare class CloakSDK {
|
|
555
|
-
private config;
|
|
556
|
-
private keypair?;
|
|
557
|
-
private wallet?;
|
|
558
|
-
private cloakKeys?;
|
|
559
|
-
private relay;
|
|
560
|
-
private storage;
|
|
561
|
-
/**
|
|
562
|
-
* Create a new Cloak SDK client
|
|
563
|
-
*
|
|
564
|
-
* @param config - Client configuration
|
|
565
|
-
*
|
|
566
|
-
* @example Node.js mode (with keypair)
|
|
567
|
-
* ```typescript
|
|
568
|
-
* const sdk = new CloakSDK({
|
|
569
|
-
* keypairBytes: keypair.secretKey,
|
|
570
|
-
* network: "devnet"
|
|
571
|
-
* });
|
|
572
|
-
* ```
|
|
573
|
-
*
|
|
574
|
-
* @example Browser mode (with wallet adapter)
|
|
575
|
-
* ```typescript
|
|
576
|
-
* const sdk = new CloakSDK({
|
|
577
|
-
* wallet: walletAdapter,
|
|
578
|
-
* network: "devnet"
|
|
579
|
-
* });
|
|
580
|
-
* ```
|
|
581
|
-
*/
|
|
582
|
-
constructor(config: {
|
|
583
|
-
/** Keypair bytes for signing (Node.js mode) */
|
|
584
|
-
keypairBytes?: Uint8Array;
|
|
585
|
-
/** Wallet adapter for signing (Browser mode) */
|
|
586
|
-
wallet?: WalletAdapter;
|
|
587
|
-
network?: Network;
|
|
588
|
-
cloakKeys?: CloakKeyPair;
|
|
589
|
-
storage?: StorageAdapter;
|
|
590
|
-
programId?: PublicKey;
|
|
591
|
-
relayUrl?: string;
|
|
592
|
-
/** Enable debug logging with structured output */
|
|
593
|
-
debug?: boolean;
|
|
594
|
-
});
|
|
595
|
-
/**
|
|
596
|
-
* Get the public key for deposits (from keypair or wallet)
|
|
597
|
-
*/
|
|
598
|
-
getPublicKey(): PublicKey;
|
|
599
|
-
/**
|
|
600
|
-
* Check if the SDK is using a wallet adapter
|
|
601
|
-
*/
|
|
602
|
-
isWalletMode(): boolean;
|
|
603
|
-
/**
|
|
604
|
-
* Deposit SOL into the Cloak protocol
|
|
605
|
-
*
|
|
606
|
-
* Creates a new note (or uses a provided one), submits a deposit transaction,
|
|
607
|
-
* and registers with the indexer.
|
|
608
|
-
*
|
|
609
|
-
* @param connection - Solana connection
|
|
610
|
-
* @param payer - Payer wallet with sendTransaction method
|
|
611
|
-
* @param amountOrNote - Amount in lamports OR an existing note to deposit
|
|
612
|
-
* @param options - Optional configuration
|
|
613
|
-
* @returns Deposit result with note and transaction info
|
|
614
|
-
*
|
|
615
|
-
* @example
|
|
616
|
-
* ```typescript
|
|
617
|
-
* // Generate and deposit in one step
|
|
618
|
-
* const result = await client.deposit(
|
|
619
|
-
* connection,
|
|
620
|
-
* wallet,
|
|
621
|
-
* 1_000_000_000,
|
|
622
|
-
* {
|
|
623
|
-
* onProgress: (status) => console.log(status)
|
|
624
|
-
* }
|
|
625
|
-
* );
|
|
626
|
-
*
|
|
627
|
-
* // Or deposit a pre-generated note
|
|
628
|
-
* const note = client.generateNote(1_000_000_000);
|
|
629
|
-
* const result = await client.deposit(connection, wallet, note);
|
|
630
|
-
* ```
|
|
631
|
-
*/
|
|
632
|
-
deposit(connection: Connection, amountOrNote: number | CloakNote, options?: DepositOptions): Promise<DepositResult>;
|
|
633
|
-
/**
|
|
634
|
-
* Private transfer with up to 5 recipients
|
|
635
|
-
*
|
|
636
|
-
* Handles the complete private transfer flow:
|
|
637
|
-
* 1. If note is not deposited, deposits it first and waits for confirmation
|
|
638
|
-
* 2. Generates a zero-knowledge proof
|
|
639
|
-
* 3. Submits the withdrawal via relay service to recipients
|
|
640
|
-
*
|
|
641
|
-
* This is the main method for performing private transfers - it handles everything!
|
|
642
|
-
*
|
|
643
|
-
* @param connection - Solana connection (required for deposit if not already deposited)
|
|
644
|
-
* @param payer - Payer wallet (required for deposit if not already deposited)
|
|
645
|
-
* @param note - Note to spend (can be deposited or not)
|
|
646
|
-
* @param recipients - Array of 1-5 recipients with amounts
|
|
647
|
-
* @param options - Optional configuration
|
|
648
|
-
* @returns Transfer result with signature and outputs
|
|
649
|
-
*
|
|
650
|
-
* @example
|
|
651
|
-
* ```typescript
|
|
652
|
-
* // Create a note (not deposited yet)
|
|
653
|
-
* const note = client.generateNote(1_000_000_000);
|
|
654
|
-
*
|
|
655
|
-
* // privateTransfer handles the full flow: deposit + withdraw
|
|
656
|
-
* const result = await client.privateTransfer(
|
|
657
|
-
* connection,
|
|
658
|
-
* wallet,
|
|
659
|
-
* note,
|
|
660
|
-
* [
|
|
661
|
-
* { recipient: new PublicKey("..."), amount: 500_000_000 },
|
|
662
|
-
* { recipient: new PublicKey("..."), amount: 492_500_000 }
|
|
663
|
-
* ],
|
|
664
|
-
* {
|
|
665
|
-
* relayFeeBps: 50, // 0.5%
|
|
666
|
-
* onProgress: (status) => console.log(status),
|
|
667
|
-
* onProofProgress: (pct) => console.log(`Proof: ${pct}%`)
|
|
668
|
-
* }
|
|
669
|
-
* );
|
|
670
|
-
* console.log(`Success! TX: ${result.signature}`);
|
|
671
|
-
* ```
|
|
672
|
-
*/
|
|
673
|
-
privateTransfer(connection: Connection, note: CloakNote, recipients: MaxLengthArray<Transfer, 5>, options?: TransferOptions): Promise<TransferResult>;
|
|
674
|
-
/**
|
|
675
|
-
* Withdraw to a single recipient
|
|
676
|
-
*
|
|
677
|
-
* Convenience method for withdrawing to one address.
|
|
678
|
-
* Handles the complete flow: deposits if needed, then withdraws.
|
|
679
|
-
*
|
|
680
|
-
* @param connection - Solana connection
|
|
681
|
-
* @param payer - Payer wallet
|
|
682
|
-
* @param note - Note to spend
|
|
683
|
-
* @param recipient - Recipient address
|
|
684
|
-
* @param options - Optional configuration
|
|
685
|
-
* @returns Transfer result
|
|
686
|
-
*
|
|
687
|
-
* @example
|
|
688
|
-
* ```typescript
|
|
689
|
-
* const note = client.generateNote(1_000_000_000);
|
|
690
|
-
* const result = await client.withdraw(
|
|
691
|
-
* connection,
|
|
692
|
-
* wallet,
|
|
693
|
-
* note,
|
|
694
|
-
* new PublicKey("..."),
|
|
695
|
-
* { withdrawAll: true }
|
|
696
|
-
* );
|
|
697
|
-
* ```
|
|
698
|
-
*/
|
|
699
|
-
withdraw(connection: Connection, note: CloakNote, recipient: PublicKey, options?: WithdrawOptions): Promise<TransferResult>;
|
|
700
|
-
/**
|
|
701
|
-
* Send SOL privately to multiple recipients
|
|
702
|
-
*
|
|
703
|
-
* Convenience method that wraps privateTransfer with a simpler API.
|
|
704
|
-
* Handles the complete flow: deposits if needed, then sends to recipients.
|
|
705
|
-
*
|
|
706
|
-
* @param connection - Solana connection
|
|
707
|
-
* @param note - Note to spend
|
|
708
|
-
* @param recipients - Array of 1-5 recipients with amounts
|
|
709
|
-
* @param options - Optional configuration
|
|
710
|
-
* @returns Transfer result
|
|
711
|
-
*
|
|
712
|
-
* @example
|
|
713
|
-
* ```typescript
|
|
714
|
-
* const note = client.generateNote(1_000_000_000);
|
|
715
|
-
* const result = await client.send(
|
|
716
|
-
* connection,
|
|
717
|
-
* note,
|
|
718
|
-
* [
|
|
719
|
-
* { recipient: new PublicKey("..."), amount: 500_000_000 },
|
|
720
|
-
* { recipient: new PublicKey("..."), amount: 492_500_000 }
|
|
721
|
-
* ]
|
|
722
|
-
* );
|
|
723
|
-
* ```
|
|
724
|
-
*/
|
|
725
|
-
send(connection: Connection, note: CloakNote, recipients: MaxLengthArray<Transfer, 5>, options?: TransferOptions): Promise<TransferResult>;
|
|
726
|
-
/**
|
|
727
|
-
* Swap SOL for tokens privately
|
|
728
|
-
*
|
|
729
|
-
* Withdraws SOL from a note and swaps it for tokens via the relay service.
|
|
730
|
-
* Handles the complete flow: deposits if needed, generates proof, and submits swap.
|
|
731
|
-
*
|
|
732
|
-
* @param connection - Solana connection
|
|
733
|
-
* @param note - Note to spend
|
|
734
|
-
* @param recipient - Recipient address (will receive tokens)
|
|
735
|
-
* @param options - Swap configuration
|
|
736
|
-
* @returns Swap result with transaction signature
|
|
737
|
-
*
|
|
738
|
-
* @example
|
|
739
|
-
* ```typescript
|
|
740
|
-
* const note = client.generateNote(1_000_000_000);
|
|
741
|
-
* const result = await client.swap(
|
|
742
|
-
* connection,
|
|
743
|
-
* note,
|
|
744
|
-
* new PublicKey("..."), // recipient
|
|
745
|
-
* {
|
|
746
|
-
* outputMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC
|
|
747
|
-
* slippageBps: 100, // 1%
|
|
748
|
-
* getQuote: async (amount, mint, slippage) => {
|
|
749
|
-
* // Fetch quote from your swap API
|
|
750
|
-
* const quote = await fetchSwapQuote(amount, mint, slippage);
|
|
751
|
-
* return {
|
|
752
|
-
* outAmount: quote.outAmount,
|
|
753
|
-
* minOutputAmount: quote.minOutputAmount
|
|
754
|
-
* };
|
|
755
|
-
* }
|
|
756
|
-
* }
|
|
757
|
-
* );
|
|
758
|
-
* ```
|
|
759
|
-
*/
|
|
760
|
-
swap(connection: Connection, note: CloakNote, recipient: PublicKey, options: SwapOptions): Promise<SwapResult>;
|
|
761
|
-
/**
|
|
762
|
-
* Generate a new note without depositing
|
|
763
|
-
*
|
|
764
|
-
* @param amountLamports - Amount for the note
|
|
765
|
-
* @param useWalletKeys - Whether to use wallet keys (v2.0 recommended)
|
|
766
|
-
* @returns New note (not yet deposited)
|
|
767
|
-
*/
|
|
768
|
-
generateNote(amountLamports: number, useWalletKeys?: boolean): Promise<CloakNote>;
|
|
769
|
-
/**
|
|
770
|
-
* Parse a note from JSON string
|
|
771
|
-
*
|
|
772
|
-
* @param jsonString - JSON representation
|
|
773
|
-
* @returns Parsed note
|
|
774
|
-
*/
|
|
775
|
-
parseNote(jsonString: string): CloakNote;
|
|
776
|
-
/**
|
|
777
|
-
* Export a note to JSON string
|
|
778
|
-
*
|
|
779
|
-
* @param note - Note to export
|
|
780
|
-
* @param pretty - Format with indentation
|
|
781
|
-
* @returns JSON string
|
|
782
|
-
*/
|
|
783
|
-
exportNote(note: CloakNote, pretty?: boolean): string;
|
|
784
|
-
/**
|
|
785
|
-
* Check if a note is ready for withdrawal
|
|
786
|
-
*
|
|
787
|
-
* @param note - Note to check
|
|
788
|
-
* @returns True if withdrawable
|
|
789
|
-
*/
|
|
790
|
-
isWithdrawable(note: CloakNote): boolean;
|
|
791
|
-
/**
|
|
792
|
-
* Get Merkle proof for a leaf index directly from on-chain state
|
|
793
|
-
*
|
|
794
|
-
* @param connection - Solana connection
|
|
795
|
-
* @param leafIndex - Leaf index in tree
|
|
796
|
-
* @returns Merkle proof computed from on-chain data
|
|
797
|
-
*/
|
|
798
|
-
getMerkleProof(connection: Connection, leafIndex: number): Promise<MerkleProof>;
|
|
799
|
-
/**
|
|
800
|
-
* Get current Merkle root directly from on-chain state
|
|
801
|
-
*
|
|
802
|
-
* @param connection - Solana connection
|
|
803
|
-
* @returns Current root hash from on-chain tree
|
|
804
|
-
*/
|
|
805
|
-
getCurrentRoot(connection: Connection): Promise<string>;
|
|
806
|
-
/**
|
|
807
|
-
* Get transaction status from relay service
|
|
808
|
-
*
|
|
809
|
-
* @param requestId - Request ID from previous submission
|
|
810
|
-
* @returns Current status
|
|
811
|
-
*/
|
|
812
|
-
getTransactionStatus(requestId: string): Promise<TxStatus>;
|
|
813
|
-
/**
|
|
814
|
-
* Fetch and decrypt this user's transaction metadata history.
|
|
815
|
-
* DEPRECATED: This functionality is no longer supported
|
|
816
|
-
*/
|
|
817
|
-
getTransactionMetadata(_options?: {
|
|
818
|
-
_after?: number;
|
|
819
|
-
_before?: number;
|
|
820
|
-
}): Promise<TransactionMetadata[]>;
|
|
821
|
-
/**
|
|
822
|
-
* Load all notes from storage
|
|
823
|
-
*
|
|
824
|
-
* @returns Array of saved notes
|
|
825
|
-
*/
|
|
826
|
-
loadNotes(): Promise<CloakNote[]>;
|
|
827
|
-
/**
|
|
828
|
-
* Save a note to storage
|
|
829
|
-
*
|
|
830
|
-
* @param note - Note to save
|
|
831
|
-
*/
|
|
832
|
-
saveNote(note: CloakNote): Promise<void>;
|
|
833
|
-
/**
|
|
834
|
-
* Find a note by its commitment
|
|
835
|
-
*
|
|
836
|
-
* @param commitment - Commitment hash
|
|
837
|
-
* @returns Note if found
|
|
838
|
-
*/
|
|
839
|
-
findNote(commitment: string): Promise<CloakNote | undefined>;
|
|
840
|
-
/**
|
|
841
|
-
* Import wallet keys from JSON
|
|
842
|
-
*
|
|
843
|
-
* @param keysJson - JSON string containing keys
|
|
844
|
-
*/
|
|
845
|
-
importWalletKeys(keysJson: string): Promise<void>;
|
|
846
|
-
/**
|
|
847
|
-
* Export wallet keys to JSON
|
|
848
|
-
*
|
|
849
|
-
* WARNING: This exports secret keys! Store securely.
|
|
850
|
-
*
|
|
851
|
-
* @returns JSON string with keys
|
|
852
|
-
*/
|
|
853
|
-
exportWalletKeys(): string;
|
|
854
|
-
/**
|
|
855
|
-
* Get the configuration
|
|
856
|
-
*/
|
|
857
|
-
getConfig(): CloakConfig;
|
|
858
|
-
/**
|
|
859
|
-
* Wrap errors with better categorization and user-friendly messages
|
|
860
|
-
*
|
|
861
|
-
* @private
|
|
862
|
-
*/
|
|
863
|
-
private wrapError;
|
|
864
|
-
}
|
|
865
|
-
|
|
866
477
|
/**
|
|
867
478
|
* Serialize a note to JSON string
|
|
868
479
|
*
|
|
@@ -1013,18 +624,12 @@ declare function calculateRelayFee(amountLamports: number, feeBps: number): numb
|
|
|
1013
624
|
* Storage is handled externally via StorageAdapter.
|
|
1014
625
|
*
|
|
1015
626
|
* Core functionality:
|
|
1016
|
-
* - Generate notes
|
|
627
|
+
* - Generate notes from wallet keys
|
|
1017
628
|
* - Parse and validate notes
|
|
1018
629
|
* - Note utilities (formatting, fees, etc.)
|
|
1019
630
|
* - Key management (without storage)
|
|
1020
631
|
*/
|
|
1021
632
|
|
|
1022
|
-
/**
|
|
1023
|
-
* Generate a new note without wallet keys (legacy v1.0)
|
|
1024
|
-
* Uses Poseidon hashing to match circuit implementation
|
|
1025
|
-
* @deprecated Use generateNoteFromWallet instead for enhanced security
|
|
1026
|
-
*/
|
|
1027
|
-
declare function generateNote(amountLamports: number, network?: Network): Promise<CloakNote>;
|
|
1028
633
|
/**
|
|
1029
634
|
* Generate a note using wallet's spend key (v2.0 recommended)
|
|
1030
635
|
* Uses Poseidon hashing to match circuit implementation
|
|
@@ -1087,9 +692,94 @@ declare function getPublicViewKey(keys: CloakKeyPair): string;
|
|
|
1087
692
|
*/
|
|
1088
693
|
declare function getViewKey(keys: CloakKeyPair): ViewKey;
|
|
1089
694
|
/**
|
|
1090
|
-
* Get recipient amount after fees
|
|
695
|
+
* Get recipient amount after fees
|
|
696
|
+
*/
|
|
697
|
+
declare function getRecipientAmount(amountLamports: number): number;
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* Storage Interface
|
|
701
|
+
*
|
|
702
|
+
* Defines a pluggable storage interface for notes and keys.
|
|
703
|
+
* Applications can implement their own storage (localStorage, IndexedDB, file system, etc.)
|
|
704
|
+
*/
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
* Storage adapter interface
|
|
708
|
+
*
|
|
709
|
+
* Implement this interface to provide custom storage for notes and keys.
|
|
710
|
+
* The SDK will use this adapter for all persistence operations.
|
|
711
|
+
*/
|
|
712
|
+
interface StorageAdapter {
|
|
713
|
+
/**
|
|
714
|
+
* Save a note
|
|
715
|
+
*/
|
|
716
|
+
saveNote(note: CloakNote): Promise<void> | void;
|
|
717
|
+
/**
|
|
718
|
+
* Load all notes
|
|
719
|
+
*/
|
|
720
|
+
loadAllNotes(): Promise<CloakNote[]> | CloakNote[];
|
|
721
|
+
/**
|
|
722
|
+
* Update a note
|
|
723
|
+
*/
|
|
724
|
+
updateNote(commitment: string, updates: Partial<CloakNote>): Promise<void> | void;
|
|
725
|
+
/**
|
|
726
|
+
* Delete a note
|
|
727
|
+
*/
|
|
728
|
+
deleteNote(commitment: string): Promise<void> | void;
|
|
729
|
+
/**
|
|
730
|
+
* Clear all notes
|
|
731
|
+
*/
|
|
732
|
+
clearAllNotes(): Promise<void> | void;
|
|
733
|
+
/**
|
|
734
|
+
* Save wallet keys
|
|
735
|
+
*/
|
|
736
|
+
saveKeys(keys: CloakKeyPair): Promise<void> | void;
|
|
737
|
+
/**
|
|
738
|
+
* Load wallet keys
|
|
739
|
+
*/
|
|
740
|
+
loadKeys(): Promise<CloakKeyPair | null> | CloakKeyPair | null;
|
|
741
|
+
/**
|
|
742
|
+
* Delete wallet keys
|
|
743
|
+
*/
|
|
744
|
+
deleteKeys(): Promise<void> | void;
|
|
745
|
+
}
|
|
746
|
+
/**
|
|
747
|
+
* In-memory storage adapter (default, no persistence)
|
|
748
|
+
*
|
|
749
|
+
* Useful for testing or when storage is handled externally
|
|
750
|
+
*/
|
|
751
|
+
declare class MemoryStorageAdapter implements StorageAdapter {
|
|
752
|
+
private notes;
|
|
753
|
+
private keys;
|
|
754
|
+
saveNote(note: CloakNote): void;
|
|
755
|
+
loadAllNotes(): CloakNote[];
|
|
756
|
+
updateNote(commitment: string, updates: Partial<CloakNote>): void;
|
|
757
|
+
deleteNote(commitment: string): void;
|
|
758
|
+
clearAllNotes(): void;
|
|
759
|
+
saveKeys(keys: CloakKeyPair): void;
|
|
760
|
+
loadKeys(): CloakKeyPair | null;
|
|
761
|
+
deleteKeys(): void;
|
|
762
|
+
}
|
|
763
|
+
/**
|
|
764
|
+
* Browser localStorage adapter (optional, for browser environments)
|
|
765
|
+
*
|
|
766
|
+
* Only use this if you're in a browser environment and want localStorage persistence.
|
|
767
|
+
* Import from a separate browser-specific module.
|
|
1091
768
|
*/
|
|
1092
|
-
declare
|
|
769
|
+
declare class LocalStorageAdapter implements StorageAdapter {
|
|
770
|
+
private notesKey;
|
|
771
|
+
private keysKey;
|
|
772
|
+
constructor(notesKey?: string, keysKey?: string);
|
|
773
|
+
private getStorage;
|
|
774
|
+
saveNote(note: CloakNote): void;
|
|
775
|
+
loadAllNotes(): CloakNote[];
|
|
776
|
+
updateNote(commitment: string, updates: Partial<CloakNote>): void;
|
|
777
|
+
deleteNote(commitment: string): void;
|
|
778
|
+
clearAllNotes(): void;
|
|
779
|
+
saveKeys(keys: CloakKeyPair): void;
|
|
780
|
+
loadKeys(): CloakKeyPair | null;
|
|
781
|
+
deleteKeys(): void;
|
|
782
|
+
}
|
|
1093
783
|
|
|
1094
784
|
interface ViewingKeyPair {
|
|
1095
785
|
privateKey: Uint8Array;
|
|
@@ -1243,26 +933,13 @@ declare function computeMerkleRoot(leaf: bigint, pathElements: bigint[], pathInd
|
|
|
1243
933
|
* Convert hex string to bigint
|
|
1244
934
|
*/
|
|
1245
935
|
declare function hexToBigint$1(hex: string): bigint;
|
|
1246
|
-
/**
|
|
1247
|
-
* Compute commitment = Poseidon(amount, r0, r1, pk_spend)
|
|
1248
|
-
* where pk_spend = Poseidon(sk0, sk1)
|
|
1249
|
-
* (matching withdraw_regular.circom)
|
|
1250
|
-
*
|
|
1251
|
-
* This is the test-style function that takes bigints directly
|
|
1252
|
-
*
|
|
1253
|
-
* @param amount - Amount as bigint
|
|
1254
|
-
* @param r - Randomness as bigint
|
|
1255
|
-
* @param sk_spend - Spending secret key as bigint
|
|
1256
|
-
* @returns Commitment hash as bigint
|
|
1257
|
-
*/
|
|
1258
|
-
declare function computeCommitment$1(amount: bigint, r: bigint, sk_spend: bigint): Promise<bigint>;
|
|
1259
936
|
/**
|
|
1260
937
|
* Generate a Poseidon commitment for a note
|
|
1261
938
|
*
|
|
1262
939
|
* Formula: Poseidon(amount, r0, r1, pk_spend)
|
|
1263
940
|
* where pk_spend = Poseidon(sk0, sk1)
|
|
1264
941
|
*
|
|
1265
|
-
*
|
|
942
|
+
* Legacy CloakNote commitment layout (see `computeCommitment`).
|
|
1266
943
|
*
|
|
1267
944
|
* @param amountLamports - Amount in lamports
|
|
1268
945
|
* @param r - Randomness bytes (32 bytes)
|
|
@@ -1270,110 +947,6 @@ declare function computeCommitment$1(amount: bigint, r: bigint, sk_spend: bigint
|
|
|
1270
947
|
* @returns Commitment hash as bigint
|
|
1271
948
|
*/
|
|
1272
949
|
declare function generateCommitmentAsync(amountLamports: number, r: Uint8Array, skSpend: Uint8Array): Promise<bigint>;
|
|
1273
|
-
/**
|
|
1274
|
-
* Generate a Poseidon commitment for a note (sync wrapper)
|
|
1275
|
-
* Returns bytes instead of bigint for backward compatibility
|
|
1276
|
-
*
|
|
1277
|
-
* @deprecated Use generateCommitmentAsync instead
|
|
1278
|
-
*/
|
|
1279
|
-
declare function generateCommitment(_amountLamports: number, _r: Uint8Array, _skSpend: Uint8Array): Uint8Array;
|
|
1280
|
-
/**
|
|
1281
|
-
* Compute nullifier = Poseidon(sk0, sk1, leaf_index)
|
|
1282
|
-
* (matching withdraw_regular.circom)
|
|
1283
|
-
*
|
|
1284
|
-
* This is the test-style function that takes bigint directly
|
|
1285
|
-
*
|
|
1286
|
-
* @param sk_spend - Spending secret key as bigint
|
|
1287
|
-
* @param leafIndex - Index in the Merkle tree as bigint
|
|
1288
|
-
* @returns Nullifier as bigint
|
|
1289
|
-
*/
|
|
1290
|
-
declare function computeNullifier$1(sk_spend: bigint, leafIndex: bigint): Promise<bigint>;
|
|
1291
|
-
/**
|
|
1292
|
-
* Compute nullifier from spending key and leaf index
|
|
1293
|
-
*
|
|
1294
|
-
* Formula: Poseidon(sk0, sk1, leaf_index)
|
|
1295
|
-
*
|
|
1296
|
-
* This matches the circuit's nullifier computation
|
|
1297
|
-
*
|
|
1298
|
-
* @param skSpend - Spending secret key bytes (32 bytes) or hex string
|
|
1299
|
-
* @param leafIndex - Index in the Merkle tree
|
|
1300
|
-
* @returns Nullifier as bigint
|
|
1301
|
-
*/
|
|
1302
|
-
declare function computeNullifierAsync(skSpend: Uint8Array | string, leafIndex: number): Promise<bigint>;
|
|
1303
|
-
/**
|
|
1304
|
-
* Compute nullifier (sync wrapper for backward compatibility)
|
|
1305
|
-
* @deprecated Use computeNullifierAsync instead
|
|
1306
|
-
*/
|
|
1307
|
-
declare function computeNullifierSync(_skSpend: Uint8Array, _leafIndex: number): Uint8Array;
|
|
1308
|
-
/**
|
|
1309
|
-
* Compute outputs hash from recipients and amounts
|
|
1310
|
-
*
|
|
1311
|
-
* Formula: Chain of Poseidon(prev_hash, addr_lo, addr_hi, amount) for each active output
|
|
1312
|
-
*
|
|
1313
|
-
* This matches the withdraw_regular.circom circuit's outputs hash computation
|
|
1314
|
-
*
|
|
1315
|
-
* @param outputs - Array of {recipient: PublicKey, amount: number}
|
|
1316
|
-
* @returns Outputs hash as bigint
|
|
1317
|
-
*/
|
|
1318
|
-
declare function computeOutputsHashAsync(outputs: Array<{
|
|
1319
|
-
recipient: PublicKey;
|
|
1320
|
-
amount: number;
|
|
1321
|
-
}>): Promise<bigint>;
|
|
1322
|
-
/**
|
|
1323
|
-
* Compute outputs hash for withdraw_regular circuit
|
|
1324
|
-
* outputs_hash = chain of Poseidon(prev_hash, addr_lo, addr_hi, amount) for each active output
|
|
1325
|
-
*
|
|
1326
|
-
* This is the test-style function that takes raw limbs
|
|
1327
|
-
*
|
|
1328
|
-
* @param outAddr - Array of [lo, hi] limb pairs for each address (5x2 array)
|
|
1329
|
-
* @param outAmount - Array of amounts as bigints (5 elements)
|
|
1330
|
-
* @param outFlags - Array of flags (1 = active, 0 = inactive) (5 elements)
|
|
1331
|
-
* @returns Outputs hash as bigint
|
|
1332
|
-
*/
|
|
1333
|
-
declare function computeOutputsHash(outAddr: bigint[][], outAmount: bigint[], outFlags: number[]): Promise<bigint>;
|
|
1334
|
-
/**
|
|
1335
|
-
* Compute outputs hash (sync wrapper for backward compatibility)
|
|
1336
|
-
* @deprecated Use computeOutputsHashAsync instead
|
|
1337
|
-
*/
|
|
1338
|
-
declare function computeOutputsHashSync(_outputs: Array<{
|
|
1339
|
-
recipient: PublicKey;
|
|
1340
|
-
amount: number;
|
|
1341
|
-
}>): Uint8Array;
|
|
1342
|
-
/**
|
|
1343
|
-
* Compute outputs hash for withdraw_swap circuit
|
|
1344
|
-
* outputs_hash = Poseidon(input_mint limbs, output_mint limbs, recipient_ata limbs, min_output_amount, public_amount)
|
|
1345
|
-
*
|
|
1346
|
-
* This is the test-style function that takes raw limbs
|
|
1347
|
-
*
|
|
1348
|
-
* @param inputMintLimbs - Input mint address as [lo, hi] limbs
|
|
1349
|
-
* @param outputMintLimbs - Output mint address as [lo, hi] limbs
|
|
1350
|
-
* @param recipientAtaLimbs - Recipient ATA as [lo, hi] limbs
|
|
1351
|
-
* @param minOutputAmount - Minimum output amount as bigint
|
|
1352
|
-
* @param publicAmount - Public amount as bigint
|
|
1353
|
-
* @returns Outputs hash as bigint
|
|
1354
|
-
*/
|
|
1355
|
-
declare function computeSwapOutputsHash(inputMintLimbs: [bigint, bigint], outputMintLimbs: [bigint, bigint], recipientAtaLimbs: [bigint, bigint], minOutputAmount: bigint, publicAmount: bigint): Promise<bigint>;
|
|
1356
|
-
/**
|
|
1357
|
-
* Compute outputs hash for swap transactions
|
|
1358
|
-
*
|
|
1359
|
-
* Formula: Poseidon(input_mint_lo, input_mint_hi, output_mint_lo, output_mint_hi,
|
|
1360
|
-
* recipient_ata_lo, recipient_ata_hi, min_output_amount, public_amount)
|
|
1361
|
-
*
|
|
1362
|
-
* This matches the withdraw_swap.circom circuit
|
|
1363
|
-
*
|
|
1364
|
-
* @param inputMint - Input token mint address (SOL = SystemProgram)
|
|
1365
|
-
* @param outputMint - Output token mint address
|
|
1366
|
-
* @param recipientAta - Recipient's associated token account
|
|
1367
|
-
* @param minOutputAmount - Minimum output amount in token's smallest unit
|
|
1368
|
-
* @param amount - Note amount in lamports (public_amount)
|
|
1369
|
-
* @returns Outputs hash as bigint
|
|
1370
|
-
*/
|
|
1371
|
-
declare function computeSwapOutputsHashAsync(inputMint: PublicKey, outputMint: PublicKey, recipientAta: PublicKey, minOutputAmount: number, amount: number): Promise<bigint>;
|
|
1372
|
-
/**
|
|
1373
|
-
* Compute swap outputs hash (sync wrapper for backward compatibility)
|
|
1374
|
-
* @deprecated Use computeSwapOutputsHashAsync instead
|
|
1375
|
-
*/
|
|
1376
|
-
declare function computeSwapOutputsHashSync(_outputMint: PublicKey, _recipientAta: PublicKey, _minOutputAmount: number, _amount: number): Uint8Array;
|
|
1377
950
|
/**
|
|
1378
951
|
* Convert bigint to 32-byte big-endian Uint8Array
|
|
1379
952
|
*/
|
|
@@ -1446,11 +1019,6 @@ interface Groth16Proof {
|
|
|
1446
1019
|
* Format: pi_a (64) + pi_b (128) + pi_c (64) = 256 bytes
|
|
1447
1020
|
*/
|
|
1448
1021
|
declare function proofToBytes(proof: Groth16Proof): Uint8Array;
|
|
1449
|
-
/**
|
|
1450
|
-
* Build public inputs bytes for on-chain verification
|
|
1451
|
-
* Format: root (32) + nullifier (32) + outputs_hash (32) + public_amount (8) = 104 bytes
|
|
1452
|
-
*/
|
|
1453
|
-
declare function buildPublicInputsBytes(root: bigint, nullifier: bigint, outputsHash: bigint, publicAmount: bigint): Uint8Array;
|
|
1454
1022
|
|
|
1455
1023
|
/**
|
|
1456
1024
|
* Validate a Solana public key
|
|
@@ -1692,7 +1260,7 @@ declare class RelayInternalError extends Error {
|
|
|
1692
1260
|
/**
|
|
1693
1261
|
* Raised when a submission's outcome could NOT be established as "landed" from chain state.
|
|
1694
1262
|
*
|
|
1695
|
-
* This is the failure side of settlement verification (see `
|
|
1263
|
+
* This is the failure side of settlement verification (see `flows/settlement.ts`). It exists
|
|
1696
1264
|
* because the campaign's worst outcome was not a failed transaction — it was an AMBIGUOUS one
|
|
1697
1265
|
* whose error text carried no signature (REL-A-10: seven POSTs, the transaction landed, the SDK
|
|
1698
1266
|
* threw `RelayInternalError`, and the user had nothing to look up). Losing the signature is what
|
|
@@ -2124,7 +1692,7 @@ interface VerifyUtxosResult {
|
|
|
2124
1692
|
declare function verifyUtxos(utxos: Utxo[], connection: Connection, programId: PublicKey, commitment?: "processed" | "confirmed" | "finalized"): Promise<VerifyUtxosResult>;
|
|
2125
1693
|
/**
|
|
2126
1694
|
* Pre-flight gate: throw `UtxoAlreadySpentError` if any input is already
|
|
2127
|
-
* spent on-chain. Called at the top of spend entry points in
|
|
1695
|
+
* spent on-chain. Called at the top of spend entry points in flows/transact.
|
|
2128
1696
|
*
|
|
2129
1697
|
* Browser-safe: uses one batched RPC call.
|
|
2130
1698
|
*/
|
|
@@ -2272,7 +1840,7 @@ declare function assertDirectSubmissionLanded(params: {
|
|
|
2272
1840
|
* 2026-01-23T00:51:46.489317Z INFO cloak::module: 📥 Message key=value
|
|
2273
1841
|
*
|
|
2274
1842
|
* Enable via:
|
|
2275
|
-
* -
|
|
1843
|
+
* - Code: setDebugMode(true)
|
|
2276
1844
|
* - Environment: CLOAK_DEBUG=1 or DEBUG=cloak:*
|
|
2277
1845
|
*/
|
|
2278
1846
|
type LogLevel = "DEBUG" | "INFO" | "WARN" | "ERROR";
|
|
@@ -2724,20 +2292,8 @@ declare function getNullifierPDA(poolPubkey: PublicKey, nullifier: Uint8Array |
|
|
|
2724
2292
|
*/
|
|
2725
2293
|
declare function getSwapStatePDA(poolPubkey: PublicKey, nullifier: Uint8Array | Buffer, programId?: PublicKey): [PublicKey, number];
|
|
2726
2294
|
/**
|
|
2727
|
-
*
|
|
2728
|
-
*
|
|
2729
|
-
* Seeds: ["refund_ledger", pool_mint]
|
|
2730
|
-
*/
|
|
2731
|
-
declare function getRefundLedgerPDA(mint?: PublicKey, programId?: PublicKey): [PublicKey, number];
|
|
2732
|
-
/**
|
|
2733
|
-
* H-04: derive the one-time RefundClaim PDA (replay guard for a voucher).
|
|
2734
|
-
*
|
|
2735
|
-
* Seeds: ["refund_claim", claim_id]
|
|
2736
|
-
*/
|
|
2737
|
-
declare function getRefundClaimPDA(claimId: Uint8Array | Buffer, programId?: PublicKey): [PublicKey, number];
|
|
2738
|
-
/**
|
|
2739
|
-
* M-07/H-04: derive the per-pool PoolAuthorityConfig PDA (holds the
|
|
2740
|
-
* withdraw-authorizer the refund voucher must be signed by).
|
|
2295
|
+
* M-07: derive the per-pool PoolAuthorityConfig PDA (holds the mint-scoped
|
|
2296
|
+
* withdraw-authorizer).
|
|
2741
2297
|
*
|
|
2742
2298
|
* Seeds: ["pool_authority", pool_mint]
|
|
2743
2299
|
*/
|
|
@@ -2759,76 +2315,6 @@ declare function getDeliveryRegistryPDA(programId?: PublicKey): PublicKey;
|
|
|
2759
2315
|
*/
|
|
2760
2316
|
declare function getChainNoteRegistryPDA(programId?: PublicKey): PublicKey;
|
|
2761
2317
|
|
|
2762
|
-
/**
|
|
2763
|
-
* H-04 — claim-based timeout refund (SDK).
|
|
2764
|
-
*
|
|
2765
|
-
* When a private swap times out, `CloseSwapState` returns the parked principal
|
|
2766
|
-
* to the pool and credits the on-chain `RefundLedger`. The user later reclaims
|
|
2767
|
-
* that principal as a FRESH shielded note via `ClaimRefund`, gated by a
|
|
2768
|
-
* withdraw-authorizer voucher (signed by the relay) and a deposit-shape Groth16
|
|
2769
|
-
* proof — with no on-chain link back to the original swap.
|
|
2770
|
-
*
|
|
2771
|
-
* This module:
|
|
2772
|
-
* 1. asks the relay to sign the 81-byte refund voucher for `claim_id`,
|
|
2773
|
-
* 2. generates a deposit-shape proof (publicAmount = +refund_amount, zero
|
|
2774
|
-
* inputs, one fresh output note `C_r`) bound to the live merkle root,
|
|
2775
|
-
* 3. builds and submits the `[ed25519 voucher][CU][ClaimRefund]` transaction,
|
|
2776
|
-
* 4. returns the fresh refund UTXO for the caller to store/spend later.
|
|
2777
|
-
*
|
|
2778
|
-
* The proof construction is byte-for-byte the same as the standalone
|
|
2779
|
-
* `audit-tests/h-04/gen-claim-proof.cjs` generator that the program-side soak
|
|
2780
|
-
* verified, so the proof verifies against the deployed transaction vkey.
|
|
2781
|
-
*/
|
|
2782
|
-
|
|
2783
|
-
/** A relay-signed refund voucher, as returned by `POST /refund-voucher`. */
|
|
2784
|
-
interface RefundVoucher {
|
|
2785
|
-
/** base64 Ed25519 signature over the 81-byte message. */
|
|
2786
|
-
signature: string;
|
|
2787
|
-
/** hex 81-byte voucher message. */
|
|
2788
|
-
message: string;
|
|
2789
|
-
/** base58 signer (pool withdraw-authorizer). */
|
|
2790
|
-
signer_pubkey: string;
|
|
2791
|
-
/** expiry slot bound into the voucher. */
|
|
2792
|
-
expiry_slot?: number;
|
|
2793
|
-
}
|
|
2794
|
-
interface ClaimTimeoutRefundParams {
|
|
2795
|
-
/** Refund principal in lamports (must equal the closed swap's parked amount). */
|
|
2796
|
-
refundAmount: bigint;
|
|
2797
|
-
/** Pool mint; ClaimRefund is SOL-pool only (defaults to WSOL sentinel). */
|
|
2798
|
-
poolMint?: PublicKey;
|
|
2799
|
-
/** 32-byte claim id = H(user secret). Random if omitted. */
|
|
2800
|
-
claimId?: Uint8Array;
|
|
2801
|
-
/** Supply a pre-fetched voucher to skip the relay round-trip. */
|
|
2802
|
-
voucher?: RefundVoucher;
|
|
2803
|
-
}
|
|
2804
|
-
interface ClaimTimeoutRefundOptions {
|
|
2805
|
-
connection: Connection;
|
|
2806
|
-
programId: PublicKey;
|
|
2807
|
-
/** Relay base URL (used to fetch the voucher when not supplied). */
|
|
2808
|
-
relayUrl?: string;
|
|
2809
|
-
/** Pays fees + signs the claim tx (relay-submitted is a documented follow-up). */
|
|
2810
|
-
payerKeypair: Keypair;
|
|
2811
|
-
onProgress?: (message: string) => void;
|
|
2812
|
-
}
|
|
2813
|
-
interface ClaimTimeoutRefundResult {
|
|
2814
|
-
/** Submitted ClaimRefund transaction signature. */
|
|
2815
|
-
signature: string;
|
|
2816
|
-
/** The fresh refund note created by the claim — store this to spend later. */
|
|
2817
|
-
refundUtxo: Utxo;
|
|
2818
|
-
/** The claim id consumed (hex). */
|
|
2819
|
-
claimId: string;
|
|
2820
|
-
/** The merkle leaf index where the refund note `C_r` landed. */
|
|
2821
|
-
leafIndex: number;
|
|
2822
|
-
}
|
|
2823
|
-
/**
|
|
2824
|
-
* Reclaim a timed-out swap's principal as a fresh shielded note via ClaimRefund.
|
|
2825
|
-
*
|
|
2826
|
-
* Front-running note: this self-submits the claim. The production default is
|
|
2827
|
-
* relay submission (decision #3) to avoid mempool exposure of the voucher; a
|
|
2828
|
-
* relay `/claim-refund` endpoint is the documented follow-up.
|
|
2829
|
-
*/
|
|
2830
|
-
declare function claimTimeoutRefund(params: ClaimTimeoutRefundParams, options: ClaimTimeoutRefundOptions): Promise<ClaimTimeoutRefundResult>;
|
|
2831
|
-
|
|
2832
2318
|
/**
|
|
2833
2319
|
* On-chain Merkle proof computation
|
|
2834
2320
|
*
|
|
@@ -2889,6 +2375,86 @@ declare function computeProofForLatestDeposit(connection: Connection, merkleTree
|
|
|
2889
2375
|
leafIndex: number;
|
|
2890
2376
|
}>;
|
|
2891
2377
|
|
|
2378
|
+
/**
|
|
2379
|
+
* The Cloak endpoints THIS BUILD of the SDK is allowed to talk to.
|
|
2380
|
+
*
|
|
2381
|
+
* ── Why this is a checked-in constant and not configuration ───────────────────────────────────
|
|
2382
|
+
* `dist/` is what `package.json` main/module/types resolve to, so `dist/` is what every consumer
|
|
2383
|
+
* executes. Anything a consumer can set at THEIR build or run time — `NODE_ENV`, an environment
|
|
2384
|
+
* variable, a bundler define, a call option — is not a pin, because we do not own the moment it is
|
|
2385
|
+
* resolved. `process.env.NODE_ENV === "production"` in particular is defeated by one line in a
|
|
2386
|
+
* consumer's bundler config or one `NODE_ENV=development` in front of `node`, so it is deliberately
|
|
2387
|
+
* not used anywhere in this package.
|
|
2388
|
+
*
|
|
2389
|
+
* The only value a published artifact carries that a consumer cannot supply is one that was decided
|
|
2390
|
+
* when WE built it. That is this file. It is compiled into the bundle, it is greppable in the
|
|
2391
|
+
* bundle, and changing it requires editing source and rebuilding.
|
|
2392
|
+
*
|
|
2393
|
+
* ── How to point the SDK somewhere else ───────────────────────────────────────────────────────
|
|
2394
|
+
* REPLACE the entry in {@link RELAY_ORIGIN_ALLOWLIST} with your local origin. Do not append:
|
|
2395
|
+
* appending leaves production reachable from a local build, which is exactly the pairing that made
|
|
2396
|
+
* a rehearsal POST real proof data to production (see SQ-F1 in
|
|
2397
|
+
* `src/__tests__/relay-url-no-production-default.test.ts`). Replacing makes production *unreachable*
|
|
2398
|
+
* from a local build, at every egress point, rather than merely "not the default".
|
|
2399
|
+
*
|
|
2400
|
+
* export const RELAY_ORIGIN_ALLOWLIST: readonly string[] = ["http://127.0.0.1:5500"];
|
|
2401
|
+
*
|
|
2402
|
+
* Inside this repo nothing else has to happen: jest (`roots: src`), `tsx examples/...` and
|
|
2403
|
+
* `scripts/` all resolve `@cloak.dev/sdk` to `src/index.ts` through the tsconfig path mapping, so
|
|
2404
|
+
* they pick the edit up with no build step. Only a consumer that imports `dist/` — the soak harness,
|
|
2405
|
+
* or a web/mobile checkout linked with `file:` / `npm link` — needs `npm run build` afterwards.
|
|
2406
|
+
*
|
|
2407
|
+
* `src/__tests__/relay-origin-lock.test.ts` goes red while the allowlist is local. That is the
|
|
2408
|
+
* mechanism working: a local allowlist cannot be committed or published without one deliberate red
|
|
2409
|
+
* test and a one-line `git diff` saying so. Run `git checkout src/config/relay.ts` before pushing.
|
|
2410
|
+
*
|
|
2411
|
+
* ── Scope, stated honestly ────────────────────────────────────────────────────────────────────
|
|
2412
|
+
* This is an integrity and product-control mechanism, not a security boundary. Anyone who can run
|
|
2413
|
+
* code in the consumer's process can `sed` this literal in `node_modules`, `patch-package` it, alias
|
|
2414
|
+
* the module, monkey-patch `globalThis.fetch`, or skip the SDK entirely. What it buys is that the
|
|
2415
|
+
* correct endpoint is the only one reachable BY ACCIDENT, and that any deviation is a deliberate,
|
|
2416
|
+
* visible, auditable edit.
|
|
2417
|
+
*/
|
|
2418
|
+
/**
|
|
2419
|
+
* Identity of Cloak's production endpoint. This is a NAME, never a default: no code path in this
|
|
2420
|
+
* SDK falls back to it, and `resolveRelayUrl` still returns `undefined` when the caller passes
|
|
2421
|
+
* nothing (SQ-F1). It exists so a caller who genuinely wants production can say so by importing a
|
|
2422
|
+
* value instead of re-typing a host.
|
|
2423
|
+
*/
|
|
2424
|
+
declare const CLOAK_PRODUCTION_RELAY_URL = "https://api.cloak.ag";
|
|
2425
|
+
/**
|
|
2426
|
+
* The origins this build may send a request to. Enforced at every network egress in the package by
|
|
2427
|
+
* `assertAllowedRelayOrigin` / `relayFetch` in `src/relay/endpoint.ts`, so it covers the entry
|
|
2428
|
+
* points that take a URL directly (`submitTransactToRelay`, `RelayService`, `fetchCommitments`,
|
|
2429
|
+
* `registerViewingKey`, `readMerkleTreeState`, …) and not only the `relayUrl` transact option.
|
|
2430
|
+
*
|
|
2431
|
+
* Typed `readonly string[]` and not `as const` on purpose: a developer replaces the entry, and a
|
|
2432
|
+
* literal tuple type would make that edit a `tsc` error in unrelated files.
|
|
2433
|
+
*/
|
|
2434
|
+
declare const RELAY_ORIGIN_ALLOWLIST: readonly string[];
|
|
2435
|
+
/**
|
|
2436
|
+
* ONE switch, DERIVED — not a second flag to keep in sync.
|
|
2437
|
+
*
|
|
2438
|
+
* True exactly when {@link RELAY_ORIGIN_ALLOWLIST} names a loopback origin, i.e. when this artifact
|
|
2439
|
+
* was built for a local stack. It is what "this build is a production artifact" means for the
|
|
2440
|
+
* localhost-RPC guard, and because it is derived there is no state where the endpoint is local but
|
|
2441
|
+
* the RPC guard is still armed. The single edit above flips both.
|
|
2442
|
+
*
|
|
2443
|
+
* ── Why the build, and not the program id, the RPC URL, or the relay URL ──────────────────────
|
|
2444
|
+
* - **Program id**: identical on mainnet and on the whole local estate by design — a Surfpool fork
|
|
2445
|
+
* mirrors mainnet, so it carries the same program id (see `src/program/ids.ts`). Zero
|
|
2446
|
+
* discriminating power.
|
|
2447
|
+
* - **`detectNetworkFromRpcUrl`**: answers "localnet" for any localhost URL and defaults unknown
|
|
2448
|
+
* strings to "mainnet" (`src/shared/network.ts`). For Surfpool — a localhost URL mirroring
|
|
2449
|
+
* mainnet — that is exactly inverted, which is why `src/relay/risk-quote.ts` calls it and
|
|
2450
|
+
* immediately undoes the answer. It also reads its own environment variable.
|
|
2451
|
+
* - **"the relay URL is the production one"**: the same fact as this flag, reached by string
|
|
2452
|
+
* comparison, and undefined on the `relayUrl: ""` self-submit path.
|
|
2453
|
+
* - **This flag**: fixed at the same instant the endpoint is fixed, unchangeable by a consumer
|
|
2454
|
+
* without forking, and needs no run-time classification of an attacker-supplied string.
|
|
2455
|
+
*/
|
|
2456
|
+
declare const BUILD_ALLOWS_LOCAL_ENDPOINTS: boolean;
|
|
2457
|
+
|
|
2892
2458
|
/**
|
|
2893
2459
|
* Relay client utilities for fetching data from the relay service
|
|
2894
2460
|
*/
|
|
@@ -3008,11 +2574,11 @@ declare function preflightCheck(relayUrl: string, rootHex: string): Promise<{
|
|
|
3008
2574
|
* The merkle-from-chain rebuild was guarded by TWO independently written predicates that disagreed
|
|
3009
2575
|
* about React Native:
|
|
3010
2576
|
*
|
|
3011
|
-
* - the GATE in `
|
|
2577
|
+
* - the GATE in `flows/transact.ts` — `!IS_BROWSER && isMerkleClass && relayUrl`, where
|
|
3012
2578
|
* `IS_BROWSER` was `typeof window !== "undefined" || typeof globalThis.document !== "undefined"`,
|
|
3013
2579
|
* with NO React-Native carve-out. React Native defines `window`, so RN read as a browser and the
|
|
3014
2580
|
* last-resort chain replay was silently skipped there.
|
|
3015
|
-
* - the BUILDER it guards — `
|
|
2581
|
+
* - the BUILDER it guards — `relay/client.ts::buildMerkleTreeFromChain`, whose own
|
|
3016
2582
|
* `isBrowser()` short-circuits on `navigator.product === "ReactNative"` and therefore explicitly
|
|
3017
2583
|
* PERMITS React Native to rebuild from chain.
|
|
3018
2584
|
*
|
|
@@ -3050,7 +2616,7 @@ declare function preflightCheck(relayUrl: string, rootHex: string): Promise<{
|
|
|
3050
2616
|
*/
|
|
3051
2617
|
/**
|
|
3052
2618
|
* True on React Native. `navigator.product === "ReactNative"` is the canonical flag and is what
|
|
3053
|
-
* `
|
|
2619
|
+
* `proving/artifacts.ts` has always used.
|
|
3054
2620
|
*/
|
|
3055
2621
|
declare function isReactNative(): boolean;
|
|
3056
2622
|
/**
|
|
@@ -3068,42 +2634,137 @@ declare function isBrowser(): boolean;
|
|
|
3068
2634
|
declare function isBrowserLike(): boolean;
|
|
3069
2635
|
|
|
3070
2636
|
/**
|
|
3071
|
-
*
|
|
3072
|
-
*
|
|
3073
|
-
*
|
|
3074
|
-
*
|
|
3075
|
-
*
|
|
3076
|
-
*
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
*
|
|
3081
|
-
*
|
|
3082
|
-
*
|
|
3083
|
-
*
|
|
3084
|
-
*
|
|
3085
|
-
*
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
*
|
|
3090
|
-
*
|
|
3091
|
-
*
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
*
|
|
3097
|
-
*
|
|
3098
|
-
*
|
|
3099
|
-
*
|
|
3100
|
-
*
|
|
3101
|
-
*
|
|
3102
|
-
*
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
2637
|
+
* How long the relay accepts a signed request after its `auth_issued_at`
|
|
2638
|
+
* (`REQUEST_AUTH_MAX_AGE_SECONDS`, `api/request_auth.rs`).
|
|
2639
|
+
*
|
|
2640
|
+
* A FIRST-USE request past this window is rejected outright. The expiry exception the relay grants
|
|
2641
|
+
* applies only to an exact replay of a request whose durable row already exists, which by
|
|
2642
|
+
* definition never happens for a request that has not been accepted once.
|
|
2643
|
+
*/
|
|
2644
|
+
declare const REQUEST_AUTH_MAX_AGE_SECONDS = 300;
|
|
2645
|
+
/**
|
|
2646
|
+
* How far ahead of the relay's clock a request may be stamped
|
|
2647
|
+
* (`REQUEST_AUTH_MAX_FUTURE_SKEW_SECONDS`, `api/request_auth.rs`).
|
|
2648
|
+
*
|
|
2649
|
+
* `auth_issued_at` comes from `Date.now()`. On a server that is NTP-disciplined; in a browser it
|
|
2650
|
+
* is the user's own machine clock, and a laptop more than 30 seconds fast cannot authenticate at
|
|
2651
|
+
* all until its clock is corrected.
|
|
2652
|
+
*/
|
|
2653
|
+
declare const REQUEST_AUTH_MAX_FUTURE_SKEW_SECONDS = 30;
|
|
2654
|
+
/**
|
|
2655
|
+
* The exact fields each endpoint signs. Both lists mirror the relay's `*_auth_request` builders and
|
|
2656
|
+
* must stay in lockstep with them: adding a field on one side alone silently invalidates every
|
|
2657
|
+
* signature, and the failure surfaces as a bare 401 with nothing pointing here.
|
|
2658
|
+
*/
|
|
2659
|
+
declare const TRANSACT_AUTH_FIELDS: readonly ["encrypted_notes", "max_fee", "mint", "proof_bytes", "public_inputs", "recipient", "recipient_delivery_notes", "risk_quote", "sender"];
|
|
2660
|
+
declare const TRANSACT_SWAP_AUTH_FIELDS: readonly ["close_timed_out", "dexes", "encrypted_notes", "exclude_dexes", "max_fee", "min_output_amount", "output_mint", "proof_bytes", "public_inputs", "recipient", "recipient_ata", "refund_blinding", "refund_pubkey", "retry_request_id", "risk_quote", "route_retry_attempts", "sender", "slippage_bps", "swap_max_retries"];
|
|
2661
|
+
/**
|
|
2662
|
+
* Serialize exactly like the relay's `canonical_json`: keys sorted bytewise, no whitespace.
|
|
2663
|
+
*
|
|
2664
|
+
* SCOPE. This is the SDK's half of a byte-for-byte agreement with one specific Rust function over
|
|
2665
|
+
* one specific schema: the values reachable through {@link TRANSACT_AUTH_FIELDS} and
|
|
2666
|
+
* {@link TRANSACT_SWAP_AUTH_FIELDS}, which are ASCII keys over strings, small unsigned integers,
|
|
2667
|
+
* booleans, nulls, arrays and plain objects. Inside that schema the two implementations agree.
|
|
2668
|
+
*
|
|
2669
|
+
* Outside it they need not, so anything that could serialize differently on the two sides is
|
|
2670
|
+
* REFUSED here rather than signed into a digest that silently fails to match:
|
|
2671
|
+
*
|
|
2672
|
+
* - Non-integer, non-finite and beyond-safe-integer numbers. `serde_json` renders an f64 as Rust
|
|
2673
|
+
* does (`1e21`) where JavaScript renders `1e+21`, and `0.1 + 0.2` has no single spelling. Every
|
|
2674
|
+
* number in both field lists is a small unsigned integer (`slippage_bps`, `route_retry_attempts`,
|
|
2675
|
+
* `swap_max_retries`); u64 amounts already travel as decimal STRINGS for exactly this reason.
|
|
2676
|
+
* - Functions and symbols as object VALUES. `JSON.stringify` drops such a key from the wire body
|
|
2677
|
+
* while it stays in the signed view, so the two digests can never agree.
|
|
2678
|
+
*
|
|
2679
|
+
* `undefined` is NOT refused: it serializes as `null` here, `JSON.stringify` omits the key on the
|
|
2680
|
+
* wire, and every optional field on the relay side is `Option<T>` with `#[serde(default)]`, so the
|
|
2681
|
+
* relay sees `null` too. That is the same agreement {@link buildAuthRequest} relies on. The one
|
|
2682
|
+
* field where it does not hold is `slippage_bps`, which is why that field is checked by name.
|
|
2683
|
+
*
|
|
2684
|
+
* `bigint` is accepted and rendered as a bare decimal integer, matching serde's u64/i64 output.
|
|
2685
|
+
* Note that such a value cannot also go on the wire: `JSON.stringify` throws on a bigint. Use a
|
|
2686
|
+
* decimal string in the body, as every SDK-built body does.
|
|
2687
|
+
*/
|
|
2688
|
+
declare function canonicalJson(value: unknown): string;
|
|
2689
|
+
/**
|
|
2690
|
+
* Everything an authenticated request needs EXCEPT the signature: the three fields that go on the
|
|
2691
|
+
* wire alongside it, plus the exact bytes to sign.
|
|
2692
|
+
*
|
|
2693
|
+
* This exists because the holder of the pen is not always a `Keypair`. A browser wallet adapter
|
|
2694
|
+
* exposes `signMessage(bytes): Promise<Uint8Array>` and no secret key at all, so the scheme has to
|
|
2695
|
+
* be reachable in two halves: build the preimage here, sign it wherever the key actually lives,
|
|
2696
|
+
* then put `sender` / `auth_issued_at` / `auth_nonce` and the base64 signature on the body.
|
|
2697
|
+
*
|
|
2698
|
+
* `message` is a plain ed25519 detached-signature preimage — nothing about the scheme changes
|
|
2699
|
+
* between a local keypair and a wallet, only who signs it.
|
|
2700
|
+
*/
|
|
2701
|
+
interface RelayAuthPreimage {
|
|
2702
|
+
sender: string;
|
|
2703
|
+
auth_issued_at: string;
|
|
2704
|
+
auth_nonce: string;
|
|
2705
|
+
message: Uint8Array;
|
|
2706
|
+
}
|
|
2707
|
+
/**
|
|
2708
|
+
* Build the signed view and its preimage for one request, WITHOUT signing.
|
|
2709
|
+
*
|
|
2710
|
+
* `sender` is bound into the signed view and returned for the body — the relay rejects a request
|
|
2711
|
+
* whose authenticated sender is not also present inside the signed payload. It must be the end
|
|
2712
|
+
* user's own wallet: `sender` is the key screened for sanctions on a shield-to-shield send, so
|
|
2713
|
+
* substituting an ephemeral or service key here moves the screening off the actual user.
|
|
2714
|
+
*
|
|
2715
|
+
* `nonce` and `issued_at` are generated here, once per call. Callers that re-POST a request must
|
|
2716
|
+
* reuse the same preimage rather than rebuilding it, or the relay sees a brand-new request.
|
|
2717
|
+
*/
|
|
2718
|
+
declare function buildRelayAuthPreimage(endpoint: string, programId: PublicKey, body: Record<string, unknown>, sender: PublicKey, nowSeconds?: number, fields?: readonly string[]): RelayAuthPreimage;
|
|
2719
|
+
/**
|
|
2720
|
+
* An async message signer standing in for a `Keypair`.
|
|
2721
|
+
*
|
|
2722
|
+
* A browser wallet adapter has no secret key to hand over — it exposes `signMessage`, and what
|
|
2723
|
+
* this scheme needs signed is a plain ed25519 detached signature, which is exactly what that
|
|
2724
|
+
* produces. Only the holder of the pen changes.
|
|
2725
|
+
*
|
|
2726
|
+
* COMPLIANCE — `walletPublicKey` becomes the request's authenticated `sender`, and `sender` is the
|
|
2727
|
+
* key screened for sanctions on a shield-to-shield send. It MUST be the end user's own wallet.
|
|
2728
|
+
* Putting an ephemeral, service-held or otherwise substituted key here moves the screening onto a
|
|
2729
|
+
* key that is not the user: a compliance regression, not a shortcut.
|
|
2730
|
+
*/
|
|
2731
|
+
interface RelayAuthSigner {
|
|
2732
|
+
/** The end user's real wallet. Becomes the authenticated `sender`. Never an ephemeral key. */
|
|
2733
|
+
walletPublicKey: PublicKey;
|
|
2734
|
+
/** Wallet-adapter `signMessage`; must return the 64-byte ed25519 detached signature. */
|
|
2735
|
+
signMessage: (message: Uint8Array) => Promise<Uint8Array>;
|
|
2736
|
+
}
|
|
2737
|
+
/**
|
|
2738
|
+
* Turn a relay rejection into something the person in front of the screen can act on.
|
|
2739
|
+
*
|
|
2740
|
+
* Every string matched here is an `Error::Unauthorized` from `api/request_auth.rs`, and all of them
|
|
2741
|
+
* arrive as the same bare 401. Two of them are not the caller's mistake at all: an approval that
|
|
2742
|
+
* sat too long, and a machine clock that is simply wrong. Returns `null` for anything that is not
|
|
2743
|
+
* an authentication rejection, so callers can append it only when there is something to add.
|
|
2744
|
+
*/
|
|
2745
|
+
declare function explainRelayAuthRejection(responseText: string): string | null;
|
|
2746
|
+
|
|
2747
|
+
/**
|
|
2748
|
+
* The circuit artifacts this SDK build proves against.
|
|
2749
|
+
*
|
|
2750
|
+
* One program, one circuit, one bundle: the deployed shield-pool embeds the
|
|
2751
|
+
* ceremony verifying key, so any other artifact set produces proofs the program
|
|
2752
|
+
* rejects (0x1010). There is deliberately no table, no bundle registry and no
|
|
2753
|
+
* version negotiation here -- an SDK build either matches the deployed program
|
|
2754
|
+
* or it is the wrong build.
|
|
2755
|
+
*
|
|
2756
|
+
* The digests are the security control: `loadVerifiedCircuitArtifacts` hashes
|
|
2757
|
+
* whatever it fetched and refuses to prove on a mismatch, so a compromised or
|
|
2758
|
+
* stale CDN cannot feed this build artifacts from another ceremony.
|
|
2759
|
+
*
|
|
2760
|
+
* Published and verified 2026-08-12; re-verify after any publish with
|
|
2761
|
+
* `packages/scripts/publish-circuits.sh --verify-only`. Two things that publish
|
|
2762
|
+
* established, both worth keeping in mind here:
|
|
2763
|
+
* - the prefix once held a half-finished upload (zkey and wasm, no witness
|
|
2764
|
+
* helpers), which is exactly what these digests defend against;
|
|
2765
|
+
* - the edge served the previous wasm for ~50 minutes after a correct upload,
|
|
2766
|
+
* so uploading the right bytes is not the same as serving them.
|
|
2767
|
+
*/
|
|
3107
2768
|
declare const TRANSACTION_CIRCUITS_VERSION = "0.2.0";
|
|
3108
2769
|
|
|
3109
2770
|
/**
|
|
@@ -3123,7 +2784,7 @@ declare const TRANSACTION_CIRCUITS_VERSION = "0.2.0";
|
|
|
3123
2784
|
* RN defines `window`, so the old inline `typeof window !== "undefined" || typeof document !==
|
|
3124
2785
|
* "undefined"` classified RN as a browser and skipped the rebuild, removing RN's only recovery path
|
|
3125
2786
|
* from a drifted relay tree while the builder was perfectly willing to serve it. Both now come from
|
|
3126
|
-
* `
|
|
2787
|
+
* `shared/environment`, so they cannot disagree about React Native again.
|
|
3127
2788
|
*
|
|
3128
2789
|
* The SSR conservatism is kept: `isBrowserLike()` is true when EITHER `window` or `document` exists,
|
|
3129
2790
|
* because an SSR host that polyfills only `document` must not be mistaken for Node and made to run a
|
|
@@ -3137,7 +2798,7 @@ declare function canRebuildMerkleTreeFromChain(): boolean;
|
|
|
3137
2798
|
/**
|
|
3138
2799
|
* Base the ceremony-frozen `transaction` artifacts are fetched from by default.
|
|
3139
2800
|
*
|
|
3140
|
-
* Derived from {@link
|
|
2801
|
+
* Derived from {@link TRANSACTION_CIRCUITS_BASE_URL} — the same record that pins the
|
|
3141
2802
|
* digests — so the version in the URL and the digests checked against it cannot
|
|
3142
2803
|
* drift apart. It is `null` while this SDK build pins no location whose bytes
|
|
3143
2804
|
* were verified to hash to those digests; that makes an unconfigured SDK a
|
|
@@ -3151,9 +2812,26 @@ declare const DEFAULT_TRANSACTION_CIRCUITS_URL: string | null;
|
|
|
3151
2812
|
* Set circuits base path: local directory containing `transaction_js/` and `transaction_final.zkey`,
|
|
3152
2813
|
* or an `http(s)` base URL to those artifacts (loaded into memory once per process).
|
|
3153
2814
|
*
|
|
2815
|
+
* ── Kept, not removed, and now checked ────────────────────────────────────────────────────────
|
|
2816
|
+
* It stays public API for one reason the pin cannot serve: an offline, air-gapped or React-Native
|
|
2817
|
+
* caller must be able to name a LOCAL directory holding the ceremony artifacts, and every example
|
|
2818
|
+
* in this repo calls it. What changed is that the string is no longer honoured verbatim. It goes
|
|
2819
|
+
* through {@link assertAllowedCircuitsBase}, the same shape of check `relayUrl` gets: a local
|
|
2820
|
+
* directory is accepted (it puts nothing on the wire, and the unconditional digest check governs
|
|
2821
|
+
* its bytes), an `http(s)` base must be at or under this build's pinned bundle base, and a loopback
|
|
2822
|
+
* base is accepted only in a build whose relay allowlist is already local.
|
|
2823
|
+
*
|
|
2824
|
+
* Asserted HERE for a good early error, and again at the read itself in `proving/artifacts.ts` —
|
|
2825
|
+
* because this setter is not the only door: `loadVerifiedCircuitArtifacts`, `verifyCircuitIntegrity`,
|
|
2826
|
+
* `assertTransactionCircuitIntegrity` and `verifyAllCircuits` are all exported and all take a base
|
|
2827
|
+
* directly. A setter-only check would have been theatre, exactly as it would have been for the
|
|
2828
|
+
* relay URL.
|
|
2829
|
+
*
|
|
3154
2830
|
* No cache invalidation is needed here: verified artifact buffers are memoised
|
|
3155
|
-
* per base inside `
|
|
2831
|
+
* per base inside `proving/artifacts.ts`, so a new base loads and re-verifies its
|
|
3156
2832
|
* own bytes.
|
|
2833
|
+
*
|
|
2834
|
+
* @throws when `next` names a location this build may not read circuit artifacts from.
|
|
3157
2835
|
*/
|
|
3158
2836
|
declare function setCircuitsPath(next: string): void;
|
|
3159
2837
|
/**
|
|
@@ -3162,13 +2840,22 @@ declare function setCircuitsPath(next: string): void;
|
|
|
3162
2840
|
*/
|
|
3163
2841
|
declare function getCircuitsPath(): string | null;
|
|
3164
2842
|
/**
|
|
3165
|
-
* Resolve a base to prove from: an explicit argument, else
|
|
3166
|
-
*
|
|
2843
|
+
* Resolve a base to prove from: an explicit argument, else this build's pinned default.
|
|
2844
|
+
*
|
|
2845
|
+
* ── The environment reads are gone ────────────────────────────────────────────────────────────
|
|
2846
|
+
* This used to fall back to `CLOAK_CIRCUITS_PATH` / `CLOAK_CIRCUITS`. Both resolve in the
|
|
2847
|
+
* CONSUMER's process, which is the same reason `NODE_ENV` is not used anywhere in this package:
|
|
2848
|
+
* `CLOAK_CIRCUITS_PATH=http://evil.example/circuits node app.js`, or one
|
|
2849
|
+
* `--define:process.env.CLOAK_CIRCUITS_PATH='"http://evil.example/circuits"'` in a consumer's
|
|
2850
|
+
* bundler, silently moved where the witness generator came from — and the witness generator is
|
|
2851
|
+
* handed the spend key. An integrator who genuinely needs a different location passes it
|
|
2852
|
+
* explicitly and it is checked against the pin like any other.
|
|
3167
2853
|
*
|
|
3168
2854
|
* Use this instead of writing an artifact URL out by hand — a hand-written URL
|
|
3169
2855
|
* is exactly how the base's version segment came to disagree with the digests
|
|
3170
2856
|
* this SDK checks against. Throws an explanatory error (naming the expected
|
|
3171
|
-
* bundle version and both expected digests) when nothing resolves
|
|
2857
|
+
* bundle version and both expected digests) when nothing resolves, and refuses a
|
|
2858
|
+
* base this build may not read from.
|
|
3172
2859
|
*/
|
|
3173
2860
|
declare function resolveCircuitsBase(explicit?: string): string;
|
|
3174
2861
|
/**
|
|
@@ -3182,6 +2869,68 @@ declare function resolveCircuitsBase(explicit?: string): string;
|
|
|
3182
2869
|
*/
|
|
3183
2870
|
declare function computeChainNoteHash(publicAmount: bigint, extDataHash: bigint, noteTimestamp: bigint, noteCommitment: bigint, noteSalt: bigint, outAmount0: bigint, outPubkey0: bigint, noteIsSendToSelfKey0: bigint): Promise<bigint>;
|
|
3184
2871
|
declare function computeExtDataHash(recipient: PublicKey | null, relayerFee: bigint, relayer: PublicKey | null, maxFee?: bigint): Promise<bigint>;
|
|
2872
|
+
/**
|
|
2873
|
+
* Adapter for a third-party fee-payer relayer (e.g. Kora, https://github.com/solana-foundation/kora)
|
|
2874
|
+
* that lets the depositor pay network fees — and, via `buildTopUpInstructions`, the on-chain rent
|
|
2875
|
+
* this deposit itself needs — in an SPL token instead of native SOL. Only consulted on the deposit
|
|
2876
|
+
* path (externalAmount > 0); ignored for transfers/withdrawals/swaps, which already go through the
|
|
2877
|
+
* relay's own SOL-funded fee payer. Optional — omitting this leaves every existing caller (including
|
|
2878
|
+
* the web app) byte-for-byte unchanged: the depositor remains the fee payer and must hold SOL.
|
|
2879
|
+
*/
|
|
2880
|
+
interface ExternalFeePayerAdapter {
|
|
2881
|
+
/** Returns the external fee payer's pubkey (Kora's `getPayerSigner`). */
|
|
2882
|
+
getPayerPubkey: () => Promise<PublicKey>;
|
|
2883
|
+
/**
|
|
2884
|
+
* Instructions to insert right after the risk-quote instruction (if any) and before every
|
|
2885
|
+
* instruction that spends the depositor's own SOL balance — typically a single
|
|
2886
|
+
* `SystemProgram.transfer(payerPubkey → depositor, neededLamports)`, so the depositor never
|
|
2887
|
+
* needs to hold SOL up front. Return an empty array when no top-up is needed (the depositor
|
|
2888
|
+
* already has enough SOL for on-chain rent).
|
|
2889
|
+
*
|
|
2890
|
+
* A plain transfer works because the external payer's own fee-pricing engine (e.g. Kora's
|
|
2891
|
+
* `calculate_fee_payer_outflow`) already accounts for ANY lamport outflow from its own account
|
|
2892
|
+
* across the whole transaction — not just the base network fee — when it prices
|
|
2893
|
+
* `getPaymentInstruction`. No swap instruction or DEX integration is needed on the client: the
|
|
2894
|
+
* payer's server-side pricing (margin/fixed, its own config) charges for this transfer
|
|
2895
|
+
* automatically. The payer is expected to replenish its own SOL out-of-band (e.g. periodically
|
|
2896
|
+
* converting collected SPL fees back to SOL) — that is entirely the payer's operational concern,
|
|
2897
|
+
* invisible to this adapter and to the depositor.
|
|
2898
|
+
*
|
|
2899
|
+
* Must NOT be inserted before the risk-quote instruction: the on-chain program verifies the risk
|
|
2900
|
+
* quote's Ed25519 signature via instruction introspection at a fixed transaction-level index (0),
|
|
2901
|
+
* so the risk-quote instruction must remain first no matter what else this adapter adds.
|
|
2902
|
+
*
|
|
2903
|
+
* Must NOT include ComputeBudgetProgram instructions of its own — the transaction already
|
|
2904
|
+
* carries one of each, sized for the whole thing including this top-up; a second pair is
|
|
2905
|
+
* rejected by the runtime as duplicate instructions.
|
|
2906
|
+
*/
|
|
2907
|
+
buildTopUpInstructions: (payerPubkey: PublicKey) => Promise<TransactionInstruction[]>;
|
|
2908
|
+
/**
|
|
2909
|
+
* Given a base64-encoded, unsigned V0 transaction (feePayer = the external payer's pubkey, every
|
|
2910
|
+
* instruction the deposit needs including any top-up, fresh blockhash), returns the fee-payment
|
|
2911
|
+
* instruction to append before final signing (Kora's `getPaymentInstruction`).
|
|
2912
|
+
*/
|
|
2913
|
+
getPaymentInstruction: (unsignedTxBase64: string) => Promise<TransactionInstruction>;
|
|
2914
|
+
/**
|
|
2915
|
+
* Given a base64-encoded transaction the depositor has already partially signed (their own signer
|
|
2916
|
+
* slot filled; the external payer's slot still empty — same instructions plus the payment
|
|
2917
|
+
* instruction, fresh blockhash), returns the fully co-signed transaction, base64-encoded (Kora's
|
|
2918
|
+
* `signTransaction`).
|
|
2919
|
+
*/
|
|
2920
|
+
cosign: (partiallySignedTxBase64: string) => Promise<string>;
|
|
2921
|
+
/**
|
|
2922
|
+
* Optional: accounts the payment instruction will reference, resolvable BEFORE that instruction
|
|
2923
|
+
* exists (for Kora: the fee payer's and depositor's fee-token ATAs).
|
|
2924
|
+
*
|
|
2925
|
+
* Purely a size optimization, never correctness — the real accounts always come from
|
|
2926
|
+
* `getPaymentInstruction`. Without it, the supplemental ALT built for the quote transaction can't
|
|
2927
|
+
* know about the payment instruction's accounts, so a deposit that lands just over the packet
|
|
2928
|
+
* limit once that instruction is appended needs a SECOND supplemental ALT (an extra on-chain
|
|
2929
|
+
* transaction and extra rent, paid by the external payer). Measured on the first real deposit:
|
|
2930
|
+
* 1236 bytes vs the 1232 limit — over by 4. With the hint, one ALT covers the final transaction.
|
|
2931
|
+
*/
|
|
2932
|
+
getPaymentAccountHints?: () => Promise<PublicKey[]>;
|
|
2933
|
+
}
|
|
3185
2934
|
/**
|
|
3186
2935
|
* Options for transact operation
|
|
3187
2936
|
*/
|
|
@@ -3199,8 +2948,19 @@ interface TransactOptions {
|
|
|
3199
2948
|
/** Relayer address for fee payment */
|
|
3200
2949
|
relayer?: PublicKey;
|
|
3201
2950
|
/**
|
|
3202
|
-
*
|
|
3203
|
-
*
|
|
2951
|
+
* Cloak endpoint to submit through.
|
|
2952
|
+
*
|
|
2953
|
+
* This option no longer SELECTS the endpoint — the endpoint is pinned when the SDK is built
|
|
2954
|
+
* (`RELAY_ORIGIN_ALLOWLIST` in `src/config/relay.ts`). Only two values are accepted:
|
|
2955
|
+
*
|
|
2956
|
+
* - an origin on this build's allowlist — say `CLOAK_PRODUCTION_RELAY_URL` rather than typing a
|
|
2957
|
+
* host; anything else throws, naming the value and the allowlist;
|
|
2958
|
+
* - `""`, which means NO endpoint: the caller signs and submits the deposit itself. Unchanged,
|
|
2959
|
+
* still supported, and checked before any validation.
|
|
2960
|
+
*
|
|
2961
|
+
* Never defaulted. Omitting it still yields `undefined` (SQ-F1), not production. To point at a
|
|
2962
|
+
* local stack, edit `src/config/relay.ts` and rebuild — not an option, not an environment
|
|
2963
|
+
* variable, because a published build must not be repointable at either.
|
|
3204
2964
|
*/
|
|
3205
2965
|
relayUrl?: string;
|
|
3206
2966
|
/** Keypair of the depositor (signs the deposit transaction) - for programmatic use */
|
|
@@ -3219,6 +2979,16 @@ interface TransactOptions {
|
|
|
3219
2979
|
walletPublicKey?: PublicKey;
|
|
3220
2980
|
/** Maximum retries on RootNotFound error (default: 5) */
|
|
3221
2981
|
maxRootRetries?: number;
|
|
2982
|
+
/**
|
|
2983
|
+
* How many times a wallet adapter may be asked to approve ONE swap (default: 5).
|
|
2984
|
+
*
|
|
2985
|
+
* Only applies to the wallet-adapter path, and only to `swapUtxo` / `swapWithChange`: a swap
|
|
2986
|
+
* re-proves on every retry, so every retry needs a fresh approval, and `maxRootRetries` alone
|
|
2987
|
+
* would allow 41 dialogs for a single swap. A `depositorKeypair` signs without prompting and is
|
|
2988
|
+
* bounded by `maxRootRetries` as before. A private send or withdrawal signs exactly once,
|
|
2989
|
+
* whatever happens on the network.
|
|
2990
|
+
*/
|
|
2991
|
+
maxWalletApprovals?: number;
|
|
3222
2992
|
/** Delay between retries in ms (default: 3000) */
|
|
3223
2993
|
retryDelayMs?: number;
|
|
3224
2994
|
/**
|
|
@@ -3231,6 +3001,12 @@ interface TransactOptions {
|
|
|
3231
3001
|
* Used for deposits when riskOracleQueue is set. The backend must return a signed
|
|
3232
3002
|
* quote instruction for the depositor wallet so the program can verify at index 0.
|
|
3233
3003
|
* Defaults to `${relayUrl}/range-quote` when relayUrl is set.
|
|
3004
|
+
*
|
|
3005
|
+
* Held to the SAME build-pinned allowlist as `relayUrl`: it is fetched directly and it is
|
|
3006
|
+
* converted back into a base URL by `deriveRelayUrlFromRiskQuoteUrl`, so leaving it unchecked
|
|
3007
|
+
* would leave a second door onto the first. It must therefore be an ABSOLUTE URL on this build's
|
|
3008
|
+
* allowlist; a relative path (e.g. `/api/risk-quote`) is no longer resolved against the page
|
|
3009
|
+
* origin. `""` disables the SDK-side prefetch, unchanged.
|
|
3234
3010
|
*/
|
|
3235
3011
|
riskQuoteUrl?: string;
|
|
3236
3012
|
/**
|
|
@@ -3251,6 +3027,15 @@ interface TransactOptions {
|
|
|
3251
3027
|
* to compress account addresses from 32 bytes to 1-byte indices.
|
|
3252
3028
|
*/
|
|
3253
3029
|
addressLookupTableAccounts?: AddressLookupTableAccount[];
|
|
3030
|
+
/**
|
|
3031
|
+
* Opt-in: when true and `relayUrl` is set, an SPL deposit that needs a supplemental lookup
|
|
3032
|
+
* table asks the relay to extend its shared table (`${relayUrl}/supplemental-alt`) instead of
|
|
3033
|
+
* creating a depositor-signed throwaway table, so the user signs exactly once. Any relay
|
|
3034
|
+
* failure — a bad response, a missing address, or the client-side slot gate never clearing —
|
|
3035
|
+
* falls back to the old depositor-signed ephemeral-ALT path automatically. Off (the default)
|
|
3036
|
+
* preserves the old behaviour exactly.
|
|
3037
|
+
*/
|
|
3038
|
+
relaySupplementalAlt?: boolean;
|
|
3254
3039
|
/**
|
|
3255
3040
|
* Optional Range.org API key for direct SDK-side quote fetching.
|
|
3256
3041
|
*
|
|
@@ -3352,7 +3137,7 @@ interface TransactOptions {
|
|
|
3352
3137
|
useUniqueNullifiers?: boolean;
|
|
3353
3138
|
/**
|
|
3354
3139
|
* Optional DEX allow-list for swaps (Jupiter `dexes`).
|
|
3355
|
-
* Example: ["
|
|
3140
|
+
* Example: ["Meteora DLMM", "Raydium CLMM"]
|
|
3356
3141
|
*/
|
|
3357
3142
|
swapDexes?: string[];
|
|
3358
3143
|
/**
|
|
@@ -3392,8 +3177,24 @@ interface TransactOptions {
|
|
|
3392
3177
|
* Use when relay may be behind the chain (e.g. commitment_sync lag) to avoid ProofInvalid.
|
|
3393
3178
|
*/
|
|
3394
3179
|
useChainRootForProof?: boolean;
|
|
3180
|
+
/**
|
|
3181
|
+
* Optional external fee-payer adapter (e.g. Kora) for deposits only. When set, the depositor no
|
|
3182
|
+
* longer needs to hold SOL: the adapter's payer covers the network fee (and, via
|
|
3183
|
+
* `buildTopUpInstructions`, any on-chain rent) and is reimbursed in an SPL token within the same
|
|
3184
|
+
* transaction. Omit for unchanged default behavior.
|
|
3185
|
+
*/
|
|
3186
|
+
externalFeePayer?: ExternalFeePayerAdapter;
|
|
3395
3187
|
}
|
|
3396
|
-
/**
|
|
3188
|
+
/**
|
|
3189
|
+
* Switchboard-style response: a pre-built instruction.
|
|
3190
|
+
*
|
|
3191
|
+
* @deprecated No longer accepted. `fetchRiskQuote` rejects this shape outright:
|
|
3192
|
+
* a relay that can name the program id, the account metas and the data of an
|
|
3193
|
+
* instruction the user's wallet signs is a signing oracle. The relay only ever
|
|
3194
|
+
* returns `{ signature, message, signer_pubkey }`, which the SDK verifies and
|
|
3195
|
+
* rebuilds locally as an account-free Ed25519 instruction. The type is kept as
|
|
3196
|
+
* an export purely so consumers importing it still compile.
|
|
3197
|
+
*/
|
|
3397
3198
|
interface RiskQuoteInstructionResponse {
|
|
3398
3199
|
instruction: {
|
|
3399
3200
|
programId: string;
|
|
@@ -3470,12 +3271,23 @@ type RelaySubmissionResult = {
|
|
|
3470
3271
|
kind: "failed";
|
|
3471
3272
|
error: Error;
|
|
3472
3273
|
};
|
|
3274
|
+
|
|
3473
3275
|
interface SubmitTransactToRelayArgs {
|
|
3474
3276
|
relayUrl: string;
|
|
3475
3277
|
/** The exact body to POST. Auth fields are added ONCE, in place, and then never changed. */
|
|
3476
3278
|
requestBody: Record<string, unknown>;
|
|
3477
3279
|
programId: PublicKey;
|
|
3478
3280
|
depositorKeypair?: Keypair;
|
|
3281
|
+
/**
|
|
3282
|
+
* Wallet-adapter alternative to `depositorKeypair` for request authentication, used only when
|
|
3283
|
+
* no keypair is supplied. Lets a browser or mobile caller — which holds no secret key — submit
|
|
3284
|
+
* through this same function instead of hand-rolling the scheme.
|
|
3285
|
+
*
|
|
3286
|
+
* COMPLIANCE: `walletPublicKey` becomes the authenticated `sender`, which is the key screened
|
|
3287
|
+
* for sanctions on shield-to-shield sends. It must be the end user's real wallet; an ephemeral
|
|
3288
|
+
* or server-side key here is a compliance regression, not a shortcut.
|
|
3289
|
+
*/
|
|
3290
|
+
relayAuthSigner?: RelayAuthSigner;
|
|
3479
3291
|
settlement: SettlementContext;
|
|
3480
3292
|
/** True while the caller still has a re-prove budget for a stale root. */
|
|
3481
3293
|
canRetryStaleRoot: boolean;
|
|
@@ -3606,9 +3418,9 @@ interface UtxoSwapResult extends TransactResult {
|
|
|
3606
3418
|
* Execute a UTXO swap withdrawal
|
|
3607
3419
|
*
|
|
3608
3420
|
* This spends input UTXOs and creates a SwapState PDA for swapping SOL to SPL tokens.
|
|
3609
|
-
*
|
|
3610
|
-
* 1. PrepareSwapSol - Wrap SOL
|
|
3611
|
-
* 2.
|
|
3421
|
+
* The swap is then completed on-chain in two follow-up instructions:
|
|
3422
|
+
* 1. PrepareSwapSol - Wrap the SOL held by the SwapState PDA into wSOL
|
|
3423
|
+
* 2. ExecuteSwap - Route the wSOL through Jupiter and deliver the output token to `recipientAta`
|
|
3612
3424
|
*
|
|
3613
3425
|
* @param params Swap parameters
|
|
3614
3426
|
* @param options Transaction options
|
|
@@ -3630,129 +3442,59 @@ declare function swapUtxo(params: UtxoSwapParams, options: TransactOptions): Pro
|
|
|
3630
3442
|
declare function swapWithChange(inputUtxos: Utxo[], swapAmount: bigint, outputMint: PublicKey, recipientAta: PublicKey, minOutputAmount: bigint, options: TransactOptions, recipientWallet?: PublicKey): Promise<UtxoSwapResult>;
|
|
3631
3443
|
|
|
3632
3444
|
/**
|
|
3633
|
-
*
|
|
3634
|
-
*
|
|
3635
|
-
* This module provides direct proof generation using snarkjs and Circom WASM,
|
|
3636
|
-
* matching the approach used in services-new/tests/src/proof.ts
|
|
3637
|
-
*
|
|
3638
|
-
* Artifacts come from the pinned per-bundle hosts in `config/circuit-release`,
|
|
3639
|
-
* verified by digest; no backend prover service is required.
|
|
3640
|
-
*/
|
|
3641
|
-
|
|
3642
|
-
/**
|
|
3643
|
-
* Default base URL for the legacy `withdraw_regular` / `withdraw_swap` artifacts.
|
|
3445
|
+
* Circuit artifact loading and integrity verification.
|
|
3644
3446
|
*
|
|
3645
|
-
*
|
|
3646
|
-
*
|
|
3647
|
-
*
|
|
3648
|
-
*
|
|
3649
|
-
* This is NOT the base for the ceremony-frozen `transaction` circuit: that
|
|
3650
|
-
* circuit lives in a different bundle ({@link TRANSACTION_CIRCUIT_BUNDLE}) with
|
|
3651
|
-
* different digests, and is configured through `setCircuitsPath()`.
|
|
3652
|
-
*
|
|
3653
|
-
* `string | null` — null when the bundle has no published host, which is the
|
|
3654
|
-
* case for the legacy withdraw artifacts.
|
|
3655
|
-
*
|
|
3656
|
-
* RESOLVED LAZILY ON PURPOSE. This was previously
|
|
3657
|
-
* `requirePinnedBaseUrl('withdraw_regular')` evaluated at module scope, so an
|
|
3658
|
-
* unpinned bundle made merely IMPORTING the SDK throw — breaking every consumer,
|
|
3659
|
-
* including those that never touch a legacy withdraw path. The diagnostic is
|
|
3660
|
-
* still raised, by `resolveCircuitsUrl` and `getDefaultCircuitsPath` at the
|
|
3661
|
-
* point of use, where a caller can actually act on it.
|
|
3662
|
-
*/
|
|
3663
|
-
declare const DEFAULT_CIRCUITS_URL: string | null;
|
|
3664
|
-
interface WithdrawRegularInputs {
|
|
3665
|
-
root: bigint;
|
|
3666
|
-
nullifier: bigint;
|
|
3667
|
-
outputs_hash: bigint;
|
|
3668
|
-
public_amount: bigint;
|
|
3669
|
-
amount: bigint;
|
|
3670
|
-
leaf_index: bigint;
|
|
3671
|
-
sk: [bigint, bigint];
|
|
3672
|
-
r: [bigint, bigint];
|
|
3673
|
-
pathElements: bigint[];
|
|
3674
|
-
pathIndices: number[];
|
|
3675
|
-
num_outputs: number;
|
|
3676
|
-
out_addr: bigint[][];
|
|
3677
|
-
out_amount: bigint[];
|
|
3678
|
-
out_flags: number[];
|
|
3679
|
-
var_fee: bigint;
|
|
3680
|
-
rem: bigint;
|
|
3681
|
-
}
|
|
3682
|
-
interface WithdrawSwapInputs {
|
|
3683
|
-
sk_spend: bigint;
|
|
3684
|
-
r: bigint;
|
|
3685
|
-
amount: bigint;
|
|
3686
|
-
leaf_index: bigint;
|
|
3687
|
-
path_elements: bigint[];
|
|
3688
|
-
path_indices: number[];
|
|
3689
|
-
root: bigint;
|
|
3690
|
-
nullifier: bigint;
|
|
3691
|
-
outputs_hash: bigint;
|
|
3692
|
-
public_amount: bigint;
|
|
3693
|
-
input_mint: bigint[];
|
|
3694
|
-
output_mint: bigint[];
|
|
3695
|
-
recipient_ata: bigint[];
|
|
3696
|
-
min_output_amount: bigint;
|
|
3697
|
-
var_fee: bigint;
|
|
3698
|
-
rem: bigint;
|
|
3699
|
-
}
|
|
3700
|
-
interface ProofResult {
|
|
3701
|
-
proof: Groth16Proof;
|
|
3702
|
-
publicSignals: string[];
|
|
3703
|
-
proofBytes: Uint8Array;
|
|
3704
|
-
publicInputsBytes: Uint8Array;
|
|
3705
|
-
}
|
|
3706
|
-
/**
|
|
3707
|
-
* Generate Groth16 proof for regular withdrawal using Circom WASM
|
|
3447
|
+
* Artifacts come from the pinned bundle in `config/circuits`, verified
|
|
3448
|
+
* by digest; no backend prover service is required. Proof generation itself
|
|
3449
|
+
* lives with the flows that own it (`flows/transact.ts`), which passes the
|
|
3450
|
+
* verified buffers this module returns straight to `snarkjs.groth16.fullProve`.
|
|
3708
3451
|
*
|
|
3709
|
-
*
|
|
3452
|
+
* The bytes are canonical HERE and copied out: every hand-off mints a fresh buffer from an
|
|
3453
|
+
* intrinsic captured at module load, and hashes a twin of that buffer, so the digest covers what is
|
|
3454
|
+
* used and not merely what was once loaded, and the buffer that is used was allocated by something
|
|
3455
|
+
* a consumer cannot redefine. See the note on `_verifiedArtifacts` for the break that made the copy
|
|
3456
|
+
* necessary (F7), and THE PRIMORDIALS for the one that made the copy's PROVENANCE necessary (F9).
|
|
3710
3457
|
*
|
|
3711
|
-
*
|
|
3712
|
-
*
|
|
3458
|
+
* Only the ceremony-frozen `transaction` circuit exists here. The deployed
|
|
3459
|
+
* program verifies proofs against that circuit's verifying key and nothing
|
|
3460
|
+
* else, so the pre-ceremony `withdraw_regular` / `withdraw_swap` circuits —
|
|
3461
|
+
* and every code path that loaded them — were removed rather than kept as
|
|
3462
|
+
* compatibility the program would reject anyway.
|
|
3713
3463
|
*/
|
|
3714
|
-
|
|
3464
|
+
|
|
3715
3465
|
/**
|
|
3716
|
-
*
|
|
3466
|
+
* Base URL of the only bundle this SDK pins: the ceremony `transaction` bundle.
|
|
3717
3467
|
*
|
|
3718
|
-
*
|
|
3468
|
+
* Identical to `DEFAULT_TRANSACTION_CIRCUITS_URL` in `flows/transact`; kept
|
|
3469
|
+
* under this name so existing imports keep resolving. Derived from
|
|
3470
|
+
* {@link TRANSACTION_CIRCUITS_BASE_URL}, so the version segment is the same one
|
|
3471
|
+
* the pinned digests were declared under — do not write this URL out by hand
|
|
3472
|
+
* anywhere; change the bundle instead.
|
|
3719
3473
|
*
|
|
3720
|
-
*
|
|
3721
|
-
*
|
|
3474
|
+
* `string | null` — `null` when this build pins no location whose bytes were
|
|
3475
|
+
* verified against the bundle's digests.
|
|
3722
3476
|
*/
|
|
3723
|
-
declare
|
|
3724
|
-
/**
|
|
3725
|
-
* Check if circuits are available from the pinned S3 source.
|
|
3726
|
-
*/
|
|
3727
|
-
declare function areCircuitsAvailable(circuitsPath: string): Promise<boolean>;
|
|
3728
|
-
/**
|
|
3729
|
-
* Get default circuits URL.
|
|
3730
|
-
*/
|
|
3731
|
-
declare function getDefaultCircuitsPath(): Promise<string>;
|
|
3477
|
+
declare const DEFAULT_CIRCUITS_URL: string;
|
|
3732
3478
|
/**
|
|
3733
3479
|
* Pinned circuit artifact hashes (SHA-256), flattened from the release table in
|
|
3734
|
-
* `
|
|
3480
|
+
* `proving/circuits.ts`.
|
|
3735
3481
|
*
|
|
3736
|
-
*
|
|
3737
|
-
*
|
|
3738
|
-
*
|
|
3482
|
+
* A read-only VIEW of {@link PINNED_TRANSACTION_WASM_DIGEST} / {@link PINNED_TRANSACTION_ZKEY_DIGEST},
|
|
3483
|
+
* kept because it is part of the published surface and integrators print it in start-up
|
|
3484
|
+
* diagnostics. FROZEN: it is not the source of truth and must not be able to pretend it is. Writing
|
|
3485
|
+
* to it throws in strict mode (every ES module is strict) and is a silent no-op in sloppy CJS
|
|
3486
|
+
* scope — either way the digests the check uses are unchanged.
|
|
3739
3487
|
*/
|
|
3740
|
-
declare const EXPECTED_CIRCUIT_HASHES: {
|
|
3741
|
-
withdraw_regular_wasm: string;
|
|
3742
|
-
withdraw_regular_zkey: string;
|
|
3743
|
-
withdraw_swap_wasm: string;
|
|
3744
|
-
withdraw_swap_zkey: string;
|
|
3488
|
+
declare const EXPECTED_CIRCUIT_HASHES: Readonly<{
|
|
3745
3489
|
transaction_wasm: string;
|
|
3746
3490
|
transaction_zkey: string;
|
|
3747
|
-
}
|
|
3491
|
+
}>;
|
|
3748
3492
|
/**
|
|
3749
3493
|
* Circuit verification result
|
|
3750
3494
|
*/
|
|
3751
3495
|
interface CircuitVerificationResult {
|
|
3752
3496
|
/** Whether verification passed */
|
|
3753
3497
|
valid: boolean;
|
|
3754
|
-
/** Which circuit was checked */
|
|
3755
|
-
circuit: CircuitName;
|
|
3756
3498
|
/** Error message if verification failed */
|
|
3757
3499
|
error?: string;
|
|
3758
3500
|
computed?: {
|
|
@@ -3764,13 +3506,25 @@ interface CircuitVerificationResult {
|
|
|
3764
3506
|
zkey: string;
|
|
3765
3507
|
};
|
|
3766
3508
|
}
|
|
3767
|
-
/**
|
|
3509
|
+
/**
|
|
3510
|
+
* Circuit artifact bytes together with the digests computed over those bytes.
|
|
3511
|
+
*
|
|
3512
|
+
* The buffers are a PRIVATE COPY, minted for this call from an intrinsic captured at module load
|
|
3513
|
+
* and hashed via a throwaway twin after they were copied. Nothing outside this module was handed
|
|
3514
|
+
* the object or a view onto it, so `digests` describes `wasm`/`zkey` as of the moment they were
|
|
3515
|
+
* handed over rather than as of some earlier load. Mutate them if you like; the SDK's canonical
|
|
3516
|
+
* bytes are elsewhere and the next call re-copies and re-hashes.
|
|
3517
|
+
*
|
|
3518
|
+
* The guarantee stops at the hand-off, and stops honestly. Once these buffers are inside
|
|
3519
|
+
* `snarkjs.groth16.fullProve` what snarkjs does with them is snarkjs's business; what this module
|
|
3520
|
+
* promises is that the bytes it handed over are the bytes whose SHA-256 it reported.
|
|
3521
|
+
*/
|
|
3768
3522
|
interface VerifiedCircuitArtifacts {
|
|
3769
|
-
/** `<circuit>_js/<circuit>.wasm` bytes. */
|
|
3523
|
+
/** `<circuit>_js/<circuit>.wasm` bytes. A fresh copy, not shared with any other caller. */
|
|
3770
3524
|
wasm: Uint8Array;
|
|
3771
|
-
/** `<circuit>_final.zkey` bytes. */
|
|
3525
|
+
/** `<circuit>_final.zkey` bytes. A fresh copy, not shared with any other caller. */
|
|
3772
3526
|
zkey: Uint8Array;
|
|
3773
|
-
/** SHA-256 (lowercase hex) of the buffers in this object. */
|
|
3527
|
+
/** SHA-256 (lowercase hex) of the buffers in this object, computed over these very buffers. */
|
|
3774
3528
|
digests: {
|
|
3775
3529
|
wasm: string;
|
|
3776
3530
|
zkey: string;
|
|
@@ -3789,8 +3543,23 @@ interface VerifiedCircuitArtifacts {
|
|
|
3789
3543
|
* Fails closed: any digest mismatch, unreachable artifact, or environment that
|
|
3790
3544
|
* cannot produce bytes (a browser pointed at a local directory) throws rather
|
|
3791
3545
|
* than falling back to an unverified source.
|
|
3546
|
+
*
|
|
3547
|
+
* Returns a FRESH COPY on every call, hashed after it was copied — see
|
|
3548
|
+
* {@link copyAndVerify} and the note on {@link _verifiedArtifacts}. Two calls never share a buffer,
|
|
3549
|
+
* and the digests in the returned object are the digests of the buffers in that same object, taken
|
|
3550
|
+
* at that call. Mutating what you are given affects nothing but your own copy.
|
|
3551
|
+
*
|
|
3552
|
+
* The environment cannot switch any of this off. It used to be skippable with
|
|
3553
|
+
* `CLOAK_SKIP_CIRCUIT_INTEGRITY_CHECK=1`, and that escape hatch was the worst hole in the package:
|
|
3554
|
+
* the variable resolves in the CONSUMER's process, so one deploy variable — or one
|
|
3555
|
+
* `--define:process.env.CLOAK_SKIP_CIRCUIT_INTEGRITY_CHECK='"1"'` in a consumer's bundler, which
|
|
3556
|
+
* compiles the guard down to a constant `true` — made this function accept whatever bytes the base
|
|
3557
|
+
* served. Paired with a repointable base that meant attacker wasm, and attacker wasm sees the spend
|
|
3558
|
+
* key. A check an environment variable disables is not a check. If a local build genuinely needs
|
|
3559
|
+
* different artifacts it needs different DIGESTS, which is a source edit and a rebuild, exactly
|
|
3560
|
+
* like the endpoint pin.
|
|
3792
3561
|
*/
|
|
3793
|
-
declare function loadVerifiedCircuitArtifacts(circuitsPath: string | null
|
|
3562
|
+
declare function loadVerifiedCircuitArtifacts(circuitsPath: string | null): Promise<VerifiedCircuitArtifacts>;
|
|
3794
3563
|
/**
|
|
3795
3564
|
* Report whether a circuit's artifacts match the digests pinned in this SDK.
|
|
3796
3565
|
*
|
|
@@ -3800,35 +3569,38 @@ declare function loadVerifiedCircuitArtifacts(circuitsPath: string | null, circu
|
|
|
3800
3569
|
* Proof paths must call {@link loadVerifiedCircuitArtifacts} and hand the bytes
|
|
3801
3570
|
* it returns to snarkjs.
|
|
3802
3571
|
*
|
|
3572
|
+
* Reports digests, never bytes. It can read the canonical memo to avoid a second download, but the
|
|
3573
|
+
* result object carries only hex strings, so calling this cannot obtain a handle on the bytes a
|
|
3574
|
+
* later proof will run over — which is the other half of the F7 fix, and the reason this function
|
|
3575
|
+
* and `loadVerifiedCircuitArtifacts` can no longer disagree about the same cache entry.
|
|
3576
|
+
*
|
|
3803
3577
|
* IMPORTANT: If the hashes don't match, the circuit may produce proofs
|
|
3804
3578
|
* that will be rejected by the on-chain verifier!
|
|
3805
3579
|
*
|
|
3806
|
-
* @param circuitsPath -
|
|
3807
|
-
*
|
|
3580
|
+
* @param circuitsPath - Base directory or URL holding the circuit's artifacts;
|
|
3581
|
+
* honoured verbatim.
|
|
3808
3582
|
* @param circuit - Which circuit to verify
|
|
3809
3583
|
* @returns Verification result
|
|
3810
3584
|
*
|
|
3811
3585
|
* @example
|
|
3812
3586
|
* ```typescript
|
|
3813
|
-
* const result = await verifyCircuitIntegrity(
|
|
3587
|
+
* const result = await verifyCircuitIntegrity(getCircuitsPath(), 'transaction');
|
|
3814
3588
|
* if (!result.valid) {
|
|
3815
3589
|
* console.error('Circuit verification failed:', result.error);
|
|
3816
3590
|
* // Don't proceed with proof generation!
|
|
3817
3591
|
* }
|
|
3818
3592
|
* ```
|
|
3819
3593
|
*/
|
|
3820
|
-
declare function verifyCircuitIntegrity(circuitsPath: string | null,
|
|
3594
|
+
declare function verifyCircuitIntegrity(circuitsPath: string | null, prefetched?: {
|
|
3821
3595
|
wasm: Uint8Array;
|
|
3822
3596
|
zkey: Uint8Array;
|
|
3823
3597
|
}): Promise<CircuitVerificationResult>;
|
|
3824
3598
|
/**
|
|
3825
3599
|
* Assert the ceremony-frozen `transaction` circuit artifacts are the pinned ones.
|
|
3826
3600
|
*
|
|
3827
|
-
* Throws (fail-closed) when the digests do not match
|
|
3828
|
-
*
|
|
3829
|
-
*
|
|
3830
|
-
* on-chain verifying key rejects, so failing here is strictly better than
|
|
3831
|
-
* failing on-chain.
|
|
3601
|
+
* Throws (fail-closed) when the digests do not match. Proving against an
|
|
3602
|
+
* unpinned zkey silently produces proofs the on-chain verifying key rejects,
|
|
3603
|
+
* so failing here is strictly better than failing on-chain.
|
|
3832
3604
|
*
|
|
3833
3605
|
* @param circuitsPath - Base directory or URL holding `transaction_js/transaction.wasm`
|
|
3834
3606
|
* and `transaction_final.zkey`.
|
|
@@ -3839,18 +3611,21 @@ declare function assertTransactionCircuitIntegrity(circuitsPath: string | null,
|
|
|
3839
3611
|
zkey: Uint8Array;
|
|
3840
3612
|
}): Promise<void>;
|
|
3841
3613
|
/**
|
|
3842
|
-
* Verify
|
|
3614
|
+
* Verify every circuit this SDK pins — which is exactly one: the ceremony
|
|
3615
|
+
* `transaction` circuit.
|
|
3843
3616
|
*
|
|
3844
3617
|
* Call this at SDK initialization to ensure circuits are valid.
|
|
3845
3618
|
*
|
|
3846
|
-
* @param circuitsPath -
|
|
3847
|
-
* always uses their own pinned bundle.
|
|
3848
|
-
* @param transactionCircuitsPath - Base for the ceremony-frozen `transaction` circuit.
|
|
3619
|
+
* @param circuitsPath - Base for the ceremony-frozen `transaction` circuit.
|
|
3849
3620
|
* Pass `getCircuitsPath()` when the caller has reconfigured it;
|
|
3850
3621
|
* `null` reports the "no base configured" state rather than throwing.
|
|
3622
|
+
* @param transactionCircuitsPath - Same base; takes precedence when given. Kept so
|
|
3623
|
+
* two-argument callers from before the legacy withdraw
|
|
3624
|
+
* circuits were removed keep compiling, with unchanged
|
|
3625
|
+
* behaviour for the `transaction` entry.
|
|
3851
3626
|
* @returns Array of verification results (one per circuit)
|
|
3852
3627
|
*/
|
|
3853
|
-
declare function verifyAllCircuits(circuitsPath: string, transactionCircuitsPath?: string | null): Promise<CircuitVerificationResult[]>;
|
|
3628
|
+
declare function verifyAllCircuits(circuitsPath: string | null, transactionCircuitsPath?: string | null): Promise<CircuitVerificationResult[]>;
|
|
3854
3629
|
|
|
3855
3630
|
/**
|
|
3856
3631
|
* Pending Operations Manager
|
|
@@ -4000,7 +3775,7 @@ declare function cleanupStalePendingOperations(maxAgeMs?: number): {
|
|
|
4000
3775
|
*
|
|
4001
3776
|
* ── Crypto ────────────────────────────────────────────────────────────────────────────────────
|
|
4002
3777
|
* X25519 ECDH + XSalsa20-Poly1305, i.e. `nacl.box`, reusing the exact construction already in
|
|
4003
|
-
* `
|
|
3778
|
+
* `notes/keypair.ts` (`nacl.box.before` + `nacl.secretbox`). No new primitive is introduced here.
|
|
4004
3779
|
*/
|
|
4005
3780
|
|
|
4006
3781
|
/** Ephemeral X25519 public key, at offset 0. */
|
|
@@ -4126,7 +3901,7 @@ declare function parseDeliveryCarrierMemo(data: Uint8Array): ParsedDeliveryCarri
|
|
|
4126
3901
|
* transaction actually published. That equality is the authentication: it is not a heuristic, and a
|
|
4127
3902
|
* wrong `nk` cannot produce it. Zero extra bytes on chain, no new envelope, no relay change.
|
|
4128
3903
|
*
|
|
4129
|
-
* This is the same shape already blessed for swap timeout refunds in `
|
|
3904
|
+
* This is the same shape already blessed for swap timeout refunds in `notes/swap-refund.ts`
|
|
4130
3905
|
* (PRF(nk, nullifier0)), for the same reason: unrecoverable randomness becomes recoverable
|
|
4131
3906
|
* randomness without changing anything an observer can see.
|
|
4132
3907
|
*
|
|
@@ -4213,6 +3988,137 @@ interface MatchDepositNoteParams {
|
|
|
4213
3988
|
*/
|
|
4214
3989
|
declare function matchDepositNote(params: MatchDepositNoteParams): Promise<RecoveredDepositNote | null>;
|
|
4215
3990
|
|
|
3991
|
+
/**
|
|
3992
|
+
* Recoverable change notes (VK-01, change shape).
|
|
3993
|
+
*
|
|
3994
|
+
* ── The defect this closes ────────────────────────────────────────────────────────────────────
|
|
3995
|
+
* A partial withdrawal spends a note worth more than the withdrawal and puts the remainder back in
|
|
3996
|
+
* the pool as a change note. `partialWithdraw` built that note with plain `createUtxo`, whose
|
|
3997
|
+
* blinding comes from `randomFieldElement()` — a 252-bit CSPRNG draw written to exactly one place:
|
|
3998
|
+
* whatever the caller does with `TransactResult.outputUtxos`. A caller that drops it, or a throw
|
|
3999
|
+
* between the relay accepting the transaction and the caller persisting the result, destroys the
|
|
4000
|
+
* only copy. The inputs are spent, the change is on chain, and it can never be spent by anyone.
|
|
4001
|
+
*
|
|
4002
|
+
* This is not hypothetical. It stranded 19.939819 USDC on 2026-09-02 (commitment
|
|
4003
|
+
* `138d126b58521b5d14e5bc85ed4e38db3f1218ef4061ad86e07ad4784ee40b6c`, leaf 2290 of the USDC tree):
|
|
4004
|
+
* a payment-link claim ran `partialWithdraw`, the claim page never read `outputUtxos`, and the
|
|
4005
|
+
* blinding died with the page. Every other value needed to spend that note is still recoverable —
|
|
4006
|
+
* amount, owner key, mint, commitment, leaf index. Only the randomness is gone.
|
|
4007
|
+
*
|
|
4008
|
+
* The SDK already ships key-only recovery for DEPOSITS (`notes/deposit-note.ts`, PRF(nk, noteSalt)),
|
|
4009
|
+
* for RECEIVED transfers (`notes/delivery-note.ts`, CLKD1 envelope) and for SWAP REFUNDS
|
|
4010
|
+
* (`notes/swap-refund.ts`, PRF(nk, nullifier0)). Change was the one shape with no recovery path at
|
|
4011
|
+
* all, and it is the shape every withdrawal produces.
|
|
4012
|
+
*
|
|
4013
|
+
* ── Why derivation, and why nothing else was available ────────────────────────────────────────
|
|
4014
|
+
* The CLKD1 delivery envelope is the only rail in the protocol that publishes a blinding, and it
|
|
4015
|
+
* rejects this shape twice over: `buildRecipientDeliveryNotes` returns `undefined` when
|
|
4016
|
+
* `externalAmount !== 0` (a withdrawal) and again when the note's owner is the spender (change is
|
|
4017
|
+
* self-owned). Both gates are correct — a delivery envelope exists to reach someone else, and
|
|
4018
|
+
* change has no one to reach. So make the chain note the protocol already emits carry the recovery
|
|
4019
|
+
* instead, at zero additional bytes:
|
|
4020
|
+
*
|
|
4021
|
+
* seed = BLAKE3("cloak_change_note_v1" || nk || noteSalt(32B BE) || outputIndex(1B) || "blinding")
|
|
4022
|
+
* blinding = seed reduced into the field
|
|
4023
|
+
*
|
|
4024
|
+
* The output index is in the preimage because one transaction carries one salt but two output
|
|
4025
|
+
* slots, and a send-to-self puts a self-owned note in BOTH. Without the index those two notes would
|
|
4026
|
+
* derive one blinding, and `transact`'s fail-closed check could not tell which slot it was looking
|
|
4027
|
+
* at. With it, every slot has its own answer.
|
|
4028
|
+
*
|
|
4029
|
+
* ── Why only the blinding, when deposits derive the keypair too ───────────────────────────────
|
|
4030
|
+
* A deposit's output note has no prior owner, so `deposit-note.ts` is free to give it a per-deposit
|
|
4031
|
+
* key and gains unlinkability by doing so. A change note is different: its owner is already fixed —
|
|
4032
|
+
* it is the keypair of the note being spent (`inputUtxos[0].keypair`), which the spender by
|
|
4033
|
+
* definition holds, and which callers rely on to keep spending their own change. Re-owning it under
|
|
4034
|
+
* a derived key would change `outPubkey0`, break that expectation, and buy nothing, because the
|
|
4035
|
+
* spender's key is the one value in a change note that was never at risk. Only the randomness was.
|
|
4036
|
+
*
|
|
4037
|
+
* ── What a cold scan can rebuild, and what it cannot ──────────────────────────────────────────
|
|
4038
|
+
* For the shape that lost the money — a partial withdrawal — recovery is COMPLETE from `nk` alone.
|
|
4039
|
+
* `partialWithdraw` emits the change as `outputUtxos[0]`, and a v4 chain note binds
|
|
4040
|
+
* `noteSemantics = Poseidon(outAmount0, outPubkey0, isSendToSelfKey0)` and carries all three in its
|
|
4041
|
+
* (encrypted, authenticated) plaintext. So a scanner holding `nk` decrypts the note, reads
|
|
4042
|
+
* `noteSalt`, `outAmount0` and `outPubkey0`, replays the line above, recomputes
|
|
4043
|
+
* `Poseidon(amount, pubkey, blinding, mint)` and requires it to equal a commitment the transaction
|
|
4044
|
+
* actually published. That equality is the authentication, exactly as in `matchDepositNote`.
|
|
4045
|
+
*
|
|
4046
|
+
* For `transfer`, change is `outputUtxos[1]` — the recipient note has to be output 0 because the
|
|
4047
|
+
* delivery carrier is bound to `output_commitments[0]`. A v4 chain note describes output 0 only, so
|
|
4048
|
+
* a cold scan does not learn the change AMOUNT and cannot finish the match on its own. The blinding
|
|
4049
|
+
* is still derived and still recoverable, which turns "permanently unspendable" into "spendable as
|
|
4050
|
+
* soon as the amount is known" — and a sender who knows what they sent knows the amount. Closing
|
|
4051
|
+
* that last gap needs the chain note to describe output 1 as well, which is a format change and is
|
|
4052
|
+
* deliberately not attempted here.
|
|
4053
|
+
*
|
|
4054
|
+
* ── Guardrails preserved ──────────────────────────────────────────────────────────────────────
|
|
4055
|
+
* [M-04] `noteSalt` stays a private input to `chainNoteHash`; it is only ever published inside the
|
|
4056
|
+
* note's own authenticated ciphertext, so nothing an observer can see changes. [H-04-shaped] the
|
|
4057
|
+
* reduction forces non-zero, because a zero blinding is an unspendable note. Callers that pass no
|
|
4058
|
+
* `nk` keep the previous random-blinding behaviour unchanged, so this is additive.
|
|
4059
|
+
*/
|
|
4060
|
+
|
|
4061
|
+
/** A change note recovered from `nk` (plus the owner key the spender already holds). */
|
|
4062
|
+
interface RecoveredChangeNote {
|
|
4063
|
+
keypair: UtxoKeypair;
|
|
4064
|
+
blinding: bigint;
|
|
4065
|
+
amount: bigint;
|
|
4066
|
+
mintAddress: PublicKey;
|
|
4067
|
+
/** The commitment the transaction published, reproduced from the derived blinding. */
|
|
4068
|
+
commitment: bigint;
|
|
4069
|
+
/** The salt the chain note carried, which anchored the derivation. */
|
|
4070
|
+
noteSalt: bigint;
|
|
4071
|
+
}
|
|
4072
|
+
/** A fresh 96-bit chain-note salt, from the same fail-closed source `transact` uses. */
|
|
4073
|
+
declare function randomChangeNoteSalt(): bigint;
|
|
4074
|
+
/**
|
|
4075
|
+
* Derive a change note's blinding from `(nk, noteSalt)`.
|
|
4076
|
+
*
|
|
4077
|
+
* Deterministic by design: this is the whole reason a cold scan can rebuild the note. Both the
|
|
4078
|
+
* builder and the scanner call it, so there is exactly one definition of what a change note is.
|
|
4079
|
+
*/
|
|
4080
|
+
declare function deriveChangeNoteBlinding(viewingKeyNk: Uint8Array, noteSalt: bigint, outputIndex: number): bigint;
|
|
4081
|
+
/**
|
|
4082
|
+
* Build a change output note whose blinding a cold `(rpc, programId, nk)` scan can re-derive.
|
|
4083
|
+
*
|
|
4084
|
+
* Returns the UTXO AND the salt that anchored it. The SAME salt must reach `transact` as
|
|
4085
|
+
* `options.chainNoteSalt`, because the chain note is what publishes it — a salt that does not reach
|
|
4086
|
+
* the note leaves the change exactly as unrecoverable as before. `partialWithdraw` and `transfer`
|
|
4087
|
+
* do this for you; the pairing is only your concern if you call `transact` directly.
|
|
4088
|
+
*/
|
|
4089
|
+
declare function createRecoverableChangeUtxo(amount: bigint, keypair: UtxoKeypair, viewingKeyNk: Uint8Array, mintAddress?: PublicKey, noteSalt?: bigint, outputIndex?: number): Promise<{
|
|
4090
|
+
utxo: Utxo;
|
|
4091
|
+
noteSalt: bigint;
|
|
4092
|
+
}>;
|
|
4093
|
+
interface MatchChangeNoteParams {
|
|
4094
|
+
/** The spending wallet's incoming viewing base. */
|
|
4095
|
+
viewingKeyNk: Uint8Array;
|
|
4096
|
+
/** `noteSalt`, read out of the decrypted chain note. */
|
|
4097
|
+
noteSalt: bigint;
|
|
4098
|
+
/** Candidate note amount — `outAmount0` for a partial withdrawal's change. */
|
|
4099
|
+
amount: bigint;
|
|
4100
|
+
/**
|
|
4101
|
+
* The change note's owner keypair. For a match, only `publicKey` is used (`outPubkey0` from the
|
|
4102
|
+
* chain note is enough); supply the private key too if you intend to spend the result.
|
|
4103
|
+
*/
|
|
4104
|
+
keypair: UtxoKeypair;
|
|
4105
|
+
/** Pool mint the commitment was computed under. */
|
|
4106
|
+
mintAddress: PublicKey;
|
|
4107
|
+
/** Which output slot the note occupied — part of the derivation, so it must match. */
|
|
4108
|
+
outputIndex: number;
|
|
4109
|
+
/** Output commitments the transaction actually published, hex or field elements. */
|
|
4110
|
+
outputCommitments: Array<string | bigint>;
|
|
4111
|
+
}
|
|
4112
|
+
/**
|
|
4113
|
+
* Decide whether a published commitment is a change note this `nk` can rebuild, and if so return it
|
|
4114
|
+
* in spendable form. Returns `null` for everything that is not ours.
|
|
4115
|
+
*
|
|
4116
|
+
* The commitment equality is the authentication. Nothing here trusts the chain note's own claim
|
|
4117
|
+
* about what it describes; the note supplies `noteSalt`, `amount` and the owner key, and the derived
|
|
4118
|
+
* blinding has to reproduce a value the transaction published or the candidate is discarded.
|
|
4119
|
+
*/
|
|
4120
|
+
declare function matchChangeNote(params: MatchChangeNoteParams): Promise<RecoveredChangeNote | null>;
|
|
4121
|
+
|
|
4216
4122
|
/**
|
|
4217
4123
|
* Swap timeout-refund discovery (VK-02).
|
|
4218
4124
|
*
|
|
@@ -4464,6 +4370,25 @@ interface ScanResult {
|
|
|
4464
4370
|
* Additive, for the same reason as `deliveredNotes`: note secrets are not compliance rows.
|
|
4465
4371
|
*/
|
|
4466
4372
|
recoveredDepositNotes: RecoveredDepositNoteRecord[];
|
|
4373
|
+
/**
|
|
4374
|
+
* This wallet's OWN withdrawal/swap change, rebuilt from `nk` alone (VK-01, change shape).
|
|
4375
|
+
*
|
|
4376
|
+
* `partialWithdraw` and `swapWithChange` emit change as output 0, and a v4 chain note carries
|
|
4377
|
+
* `outAmount0`/`outPubkey0`, so `nk` plus the derived blinding is everything the note needs.
|
|
4378
|
+
*
|
|
4379
|
+
* One difference from `recoveredDepositNotes`: a change note's owner key is NOT derived — it is
|
|
4380
|
+
* the keypair of the note that was spent, deliberately, so that holding a viewing key never
|
|
4381
|
+
* confers spend authority. So `keypair.privateKey` comes back as `0n` and the caller must supply
|
|
4382
|
+
* their own before spending. Everything else is complete.
|
|
4383
|
+
*/
|
|
4384
|
+
recoveredChangeNotes: RecoveredChangeNoteRecord[];
|
|
4385
|
+
}
|
|
4386
|
+
/** A recovered change note plus the chain coordinates it was recovered from. */
|
|
4387
|
+
interface RecoveredChangeNoteRecord extends RecoveredChangeNote {
|
|
4388
|
+
/** Signature of the withdrawal/swap transaction. */
|
|
4389
|
+
signature: string;
|
|
4390
|
+
/** Millisecond timestamp from the chain note. */
|
|
4391
|
+
timestamp: bigint;
|
|
4467
4392
|
}
|
|
4468
4393
|
/** A recovered deposit note plus the chain coordinates it was recovered from. */
|
|
4469
4394
|
interface RecoveredDepositNoteRecord extends RecoveredDepositNote {
|
|
@@ -4749,8 +4674,8 @@ declare class SimpleWallet {
|
|
|
4749
4674
|
* @packageDocumentation
|
|
4750
4675
|
*/
|
|
4751
4676
|
|
|
4752
|
-
declare const VERSION = "0.2.
|
|
4677
|
+
declare const VERSION = "0.2.1";
|
|
4753
4678
|
/** True when scanner supports TransactSwap (tag 1). Check this to verify the correct SDK bundle is loaded. */
|
|
4754
4679
|
declare const SCANNER_SUPPORTS_TRANSACT_SWAP = true;
|
|
4755
4680
|
|
|
4756
|
-
export { type BuildRecipientDeliveryNotesParams, CHAIN_NOTE_SALT_BITS, CLOAK_PROGRAM_ID, type ChainNoteTxType, type
|
|
4681
|
+
export { BUILD_ALLOWS_LOCAL_ENDPOINTS, type BuildRecipientDeliveryNotesParams, CHAIN_NOTE_SALT_BITS, CLOAK_PRODUCTION_RELAY_URL, CLOAK_PROGRAM_ID, type ChainNoteTxType, type CircuitVerificationResult, type CloakConfig, CloakError, type CloakKeyPair, type CloakNote, type CommitmentEntry, type CommitmentsResponse, type CompactChainNote, type ComplianceReport, type ComplianceTxType, type ConfirmSettlementParams, DEFAULT_CIRCUITS_URL, DEFAULT_TRANSACTION_CIRCUITS_URL, DELIVERY_MEMO_TAG, DELIVERY_REGISTRY_SEED, type DeliveredNote, type DepositInstructionParams, type DepositNoteSecrets, type DepositOptions, type DepositResult, type DepositStatus, type DiscoverSwapRefundsOptions, type DiscoveredSwapRefund, EXPECTED_CIRCUIT_HASHES, type EncryptedMetadataBundle, type EncryptedNote$1 as EncryptedNote, type ErrorCategory, type ExpandedSpendKey, type ExternalFeePayerAdapter, FIXED_FEE_LAMPORTS, type Groth16Proof, InsecureRandomnessError, LAMPORTS_PER_SOL, LocalStorageAdapter, type LogLevel, type Logger, MERKLE_TREE_HEIGHT, MIN_DEPOSIT_LAMPORTS, type MasterKey, type MatchChangeNoteParams, type MatchDepositNoteParams, type MatchSwapRefundLeafParams, type MaxLengthArray, MemoryStorageAdapter, type MerkleProof, type MerkleRootResponse, MerkleTree, NATIVE_SOL_MINT, type Network, type NoteData, type OnchainMerkleProof, type ParsedDeliveryCarrier, type PendingDeposit, type PendingWithdrawal, RECIPIENT_DELIVERY_CIPHERTEXT_LEN, RECIPIENT_DELIVERY_EPHEMERAL_PK_LEN, RECIPIENT_DELIVERY_NONCE_LEN, RECIPIENT_DELIVERY_NOTE_BYTES, RECIPIENT_DELIVERY_PLAINTEXT_LEN, RECIPIENT_DELIVERY_TAG_LEN, RELAY_ORIGIN_ALLOWLIST, REQUEST_AUTH_MAX_AGE_SECONDS, REQUEST_AUTH_MAX_FUTURE_SKEW_SECONDS, type RecipientDeliveryNote, type RecoveredChangeNote, type RecoveredChangeNoteRecord, type RecoveredDepositNote, type RecoveredDepositNoteRecord, type RecoveredSwapRefund, type RelayAuthPreimage, type RelayAuthSigner, RelayInternalError, RelayService, type RelaySubmissionResult, type RiskQuoteInstructionResponse, RootNotFoundError, SCANNER_SUPPORTS_TRANSACT_SWAP, SIGN_IN_MESSAGE, SanctionsQuoteError, type ScanOptions, type ScanRecipientDeliveryOptions, type ScanResult, type ScanSummary, type ScannedTransaction, type SettlementConnection, type SettlementContext, type SettlementStatus, type SettlementVerdict, SettlementVerificationError, ShieldPoolErrors, type ShieldPoolPDAs, SimpleWallet, type SpendKey, type StorageAdapter, type SubmitTransactToRelayArgs, type SwapOptions, type SwapParams, type SwapRefundAuthorization, type SwapResult, TRANSACTION_CIRCUITS_VERSION, TRANSACT_AUTH_FIELDS, TRANSACT_SWAP_AUTH_FIELDS, type TransactOptions, type TransactParams, type TransactRequestBodyParams, 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 WithdrawSubmissionResult, assertDirectSubmissionLanded, assertTransactionCircuitIntegrity, bigintToBytes32$1 as bigintToBytes32, bigintToHex, buildMerkleTree, buildMerkleTreeFromChain, buildMerkleTreeFromRelay, buildRecipientDeliveryNotes, buildRelayAuthPreimage, buildTransactRequestBody, bytesToHex, calculateFee, calculateFeeBigint, calculateRelayFee, canRebuildMerkleTreeFromChain, canonicalJson, chainNoteFromBase64, chainNoteToBase64, classifyRelayError, cleanupStalePendingOperations, clearPendingDeposits, clearPendingWithdrawals, computeChainNoteHash, computeExtDataHash, computeMerkleRoot, computeProofForLatestDeposit, computeProofFromChain, computeSignature, computeSwapRefundCommitment, computeCommitment as computeUtxoCommitment, computeNullifier as computeUtxoNullifier, confirmTransactSettlement, copyNoteToClipboard, createCloakError, createDepositInstruction, createLogger, createRecoverableChangeUtxo, createRecoverableDepositUtxo, createUtxo, createZeroUtxo, decryptCompactChainNote, decryptComplianceMetadataWithMasterKey, decryptTransactionMetadata, deriveChangeNoteBlinding, deriveDepositNoteSecrets, deriveDiversifiedViewingKey, deriveDiversifier, deriveInputNullifierPdas, derivePublicKey, deriveSpendKey, deriveSwapRefundAuthorization, deriveUserCompliancePublicKey, deriveUserComplianceScalar, deriveUtxoKeypairFromSpendKey, deriveViewKey, deriveViewingKeyFromNk, deriveViewingKeyFromSpendKey, deriveViewingKeyFromUtxoPrivateKey, deserializeUtxo, detectNetworkFromRpcUrl, discoverSwapRefunds, downloadNote, encodeDeliveryCarrierMemo, encodeNoteSimple, encodeRecipientDeliveryNote, encryptCompactChainNote, encryptNoteForRecipient, encryptTransactionMetadata, encryptTransactionMetadataBundle, expandSpendKey, explainRelayAuthRejection, exportKeys, exportNote, exportWalletKeys, fetchCommitments, fetchRiskQuoteInstruction, fetchRiskQuoteIx, filterNotesByNetwork, filterWithdrawableNotes, findNoteByCommitment, formatAmount, formatComplianceCsv, formatErrorForLogging, formatSol, fullWithdraw, generateCloakKeys, generateCommitmentAsync, generateMasterSeed, generateNoteFromWallet, generateUtxoKeypair, generateViewingKeyPair, getAddressExplorerUrl, getChainNoteRegistryPDA, getCircuitsPath, getDeliveryRegistryPDA, getDistributableAmount, getExplorerUrl, getNkFromUtxoPrivateKey, getNullifierPDA, getPendingOperationsSummary, getPoolAuthorityConfigPDA, getPublicKey, getPublicViewKey, getRecipientAmount, getRpcUrlForNetwork, getShieldPoolPDAs, getSwapStatePDA, getViewKey, hasPendingOperations, hexToBigint$1 as hexToBigint, hexToBytes, importKeys, importWalletKeys, isBrowser, isBrowserLike, isDebugEnabled, isPlausibleSignature, isReactNative, isRootNotFoundError, isSubmissionOutcomeUnknownResponse, isValidHex, isValidRpcUrl, isValidSolanaAddress, isWithdrawAmountSufficient, isWithdrawable, keypairToAdapter, loadPendingDeposits, loadPendingWithdrawals, loadVerifiedCircuitArtifacts, matchChangeNote, matchDepositNote, matchSwapRefundLeaf, openRecipientDeliveryNote, parseAmount, parseDeliveryCarrierMemo, parseError, parseNote, parseRelayErrorResponse, parseRelayErrorSignature, parseTransactionError, partialWithdraw, poseidonHash, preflightCheck, preflightNullifiers, prepareEncryptedOutput, prepareEncryptedOutputForRecipient, proofToBytes, pubkeyToFieldElement, pubkeyToLimbs, randomBytes, randomChangeNoteSalt, randomDepositNoteSalt, randomFieldElement, readMerkleTreeState, recipientDeliveryNoteToBase64, registerViewingKey, removePendingDeposit, removePendingWithdrawal, resolveCircuitsBase, savePendingDeposit, savePendingWithdrawal, scanNotesForWallet, scanRecipientDeliveryNotes, scanTransactions, sdkLogger, selectUtxos, sendTransaction, serializeNote, serializeUtxo, setCircuitsPath, setDebugMode, signTransaction, splitTo2Limbs, submitTransactToRelay, 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 };
|