@sip-protocol/sdk 0.7.3 → 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 (264) 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 +47556 -19603
  7. package/dist/browser.mjs +628 -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-3M3HNQCW.mjs → chunk-YWGJ77A2.mjs} +28656 -13103
  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-DIBZHOOQ.d.ts → index-DXh2IGkz.d.ts} +21239 -10304
  24. package/dist/{index-8MQz13eJ.d.mts → index-DeE1ZzA4.d.mts} +21239 -10304
  25. package/dist/index.d.mts +9 -3
  26. package/dist/index.d.ts +9 -3
  27. package/dist/index.js +48396 -19623
  28. package/dist/index.mjs +537 -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 +252 -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 +47 -6
  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 +186 -33
  98. package/src/chains/solana/providers/index.ts +31 -0
  99. package/src/chains/solana/providers/interface.ts +61 -18
  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 +338 -67
  103. package/src/chains/solana/rpc-client.ts +1150 -0
  104. package/src/chains/solana/scan.ts +83 -66
  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 +57 -6
  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 +23 -0
  116. package/src/compliance/range-sas.ts +398 -33
  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 +686 -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 +254 -4
  143. package/src/privacy-backends/interface.ts +649 -6
  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.ts +13 -17
  148. package/src/privacy-backends/private-swap.ts +570 -0
  149. package/src/privacy-backends/rate-limiter.ts +683 -0
  150. package/src/privacy-backends/registry.ts +414 -2
  151. package/src/privacy-backends/router.ts +283 -3
  152. package/src/privacy-backends/shadowwire.ts +449 -0
  153. package/src/privacy-backends/sip-native.ts +3 -0
  154. package/src/privacy-logger.ts +191 -0
  155. package/src/production-safety.ts +373 -0
  156. package/src/proofs/aggregator.ts +1029 -0
  157. package/src/proofs/browser-composer.ts +1150 -0
  158. package/src/proofs/browser.ts +113 -25
  159. package/src/proofs/cache/index.ts +127 -0
  160. package/src/proofs/cache/interface.ts +545 -0
  161. package/src/proofs/cache/key-generator.ts +188 -0
  162. package/src/proofs/cache/lru-cache.ts +481 -0
  163. package/src/proofs/cache/multi-tier-cache.ts +575 -0
  164. package/src/proofs/cache/persistent-cache.ts +788 -0
  165. package/src/proofs/compliance-proof.ts +872 -0
  166. package/src/proofs/composer/base.ts +923 -0
  167. package/src/proofs/composer/index.ts +25 -0
  168. package/src/proofs/composer/interface.ts +518 -0
  169. package/src/proofs/composer/types.ts +383 -0
  170. package/src/proofs/converters/halo2.ts +452 -0
  171. package/src/proofs/converters/index.ts +208 -0
  172. package/src/proofs/converters/interface.ts +363 -0
  173. package/src/proofs/converters/kimchi.ts +462 -0
  174. package/src/proofs/converters/noir.ts +451 -0
  175. package/src/proofs/fallback.ts +888 -0
  176. package/src/proofs/halo2.ts +42 -0
  177. package/src/proofs/index.ts +471 -0
  178. package/src/proofs/interface.ts +13 -0
  179. package/src/proofs/kimchi.ts +42 -0
  180. package/src/proofs/lazy.ts +1004 -0
  181. package/src/proofs/mock.ts +25 -1
  182. package/src/proofs/noir.ts +110 -29
  183. package/src/proofs/orchestrator.ts +960 -0
  184. package/src/proofs/parallel/concurrency.ts +297 -0
  185. package/src/proofs/parallel/dependency-graph.ts +602 -0
  186. package/src/proofs/parallel/executor.ts +420 -0
  187. package/src/proofs/parallel/index.ts +131 -0
  188. package/src/proofs/parallel/interface.ts +685 -0
  189. package/src/proofs/parallel/worker-pool.ts +644 -0
  190. package/src/proofs/providers/halo2.ts +560 -0
  191. package/src/proofs/providers/index.ts +34 -0
  192. package/src/proofs/providers/kimchi.ts +641 -0
  193. package/src/proofs/validator.ts +881 -0
  194. package/src/proofs/verifier.ts +867 -0
  195. package/src/quantum/index.ts +112 -0
  196. package/src/quantum/winternitz-vault.ts +639 -0
  197. package/src/quantum/wots.ts +611 -0
  198. package/src/settlement/backends/direct-chain.ts +1 -0
  199. package/src/settlement/index.ts +9 -0
  200. package/src/settlement/router.ts +732 -46
  201. package/src/solana/index.ts +72 -0
  202. package/src/solana/jito-relayer.ts +687 -0
  203. package/src/solana/noir-verifier-types.ts +430 -0
  204. package/src/solana/noir-verifier.ts +816 -0
  205. package/src/stealth/address-derivation.ts +193 -0
  206. package/src/stealth/ed25519.ts +431 -0
  207. package/src/stealth/index.ts +233 -0
  208. package/src/stealth/meta-address.ts +221 -0
  209. package/src/stealth/secp256k1.ts +368 -0
  210. package/src/stealth/utils.ts +194 -0
  211. package/src/stealth.ts +50 -1504
  212. package/src/sync/index.ts +106 -0
  213. package/src/sync/manager.ts +504 -0
  214. package/src/sync/mock-provider.ts +318 -0
  215. package/src/sync/oblivious.ts +625 -0
  216. package/src/tokens/index.ts +15 -0
  217. package/src/tokens/registry.ts +301 -0
  218. package/src/utils/deprecation.ts +94 -0
  219. package/src/utils/index.ts +9 -0
  220. package/src/wallet/ethereum/index.ts +68 -0
  221. package/src/wallet/ethereum/metamask-privacy.ts +420 -0
  222. package/src/wallet/ethereum/multi-wallet.ts +646 -0
  223. package/src/wallet/ethereum/privacy-adapter.ts +700 -0
  224. package/src/wallet/ethereum/types.ts +3 -1
  225. package/src/wallet/ethereum/walletconnect-adapter.ts +675 -0
  226. package/src/wallet/hardware/index.ts +10 -0
  227. package/src/wallet/hardware/ledger-privacy.ts +414 -0
  228. package/src/wallet/index.ts +71 -0
  229. package/src/wallet/near/adapter.ts +626 -0
  230. package/src/wallet/near/index.ts +86 -0
  231. package/src/wallet/near/meteor-wallet.ts +1153 -0
  232. package/src/wallet/near/my-near-wallet.ts +790 -0
  233. package/src/wallet/near/wallet-selector.ts +702 -0
  234. package/src/wallet/solana/adapter.ts +6 -4
  235. package/src/wallet/solana/index.ts +13 -0
  236. package/src/wallet/solana/privacy-adapter.ts +567 -0
  237. package/src/wallet/sui/types.ts +6 -4
  238. package/src/zcash/rpc-client.ts +13 -6
  239. package/dist/chunk-2XIVXWHA.mjs +0 -1930
  240. package/dist/chunk-3INS3PR5.mjs +0 -884
  241. package/dist/chunk-3OVABDRH.mjs +0 -17096
  242. package/dist/chunk-7RFRWDCW.mjs +0 -1504
  243. package/dist/chunk-DLDWZFYC.mjs +0 -1495
  244. package/dist/chunk-E6SZWREQ.mjs +0 -57
  245. package/dist/chunk-F6F73W35.mjs +0 -16166
  246. package/dist/chunk-G33LB27A.mjs +0 -16166
  247. package/dist/chunk-HGU6HZRC.mjs +0 -231
  248. package/dist/chunk-L2K34JCU.mjs +0 -1496
  249. package/dist/chunk-OFDBEIEK.mjs +0 -16166
  250. package/dist/chunk-SF7YSLF5.mjs +0 -1515
  251. package/dist/chunk-SN4ZDTVW.mjs +0 -16166
  252. package/dist/chunk-WWUSGOXE.mjs +0 -17129
  253. package/dist/constants-VOI7BSLK.mjs +0 -27
  254. package/dist/index-B71aXVzk.d.ts +0 -13264
  255. package/dist/index-BYZbDjal.d.ts +0 -11390
  256. package/dist/index-CHB3KuOB.d.mts +0 -11859
  257. package/dist/index-CzWPI6Le.d.ts +0 -11859
  258. package/dist/index-pOIIuwfV.d.mts +0 -13264
  259. package/dist/index-xbWjohNq.d.mts +0 -11390
  260. package/dist/solana-4O4K45VU.mjs +0 -46
  261. package/dist/solana-5EMCTPTS.mjs +0 -46
  262. package/dist/solana-NDABAZ6P.mjs +0 -56
  263. package/dist/solana-Q4NAVBTS.mjs +0 -46
  264. package/dist/solana-ZYO63LY5.mjs +0 -46
@@ -0,0 +1,605 @@
1
+ /**
2
+ * Solana Privacy Adapter
3
+ *
4
+ * Orchestrates privacy operations for Solana same-chain transactions.
5
+ * Provides a unified interface for stealth transfers, scanning, and claiming.
6
+ *
7
+ * @module chains/solana/privacy-adapter
8
+ */
9
+
10
+ import { Connection, PublicKey, type Transaction, type VersionedTransaction } from '@solana/web3.js'
11
+ import type { StealthMetaAddress, HexString } from '@sip-protocol/types'
12
+ import {
13
+ generateEd25519StealthAddress,
14
+ decodeStealthMetaAddress,
15
+ ed25519PublicKeyToSolanaAddress,
16
+ generateEd25519StealthMetaAddress,
17
+ } from '../../stealth'
18
+ import { sendPrivateSPLTransfer, estimatePrivateTransferFee, hasTokenAccount } from './transfer'
19
+ import { scanForPayments, claimStealthPayment, getStealthBalance } from './scan'
20
+ import {
21
+ StealthScanner,
22
+ createStealthScanner,
23
+ type ScanRecipient,
24
+ type DetectedPayment,
25
+ type HistoricalScanOptions,
26
+ } from './stealth-scanner'
27
+ import {
28
+ generateEphemeralKeypair,
29
+ generateManagedEphemeralKeypair,
30
+ type EphemeralKeypair,
31
+ type ManagedEphemeralKeypair,
32
+ } from './ephemeral-keys'
33
+ import { createProvider, type SolanaRPCProvider, type ProviderType, type ProviderConfig } from './providers'
34
+ import type {
35
+ SolanaPrivateTransferResult,
36
+ SolanaScanResult,
37
+ SolanaClaimResult,
38
+ } from './types'
39
+ import type { SolanaCluster } from './constants'
40
+
41
+ // ─── Types ────────────────────────────────────────────────────────────────────
42
+
43
+ /**
44
+ * Configuration for SolanaPrivacyAdapter
45
+ */
46
+ export interface SolanaPrivacyAdapterConfig {
47
+ /**
48
+ * Solana RPC connection
49
+ */
50
+ connection: Connection
51
+
52
+ /**
53
+ * Network cluster
54
+ * @default 'mainnet-beta'
55
+ */
56
+ cluster?: SolanaCluster
57
+
58
+ /**
59
+ * Optional RPC provider for efficient queries
60
+ */
61
+ provider?: SolanaRPCProvider
62
+
63
+ /**
64
+ * Provider type to auto-create if provider not specified
65
+ */
66
+ providerType?: ProviderType
67
+
68
+ /**
69
+ * Provider configuration (API key, etc.)
70
+ */
71
+ providerConfig?: ProviderConfig
72
+ }
73
+
74
+ /**
75
+ * Parameters for creating a shielded transfer
76
+ */
77
+ export interface ShieldedTransferParams {
78
+ /**
79
+ * Sender's public key
80
+ */
81
+ sender: PublicKey
82
+
83
+ /**
84
+ * Sender's token account (ATA)
85
+ */
86
+ senderTokenAccount: PublicKey
87
+
88
+ /**
89
+ * Recipient's stealth meta-address
90
+ * Can be a StealthMetaAddress object or encoded string (sip:solana:...)
91
+ */
92
+ recipient: StealthMetaAddress | string
93
+
94
+ /**
95
+ * SPL token mint address
96
+ */
97
+ mint: PublicKey
98
+
99
+ /**
100
+ * Amount to transfer (in token's smallest unit)
101
+ */
102
+ amount: bigint
103
+
104
+ /**
105
+ * Function to sign the transaction
106
+ */
107
+ signTransaction: <T extends Transaction | VersionedTransaction>(tx: T) => Promise<T>
108
+ }
109
+
110
+ /**
111
+ * Parameters for scanning with the adapter
112
+ */
113
+ export interface AdapterScanParams {
114
+ /**
115
+ * Viewing private key (hex)
116
+ */
117
+ viewingPrivateKey: HexString
118
+
119
+ /**
120
+ * Spending public key (hex)
121
+ */
122
+ spendingPublicKey: HexString
123
+
124
+ /**
125
+ * Scan options (slots, limits, etc.)
126
+ */
127
+ options?: HistoricalScanOptions
128
+ }
129
+
130
+ /**
131
+ * Parameters for claiming with the adapter
132
+ */
133
+ export interface AdapterClaimParams {
134
+ /**
135
+ * Detected payment to claim
136
+ */
137
+ payment: DetectedPayment
138
+
139
+ /**
140
+ * Viewing private key (hex)
141
+ */
142
+ viewingPrivateKey: HexString
143
+
144
+ /**
145
+ * Spending private key (hex)
146
+ */
147
+ spendingPrivateKey: HexString
148
+
149
+ /**
150
+ * Destination address for claimed funds
151
+ */
152
+ destinationAddress: string
153
+ }
154
+
155
+ /**
156
+ * Privacy adapter state
157
+ */
158
+ export interface PrivacyAdapterState {
159
+ /**
160
+ * Whether the adapter is initialized
161
+ */
162
+ isInitialized: boolean
163
+
164
+ /**
165
+ * Current cluster
166
+ */
167
+ cluster: SolanaCluster
168
+
169
+ /**
170
+ * Whether a provider is available
171
+ */
172
+ hasProvider: boolean
173
+
174
+ /**
175
+ * Number of recipients in the scanner
176
+ */
177
+ scannerRecipientCount: number
178
+
179
+ /**
180
+ * Whether actively scanning (subscribed)
181
+ */
182
+ isScanning: boolean
183
+ }
184
+
185
+ // ─── SolanaPrivacyAdapter Class ───────────────────────────────────────────────
186
+
187
+ /**
188
+ * Solana Privacy Adapter
189
+ *
190
+ * Provides a unified interface for privacy operations on Solana:
191
+ * - Shielded transfers to stealth addresses
192
+ * - Payment scanning and detection
193
+ * - Claiming detected payments
194
+ * - Meta-address and keypair generation
195
+ *
196
+ * @example Basic usage
197
+ * ```typescript
198
+ * const adapter = new SolanaPrivacyAdapter({
199
+ * connection,
200
+ * cluster: 'mainnet-beta',
201
+ * providerType: 'helius',
202
+ * providerConfig: { apiKey: '...' },
203
+ * })
204
+ *
205
+ * // Generate meta-address for recipient
206
+ * const { metaAddress, viewingPrivateKey, spendingPrivateKey } =
207
+ * adapter.generateMetaAddress('Primary Wallet')
208
+ *
209
+ * // Send shielded transfer
210
+ * const result = await adapter.sendShieldedTransfer({
211
+ * sender: wallet.publicKey,
212
+ * senderTokenAccount: walletATA,
213
+ * recipient: recipientMetaAddress,
214
+ * mint: USDC_MINT,
215
+ * amount: 5_000_000n,
216
+ * signTransaction: wallet.signTransaction,
217
+ * })
218
+ *
219
+ * // Scan for incoming payments
220
+ * const payments = await adapter.scanForPayments({
221
+ * viewingPrivateKey,
222
+ * spendingPublicKey: metaAddress.spendingKey,
223
+ * })
224
+ * ```
225
+ *
226
+ * @example Real-time scanning
227
+ * ```typescript
228
+ * // Add recipient for scanning
229
+ * adapter.addScanRecipient({
230
+ * viewingPrivateKey,
231
+ * spendingPublicKey,
232
+ * label: 'Main Wallet',
233
+ * })
234
+ *
235
+ * // Subscribe to real-time payments
236
+ * adapter.subscribeToPayments(
237
+ * (payment) => console.log('Received:', payment),
238
+ * (error) => console.error('Error:', error)
239
+ * )
240
+ *
241
+ * // Later: stop scanning
242
+ * await adapter.unsubscribeFromPayments()
243
+ * ```
244
+ */
245
+ export class SolanaPrivacyAdapter {
246
+ private connection: Connection
247
+ private cluster: SolanaCluster
248
+ private provider?: SolanaRPCProvider
249
+ private scanner: StealthScanner
250
+ private initialized: boolean = false
251
+
252
+ constructor(config: SolanaPrivacyAdapterConfig) {
253
+ this.connection = config.connection
254
+ this.cluster = config.cluster ?? 'mainnet-beta'
255
+
256
+ // Initialize provider
257
+ if (config.provider) {
258
+ this.provider = config.provider
259
+ } else if (config.providerType && config.providerConfig) {
260
+ this.provider = createProvider(config.providerType, config.providerConfig)
261
+ }
262
+
263
+ // Initialize scanner
264
+ this.scanner = createStealthScanner({
265
+ connection: this.connection,
266
+ provider: this.provider,
267
+ })
268
+
269
+ this.initialized = true
270
+ }
271
+
272
+ // ─── Meta-Address Generation ────────────────────────────────────────────────
273
+
274
+ /**
275
+ * Generate a new stealth meta-address
276
+ *
277
+ * Creates a new keypair for receiving private payments.
278
+ * The meta-address can be shared publicly; only the private keys
279
+ * enable scanning and claiming.
280
+ *
281
+ * @param label - Optional label for the address
282
+ * @returns Meta-address and private keys
283
+ */
284
+ generateMetaAddress(label?: string): {
285
+ metaAddress: StealthMetaAddress
286
+ viewingPrivateKey: HexString
287
+ spendingPrivateKey: HexString
288
+ } {
289
+ const result = generateEd25519StealthMetaAddress('solana', label)
290
+ return {
291
+ metaAddress: result.metaAddress,
292
+ viewingPrivateKey: result.viewingPrivateKey,
293
+ spendingPrivateKey: result.spendingPrivateKey,
294
+ }
295
+ }
296
+
297
+ /**
298
+ * Parse an encoded meta-address string
299
+ *
300
+ * @param encoded - Encoded meta-address (sip:solana:...)
301
+ * @returns Decoded meta-address
302
+ */
303
+ parseMetaAddress(encoded: string): StealthMetaAddress {
304
+ return decodeStealthMetaAddress(encoded)
305
+ }
306
+
307
+ // ─── Ephemeral Keys ─────────────────────────────────────────────────────────
308
+
309
+ /**
310
+ * Generate an ephemeral keypair for a single transfer
311
+ *
312
+ * @returns Ephemeral keypair
313
+ */
314
+ generateEphemeralKeypair(): EphemeralKeypair {
315
+ return generateEphemeralKeypair()
316
+ }
317
+
318
+ /**
319
+ * Generate a managed ephemeral keypair with auto-disposal
320
+ *
321
+ * @returns Managed ephemeral keypair
322
+ */
323
+ generateManagedEphemeralKeypair(): ManagedEphemeralKeypair {
324
+ return generateManagedEphemeralKeypair()
325
+ }
326
+
327
+ // ─── Stealth Address Resolution ─────────────────────────────────────────────
328
+
329
+ /**
330
+ * Resolve a meta-address to a one-time stealth address
331
+ *
332
+ * Generates a fresh stealth address for the recipient.
333
+ * Each call produces a different, unlinkable address.
334
+ *
335
+ * @param recipient - Recipient's meta-address
336
+ * @returns Stealth address details
337
+ */
338
+ resolveStealthAddress(recipient: StealthMetaAddress | string): {
339
+ stealthAddress: string
340
+ stealthAddressHex: HexString
341
+ ephemeralPublicKey: string
342
+ ephemeralPublicKeyHex: HexString
343
+ viewTag: number
344
+ sharedSecret: HexString
345
+ } {
346
+ const metaAddress = typeof recipient === 'string'
347
+ ? decodeStealthMetaAddress(recipient)
348
+ : recipient
349
+
350
+ const { stealthAddress, sharedSecret } = generateEd25519StealthAddress(metaAddress)
351
+
352
+ const stealthAddressBase58 = ed25519PublicKeyToSolanaAddress(stealthAddress.address)
353
+ const ephemeralPublicKeyBase58 = ed25519PublicKeyToSolanaAddress(stealthAddress.ephemeralPublicKey)
354
+
355
+ return {
356
+ stealthAddress: stealthAddressBase58,
357
+ stealthAddressHex: stealthAddress.address,
358
+ ephemeralPublicKey: ephemeralPublicKeyBase58,
359
+ ephemeralPublicKeyHex: stealthAddress.ephemeralPublicKey,
360
+ viewTag: stealthAddress.viewTag,
361
+ sharedSecret,
362
+ }
363
+ }
364
+
365
+ // ─── Shielded Transfers ─────────────────────────────────────────────────────
366
+
367
+ /**
368
+ * Send a shielded SPL token transfer
369
+ *
370
+ * Transfers tokens to a stealth address with on-chain announcement
371
+ * for recipient scanning.
372
+ *
373
+ * @param params - Transfer parameters
374
+ * @returns Transfer result
375
+ */
376
+ async sendShieldedTransfer(
377
+ params: ShieldedTransferParams
378
+ ): Promise<SolanaPrivateTransferResult> {
379
+ const recipient = typeof params.recipient === 'string'
380
+ ? decodeStealthMetaAddress(params.recipient)
381
+ : params.recipient
382
+
383
+ return sendPrivateSPLTransfer({
384
+ connection: this.connection,
385
+ sender: params.sender,
386
+ senderTokenAccount: params.senderTokenAccount,
387
+ recipientMetaAddress: recipient,
388
+ mint: params.mint,
389
+ amount: params.amount,
390
+ signTransaction: params.signTransaction,
391
+ })
392
+ }
393
+
394
+ /**
395
+ * Estimate fee for a shielded transfer
396
+ *
397
+ * @param needsATACreation - Whether ATA needs to be created
398
+ * @returns Estimated fee in lamports
399
+ */
400
+ async estimateTransferFee(needsATACreation: boolean = true): Promise<bigint> {
401
+ return estimatePrivateTransferFee(this.connection, needsATACreation)
402
+ }
403
+
404
+ /**
405
+ * Check if a stealth address has a token account
406
+ *
407
+ * @param stealthAddress - Stealth address (base58)
408
+ * @param mint - Token mint
409
+ * @returns True if token account exists
410
+ */
411
+ async hasTokenAccount(stealthAddress: string, mint: PublicKey): Promise<boolean> {
412
+ return hasTokenAccount(this.connection, stealthAddress, mint)
413
+ }
414
+
415
+ // ─── Payment Scanning ───────────────────────────────────────────────────────
416
+
417
+ /**
418
+ * Scan for incoming stealth payments (one-time)
419
+ *
420
+ * @param params - Scan parameters
421
+ * @returns Detected payments
422
+ */
423
+ async scanForPayments(params: AdapterScanParams): Promise<SolanaScanResult[]> {
424
+ return scanForPayments({
425
+ connection: this.connection,
426
+ viewingPrivateKey: params.viewingPrivateKey,
427
+ spendingPublicKey: params.spendingPublicKey,
428
+ provider: this.provider,
429
+ fromSlot: params.options?.fromSlot,
430
+ toSlot: params.options?.toSlot,
431
+ limit: params.options?.limit,
432
+ })
433
+ }
434
+
435
+ /**
436
+ * Add a recipient to the continuous scanner
437
+ *
438
+ * @param recipient - Recipient keys and label
439
+ */
440
+ addScanRecipient(recipient: ScanRecipient): void {
441
+ this.scanner.addRecipient(recipient)
442
+ }
443
+
444
+ /**
445
+ * Remove a recipient from the scanner
446
+ *
447
+ * @param label - Recipient label to remove
448
+ */
449
+ removeScanRecipient(label: string): void {
450
+ this.scanner.removeRecipient(label)
451
+ }
452
+
453
+ /**
454
+ * Get all scan recipients
455
+ */
456
+ getScanRecipients(): ScanRecipient[] {
457
+ return this.scanner.getRecipients()
458
+ }
459
+
460
+ /**
461
+ * Clear all scan recipients
462
+ */
463
+ clearScanRecipients(): void {
464
+ this.scanner.clearRecipients()
465
+ }
466
+
467
+ /**
468
+ * Scan historical transactions
469
+ *
470
+ * @param options - Scan options
471
+ * @returns Scan result with detected payments
472
+ */
473
+ async scanHistorical(options?: HistoricalScanOptions) {
474
+ return this.scanner.scanHistorical(options)
475
+ }
476
+
477
+ /**
478
+ * Subscribe to real-time payment detection
479
+ *
480
+ * @param onPayment - Callback for detected payments
481
+ * @param onError - Callback for errors
482
+ */
483
+ subscribeToPayments(
484
+ onPayment: (payment: DetectedPayment) => void,
485
+ onError?: (error: Error) => void
486
+ ): void {
487
+ this.scanner.subscribe(onPayment, onError)
488
+ }
489
+
490
+ /**
491
+ * Unsubscribe from real-time payments
492
+ */
493
+ async unsubscribeFromPayments(): Promise<void> {
494
+ await this.scanner.unsubscribe()
495
+ }
496
+
497
+ /**
498
+ * Check if currently subscribed to payments
499
+ */
500
+ isSubscribedToPayments(): boolean {
501
+ return this.scanner.isSubscribed()
502
+ }
503
+
504
+ // ─── Payment Claiming ───────────────────────────────────────────────────────
505
+
506
+ /**
507
+ * Claim a detected payment
508
+ *
509
+ * Derives the stealth private key and transfers funds to the destination.
510
+ *
511
+ * @param params - Claim parameters
512
+ * @returns Claim result
513
+ */
514
+ async claimPayment(params: AdapterClaimParams): Promise<SolanaClaimResult> {
515
+ return claimStealthPayment({
516
+ connection: this.connection,
517
+ stealthAddress: params.payment.stealthAddress,
518
+ ephemeralPublicKey: params.payment.ephemeralPublicKey,
519
+ viewingPrivateKey: params.viewingPrivateKey,
520
+ spendingPrivateKey: params.spendingPrivateKey,
521
+ destinationAddress: params.destinationAddress,
522
+ mint: new PublicKey(params.payment.mint),
523
+ })
524
+ }
525
+
526
+ /**
527
+ * Get balance for a stealth address
528
+ *
529
+ * @param stealthAddress - Stealth address (base58)
530
+ * @param mint - Token mint
531
+ * @returns Token balance
532
+ */
533
+ async getStealthBalance(stealthAddress: string, mint: PublicKey): Promise<bigint> {
534
+ return getStealthBalance(this.connection, stealthAddress, mint, this.provider)
535
+ }
536
+
537
+ // ─── State & Utilities ──────────────────────────────────────────────────────
538
+
539
+ /**
540
+ * Get adapter state
541
+ */
542
+ getState(): PrivacyAdapterState {
543
+ return {
544
+ isInitialized: this.initialized,
545
+ cluster: this.cluster,
546
+ hasProvider: !!this.provider,
547
+ scannerRecipientCount: this.scanner.getRecipients().length,
548
+ isScanning: this.scanner.isSubscribed(),
549
+ }
550
+ }
551
+
552
+ /**
553
+ * Get the underlying connection
554
+ */
555
+ getConnection(): Connection {
556
+ return this.connection
557
+ }
558
+
559
+ /**
560
+ * Get the RPC provider (if configured)
561
+ */
562
+ getProvider(): SolanaRPCProvider | undefined {
563
+ return this.provider
564
+ }
565
+
566
+ /**
567
+ * Get the current cluster
568
+ */
569
+ getCluster(): SolanaCluster {
570
+ return this.cluster
571
+ }
572
+
573
+ /**
574
+ * Dispose of the adapter and clean up resources
575
+ */
576
+ async dispose(): Promise<void> {
577
+ await this.scanner.unsubscribe()
578
+ this.scanner.clearRecipients()
579
+ this.initialized = false
580
+ }
581
+ }
582
+
583
+ // ─── Factory Function ─────────────────────────────────────────────────────────
584
+
585
+ /**
586
+ * Create a new Solana privacy adapter
587
+ *
588
+ * @param config - Adapter configuration
589
+ * @returns Configured privacy adapter
590
+ *
591
+ * @example
592
+ * ```typescript
593
+ * const adapter = createSolanaPrivacyAdapter({
594
+ * connection: new Connection('https://api.mainnet-beta.solana.com'),
595
+ * cluster: 'mainnet-beta',
596
+ * providerType: 'helius',
597
+ * providerConfig: { apiKey: process.env.HELIUS_API_KEY },
598
+ * })
599
+ * ```
600
+ */
601
+ export function createSolanaPrivacyAdapter(
602
+ config: SolanaPrivacyAdapterConfig
603
+ ): SolanaPrivacyAdapter {
604
+ return new SolanaPrivacyAdapter(config)
605
+ }
@@ -30,8 +30,12 @@ import {
30
30
  TOKEN_PROGRAM_ID,
31
31
  getAssociatedTokenAddress,
32
32
  getAccount,
33
+ TokenAccountNotFoundError,
34
+ TokenInvalidAccountOwnerError,
33
35
  } from '@solana/spl-token'
34
36
  import type { SolanaRPCProvider, TokenAsset, GenericProviderConfig } from './interface'
37
+ import { NetworkError, ValidationError, ErrorCode } from '../../../errors'
38
+ import { sanitizeUrl } from '../constants'
35
39
 
36
40
  /**
37
41
  * RPC endpoint URLs by cluster
@@ -43,14 +47,21 @@ const CLUSTER_ENDPOINTS: Record<string, string> = {
43
47
  }
44
48
 
45
49
  /**
46
- * Validate a Solana address (base58)
47
- * @throws Error if address is invalid
50
+ * Validate and parse a Solana address (base58)
51
+ *
52
+ * Attempts to create a PublicKey from the address string.
53
+ *
54
+ * @param address - Solana address in base58 format
55
+ * @param paramName - Parameter name for error message context
56
+ * @returns Validated PublicKey instance
57
+ * @throws Error if address is invalid base58 or wrong length
58
+ * @internal
48
59
  */
49
60
  function validateSolanaAddress(address: string, paramName: string): PublicKey {
50
61
  try {
51
62
  return new PublicKey(address)
52
63
  } catch {
53
- throw new Error(`Invalid Solana address for ${paramName}: ${address}`)
64
+ throw new ValidationError('invalid Solana address format', paramName, undefined, ErrorCode.INVALID_ADDRESS)
54
65
  }
55
66
  }
56
67
 
@@ -119,6 +130,12 @@ export class GenericProvider implements SolanaRPCProvider {
119
130
  *
120
131
  * Uses getAccount on the associated token address.
121
132
  */
133
+ /**
134
+ * Get token balance for a specific mint
135
+ *
136
+ * M1 FIX: Properly differentiate between missing accounts (return 0n)
137
+ * and actual RPC errors (throw NetworkError)
138
+ */
122
139
  async getTokenBalance(owner: string, mint: string): Promise<bigint> {
123
140
  // Validate addresses before trying to fetch (these errors should propagate)
124
141
  const ownerPubkey = validateSolanaAddress(owner, 'owner')
@@ -133,9 +150,33 @@ export class GenericProvider implements SolanaRPCProvider {
133
150
 
134
151
  const account = await getAccount(this.connection, ata)
135
152
  return account.amount
136
- } catch {
137
- // Account doesn't exist or other RPC error
138
- return 0n
153
+ } catch (error) {
154
+ // M1 FIX: Only return 0n for "account not found" errors
155
+ // Throw for actual RPC/network errors
156
+ if (
157
+ error instanceof TokenAccountNotFoundError ||
158
+ error instanceof TokenInvalidAccountOwnerError
159
+ ) {
160
+ // Account doesn't exist - this is expected, return 0n
161
+ return 0n
162
+ }
163
+
164
+ // Check for common RPC error patterns
165
+ const errorMessage = error instanceof Error ? error.message : String(error)
166
+ if (
167
+ errorMessage.includes('could not find account') ||
168
+ errorMessage.includes('Account does not exist')
169
+ ) {
170
+ return 0n
171
+ }
172
+
173
+ // Actual RPC/network error - throw
174
+ // H-2 FIX: Sanitize endpoint URL to prevent credential exposure
175
+ throw new NetworkError(
176
+ `Failed to get token balance: ${errorMessage}`,
177
+ undefined,
178
+ { endpoint: sanitizeUrl(this.connection.rpcEndpoint) }
179
+ )
139
180
  }
140
181
  }
141
182