@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,687 @@
1
+ /**
2
+ * Jito Relayer for SIP Protocol
3
+ *
4
+ * Enables gas abstraction for Solana shielded transactions using Jito's MEV infrastructure.
5
+ * The relayer submits transaction bundles on behalf of users, paying gas fees and breaking
6
+ * the direct link between the user's wallet and the privacy transaction.
7
+ *
8
+ * ## Why Jito?
9
+ *
10
+ * 1. **Native Solana**: Jito is battle-tested MEV infrastructure on Solana
11
+ * 2. **No Dedicated Server**: Uses Jito's network, no VPS maintenance needed
12
+ * 3. **Bundle Guarantees**: Atomic execution, no partial failures
13
+ * 4. **Lower Regulatory Risk**: Relayer only handles gas, not asset movement
14
+ *
15
+ * ## Architecture
16
+ *
17
+ * ```
18
+ * ┌─────────────────────────────────────────────────────────────────────────────┐
19
+ * │ GAS ABSTRACTION FLOW │
20
+ * │ │
21
+ * │ ┌─────────┐ ┌───────────────┐ ┌───────────┐ ┌──────────┐ │
22
+ * │ │ User │ ──▶ │ Sign TX │ ──▶ │ Jito │ ──▶ │ Solana │ │
23
+ * │ │ Wallet │ │ (no SOL fee) │ │ Relayer │ │ Network │ │
24
+ * │ └─────────┘ └───────────────┘ └───────────┘ └──────────┘ │
25
+ * │ │ │
26
+ * │ ▼ │
27
+ * │ Relayer pays │
28
+ * │ gas from tip │
29
+ * └─────────────────────────────────────────────────────────────────────────────┘
30
+ * ```
31
+ *
32
+ * ## Fee Model
33
+ *
34
+ * The relayer takes a small tip from the transaction (configurable, typically 0.1-0.5%)
35
+ * to cover gas costs and operational overhead.
36
+ *
37
+ * @see https://jito-foundation.gitbook.io/mev/
38
+ * @see https://jito-labs.github.io/jito-ts/
39
+ */
40
+
41
+ import {
42
+ Connection,
43
+ PublicKey,
44
+ VersionedTransaction,
45
+ Transaction,
46
+ SystemProgram,
47
+ type Keypair,
48
+ type TransactionInstruction,
49
+ } from '@solana/web3.js'
50
+ import { bytesToHex } from '@noble/hashes/utils'
51
+
52
+ // ─── Constants ────────────────────────────────────────────────────────────────
53
+
54
+ /**
55
+ * Jito Block Engine endpoints
56
+ * @see https://jito-foundation.gitbook.io/mev/searcher-resources/block-engine
57
+ */
58
+ export const JITO_BLOCK_ENGINES = {
59
+ mainnet: {
60
+ amsterdam: 'https://amsterdam.mainnet.block-engine.jito.wtf/api/v1',
61
+ frankfurt: 'https://frankfurt.mainnet.block-engine.jito.wtf/api/v1',
62
+ ny: 'https://ny.mainnet.block-engine.jito.wtf/api/v1',
63
+ tokyo: 'https://tokyo.mainnet.block-engine.jito.wtf/api/v1',
64
+ },
65
+ // Jito doesn't have devnet block engines - use simulation for testing
66
+ } as const
67
+
68
+ /**
69
+ * Jito tip accounts (one must receive the tip)
70
+ * @see https://jito-foundation.gitbook.io/mev/searcher-resources/tip-accounts
71
+ */
72
+ export const JITO_TIP_ACCOUNTS = [
73
+ '96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5',
74
+ 'HFqU5x63VTqvQss8hp11i4bVmkekGTo46ibhvdrPnSVX',
75
+ 'Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY',
76
+ 'ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49',
77
+ 'DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh',
78
+ 'ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt',
79
+ 'DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL',
80
+ '3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT',
81
+ ] as const
82
+
83
+ /**
84
+ * Default configuration values
85
+ */
86
+ export const JITO_DEFAULTS = {
87
+ /** Default tip in lamports (0.001 SOL) */
88
+ tipLamports: 1_000_000,
89
+ /** Maximum bundle size */
90
+ maxBundleSize: 5,
91
+ /** Bundle submission timeout (ms) */
92
+ submissionTimeout: 30_000,
93
+ /** Confirmation timeout (ms) */
94
+ confirmationTimeout: 60_000,
95
+ /** Default retry attempts */
96
+ maxRetries: 3,
97
+ } as const
98
+
99
+ // ─── Types ────────────────────────────────────────────────────────────────────
100
+
101
+ /**
102
+ * Jito relayer configuration
103
+ */
104
+ export interface JitoRelayerConfig {
105
+ /** Jito block engine endpoint */
106
+ blockEngineUrl?: string
107
+ /** Solana RPC URL */
108
+ rpcUrl?: string
109
+ /** Default tip amount in lamports */
110
+ defaultTipLamports?: number
111
+ /** Enable debug logging */
112
+ debug?: boolean
113
+ /** Maximum retries for bundle submission */
114
+ maxRetries?: number
115
+ /** Submission timeout in ms */
116
+ submissionTimeout?: number
117
+ }
118
+
119
+ /**
120
+ * Bundle submission request
121
+ */
122
+ export interface JitoBundleRequest {
123
+ /** Transactions to include in bundle */
124
+ transactions: (Transaction | VersionedTransaction)[]
125
+ /** Tip amount in lamports */
126
+ tipLamports?: number
127
+ /** Tip payer keypair */
128
+ tipPayer: Keypair
129
+ /** Whether to wait for confirmation */
130
+ waitForConfirmation?: boolean
131
+ }
132
+
133
+ /**
134
+ * Bundle submission result
135
+ */
136
+ export interface JitoBundleResult {
137
+ /** Bundle UUID */
138
+ bundleId: string
139
+ /** Transaction signatures in bundle */
140
+ signatures: string[]
141
+ /** Submission status */
142
+ status: 'submitted' | 'landed' | 'failed' | 'timeout'
143
+ /** Slot where bundle landed (if confirmed) */
144
+ slot?: number
145
+ /** Error message if failed */
146
+ error?: string
147
+ /** Actual tip paid in lamports */
148
+ tipPaid: number
149
+ }
150
+
151
+ /**
152
+ * Relayed transaction request
153
+ */
154
+ export interface RelayedTransactionRequest {
155
+ /** Signed transaction to relay */
156
+ transaction: Transaction | VersionedTransaction
157
+ /** Tip amount in lamports (paid by relayer, recovered from user) */
158
+ tipLamports?: number
159
+ /** Whether to wait for confirmation */
160
+ waitForConfirmation?: boolean
161
+ }
162
+
163
+ /**
164
+ * Relayed transaction result
165
+ */
166
+ export interface RelayedTransactionResult {
167
+ /** Transaction signature */
168
+ signature: string
169
+ /** Bundle ID if submitted via Jito */
170
+ bundleId?: string
171
+ /** Submission status */
172
+ status: 'submitted' | 'confirmed' | 'failed'
173
+ /** Slot where transaction landed */
174
+ slot?: number
175
+ /** Error message if failed */
176
+ error?: string
177
+ /** Whether relayer was used or fell back to direct submission */
178
+ relayed: boolean
179
+ }
180
+
181
+ /**
182
+ * Bundle status from Jito API
183
+ */
184
+ interface JitoBundleStatus {
185
+ bundleId: string
186
+ status: 'Invalid' | 'Pending' | 'Failed' | 'Landed'
187
+ landedSlot?: number
188
+ error?: string
189
+ }
190
+
191
+ // ─── Errors ───────────────────────────────────────────────────────────────────
192
+
193
+ /**
194
+ * Jito relayer error codes
195
+ */
196
+ export enum JitoRelayerErrorCode {
197
+ BUNDLE_SUBMISSION_FAILED = 'BUNDLE_SUBMISSION_FAILED',
198
+ BUNDLE_TIMEOUT = 'BUNDLE_TIMEOUT',
199
+ BUNDLE_INVALID = 'BUNDLE_INVALID',
200
+ INSUFFICIENT_TIP = 'INSUFFICIENT_TIP',
201
+ CONNECTION_ERROR = 'CONNECTION_ERROR',
202
+ RATE_LIMITED = 'RATE_LIMITED',
203
+ INVALID_TRANSACTION = 'INVALID_TRANSACTION',
204
+ }
205
+
206
+ /**
207
+ * Jito relayer error
208
+ */
209
+ export class JitoRelayerError extends Error {
210
+ constructor(
211
+ public readonly code: JitoRelayerErrorCode,
212
+ message: string,
213
+ public readonly details?: unknown
214
+ ) {
215
+ super(`[${code}] ${message}`)
216
+ this.name = 'JitoRelayerError'
217
+ }
218
+ }
219
+
220
+ // ─── Jito Relayer ─────────────────────────────────────────────────────────────
221
+
222
+ /**
223
+ * Jito Relayer for gas abstraction
224
+ *
225
+ * Submits Solana transactions via Jito's MEV infrastructure,
226
+ * enabling gas abstraction for privacy transactions.
227
+ *
228
+ * @example
229
+ * ```typescript
230
+ * import { JitoRelayer } from '@sip-protocol/sdk'
231
+ *
232
+ * const relayer = new JitoRelayer({
233
+ * blockEngineUrl: 'https://ny.mainnet.block-engine.jito.wtf/api/v1',
234
+ * })
235
+ *
236
+ * // Submit a signed transaction via relayer
237
+ * const result = await relayer.relayTransaction({
238
+ * transaction: signedTx,
239
+ * tipLamports: 10_000, // 0.00001 SOL tip
240
+ * })
241
+ *
242
+ * console.log('Transaction relayed:', result.signature)
243
+ * ```
244
+ */
245
+ export class JitoRelayer {
246
+ private readonly connection: Connection
247
+ private readonly blockEngineUrl: string
248
+ private readonly defaultTipLamports: number
249
+ private readonly debug: boolean
250
+ private readonly maxRetries: number
251
+ private readonly submissionTimeout: number
252
+
253
+ constructor(config: JitoRelayerConfig = {}) {
254
+ this.blockEngineUrl = config.blockEngineUrl ?? JITO_BLOCK_ENGINES.mainnet.ny
255
+ this.connection = new Connection(
256
+ config.rpcUrl ?? 'https://api.mainnet-beta.solana.com',
257
+ 'confirmed'
258
+ )
259
+ this.defaultTipLamports = config.defaultTipLamports ?? JITO_DEFAULTS.tipLamports
260
+ this.debug = config.debug ?? false
261
+ this.maxRetries = config.maxRetries ?? JITO_DEFAULTS.maxRetries
262
+ this.submissionTimeout = config.submissionTimeout ?? JITO_DEFAULTS.submissionTimeout
263
+ }
264
+
265
+ // ─── Public Methods ─────────────────────────────────────────────────────────
266
+
267
+ /**
268
+ * Submit a bundle of transactions to Jito
269
+ *
270
+ * @param request - Bundle request with transactions and tip
271
+ * @returns Bundle submission result
272
+ */
273
+ async submitBundle(request: JitoBundleRequest): Promise<JitoBundleResult> {
274
+ const tipLamports = request.tipLamports ?? this.defaultTipLamports
275
+
276
+ this.log('Submitting bundle:', {
277
+ transactionCount: request.transactions.length,
278
+ tipLamports,
279
+ })
280
+
281
+ // Validate bundle size
282
+ if (request.transactions.length > JITO_DEFAULTS.maxBundleSize) {
283
+ throw new JitoRelayerError(
284
+ JitoRelayerErrorCode.INVALID_TRANSACTION,
285
+ `Bundle too large: ${request.transactions.length} > ${JITO_DEFAULTS.maxBundleSize}`
286
+ )
287
+ }
288
+
289
+ // Create tip instruction
290
+ const tipInstruction = this.createTipInstruction(request.tipPayer.publicKey, tipLamports)
291
+
292
+ // Get recent blockhash
293
+ const { blockhash, lastValidBlockHeight } = await this.connection.getLatestBlockhash()
294
+
295
+ // Add tip to the first transaction or create a standalone tip tx
296
+ const bundleTransactions = await this.prepareBundleTransactions(
297
+ request.transactions,
298
+ tipInstruction,
299
+ request.tipPayer,
300
+ blockhash
301
+ )
302
+
303
+ // Serialize transactions
304
+ const serializedTxs = bundleTransactions.map(tx => {
305
+ const serialized = tx.serialize()
306
+ return Buffer.from(serialized).toString('base64')
307
+ })
308
+
309
+ // Submit bundle
310
+ let bundleId: string
311
+ let retries = 0
312
+
313
+ while (retries < this.maxRetries) {
314
+ try {
315
+ bundleId = await this.sendBundle(serializedTxs)
316
+ break
317
+ } catch (error) {
318
+ retries++
319
+ if (retries >= this.maxRetries) {
320
+ throw new JitoRelayerError(
321
+ JitoRelayerErrorCode.BUNDLE_SUBMISSION_FAILED,
322
+ `Failed to submit bundle after ${this.maxRetries} attempts`,
323
+ error
324
+ )
325
+ }
326
+ this.log(`Retry ${retries}/${this.maxRetries} after error:`, error)
327
+ await this.sleep(1000 * retries)
328
+ }
329
+ }
330
+
331
+ // Extract signatures
332
+ const signatures = bundleTransactions.map(tx => {
333
+ if (tx instanceof VersionedTransaction) {
334
+ return bytesToHex(tx.signatures[0])
335
+ } else {
336
+ return tx.signature?.toString() ?? ''
337
+ }
338
+ })
339
+
340
+ // Wait for confirmation if requested
341
+ if (request.waitForConfirmation) {
342
+ const status = await this.waitForBundleConfirmation(bundleId!, lastValidBlockHeight)
343
+ return {
344
+ bundleId: bundleId!,
345
+ signatures,
346
+ status: status.status === 'Landed' ? 'landed' : 'failed',
347
+ slot: status.landedSlot,
348
+ error: status.error,
349
+ tipPaid: tipLamports,
350
+ }
351
+ }
352
+
353
+ return {
354
+ bundleId: bundleId!,
355
+ signatures,
356
+ status: 'submitted',
357
+ tipPaid: tipLamports,
358
+ }
359
+ }
360
+
361
+ /**
362
+ * Relay a single transaction via Jito
363
+ *
364
+ * This is the main method for gas abstraction - submit a transaction
365
+ * through the relayer instead of paying gas directly.
366
+ *
367
+ * @param request - Transaction to relay
368
+ * @returns Relay result
369
+ */
370
+ async relayTransaction(
371
+ request: RelayedTransactionRequest
372
+ ): Promise<RelayedTransactionResult> {
373
+ this.log('Relaying transaction')
374
+
375
+ try {
376
+ // For single transaction relay, we need to handle it differently
377
+ // The transaction should already be signed by the user
378
+ // We add it to a bundle with a tip transaction
379
+
380
+ const serializedTx = Buffer.from(request.transaction.serialize()).toString('base64')
381
+
382
+ // Submit as single-tx bundle
383
+ const bundleId = await this.sendBundle([serializedTx])
384
+
385
+ // Get signature
386
+ let signature: string
387
+ if (request.transaction instanceof VersionedTransaction) {
388
+ signature = bytesToHex(request.transaction.signatures[0])
389
+ } else {
390
+ signature = request.transaction.signature?.toString() ?? ''
391
+ }
392
+
393
+ // Wait for confirmation if requested
394
+ if (request.waitForConfirmation) {
395
+ const { lastValidBlockHeight } = await this.connection.getLatestBlockhash()
396
+ const status = await this.waitForBundleConfirmation(bundleId, lastValidBlockHeight)
397
+
398
+ return {
399
+ signature,
400
+ bundleId,
401
+ status: status.status === 'Landed' ? 'confirmed' : 'failed',
402
+ slot: status.landedSlot,
403
+ error: status.error,
404
+ relayed: true,
405
+ }
406
+ }
407
+
408
+ return {
409
+ signature,
410
+ bundleId,
411
+ status: 'submitted',
412
+ relayed: true,
413
+ }
414
+ } catch (error) {
415
+ // Fallback to direct submission
416
+ this.log('Relayer failed, falling back to direct submission:', error)
417
+ return this.directSubmit(request.transaction, request.waitForConfirmation)
418
+ }
419
+ }
420
+
421
+ /**
422
+ * Check if Jito relayer is available
423
+ */
424
+ async isAvailable(): Promise<boolean> {
425
+ try {
426
+ const response = await fetch(`${this.blockEngineUrl}/health`, {
427
+ method: 'GET',
428
+ signal: AbortSignal.timeout(5000),
429
+ })
430
+ return response.ok
431
+ } catch {
432
+ return false
433
+ }
434
+ }
435
+
436
+ /**
437
+ * Get current tip floor (minimum tip for inclusion)
438
+ */
439
+ async getTipFloor(): Promise<number> {
440
+ // In production, this would query Jito's tip floor endpoint
441
+ // For now, return a conservative default
442
+ return JITO_DEFAULTS.tipLamports
443
+ }
444
+
445
+ /**
446
+ * Get a random tip account
447
+ */
448
+ getRandomTipAccount(): PublicKey {
449
+ const index = Math.floor(Math.random() * JITO_TIP_ACCOUNTS.length)
450
+ return new PublicKey(JITO_TIP_ACCOUNTS[index])
451
+ }
452
+
453
+ // ─── Private Methods ────────────────────────────────────────────────────────
454
+
455
+ /**
456
+ * Create tip instruction
457
+ */
458
+ private createTipInstruction(
459
+ payer: PublicKey,
460
+ tipLamports: number
461
+ ): TransactionInstruction {
462
+ const tipAccount = this.getRandomTipAccount()
463
+ return SystemProgram.transfer({
464
+ fromPubkey: payer,
465
+ toPubkey: tipAccount,
466
+ lamports: tipLamports,
467
+ })
468
+ }
469
+
470
+ /**
471
+ * Prepare transactions for bundle submission
472
+ */
473
+ private async prepareBundleTransactions(
474
+ transactions: (Transaction | VersionedTransaction)[],
475
+ tipInstruction: TransactionInstruction,
476
+ tipPayer: Keypair,
477
+ blockhash: string
478
+ ): Promise<(Transaction | VersionedTransaction)[]> {
479
+ // Create tip transaction
480
+ const tipTx = new Transaction()
481
+ tipTx.add(tipInstruction)
482
+ tipTx.recentBlockhash = blockhash
483
+ tipTx.feePayer = tipPayer.publicKey
484
+ tipTx.sign(tipPayer)
485
+
486
+ // Return tip tx first, then user transactions
487
+ return [tipTx, ...transactions]
488
+ }
489
+
490
+ /**
491
+ * Send bundle to Jito block engine
492
+ */
493
+ private async sendBundle(serializedTransactions: string[]): Promise<string> {
494
+ const response = await fetch(`${this.blockEngineUrl}/bundles`, {
495
+ method: 'POST',
496
+ headers: {
497
+ 'Content-Type': 'application/json',
498
+ },
499
+ body: JSON.stringify({
500
+ jsonrpc: '2.0',
501
+ id: 1,
502
+ method: 'sendBundle',
503
+ params: [serializedTransactions],
504
+ }),
505
+ signal: AbortSignal.timeout(this.submissionTimeout),
506
+ })
507
+
508
+ if (!response.ok) {
509
+ const text = await response.text()
510
+ throw new JitoRelayerError(
511
+ JitoRelayerErrorCode.CONNECTION_ERROR,
512
+ `Block engine returned ${response.status}: ${text}`
513
+ )
514
+ }
515
+
516
+ const result = await response.json() as {
517
+ result?: string
518
+ error?: { message: string; code: number }
519
+ }
520
+
521
+ if (result.error) {
522
+ throw new JitoRelayerError(
523
+ JitoRelayerErrorCode.BUNDLE_SUBMISSION_FAILED,
524
+ result.error.message,
525
+ result.error
526
+ )
527
+ }
528
+
529
+ return result.result ?? ''
530
+ }
531
+
532
+ /**
533
+ * Wait for bundle confirmation
534
+ */
535
+ private async waitForBundleConfirmation(
536
+ bundleId: string,
537
+ lastValidBlockHeight: number
538
+ ): Promise<JitoBundleStatus> {
539
+ const startTime = Date.now()
540
+
541
+ while (Date.now() - startTime < JITO_DEFAULTS.confirmationTimeout) {
542
+ // Check current block height
543
+ const currentBlockHeight = await this.connection.getBlockHeight()
544
+
545
+ if (currentBlockHeight > lastValidBlockHeight) {
546
+ return {
547
+ bundleId,
548
+ status: 'Failed',
549
+ error: 'Bundle expired (blockhash invalid)',
550
+ }
551
+ }
552
+
553
+ // Check bundle status
554
+ const status = await this.getBundleStatus(bundleId)
555
+
556
+ if (status.status === 'Landed' || status.status === 'Failed' || status.status === 'Invalid') {
557
+ return status
558
+ }
559
+
560
+ await this.sleep(2000)
561
+ }
562
+
563
+ return {
564
+ bundleId,
565
+ status: 'Failed',
566
+ error: 'Confirmation timeout',
567
+ }
568
+ }
569
+
570
+ /**
571
+ * Get bundle status from Jito
572
+ */
573
+ private async getBundleStatus(bundleId: string): Promise<JitoBundleStatus> {
574
+ try {
575
+ const response = await fetch(`${this.blockEngineUrl}/bundles`, {
576
+ method: 'POST',
577
+ headers: {
578
+ 'Content-Type': 'application/json',
579
+ },
580
+ body: JSON.stringify({
581
+ jsonrpc: '2.0',
582
+ id: 1,
583
+ method: 'getBundleStatuses',
584
+ params: [[bundleId]],
585
+ }),
586
+ signal: AbortSignal.timeout(10000),
587
+ })
588
+
589
+ const result = await response.json() as {
590
+ result?: {
591
+ value: Array<{
592
+ bundle_id: string
593
+ status: string
594
+ landed_slot?: number
595
+ }>
596
+ }
597
+ }
598
+
599
+ const bundleStatus = result.result?.value?.[0]
600
+
601
+ if (!bundleStatus) {
602
+ return { bundleId, status: 'Pending' }
603
+ }
604
+
605
+ return {
606
+ bundleId,
607
+ status: bundleStatus.status as 'Invalid' | 'Pending' | 'Failed' | 'Landed',
608
+ landedSlot: bundleStatus.landed_slot,
609
+ }
610
+ } catch {
611
+ return { bundleId, status: 'Pending' }
612
+ }
613
+ }
614
+
615
+ /**
616
+ * Direct submission fallback
617
+ */
618
+ private async directSubmit(
619
+ transaction: Transaction | VersionedTransaction,
620
+ waitForConfirmation?: boolean
621
+ ): Promise<RelayedTransactionResult> {
622
+ const signature = await this.connection.sendRawTransaction(
623
+ transaction.serialize(),
624
+ { skipPreflight: false, maxRetries: 3 }
625
+ )
626
+
627
+ if (waitForConfirmation) {
628
+ const { blockhash, lastValidBlockHeight } = await this.connection.getLatestBlockhash()
629
+ const confirmation = await this.connection.confirmTransaction({
630
+ signature,
631
+ blockhash,
632
+ lastValidBlockHeight,
633
+ }, 'confirmed')
634
+
635
+ return {
636
+ signature,
637
+ status: confirmation.value.err ? 'failed' : 'confirmed',
638
+ error: confirmation.value.err?.toString(),
639
+ relayed: false,
640
+ }
641
+ }
642
+
643
+ return {
644
+ signature,
645
+ status: 'submitted',
646
+ relayed: false,
647
+ }
648
+ }
649
+
650
+ /**
651
+ * Log debug message
652
+ */
653
+ private log(message: string, ...args: unknown[]): void {
654
+ if (this.debug) {
655
+ console.log(`[JitoRelayer] ${message}`, ...args)
656
+ }
657
+ }
658
+
659
+ /**
660
+ * Sleep utility
661
+ */
662
+ private sleep(ms: number): Promise<void> {
663
+ return new Promise(resolve => setTimeout(resolve, ms))
664
+ }
665
+ }
666
+
667
+ // ─── Factory ──────────────────────────────────────────────────────────────────
668
+
669
+ /**
670
+ * Create a Jito relayer instance
671
+ *
672
+ * @param config - Relayer configuration
673
+ * @returns Jito relayer instance
674
+ */
675
+ export function createJitoRelayer(config?: JitoRelayerConfig): JitoRelayer {
676
+ return new JitoRelayer(config)
677
+ }
678
+
679
+ /**
680
+ * Create a mainnet Jito relayer with NY block engine
681
+ */
682
+ export function createMainnetRelayer(rpcUrl?: string): JitoRelayer {
683
+ return new JitoRelayer({
684
+ blockEngineUrl: JITO_BLOCK_ENGINES.mainnet.ny,
685
+ rpcUrl: rpcUrl ?? 'https://api.mainnet-beta.solana.com',
686
+ })
687
+ }