@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,623 @@
1
+ /**
2
+ * Helius Enhanced Transactions Integration
3
+ *
4
+ * Provides human-readable transaction data with SIP-specific parsing
5
+ * for privacy-preserving display to viewing key holders.
6
+ *
7
+ * @see https://docs.helius.dev/solana-apis/enhanced-transactions
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { HeliusEnhanced } from '@sip-protocol/sdk'
12
+ *
13
+ * const helius = new HeliusEnhanced({
14
+ * apiKey: process.env.HELIUS_API_KEY!,
15
+ * cluster: 'mainnet-beta'
16
+ * })
17
+ *
18
+ * // Parse a specific transaction
19
+ * const tx = await helius.parseTransaction('5rfFLBUp5YPr...')
20
+ * console.log(tx.description) // "Alice sent 1.5 SOL to Bob"
21
+ *
22
+ * // Get transaction history with SIP metadata
23
+ * const history = await helius.getTransactionHistory('7xK9...', {
24
+ * type: 'TRANSFER',
25
+ * limit: 50
26
+ * })
27
+ *
28
+ * // Get human-readable summaries for UI
29
+ * const summaries = await helius.getTransactionSummaries('7xK9...', {
30
+ * viewingPrivateKey: myViewingKey
31
+ * })
32
+ * ```
33
+ */
34
+
35
+ import { ValidationError, NetworkError } from '../../../errors'
36
+ import {
37
+ SOLANA_ADDRESS_MIN_LENGTH,
38
+ SOLANA_ADDRESS_MAX_LENGTH,
39
+ HELIUS_API_KEY_MIN_LENGTH,
40
+ sanitizeUrl,
41
+ SIP_MEMO_PREFIX,
42
+ getExplorerUrl,
43
+ } from '../constants'
44
+ import type {
45
+ EnhancedTransaction,
46
+ SIPEnhancedTransaction,
47
+ SIPTransactionMetadata,
48
+ GetTransactionHistoryOptions,
49
+ PrivacyDisplayOptions,
50
+ TransactionSummary,
51
+ EnhancedTransactionType,
52
+ } from './helius-enhanced-types'
53
+
54
+ /** Default fetch timeout in milliseconds */
55
+ const DEFAULT_FETCH_TIMEOUT_MS = 30000
56
+
57
+ /** Maximum transactions per parse request */
58
+ const MAX_PARSE_BATCH_SIZE = 100
59
+
60
+ /** Default history limit */
61
+ const DEFAULT_HISTORY_LIMIT = 100
62
+
63
+ /**
64
+ * Mask API key for safe logging/error messages
65
+ * @internal
66
+ */
67
+ function maskApiKey(apiKey: string): string {
68
+ if (apiKey.length <= HELIUS_API_KEY_MIN_LENGTH) return '***'
69
+ return `${apiKey.slice(0, 4)}...${apiKey.slice(-4)}`
70
+ }
71
+
72
+ /**
73
+ * Fetch with configurable timeout
74
+ * @internal
75
+ */
76
+ async function fetchWithTimeout(
77
+ url: string,
78
+ options: RequestInit,
79
+ timeoutMs: number = DEFAULT_FETCH_TIMEOUT_MS
80
+ ): Promise<Response> {
81
+ const controller = new AbortController()
82
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs)
83
+
84
+ try {
85
+ const response = await fetch(url, {
86
+ ...options,
87
+ signal: controller.signal,
88
+ })
89
+ return response
90
+ } catch (error) {
91
+ if (error instanceof Error && error.name === 'AbortError') {
92
+ throw new NetworkError(
93
+ `Request timeout after ${timeoutMs}ms`,
94
+ undefined,
95
+ { endpoint: sanitizeUrl(url) }
96
+ )
97
+ }
98
+ throw error
99
+ } finally {
100
+ clearTimeout(timeoutId)
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Helius Enhanced Transactions configuration
106
+ */
107
+ export interface HeliusEnhancedConfig {
108
+ /** Helius API key (required) */
109
+ apiKey: string
110
+ /** Solana cluster (default: mainnet-beta) */
111
+ cluster?: 'mainnet-beta' | 'devnet'
112
+ }
113
+
114
+ /**
115
+ * Helius Enhanced Transactions Provider
116
+ *
117
+ * Extends the base Helius provider with Enhanced Transactions API
118
+ * for human-readable transaction parsing and SIP-specific metadata extraction.
119
+ */
120
+ export class HeliusEnhanced {
121
+ private readonly apiKey: string
122
+ private readonly cluster: 'mainnet-beta' | 'devnet'
123
+ private readonly baseUrl: string
124
+
125
+ constructor(config: HeliusEnhancedConfig) {
126
+ // Validate API key
127
+ if (!config.apiKey) {
128
+ throw new ValidationError(
129
+ 'Helius API key is required. Get one at https://dev.helius.xyz',
130
+ 'apiKey'
131
+ )
132
+ }
133
+
134
+ if (typeof config.apiKey !== 'string' || config.apiKey.length < HELIUS_API_KEY_MIN_LENGTH) {
135
+ throw new ValidationError('Invalid Helius API key format', 'apiKey')
136
+ }
137
+
138
+ this.apiKey = config.apiKey
139
+ this.cluster = config.cluster ?? 'mainnet-beta'
140
+
141
+ // REST endpoint for Enhanced Transactions API
142
+ this.baseUrl = this.cluster === 'devnet'
143
+ ? 'https://api-devnet.helius.xyz/v0'
144
+ : 'https://api.helius.xyz/v0'
145
+ }
146
+
147
+ /**
148
+ * Parse one or more transactions into human-readable format
149
+ *
150
+ * @param signatures - Transaction signature(s) to parse
151
+ * @returns Array of enhanced transactions with human-readable data
152
+ *
153
+ * @example
154
+ * ```typescript
155
+ * const txs = await helius.parseTransactions(['5rfFLBUp5YPr...', 'abc123...'])
156
+ * for (const tx of txs) {
157
+ * console.log(`${tx.type}: ${tx.description}`)
158
+ * }
159
+ * ```
160
+ */
161
+ async parseTransactions(
162
+ signatures: string | string[]
163
+ ): Promise<EnhancedTransaction[]> {
164
+ const sigs = Array.isArray(signatures) ? signatures : [signatures]
165
+
166
+ // Validate signatures
167
+ if (sigs.length === 0) {
168
+ throw new ValidationError('At least one signature is required', 'signatures')
169
+ }
170
+
171
+ if (sigs.length > MAX_PARSE_BATCH_SIZE) {
172
+ throw new ValidationError(
173
+ `Maximum ${MAX_PARSE_BATCH_SIZE} transactions per request`,
174
+ 'signatures'
175
+ )
176
+ }
177
+
178
+ for (const sig of sigs) {
179
+ if (!sig || typeof sig !== 'string' || sig.length < 32) {
180
+ throw new ValidationError(`Invalid signature format: ${sig?.slice(0, 10)}...`, 'signatures')
181
+ }
182
+ }
183
+
184
+ const url = `${this.baseUrl}/transactions`
185
+
186
+ const response = await fetchWithTimeout(url, {
187
+ method: 'POST',
188
+ headers: {
189
+ 'Content-Type': 'application/json',
190
+ 'Authorization': `Bearer ${this.apiKey}`,
191
+ },
192
+ body: JSON.stringify({
193
+ transactions: sigs,
194
+ }),
195
+ })
196
+
197
+ if (!response.ok) {
198
+ throw new NetworkError(
199
+ `Helius Enhanced API error: ${response.status} ${response.statusText} (key: ${maskApiKey(this.apiKey)})`,
200
+ undefined,
201
+ { endpoint: sanitizeUrl(url), statusCode: response.status }
202
+ )
203
+ }
204
+
205
+ const data = await response.json() as EnhancedTransaction[]
206
+ return data
207
+ }
208
+
209
+ /**
210
+ * Parse a single transaction
211
+ *
212
+ * Convenience method for parsing a single transaction.
213
+ *
214
+ * @param signature - Transaction signature
215
+ * @returns Enhanced transaction or null if not found
216
+ */
217
+ async parseTransaction(signature: string): Promise<EnhancedTransaction | null> {
218
+ const results = await this.parseTransactions([signature])
219
+ return results[0] ?? null
220
+ }
221
+
222
+ /**
223
+ * Get transaction history for an address
224
+ *
225
+ * Retrieves parsed transaction history with optional type filtering.
226
+ *
227
+ * @param address - Solana address
228
+ * @param options - Filter and pagination options
229
+ * @returns Array of enhanced transactions
230
+ *
231
+ * @example
232
+ * ```typescript
233
+ * // Get all transfers
234
+ * const transfers = await helius.getTransactionHistory(address, {
235
+ * type: 'TRANSFER',
236
+ * limit: 50
237
+ * })
238
+ *
239
+ * // Get all swaps
240
+ * const swaps = await helius.getTransactionHistory(address, {
241
+ * type: 'SWAP'
242
+ * })
243
+ * ```
244
+ */
245
+ async getTransactionHistory(
246
+ address: string,
247
+ options: GetTransactionHistoryOptions = {}
248
+ ): Promise<EnhancedTransaction[]> {
249
+ // Validate address
250
+ if (!address || typeof address !== 'string') {
251
+ throw new ValidationError('address is required', 'address')
252
+ }
253
+ if (address.length < SOLANA_ADDRESS_MIN_LENGTH || address.length > SOLANA_ADDRESS_MAX_LENGTH) {
254
+ throw new ValidationError('invalid Solana address format', 'address')
255
+ }
256
+
257
+ // Build URL with query parameters
258
+ const params = new URLSearchParams()
259
+ if (options.type) {
260
+ params.set('type', options.type)
261
+ }
262
+ if (options.limit) {
263
+ params.set('limit', Math.min(options.limit, DEFAULT_HISTORY_LIMIT).toString())
264
+ }
265
+ if (options.before) {
266
+ params.set('before', options.before)
267
+ }
268
+
269
+ const queryString = params.toString()
270
+ const url = `${this.baseUrl}/addresses/${address}/transactions${queryString ? `?${queryString}` : ''}`
271
+
272
+ const response = await fetchWithTimeout(url, {
273
+ method: 'GET',
274
+ headers: {
275
+ 'Authorization': `Bearer ${this.apiKey}`,
276
+ },
277
+ })
278
+
279
+ if (!response.ok) {
280
+ throw new NetworkError(
281
+ `Helius Enhanced API error: ${response.status} ${response.statusText}`,
282
+ undefined,
283
+ { endpoint: sanitizeUrl(url), statusCode: response.status }
284
+ )
285
+ }
286
+
287
+ const data = await response.json() as EnhancedTransaction[]
288
+ return data
289
+ }
290
+
291
+ /**
292
+ * Get SIP-enhanced transactions with metadata extraction
293
+ *
294
+ * Parses transactions and extracts SIP-specific metadata from memo
295
+ * instructions (stealth addresses, view tags, encrypted amounts).
296
+ *
297
+ * @param address - Solana address
298
+ * @param options - Filter and pagination options
299
+ * @returns Transactions with SIP metadata
300
+ *
301
+ * @example
302
+ * ```typescript
303
+ * const sipTxs = await helius.getSIPTransactionHistory(address)
304
+ * for (const tx of sipTxs) {
305
+ * if (tx.sipMetadata.isSIPTransaction) {
306
+ * console.log('SIP Transfer:', tx.sipMetadata.stealthAddress)
307
+ * }
308
+ * }
309
+ * ```
310
+ */
311
+ async getSIPTransactionHistory(
312
+ address: string,
313
+ options: GetTransactionHistoryOptions = {}
314
+ ): Promise<SIPEnhancedTransaction[]> {
315
+ const transactions = await this.getTransactionHistory(address, options)
316
+
317
+ return transactions.map((tx) => ({
318
+ ...tx,
319
+ sipMetadata: this.extractSIPMetadata(tx),
320
+ }))
321
+ }
322
+
323
+ /**
324
+ * Extract SIP metadata from a transaction
325
+ *
326
+ * Parses memo program instructions to find SIP announcements.
327
+ * SIP memo format: SIP:1:<ephemeral_pubkey_base58>:<view_tag_hex>
328
+ *
329
+ * @param tx - Enhanced transaction
330
+ * @returns SIP metadata if found
331
+ * @internal
332
+ */
333
+ private extractSIPMetadata(tx: EnhancedTransaction): SIPTransactionMetadata {
334
+ const metadata: SIPTransactionMetadata = {
335
+ isSIPTransaction: false,
336
+ }
337
+
338
+ // Look for SIP memo in description or raw data
339
+ const description = tx.description || ''
340
+
341
+ // Check if this looks like a SIP transaction
342
+ // SIP transactions have a memo with format: SIP:1:<ephemeral_pubkey>:<view_tag>
343
+ if (description.includes(SIP_MEMO_PREFIX) || description.includes('SIP:')) {
344
+ metadata.isSIPTransaction = true
345
+
346
+ // Try to extract SIP memo data
347
+ // The memo format is: SIP:1:<ephemeral_pubkey_base58>:<view_tag_hex>
348
+ const sipMemoMatch = description.match(/SIP:1:([A-Za-z0-9]{32,44}):([0-9a-fA-F]{2})/)
349
+ if (sipMemoMatch) {
350
+ metadata.ephemeralPubKey = sipMemoMatch[1]
351
+ metadata.viewTag = parseInt(sipMemoMatch[2], 16)
352
+ metadata.rawMemo = sipMemoMatch[0]
353
+ }
354
+ }
355
+
356
+ // Check token transfers for potential stealth addresses
357
+ if (tx.tokenTransfers && tx.tokenTransfers.length > 0) {
358
+ const transfer = tx.tokenTransfers[0]
359
+ // If this is a SIP transaction, the recipient is likely a stealth address
360
+ if (metadata.isSIPTransaction) {
361
+ metadata.stealthAddress = transfer.toUserAccount
362
+ metadata.tokenMint = transfer.mint
363
+ }
364
+ }
365
+
366
+ // Check native transfers similarly
367
+ if (!metadata.stealthAddress && tx.nativeTransfers && tx.nativeTransfers.length > 0) {
368
+ const transfer = tx.nativeTransfers[0]
369
+ if (metadata.isSIPTransaction) {
370
+ metadata.stealthAddress = transfer.toUserAccount
371
+ }
372
+ }
373
+
374
+ return metadata
375
+ }
376
+
377
+ /**
378
+ * Get human-readable transaction summaries
379
+ *
380
+ * Provides clean summaries for UI display with privacy-aware formatting.
381
+ * Amounts are only shown to authorized viewers with the viewing key.
382
+ *
383
+ * @param address - Solana address
384
+ * @param options - Display and privacy options
385
+ * @returns Array of transaction summaries
386
+ *
387
+ * @example
388
+ * ```typescript
389
+ * // Without viewing key - amounts hidden for SIP transactions
390
+ * const summaries = await helius.getTransactionSummaries(address)
391
+ *
392
+ * // With viewing key - full details visible
393
+ * const fullSummaries = await helius.getTransactionSummaries(address, {
394
+ * viewingPrivateKey: myViewingKey
395
+ * })
396
+ * ```
397
+ */
398
+ async getTransactionSummaries(
399
+ address: string,
400
+ options: PrivacyDisplayOptions & GetTransactionHistoryOptions = {}
401
+ ): Promise<TransactionSummary[]> {
402
+ const sipTxs = await this.getSIPTransactionHistory(address, options)
403
+
404
+ return sipTxs.map((tx) => this.createSummary(tx, address, options))
405
+ }
406
+
407
+ /**
408
+ * Create a human-readable summary from an enhanced transaction
409
+ * @internal
410
+ */
411
+ private createSummary(
412
+ tx: SIPEnhancedTransaction,
413
+ viewerAddress: string,
414
+ options: PrivacyDisplayOptions
415
+ ): TransactionSummary {
416
+ const isAuthorized = this.isAuthorizedViewer(tx, options)
417
+ const isSIP = tx.sipMetadata.isSIPTransaction
418
+
419
+ // Determine transaction direction relative to viewer
420
+ const tokens = this.extractTokenInfo(tx, viewerAddress, isAuthorized || !isSIP)
421
+
422
+ // Create human-readable title
423
+ const title = this.createTitle(tx.type, tokens, isSIP)
424
+
425
+ // Create description
426
+ const description = isSIP && !isAuthorized
427
+ ? 'Shielded transaction (viewing key required for details)'
428
+ : tx.description || this.createDescription(tx.type, tokens)
429
+
430
+ return {
431
+ signature: tx.signature,
432
+ title,
433
+ description,
434
+ type: tx.type,
435
+ timestamp: new Date(tx.timestamp * 1000),
436
+ feeInSol: tx.fee / 1e9,
437
+ isAuthorizedViewer: isAuthorized,
438
+ tokens,
439
+ status: tx.transactionError ? 'failed' : 'success',
440
+ explorerUrl: getExplorerUrl(tx.signature, this.cluster),
441
+ }
442
+ }
443
+
444
+ /**
445
+ * Check if viewer is authorized to see full transaction details
446
+ * @internal
447
+ */
448
+ private isAuthorizedViewer(
449
+ tx: SIPEnhancedTransaction,
450
+ options: PrivacyDisplayOptions
451
+ ): boolean {
452
+ // If not a SIP transaction, everyone can see details
453
+ if (!tx.sipMetadata.isSIPTransaction) {
454
+ return true
455
+ }
456
+
457
+ // If no viewing key provided, not authorized
458
+ if (!options.viewingPrivateKey) {
459
+ return false
460
+ }
461
+
462
+ // TODO: Implement actual viewing key verification
463
+ // This would involve:
464
+ // 1. Deriving the shared secret from ephemeral pubkey + viewing private key
465
+ // 2. Computing the expected view tag
466
+ // 3. Comparing with the transaction's view tag
467
+ // For now, we just check if a viewing key was provided
468
+ return !!options.viewingPrivateKey
469
+ }
470
+
471
+ /**
472
+ * Extract token information from transaction
473
+ * @internal
474
+ */
475
+ private extractTokenInfo(
476
+ tx: SIPEnhancedTransaction,
477
+ viewerAddress: string,
478
+ showAmounts: boolean
479
+ ): TransactionSummary['tokens'] {
480
+ const tokens: TransactionSummary['tokens'] = []
481
+
482
+ // Process token transfers
483
+ for (const transfer of tx.tokenTransfers || []) {
484
+ const isIncoming = transfer.toUserAccount === viewerAddress
485
+ const amount = showAmounts
486
+ ? this.formatAmount(transfer.tokenAmount, transfer.decimals ?? 0)
487
+ : '***'
488
+
489
+ tokens.push({
490
+ symbol: transfer.tokenSymbol || transfer.mint.slice(0, 4) + '...',
491
+ name: transfer.tokenName,
492
+ amount,
493
+ direction: isIncoming ? 'in' : 'out',
494
+ })
495
+ }
496
+
497
+ // Process native SOL transfers
498
+ for (const transfer of tx.nativeTransfers || []) {
499
+ const isIncoming = transfer.toUserAccount === viewerAddress
500
+ const amount = showAmounts
501
+ ? this.formatAmount(transfer.amount, 9)
502
+ : '***'
503
+
504
+ tokens.push({
505
+ symbol: 'SOL',
506
+ name: 'Solana',
507
+ amount,
508
+ direction: isIncoming ? 'in' : 'out',
509
+ })
510
+ }
511
+
512
+ return tokens
513
+ }
514
+
515
+ /**
516
+ * Format amount with proper decimal places
517
+ * @internal
518
+ */
519
+ private formatAmount(amount: number, decimals: number): string {
520
+ const value = amount / Math.pow(10, decimals)
521
+ // Use appropriate precision based on value
522
+ if (value >= 1000) {
523
+ return value.toLocaleString(undefined, { maximumFractionDigits: 2 })
524
+ } else if (value >= 1) {
525
+ return value.toLocaleString(undefined, { maximumFractionDigits: 4 })
526
+ } else {
527
+ return value.toLocaleString(undefined, { maximumFractionDigits: 6 })
528
+ }
529
+ }
530
+
531
+ /**
532
+ * Create human-readable title
533
+ * @internal
534
+ */
535
+ private createTitle(
536
+ type: EnhancedTransactionType,
537
+ tokens: TransactionSummary['tokens'],
538
+ isSIP: boolean
539
+ ): string {
540
+ const prefix = isSIP ? 'Shielded ' : ''
541
+
542
+ switch (type) {
543
+ case 'TRANSFER':
544
+ if (tokens.length > 0) {
545
+ const token = tokens[0]
546
+ return `${prefix}${token.direction === 'in' ? 'Received' : 'Sent'} ${token.symbol}`
547
+ }
548
+ return `${prefix}Transfer`
549
+
550
+ case 'SWAP':
551
+ return `${prefix}Swap`
552
+
553
+ case 'NFT_SALE':
554
+ return 'NFT Sale'
555
+
556
+ case 'NFT_MINT':
557
+ case 'COMPRESSED_NFT_MINT':
558
+ return 'NFT Mint'
559
+
560
+ case 'ADD_LIQUIDITY':
561
+ return 'Added Liquidity'
562
+
563
+ case 'REMOVE_LIQUIDITY':
564
+ return 'Removed Liquidity'
565
+
566
+ case 'STAKE':
567
+ return 'Staked'
568
+
569
+ case 'UNSTAKE':
570
+ return 'Unstaked'
571
+
572
+ case 'CLAIM_REWARDS':
573
+ return 'Claimed Rewards'
574
+
575
+ default:
576
+ return `${prefix}${type.replace(/_/g, ' ').toLowerCase()}`
577
+ }
578
+ }
579
+
580
+ /**
581
+ * Create human-readable description
582
+ * @internal
583
+ */
584
+ private createDescription(
585
+ type: EnhancedTransactionType,
586
+ tokens: TransactionSummary['tokens']
587
+ ): string {
588
+ switch (type) {
589
+ case 'TRANSFER':
590
+ if (tokens.length > 0) {
591
+ const token = tokens[0]
592
+ const action = token.direction === 'in' ? 'Received' : 'Sent'
593
+ const amountStr = token.amount !== '***' ? `${token.amount} ` : ''
594
+ return `${action} ${amountStr}${token.symbol}`
595
+ }
596
+ return 'Token transfer'
597
+
598
+ case 'SWAP': {
599
+ const inputs = tokens.filter(t => t.direction === 'out')
600
+ const outputs = tokens.filter(t => t.direction === 'in')
601
+ if (inputs.length > 0 && outputs.length > 0) {
602
+ return `Swapped ${inputs[0].symbol} for ${outputs[0].symbol}`
603
+ }
604
+ return 'Token swap'
605
+ }
606
+
607
+ default:
608
+ return `${type.replace(/_/g, ' ').toLowerCase()} transaction`
609
+ }
610
+ }
611
+ }
612
+
613
+ /**
614
+ * Create a HeliusEnhanced instance
615
+ *
616
+ * Factory function for creating enhanced transactions provider.
617
+ *
618
+ * @param config - Provider configuration
619
+ * @returns HeliusEnhanced instance
620
+ */
621
+ export function createHeliusEnhanced(config: HeliusEnhancedConfig): HeliusEnhanced {
622
+ return new HeliusEnhanced(config)
623
+ }