@velumdotcash/sdk 2.0.0

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.
Files changed (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +142 -0
  3. package/dist/__tests__/paylink.test.d.ts +9 -0
  4. package/dist/__tests__/paylink.test.js +254 -0
  5. package/dist/config.d.ts +9 -0
  6. package/dist/config.js +12 -0
  7. package/dist/deposit.d.ts +22 -0
  8. package/dist/deposit.js +445 -0
  9. package/dist/depositSPL.d.ts +24 -0
  10. package/dist/depositSPL.js +499 -0
  11. package/dist/errors.d.ts +78 -0
  12. package/dist/errors.js +127 -0
  13. package/dist/exportUtils.d.ts +10 -0
  14. package/dist/exportUtils.js +10 -0
  15. package/dist/getUtxos.d.ts +30 -0
  16. package/dist/getUtxos.js +335 -0
  17. package/dist/getUtxosSPL.d.ts +34 -0
  18. package/dist/getUtxosSPL.js +442 -0
  19. package/dist/index.d.ts +183 -0
  20. package/dist/index.js +436 -0
  21. package/dist/models/keypair.d.ts +26 -0
  22. package/dist/models/keypair.js +43 -0
  23. package/dist/models/utxo.d.ts +51 -0
  24. package/dist/models/utxo.js +99 -0
  25. package/dist/test_paylink_logic.test.d.ts +1 -0
  26. package/dist/test_paylink_logic.test.js +114 -0
  27. package/dist/utils/address_lookup_table.d.ts +9 -0
  28. package/dist/utils/address_lookup_table.js +45 -0
  29. package/dist/utils/constants.d.ts +27 -0
  30. package/dist/utils/constants.js +56 -0
  31. package/dist/utils/debug-logger.d.ts +250 -0
  32. package/dist/utils/debug-logger.js +688 -0
  33. package/dist/utils/encryption.d.ts +152 -0
  34. package/dist/utils/encryption.js +700 -0
  35. package/dist/utils/logger.d.ts +9 -0
  36. package/dist/utils/logger.js +35 -0
  37. package/dist/utils/merkle_tree.d.ts +92 -0
  38. package/dist/utils/merkle_tree.js +186 -0
  39. package/dist/utils/node-shim.d.ts +14 -0
  40. package/dist/utils/node-shim.js +21 -0
  41. package/dist/utils/prover.d.ts +36 -0
  42. package/dist/utils/prover.js +169 -0
  43. package/dist/utils/utils.d.ts +64 -0
  44. package/dist/utils/utils.js +165 -0
  45. package/dist/withdraw.d.ts +22 -0
  46. package/dist/withdraw.js +290 -0
  47. package/dist/withdrawSPL.d.ts +24 -0
  48. package/dist/withdrawSPL.js +329 -0
  49. package/package.json +59 -0
@@ -0,0 +1,114 @@
1
+ import { describe, it, expect, beforeAll } from 'vitest';
2
+ import { Keypair } from '@solana/web3.js';
3
+ import { EncryptionService } from './utils/encryption.js';
4
+ import { WasmFactory } from '@lightprotocol/hasher.rs';
5
+ import { LocalStorage } from 'node-localstorage';
6
+ import { Utxo } from './models/utxo.js';
7
+ import { Keypair as UtxoKeypair } from './models/keypair.js';
8
+ // Mock storage
9
+ const storage = new LocalStorage('./test-storage');
10
+ describe('Paylink Logic (Third-Party Deposit)', () => {
11
+ let connection;
12
+ let senderKeypair;
13
+ let receiverKeypair;
14
+ let encryptionServiceSender;
15
+ let encryptionServiceReceiver;
16
+ let lightWasm;
17
+ beforeAll(async () => {
18
+ // Use a local validator or devnet. For unit testing logic we might mock connection,
19
+ // but here we want to test the flow.
20
+ // If no local validator, we might fail network calls.
21
+ // Let's assume we are testing the *logic* of key derivation and encryption first,
22
+ // and mocking the actual transaction submission if possible, or just checking the function arguments.
23
+ // Actually, we can't easily mock the whole deposit flow without a real RPC.
24
+ // But we can test the critical parts:
25
+ // 1. Recipient Key Derivation
26
+ // 2. Encryption (Asymmetric)
27
+ // 3. Decryption (by Recipient)
28
+ lightWasm = await WasmFactory.getInstance();
29
+ senderKeypair = Keypair.generate();
30
+ receiverKeypair = Keypair.generate();
31
+ encryptionServiceSender = new EncryptionService();
32
+ encryptionServiceSender.deriveEncryptionKeyFromWallet(senderKeypair);
33
+ encryptionServiceReceiver = new EncryptionService();
34
+ encryptionServiceReceiver.deriveEncryptionKeyFromWallet(receiverKeypair);
35
+ });
36
+ it('should correctly derive keys for the recipient', () => {
37
+ // 1. Get Recipient's UTXO Public Key (Poseidon Hash of Private Key)
38
+ const recipientUtxoPrivateKey = encryptionServiceReceiver.getUtxoPrivateKeyV2();
39
+ // We need to simulate how the frontend would get this.
40
+ // The frontend would have access to the recipient's wallet signature to derive this.
41
+ // This is the key the recipient publishes
42
+ const recipientUtxoPubkey = encryptionServiceReceiver.getUtxoPrivateKeyV2();
43
+ // WAIT: getUtxoPrivateKeyV2 returns the PRIVATE key.
44
+ // We need the PUBLIC key corresponding to this.
45
+ // Let's check how UtxoKeypair works.
46
+ // It takes the privkey and derives the pubkey.
47
+ // We need to instantiate it to get the pubkey.
48
+ const recipientUtxoKeypair = new UtxoKeypair(recipientUtxoPrivateKey, lightWasm);
49
+ const recipientPublicUtxoKey = recipientUtxoKeypair.pubkey;
50
+ console.log('Recipient UTXO Public Key:', recipientPublicUtxoKey.toString());
51
+ expect(recipientPublicUtxoKey).toBeDefined();
52
+ // 2. Get Recipient's Encryption Public Key (X25519)
53
+ const recipientAsymmetricPubKey = encryptionServiceReceiver.getAsymmetricPublicKey();
54
+ console.log('Recipient Asymmetric Public Key:', Buffer.from(recipientAsymmetricPubKey).toString('hex'));
55
+ expect(recipientAsymmetricPubKey).toBeDefined();
56
+ expect(recipientAsymmetricPubKey.length).toBe(32);
57
+ });
58
+ it('should encrypt a message sender -> recipient using UTXO format', async () => {
59
+ // Create a proper UTXO for encryption (not raw string)
60
+ const recipientAsymmetricPubKey = encryptionServiceReceiver.getAsymmetricPublicKey();
61
+ const recipientUtxoPrivateKey = encryptionServiceReceiver.getUtxoPrivateKeyV2();
62
+ const recipientUtxoKeypair = new UtxoKeypair(recipientUtxoPrivateKey, lightWasm);
63
+ const recipientPublicUtxoKey = recipientUtxoKeypair.pubkey;
64
+ // Create a test UTXO
65
+ const testUtxo = new Utxo({
66
+ lightWasm,
67
+ amount: '5000',
68
+ publicKey: recipientPublicUtxoKey,
69
+ index: 5
70
+ });
71
+ // Sender encrypts for Recipient using V3 (asymmetric)
72
+ const encrypted = encryptionServiceSender.encryptUtxo(testUtxo, recipientAsymmetricPubKey);
73
+ // Verify it's V3 format
74
+ expect(encryptionServiceSender.getEncryptionKeyVersion(encrypted)).toBe('v3');
75
+ // Recipient decrypts
76
+ const decrypted = await encryptionServiceReceiver.decryptUtxo(encrypted, lightWasm);
77
+ expect(decrypted).not.toBeNull();
78
+ expect(decrypted.amount.toString()).toBe('5000');
79
+ });
80
+ it('should encrypt and decrypt a UTXO for a third party', async () => {
81
+ // Recipient Setup
82
+ const recipientUtxoPrivateKey = encryptionServiceReceiver.getUtxoPrivateKeyV2();
83
+ const recipientUtxoKeypair = new UtxoKeypair(recipientUtxoPrivateKey, lightWasm);
84
+ const recipientPublicUtxoKey = recipientUtxoKeypair.pubkey;
85
+ const recipientAsymmetricPubKey = encryptionServiceReceiver.getAsymmetricPublicKey();
86
+ // Sender creates a UTXO destined for Recipient
87
+ // Sender DOES NOT have recipientUtxoPrivateKey.
88
+ // Sender only has recipientPublicUtxoKey.
89
+ const utxoForRecipient = new Utxo({
90
+ lightWasm,
91
+ amount: '1000',
92
+ publicKey: recipientPublicUtxoKey, // Using the new functionality we added
93
+ index: 10
94
+ });
95
+ // Verify Utxo was created correctly
96
+ expect(utxoForRecipient.pubkey.toString()).toBe(recipientPublicUtxoKey.toString());
97
+ expect(utxoForRecipient.keypair).toBeUndefined(); // Should not have private key
98
+ // Sender Encrypts UTXO for Recipient
99
+ const encryptedUtxo = encryptionServiceSender.encryptUtxo(utxoForRecipient, recipientAsymmetricPubKey);
100
+ // Verify it's V3
101
+ expect(encryptionServiceReceiver.getEncryptionKeyVersion(encryptedUtxo)).toBe('v3');
102
+ // Recipient Decrypts
103
+ const decryptedUtxo = await encryptionServiceReceiver.decryptUtxo(encryptedUtxo, lightWasm);
104
+ // Verification - decryptUtxo can return null for schema version mismatch, but should succeed here
105
+ expect(decryptedUtxo).not.toBeNull();
106
+ expect(decryptedUtxo.amount.toString()).toBe('1000');
107
+ expect(decryptedUtxo.index).toBe(10);
108
+ // Important: Decrypted UTXO should have the private key derived from the receiver's service!
109
+ // The `decryptUtxo` function uses `this.getUtxoPrivateKeyWithVersion('v2')` internally.
110
+ expect(decryptedUtxo.keypair).toBeDefined();
111
+ expect(decryptedUtxo.keypair.pubkey.toString()).toBe(recipientPublicUtxoKey.toString());
112
+ console.log("Third-party UTXO encryption/decryption cycle successful!");
113
+ });
114
+ });
@@ -0,0 +1,9 @@
1
+ import { Connection, PublicKey } from '@solana/web3.js';
2
+ /**
3
+ * Helper function to use an existing ALT (recommended for production)
4
+ * Use create_alt.ts to create the ALT once, then hardcode the address and use this function
5
+ */
6
+ export declare function useExistingALT(connection: Connection, altAddress: PublicKey): Promise<{
7
+ value: any;
8
+ } | null>;
9
+ export declare function getProtocolAddressesWithMint(programId: PublicKey, authority: PublicKey, treeAta: PublicKey, feeRecipient: PublicKey, feeRecipientAta: PublicKey): PublicKey[];
@@ -0,0 +1,45 @@
1
+ import { PublicKey, SystemProgram, ComputeBudgetProgram } from '@solana/web3.js';
2
+ import { ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID } from '@solana/spl-token';
3
+ import { logger } from './logger.js';
4
+ /**
5
+ * Helper function to use an existing ALT (recommended for production)
6
+ * Use create_alt.ts to create the ALT once, then hardcode the address and use this function
7
+ */
8
+ export async function useExistingALT(connection, altAddress) {
9
+ try {
10
+ logger.debug(`Using existing ALT: ${altAddress.toString()}`);
11
+ const altAccount = await connection.getAddressLookupTable(altAddress);
12
+ if (altAccount.value) {
13
+ logger.debug(`✅ ALT found with ${altAccount.value.state.addresses.length} addresses`);
14
+ }
15
+ else {
16
+ logger.error('❌ ALT not found');
17
+ }
18
+ return altAccount;
19
+ }
20
+ catch (error) {
21
+ console.error('Error getting existing ALT:', error);
22
+ return null;
23
+ }
24
+ }
25
+ export function getProtocolAddressesWithMint(programId, authority, treeAta, feeRecipient, feeRecipientAta) {
26
+ // Derive global config PDA
27
+ const [globalConfigAccount] = PublicKey.findProgramAddressSync([Buffer.from('global_config')], programId);
28
+ // Derive tree accounts
29
+ const [treeAccount] = PublicKey.findProgramAddressSync([Buffer.from('merkle_tree')], programId);
30
+ return [
31
+ // Core program accounts (constant)
32
+ programId,
33
+ treeAccount,
34
+ treeAta,
35
+ globalConfigAccount,
36
+ authority,
37
+ feeRecipient,
38
+ feeRecipientAta,
39
+ // System programs (constant)
40
+ SystemProgram.programId,
41
+ ComputeBudgetProgram.programId,
42
+ ASSOCIATED_TOKEN_PROGRAM_ID,
43
+ TOKEN_PROGRAM_ID,
44
+ ];
45
+ }
@@ -0,0 +1,27 @@
1
+ import { PublicKey } from '@solana/web3.js';
2
+ import BN from 'bn.js';
3
+ export declare const FIELD_SIZE: BN;
4
+ export declare const PROGRAM_ID: PublicKey;
5
+ export declare const FEE_RECIPIENT: PublicKey;
6
+ export declare const FETCH_UTXOS_GROUP_SIZE = 20000;
7
+ export declare const TRANSACT_IX_DISCRIMINATOR: Buffer<ArrayBuffer>;
8
+ export declare const TRANSACT_SPL_IX_DISCRIMINATOR: Buffer<ArrayBuffer>;
9
+ export declare const MERKLE_TREE_DEPTH = 26;
10
+ export declare const ALT_ADDRESS: PublicKey;
11
+ export declare const RELAYER_API_URL: string;
12
+ export declare const SIGN_MESSAGE = "Privacy Money account sign in";
13
+ export declare const LSK_FETCH_OFFSET = "fetch_offset";
14
+ export declare const LSK_ENCRYPTED_OUTPUTS = "encrypted_outputs";
15
+ export declare const USDC_MINT: PublicKey;
16
+ declare const tokenList: readonly ["sol", "usdc", "usdt", "zec", "ore", "store"];
17
+ export type TokenList = typeof tokenList[number];
18
+ declare const splList: readonly ["usdc", "usdt", "zec", "ore", "store"];
19
+ export type SplList = typeof splList[number];
20
+ export type Token = {
21
+ name: TokenList;
22
+ prefix: string;
23
+ units_per_token: number;
24
+ pubkey: PublicKey;
25
+ };
26
+ export declare const tokens: Token[];
27
+ export {};
@@ -0,0 +1,56 @@
1
+ import { PublicKey } from '@solana/web3.js';
2
+ import BN from 'bn.js';
3
+ export const FIELD_SIZE = new BN('21888242871839275222246405745257275088548364400416034343698204186575808495617');
4
+ export const PROGRAM_ID = process.env.NEXT_PUBLIC_PROGRAM_ID ? new PublicKey(process.env.NEXT_PUBLIC_PROGRAM_ID) : new PublicKey('9fhQBbumKEFuXtMBDw8AaQyAjCorLGJQiS3skWZdQyQD');
5
+ export const FEE_RECIPIENT = new PublicKey('AWexibGxNFKTa1b5R5MN4PJr9HWnWRwf8EW9g8cLx3dM');
6
+ export const FETCH_UTXOS_GROUP_SIZE = 20_000;
7
+ export const TRANSACT_IX_DISCRIMINATOR = Buffer.from([217, 149, 130, 143, 221, 52, 252, 119]);
8
+ export const TRANSACT_SPL_IX_DISCRIMINATOR = Buffer.from([154, 66, 244, 204, 78, 225, 163, 151]);
9
+ export const MERKLE_TREE_DEPTH = 26;
10
+ export const ALT_ADDRESS = process.env.NEXT_PUBLIC_ALT_ADDRESS ? new PublicKey(process.env.NEXT_PUBLIC_ALT_ADDRESS) : new PublicKey('HEN49U2ySJ85Vc78qprSW9y6mFDhs1NczRxyppNHjofe');
11
+ export const RELAYER_API_URL = process.env.NEXT_PUBLIC_RELAYER_API_URL ?? 'https://api3.privacycash.org';
12
+ export const SIGN_MESSAGE = `Privacy Money account sign in`;
13
+ // localStorage cache keys
14
+ export const LSK_FETCH_OFFSET = 'fetch_offset';
15
+ export const LSK_ENCRYPTED_OUTPUTS = 'encrypted_outputs';
16
+ export const USDC_MINT = process.env.NEXT_PUBLIC_USDC_MINT ? new PublicKey(process.env.NEXT_PUBLIC_USDC_MINT) : new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v');
17
+ const tokenList = ['sol', 'usdc', 'usdt', 'zec', 'ore', 'store'];
18
+ const splList = ['usdc', 'usdt', 'zec', 'ore', 'store'];
19
+ export const tokens = [
20
+ {
21
+ name: 'sol',
22
+ pubkey: new PublicKey('So11111111111111111111111111111111111111112'),
23
+ prefix: '',
24
+ units_per_token: 1e9
25
+ },
26
+ {
27
+ name: 'usdc',
28
+ pubkey: process.env.NEXT_PUBLIC_USDC_MINT ? new PublicKey(process.env.NEXT_PUBLIC_USDC_MINT) : new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'),
29
+ prefix: 'usdc_',
30
+ units_per_token: 1e6
31
+ },
32
+ {
33
+ name: 'usdt',
34
+ pubkey: process.env.NEXT_PUBLIC_USDT_MINT ? new PublicKey(process.env.NEXT_PUBLIC_USDT_MINT) : new PublicKey('Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB'),
35
+ prefix: 'usdt_',
36
+ units_per_token: 1e6
37
+ },
38
+ {
39
+ name: 'zec',
40
+ pubkey: process.env.NEXT_PUBLIC_ZEC_MINT ? new PublicKey(process.env.NEXT_PUBLIC_ZEC_MINT) : new PublicKey('A7bdiYdS5GjqGFtxf17ppRHtDKPkkRqbKtR27dxvQXaS'),
41
+ prefix: 'zec_',
42
+ units_per_token: 1e8
43
+ },
44
+ {
45
+ name: 'ore',
46
+ pubkey: process.env.NEXT_PUBLIC_ORE_MINT ? new PublicKey(process.env.NEXT_PUBLIC_ORE_MINT) : new PublicKey('oreoU2P8bN6jkk3jbaiVxYnG1dCXcYxwhwyK9jSybcp'),
47
+ prefix: 'ore_',
48
+ units_per_token: 1e11
49
+ },
50
+ {
51
+ name: 'store',
52
+ pubkey: process.env.NEXT_PUBLIC_STORE_MINT ? new PublicKey(process.env.NEXT_PUBLIC_STORE_MINT) : new PublicKey('sTorERYB6xAZ1SSbwpK3zoK2EEwbBrc7TZAzg1uCGiH'),
53
+ prefix: 'store_',
54
+ units_per_token: 1e11
55
+ },
56
+ ];
@@ -0,0 +1,250 @@
1
+ /**
2
+ * Debug logging utility for privacy-cash SDK
3
+ *
4
+ * Provides detailed diagnostic logging for V3 asymmetric encryption decryption
5
+ * to help identify failure points without exposing sensitive key material.
6
+ */
7
+ export type DebugLogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error';
8
+ /**
9
+ * Error categories for decryption failures
10
+ */
11
+ export type DecryptionErrorCategory = 'key_mismatch' | 'malformed_data' | 'version_error' | 'missing_key' | 'unknown';
12
+ /**
13
+ * Detailed decryption failure record
14
+ */
15
+ export interface DecryptionFailureRecord {
16
+ category: DecryptionErrorCategory;
17
+ errorMessage: string;
18
+ stackTrace?: string;
19
+ encryptedDataHash: string;
20
+ encryptedDataLength: number;
21
+ attemptedVersions?: string[];
22
+ timestamp: string;
23
+ }
24
+ /**
25
+ * Summary of decryption failures for a balance fetch operation
26
+ */
27
+ export interface DecryptionFailureSummary {
28
+ totalAttempted: number;
29
+ totalDecrypted: number;
30
+ totalFailed: number;
31
+ totalSkipped: number;
32
+ totalSchemaMismatch: number;
33
+ failuresByCategory: Record<DecryptionErrorCategory, number>;
34
+ failures: DecryptionFailureRecord[];
35
+ }
36
+ export interface DebugLogEntry {
37
+ timestamp: string;
38
+ level: DebugLogLevel;
39
+ category: string;
40
+ message: string;
41
+ data?: Record<string, unknown>;
42
+ }
43
+ export type DebugLoggerFn = (entry: DebugLogEntry) => void;
44
+ /**
45
+ * Enable debug logging programmatically
46
+ * @param customLogger Optional custom logger function
47
+ * @param verbose Enable verbose/trace mode for individual UTXO logs (default: false)
48
+ */
49
+ export declare function enableDebugLogging(customLogger?: DebugLoggerFn, verbose?: boolean): void;
50
+ /**
51
+ * Enable verbose mode for individual UTXO logs
52
+ */
53
+ export declare function enableVerboseLogging(): void;
54
+ /**
55
+ * Disable verbose mode
56
+ */
57
+ export declare function disableVerboseLogging(): void;
58
+ /**
59
+ * Check if verbose logging is enabled
60
+ */
61
+ export declare function isVerboseEnabled(): boolean;
62
+ /**
63
+ * Disable debug logging
64
+ */
65
+ export declare function disableDebugLogging(): void;
66
+ /**
67
+ * Install debug commands on the window object for production debugging
68
+ * Call this from browser console: window.privacyCashDebug.enable()
69
+ */
70
+ export declare function installDebugCommands(): void;
71
+ /**
72
+ * Check if debug logging is enabled
73
+ *
74
+ * Debug logging is enabled if any of the following conditions are met:
75
+ * 1. Explicitly enabled via enableDebugLogging()
76
+ * 2. PRIVACY_CASH_DEBUG environment variable is set to 'true' or '1'
77
+ * 3. window.PRIVACY_CASH_DEBUG is set to true, 'true', or '1'
78
+ * 4. Running in development mode (NODE_ENV=development or localhost)
79
+ * 5. URL contains ?privacy_cash_debug=true or ?privacy_cash_debug=1 (production feature)
80
+ */
81
+ export declare function isDebugEnabled(): boolean;
82
+ /**
83
+ * Set a custom debug logger function
84
+ */
85
+ export declare function setDebugLogger(fn: DebugLoggerFn): void;
86
+ /**
87
+ * Hash sensitive data for safe logging (first 8 chars of hex)
88
+ */
89
+ export declare function hashForLog(data: Uint8Array | string | null | undefined): string;
90
+ /**
91
+ * Format bytes length for logging
92
+ */
93
+ export declare function bytesInfo(data: Uint8Array | Buffer | string | null | undefined): string;
94
+ /**
95
+ * Debug logger for encryption-related operations
96
+ */
97
+ export declare const debugLogger: {
98
+ /**
99
+ * Log the first 8 bytes (version prefix) of encrypted data
100
+ */
101
+ versionPrefixBytes(prefixHex: string, dataLength: number): void;
102
+ /**
103
+ * Log encryption version detection
104
+ */
105
+ versionDetected(encryptedDataHash: string, version: "v1" | "v2" | "v3", dataLength: number): void;
106
+ /**
107
+ * Log when version detection falls back to legacy V1 mode
108
+ */
109
+ versionFallbackToLegacy(prefixHex: string, reason: string): void;
110
+ /**
111
+ * Log key derivation steps (with hashed keys for privacy)
112
+ */
113
+ keyDerivation(step: string, keyHash: string, keyType: string): void;
114
+ /**
115
+ * Log asymmetric key pair generation
116
+ */
117
+ asymmetricKeyGenerated(publicKeyHash: string, secretKeyHash: string): void;
118
+ /**
119
+ * Log decryption attempt start
120
+ */
121
+ decryptionAttemptStart(version: string, encryptedDataHash: string, dataLength: number): void;
122
+ /**
123
+ * Log schema version mismatch for early termination
124
+ * Individual UTXO logs are verbose-only; tracking is always updated
125
+ * @param foundVersion The schema version byte found in the encrypted data
126
+ * @param expectedVersion The expected schema version byte
127
+ * @param encryptedDataHash Hash of the encrypted data for identification
128
+ */
129
+ schemaVersionMismatch(foundVersion: number, expectedVersion: number, encryptedDataHash: string): void;
130
+ /**
131
+ * Log recipient ID hash mismatch (O(1) early termination)
132
+ * This is the fastest way to skip UTXOs that don't belong to this wallet
133
+ */
134
+ recipientIdMismatch(encryptedDataHash: string): void;
135
+ /**
136
+ * Log decryption success
137
+ */
138
+ decryptionSuccess(version: string, decryptedLength: number): void;
139
+ /**
140
+ * Log decryption failure with detailed error info
141
+ */
142
+ decryptionFailure(version: string, errorType: string, errorMessage: string, context?: Record<string, unknown>): void;
143
+ /**
144
+ * Log V3 asymmetric decryption details
145
+ */
146
+ v3DecryptionDetails(ephemeralPubKeyHash: string, nonceHash: string, boxLength: number, recipientSecretKeyHash: string): void;
147
+ /**
148
+ * Log UTXO metadata after successful decryption
149
+ */
150
+ utxoDecrypted(commitmentHash: string, tokenMint: string, encryptedLength: number, utxoIndex: number | string, version: string): void;
151
+ /**
152
+ * Log UTXO decryption batch summary
153
+ */
154
+ utxoBatchSummary(total: number, decrypted: number, skipped: number, failed: number): void;
155
+ /**
156
+ * Log encryption service initialization
157
+ */
158
+ serviceInitialized(hasV1Key: boolean, hasV2Key: boolean, hasAsymmetricKey: boolean): void;
159
+ /**
160
+ * Log when attempting decryption without required key
161
+ */
162
+ missingKey(keyType: string, operation: string): void;
163
+ /**
164
+ * Generic debug log
165
+ */
166
+ debug(category: string, message: string, data?: Record<string, unknown>): void;
167
+ /**
168
+ * Generic info log
169
+ */
170
+ info(category: string, message: string, data?: Record<string, unknown>): void;
171
+ /**
172
+ * Generic warning log
173
+ */
174
+ warn(category: string, message: string, data?: Record<string, unknown>): void;
175
+ /**
176
+ * Generic error log
177
+ */
178
+ error(category: string, message: string, data?: Record<string, unknown>): void;
179
+ /**
180
+ * Log X25519 public key derivation for sender-side verification
181
+ * @param publicKeyHash Hash of the derived X25519 public key
182
+ * @param walletAddress The wallet address used for key derivation
183
+ * @param context Whether this is sender or recipient side
184
+ */
185
+ x25519KeyDerived(publicKeyHash: string, walletAddress: string, context: "sender" | "recipient"): void;
186
+ /**
187
+ * Log X25519 public key used during encryption (sender side)
188
+ * @param recipientPublicKeyHash Hash of the recipient's X25519 public key being encrypted to
189
+ * @param walletAddress Sender's wallet address
190
+ */
191
+ x25519EncryptionKey(recipientPublicKeyHash: string, walletAddress?: string): void;
192
+ /**
193
+ * Log X25519 public key used during decryption (recipient side)
194
+ * @param derivedPublicKeyHash Hash of the recipient's derived X25519 public key
195
+ * @param walletAddress Recipient's wallet address
196
+ */
197
+ x25519DecryptionKey(derivedPublicKeyHash: string, walletAddress?: string): void;
198
+ /**
199
+ * Log key mismatch comparison when decryption fails
200
+ * @param expectedKeyHash Hash of the expected public key (from encrypted data)
201
+ * @param derivedKeyHash Hash of the derived public key (from wallet signature)
202
+ * @param walletAddress The wallet address used for derivation
203
+ */
204
+ x25519KeyMismatch(expectedKeyHash: string, derivedKeyHash: string, walletAddress?: string): void;
205
+ /**
206
+ * Log wallet address association with key derivation
207
+ * @param walletAddress The wallet address being used
208
+ * @param operation The operation being performed (encryption/decryption)
209
+ */
210
+ walletKeyDerivation(walletAddress: string, operation: "encrypt" | "decrypt" | "derive"): void;
211
+ /**
212
+ * Initialize failure tracking for a new balance fetch operation
213
+ */
214
+ startFailureTracking(): void;
215
+ /**
216
+ * Categorize an error based on its message and type
217
+ */
218
+ categorizeError(error: Error | unknown): DecryptionErrorCategory;
219
+ /**
220
+ * Record a decryption failure with full context
221
+ * Individual failure logs are only shown in verbose mode to avoid console spam
222
+ */
223
+ recordDecryptionFailure(error: Error | unknown, encryptedDataHex: string, attemptedVersions?: string[]): void;
224
+ /**
225
+ * Record a schema version mismatch (early termination)
226
+ * These are tracked separately since they're expected behavior for UTXOs not belonging to the user
227
+ */
228
+ recordSchemaMismatch(): void;
229
+ /**
230
+ * Record a successful decryption
231
+ */
232
+ recordDecryptionSuccess(): void;
233
+ /**
234
+ * Record a skipped UTXO (empty/null encrypted data)
235
+ */
236
+ recordDecryptionSkipped(): void;
237
+ /**
238
+ * Increment the total attempted counter
239
+ */
240
+ recordDecryptionAttempt(): void;
241
+ /**
242
+ * Get the current failure summary and log it
243
+ * Logs a single summary line per balance fetch (not per-UTXO)
244
+ */
245
+ endFailureTracking(): DecryptionFailureSummary | null;
246
+ /**
247
+ * Get the current failure summary without ending tracking
248
+ */
249
+ getCurrentFailureSummary(): DecryptionFailureSummary | null;
250
+ };