@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,571 @@
1
+ /**
2
+ * Jupiter DEX Adapter for SIP Protocol
3
+ *
4
+ * Enables privacy-preserving token swaps on Solana via Jupiter aggregator.
5
+ * SIP adds stealth addresses for recipient privacy and viewing keys for compliance.
6
+ *
7
+ * ## Privacy Model
8
+ *
9
+ * Jupiter swaps are on-chain and transparent by default. SIP enhances privacy by:
10
+ * - Sending output tokens to a stealth address (recipient unlinkable)
11
+ * - Encrypting swap metadata with viewing keys (selective disclosure)
12
+ *
13
+ * ```
14
+ * ┌──────────────────────────────────────────────────────────────┐
15
+ * │ JUPITER + SIP PRIVACY FLOW │
16
+ * │ │
17
+ * │ 1. User: "Swap 1 SOL → USDC privately" │
18
+ * │ 2. SIP: Generate stealth address for USDC output │
19
+ * │ 3. Jupiter: Get quote, find best route │
20
+ * │ 4. Jupiter: Execute swap → output to stealth address │
21
+ * │ 5. SIP: Encrypt metadata with viewing key (compliance) │
22
+ * │ │
23
+ * │ Result: Swap on-chain, but recipient unlinkable │
24
+ * └──────────────────────────────────────────────────────────────┘
25
+ * ```
26
+ *
27
+ * @see https://station.jup.ag/docs
28
+ * @see https://github.com/jup-ag/jupiter-quote-api-node
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * import { JupiterAdapter } from '@sip-protocol/sdk'
33
+ * import { Keypair } from '@solana/web3.js'
34
+ *
35
+ * const adapter = new JupiterAdapter({
36
+ * rpcUrl: 'https://api.mainnet-beta.solana.com',
37
+ * })
38
+ *
39
+ * // Get a quote
40
+ * const quote = await adapter.getQuote({
41
+ * inputMint: 'So11111111111111111111111111111111111111112', // SOL
42
+ * outputMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC
43
+ * amount: 1_000_000_000n, // 1 SOL
44
+ * })
45
+ *
46
+ * // Execute private swap (output to stealth address)
47
+ * const result = await adapter.swapPrivate({
48
+ * quote,
49
+ * wallet: userKeypair,
50
+ * recipientMetaAddress: 'sip:solana:0x...:0x...',
51
+ * })
52
+ *
53
+ * console.log('Swap complete:', result.signature)
54
+ * console.log('Output at stealth address:', result.stealthAddress)
55
+ * ```
56
+ */
57
+
58
+ import { createJupiterApiClient, type QuoteResponse } from '@jup-ag/api'
59
+ import {
60
+ Connection,
61
+ PublicKey,
62
+ VersionedTransaction,
63
+ type Keypair,
64
+ } from '@solana/web3.js'
65
+ import type { StealthMetaAddress, HexString, ViewingKey } from '@sip-protocol/types'
66
+ import {
67
+ generateEd25519StealthAddress,
68
+ decodeStealthMetaAddress,
69
+ ed25519PublicKeyToSolanaAddress,
70
+ } from '../stealth'
71
+ import { generateViewingKey, encryptForViewing, type TransactionData } from '../privacy'
72
+ import { bytesToHex } from '@noble/hashes/utils'
73
+
74
+ // ─── Constants ────────────────────────────────────────────────────────────────
75
+
76
+ /**
77
+ * Common Solana token mints
78
+ */
79
+ export const SOLANA_TOKEN_MINTS = {
80
+ SOL: 'So11111111111111111111111111111111111111112',
81
+ USDC: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
82
+ USDT: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',
83
+ BONK: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263',
84
+ JUP: 'JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN',
85
+ RAY: '4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R',
86
+ ORCA: 'orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE',
87
+ } as const
88
+
89
+ /**
90
+ * Default Jupiter API endpoint
91
+ */
92
+ export const JUPITER_API_ENDPOINT = 'https://quote-api.jup.ag/v6'
93
+
94
+ /**
95
+ * Default RPC endpoints
96
+ */
97
+ export const SOLANA_RPC_ENDPOINTS = {
98
+ mainnet: 'https://api.mainnet-beta.solana.com',
99
+ devnet: 'https://api.devnet.solana.com',
100
+ } as const
101
+
102
+ // ─── Types ────────────────────────────────────────────────────────────────────
103
+
104
+ /**
105
+ * Jupiter adapter configuration
106
+ */
107
+ export interface JupiterAdapterConfig {
108
+ /** Solana RPC URL */
109
+ rpcUrl?: string
110
+ /** Jupiter API key (optional, for higher rate limits) */
111
+ apiKey?: string
112
+ /** Default slippage in basis points (default: 50 = 0.5%) */
113
+ defaultSlippageBps?: number
114
+ /** Enable debug logging */
115
+ debug?: boolean
116
+ }
117
+
118
+ /**
119
+ * Quote request parameters
120
+ */
121
+ export interface JupiterQuoteRequest {
122
+ /** Input token mint address */
123
+ inputMint: string
124
+ /** Output token mint address */
125
+ outputMint: string
126
+ /** Input amount in smallest units (lamports for SOL) */
127
+ amount: bigint
128
+ /** Slippage tolerance in basis points (overrides default) */
129
+ slippageBps?: number
130
+ /** Only use direct routes (no multi-hop) */
131
+ onlyDirectRoutes?: boolean
132
+ /** Exclude specific DEXes */
133
+ excludeDexes?: string[]
134
+ }
135
+
136
+ /**
137
+ * Enhanced quote with SIP metadata
138
+ */
139
+ export interface JupiterQuote {
140
+ /** Raw Jupiter quote response */
141
+ raw: QuoteResponse
142
+ /** Input mint */
143
+ inputMint: string
144
+ /** Output mint */
145
+ outputMint: string
146
+ /** Input amount */
147
+ inputAmount: bigint
148
+ /** Expected output amount */
149
+ outputAmount: bigint
150
+ /** Minimum output after slippage */
151
+ minOutputAmount: bigint
152
+ /** Price impact percentage */
153
+ priceImpactPct: number
154
+ /** Route description */
155
+ route: string[]
156
+ /** Slippage in basis points */
157
+ slippageBps: number
158
+ }
159
+
160
+ /**
161
+ * Standard swap parameters (transparent)
162
+ */
163
+ export interface JupiterSwapParams {
164
+ /** Quote from getQuote() */
165
+ quote: JupiterQuote
166
+ /** User's wallet keypair for signing */
167
+ wallet: Keypair
168
+ /** Recipient address (defaults to wallet public key) */
169
+ recipient?: string
170
+ /** Priority fee in lamports (or 'auto') */
171
+ priorityFee?: number | 'auto'
172
+ }
173
+
174
+ /**
175
+ * Private swap parameters (with stealth address)
176
+ */
177
+ export interface JupiterPrivateSwapParams extends Omit<JupiterSwapParams, 'recipient'> {
178
+ /** Recipient's stealth meta-address */
179
+ recipientMetaAddress: StealthMetaAddress | string
180
+ /** Generate viewing key for compliance */
181
+ generateViewingKey?: boolean
182
+ /** Existing viewing key to use */
183
+ viewingKey?: ViewingKey
184
+ }
185
+
186
+ /**
187
+ * Swap result
188
+ */
189
+ export interface JupiterSwapResult {
190
+ /** Whether swap succeeded */
191
+ success: boolean
192
+ /** Transaction signature */
193
+ signature?: string
194
+ /** Input amount swapped */
195
+ inputAmount?: bigint
196
+ /** Output amount received */
197
+ outputAmount?: bigint
198
+ /** Recipient address */
199
+ recipient?: string
200
+ /** Error message if failed */
201
+ error?: string
202
+ }
203
+
204
+ /**
205
+ * Private swap result (with stealth data)
206
+ */
207
+ export interface JupiterPrivateSwapResult extends JupiterSwapResult {
208
+ /** Stealth address where output was sent */
209
+ stealthAddress?: string
210
+ /** Ephemeral public key for recipient to derive stealth key */
211
+ ephemeralPublicKey?: HexString
212
+ /** View tag for efficient scanning */
213
+ viewTag?: number
214
+ /** Shared secret (for recipient to derive private key) */
215
+ sharedSecret?: HexString
216
+ /** Encrypted metadata for viewing key holders */
217
+ encryptedMetadata?: HexString
218
+ /** Viewing key (if generated) */
219
+ viewingKey?: ViewingKey
220
+ }
221
+
222
+ // ─── Jupiter Adapter ──────────────────────────────────────────────────────────
223
+
224
+ /**
225
+ * Jupiter DEX Adapter
226
+ *
227
+ * Provides privacy-enhanced token swaps on Solana via Jupiter aggregator.
228
+ */
229
+ export class JupiterAdapter {
230
+ private readonly connection: Connection
231
+ private readonly jupiterApi: ReturnType<typeof createJupiterApiClient>
232
+ private readonly defaultSlippageBps: number
233
+ private readonly debug: boolean
234
+
235
+ constructor(config: JupiterAdapterConfig = {}) {
236
+ const rpcUrl = config.rpcUrl ?? SOLANA_RPC_ENDPOINTS.mainnet
237
+ this.connection = new Connection(rpcUrl, 'confirmed')
238
+
239
+ // Initialize Jupiter API client
240
+ // Note: apiKey is passed if available for higher rate limits
241
+ this.jupiterApi = createJupiterApiClient()
242
+
243
+ this.defaultSlippageBps = config.defaultSlippageBps ?? 50 // 0.5%
244
+ this.debug = config.debug ?? false
245
+ }
246
+
247
+ // ─── Quote Methods ────────────────────────────────────────────────────────────
248
+
249
+ /**
250
+ * Get a swap quote from Jupiter
251
+ *
252
+ * @param request - Quote request parameters
253
+ * @returns Quote with routing info
254
+ */
255
+ async getQuote(request: JupiterQuoteRequest): Promise<JupiterQuote> {
256
+ this.log('Getting quote:', request)
257
+
258
+ const slippageBps = request.slippageBps ?? this.defaultSlippageBps
259
+
260
+ // Jupiter API requires amount as number
261
+ const amount = Number(request.amount)
262
+ if (!Number.isSafeInteger(amount)) {
263
+ throw new Error('Amount too large for Jupiter API')
264
+ }
265
+
266
+ const quoteResponse = await this.jupiterApi.quoteGet({
267
+ inputMint: request.inputMint,
268
+ outputMint: request.outputMint,
269
+ amount,
270
+ slippageBps,
271
+ onlyDirectRoutes: request.onlyDirectRoutes,
272
+ excludeDexes: request.excludeDexes,
273
+ })
274
+
275
+ if (!quoteResponse) {
276
+ throw new Error('Failed to get quote from Jupiter')
277
+ }
278
+
279
+ // Extract route names
280
+ const route = quoteResponse.routePlan?.map(step => step.swapInfo?.label ?? 'Unknown') ?? []
281
+
282
+ const quote: JupiterQuote = {
283
+ raw: quoteResponse,
284
+ inputMint: quoteResponse.inputMint,
285
+ outputMint: quoteResponse.outputMint,
286
+ inputAmount: BigInt(quoteResponse.inAmount),
287
+ outputAmount: BigInt(quoteResponse.outAmount),
288
+ minOutputAmount: BigInt(quoteResponse.otherAmountThreshold),
289
+ priceImpactPct: parseFloat(quoteResponse.priceImpactPct ?? '0'),
290
+ route,
291
+ slippageBps,
292
+ }
293
+
294
+ this.log('Quote received:', {
295
+ inputAmount: quote.inputAmount.toString(),
296
+ outputAmount: quote.outputAmount.toString(),
297
+ route: quote.route,
298
+ })
299
+
300
+ return quote
301
+ }
302
+
303
+ // ─── Swap Methods ─────────────────────────────────────────────────────────────
304
+
305
+ /**
306
+ * Execute a standard (transparent) swap
307
+ *
308
+ * @param params - Swap parameters
309
+ * @returns Swap result
310
+ */
311
+ async swap(params: JupiterSwapParams): Promise<JupiterSwapResult> {
312
+ this.log('Executing swap')
313
+
314
+ try {
315
+ const recipient = params.recipient ?? params.wallet.publicKey.toBase58()
316
+
317
+ // Get swap transaction from Jupiter
318
+ // Note: prioritizationFeeLamports requires specific object format
319
+ const priorityFeeConfig = params.priorityFee === 'auto'
320
+ ? { priorityLevelWithMaxLamports: { priorityLevel: 'high' as const, maxLamports: 1000000 } }
321
+ : typeof params.priorityFee === 'number'
322
+ ? { jitoTipLamports: params.priorityFee }
323
+ : undefined
324
+
325
+ const swapResponse = await this.jupiterApi.swapPost({
326
+ swapRequest: {
327
+ quoteResponse: params.quote.raw,
328
+ userPublicKey: params.wallet.publicKey.toBase58(),
329
+ destinationTokenAccount: recipient !== params.wallet.publicKey.toBase58()
330
+ ? recipient
331
+ : undefined,
332
+ prioritizationFeeLamports: priorityFeeConfig,
333
+ },
334
+ })
335
+
336
+ // Deserialize and sign transaction
337
+ const swapTransactionBuf = Buffer.from(swapResponse.swapTransaction, 'base64')
338
+ const transaction = VersionedTransaction.deserialize(swapTransactionBuf)
339
+ transaction.sign([params.wallet])
340
+
341
+ // Send transaction
342
+ const signature = await this.connection.sendRawTransaction(
343
+ transaction.serialize(),
344
+ {
345
+ skipPreflight: false,
346
+ maxRetries: 3,
347
+ }
348
+ )
349
+
350
+ this.log('Transaction sent:', signature)
351
+
352
+ // Confirm transaction
353
+ const latestBlockhash = await this.connection.getLatestBlockhash()
354
+ await this.connection.confirmTransaction({
355
+ signature,
356
+ blockhash: latestBlockhash.blockhash,
357
+ lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
358
+ }, 'confirmed')
359
+
360
+ this.log('Transaction confirmed')
361
+
362
+ return {
363
+ success: true,
364
+ signature,
365
+ inputAmount: params.quote.inputAmount,
366
+ outputAmount: params.quote.outputAmount,
367
+ recipient,
368
+ }
369
+ } catch (error) {
370
+ return {
371
+ success: false,
372
+ error: this.formatError(error),
373
+ }
374
+ }
375
+ }
376
+
377
+ /**
378
+ * Execute a private swap with stealth recipient
379
+ *
380
+ * Output tokens are sent to a stealth address derived from the recipient's
381
+ * meta-address. The recipient can later claim using their spending key.
382
+ *
383
+ * @param params - Private swap parameters
384
+ * @returns Private swap result with stealth data
385
+ */
386
+ async swapPrivate(params: JupiterPrivateSwapParams): Promise<JupiterPrivateSwapResult> {
387
+ this.log('Executing private swap')
388
+
389
+ try {
390
+ // Decode meta-address if string
391
+ const metaAddress = typeof params.recipientMetaAddress === 'string'
392
+ ? decodeStealthMetaAddress(params.recipientMetaAddress)
393
+ : params.recipientMetaAddress
394
+
395
+ // Validate ed25519 keys (Solana uses ed25519)
396
+ const spendingKeyBytes = (metaAddress.spendingKey.length - 2) / 2
397
+ if (spendingKeyBytes !== 32) {
398
+ return {
399
+ success: false,
400
+ error: `Meta-address has ${spendingKeyBytes}-byte keys but Solana requires ed25519 (32-byte) keys. ` +
401
+ 'Generate an ed25519 meta-address using generateEd25519StealthMetaAddress().',
402
+ }
403
+ }
404
+
405
+ // Generate stealth address
406
+ const { stealthAddress, sharedSecret } = generateEd25519StealthAddress(metaAddress)
407
+
408
+ // Convert stealth public key to Solana address
409
+ const solanaStealthAddress = ed25519PublicKeyToSolanaAddress(stealthAddress.address)
410
+
411
+ this.log('Generated stealth address:', solanaStealthAddress)
412
+
413
+ // Execute swap with stealth address as recipient
414
+ const swapResult = await this.swap({
415
+ ...params,
416
+ recipient: solanaStealthAddress,
417
+ })
418
+
419
+ if (!swapResult.success) {
420
+ return {
421
+ ...swapResult,
422
+ stealthAddress: solanaStealthAddress,
423
+ }
424
+ }
425
+
426
+ // Prepare result with stealth data
427
+ const result: JupiterPrivateSwapResult = {
428
+ ...swapResult,
429
+ stealthAddress: solanaStealthAddress,
430
+ ephemeralPublicKey: stealthAddress.ephemeralPublicKey,
431
+ viewTag: stealthAddress.viewTag,
432
+ sharedSecret,
433
+ }
434
+
435
+ // Generate viewing key and encrypt metadata if requested
436
+ if (params.generateViewingKey || params.viewingKey) {
437
+ const viewingKey = params.viewingKey ?? generateViewingKey()
438
+
439
+ // TransactionData requires sender, recipient, amount, timestamp
440
+ // We encode additional swap metadata in the amount field as JSON
441
+ const swapMetadata = JSON.stringify({
442
+ type: 'jupiter_private_swap',
443
+ signature: swapResult.signature,
444
+ inputMint: params.quote.inputMint,
445
+ outputMint: params.quote.outputMint,
446
+ inputAmount: params.quote.inputAmount.toString(),
447
+ outputAmount: params.quote.outputAmount.toString(),
448
+ ephemeralPublicKey: stealthAddress.ephemeralPublicKey,
449
+ })
450
+
451
+ const txData: TransactionData = {
452
+ sender: params.wallet.publicKey.toBase58(),
453
+ recipient: solanaStealthAddress,
454
+ amount: swapMetadata, // Encode metadata in amount field
455
+ timestamp: Date.now(),
456
+ }
457
+
458
+ const encrypted = encryptForViewing(txData, viewingKey)
459
+ const jsonBytes = new TextEncoder().encode(JSON.stringify(encrypted))
460
+ result.encryptedMetadata = `0x${bytesToHex(jsonBytes)}` as HexString
461
+
462
+ if (params.generateViewingKey) {
463
+ result.viewingKey = viewingKey
464
+ }
465
+ }
466
+
467
+ return result
468
+ } catch (error) {
469
+ return {
470
+ success: false,
471
+ error: this.formatError(error),
472
+ }
473
+ }
474
+ }
475
+
476
+ // ─── Utility Methods ──────────────────────────────────────────────────────────
477
+
478
+ /**
479
+ * Check if a token is supported by Jupiter
480
+ *
481
+ * @param mint - Token mint address
482
+ * @returns Whether token is tradeable
483
+ */
484
+ async isTokenSupported(mint: string): Promise<boolean> {
485
+ try {
486
+ // Try to get a small quote to SOL
487
+ const quote = await this.jupiterApi.quoteGet({
488
+ inputMint: mint,
489
+ outputMint: SOLANA_TOKEN_MINTS.SOL,
490
+ amount: 1000000, // 0.001 of any token (6 decimals)
491
+ slippageBps: 100,
492
+ })
493
+ return !!quote
494
+ } catch {
495
+ return false
496
+ }
497
+ }
498
+
499
+ /**
500
+ * Get the underlying Solana connection
501
+ */
502
+ getConnection(): Connection {
503
+ return this.connection
504
+ }
505
+
506
+ /**
507
+ * Get token balance for an address
508
+ *
509
+ * @param owner - Wallet address
510
+ * @param mint - Token mint (omit for SOL)
511
+ * @returns Balance in smallest units
512
+ */
513
+ async getBalance(owner: string, mint?: string): Promise<bigint> {
514
+ const ownerPubkey = new PublicKey(owner)
515
+
516
+ if (!mint || mint === SOLANA_TOKEN_MINTS.SOL) {
517
+ const balance = await this.connection.getBalance(ownerPubkey)
518
+ return BigInt(balance)
519
+ }
520
+
521
+ // Get SPL token balance
522
+ const mintPubkey = new PublicKey(mint)
523
+ const tokenAccounts = await this.connection.getTokenAccountsByOwner(
524
+ ownerPubkey,
525
+ { mint: mintPubkey }
526
+ )
527
+
528
+ if (tokenAccounts.value.length === 0) {
529
+ return 0n
530
+ }
531
+
532
+ // Parse account data to get balance
533
+ // Token account data: 64 bytes mint + 32 bytes owner + 8 bytes amount + ...
534
+ const accountData = tokenAccounts.value[0].account.data
535
+ const amountBytes = accountData.subarray(64, 72)
536
+ const amount = new DataView(amountBytes.buffer, amountBytes.byteOffset).getBigUint64(0, true)
537
+
538
+ return amount
539
+ }
540
+
541
+ // ─── Private Helpers ──────────────────────────────────────────────────────────
542
+
543
+ private log(...args: unknown[]): void {
544
+ if (this.debug) {
545
+ console.log('[JupiterAdapter]', ...args)
546
+ }
547
+ }
548
+
549
+ private formatError(error: unknown): string {
550
+ if (error instanceof Error) {
551
+ if (error.message.includes('insufficient')) {
552
+ return 'Insufficient balance for swap'
553
+ }
554
+ if (error.message.includes('slippage')) {
555
+ return 'Slippage tolerance exceeded'
556
+ }
557
+ if (error.message.includes('route')) {
558
+ return 'No route found for this swap'
559
+ }
560
+ return error.message
561
+ }
562
+ return 'Unknown Jupiter error'
563
+ }
564
+ }
565
+
566
+ /**
567
+ * Create a Jupiter adapter with default configuration
568
+ */
569
+ export function createJupiterAdapter(config?: JupiterAdapterConfig): JupiterAdapter {
570
+ return new JupiterAdapter(config)
571
+ }