@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,456 @@
1
+ /**
2
+ * PrivacyCash Privacy Backend
3
+ *
4
+ * Implements the PrivacyBackend interface using PrivacyCash pool mixing.
5
+ * PrivacyCash is a Tornado Cash-style mixer for Solana that provides
6
+ * anonymity through fixed-size deposit pools.
7
+ *
8
+ * ## Key Characteristics
9
+ *
10
+ * - **Pool Mixing**: Users deposit into fixed-size pools and withdraw to fresh addresses
11
+ * - **Anonymity Set**: Privacy comes from the number of depositors in each pool
12
+ * - **Fixed Amounts**: Only supports specific pool sizes (0.1, 1, 10, 100 SOL)
13
+ * - **No Compliance**: Does not support viewing keys or selective disclosure
14
+ *
15
+ * ## Trade-offs vs SIP Native
16
+ *
17
+ * | Feature | PrivacyCash | SIP Native |
18
+ * |---------|-------------|------------|
19
+ * | Amount hidden | No (fixed pools) | Yes (Pedersen) |
20
+ * | Sender hidden | Yes (pool mixing) | Yes (stealth) |
21
+ * | Compliance | No | Yes (viewing keys) |
22
+ * | Anonymity set | Yes (pool size) | No |
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * import { PrivacyCashBackend, PrivacyBackendRegistry } from '@sip-protocol/sdk'
27
+ *
28
+ * const backend = new PrivacyCashBackend({
29
+ * rpcUrl: 'https://api.mainnet-beta.solana.com',
30
+ * })
31
+ *
32
+ * const registry = new PrivacyBackendRegistry()
33
+ * registry.register(backend, { priority: 80 })
34
+ *
35
+ * // Check if available for 1 SOL transfer
36
+ * const availability = await backend.checkAvailability({
37
+ * chain: 'solana',
38
+ * sender: '...',
39
+ * recipient: '...',
40
+ * mint: null,
41
+ * amount: BigInt(1_000_000_000), // 1 SOL
42
+ * decimals: 9,
43
+ * })
44
+ *
45
+ * if (availability.available) {
46
+ * console.log(`Estimated cost: ${availability.estimatedCost}`)
47
+ * }
48
+ * ```
49
+ *
50
+ * @see https://github.com/Privacy-Cash/privacy-cash-sdk
51
+ */
52
+
53
+ import type {
54
+ PrivacyBackend,
55
+ BackendType,
56
+ BackendCapabilities,
57
+ TransferParams,
58
+ TransactionResult,
59
+ AvailabilityResult,
60
+ } from './interface'
61
+
62
+ import {
63
+ SOL_POOL_AMOUNTS,
64
+ SPL_TOKEN_MINTS,
65
+ findNearestPoolSize,
66
+ isValidPoolAmount,
67
+ getAvailablePoolSizes,
68
+ type PrivacyCashSPLToken,
69
+ type PoolInfo,
70
+ type IPrivacyCashSDK,
71
+ } from './privacycash-types'
72
+ import { createPrivacyLogger } from '../privacy-logger'
73
+
74
+ /** Privacy-aware logger for PrivacyCash backend */
75
+ const privacyCashLogger = createPrivacyLogger('PrivacyCash')
76
+
77
+ import { randomBytes, bytesToHex } from '@noble/hashes/utils'
78
+
79
+ /**
80
+ * Default estimated anonymity set size
81
+ * In production, this would be fetched from the pool
82
+ */
83
+ const DEFAULT_ANONYMITY_SET = 50
84
+
85
+ /**
86
+ * Estimated time for pool operations (deposit + withdrawal)
87
+ * Pool mixing typically requires waiting for more deposits
88
+ */
89
+ const ESTIMATED_TIME_MS = 30000 // 30 seconds minimum
90
+
91
+ /**
92
+ * Base cost for PrivacyCash operations (in lamports)
93
+ * Includes: deposit tx + withdrawal tx + relayer fee
94
+ */
95
+ const BASE_COST_LAMPORTS = BigInt(10_000_000) // ~0.01 SOL
96
+
97
+ /**
98
+ * Configuration options for PrivacyCash backend
99
+ */
100
+ export interface PrivacyCashBackendConfig {
101
+ /** Solana RPC endpoint URL */
102
+ rpcUrl?: string
103
+ /** Network type */
104
+ network?: 'mainnet-beta' | 'devnet'
105
+ /** Relayer URL for withdrawals */
106
+ relayerUrl?: string
107
+ /** Minimum anonymity set required for withdrawals */
108
+ minAnonymitySet?: number
109
+ /** Custom SDK instance (for testing) */
110
+ sdk?: IPrivacyCashSDK
111
+ }
112
+
113
+ /**
114
+ * PrivacyCash capabilities (static)
115
+ */
116
+ const PRIVACYCASH_CAPABILITIES: BackendCapabilities = {
117
+ hiddenAmount: false, // Fixed pool sizes, amount is known
118
+ hiddenSender: true, // Pool mixing hides sender
119
+ hiddenRecipient: true, // Withdrawal to fresh address
120
+ hiddenCompute: false, // No compute privacy
121
+ complianceSupport: false, // No viewing keys
122
+ anonymitySet: DEFAULT_ANONYMITY_SET,
123
+ setupRequired: false, // No setup needed
124
+ latencyEstimate: 'medium', // Need to wait for pool
125
+ supportedTokens: 'all', // SOL + USDC/USDT
126
+ minAmount: SOL_POOL_AMOUNTS[0], // Smallest pool
127
+ maxAmount: SOL_POOL_AMOUNTS[SOL_POOL_AMOUNTS.length - 1], // Largest pool
128
+ }
129
+
130
+ /**
131
+ * PrivacyCash Privacy Backend
132
+ *
133
+ * Uses pool mixing for transaction privacy on Solana.
134
+ * Integrates with the PrivacyCash protocol as an alternative
135
+ * to SIP Native's cryptographic approach.
136
+ */
137
+ export class PrivacyCashBackend implements PrivacyBackend {
138
+ readonly name = 'privacycash'
139
+ readonly type: BackendType = 'transaction'
140
+ readonly chains: string[] = ['solana']
141
+
142
+ private config: Required<Omit<PrivacyCashBackendConfig, 'sdk'>> & {
143
+ sdk?: IPrivacyCashSDK
144
+ }
145
+ private poolCache: Map<string, PoolInfo> = new Map()
146
+ private poolCacheExpiry: Map<string, number> = new Map()
147
+
148
+ /**
149
+ * Create a new PrivacyCash backend
150
+ *
151
+ * @param config - Backend configuration
152
+ */
153
+ constructor(config: PrivacyCashBackendConfig = {}) {
154
+ this.config = {
155
+ rpcUrl: config.rpcUrl ?? 'https://api.mainnet-beta.solana.com',
156
+ network: config.network ?? 'mainnet-beta',
157
+ relayerUrl: config.relayerUrl ?? 'https://relayer.privacycash.org',
158
+ minAnonymitySet: config.minAnonymitySet ?? 5,
159
+ sdk: config.sdk,
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Check if backend is available for given parameters
165
+ */
166
+ async checkAvailability(params: TransferParams): Promise<AvailabilityResult> {
167
+ // Validate amount is non-negative
168
+ if (params.amount < BigInt(0)) {
169
+ return {
170
+ available: false,
171
+ reason: 'Amount cannot be negative',
172
+ }
173
+ }
174
+
175
+ // Only supports Solana
176
+ if (params.chain !== 'solana') {
177
+ return {
178
+ available: false,
179
+ reason: `PrivacyCash only supports Solana, not '${params.chain}'`,
180
+ }
181
+ }
182
+
183
+ // Determine if this is SOL or SPL token
184
+ const isSOL = params.mint === null
185
+ const isSupportedSPL = params.mint
186
+ ? this.isSupportedSPLToken(params.mint)
187
+ : false
188
+
189
+ if (!isSOL && !isSupportedSPL) {
190
+ return {
191
+ available: false,
192
+ reason: params.mint
193
+ ? `Token ${params.mint} not supported. PrivacyCash supports SOL, USDC, and USDT only.`
194
+ : 'Invalid token configuration',
195
+ }
196
+ }
197
+
198
+ // Check if amount matches a pool size
199
+ if (!isValidPoolAmount(params.amount, isSOL)) {
200
+ const nearestPool = findNearestPoolSize(params.amount, isSOL)
201
+ const availablePools = getAvailablePoolSizes(isSOL)
202
+ .map(p => this.formatAmount(p, params.decimals))
203
+ .join(', ')
204
+
205
+ return {
206
+ available: false,
207
+ reason:
208
+ `Amount must match a pool size. ` +
209
+ `Nearest pool: ${this.formatAmount(nearestPool, params.decimals)}. ` +
210
+ `Available pools: ${availablePools}`,
211
+ }
212
+ }
213
+
214
+ // Check pool liquidity (in production, query actual pool)
215
+ const poolInfo = await this.getPoolInfo(params.amount, isSOL ? undefined : this.getSPLToken(params.mint!))
216
+
217
+ if (poolInfo.depositors < this.config.minAnonymitySet) {
218
+ return {
219
+ available: false,
220
+ reason:
221
+ `Pool anonymity set (${poolInfo.depositors}) below minimum (${this.config.minAnonymitySet}). ` +
222
+ `Wait for more deposits or use a different pool.`,
223
+ }
224
+ }
225
+
226
+ // Viewing keys are not supported - warn if provided
227
+ if (params.viewingKey) {
228
+ privacyCashLogger.warn(
229
+ 'Viewing keys are not supported. Use SIP Native backend for compliance features.'
230
+ )
231
+ }
232
+
233
+ return {
234
+ available: true,
235
+ estimatedCost: this.estimateCostForTransfer(params),
236
+ estimatedTime: ESTIMATED_TIME_MS,
237
+ }
238
+ }
239
+
240
+ /**
241
+ * Get backend capabilities
242
+ */
243
+ getCapabilities(): BackendCapabilities {
244
+ return {
245
+ ...PRIVACYCASH_CAPABILITIES,
246
+ // Dynamic anonymity set from cache if available
247
+ anonymitySet: this.getAverageAnonymitySet(),
248
+ }
249
+ }
250
+
251
+ /**
252
+ * Execute a privacy-preserving transfer via pool mixing
253
+ *
254
+ * This performs a two-step process:
255
+ * 1. Deposit into the matching pool (returns a secret note)
256
+ * 2. Withdraw to recipient address (using the note)
257
+ *
258
+ * For production use, the note should be stored securely
259
+ * and withdrawal can happen later.
260
+ */
261
+ async execute(params: TransferParams): Promise<TransactionResult> {
262
+ // Validate availability first
263
+ const availability = await this.checkAvailability(params)
264
+ if (!availability.available) {
265
+ return {
266
+ success: false,
267
+ error: availability.reason,
268
+ backend: this.name,
269
+ }
270
+ }
271
+
272
+ try {
273
+ const isSOL = params.mint === null
274
+
275
+ // In a real implementation with the SDK:
276
+ // 1. const depositResult = await this.sdk.deposit({ amount, wallet })
277
+ // 2. Store depositResult.note securely
278
+ // 3. const withdrawResult = await this.sdk.withdraw({ amount, recipient, note })
279
+
280
+ // Simulated result for now (SDK requires Node 24+)
281
+ const simulatedNote = this.generateSimulatedNote()
282
+ const simulatedSignature = `pc_${Date.now()}_${Math.random().toString(36).slice(2)}`
283
+
284
+ return {
285
+ success: true,
286
+ signature: simulatedSignature,
287
+ backend: this.name,
288
+ metadata: {
289
+ poolSize: params.amount.toString(),
290
+ isSOL,
291
+ token: isSOL ? 'SOL' : this.getSPLToken(params.mint!),
292
+ note: simulatedNote, // In production, this is the withdrawal proof
293
+ anonymitySet: await this.getPoolAnonymitySet(params.amount, isSOL, params.mint),
294
+ timestamp: Date.now(),
295
+ warning: 'Simulated result - SDK integration pending',
296
+ },
297
+ }
298
+ } catch (error) {
299
+ return {
300
+ success: false,
301
+ error: error instanceof Error ? error.message : 'Unknown error',
302
+ backend: this.name,
303
+ }
304
+ }
305
+ }
306
+
307
+ /**
308
+ * Estimate cost for a transfer
309
+ */
310
+ async estimateCost(params: TransferParams): Promise<bigint> {
311
+ return this.estimateCostForTransfer(params)
312
+ }
313
+
314
+ // ─── Private Methods ─────────────────────────────────────────────────────────
315
+
316
+ /**
317
+ * Check if a mint address is a supported SPL token
318
+ */
319
+ private isSupportedSPLToken(mint: string): boolean {
320
+ return Object.values(SPL_TOKEN_MINTS).includes(mint)
321
+ }
322
+
323
+ /**
324
+ * Get SPL token type from mint address
325
+ */
326
+ private getSPLToken(mint: string): PrivacyCashSPLToken | undefined {
327
+ for (const [token, address] of Object.entries(SPL_TOKEN_MINTS)) {
328
+ if (address === mint) {
329
+ return token as PrivacyCashSPLToken
330
+ }
331
+ }
332
+ return undefined
333
+ }
334
+
335
+ /**
336
+ * Format amount for display
337
+ */
338
+ private formatAmount(amount: bigint, decimals: number): string {
339
+ const divisor = BigInt(10 ** decimals)
340
+ const whole = amount / divisor
341
+ const fraction = amount % divisor
342
+ if (fraction === BigInt(0)) {
343
+ return whole.toString()
344
+ }
345
+ return `${whole}.${fraction.toString().padStart(decimals, '0').replace(/0+$/, '')}`
346
+ }
347
+
348
+ /**
349
+ * Estimate cost for a transfer
350
+ */
351
+ private estimateCostForTransfer(params: TransferParams): bigint {
352
+ // Base cost for deposit + withdrawal transactions
353
+ let cost = BASE_COST_LAMPORTS
354
+
355
+ // SPL token transfers have additional account rent
356
+ if (params.mint !== null) {
357
+ cost += BigInt(2_000_000) // ~0.002 SOL for token accounts
358
+ }
359
+
360
+ // Relayer fee (typically 0.1% of amount, min 0.001 SOL)
361
+ const relayerFee = params.amount / BigInt(1000)
362
+ const minRelayerFee = BigInt(1_000_000)
363
+ cost += relayerFee > minRelayerFee ? relayerFee : minRelayerFee
364
+
365
+ return cost
366
+ }
367
+
368
+ /**
369
+ * Get pool information (mocked for now)
370
+ */
371
+ private async getPoolInfo(
372
+ amount: bigint,
373
+ token?: PrivacyCashSPLToken
374
+ ): Promise<PoolInfo> {
375
+ const cacheKey = `${amount.toString()}-${token ?? 'SOL'}`
376
+
377
+ // Check cache
378
+ const cached = this.poolCache.get(cacheKey)
379
+ const expiry = this.poolCacheExpiry.get(cacheKey)
380
+ if (cached && expiry && Date.now() < expiry) {
381
+ return cached
382
+ }
383
+
384
+ // In production, query the actual pool:
385
+ // const poolInfo = await this.config.sdk?.getPoolInfo(amount, token)
386
+
387
+ // Simulated pool info based on pool size
388
+ // Larger pools typically have more depositors
389
+ const baseDepositors = token ? 30 : 50
390
+ const sizeMultiplier = Number(amount / BigInt(100_000_000))
391
+ const depositors = Math.max(
392
+ 10,
393
+ baseDepositors + Math.floor(Math.random() * 20) - Math.floor(sizeMultiplier / 10)
394
+ )
395
+
396
+ const poolInfo: PoolInfo = {
397
+ size: amount,
398
+ depositors,
399
+ liquidity: amount * BigInt(depositors),
400
+ withdrawable: depositors >= this.config.minAnonymitySet,
401
+ }
402
+
403
+ // Cache for 60 seconds
404
+ this.poolCache.set(cacheKey, poolInfo)
405
+ this.poolCacheExpiry.set(cacheKey, Date.now() + 60000)
406
+
407
+ return poolInfo
408
+ }
409
+
410
+ /**
411
+ * Get anonymity set for a specific pool
412
+ */
413
+ private async getPoolAnonymitySet(
414
+ amount: bigint,
415
+ isSOL: boolean,
416
+ mint?: string | null
417
+ ): Promise<number> {
418
+ const token = isSOL ? undefined : (mint ? this.getSPLToken(mint) : undefined)
419
+ const poolInfo = await this.getPoolInfo(amount, token)
420
+ return poolInfo.depositors
421
+ }
422
+
423
+ /**
424
+ * Get average anonymity set across cached pools
425
+ */
426
+ private getAverageAnonymitySet(): number {
427
+ if (this.poolCache.size === 0) {
428
+ return DEFAULT_ANONYMITY_SET
429
+ }
430
+
431
+ let total = 0
432
+ for (const pool of this.poolCache.values()) {
433
+ total += pool.depositors
434
+ }
435
+ return Math.round(total / this.poolCache.size)
436
+ }
437
+
438
+ /**
439
+ * Generate a simulated withdrawal note
440
+ *
441
+ * Uses cryptographically secure random bytes.
442
+ * In production, this comes from the deposit transaction.
443
+ */
444
+ private generateSimulatedNote(): string {
445
+ const bytes = randomBytes(32)
446
+ return `privacycash:${bytesToHex(bytes)}`
447
+ }
448
+
449
+ /**
450
+ * Clear pool cache
451
+ */
452
+ clearPoolCache(): void {
453
+ this.poolCache.clear()
454
+ this.poolCacheExpiry.clear()
455
+ }
456
+ }