forgex-cli 1.0.0

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 (275) hide show
  1. package/README.md +479 -0
  2. package/dist/bin/forgex.d.ts +12 -0
  3. package/dist/bin/forgex.d.ts.map +1 -0
  4. package/dist/bin/forgex.js +23 -0
  5. package/dist/bin/forgex.js.map +1 -0
  6. package/dist/src/adapters/codex-adapter.d.ts +238 -0
  7. package/dist/src/adapters/codex-adapter.d.ts.map +1 -0
  8. package/dist/src/adapters/codex-adapter.js +524 -0
  9. package/dist/src/adapters/codex-adapter.js.map +1 -0
  10. package/dist/src/adapters/connection.d.ts +20 -0
  11. package/dist/src/adapters/connection.d.ts.map +1 -0
  12. package/dist/src/adapters/connection.js +43 -0
  13. package/dist/src/adapters/connection.js.map +1 -0
  14. package/dist/src/adapters/ipfs.d.ts +17 -0
  15. package/dist/src/adapters/ipfs.d.ts.map +1 -0
  16. package/dist/src/adapters/ipfs.js +30 -0
  17. package/dist/src/adapters/ipfs.js.map +1 -0
  18. package/dist/src/adapters/jito-adapter.d.ts +194 -0
  19. package/dist/src/adapters/jito-adapter.d.ts.map +1 -0
  20. package/dist/src/adapters/jito-adapter.js +474 -0
  21. package/dist/src/adapters/jito-adapter.js.map +1 -0
  22. package/dist/src/adapters/rpc-adapter.d.ts +148 -0
  23. package/dist/src/adapters/rpc-adapter.d.ts.map +1 -0
  24. package/dist/src/adapters/rpc-adapter.js +410 -0
  25. package/dist/src/adapters/rpc-adapter.js.map +1 -0
  26. package/dist/src/adapters/sdk-adapter.d.ts +148 -0
  27. package/dist/src/adapters/sdk-adapter.d.ts.map +1 -0
  28. package/dist/src/adapters/sdk-adapter.js +554 -0
  29. package/dist/src/adapters/sdk-adapter.js.map +1 -0
  30. package/dist/src/commands/config/index.d.ts +8 -0
  31. package/dist/src/commands/config/index.d.ts.map +1 -0
  32. package/dist/src/commands/config/index.js +91 -0
  33. package/dist/src/commands/config/index.js.map +1 -0
  34. package/dist/src/commands/query/index.d.ts +10 -0
  35. package/dist/src/commands/query/index.d.ts.map +1 -0
  36. package/dist/src/commands/query/index.js +376 -0
  37. package/dist/src/commands/query/index.js.map +1 -0
  38. package/dist/src/commands/sniper/index.d.ts +16 -0
  39. package/dist/src/commands/sniper/index.d.ts.map +1 -0
  40. package/dist/src/commands/sniper/index.js +292 -0
  41. package/dist/src/commands/sniper/index.js.map +1 -0
  42. package/dist/src/commands/token/index.d.ts +16 -0
  43. package/dist/src/commands/token/index.d.ts.map +1 -0
  44. package/dist/src/commands/token/index.js +295 -0
  45. package/dist/src/commands/token/index.js.map +1 -0
  46. package/dist/src/commands/tools/index.d.ts +17 -0
  47. package/dist/src/commands/tools/index.d.ts.map +1 -0
  48. package/dist/src/commands/tools/index.js +626 -0
  49. package/dist/src/commands/tools/index.js.map +1 -0
  50. package/dist/src/commands/trade/index.d.ts +8 -0
  51. package/dist/src/commands/trade/index.d.ts.map +1 -0
  52. package/dist/src/commands/trade/index.js +531 -0
  53. package/dist/src/commands/trade/index.js.map +1 -0
  54. package/dist/src/commands/transfer/index.d.ts +16 -0
  55. package/dist/src/commands/transfer/index.d.ts.map +1 -0
  56. package/dist/src/commands/transfer/index.js +509 -0
  57. package/dist/src/commands/transfer/index.js.map +1 -0
  58. package/dist/src/commands/wallet/index.d.ts +10 -0
  59. package/dist/src/commands/wallet/index.d.ts.map +1 -0
  60. package/dist/src/commands/wallet/index.js +828 -0
  61. package/dist/src/commands/wallet/index.js.map +1 -0
  62. package/dist/src/config.d.ts +74 -0
  63. package/dist/src/config.d.ts.map +1 -0
  64. package/dist/src/config.js +190 -0
  65. package/dist/src/config.js.map +1 -0
  66. package/dist/src/const/IDL/index.d.ts +4 -0
  67. package/dist/src/const/IDL/index.d.ts.map +1 -0
  68. package/dist/src/const/IDL/index.js +2 -0
  69. package/dist/src/const/IDL/index.js.map +1 -0
  70. package/dist/src/const/IDL/meteora-DLMM.d.ts +10249 -0
  71. package/dist/src/const/IDL/meteora-DLMM.d.ts.map +1 -0
  72. package/dist/src/const/IDL/meteora-DLMM.js +4177 -0
  73. package/dist/src/const/IDL/meteora-DLMM.js.map +1 -0
  74. package/dist/src/const/IDL/pump-fun.d.ts +4811 -0
  75. package/dist/src/const/IDL/pump-fun.d.ts.map +1 -0
  76. package/dist/src/const/IDL/pump-fun.js +2954 -0
  77. package/dist/src/const/IDL/pump-fun.js.map +1 -0
  78. package/dist/src/const/IDL/pump-swap-IDL.d.ts +3119 -0
  79. package/dist/src/const/IDL/pump-swap-IDL.d.ts.map +1 -0
  80. package/dist/src/const/IDL/pump-swap-IDL.js +2095 -0
  81. package/dist/src/const/IDL/pump-swap-IDL.js.map +1 -0
  82. package/dist/src/const/IDL/raydium-launchlab-IDL.d.ts +4031 -0
  83. package/dist/src/const/IDL/raydium-launchlab-IDL.d.ts.map +1 -0
  84. package/dist/src/const/IDL/raydium-launchlab-IDL.js +2110 -0
  85. package/dist/src/const/IDL/raydium-launchlab-IDL.js.map +1 -0
  86. package/dist/src/const/index.d.ts +40 -0
  87. package/dist/src/const/index.d.ts.map +1 -0
  88. package/dist/src/const/index.js +57 -0
  89. package/dist/src/const/index.js.map +1 -0
  90. package/dist/src/data-source.d.ts +270 -0
  91. package/dist/src/data-source.d.ts.map +1 -0
  92. package/dist/src/data-source.js +628 -0
  93. package/dist/src/data-source.js.map +1 -0
  94. package/dist/src/data-store/index.d.ts +87 -0
  95. package/dist/src/data-store/index.d.ts.map +1 -0
  96. package/dist/src/data-store/index.js +561 -0
  97. package/dist/src/data-store/index.js.map +1 -0
  98. package/dist/src/data-store/types.d.ts +91 -0
  99. package/dist/src/data-store/types.d.ts.map +1 -0
  100. package/dist/src/data-store/types.js +8 -0
  101. package/dist/src/data-store/types.js.map +1 -0
  102. package/dist/src/index.d.ts +8 -0
  103. package/dist/src/index.d.ts.map +1 -0
  104. package/dist/src/index.js +36 -0
  105. package/dist/src/index.js.map +1 -0
  106. package/dist/src/output.d.ts +52 -0
  107. package/dist/src/output.d.ts.map +1 -0
  108. package/dist/src/output.js +218 -0
  109. package/dist/src/output.js.map +1 -0
  110. package/dist/src/shims/store.d.ts +58 -0
  111. package/dist/src/shims/store.d.ts.map +1 -0
  112. package/dist/src/shims/store.js +55 -0
  113. package/dist/src/shims/store.js.map +1 -0
  114. package/dist/src/sol-sdk/account/index.d.ts +13 -0
  115. package/dist/src/sol-sdk/account/index.d.ts.map +1 -0
  116. package/dist/src/sol-sdk/account/index.js +174 -0
  117. package/dist/src/sol-sdk/account/index.js.map +1 -0
  118. package/dist/src/sol-sdk/account/lookupTable.d.ts +24 -0
  119. package/dist/src/sol-sdk/account/lookupTable.d.ts.map +1 -0
  120. package/dist/src/sol-sdk/account/lookupTable.js +103 -0
  121. package/dist/src/sol-sdk/account/lookupTable.js.map +1 -0
  122. package/dist/src/sol-sdk/batch/create.d.ts +23 -0
  123. package/dist/src/sol-sdk/batch/create.d.ts.map +1 -0
  124. package/dist/src/sol-sdk/batch/create.js +580 -0
  125. package/dist/src/sol-sdk/batch/create.js.map +1 -0
  126. package/dist/src/sol-sdk/batch/external-sniper.d.ts +31 -0
  127. package/dist/src/sol-sdk/batch/external-sniper.d.ts.map +1 -0
  128. package/dist/src/sol-sdk/batch/external-sniper.js +163 -0
  129. package/dist/src/sol-sdk/batch/external-sniper.js.map +1 -0
  130. package/dist/src/sol-sdk/batch/index.d.ts +144 -0
  131. package/dist/src/sol-sdk/batch/index.d.ts.map +1 -0
  132. package/dist/src/sol-sdk/batch/index.js +1573 -0
  133. package/dist/src/sol-sdk/batch/index.js.map +1 -0
  134. package/dist/src/sol-sdk/calc.d.ts +277 -0
  135. package/dist/src/sol-sdk/calc.d.ts.map +1 -0
  136. package/dist/src/sol-sdk/calc.js +590 -0
  137. package/dist/src/sol-sdk/calc.js.map +1 -0
  138. package/dist/src/sol-sdk/index.d.ts +1 -0
  139. package/dist/src/sol-sdk/index.d.ts.map +1 -0
  140. package/dist/src/sol-sdk/index.js +1 -0
  141. package/dist/src/sol-sdk/index.js.map +1 -0
  142. package/dist/src/sol-sdk/jito/index.d.ts +50 -0
  143. package/dist/src/sol-sdk/jito/index.d.ts.map +1 -0
  144. package/dist/src/sol-sdk/jito/index.js +225 -0
  145. package/dist/src/sol-sdk/jito/index.js.map +1 -0
  146. package/dist/src/sol-sdk/launchlab/index.d.ts +32 -0
  147. package/dist/src/sol-sdk/launchlab/index.d.ts.map +1 -0
  148. package/dist/src/sol-sdk/launchlab/index.js +78 -0
  149. package/dist/src/sol-sdk/launchlab/index.js.map +1 -0
  150. package/dist/src/sol-sdk/launchlab/instructions/buy.d.ts +27 -0
  151. package/dist/src/sol-sdk/launchlab/instructions/buy.d.ts.map +1 -0
  152. package/dist/src/sol-sdk/launchlab/instructions/buy.js +124 -0
  153. package/dist/src/sol-sdk/launchlab/instructions/buy.js.map +1 -0
  154. package/dist/src/sol-sdk/launchlab/instructions/create.d.ts +27 -0
  155. package/dist/src/sol-sdk/launchlab/instructions/create.d.ts.map +1 -0
  156. package/dist/src/sol-sdk/launchlab/instructions/create.js +125 -0
  157. package/dist/src/sol-sdk/launchlab/instructions/create.js.map +1 -0
  158. package/dist/src/sol-sdk/launchlab/instructions/sell.d.ts +15 -0
  159. package/dist/src/sol-sdk/launchlab/instructions/sell.d.ts.map +1 -0
  160. package/dist/src/sol-sdk/launchlab/instructions/sell.js +65 -0
  161. package/dist/src/sol-sdk/launchlab/instructions/sell.js.map +1 -0
  162. package/dist/src/sol-sdk/meteora/index.d.ts +32 -0
  163. package/dist/src/sol-sdk/meteora/index.d.ts.map +1 -0
  164. package/dist/src/sol-sdk/meteora/index.js +72 -0
  165. package/dist/src/sol-sdk/meteora/index.js.map +1 -0
  166. package/dist/src/sol-sdk/meteora/instructions/buy.d.ts +46 -0
  167. package/dist/src/sol-sdk/meteora/instructions/buy.d.ts.map +1 -0
  168. package/dist/src/sol-sdk/meteora/instructions/buy.js +153 -0
  169. package/dist/src/sol-sdk/meteora/instructions/buy.js.map +1 -0
  170. package/dist/src/sol-sdk/meteora/instructions/sell.d.ts +24 -0
  171. package/dist/src/sol-sdk/meteora/instructions/sell.d.ts.map +1 -0
  172. package/dist/src/sol-sdk/meteora/instructions/sell.js +98 -0
  173. package/dist/src/sol-sdk/meteora/instructions/sell.js.map +1 -0
  174. package/dist/src/sol-sdk/pump/index.d.ts +22 -0
  175. package/dist/src/sol-sdk/pump/index.d.ts.map +1 -0
  176. package/dist/src/sol-sdk/pump/index.js +101 -0
  177. package/dist/src/sol-sdk/pump/index.js.map +1 -0
  178. package/dist/src/sol-sdk/pump/instructions/buy.d.ts +29 -0
  179. package/dist/src/sol-sdk/pump/instructions/buy.d.ts.map +1 -0
  180. package/dist/src/sol-sdk/pump/instructions/buy.js +131 -0
  181. package/dist/src/sol-sdk/pump/instructions/buy.js.map +1 -0
  182. package/dist/src/sol-sdk/pump/instructions/createAndBuy.d.ts +36 -0
  183. package/dist/src/sol-sdk/pump/instructions/createAndBuy.d.ts.map +1 -0
  184. package/dist/src/sol-sdk/pump/instructions/createAndBuy.js +77 -0
  185. package/dist/src/sol-sdk/pump/instructions/createAndBuy.js.map +1 -0
  186. package/dist/src/sol-sdk/pump/instructions/sell.d.ts +7 -0
  187. package/dist/src/sol-sdk/pump/instructions/sell.d.ts.map +1 -0
  188. package/dist/src/sol-sdk/pump/instructions/sell.js +38 -0
  189. package/dist/src/sol-sdk/pump/instructions/sell.js.map +1 -0
  190. package/dist/src/sol-sdk/pumpswap/index.d.ts +9 -0
  191. package/dist/src/sol-sdk/pumpswap/index.d.ts.map +1 -0
  192. package/dist/src/sol-sdk/pumpswap/index.js +27 -0
  193. package/dist/src/sol-sdk/pumpswap/index.js.map +1 -0
  194. package/dist/src/sol-sdk/pumpswap/instructions/buy.d.ts +61 -0
  195. package/dist/src/sol-sdk/pumpswap/instructions/buy.d.ts.map +1 -0
  196. package/dist/src/sol-sdk/pumpswap/instructions/buy.js +215 -0
  197. package/dist/src/sol-sdk/pumpswap/instructions/buy.js.map +1 -0
  198. package/dist/src/sol-sdk/pumpswap/instructions/migrate.d.ts +3 -0
  199. package/dist/src/sol-sdk/pumpswap/instructions/migrate.d.ts.map +1 -0
  200. package/dist/src/sol-sdk/pumpswap/instructions/migrate.js +33 -0
  201. package/dist/src/sol-sdk/pumpswap/instructions/migrate.js.map +1 -0
  202. package/dist/src/sol-sdk/pumpswap/instructions/sell.d.ts +20 -0
  203. package/dist/src/sol-sdk/pumpswap/instructions/sell.d.ts.map +1 -0
  204. package/dist/src/sol-sdk/pumpswap/instructions/sell.js +107 -0
  205. package/dist/src/sol-sdk/pumpswap/instructions/sell.js.map +1 -0
  206. package/dist/src/sol-sdk/pumpswap/rpc/index.d.ts +28 -0
  207. package/dist/src/sol-sdk/pumpswap/rpc/index.d.ts.map +1 -0
  208. package/dist/src/sol-sdk/pumpswap/rpc/index.js +63 -0
  209. package/dist/src/sol-sdk/pumpswap/rpc/index.js.map +1 -0
  210. package/dist/src/sol-sdk/raydium/index.d.ts +16 -0
  211. package/dist/src/sol-sdk/raydium/index.d.ts.map +1 -0
  212. package/dist/src/sol-sdk/raydium/index.js +47 -0
  213. package/dist/src/sol-sdk/raydium/index.js.map +1 -0
  214. package/dist/src/sol-sdk/raydium/instructions/buy.d.ts +29 -0
  215. package/dist/src/sol-sdk/raydium/instructions/buy.d.ts.map +1 -0
  216. package/dist/src/sol-sdk/raydium/instructions/buy.js +106 -0
  217. package/dist/src/sol-sdk/raydium/instructions/buy.js.map +1 -0
  218. package/dist/src/sol-sdk/raydium/instructions/cpmmBuy.d.ts +29 -0
  219. package/dist/src/sol-sdk/raydium/instructions/cpmmBuy.d.ts.map +1 -0
  220. package/dist/src/sol-sdk/raydium/instructions/cpmmBuy.js +80 -0
  221. package/dist/src/sol-sdk/raydium/instructions/cpmmBuy.js.map +1 -0
  222. package/dist/src/sol-sdk/raydium/instructions/cpmmSell.d.ts +17 -0
  223. package/dist/src/sol-sdk/raydium/instructions/cpmmSell.d.ts.map +1 -0
  224. package/dist/src/sol-sdk/raydium/instructions/cpmmSell.js +56 -0
  225. package/dist/src/sol-sdk/raydium/instructions/cpmmSell.js.map +1 -0
  226. package/dist/src/sol-sdk/raydium/instructions/sell.d.ts +8558 -0
  227. package/dist/src/sol-sdk/raydium/instructions/sell.d.ts.map +1 -0
  228. package/dist/src/sol-sdk/raydium/instructions/sell.js +70 -0
  229. package/dist/src/sol-sdk/raydium/instructions/sell.js.map +1 -0
  230. package/dist/src/sol-sdk/raydium/rpc/index.d.ts +39 -0
  231. package/dist/src/sol-sdk/raydium/rpc/index.d.ts.map +1 -0
  232. package/dist/src/sol-sdk/raydium/rpc/index.js +82 -0
  233. package/dist/src/sol-sdk/raydium/rpc/index.js.map +1 -0
  234. package/dist/src/sol-sdk/raydium/rpc/raydium.d.ts +5 -0
  235. package/dist/src/sol-sdk/raydium/rpc/raydium.d.ts.map +1 -0
  236. package/dist/src/sol-sdk/raydium/rpc/raydium.js +18 -0
  237. package/dist/src/sol-sdk/raydium/rpc/raydium.js.map +1 -0
  238. package/dist/src/sol-sdk/rpc/index.d.ts +33 -0
  239. package/dist/src/sol-sdk/rpc/index.d.ts.map +1 -0
  240. package/dist/src/sol-sdk/rpc/index.js +128 -0
  241. package/dist/src/sol-sdk/rpc/index.js.map +1 -0
  242. package/dist/src/sol-sdk/transfer/index.d.ts +24 -0
  243. package/dist/src/sol-sdk/transfer/index.d.ts.map +1 -0
  244. package/dist/src/sol-sdk/transfer/index.js +65 -0
  245. package/dist/src/sol-sdk/transfer/index.js.map +1 -0
  246. package/dist/src/sol-sdk/turnover/index.d.ts +84 -0
  247. package/dist/src/sol-sdk/turnover/index.d.ts.map +1 -0
  248. package/dist/src/sol-sdk/turnover/index.js +569 -0
  249. package/dist/src/sol-sdk/turnover/index.js.map +1 -0
  250. package/dist/src/tx-tracker/detail-adapter.d.ts +100 -0
  251. package/dist/src/tx-tracker/detail-adapter.d.ts.map +1 -0
  252. package/dist/src/tx-tracker/detail-adapter.js +215 -0
  253. package/dist/src/tx-tracker/detail-adapter.js.map +1 -0
  254. package/dist/src/tx-tracker/index.d.ts +142 -0
  255. package/dist/src/tx-tracker/index.d.ts.map +1 -0
  256. package/dist/src/tx-tracker/index.js +447 -0
  257. package/dist/src/tx-tracker/index.js.map +1 -0
  258. package/dist/src/types/index.d.ts +76 -0
  259. package/dist/src/types/index.d.ts.map +1 -0
  260. package/dist/src/types/index.js +69 -0
  261. package/dist/src/types/index.js.map +1 -0
  262. package/dist/src/types/websocket.d.ts +15 -0
  263. package/dist/src/types/websocket.d.ts.map +1 -0
  264. package/dist/src/types/websocket.js +18 -0
  265. package/dist/src/types/websocket.js.map +1 -0
  266. package/dist/src/utils/index.d.ts +13 -0
  267. package/dist/src/utils/index.d.ts.map +1 -0
  268. package/dist/src/utils/index.js +174 -0
  269. package/dist/src/utils/index.js.map +1 -0
  270. package/dist/src/wallet-store.d.ts +124 -0
  271. package/dist/src/wallet-store.d.ts.map +1 -0
  272. package/dist/src/wallet-store.js +524 -0
  273. package/dist/src/wallet-store.js.map +1 -0
  274. package/package.json +86 -0
  275. package/scripts/postinstall.js +88 -0
@@ -0,0 +1,194 @@
1
+ /**
2
+ * ForgeX CLI Jito Bundle 直连适配器
3
+ *
4
+ * 替代现有通过 forgex.online/api 代理的 bundle 状态查询和发送。
5
+ * 直接调用 Jito Block Engine 的 JSON-RPC API。
6
+ *
7
+ * 设计参考: ARCH-DESIGN-v2.md Section 2.5
8
+ *
9
+ * 复用自 sol-sdk/jito/index.ts 的端点配置和 tip 账户列表。
10
+ */
11
+ import { PublicKey } from '@solana/web3.js';
12
+ /** Jito Block Engine API 端点列表 (多区域容错) */
13
+ export declare const JITO_ENDPOINTS: string[];
14
+ /** Jito Tip 账户列表 */
15
+ export declare const JITO_TIP_ACCOUNTS: string[];
16
+ /** Bundle 确认状态枚举 */
17
+ export declare enum BundleStatusEnum {
18
+ /** 已发送,尚未处理 */
19
+ SENT = "sent",
20
+ /** 已处理 (包含在区块中) */
21
+ PROCESSED = "processed",
22
+ /** 已确认 (超级多数验证) */
23
+ CONFIRMED = "confirmed",
24
+ /** 已最终确认 (不可逆) */
25
+ FINALIZED = "finalized",
26
+ /** 执行失败 */
27
+ FAILED = "failed",
28
+ /** 查询超时 */
29
+ TIMEOUT = "timeout",
30
+ /** 在 landing 中 (inflight) */
31
+ INFLIGHT = "inflight",
32
+ /** 未知状态 */
33
+ UNKNOWN = "unknown"
34
+ }
35
+ /** Bundle 状态查询结果 (getBundleStatuses API) */
36
+ export interface BundleStatusResult {
37
+ /** Bundle ID */
38
+ bundleId: string;
39
+ /** 确认状态 */
40
+ status: BundleStatusEnum;
41
+ /** Bundle 所在的 Slot */
42
+ slot?: number;
43
+ /** Bundle 中包含的交易签名列表 */
44
+ transactions?: string[];
45
+ /** 确认时间 (Unix ms) */
46
+ confirmationTime?: number;
47
+ /** 错误信息 (如果失败) */
48
+ err?: any;
49
+ }
50
+ /** Inflight Bundle 状态 */
51
+ export interface InflightBundleStatus {
52
+ bundleId: string;
53
+ status: string;
54
+ landedSlot?: number;
55
+ }
56
+ /** Bundle 确认等待结果 */
57
+ export interface BundleConfirmationResult {
58
+ /** Bundle ID */
59
+ bundleId: string;
60
+ /** 最终状态 */
61
+ status: BundleStatusEnum;
62
+ /** 是否成功 (processed/confirmed/finalized) */
63
+ success: boolean;
64
+ /** Bundle 所在的 Slot */
65
+ slot?: number;
66
+ /** Bundle 中的交易列表 */
67
+ transactions?: string[];
68
+ /** 错误信息 */
69
+ error?: string;
70
+ }
71
+ /** 等待确认选项 */
72
+ export interface WaitOptions {
73
+ /** 超时时间 (ms), 默认 60000 */
74
+ timeoutMs?: number;
75
+ /** 轮询间隔 (ms), 默认 2000 */
76
+ intervalMs?: number;
77
+ }
78
+ export declare class JitoAdapter {
79
+ private endpoints;
80
+ private currentEndpointIndex;
81
+ private client;
82
+ private maxRetries;
83
+ constructor(options?: {
84
+ endpoints?: string[];
85
+ maxRetries?: number;
86
+ });
87
+ /**
88
+ * 发送 JSON-RPC 请求到 Jito Block Engine
89
+ * @param path API 路径 (如 /bundles)
90
+ * @param method JSON-RPC 方法名
91
+ * @param params JSON-RPC 参数
92
+ */
93
+ private sendRequest;
94
+ /**
95
+ * 带指数退避重试 + 端点轮转的执行器
96
+ * 1. 在当前端点上重试 maxRetries 次 (指数退避)
97
+ * 2. 如果当前端点全部失败,切换到下一个端点继续
98
+ * 3. 所有端点都失败后抛出最后一个错误
99
+ */
100
+ private executeWithRetry;
101
+ /** 判断错误是否可重试 */
102
+ private isRetryableError;
103
+ /** 切换到下一个端点 */
104
+ private switchEndpoint;
105
+ /** 获取当前端点 URL (供调试使用) */
106
+ getCurrentEndpoint(): string;
107
+ /**
108
+ * 查询 Bundle 状态
109
+ * 调用 Jito 的 getBundleStatuses JSON-RPC 方法
110
+ *
111
+ * @param bundleIds 要查询的 Bundle ID 列表
112
+ * @returns 每个 Bundle 的状态
113
+ */
114
+ getBundleStatuses(bundleIds: string[]): Promise<BundleStatusResult[]>;
115
+ /**
116
+ * 查询单个 Bundle 的状态 (便捷方法)
117
+ */
118
+ getBundleStatus(bundleId: string): Promise<BundleStatusResult>;
119
+ /**
120
+ * 查询 Inflight Bundle 状态
121
+ * 用于查询刚发送、尚未落地的 bundle
122
+ */
123
+ getInflightBundleStatuses(bundleIds: string[]): Promise<InflightBundleStatus[]>;
124
+ /**
125
+ * 等待 Bundle 确认
126
+ * 轮询 getBundleStatuses 直到达到终态或超时
127
+ *
128
+ * @param bundleId Bundle ID
129
+ * @param options 超时和轮询间隔配置
130
+ * @returns Bundle 确认结果
131
+ */
132
+ waitForBundleConfirmation(bundleId: string, options?: WaitOptions): Promise<BundleConfirmationResult>;
133
+ /**
134
+ * 发送 Bundle 到 Jito Block Engine
135
+ * 直连 Jito,不经过 forgex.online/api 代理
136
+ *
137
+ * @param base64Txs Base64 编码的交易列表
138
+ * @returns Bundle ID
139
+ */
140
+ sendBundle(base64Txs: string[]): Promise<{
141
+ bundleId: string;
142
+ }>;
143
+ /**
144
+ * 从 Jito API 获取最新的 Tip 账户列表
145
+ * 通常使用本地硬编码的 JITO_TIP_ACCOUNTS 即可,
146
+ * 此方法用于需要动态获取最新 tip 账户的场景
147
+ */
148
+ getTipAccounts(): Promise<string[]>;
149
+ /**
150
+ * 随机获取一个 Tip 账户地址
151
+ * 使用本地硬编码列表,无网络开销
152
+ */
153
+ getRandomTipAccount(): string;
154
+ /**
155
+ * 构建 Jito Tip 转账指令
156
+ * 复用 sol-sdk/jito 中的逻辑
157
+ *
158
+ * @param payer 付款者的 PublicKey
159
+ * @param tipAmountSol Tip 金额 (SOL 单位)
160
+ * @returns SystemProgram.transfer 指令
161
+ */
162
+ getTipInstruction(payer: PublicKey, tipAmountSol: number): import("@solana/web3.js").TransactionInstruction;
163
+ /**
164
+ * 判断 Bundle 状态是否为成功状态
165
+ * (processed / confirmed / finalized 均视为成功)
166
+ */
167
+ isSuccessStatus(status: BundleStatusEnum): boolean;
168
+ /**
169
+ * 判断 Bundle 状态是否为终态 (不会再变化)
170
+ */
171
+ isTerminalStatus(status: BundleStatusEnum): boolean;
172
+ /**
173
+ * 将 Jito API 返回的状态字符串映射到 BundleStatusEnum
174
+ */
175
+ private mapBundleStatus;
176
+ /**
177
+ * 健康检查: 验证当前 Jito 端点是否可用
178
+ */
179
+ healthCheck(): Promise<{
180
+ healthy: boolean;
181
+ endpoint: string;
182
+ error?: string;
183
+ }>;
184
+ }
185
+ /**
186
+ * 获取 JitoAdapter 单例
187
+ * 首次调用时创建实例
188
+ */
189
+ export declare function getJitoAdapter(): JitoAdapter;
190
+ /**
191
+ * 重置单例 (用于配置变更后重新初始化)
192
+ */
193
+ export declare function resetJitoAdapter(): void;
194
+ //# sourceMappingURL=jito-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jito-adapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/jito-adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,474 @@
1
+ /**
2
+ * ForgeX CLI Jito Bundle 直连适配器
3
+ *
4
+ * 替代现有通过 forgex.online/api 代理的 bundle 状态查询和发送。
5
+ * 直接调用 Jito Block Engine 的 JSON-RPC API。
6
+ *
7
+ * 设计参考: ARCH-DESIGN-v2.md Section 2.5
8
+ *
9
+ * 复用自 sol-sdk/jito/index.ts 的端点配置和 tip 账户列表。
10
+ */
11
+ import axios from 'axios';
12
+ import { PublicKey, SystemProgram, LAMPORTS_PER_SOL } from '@solana/web3.js';
13
+ import { loadConfig } from '../config.js';
14
+ // ============================================================
15
+ // 常量 (复用 sol-sdk/jito 配置)
16
+ // ============================================================
17
+ /** Jito Block Engine API 端点列表 (多区域容错) */
18
+ export const JITO_ENDPOINTS = [
19
+ 'https://mainnet.block-engine.jito.wtf/api/v1',
20
+ 'https://amsterdam.mainnet.block-engine.jito.wtf/api/v1',
21
+ 'https://frankfurt.mainnet.block-engine.jito.wtf/api/v1',
22
+ 'https://ny.mainnet.block-engine.jito.wtf/api/v1',
23
+ 'https://tokyo.mainnet.block-engine.jito.wtf/api/v1',
24
+ ];
25
+ /** Jito Tip 账户列表 */
26
+ export const JITO_TIP_ACCOUNTS = [
27
+ '96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5',
28
+ 'HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe',
29
+ 'Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY',
30
+ 'ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49',
31
+ 'DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh',
32
+ 'ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt',
33
+ 'DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL',
34
+ '3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT',
35
+ ];
36
+ /** Bundle 确认状态枚举 */
37
+ export var BundleStatusEnum;
38
+ (function (BundleStatusEnum) {
39
+ /** 已发送,尚未处理 */
40
+ BundleStatusEnum["SENT"] = "sent";
41
+ /** 已处理 (包含在区块中) */
42
+ BundleStatusEnum["PROCESSED"] = "processed";
43
+ /** 已确认 (超级多数验证) */
44
+ BundleStatusEnum["CONFIRMED"] = "confirmed";
45
+ /** 已最终确认 (不可逆) */
46
+ BundleStatusEnum["FINALIZED"] = "finalized";
47
+ /** 执行失败 */
48
+ BundleStatusEnum["FAILED"] = "failed";
49
+ /** 查询超时 */
50
+ BundleStatusEnum["TIMEOUT"] = "timeout";
51
+ /** 在 landing 中 (inflight) */
52
+ BundleStatusEnum["INFLIGHT"] = "inflight";
53
+ /** 未知状态 */
54
+ BundleStatusEnum["UNKNOWN"] = "unknown";
55
+ })(BundleStatusEnum || (BundleStatusEnum = {}));
56
+ // ============================================================
57
+ // 默认值
58
+ // ============================================================
59
+ const DEFAULT_MAX_RETRIES = 3;
60
+ const INITIAL_RETRY_DELAY_MS = 500;
61
+ const DEFAULT_TIMEOUT_MS = 60000;
62
+ const DEFAULT_POLL_INTERVAL_MS = 2000;
63
+ // ============================================================
64
+ // JitoAdapter 实现
65
+ // ============================================================
66
+ export class JitoAdapter {
67
+ endpoints;
68
+ currentEndpointIndex;
69
+ client;
70
+ maxRetries;
71
+ constructor(options) {
72
+ // 端点列表: 用户配置 > 默认 Jito 端点
73
+ if (options?.endpoints && options.endpoints.length > 0) {
74
+ this.endpoints = [...options.endpoints];
75
+ }
76
+ else {
77
+ // 尝试从 config 读取自定义 Jito 端点
78
+ try {
79
+ const config = loadConfig();
80
+ const configEndpoints = config.jitoEndpoints;
81
+ if (Array.isArray(configEndpoints) && configEndpoints.length > 0) {
82
+ this.endpoints = configEndpoints;
83
+ }
84
+ else {
85
+ this.endpoints = [...JITO_ENDPOINTS];
86
+ }
87
+ }
88
+ catch {
89
+ this.endpoints = [...JITO_ENDPOINTS];
90
+ }
91
+ }
92
+ this.currentEndpointIndex = 0;
93
+ this.maxRetries = options?.maxRetries ?? DEFAULT_MAX_RETRIES;
94
+ this.client = axios.create({
95
+ headers: {
96
+ 'Content-Type': 'application/json',
97
+ },
98
+ timeout: 15000,
99
+ });
100
+ }
101
+ // ============================================================
102
+ // 底层 JSON-RPC 通信
103
+ // ============================================================
104
+ /**
105
+ * 发送 JSON-RPC 请求到 Jito Block Engine
106
+ * @param path API 路径 (如 /bundles)
107
+ * @param method JSON-RPC 方法名
108
+ * @param params JSON-RPC 参数
109
+ */
110
+ async sendRequest(path, method, params) {
111
+ const baseUrl = this.endpoints[this.currentEndpointIndex];
112
+ const url = `${baseUrl}${path}`;
113
+ const payload = {
114
+ jsonrpc: '2.0',
115
+ id: 1,
116
+ method,
117
+ params: params || [],
118
+ };
119
+ const response = await this.client.post(url, payload);
120
+ return response.data;
121
+ }
122
+ // ============================================================
123
+ // 重试和容错 (与 RpcAdapter 一致的模式)
124
+ // ============================================================
125
+ /**
126
+ * 带指数退避重试 + 端点轮转的执行器
127
+ * 1. 在当前端点上重试 maxRetries 次 (指数退避)
128
+ * 2. 如果当前端点全部失败,切换到下一个端点继续
129
+ * 3. 所有端点都失败后抛出最后一个错误
130
+ */
131
+ async executeWithRetry(operation, operationName) {
132
+ const triedEndpoints = new Set();
133
+ let lastError = null;
134
+ while (triedEndpoints.size < this.endpoints.length) {
135
+ triedEndpoints.add(this.currentEndpointIndex);
136
+ for (let attempt = 0; attempt < this.maxRetries; attempt++) {
137
+ try {
138
+ return await operation();
139
+ }
140
+ catch (err) {
141
+ lastError = err;
142
+ if (!this.isRetryableError(err)) {
143
+ throw err;
144
+ }
145
+ // 指数退避等待
146
+ if (attempt < this.maxRetries - 1) {
147
+ const delay = INITIAL_RETRY_DELAY_MS * Math.pow(2, attempt);
148
+ await sleep(delay);
149
+ }
150
+ }
151
+ }
152
+ // 当前端点全部重试失败,尝试切换
153
+ const switched = this.switchEndpoint();
154
+ if (!switched)
155
+ break;
156
+ }
157
+ throw lastError || new Error(`${operationName}: 所有 Jito 端点均不可用`);
158
+ }
159
+ /** 判断错误是否可重试 */
160
+ isRetryableError(err) {
161
+ const message = (err?.message || '').toLowerCase();
162
+ const status = err?.response?.status;
163
+ // HTTP 状态码判断
164
+ if (status === 429 || status === 502 || status === 503 || status === 500) {
165
+ return true;
166
+ }
167
+ // 网络错误
168
+ if (message.includes('fetch failed') ||
169
+ message.includes('econnrefused') ||
170
+ message.includes('econnreset') ||
171
+ message.includes('enotfound') ||
172
+ message.includes('network error')) {
173
+ return true;
174
+ }
175
+ // 超时
176
+ if (message.includes('timeout') || message.includes('timed out') || err?.code === 'ECONNABORTED') {
177
+ return true;
178
+ }
179
+ // 速率限制
180
+ if (message.includes('rate limit') || message.includes('too many requests')) {
181
+ return true;
182
+ }
183
+ return false;
184
+ }
185
+ /** 切换到下一个端点 */
186
+ switchEndpoint() {
187
+ if (this.endpoints.length <= 1)
188
+ return false;
189
+ const oldIndex = this.currentEndpointIndex;
190
+ this.currentEndpointIndex = (this.currentEndpointIndex + 1) % this.endpoints.length;
191
+ return this.currentEndpointIndex !== oldIndex;
192
+ }
193
+ /** 获取当前端点 URL (供调试使用) */
194
+ getCurrentEndpoint() {
195
+ return this.endpoints[this.currentEndpointIndex];
196
+ }
197
+ // ============================================================
198
+ // Bundle 状态查询
199
+ // ============================================================
200
+ /**
201
+ * 查询 Bundle 状态
202
+ * 调用 Jito 的 getBundleStatuses JSON-RPC 方法
203
+ *
204
+ * @param bundleIds 要查询的 Bundle ID 列表
205
+ * @returns 每个 Bundle 的状态
206
+ */
207
+ async getBundleStatuses(bundleIds) {
208
+ if (bundleIds.length === 0)
209
+ return [];
210
+ return this.executeWithRetry(async () => {
211
+ const response = await this.sendRequest('/bundles', 'getBundleStatuses', [bundleIds]);
212
+ if (response.error) {
213
+ throw new Error(`Jito getBundleStatuses 错误: ${response.error.message}`);
214
+ }
215
+ const value = response.result?.value;
216
+ if (!Array.isArray(value)) {
217
+ // 没有找到任何 bundle 状态
218
+ return bundleIds.map((id) => ({
219
+ bundleId: id,
220
+ status: BundleStatusEnum.UNKNOWN,
221
+ }));
222
+ }
223
+ return bundleIds.map((id, index) => {
224
+ const entry = value[index];
225
+ if (!entry) {
226
+ return { bundleId: id, status: BundleStatusEnum.UNKNOWN };
227
+ }
228
+ return {
229
+ bundleId: entry.bundle_id || id,
230
+ status: this.mapBundleStatus(entry.confirmation_status),
231
+ slot: entry.slot ?? undefined,
232
+ transactions: entry.transactions ?? undefined,
233
+ err: entry.err ?? undefined,
234
+ };
235
+ });
236
+ }, 'getBundleStatuses');
237
+ }
238
+ /**
239
+ * 查询单个 Bundle 的状态 (便捷方法)
240
+ */
241
+ async getBundleStatus(bundleId) {
242
+ const results = await this.getBundleStatuses([bundleId]);
243
+ return results[0];
244
+ }
245
+ /**
246
+ * 查询 Inflight Bundle 状态
247
+ * 用于查询刚发送、尚未落地的 bundle
248
+ */
249
+ async getInflightBundleStatuses(bundleIds) {
250
+ if (bundleIds.length === 0)
251
+ return [];
252
+ return this.executeWithRetry(async () => {
253
+ const response = await this.sendRequest('/bundles', 'getInflightBundleStatuses', [bundleIds]);
254
+ if (response.error) {
255
+ throw new Error(`Jito getInflightBundleStatuses 错误: ${response.error.message}`);
256
+ }
257
+ const value = response.result?.value;
258
+ if (!Array.isArray(value)) {
259
+ return bundleIds.map((id) => ({
260
+ bundleId: id,
261
+ status: 'unknown',
262
+ }));
263
+ }
264
+ return value.map((entry, index) => ({
265
+ bundleId: entry?.bundle_id || bundleIds[index],
266
+ status: entry?.status || 'unknown',
267
+ landedSlot: entry?.landed_slot ?? undefined,
268
+ }));
269
+ }, 'getInflightBundleStatuses');
270
+ }
271
+ // ============================================================
272
+ // Bundle 确认等待 (轮询)
273
+ // ============================================================
274
+ /**
275
+ * 等待 Bundle 确认
276
+ * 轮询 getBundleStatuses 直到达到终态或超时
277
+ *
278
+ * @param bundleId Bundle ID
279
+ * @param options 超时和轮询间隔配置
280
+ * @returns Bundle 确认结果
281
+ */
282
+ async waitForBundleConfirmation(bundleId, options) {
283
+ const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
284
+ const intervalMs = options?.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
285
+ const start = Date.now();
286
+ while (Date.now() - start < timeoutMs) {
287
+ try {
288
+ const status = await this.getBundleStatus(bundleId);
289
+ // 终态判断
290
+ if (this.isTerminalStatus(status.status)) {
291
+ const success = this.isSuccessStatus(status.status);
292
+ return {
293
+ bundleId,
294
+ status: status.status,
295
+ success,
296
+ slot: status.slot,
297
+ transactions: status.transactions,
298
+ error: success ? undefined : `Bundle 状态: ${status.status}`,
299
+ };
300
+ }
301
+ // 非终态 (SENT/INFLIGHT/UNKNOWN) -- 继续轮询
302
+ }
303
+ catch {
304
+ // 查询失败不立即退出,继续重试
305
+ // executeWithRetry 内部已经做了重试,这里只处理最终失败
306
+ }
307
+ await sleep(intervalMs);
308
+ }
309
+ // 超时
310
+ return {
311
+ bundleId,
312
+ status: BundleStatusEnum.TIMEOUT,
313
+ success: false,
314
+ error: `等待 Bundle 确认超时 (${timeoutMs}ms)`,
315
+ };
316
+ }
317
+ // ============================================================
318
+ // Bundle 发送
319
+ // ============================================================
320
+ /**
321
+ * 发送 Bundle 到 Jito Block Engine
322
+ * 直连 Jito,不经过 forgex.online/api 代理
323
+ *
324
+ * @param base64Txs Base64 编码的交易列表
325
+ * @returns Bundle ID
326
+ */
327
+ async sendBundle(base64Txs) {
328
+ if (base64Txs.length === 0) {
329
+ throw new Error('sendBundle: 交易列表不能为空');
330
+ }
331
+ return this.executeWithRetry(async () => {
332
+ const response = await this.sendRequest('/bundles', 'sendBundle', [base64Txs]);
333
+ if (response.error) {
334
+ throw new Error(`Jito sendBundle 错误: ${response.error.message}`);
335
+ }
336
+ const bundleId = response.result;
337
+ if (!bundleId || typeof bundleId !== 'string') {
338
+ throw new Error('Jito sendBundle: 未返回有效的 Bundle ID');
339
+ }
340
+ return { bundleId };
341
+ }, 'sendBundle');
342
+ }
343
+ // ============================================================
344
+ // Tip 相关查询
345
+ // ============================================================
346
+ /**
347
+ * 从 Jito API 获取最新的 Tip 账户列表
348
+ * 通常使用本地硬编码的 JITO_TIP_ACCOUNTS 即可,
349
+ * 此方法用于需要动态获取最新 tip 账户的场景
350
+ */
351
+ async getTipAccounts() {
352
+ return this.executeWithRetry(async () => {
353
+ const response = await this.sendRequest('/bundles', 'getTipAccounts');
354
+ if (response.error) {
355
+ throw new Error(`Jito getTipAccounts 错误: ${response.error.message}`);
356
+ }
357
+ const accounts = response.result;
358
+ if (Array.isArray(accounts) && accounts.length > 0) {
359
+ return accounts;
360
+ }
361
+ // fallback 到本地硬编码列表
362
+ return [...JITO_TIP_ACCOUNTS];
363
+ }, 'getTipAccounts');
364
+ }
365
+ /**
366
+ * 随机获取一个 Tip 账户地址
367
+ * 使用本地硬编码列表,无网络开销
368
+ */
369
+ getRandomTipAccount() {
370
+ const index = Math.floor(Math.random() * JITO_TIP_ACCOUNTS.length);
371
+ return JITO_TIP_ACCOUNTS[index];
372
+ }
373
+ /**
374
+ * 构建 Jito Tip 转账指令
375
+ * 复用 sol-sdk/jito 中的逻辑
376
+ *
377
+ * @param payer 付款者的 PublicKey
378
+ * @param tipAmountSol Tip 金额 (SOL 单位)
379
+ * @returns SystemProgram.transfer 指令
380
+ */
381
+ getTipInstruction(payer, tipAmountSol) {
382
+ const tipAccount = new PublicKey(this.getRandomTipAccount());
383
+ const lamports = Math.floor(tipAmountSol * LAMPORTS_PER_SOL);
384
+ return SystemProgram.transfer({
385
+ fromPubkey: payer,
386
+ toPubkey: tipAccount,
387
+ lamports,
388
+ });
389
+ }
390
+ // ============================================================
391
+ // 辅助方法
392
+ // ============================================================
393
+ /**
394
+ * 判断 Bundle 状态是否为成功状态
395
+ * (processed / confirmed / finalized 均视为成功)
396
+ */
397
+ isSuccessStatus(status) {
398
+ return (status === BundleStatusEnum.PROCESSED ||
399
+ status === BundleStatusEnum.CONFIRMED ||
400
+ status === BundleStatusEnum.FINALIZED);
401
+ }
402
+ /**
403
+ * 判断 Bundle 状态是否为终态 (不会再变化)
404
+ */
405
+ isTerminalStatus(status) {
406
+ return (status === BundleStatusEnum.PROCESSED ||
407
+ status === BundleStatusEnum.CONFIRMED ||
408
+ status === BundleStatusEnum.FINALIZED ||
409
+ status === BundleStatusEnum.FAILED);
410
+ }
411
+ /**
412
+ * 将 Jito API 返回的状态字符串映射到 BundleStatusEnum
413
+ */
414
+ mapBundleStatus(rawStatus) {
415
+ if (!rawStatus)
416
+ return BundleStatusEnum.UNKNOWN;
417
+ const normalized = rawStatus.toLowerCase();
418
+ switch (normalized) {
419
+ case 'sent':
420
+ return BundleStatusEnum.SENT;
421
+ case 'processed':
422
+ return BundleStatusEnum.PROCESSED;
423
+ case 'confirmed':
424
+ return BundleStatusEnum.CONFIRMED;
425
+ case 'finalized':
426
+ return BundleStatusEnum.FINALIZED;
427
+ case 'failed':
428
+ return BundleStatusEnum.FAILED;
429
+ default:
430
+ return BundleStatusEnum.UNKNOWN;
431
+ }
432
+ }
433
+ /**
434
+ * 健康检查: 验证当前 Jito 端点是否可用
435
+ */
436
+ async healthCheck() {
437
+ const endpoint = this.getCurrentEndpoint();
438
+ try {
439
+ // getTipAccounts 是最轻量的 Jito API 调用,适合做健康检查
440
+ await this.getTipAccounts();
441
+ return { healthy: true, endpoint };
442
+ }
443
+ catch (err) {
444
+ return { healthy: false, endpoint, error: err.message };
445
+ }
446
+ }
447
+ }
448
+ // ============================================================
449
+ // 单例管理 (与 RpcAdapter 一致的模式)
450
+ // ============================================================
451
+ let _instance = null;
452
+ /**
453
+ * 获取 JitoAdapter 单例
454
+ * 首次调用时创建实例
455
+ */
456
+ export function getJitoAdapter() {
457
+ if (!_instance) {
458
+ _instance = new JitoAdapter();
459
+ }
460
+ return _instance;
461
+ }
462
+ /**
463
+ * 重置单例 (用于配置变更后重新初始化)
464
+ */
465
+ export function resetJitoAdapter() {
466
+ _instance = null;
467
+ }
468
+ // ============================================================
469
+ // 工具函数
470
+ // ============================================================
471
+ function sleep(ms) {
472
+ return new Promise((resolve) => setTimeout(resolve, ms));
473
+ }
474
+ //# sourceMappingURL=jito-adapter.js.map