@sip-protocol/sdk 0.7.2 → 0.7.4

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 (262) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +267 -0
  3. package/dist/{TransportWebUSB-TQ7WZ4LE.mjs → TransportWebUSB-YQMAGJAJ.mjs} +12 -9
  4. package/dist/browser.d.mts +10 -4
  5. package/dist/browser.d.ts +10 -4
  6. package/dist/browser.js +48874 -18336
  7. package/dist/browser.mjs +674 -48
  8. package/dist/chunk-4GRJ5MAW.mjs +152 -0
  9. package/dist/chunk-5D7A3L3W.mjs +717 -0
  10. package/dist/chunk-64AYA5F5.mjs +7834 -0
  11. package/dist/chunk-GMDGB22A.mjs +379 -0
  12. package/dist/chunk-I534WKN7.mjs +328 -0
  13. package/dist/chunk-IBZVA5Y7.mjs +1003 -0
  14. package/dist/chunk-PRRZAWJE.mjs +223 -0
  15. package/dist/{chunk-UJCSKKID.mjs → chunk-XGB3TDIC.mjs} +13 -1
  16. package/dist/chunk-YWGJ77A2.mjs +33806 -0
  17. package/dist/{chunk-6WGN57S2.mjs → chunk-Z3K7W5S3.mjs} +48 -0
  18. package/dist/constants-LHAAUC2T.mjs +51 -0
  19. package/dist/dist-2OGQ7FED.mjs +3957 -0
  20. package/dist/dist-IFHPYLDX.mjs +254 -0
  21. package/dist/fulfillment_proof-ANHVPKTB.mjs +21 -0
  22. package/dist/funding_proof-ICFZ5LHY.mjs +21 -0
  23. package/dist/index-DXh2IGkz.d.ts +24681 -0
  24. package/dist/index-DeE1ZzA4.d.mts +24681 -0
  25. package/dist/index.d.mts +9 -3
  26. package/dist/index.d.ts +9 -3
  27. package/dist/index.js +48676 -17318
  28. package/dist/index.mjs +583 -19
  29. package/dist/interface-Bf7w1PLW.d.mts +679 -0
  30. package/dist/interface-Bf7w1PLW.d.ts +679 -0
  31. package/dist/{noir-DKfEzWy9.d.mts → noir-kzbLVTei.d.mts} +31 -21
  32. package/dist/{noir-DKfEzWy9.d.ts → noir-kzbLVTei.d.ts} +31 -21
  33. package/dist/proofs/halo2.d.mts +151 -0
  34. package/dist/proofs/halo2.d.ts +151 -0
  35. package/dist/proofs/halo2.js +350 -0
  36. package/dist/proofs/halo2.mjs +11 -0
  37. package/dist/proofs/kimchi.d.mts +160 -0
  38. package/dist/proofs/kimchi.d.ts +160 -0
  39. package/dist/proofs/kimchi.js +431 -0
  40. package/dist/proofs/kimchi.mjs +13 -0
  41. package/dist/proofs/noir.d.mts +1 -1
  42. package/dist/proofs/noir.d.ts +1 -1
  43. package/dist/proofs/noir.js +74 -18
  44. package/dist/proofs/noir.mjs +84 -24
  45. package/dist/solana-U3MEGU7W.mjs +280 -0
  46. package/dist/validity_proof-3POXLPNY.mjs +21 -0
  47. package/package.json +54 -21
  48. package/src/adapters/index.ts +41 -0
  49. package/src/adapters/jupiter.ts +571 -0
  50. package/src/adapters/near-intents.ts +135 -0
  51. package/src/advisor/advisor.ts +653 -0
  52. package/src/advisor/index.ts +54 -0
  53. package/src/advisor/tools.ts +303 -0
  54. package/src/advisor/types.ts +164 -0
  55. package/src/chains/ethereum/announcement.ts +536 -0
  56. package/src/chains/ethereum/bnb-optimizations.ts +474 -0
  57. package/src/chains/ethereum/commitment.ts +522 -0
  58. package/src/chains/ethereum/constants.ts +462 -0
  59. package/src/chains/ethereum/deployment.ts +596 -0
  60. package/src/chains/ethereum/gas-estimation.ts +538 -0
  61. package/src/chains/ethereum/index.ts +268 -0
  62. package/src/chains/ethereum/optimizations.ts +614 -0
  63. package/src/chains/ethereum/privacy-adapter.ts +855 -0
  64. package/src/chains/ethereum/registry.ts +584 -0
  65. package/src/chains/ethereum/rpc.ts +905 -0
  66. package/src/chains/ethereum/stealth.ts +491 -0
  67. package/src/chains/ethereum/token.ts +790 -0
  68. package/src/chains/ethereum/transfer.ts +637 -0
  69. package/src/chains/ethereum/types.ts +456 -0
  70. package/src/chains/ethereum/viewing-key.ts +455 -0
  71. package/src/chains/near/commitment.ts +608 -0
  72. package/src/chains/near/constants.ts +284 -0
  73. package/src/chains/near/function-call.ts +871 -0
  74. package/src/chains/near/history.ts +654 -0
  75. package/src/chains/near/implicit-account.ts +840 -0
  76. package/src/chains/near/index.ts +393 -0
  77. package/src/chains/near/native-transfer.ts +658 -0
  78. package/src/chains/near/nep141.ts +775 -0
  79. package/src/chains/near/privacy-adapter.ts +889 -0
  80. package/src/chains/near/resolver.ts +971 -0
  81. package/src/chains/near/rpc.ts +1016 -0
  82. package/src/chains/near/stealth.ts +419 -0
  83. package/src/chains/near/types.ts +317 -0
  84. package/src/chains/near/viewing-key.ts +876 -0
  85. package/src/chains/solana/anchor-transfer.ts +386 -0
  86. package/src/chains/solana/commitment.ts +577 -0
  87. package/src/chains/solana/constants.ts +126 -12
  88. package/src/chains/solana/ephemeral-keys.ts +543 -0
  89. package/src/chains/solana/index.ts +276 -1
  90. package/src/chains/solana/key-derivation.ts +418 -0
  91. package/src/chains/solana/kit-compat.ts +334 -0
  92. package/src/chains/solana/optimizations.ts +560 -0
  93. package/src/chains/solana/privacy-adapter.ts +605 -0
  94. package/src/chains/solana/providers/generic.ts +201 -0
  95. package/src/chains/solana/providers/helius-enhanced-types.ts +336 -0
  96. package/src/chains/solana/providers/helius-enhanced.ts +623 -0
  97. package/src/chains/solana/providers/helius.ts +402 -0
  98. package/src/chains/solana/providers/index.ts +85 -0
  99. package/src/chains/solana/providers/interface.ts +221 -0
  100. package/src/chains/solana/providers/quicknode.ts +409 -0
  101. package/src/chains/solana/providers/triton.ts +426 -0
  102. package/src/chains/solana/providers/webhook.ts +790 -0
  103. package/src/chains/solana/rpc-client.ts +1150 -0
  104. package/src/chains/solana/scan.ts +170 -73
  105. package/src/chains/solana/sol-transfer.ts +732 -0
  106. package/src/chains/solana/spl-transfer.ts +886 -0
  107. package/src/chains/solana/stealth-scanner.ts +703 -0
  108. package/src/chains/solana/sunspot-verifier.ts +453 -0
  109. package/src/chains/solana/transaction-builder.ts +755 -0
  110. package/src/chains/solana/transfer.ts +74 -5
  111. package/src/chains/solana/types.ts +77 -7
  112. package/src/chains/solana/utils.ts +110 -0
  113. package/src/chains/solana/viewing-key.ts +807 -0
  114. package/src/compliance/fireblocks.ts +921 -0
  115. package/src/compliance/index.ts +37 -0
  116. package/src/compliance/range-sas.ts +956 -0
  117. package/src/config/endpoints.ts +100 -0
  118. package/src/crypto.ts +11 -8
  119. package/src/errors.ts +82 -0
  120. package/src/evm/erc4337-relayer.ts +830 -0
  121. package/src/evm/index.ts +47 -0
  122. package/src/fees/calculator.ts +396 -0
  123. package/src/fees/index.ts +87 -0
  124. package/src/fees/near-contract.ts +429 -0
  125. package/src/fees/types.ts +268 -0
  126. package/src/index.ts +785 -1
  127. package/src/intent.ts +6 -3
  128. package/src/logger.ts +324 -0
  129. package/src/network/index.ts +80 -0
  130. package/src/network/proxy.ts +691 -0
  131. package/src/optimizations/index.ts +541 -0
  132. package/src/oracle/types.ts +1 -0
  133. package/src/privacy-backends/arcium-types.ts +727 -0
  134. package/src/privacy-backends/arcium.ts +719 -0
  135. package/src/privacy-backends/combined-privacy.ts +866 -0
  136. package/src/privacy-backends/cspl-token.ts +595 -0
  137. package/src/privacy-backends/cspl-types.ts +512 -0
  138. package/src/privacy-backends/cspl.ts +907 -0
  139. package/src/privacy-backends/health.ts +488 -0
  140. package/src/privacy-backends/inco-types.ts +323 -0
  141. package/src/privacy-backends/inco.ts +616 -0
  142. package/src/privacy-backends/index.ts +336 -0
  143. package/src/privacy-backends/interface.ts +906 -0
  144. package/src/privacy-backends/lru-cache.ts +343 -0
  145. package/src/privacy-backends/magicblock.ts +458 -0
  146. package/src/privacy-backends/mock.ts +258 -0
  147. package/src/privacy-backends/privacycash-types.ts +278 -0
  148. package/src/privacy-backends/privacycash.ts +456 -0
  149. package/src/privacy-backends/private-swap.ts +570 -0
  150. package/src/privacy-backends/rate-limiter.ts +683 -0
  151. package/src/privacy-backends/registry.ts +690 -0
  152. package/src/privacy-backends/router.ts +626 -0
  153. package/src/privacy-backends/shadowwire.ts +449 -0
  154. package/src/privacy-backends/sip-native.ts +256 -0
  155. package/src/privacy-logger.ts +191 -0
  156. package/src/production-safety.ts +373 -0
  157. package/src/proofs/aggregator.ts +1029 -0
  158. package/src/proofs/browser-composer.ts +1150 -0
  159. package/src/proofs/browser.ts +113 -25
  160. package/src/proofs/cache/index.ts +127 -0
  161. package/src/proofs/cache/interface.ts +545 -0
  162. package/src/proofs/cache/key-generator.ts +188 -0
  163. package/src/proofs/cache/lru-cache.ts +481 -0
  164. package/src/proofs/cache/multi-tier-cache.ts +575 -0
  165. package/src/proofs/cache/persistent-cache.ts +788 -0
  166. package/src/proofs/compliance-proof.ts +872 -0
  167. package/src/proofs/composer/base.ts +923 -0
  168. package/src/proofs/composer/index.ts +25 -0
  169. package/src/proofs/composer/interface.ts +518 -0
  170. package/src/proofs/composer/types.ts +383 -0
  171. package/src/proofs/converters/halo2.ts +452 -0
  172. package/src/proofs/converters/index.ts +208 -0
  173. package/src/proofs/converters/interface.ts +363 -0
  174. package/src/proofs/converters/kimchi.ts +462 -0
  175. package/src/proofs/converters/noir.ts +451 -0
  176. package/src/proofs/fallback.ts +888 -0
  177. package/src/proofs/halo2.ts +42 -0
  178. package/src/proofs/index.ts +471 -0
  179. package/src/proofs/interface.ts +13 -0
  180. package/src/proofs/kimchi.ts +42 -0
  181. package/src/proofs/lazy.ts +1004 -0
  182. package/src/proofs/mock.ts +25 -1
  183. package/src/proofs/noir.ts +111 -30
  184. package/src/proofs/orchestrator.ts +960 -0
  185. package/src/proofs/parallel/concurrency.ts +297 -0
  186. package/src/proofs/parallel/dependency-graph.ts +602 -0
  187. package/src/proofs/parallel/executor.ts +420 -0
  188. package/src/proofs/parallel/index.ts +131 -0
  189. package/src/proofs/parallel/interface.ts +685 -0
  190. package/src/proofs/parallel/worker-pool.ts +644 -0
  191. package/src/proofs/providers/halo2.ts +560 -0
  192. package/src/proofs/providers/index.ts +34 -0
  193. package/src/proofs/providers/kimchi.ts +641 -0
  194. package/src/proofs/validator.ts +881 -0
  195. package/src/proofs/verifier.ts +867 -0
  196. package/src/quantum/index.ts +112 -0
  197. package/src/quantum/winternitz-vault.ts +639 -0
  198. package/src/quantum/wots.ts +611 -0
  199. package/src/settlement/backends/direct-chain.ts +1 -0
  200. package/src/settlement/index.ts +9 -0
  201. package/src/settlement/router.ts +732 -46
  202. package/src/solana/index.ts +72 -0
  203. package/src/solana/jito-relayer.ts +687 -0
  204. package/src/solana/noir-verifier-types.ts +430 -0
  205. package/src/solana/noir-verifier.ts +816 -0
  206. package/src/stealth/address-derivation.ts +193 -0
  207. package/src/stealth/ed25519.ts +431 -0
  208. package/src/stealth/index.ts +233 -0
  209. package/src/stealth/meta-address.ts +221 -0
  210. package/src/stealth/secp256k1.ts +368 -0
  211. package/src/stealth/utils.ts +194 -0
  212. package/src/stealth.ts +50 -1504
  213. package/src/surveillance/algorithms/address-reuse.ts +143 -0
  214. package/src/surveillance/algorithms/cluster.ts +247 -0
  215. package/src/surveillance/algorithms/exchange.ts +295 -0
  216. package/src/surveillance/algorithms/temporal.ts +337 -0
  217. package/src/surveillance/analyzer.ts +442 -0
  218. package/src/surveillance/index.ts +64 -0
  219. package/src/surveillance/scoring.ts +372 -0
  220. package/src/surveillance/types.ts +264 -0
  221. package/src/sync/index.ts +106 -0
  222. package/src/sync/manager.ts +504 -0
  223. package/src/sync/mock-provider.ts +318 -0
  224. package/src/sync/oblivious.ts +625 -0
  225. package/src/tokens/index.ts +15 -0
  226. package/src/tokens/registry.ts +301 -0
  227. package/src/utils/deprecation.ts +94 -0
  228. package/src/utils/index.ts +9 -0
  229. package/src/wallet/ethereum/index.ts +68 -0
  230. package/src/wallet/ethereum/metamask-privacy.ts +420 -0
  231. package/src/wallet/ethereum/multi-wallet.ts +646 -0
  232. package/src/wallet/ethereum/privacy-adapter.ts +700 -0
  233. package/src/wallet/ethereum/types.ts +3 -1
  234. package/src/wallet/ethereum/walletconnect-adapter.ts +675 -0
  235. package/src/wallet/hardware/index.ts +10 -0
  236. package/src/wallet/hardware/ledger-privacy.ts +414 -0
  237. package/src/wallet/index.ts +71 -0
  238. package/src/wallet/near/adapter.ts +626 -0
  239. package/src/wallet/near/index.ts +86 -0
  240. package/src/wallet/near/meteor-wallet.ts +1153 -0
  241. package/src/wallet/near/my-near-wallet.ts +790 -0
  242. package/src/wallet/near/wallet-selector.ts +702 -0
  243. package/src/wallet/solana/adapter.ts +6 -4
  244. package/src/wallet/solana/index.ts +13 -0
  245. package/src/wallet/solana/privacy-adapter.ts +567 -0
  246. package/src/wallet/sui/types.ts +6 -4
  247. package/src/zcash/rpc-client.ts +13 -6
  248. package/dist/chunk-3INS3PR5.mjs +0 -884
  249. package/dist/chunk-3OVABDRH.mjs +0 -17096
  250. package/dist/chunk-DLDWZFYC.mjs +0 -1495
  251. package/dist/chunk-E6SZWREQ.mjs +0 -57
  252. package/dist/chunk-G33LB27A.mjs +0 -16166
  253. package/dist/chunk-HGU6HZRC.mjs +0 -231
  254. package/dist/chunk-L2K34JCU.mjs +0 -1496
  255. package/dist/chunk-SN4ZDTVW.mjs +0 -16166
  256. package/dist/constants-VOI7BSLK.mjs +0 -27
  257. package/dist/index-BYZbDjal.d.ts +0 -11390
  258. package/dist/index-CHB3KuOB.d.mts +0 -11859
  259. package/dist/index-CzWPI6Le.d.ts +0 -11859
  260. package/dist/index-xbWjohNq.d.mts +0 -11390
  261. package/dist/solana-5EMCTPTS.mjs +0 -46
  262. package/dist/solana-Q4NAVBTS.mjs +0 -46
@@ -0,0 +1,907 @@
1
+ /**
2
+ * C-SPL (Confidential SPL) Token Client
3
+ *
4
+ * Client for interacting with Confidential SPL tokens on Solana.
5
+ * Provides wrapping, unwrapping, transfers, and balance queries for C-SPL tokens.
6
+ *
7
+ * ## Features
8
+ *
9
+ * - Wrap any SPL token to its confidential version
10
+ * - Transfer C-SPL tokens with encrypted amounts
11
+ * - Query confidential balances
12
+ * - Encrypt/decrypt amounts for transfers
13
+ *
14
+ * ## Usage
15
+ *
16
+ * ```typescript
17
+ * import { CSPLClient, CSPL_TOKENS } from '@sip-protocol/sdk'
18
+ *
19
+ * const client = new CSPLClient({ rpcUrl: 'https://api.devnet.solana.com' })
20
+ *
21
+ * // Wrap 1 SOL to C-wSOL
22
+ * const wrapResult = await client.wrapToken({
23
+ * mint: CSPL_TOKENS['C-wSOL'].mint!,
24
+ * amount: 1_000_000_000n, // 1 SOL
25
+ * owner: walletAddress,
26
+ * })
27
+ *
28
+ * // Transfer confidentially
29
+ * const encryptedAmount = await client.encryptAmount({
30
+ * amount: 500_000_000n,
31
+ * recipientPubkey: recipientAddress,
32
+ * })
33
+ *
34
+ * await client.transfer({
35
+ * from: walletAddress,
36
+ * to: recipientAddress,
37
+ * token: wrapResult.token!,
38
+ * encryptedAmount: encryptedAmount.ciphertext,
39
+ * })
40
+ * ```
41
+ *
42
+ * @see https://docs.arcium.com
43
+ */
44
+
45
+ import type {
46
+ CSPLToken,
47
+ ConfidentialTokenAccount,
48
+ ConfidentialBalance,
49
+ ConfidentialTransferParams,
50
+ ConfidentialTransferResult,
51
+ WrapTokenParams,
52
+ WrapTokenResult,
53
+ UnwrapTokenParams,
54
+ UnwrapTokenResult,
55
+ CSPLEncryptionParams,
56
+ CSPLDecryptionParams,
57
+ EncryptedAmount,
58
+ CSPLEncryptionType,
59
+ ICSPLClient,
60
+ } from './cspl-types'
61
+
62
+ import {
63
+ CSPL_TOKENS,
64
+ CSPL_PROGRAM_IDS,
65
+ CSPL_OPERATION_COSTS,
66
+ CSPL_OPERATION_TIMES,
67
+ CSPL_MAX_MEMO_BYTES,
68
+ } from './cspl-types'
69
+
70
+ import { isValidSolanaAddressFormat } from '../validation'
71
+ import { deepFreeze } from './interface'
72
+ import {
73
+ LRUCache,
74
+ DEFAULT_CACHE_SIZES,
75
+ DEFAULT_CACHE_TTL,
76
+ type LRUCacheStats,
77
+ } from './lru-cache'
78
+
79
+ /**
80
+ * Cache configuration for CSPLClient
81
+ */
82
+ export interface CSPLCacheConfig {
83
+ /** Maximum entries in account cache (default: 1000) */
84
+ accountCacheSize?: number
85
+ /** Maximum entries in balance cache (default: 500) */
86
+ balanceCacheSize?: number
87
+ /** Account cache TTL in ms (default: 5 minutes) */
88
+ accountCacheTTL?: number
89
+ /** Balance cache TTL in ms (default: 30 seconds) */
90
+ balanceCacheTTL?: number
91
+ }
92
+
93
+ /**
94
+ * Configuration for CSPLClient
95
+ */
96
+ export interface CSPLClientConfig {
97
+ /** Solana RPC endpoint URL */
98
+ rpcUrl?: string
99
+ /** Default encryption type */
100
+ defaultEncryption?: CSPLEncryptionType
101
+ /** Enable compliance/audit features */
102
+ enableCompliance?: boolean
103
+ /** Request timeout in milliseconds */
104
+ timeout?: number
105
+ /** Cache configuration */
106
+ cache?: CSPLCacheConfig
107
+ }
108
+
109
+ /**
110
+ * C-SPL Token Client
111
+ *
112
+ * Handles all operations for Confidential SPL tokens.
113
+ */
114
+ /**
115
+ * Extended cache stats including LRU metrics
116
+ */
117
+ export interface CSPLCacheStats {
118
+ /** Account cache statistics */
119
+ accounts: LRUCacheStats
120
+ /** Balance cache statistics */
121
+ balances: LRUCacheStats
122
+ }
123
+
124
+ export class CSPLClient implements ICSPLClient {
125
+ private config: Required<Omit<CSPLClientConfig, 'cache'>>
126
+ private cacheConfig: Required<CSPLCacheConfig>
127
+ private connected: boolean = false
128
+ private accountCache: LRUCache<string, ConfidentialTokenAccount>
129
+ private balanceCache: LRUCache<string, ConfidentialBalance>
130
+
131
+ /**
132
+ * Create a new C-SPL client
133
+ *
134
+ * @param config - Client configuration
135
+ */
136
+ constructor(config: CSPLClientConfig = {}) {
137
+ this.config = {
138
+ rpcUrl: config.rpcUrl ?? 'https://api.devnet.solana.com',
139
+ defaultEncryption: config.defaultEncryption ?? 'twisted-elgamal',
140
+ enableCompliance: config.enableCompliance ?? false,
141
+ timeout: config.timeout ?? 30_000,
142
+ }
143
+
144
+ // Initialize cache configuration with defaults
145
+ this.cacheConfig = {
146
+ accountCacheSize: config.cache?.accountCacheSize ?? DEFAULT_CACHE_SIZES.TOKEN_ACCOUNTS,
147
+ balanceCacheSize: config.cache?.balanceCacheSize ?? DEFAULT_CACHE_SIZES.BALANCES,
148
+ accountCacheTTL: config.cache?.accountCacheTTL ?? DEFAULT_CACHE_TTL.TOKEN_ACCOUNTS,
149
+ balanceCacheTTL: config.cache?.balanceCacheTTL ?? DEFAULT_CACHE_TTL.BALANCES,
150
+ }
151
+
152
+ // Initialize LRU caches
153
+ this.accountCache = new LRUCache<string, ConfidentialTokenAccount>({
154
+ maxSize: this.cacheConfig.accountCacheSize,
155
+ ttl: this.cacheConfig.accountCacheTTL,
156
+ })
157
+
158
+ this.balanceCache = new LRUCache<string, ConfidentialBalance>({
159
+ maxSize: this.cacheConfig.balanceCacheSize,
160
+ ttl: this.cacheConfig.balanceCacheTTL,
161
+ })
162
+ }
163
+
164
+ /**
165
+ * Initialize connection to Solana
166
+ */
167
+ async connect(rpcUrl?: string): Promise<void> {
168
+ if (rpcUrl) {
169
+ this.config.rpcUrl = rpcUrl
170
+ }
171
+
172
+ // In production: Initialize Solana connection
173
+ // const connection = new Connection(this.config.rpcUrl)
174
+ // await connection.getVersion()
175
+
176
+ this.connected = true
177
+ }
178
+
179
+ /**
180
+ * Disconnect from Solana
181
+ */
182
+ async disconnect(): Promise<void> {
183
+ this.connected = false
184
+ this.accountCache.clear()
185
+ this.balanceCache.clear()
186
+ }
187
+
188
+ /**
189
+ * Check if client is connected
190
+ */
191
+ isConnected(): boolean {
192
+ return this.connected
193
+ }
194
+
195
+ /**
196
+ * Get or create a confidential token account
197
+ *
198
+ * Creates the account automatically if it doesn't exist.
199
+ *
200
+ * @param owner - Account owner address
201
+ * @param token - C-SPL token configuration
202
+ * @returns Confidential token account
203
+ */
204
+ async getOrCreateAccount(
205
+ owner: string,
206
+ token: CSPLToken
207
+ ): Promise<ConfidentialTokenAccount> {
208
+ // Validate owner address format
209
+ if (!owner || !isValidSolanaAddressFormat(owner)) {
210
+ throw new Error('Invalid owner address format. Expected base58-encoded Solana address (32-44 chars)')
211
+ }
212
+
213
+ // Check cache first
214
+ const cacheKey = `${owner}:${token.confidentialMint}`
215
+ const cached = this.accountCache.get(cacheKey)
216
+ if (cached) {
217
+ return cached
218
+ }
219
+
220
+ // Validate inputs
221
+ if (!owner || owner.trim() === '') {
222
+ throw new Error('Owner address is required')
223
+ }
224
+ if (!token.confidentialMint || token.confidentialMint.trim() === '') {
225
+ throw new Error('Token confidentialMint is required')
226
+ }
227
+
228
+ // In production: Query or create account via Solana
229
+ // const ata = getAssociatedTokenAddress(token.confidentialMint, owner)
230
+ // let accountInfo = await connection.getAccountInfo(ata)
231
+ // if (!accountInfo) {
232
+ // await createConfidentialTokenAccount(...)
233
+ // }
234
+
235
+ // Simulated account
236
+ const account: ConfidentialTokenAccount = {
237
+ address: this.deriveAccountAddress(owner, token),
238
+ owner,
239
+ token,
240
+ encryptedBalance: new Uint8Array(64), // Empty encrypted balance
241
+ pendingBalance: undefined,
242
+ pendingCount: 0,
243
+ isInitialized: true,
244
+ isFrozen: false,
245
+ }
246
+
247
+ this.accountCache.set(cacheKey, account)
248
+ return account
249
+ }
250
+
251
+ /**
252
+ * Get confidential balance for an account
253
+ *
254
+ * @param owner - Account owner address
255
+ * @param token - C-SPL token configuration
256
+ * @returns Confidential balance
257
+ */
258
+ async getBalance(owner: string, token: CSPLToken): Promise<ConfidentialBalance> {
259
+ // Validate owner address format
260
+ if (!owner || !isValidSolanaAddressFormat(owner)) {
261
+ throw new Error('Invalid owner address format. Expected base58-encoded Solana address (32-44 chars)')
262
+ }
263
+
264
+ // Check cache
265
+ const cacheKey = `balance:${owner}:${token.confidentialMint}`
266
+ const cached = this.balanceCache.get(cacheKey)
267
+ if (cached) {
268
+ return cached
269
+ }
270
+
271
+ // Get or create account
272
+ const account = await this.getOrCreateAccount(owner, token)
273
+
274
+ // In production: Query on-chain balance
275
+ // const accountData = await program.account.confidentialAccount.fetch(account.address)
276
+
277
+ const balance: ConfidentialBalance = {
278
+ token,
279
+ encryptedAmount: account.encryptedBalance,
280
+ pendingBalance: account.pendingBalance,
281
+ }
282
+
283
+ this.balanceCache.set(cacheKey, balance)
284
+ return balance
285
+ }
286
+
287
+ /**
288
+ * Wrap SPL tokens to C-SPL
289
+ *
290
+ * Converts regular SPL tokens to their confidential version.
291
+ *
292
+ * @param params - Wrap parameters
293
+ * @returns Wrap result
294
+ */
295
+ async wrapToken(params: WrapTokenParams): Promise<WrapTokenResult> {
296
+ // Validate inputs
297
+ if (!params.mint || params.mint.trim() === '') {
298
+ return {
299
+ success: false,
300
+ error: 'Token mint address is required',
301
+ }
302
+ }
303
+ if (!isValidSolanaAddressFormat(params.mint)) {
304
+ return {
305
+ success: false,
306
+ error: 'Invalid token mint address format. Expected base58-encoded Solana address (32-44 chars)',
307
+ }
308
+ }
309
+ if (!params.owner || params.owner.trim() === '') {
310
+ return {
311
+ success: false,
312
+ error: 'Owner address is required',
313
+ }
314
+ }
315
+ if (!isValidSolanaAddressFormat(params.owner)) {
316
+ return {
317
+ success: false,
318
+ error: 'Invalid owner address format. Expected base58-encoded Solana address (32-44 chars)',
319
+ }
320
+ }
321
+ if (params.amount <= BigInt(0)) {
322
+ return {
323
+ success: false,
324
+ error: 'Amount must be greater than 0',
325
+ }
326
+ }
327
+
328
+ try {
329
+ // Look up or create C-SPL token config
330
+ const token = this.getOrCreateTokenConfig(params.mint)
331
+
332
+ // Ensure confidential account exists
333
+ if (params.createAccount !== false) {
334
+ await this.getOrCreateAccount(params.owner, token)
335
+ }
336
+
337
+ // In production:
338
+ // 1. Transfer SPL tokens to wrap escrow
339
+ // 2. Encrypt the amount
340
+ // 3. Credit confidential account
341
+
342
+ const encryptedBalance = await this.encryptAmount({
343
+ amount: params.amount,
344
+ })
345
+
346
+ // Simulated result
347
+ const signature = this.generateSignature()
348
+
349
+ // Update cache
350
+ const cacheKey = `balance:${params.owner}:${token.confidentialMint}`
351
+ this.balanceCache.set(cacheKey, {
352
+ token,
353
+ encryptedAmount: encryptedBalance.ciphertext,
354
+ decryptedAmount: params.amount,
355
+ })
356
+
357
+ return {
358
+ success: true,
359
+ signature,
360
+ token,
361
+ encryptedBalance: encryptedBalance.ciphertext,
362
+ }
363
+ } catch (error) {
364
+ return {
365
+ success: false,
366
+ error: error instanceof Error ? error.message : 'Unknown error during wrap',
367
+ }
368
+ }
369
+ }
370
+
371
+ /**
372
+ * Unwrap C-SPL back to regular SPL tokens
373
+ *
374
+ * Converts confidential tokens back to their public version.
375
+ *
376
+ * @param params - Unwrap parameters
377
+ * @returns Unwrap result
378
+ */
379
+ async unwrapToken(params: UnwrapTokenParams): Promise<UnwrapTokenResult> {
380
+ // Validate inputs
381
+ if (!params.token || !params.token.confidentialMint) {
382
+ return {
383
+ success: false,
384
+ error: 'Token configuration is required',
385
+ }
386
+ }
387
+ if (!params.owner || params.owner.trim() === '') {
388
+ return {
389
+ success: false,
390
+ error: 'Owner address is required',
391
+ }
392
+ }
393
+ if (!isValidSolanaAddressFormat(params.owner)) {
394
+ return {
395
+ success: false,
396
+ error: 'Invalid owner address format. Expected base58-encoded Solana address (32-44 chars)',
397
+ }
398
+ }
399
+ if (!params.encryptedAmount || params.encryptedAmount.length === 0) {
400
+ return {
401
+ success: false,
402
+ error: 'Encrypted amount is required',
403
+ }
404
+ }
405
+
406
+ try {
407
+ // In production:
408
+ // 1. Verify ownership and balance
409
+ // 2. Generate range proof
410
+ // 3. Debit confidential account
411
+ // 4. Transfer SPL tokens from escrow
412
+
413
+ // Simulated decryption
414
+ const amount = await this.decryptAmount({
415
+ encryptedAmount: params.encryptedAmount,
416
+ decryptionKey: new Uint8Array(32), // Would be owner's key
417
+ })
418
+
419
+ const signature = this.generateSignature()
420
+
421
+ // Clear balance cache
422
+ const cacheKey = `balance:${params.owner}:${params.token.confidentialMint}`
423
+ this.balanceCache.delete(cacheKey)
424
+
425
+ return {
426
+ success: true,
427
+ signature,
428
+ amount,
429
+ }
430
+ } catch (error) {
431
+ return {
432
+ success: false,
433
+ error: error instanceof Error ? error.message : 'Unknown error during unwrap',
434
+ }
435
+ }
436
+ }
437
+
438
+ /**
439
+ * Execute a confidential transfer
440
+ *
441
+ * Transfers C-SPL tokens with encrypted amounts.
442
+ *
443
+ * @param params - Transfer parameters
444
+ * @returns Transfer result
445
+ */
446
+ async transfer(
447
+ params: ConfidentialTransferParams
448
+ ): Promise<ConfidentialTransferResult> {
449
+ // Validate inputs
450
+ if (!params.from || params.from.trim() === '') {
451
+ return {
452
+ success: false,
453
+ error: 'Sender address is required',
454
+ }
455
+ }
456
+ if (!isValidSolanaAddressFormat(params.from)) {
457
+ return {
458
+ success: false,
459
+ error: 'Invalid sender address format. Expected base58-encoded Solana address (32-44 chars)',
460
+ }
461
+ }
462
+ if (!params.to || params.to.trim() === '') {
463
+ return {
464
+ success: false,
465
+ error: 'Recipient address is required',
466
+ }
467
+ }
468
+ if (!isValidSolanaAddressFormat(params.to)) {
469
+ return {
470
+ success: false,
471
+ error: 'Invalid recipient address format. Expected base58-encoded Solana address (32-44 chars)',
472
+ }
473
+ }
474
+ if (!params.token || !params.token.confidentialMint) {
475
+ return {
476
+ success: false,
477
+ error: 'Token configuration is required',
478
+ }
479
+ }
480
+ if (!params.encryptedAmount || params.encryptedAmount.length === 0) {
481
+ return {
482
+ success: false,
483
+ error: 'Encrypted amount is required',
484
+ }
485
+ }
486
+
487
+ // Validate memo length (if provided)
488
+ if (params.memo !== undefined) {
489
+ const memoBytes = new TextEncoder().encode(params.memo)
490
+ if (memoBytes.length > CSPL_MAX_MEMO_BYTES) {
491
+ return {
492
+ success: false,
493
+ error: `Memo exceeds maximum length (${memoBytes.length} bytes > ${CSPL_MAX_MEMO_BYTES} bytes limit)`,
494
+ }
495
+ }
496
+ }
497
+
498
+ try {
499
+ // Ensure both accounts exist
500
+ await this.getOrCreateAccount(params.from, params.token)
501
+ await this.getOrCreateAccount(params.to, params.token)
502
+
503
+ // In production:
504
+ // 1. Generate equality and range proofs
505
+ // 2. Debit sender's confidential balance
506
+ // 3. Credit recipient's pending balance
507
+ // 4. Submit transaction
508
+
509
+ const signature = this.generateSignature()
510
+
511
+ // Simulate new sender balance (would be calculated from proofs)
512
+ const newSenderBalance = new Uint8Array(64)
513
+
514
+ // Clear cache for both parties
515
+ this.balanceCache.delete(`balance:${params.from}:${params.token.confidentialMint}`)
516
+ this.balanceCache.delete(`balance:${params.to}:${params.token.confidentialMint}`)
517
+
518
+ return {
519
+ success: true,
520
+ signature,
521
+ newSenderBalance,
522
+ recipientPendingUpdated: true,
523
+ }
524
+ } catch (error) {
525
+ return {
526
+ success: false,
527
+ error: error instanceof Error ? error.message : 'Unknown error during transfer',
528
+ }
529
+ }
530
+ }
531
+
532
+ /**
533
+ * Encrypt an amount for transfer
534
+ *
535
+ * Uses Twisted ElGamal or AES-GCM depending on configuration.
536
+ *
537
+ * @param params - Encryption parameters
538
+ * @returns Encrypted amount
539
+ */
540
+ async encryptAmount(params: CSPLEncryptionParams): Promise<EncryptedAmount> {
541
+ // Validate amount
542
+ if (params.amount < BigInt(0)) {
543
+ throw new Error('Amount cannot be negative')
544
+ }
545
+
546
+ // Validate recipient pubkey if provided
547
+ if (params.recipientPubkey !== undefined && params.recipientPubkey !== '') {
548
+ if (!isValidSolanaAddressFormat(params.recipientPubkey)) {
549
+ throw new Error(
550
+ `Invalid recipient pubkey format: '${params.recipientPubkey}'. ` +
551
+ 'Expected base58-encoded Solana address (32-44 chars)'
552
+ )
553
+ }
554
+ }
555
+
556
+ // Validate auditor keys if provided
557
+ if (params.auditorKeys?.length) {
558
+ for (let i = 0; i < params.auditorKeys.length; i++) {
559
+ const auditorKey = params.auditorKeys[i]
560
+ if (!auditorKey || auditorKey.trim() === '') {
561
+ throw new Error(`Auditor key at index ${i} is empty`)
562
+ }
563
+ if (!isValidSolanaAddressFormat(auditorKey)) {
564
+ throw new Error(
565
+ `Invalid auditor key format at index ${i}: '${auditorKey}'. ` +
566
+ 'Expected base58-encoded Solana address (32-44 chars)'
567
+ )
568
+ }
569
+ }
570
+ }
571
+
572
+ const encryptionType = this.config.defaultEncryption
573
+
574
+ // In production: Use actual cryptographic encryption
575
+ // For Twisted ElGamal (Solana Confidential Transfers):
576
+ // const ciphertext = twistedElgamal.encrypt(amount, recipientPubkey)
577
+
578
+ // Simulated encryption
579
+ const ciphertext = this.simulateEncryption(params.amount, encryptionType)
580
+ const nonce = this.generateNonce()
581
+
582
+ // Handle auditor ciphertexts if compliance enabled
583
+ let auditorCiphertexts: Map<string, Uint8Array> | undefined
584
+ if (this.config.enableCompliance && params.auditorKeys?.length) {
585
+ auditorCiphertexts = new Map()
586
+ for (const auditorKey of params.auditorKeys) {
587
+ const auditorCiphertext = this.simulateEncryption(params.amount, 'aes-gcm')
588
+ auditorCiphertexts.set(auditorKey, auditorCiphertext)
589
+ }
590
+ }
591
+
592
+ return {
593
+ ciphertext,
594
+ encryptionType,
595
+ nonce,
596
+ auditorCiphertexts,
597
+ }
598
+ }
599
+
600
+ /**
601
+ * Decrypt an encrypted amount
602
+ *
603
+ * Only the account owner can decrypt their balance.
604
+ *
605
+ * @param params - Decryption parameters
606
+ * @returns Decrypted amount
607
+ */
608
+ async decryptAmount(params: CSPLDecryptionParams): Promise<bigint> {
609
+ // Validate
610
+ if (!params.encryptedAmount || params.encryptedAmount.length === 0) {
611
+ throw new Error('Encrypted amount is required')
612
+ }
613
+ if (!params.decryptionKey || params.decryptionKey.length === 0) {
614
+ throw new Error('Decryption key is required')
615
+ }
616
+
617
+ // In production: Use actual cryptographic decryption
618
+ // const amount = twistedElgamal.decrypt(encryptedAmount, decryptionKey)
619
+
620
+ // Simulated decryption - return a deterministic value based on ciphertext
621
+ return this.simulateDecryption(params.encryptedAmount)
622
+ }
623
+
624
+ /**
625
+ * Apply pending balance to available balance
626
+ *
627
+ * Required after receiving transfers to make funds spendable.
628
+ *
629
+ * @param owner - Account owner
630
+ * @param token - C-SPL token
631
+ * @returns Transfer result
632
+ */
633
+ async applyPendingBalance(
634
+ owner: string,
635
+ token: CSPLToken
636
+ ): Promise<ConfidentialTransferResult> {
637
+ // Validate
638
+ if (!owner || owner.trim() === '') {
639
+ return {
640
+ success: false,
641
+ error: 'Owner address is required',
642
+ }
643
+ }
644
+ if (!isValidSolanaAddressFormat(owner)) {
645
+ return {
646
+ success: false,
647
+ error: 'Invalid owner address format. Expected base58-encoded Solana address (32-44 chars)',
648
+ }
649
+ }
650
+ if (!token || !token.confidentialMint) {
651
+ return {
652
+ success: false,
653
+ error: 'Token configuration is required',
654
+ }
655
+ }
656
+ if (!isValidSolanaAddressFormat(token.confidentialMint)) {
657
+ return {
658
+ success: false,
659
+ error: 'Invalid token confidentialMint format. Expected base58-encoded Solana address (32-44 chars)',
660
+ }
661
+ }
662
+
663
+ try {
664
+ const account = await this.getOrCreateAccount(owner, token)
665
+
666
+ if (!account.pendingBalance || account.pendingCount === 0) {
667
+ return {
668
+ success: true,
669
+ newSenderBalance: account.encryptedBalance,
670
+ recipientPendingUpdated: false,
671
+ }
672
+ }
673
+
674
+ // In production:
675
+ // 1. Combine pending balance with available balance
676
+ // 2. Clear pending balance
677
+ // 3. Submit transaction
678
+
679
+ const signature = this.generateSignature()
680
+
681
+ // Update cache
682
+ const cacheKey = `${owner}:${token.confidentialMint}`
683
+ const updatedAccount: ConfidentialTokenAccount = {
684
+ ...account,
685
+ pendingBalance: undefined,
686
+ pendingCount: 0,
687
+ }
688
+ this.accountCache.set(cacheKey, updatedAccount)
689
+
690
+ return {
691
+ success: true,
692
+ signature,
693
+ newSenderBalance: updatedAccount.encryptedBalance,
694
+ recipientPendingUpdated: true,
695
+ }
696
+ } catch (error) {
697
+ return {
698
+ success: false,
699
+ error: error instanceof Error ? error.message : 'Unknown error',
700
+ }
701
+ }
702
+ }
703
+
704
+ // ─── Query Methods ────────────────────────────────────────────────────────────
705
+
706
+ /**
707
+ * Get token configuration for a known mint
708
+ *
709
+ * @param symbol - Token symbol (e.g., 'C-USDC')
710
+ * @returns Token configuration or undefined
711
+ */
712
+ getKnownToken(symbol: string): Partial<CSPLToken> | undefined {
713
+ return CSPL_TOKENS[symbol]
714
+ }
715
+
716
+ /**
717
+ * List all known C-SPL tokens
718
+ */
719
+ listKnownTokens(): string[] {
720
+ return Object.keys(CSPL_TOKENS)
721
+ }
722
+
723
+ /**
724
+ * Estimate cost for an operation
725
+ *
726
+ * Returns the estimated cost in lamports. Made async for consistency
727
+ * with other privacy backend cost estimation methods.
728
+ *
729
+ * @param operation - Operation type
730
+ * @returns Estimated cost in lamports
731
+ */
732
+ async estimateCost(operation: keyof typeof CSPL_OPERATION_COSTS): Promise<bigint> {
733
+ return CSPL_OPERATION_COSTS[operation]
734
+ }
735
+
736
+ /**
737
+ * Estimate time for an operation
738
+ *
739
+ * Returns the estimated time in milliseconds. Made async for consistency
740
+ * with other privacy backend estimation methods.
741
+ *
742
+ * @param operation - Operation type
743
+ * @returns Estimated time in milliseconds
744
+ */
745
+ async estimateTime(operation: keyof typeof CSPL_OPERATION_TIMES): Promise<number> {
746
+ return CSPL_OPERATION_TIMES[operation]
747
+ }
748
+
749
+ /**
750
+ * Get current configuration (deeply frozen copy)
751
+ */
752
+ getConfig(): Readonly<CSPLClientConfig> {
753
+ return deepFreeze({ ...this.config })
754
+ }
755
+
756
+ /**
757
+ * Get program IDs
758
+ */
759
+ getProgramIds(): typeof CSPL_PROGRAM_IDS {
760
+ return CSPL_PROGRAM_IDS
761
+ }
762
+
763
+ // ─── Private Methods ──────────────────────────────────────────────────────────
764
+
765
+ /**
766
+ * Derive confidential account address
767
+ */
768
+ private deriveAccountAddress(owner: string, token: CSPLToken): string {
769
+ // In production: Calculate actual PDA
770
+ // return PublicKey.findProgramAddress(...)
771
+ const hash = this.simpleHash(`${owner}:${token.confidentialMint}`)
772
+ return `cspl_${hash}`
773
+ }
774
+
775
+ /**
776
+ * Get or create token configuration
777
+ */
778
+ private getOrCreateTokenConfig(mint: string): CSPLToken {
779
+ // Check known tokens
780
+ for (const [, config] of Object.entries(CSPL_TOKENS)) {
781
+ if (config.mint === mint) {
782
+ return {
783
+ mint,
784
+ confidentialMint: `cspl_${mint.slice(0, 8)}`,
785
+ decimals: config.decimals ?? 9,
786
+ symbol: config.symbol,
787
+ name: config.name,
788
+ isNativeWrap: config.isNativeWrap,
789
+ }
790
+ }
791
+ }
792
+
793
+ // Create generic config for unknown token
794
+ return {
795
+ mint,
796
+ confidentialMint: `cspl_${mint.slice(0, 8)}`,
797
+ decimals: 9, // Default to 9 decimals
798
+ }
799
+ }
800
+
801
+ /**
802
+ * Generate a simulated transaction signature
803
+ */
804
+ private generateSignature(): string {
805
+ const timestamp = Date.now().toString(36)
806
+ const random = Math.random().toString(36).slice(2, 10)
807
+ return `cspl_tx_${timestamp}_${random}`
808
+ }
809
+
810
+ /**
811
+ * Generate a nonce for encryption
812
+ */
813
+ private generateNonce(): Uint8Array {
814
+ const nonce = new Uint8Array(12)
815
+ for (let i = 0; i < 12; i++) {
816
+ nonce[i] = Math.floor(Math.random() * 256)
817
+ }
818
+ return nonce
819
+ }
820
+
821
+ /**
822
+ * Simulate encryption (for testing without crypto libs)
823
+ */
824
+ private simulateEncryption(amount: bigint, type: CSPLEncryptionType): Uint8Array {
825
+ const encoder = new TextEncoder()
826
+ const combined = `${type}:${amount.toString()}:${Date.now()}`
827
+ return encoder.encode(combined)
828
+ }
829
+
830
+ /**
831
+ * Simulate decryption (for testing)
832
+ */
833
+ private simulateDecryption(ciphertext: Uint8Array): bigint {
834
+ // Deterministic but fake - return hash-based value
835
+ let sum = 0
836
+ for (const byte of ciphertext) {
837
+ sum += byte
838
+ }
839
+ return BigInt(sum % 1_000_000_000)
840
+ }
841
+
842
+ /**
843
+ * Simple hash for deterministic addresses
844
+ */
845
+ private simpleHash(input: string): string {
846
+ let hash = 0
847
+ for (let i = 0; i < input.length; i++) {
848
+ const char = input.charCodeAt(i)
849
+ hash = ((hash << 5) - hash) + char
850
+ hash = hash & hash
851
+ }
852
+ return Math.abs(hash).toString(36)
853
+ }
854
+
855
+ /**
856
+ * Clear all caches
857
+ */
858
+ clearCache(): void {
859
+ this.accountCache.clear()
860
+ this.balanceCache.clear()
861
+ }
862
+
863
+ /**
864
+ * Get cache entry counts (backward compatible)
865
+ *
866
+ * @returns Number of entries in each cache
867
+ */
868
+ getCacheStats(): { accounts: number; balances: number } {
869
+ return {
870
+ accounts: this.accountCache.size,
871
+ balances: this.balanceCache.size,
872
+ }
873
+ }
874
+
875
+ /**
876
+ * Get detailed cache statistics including LRU metrics
877
+ *
878
+ * @returns Detailed cache stats with hit rates and eviction counts
879
+ */
880
+ getDetailedCacheStats(): CSPLCacheStats {
881
+ return {
882
+ accounts: this.accountCache.getStats(),
883
+ balances: this.balanceCache.getStats(),
884
+ }
885
+ }
886
+
887
+ /**
888
+ * Get cache configuration
889
+ *
890
+ * @returns Current cache configuration
891
+ */
892
+ getCacheConfig(): Readonly<CSPLCacheConfig> {
893
+ return deepFreeze({ ...this.cacheConfig })
894
+ }
895
+
896
+ /**
897
+ * Prune expired entries from all caches
898
+ *
899
+ * @returns Number of entries pruned from each cache
900
+ */
901
+ pruneExpiredCache(): { accounts: number; balances: number } {
902
+ return {
903
+ accounts: this.accountCache.prune(),
904
+ balances: this.balanceCache.prune(),
905
+ }
906
+ }
907
+ }