perp-cli 0.14.3 → 0.16.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 (363) hide show
  1. package/README.ja.md +243 -0
  2. package/README.ko.md +243 -0
  3. package/README.md +138 -405
  4. package/README.zh.md +243 -0
  5. package/dist/agent-wallet/store.d.ts +3 -2
  6. package/dist/agent-wallet/store.js +2 -2
  7. package/dist/api/public/hyperliquid.js +4 -0
  8. package/dist/api/public/lighter.d.ts +5 -0
  9. package/dist/api/public/lighter.js +5 -0
  10. package/dist/api/public/pacifica.js +85 -15
  11. package/dist/api/public/urls.d.ts +2 -0
  12. package/dist/api/public/urls.js +3 -0
  13. package/dist/arb/sizing.js +4 -2
  14. package/dist/arb/state.d.ts +6 -0
  15. package/dist/arb/utils.d.ts +1 -2
  16. package/dist/arb/utils.js +1 -2
  17. package/dist/balance-by-address.d.ts +39 -0
  18. package/dist/balance-by-address.js +44 -0
  19. package/dist/bot/apex/pulse.js +3 -0
  20. package/dist/bot/apex/radar.js +2 -1
  21. package/dist/bot/engine.d.ts +10 -1
  22. package/dist/bot/engine.js +14 -6
  23. package/dist/bot/indicators.d.ts +7 -0
  24. package/dist/bot/indicators.js +16 -0
  25. package/dist/bot/perp-order.d.ts +4 -4
  26. package/dist/bot/perp-order.js +5 -5
  27. package/dist/bot/quarantine.d.ts +1 -1
  28. package/dist/bot/quarantine.js +1 -1
  29. package/dist/bot/quote-rules.js +1 -1
  30. package/dist/bot/strategies/apex-strategy.js +3 -2
  31. package/dist/bot/strategies/engine-mm.js +6 -5
  32. package/dist/bot/strategies/funding-arb-strategy.js +12 -5
  33. package/dist/bot/strategies/funding-arb-utils.d.ts +15 -3
  34. package/dist/bot/strategies/funding-arb-utils.js +53 -20
  35. package/dist/bot/strategies/funding-auto.js +2 -2
  36. package/dist/bot/strategies/liquidation-mm.d.ts +1 -0
  37. package/dist/bot/strategies/liquidation-mm.js +8 -2
  38. package/dist/bot/strategies/momentum-breakout.d.ts +1 -0
  39. package/dist/bot/strategies/momentum-breakout.js +11 -3
  40. package/dist/bot/strategies/spot-perp-arb-strategy.d.ts +1 -1
  41. package/dist/bot/strategies/spot-perp-arb-strategy.js +6 -4
  42. package/dist/bot/strategies/spot-perp-executor.d.ts +1 -1
  43. package/dist/bot/strategies/spot-perp-executor.js +3 -3
  44. package/dist/bot/strategy-types.d.ts +2 -1
  45. package/dist/bot/tui/BotDashboard.d.ts +1 -1
  46. package/dist/bot/tui/BotDashboard.js +1 -1
  47. package/dist/cache.js +12 -6
  48. package/dist/cli-program.d.ts +15 -0
  49. package/dist/cli-program.js +126 -6
  50. package/dist/commands/account.js +168 -24
  51. package/dist/commands/agent-import.d.ts +7 -0
  52. package/dist/commands/agent-import.js +30 -1
  53. package/dist/commands/agent.d.ts +6 -3
  54. package/dist/commands/agent.js +160 -12
  55. package/dist/commands/arb/index.js +23 -81
  56. package/dist/commands/arb-auto.d.ts +24 -0
  57. package/dist/commands/arb-auto.js +175 -97
  58. package/dist/commands/arb.d.ts +20 -0
  59. package/dist/commands/arb.js +107 -163
  60. package/dist/commands/backtest.js +23 -21
  61. package/dist/commands/bot.js +1 -1
  62. package/dist/commands/builder.js +1 -1
  63. package/dist/commands/funds.js +113 -3
  64. package/dist/commands/init.d.ts +1 -1
  65. package/dist/commands/init.js +27 -7
  66. package/dist/commands/manage.js +23 -21
  67. package/dist/commands/market.d.ts +48 -0
  68. package/dist/commands/market.js +395 -100
  69. package/dist/commands/options.d.ts +14 -0
  70. package/dist/commands/options.js +151 -0
  71. package/dist/commands/pacifica-earn.d.ts +5 -0
  72. package/dist/commands/pacifica-earn.js +455 -0
  73. package/dist/commands/pacifica-orders.d.ts +14 -0
  74. package/dist/commands/pacifica-orders.js +142 -0
  75. package/dist/commands/portfolio.d.ts +16 -0
  76. package/dist/commands/portfolio.js +83 -55
  77. package/dist/commands/rebalance.d.ts +1 -0
  78. package/dist/commands/rebalance.js +15 -0
  79. package/dist/commands/risk.d.ts +11 -2
  80. package/dist/commands/risk.js +39 -44
  81. package/dist/commands/trade.d.ts +1 -0
  82. package/dist/commands/trade.js +67 -62
  83. package/dist/commands/wallet.js +1 -1
  84. package/dist/config.d.ts +2 -2
  85. package/dist/config.js +15 -4
  86. package/dist/constants.js +6 -0
  87. package/dist/cross-chain-margin.d.ts +3 -1
  88. package/dist/cross-chain-margin.js +4 -2
  89. package/dist/dashboard/server.js +3 -3
  90. package/dist/dashboard/ui.js +9 -6
  91. package/dist/errors.d.ts +29 -1
  92. package/dist/errors.js +35 -3
  93. package/dist/exchanges/address.d.ts +8 -0
  94. package/dist/exchanges/address.js +47 -0
  95. package/dist/exchanges/arcus/adapter.d.ts +16 -12
  96. package/dist/exchanges/arcus/adapter.js +45 -18
  97. package/dist/exchanges/arcus/agent.d.ts +1 -1
  98. package/dist/exchanges/arcus/agent.js +1 -1
  99. package/dist/exchanges/arcus/client.js +1 -1
  100. package/dist/exchanges/arcus/public.js +3 -2
  101. package/dist/exchanges/arcus/signing.d.ts +2 -3
  102. package/dist/exchanges/arcus/signing.js +1 -1
  103. package/dist/exchanges/arcus/spot-chain.d.ts +1 -1
  104. package/dist/exchanges/arcus/spot-chain.js +1 -1
  105. package/dist/exchanges/arcus/spot-router.d.ts +1 -1
  106. package/dist/exchanges/arcus/spot-router.js +2 -2
  107. package/dist/exchanges/arcus/spot.d.ts +2 -3
  108. package/dist/exchanges/arcus/spot.js +2 -3
  109. package/dist/exchanges/aster-spot.d.ts +3 -3
  110. package/dist/exchanges/aster-spot.js +6 -9
  111. package/dist/exchanges/aster-typed-data.d.ts +1 -1
  112. package/dist/exchanges/aster-typed-data.js +1 -1
  113. package/dist/exchanges/aster.d.ts +30 -10
  114. package/dist/exchanges/aster.js +153 -53
  115. package/dist/exchanges/builder-fee.d.ts +1 -1
  116. package/dist/exchanges/builder-fee.js +13 -2
  117. package/dist/exchanges/canonical-symbols.d.ts +8 -2
  118. package/dist/exchanges/canonical-symbols.js +46 -2
  119. package/dist/exchanges/capabilities.d.ts +2 -0
  120. package/dist/exchanges/capabilities.js +2 -1
  121. package/dist/exchanges/derive/client.d.ts +37 -0
  122. package/dist/exchanges/derive/client.js +135 -0
  123. package/dist/exchanges/derive/options.d.ts +73 -0
  124. package/dist/exchanges/derive/options.js +379 -0
  125. package/dist/exchanges/extended/adapter.d.ts +96 -0
  126. package/dist/exchanges/extended/adapter.js +241 -0
  127. package/dist/exchanges/extended/client.d.ts +38 -0
  128. package/dist/exchanges/extended/client.js +88 -0
  129. package/dist/exchanges/extended/public.d.ts +133 -0
  130. package/dist/exchanges/extended/public.js +436 -0
  131. package/dist/exchanges/grvt/adapter.d.ts +100 -0
  132. package/dist/exchanges/grvt/adapter.js +283 -0
  133. package/dist/exchanges/grvt/client.d.ts +25 -0
  134. package/dist/exchanges/grvt/client.js +86 -0
  135. package/dist/exchanges/grvt/public.d.ts +151 -0
  136. package/dist/exchanges/grvt/public.js +438 -0
  137. package/dist/exchanges/hyperliquid-outcome.d.ts +2 -0
  138. package/dist/exchanges/hyperliquid-outcome.js +29 -1
  139. package/dist/exchanges/hyperliquid-spot.d.ts +9 -1
  140. package/dist/exchanges/hyperliquid-spot.js +24 -16
  141. package/dist/exchanges/hyperliquid.d.ts +199 -22
  142. package/dist/exchanges/hyperliquid.js +550 -202
  143. package/dist/exchanges/index.d.ts +1 -1
  144. package/dist/exchanges/index.js +1 -1
  145. package/dist/exchanges/interface.d.ts +157 -13
  146. package/dist/exchanges/interface.js +47 -0
  147. package/dist/exchanges/ioc-outcome.d.ts +1 -1
  148. package/dist/exchanges/ioc-outcome.js +1 -1
  149. package/dist/exchanges/legacy-trading-v2.d.ts +2 -2
  150. package/dist/exchanges/legacy-trading-v2.js +7 -2
  151. package/dist/exchanges/lighter-public.d.ts +67 -12
  152. package/dist/exchanges/lighter-public.js +250 -82
  153. package/dist/exchanges/lighter-signer.d.ts +1 -1
  154. package/dist/exchanges/lighter-signer.js +1 -1
  155. package/dist/exchanges/lighter-spot.d.ts +10 -5
  156. package/dist/exchanges/lighter-spot.js +105 -97
  157. package/dist/exchanges/lighter.d.ts +80 -21
  158. package/dist/exchanges/lighter.js +312 -105
  159. package/dist/exchanges/ondo/adapter.d.ts +38 -13
  160. package/dist/exchanges/ondo/adapter.js +86 -27
  161. package/dist/exchanges/ondo/agent.d.ts +1 -1
  162. package/dist/exchanges/ondo/agent.js +1 -1
  163. package/dist/exchanges/ondo/client.d.ts +1 -1
  164. package/dist/exchanges/ondo/client.js +2 -2
  165. package/dist/exchanges/ondo/public.d.ts +35 -3
  166. package/dist/exchanges/ondo/public.js +75 -32
  167. package/dist/exchanges/ondo/spot.d.ts +2 -2
  168. package/dist/exchanges/ondo/spot.js +3 -3
  169. package/dist/exchanges/options-interface.d.ts +158 -0
  170. package/dist/exchanges/options-interface.js +17 -0
  171. package/dist/exchanges/options-venues.d.ts +12 -0
  172. package/dist/exchanges/options-venues.js +35 -0
  173. package/dist/exchanges/outcome-interface.d.ts +4 -0
  174. package/dist/exchanges/pacifica-atomic.d.ts +211 -0
  175. package/dist/exchanges/pacifica-atomic.js +440 -0
  176. package/dist/exchanges/pacifica-decimal.d.ts +10 -0
  177. package/dist/exchanges/pacifica-decimal.js +51 -0
  178. package/dist/exchanges/pacifica-presigned.d.ts +53 -0
  179. package/dist/exchanges/pacifica-presigned.js +141 -0
  180. package/dist/exchanges/pacifica-print.d.ts +200 -0
  181. package/dist/exchanges/pacifica-print.js +417 -0
  182. package/dist/exchanges/pacifica-spot.d.ts +8 -2
  183. package/dist/exchanges/pacifica-spot.js +26 -18
  184. package/dist/exchanges/pacifica-typed-data.d.ts +1 -1
  185. package/dist/exchanges/pacifica-typed-data.js +1 -1
  186. package/dist/exchanges/pacifica-vaults.d.ts +130 -0
  187. package/dist/exchanges/pacifica-vaults.js +277 -0
  188. package/dist/exchanges/pacifica.d.ts +108 -10
  189. package/dist/exchanges/pacifica.js +428 -171
  190. package/dist/exchanges/precision.d.ts +3 -1
  191. package/dist/exchanges/precision.js +9 -2
  192. package/dist/exchanges/public-balances.d.ts +25 -0
  193. package/dist/exchanges/public-balances.js +158 -0
  194. package/dist/exchanges/public-positions.d.ts +43 -0
  195. package/dist/exchanges/public-positions.js +154 -0
  196. package/dist/exchanges/qfex/adapter.d.ts +69 -13
  197. package/dist/exchanges/qfex/adapter.js +102 -17
  198. package/dist/exchanges/qfex/agent.d.ts +1 -1
  199. package/dist/exchanges/qfex/agent.js +1 -1
  200. package/dist/exchanges/qfex/client.d.ts +1 -1
  201. package/dist/exchanges/qfex/client.js +1 -1
  202. package/dist/exchanges/qfex/errors.d.ts +1 -1
  203. package/dist/exchanges/qfex/errors.js +2 -2
  204. package/dist/exchanges/qfex/public.d.ts +65 -12
  205. package/dist/exchanges/qfex/public.js +131 -25
  206. package/dist/exchanges/qfex/signing.d.ts +2 -2
  207. package/dist/exchanges/qfex/signing.js +4 -5
  208. package/dist/exchanges/qfex/ws-transport.d.ts +3 -3
  209. package/dist/exchanges/qfex/ws-transport.js +3 -3
  210. package/dist/exchanges/rate-limiter.d.ts +1 -1
  211. package/dist/exchanges/rate-limiter.js +5 -2
  212. package/dist/exchanges/registry.d.ts +1 -1
  213. package/dist/exchanges/registry.js +1 -1
  214. package/dist/exchanges/risex/adapter.d.ts +160 -0
  215. package/dist/exchanges/risex/adapter.js +842 -0
  216. package/dist/exchanges/risex/agent.d.ts +154 -0
  217. package/dist/exchanges/risex/agent.js +384 -0
  218. package/dist/exchanges/risex/client.d.ts +47 -0
  219. package/dist/exchanges/risex/client.js +174 -0
  220. package/dist/exchanges/risex/nonce.d.ts +43 -0
  221. package/dist/exchanges/risex/nonce.js +212 -0
  222. package/dist/exchanges/risex/public.d.ts +64 -0
  223. package/dist/exchanges/risex/public.js +150 -0
  224. package/dist/exchanges/risex/session.d.ts +71 -0
  225. package/dist/exchanges/risex/session.js +171 -0
  226. package/dist/exchanges/risex/typed-data.d.ts +173 -0
  227. package/dist/exchanges/risex/typed-data.js +240 -0
  228. package/dist/exchanges/risex/units.d.ts +29 -0
  229. package/dist/exchanges/risex/units.js +104 -0
  230. package/dist/exchanges/slippage.d.ts +1 -1
  231. package/dist/exchanges/slippage.js +1 -1
  232. package/dist/exchanges/spot-factory.d.ts +3 -3
  233. package/dist/exchanges/spot-factory.js +8 -8
  234. package/dist/exchanges/spot-interface.d.ts +5 -5
  235. package/dist/exchanges/spot-interface.js +2 -2
  236. package/dist/exchanges/spot-result.d.ts +3 -3
  237. package/dist/exchanges/spot-result.js +3 -3
  238. package/dist/exchanges/trading-v2.d.ts +3 -3
  239. package/dist/exchanges/trading-v2.js +9 -6
  240. package/dist/exchanges/txflow/adapter.d.ts +61 -0
  241. package/dist/exchanges/txflow/adapter.js +150 -0
  242. package/dist/exchanges/txflow/client.d.ts +47 -0
  243. package/dist/exchanges/txflow/client.js +155 -0
  244. package/dist/exchanges/txflow/public.d.ts +87 -0
  245. package/dist/exchanges/txflow/public.js +355 -0
  246. package/dist/exchanges/unknown-symbol.d.ts +34 -0
  247. package/dist/exchanges/unknown-symbol.js +56 -0
  248. package/dist/exchanges/variational/adapter.d.ts +67 -0
  249. package/dist/exchanges/variational/adapter.js +137 -0
  250. package/dist/exchanges/variational/client.d.ts +21 -0
  251. package/dist/exchanges/variational/client.js +66 -0
  252. package/dist/exchanges/variational/public.d.ts +126 -0
  253. package/dist/exchanges/variational/public.js +430 -0
  254. package/dist/exchanges/venue-types.d.ts +52 -10
  255. package/dist/exchanges/venue-types.js +82 -11
  256. package/dist/exchanges/venue.d.ts +150 -11
  257. package/dist/exchanges/venue.js +126 -4
  258. package/dist/exchanges/venues/arcus.d.ts +1 -2
  259. package/dist/exchanges/venues/arcus.js +5 -4
  260. package/dist/exchanges/venues/aster.d.ts +2 -2
  261. package/dist/exchanges/venues/aster.js +6 -4
  262. package/dist/exchanges/venues/create-helpers.d.ts +1 -1
  263. package/dist/exchanges/venues/create-helpers.js +3 -3
  264. package/dist/exchanges/venues/extended.d.ts +21 -0
  265. package/dist/exchanges/venues/extended.js +96 -0
  266. package/dist/exchanges/venues/grvt.d.ts +30 -0
  267. package/dist/exchanges/venues/grvt.js +98 -0
  268. package/dist/exchanges/venues/hyperliquid.d.ts +2 -2
  269. package/dist/exchanges/venues/hyperliquid.js +19 -8
  270. package/dist/exchanges/venues/index.d.ts +7 -2
  271. package/dist/exchanges/venues/index.js +8 -2
  272. package/dist/exchanges/venues/lighter-family.d.ts +7 -9
  273. package/dist/exchanges/venues/lighter-family.js +9 -11
  274. package/dist/exchanges/venues/lighter-rh.d.ts +2 -2
  275. package/dist/exchanges/venues/lighter-rh.js +20 -8
  276. package/dist/exchanges/venues/lighter.d.ts +1 -1
  277. package/dist/exchanges/venues/lighter.js +18 -6
  278. package/dist/exchanges/venues/ondo.d.ts +1 -1
  279. package/dist/exchanges/venues/ondo.js +5 -3
  280. package/dist/exchanges/venues/pacifica.d.ts +2 -2
  281. package/dist/exchanges/venues/pacifica.js +15 -4
  282. package/dist/exchanges/venues/qfex.d.ts +1 -1
  283. package/dist/exchanges/venues/qfex.js +4 -2
  284. package/dist/exchanges/venues/risex-release.d.ts +14 -0
  285. package/dist/exchanges/venues/risex-release.js +14 -0
  286. package/dist/exchanges/venues/risex.d.ts +31 -0
  287. package/dist/exchanges/venues/risex.js +131 -0
  288. package/dist/exchanges/venues/txflow.d.ts +18 -0
  289. package/dist/exchanges/venues/txflow.js +77 -0
  290. package/dist/exchanges/venues/variational.d.ts +21 -0
  291. package/dist/exchanges/venues/variational.js +85 -0
  292. package/dist/execution-log.d.ts +1 -1
  293. package/dist/funding/legacy-public.d.ts +6 -4
  294. package/dist/funding/legacy-public.js +42 -41
  295. package/dist/funding/normalize.d.ts +1 -1
  296. package/dist/funding/normalize.js +1 -1
  297. package/dist/funding/rates.d.ts +95 -6
  298. package/dist/funding/rates.js +99 -19
  299. package/dist/index.js +7 -6
  300. package/dist/jobs.d.ts +1 -0
  301. package/dist/jobs.js +25 -1
  302. package/dist/landing.d.ts +2 -0
  303. package/dist/landing.js +1 -1
  304. package/dist/liquidity.d.ts +3 -1
  305. package/dist/liquidity.js +8 -4
  306. package/dist/mcp-pacifica-earn.d.ts +9 -0
  307. package/dist/mcp-pacifica-earn.js +64 -0
  308. package/dist/mcp-server.js +211 -68
  309. package/dist/pacifica/client.d.ts +69 -5
  310. package/dist/pacifica/client.js +181 -8
  311. package/dist/pacifica/rate-limit.d.ts +144 -0
  312. package/dist/pacifica/rate-limit.js +267 -0
  313. package/dist/pacifica/types/order.d.ts +2 -1
  314. package/dist/plan-executor.js +7 -2
  315. package/dist/positions-by-address.d.ts +34 -0
  316. package/dist/positions-by-address.js +46 -0
  317. package/dist/rebalance.js +1 -1
  318. package/dist/risk.d.ts +2 -1
  319. package/dist/risk.js +2 -4
  320. package/dist/settings.d.ts +32 -3
  321. package/dist/signer/ows-evm.d.ts +1 -1
  322. package/dist/signer/ows-evm.js +1 -1
  323. package/dist/smart-order.d.ts +1 -1
  324. package/dist/smart-order.js +1 -1
  325. package/dist/strategies/funding-arb.d.ts +1 -1
  326. package/dist/strategies/funding-arb.js +36 -63
  327. package/dist/trade-validator.js +2 -2
  328. package/dist/utils.d.ts +22 -3
  329. package/dist/utils.js +11 -3
  330. package/dist/venue-health.d.ts +40 -0
  331. package/dist/venue-health.js +75 -0
  332. package/dist/withdraw-gate.d.ts +1 -1
  333. package/dist/withdraw-gate.js +1 -1
  334. package/dist/ws/arcus-market.d.ts +9 -0
  335. package/dist/ws/arcus-market.js +9 -0
  336. package/dist/ws/aster-market.d.ts +33 -0
  337. package/dist/ws/aster-market.js +30 -0
  338. package/dist/ws/index.d.ts +980 -0
  339. package/dist/ws/index.js +4460 -0
  340. package/dist/ws/lighter-market.d.ts +14 -0
  341. package/dist/ws/lighter-market.js +13 -0
  342. package/dist/ws/node.d.ts +996 -0
  343. package/dist/ws/node.js +4554 -0
  344. package/dist/ws/pacifica-instrument.d.ts +8 -0
  345. package/dist/ws/pacifica-instrument.js +8 -0
  346. package/dist/ws/unclassified.d.ts +16 -0
  347. package/dist/ws/unclassified.js +43 -0
  348. package/dist/ws-cli/credentials.d.ts +62 -0
  349. package/dist/ws-cli/credentials.js +126 -0
  350. package/package.json +71 -10
  351. package/skills/perp-cli/SKILL.md +153 -36
  352. package/skills/perp-cli/package.json +15 -2
  353. package/skills/perp-cli/references/agent-operations.md +22 -12
  354. package/skills/perp-cli/references/commands.md +143 -17
  355. package/skills/perp-cli/references/strategies.md +38 -3
  356. package/skills/perp-cli/references/ws-library.md +523 -0
  357. package/skills/perp-cli/scripts/arb-monitor.sh +13 -10
  358. package/skills/perp-cli/scripts/funding-analysis.sh +57 -29
  359. package/skills/perp-cli/scripts/preflight.sh +27 -19
  360. package/skills/perp-cli/scripts/spot-perp-scan.sh +58 -38
  361. package/skills/perp-cli/scripts/validate-arb.sh +56 -39
  362. package/dist/cli-spec.d.ts +0 -46
  363. package/dist/cli-spec.js +0 -81
@@ -1,59 +1,45 @@
1
1
  /**
2
- * Lighter-family public market data (`lighter`, `lighter-rh`) — design §10.6.
2
+ * Lighter-family public market data (`lighter`, `lighter-rh`).
3
3
  *
4
4
  * Sources (REST base from venues/lighter-family.ts, per venue + network):
5
5
  * GET /api/v1/orderBookDetails → perps in `order_book_details` (decimals, min
6
6
  * amounts, status, mark/index price, IMF, OI, volume). It carries every
7
7
  * field /orderBooks has, so /orderBooks is not fetched (one fewer call
8
8
  * under the 60 req/min standard limit).
9
- * GET /api/v1/funding-rates → MULTI-EXCHANGE aggregate (binance/bybit/
10
- * hyperliquid/lighter). Only rows with exchange === "lighter" are the
11
- * venue's own; the RH host labels its own rows "lighter" too (live
12
- * 2026-09-30: 57 "lighter" rows = RH's 57 perps, matched by market_id).
9
+ * WS market_stats/all (first frame) → per market `funding_rate` (LAST SETTLED, percent per
10
+ * 1 h; = the newest GET /fundings print) and `current_funding_rate` (predicted). REST
11
+ * /funding-rates is the predicted rate × 8 and is not read here (fetchLighterFundingStats).
13
12
  *
14
- * FUNDING: basis 8h per quoted rate, hourly settlement (design §10.1, Lighter
15
- * and Lighter RH identical).
13
+ * FUNDING: market / funding rows carry the settled rate per 1 h (hourly settlement; Lighter and
14
+ * Lighter RH identical).
16
15
  *
17
16
  * ASSET CLASS: the API has no asset-class field (the undocumented
18
17
  * `strategy_index` groups markets on Lighter main but is 0 for every RH market),
19
18
  * so classification is an explicit per-venue table built from live listings on
20
19
  * 2026-09-30:
21
- * - lighter-rh: every listed perp is in RH_CLASS. An unlisted symbol is
22
- * excluded with a warning until it is classified (RH lists mostly equities,
23
- * so no class can be assumed).
20
+ * - lighter-rh: every listed perp is in LIGHTER_RH_CLASS (src/ws/unclassified.ts). An unlisted symbol is
21
+ * "unclassified" (listed, canonical null) until it is classified (RH lists
22
+ * mostly equities, so no class can be assumed).
24
23
  * - lighter: crypto-centric venue. LIGHTER_NON_CRYPTO lists every non-crypto
25
24
  * perp; any other symbol is crypto by this venue's definition.
26
- * LIGHTER_AMBIGUOUS tickers are excluded with a warning so they cannot
27
- * produce a false cross-venue match.
25
+ * UNCLASSIFIED_TICKERS.lighter (src/ws/unclassified.ts) are "unclassified" (listed, canonical null) so
26
+ * they cannot produce a false cross-venue match.
28
27
  *
29
28
  * OPEN INTEREST: `open_interest` in base units (same value legacy getMarkets reports).
30
29
  */
31
30
  import { PerpError } from "../errors.js";
32
- import { venueRateField } from "../utils/numeric.js";
33
31
  import { acquireRate, rateLimitedError } from "./rate-limiter.js";
34
32
  import { canonicalFor } from "./canonical-symbols.js";
33
+ import { isLighterMarketLive } from "../ws/lighter-market.js";
34
+ import { isUnclassifiedTicker, LIGHTER_RH_CLASS } from "../ws/unclassified.js";
35
+ import { addDecimal, mulDecimal } from "./precision.js";
36
+ import { nextTopOfHourMs } from "./venue-types.js";
35
37
  import { lighterFamilyNetworks, lighterFamilyRateLimit } from "./venues/lighter-family.js";
36
- const BASIS_8H = { kind: "perHours", hours: 8 };
38
+ /** Market rows / funding rows carry the settled HOURLY rate (market_stats funding_rate): per 1 h. */
39
+ const BASIS_1H = { kind: "perHours", hours: 1 };
37
40
  const SETTLEMENT_INTERVAL_HOURS = 1;
38
41
  // ── Classification tables (live listings 2026-09-30) ──
39
- const RH_CLASS = {
40
- // crypto
41
- BTC: "crypto", ETH: "crypto", SOL: "crypto", HYPE: "crypto", ZEC: "crypto", LIT: "crypto",
42
- VVV: "crypto", SUI: "crypto", NEAR: "crypto", XRP: "crypto", CASHCAT: "crypto", PONS: "crypto",
43
- // commodity (canonical via EXPLICIT_CANONICAL: XAU → GOLD, XAG → SILVER)
44
- XAU: "commodity", XAG: "commodity",
45
- // etf
46
- SPY: "etf", QQQ: "etf", SOXL: "etf", SLV: "etf", USO: "etf", SGOV: "etf",
47
- // equity
48
- AAPL: "equity", AMZN: "equity", GOOGL: "equity", META: "equity", MSFT: "equity", NVDA: "equity",
49
- TSLA: "equity", AMD: "equity", INTC: "equity", MU: "equity", TSM: "equity", ORCL: "equity",
50
- PLTR: "equity", COIN: "equity", CRCL: "equity", CRWV: "equity", BABA: "equity", SNDK: "equity",
51
- SMCI: "equity", SOFI: "equity", AMC: "equity", RGTI: "equity", QBTS: "equity", CLSK: "equity",
52
- IREN: "equity", WULF: "equity", LUNR: "equity", ASTS: "equity", BE: "equity", USAR: "equity",
53
- SPCX: "equity", SKHY: "equity",
54
- // pre-IPO / private (explicit-only canonical → null unless mapped)
55
- OPENAI: "preIpo", ANTHROPIC: "preIpo", SHEIN: "preIpo", ANSEM: "preIpo", AI: "preIpo",
56
- };
42
+ // RH_CLASS (Lighter RH listing classification) lives in src/ws/unclassified.ts, shared with the WS directory.
57
43
  const LIGHTER_NON_CRYPTO = {
58
44
  // commodity
59
45
  XAU: "commodity", XAG: "commodity", XPD: "commodity", XPT: "commodity", XCU: "commodity",
@@ -85,21 +71,19 @@ const LIGHTER_NON_CRYPTO = {
85
71
  ZHIPU: "preIpo", UNITREE: "preIpo", MINIMAX: "preIpo", AI: "preIpo", ANSEM: "preIpo",
86
72
  STABLECOINX: "preIpo", OURA: "preIpo", PRL: "preIpo", ADI: "preIpo",
87
73
  };
74
+ // Ambiguous Lighter tickers (BB, BOT, WEN, QNT, SPX): UNCLASSIFIED_TICKERS in src/ws/unclassified.ts.
88
75
  /**
89
- * Excluded from cross-venue data until mapped explicitly:
90
- * - BB, BOT, WEN, QNT: Lighter groups them with US equities, but each is also a live crypto ticker elsewhere.
91
- * - SPX: the SPX6900 token on Lighter; its ticker equals the canonical key of the S&P 500 index ("SPX").
76
+ * Asset class for a venue symbol; "unclassified" (canonical null — listed, never matched across
77
+ * venues) when it is ambiguous or not mapped.
92
78
  */
93
- const LIGHTER_AMBIGUOUS = new Set(["BB", "BOT", "WEN", "QNT", "SPX"]);
94
- /** Asset class for a venue symbol, or null when it must be excluded (unclassified / ambiguous). */
95
79
  function classify(venue, symbol) {
96
80
  const up = symbol.toUpperCase();
97
81
  switch (venue) {
98
82
  case "lighter-rh":
99
- return RH_CLASS[up] ?? null;
83
+ return LIGHTER_RH_CLASS[up] ?? "unclassified";
100
84
  case "lighter":
101
- if (LIGHTER_AMBIGUOUS.has(up))
102
- return null;
85
+ if (isUnclassifiedTicker("lighter", up))
86
+ return "unclassified";
103
87
  return LIGHTER_NON_CRYPTO[up] ?? "crypto"; // crypto-centric venue: non-crypto is listed explicitly
104
88
  }
105
89
  }
@@ -130,7 +114,56 @@ export function lighterWafChallenge(venue, status, body) {
130
114
  remediation: `Wait 1–2 minutes before the next ${venue} request, then retry at a lower request rate (standard accounts: 60 requests per rolling minute)`,
131
115
  });
132
116
  }
133
- async function getJson(venue, net, path, endpoint) {
117
+ /** `limit` of GET /api/v1/orderBookOrders: the documented maximum (apidocs.lighter.xyz/reference/orderbookorders, 1..250). */
118
+ export const LIGHTER_BOOK_ORDERS_LIMIT = 250;
119
+ /**
120
+ * One side of GET /api/v1/orderBookOrders (individual resting ORDERS, best price first) → price
121
+ * levels: `remaining_base_amount` summed per price, in the venue's order — the shape of the WS
122
+ * `order_book/{id}` channel (levels). A side of exactly `limit` orders may have more orders at its
123
+ * last price beyond the page, so that (possibly partial) level is dropped. A row without a price /
124
+ * remaining amount is a payload error (never skipped, never "0").
125
+ */
126
+ export function lighterBookLevels(venue, rows, what, limit = LIGHTER_BOOK_ORDERS_LIMIT) {
127
+ if (rows === undefined || rows === null)
128
+ return [];
129
+ if (!Array.isArray(rows))
130
+ throw new PerpError("EXCHANGE_ERROR", `${venue} orderBookOrders ${what}: side is not a list`, { exchange: venue });
131
+ const levels = new Map();
132
+ for (const r of rows) {
133
+ const price = r?.price;
134
+ const size = r?.remaining_base_amount ?? r?.size;
135
+ if (typeof price !== "string" || typeof size !== "string" || !Number.isFinite(Number(price)) || !Number.isFinite(Number(size))) {
136
+ throw new PerpError("EXCHANGE_ERROR", `${venue} orderBookOrders ${what}: order without price / remaining size: ${JSON.stringify(r).slice(0, 160)}`, { exchange: venue });
137
+ }
138
+ const prev = levels.get(price);
139
+ levels.set(price, prev === undefined ? size : addDecimal(prev, size));
140
+ }
141
+ const out = Array.from(levels);
142
+ if (rows.length >= limit && out.length > 1)
143
+ out.pop();
144
+ return out;
145
+ }
146
+ /**
147
+ * A GET /orderBookOrders answer → price levels per side, cut to `depth`. A side whose page is full
148
+ * (LIGHTER_BOOK_ORDERS_LIMIT orders, the endpoint max) but aggregates to fewer than `depth` levels
149
+ * cannot be paged: INVALID_PARAMS naming the 250-order cap, never a silently shallower book.
150
+ */
151
+ export function lighterBook(venue, res, what, depth) {
152
+ const bids = lighterBookLevels(venue, res.bids, `${what} bids`);
153
+ const asks = lighterBookLevels(venue, res.asks, `${what} asks`);
154
+ if (depth === undefined)
155
+ return { bids, asks };
156
+ const full = (rows) => Array.isArray(rows) && rows.length >= LIGHTER_BOOK_ORDERS_LIMIT;
157
+ for (const [side, rows, levels] of [["bids", res.bids, bids], ["asks", res.asks, asks]]) {
158
+ if (full(rows) && levels.length < depth) {
159
+ throw new PerpError("INVALID_PARAMS", `${venue} order book: ${what} ${side} — ${LIGHTER_BOOK_ORDERS_LIMIT} orders (the endpoint max, no paging) make only ${levels.length} price levels; --depth ${depth} cannot be served`, {
160
+ exchange: venue, remediation: `Use --depth ${levels.length} or less`,
161
+ });
162
+ }
163
+ }
164
+ return { bids: bids.slice(0, depth), asks: asks.slice(0, depth) };
165
+ }
166
+ async function getJson(venue, net, path, endpoint, notFound) {
134
167
  await acquireRate(`${venue}:${net}`, lighterFamilyRateLimit(venue), endpoint);
135
168
  const base = lighterFamilyNetworks(venue)[net].restUrl;
136
169
  const res = await fetch(`${base}/api/v1${path}`, { signal: AbortSignal.timeout(15_000) });
@@ -140,6 +173,8 @@ async function getJson(venue, net, path, endpoint) {
140
173
  const waf = lighterWafChallenge(venue, res.status, text);
141
174
  if (waf !== null)
142
175
  throw waf;
176
+ if (notFound !== undefined && notFound(res.status, text))
177
+ return null;
143
178
  if (!res.ok) {
144
179
  throw new PerpError("EXCHANGE_ERROR", `${venue} GET ${path} HTTP ${res.status}`, { body: text.slice(0, 500) });
145
180
  }
@@ -181,23 +216,150 @@ async function fetchPerpDetails(venue, net) {
181
216
  warnExcluded(venue, "malformed market(s)", malformed);
182
217
  return out;
183
218
  }
184
- /** The venue's own funding rows, keyed by market_id. */
185
- async function fetchOwnFunding(venue, net) {
186
- const json = await getJson(venue, net, "/funding-rates", "funding-rates");
187
- const list = json.funding_rates;
188
- if (!Array.isArray(list)) {
189
- throw new PerpError("EXCHANGE_ERROR", `${venue} funding-rates: missing funding_rates array`);
219
+ /**
220
+ * Every account of an L1 (EVM) address — `GET /account?by=l1_address&value=` (public). One
221
+ * address can own several accounts (sub-accounts). An address without a Lighter account answers
222
+ * HTTP 400 `{"code":21100,"message":"account not found"}` (live 2026-10-19) → null, not an error.
223
+ */
224
+ export async function fetchLighterAccountsByL1(venue, net, address) {
225
+ const json = await getJson(venue, net, `/account?by=l1_address&value=${encodeURIComponent(address)}`, "account", (status, text) => status === 400 && /"code"\s*:\s*21100\b/.test(text));
226
+ if (json === null)
227
+ return null;
228
+ const list = json.accounts;
229
+ if (!Array.isArray(list))
230
+ throw new PerpError("EXCHANGE_ERROR", `${venue} account: missing accounts array`, { exchange: venue });
231
+ return list;
232
+ }
233
+ /** Perp price decimals by symbol (upper case) — `GET /orderBooks` `supported_price_decimals`, as the adapter's market map. */
234
+ export async function fetchLighterPriceDecimals(venue, net) {
235
+ const json = await getJson(venue, net, "/orderBooks", "orderBooks");
236
+ const list = json.order_books;
237
+ if (!Array.isArray(list))
238
+ throw new PerpError("EXCHANGE_ERROR", `${venue} orderBooks: missing order_books array`, { exchange: venue });
239
+ const out = new Map();
240
+ for (const d of list) {
241
+ if (d.market_type === "perp" && typeof d.symbol === "string" && Number.isInteger(d.supported_price_decimals))
242
+ out.set(d.symbol.toUpperCase(), d.supported_price_decimals);
190
243
  }
191
- const map = new Map();
192
- for (const r of list) {
193
- if (r.exchange !== "lighter")
194
- continue; // other exchanges' rates in the aggregate
195
- if (!Number.isInteger(r.market_id) || typeof r.symbol !== "string" || typeof r.rate !== "number" || !Number.isFinite(r.rate)) {
196
- throw new PerpError("EXCHANGE_ERROR", `${venue} funding-rates: malformed own row ${JSON.stringify(r).slice(0, 200)}`);
197
- }
198
- map.set(r.market_id, r);
244
+ return out;
245
+ }
246
+ /** market_stats rates are PERCENT per 1 h (codec notes): exact × 0.01. undefined = malformed. */
247
+ function percentToFraction(v) {
248
+ if (v === undefined || v === null)
249
+ return null;
250
+ const s = typeof v === "string" ? v.trim() : typeof v === "number" && Number.isFinite(v) ? String(v) : null;
251
+ if (s === null || !/^-?\d+(\.\d+)?$/.test(s))
252
+ return undefined;
253
+ return mulDecimal(s, "0.01"); // exact (no float)
254
+ }
255
+ const STATS_TTL_MS = 10_000;
256
+ /** A failed read is remembered this long (one stderr line / meta warning, not a socket per call). */
257
+ const STATS_FAILURE_TTL_MS = 60_000;
258
+ const STATS_TIMEOUT_MS = 4_000;
259
+ const statsCache = new Map();
260
+ /** Drop the shared market_stats snapshots and remembered failures (tests; a network switch). */
261
+ export function clearLighterFundingStatsCache() {
262
+ statsCache.clear();
263
+ }
264
+ /**
265
+ * Why the settled rate of `venue` / `net` is unavailable right now (the remembered failure of the
266
+ * last snapshot read), null when it was read or not tried. Callers put it in `meta.warnings`
267
+ * (CLI --json, MCP) next to the rows whose fundingRate is null.
268
+ */
269
+ export function lighterFundingStatsWarning(venue, net) {
270
+ const hit = statsCache.get(`${venue}:${net}`);
271
+ return hit !== undefined && hit.failure !== null && Date.now() - hit.at < STATS_FAILURE_TTL_MS
272
+ ? `${venue}: fundingRate null — settled funding rate unavailable (${hit.failure})` : null;
273
+ }
274
+ /**
275
+ * Settled + predicted hourly funding of every market, keyed by market_id: the SNAPSHOT frame
276
+ * (`subscribed/market_stats`, channel `market_stats:all` — later `update/…` frames carry only the
277
+ * markets that changed) of the WS `market_stats/all` channel, the source of the perp-ws `rate` /
278
+ * `predictedRate`. REST has no bulk settled source: /funding-rates is the PREDICTED rate × 8 (live
279
+ * 2026-10-19: ETH 0.0009 % /h predicted → 0.000072; settled 0.0012 % /h), and /fundings is one
280
+ * market per request. One snapshot per venue / network is shared STATS_TTL_MS; a failure is
281
+ * remembered STATS_FAILURE_TTL_MS (lighterFundingStatsWarning).
282
+ */
283
+ export function fetchLighterFundingStats(venue, net) {
284
+ const key = `${venue}:${net}`;
285
+ const hit = statsCache.get(key);
286
+ if (hit !== undefined && Date.now() - hit.at < (hit.failure === null ? STATS_TTL_MS : STATS_FAILURE_TTL_MS))
287
+ return hit.value;
288
+ const value = readFundingStats(venue, net);
289
+ const entry = { at: Date.now(), value, failure: null };
290
+ statsCache.set(key, entry);
291
+ value.catch((e) => {
292
+ const code = e instanceof PerpError ? `${e.structured.code}: ` : "";
293
+ entry.failure = `${code}${e instanceof Error ? e.message : String(e)}`;
294
+ entry.at = Date.now();
295
+ });
296
+ return value;
297
+ }
298
+ async function readFundingStats(venue, net) {
299
+ const url = lighterFamilyNetworks(venue)[net].wsUrl;
300
+ if (url === null) {
301
+ throw new PerpError("CAPABILITY_UNSUPPORTED", `${venue} ${net} publishes no WebSocket endpoint, so its settled funding rate (market_stats) cannot be read`, { exchange: venue });
199
302
  }
200
- return map;
303
+ const { default: WebSocket } = await import("ws");
304
+ return new Promise((resolve, reject) => {
305
+ const ws = new WebSocket(url);
306
+ let settled = false;
307
+ const done = (err, value) => {
308
+ if (settled)
309
+ return;
310
+ settled = true;
311
+ clearTimeout(timer);
312
+ try {
313
+ ws.close();
314
+ }
315
+ catch { /* already closed */ }
316
+ if (err !== null)
317
+ reject(err);
318
+ else
319
+ resolve(value);
320
+ };
321
+ const timer = setTimeout(() => done(new PerpError("EXCHANGE_UNREACHABLE", `${venue} market_stats: no snapshot within ${STATS_TIMEOUT_MS / 1000} s`, { exchange: venue })), STATS_TIMEOUT_MS);
322
+ ws.on("open", () => ws.send(JSON.stringify({ type: "subscribe", channel: "market_stats/all" })));
323
+ ws.on("error", (e) => done(new PerpError("EXCHANGE_UNREACHABLE", `${venue} market_stats: ${e.message}`, { exchange: venue })));
324
+ ws.on("close", (code) => done(new PerpError("EXCHANGE_UNREACHABLE", `${venue} market_stats: socket closed (code ${code}) before the snapshot`, { exchange: venue })));
325
+ ws.on("message", (data) => {
326
+ let f;
327
+ try {
328
+ f = JSON.parse(String(data));
329
+ }
330
+ catch {
331
+ return;
332
+ }
333
+ if (f.error !== undefined) {
334
+ done(new PerpError("EXCHANGE_ERROR", `${venue} market_stats: ${JSON.stringify(f.error).slice(0, 200)}`, { exchange: venue }));
335
+ return;
336
+ }
337
+ // Only the snapshot frame has every market ("connected" and update frames are skipped).
338
+ if (f.type !== "subscribed/market_stats" || f.channel !== "market_stats:all")
339
+ return;
340
+ const stats = f.market_stats;
341
+ if (stats === null || typeof stats !== "object") {
342
+ done(new PerpError("EXCHANGE_ERROR", `${venue} market_stats snapshot without market_stats`, { exchange: venue }));
343
+ return;
344
+ }
345
+ const out = new Map();
346
+ const malformed = [];
347
+ for (const [id, r] of Object.entries(stats)) {
348
+ if (r === null || typeof r !== "object") {
349
+ malformed.push(`#${id}`);
350
+ continue;
351
+ }
352
+ const rate = percentToFraction(r.funding_rate);
353
+ const predictedRate = percentToFraction(r.current_funding_rate);
354
+ if (rate === undefined || predictedRate === undefined)
355
+ malformed.push(typeof r.symbol === "string" ? r.symbol : `#${id}`);
356
+ out.set(Number(id), { rate: rate ?? null, predictedRate: predictedRate ?? null });
357
+ }
358
+ if (malformed.length > 0)
359
+ console.warn(`[${venue}] market_stats: ${malformed.length} market(s) with a malformed funding value (rate null): ${malformed.slice(0, 10).join(", ")}`);
360
+ done(null, out);
361
+ });
362
+ });
201
363
  }
202
364
  function stepFromDecimals(d) {
203
365
  return d === 0 ? "1" : `0.${"0".repeat(d - 1)}1`;
@@ -216,8 +378,9 @@ function toMarket(venue, net, d, assetClass, fr) {
216
378
  quoteAsset: null,
217
379
  markPrice: d.mark_price,
218
380
  indexPrice: isNumStr(d.index_price) ? d.index_price : null,
219
- fundingRate: fr ? venueRateField(fr.rate, "funding-rates rate", venue) : null,
220
- fundingRateBasis: BASIS_8H,
381
+ // Last settled hourly rate (market_stats funding_rate), per 1 h — the perp-ws `rate`.
382
+ fundingRate: fr?.rate ?? null,
383
+ fundingRateBasis: BASIS_1H,
221
384
  settlementIntervalHours: SETTLEMENT_INTERVAL_HOURS,
222
385
  openInterest: typeof d.open_interest === "number" ? String(d.open_interest) : null,
223
386
  volume24h: typeof d.daily_quote_token_volume === "number" ? String(d.daily_quote_token_volume) : null,
@@ -228,48 +391,53 @@ function toMarket(venue, net, d, assetClass, fr) {
228
391
  maxLeverage: Math.floor(10000 / d.min_initial_margin_fraction),
229
392
  marginTiers: null,
230
393
  session: null, // RH: 24/7, no session info published
231
- tradable: d.status === "active" && d.is_frozen !== true,
394
+ tradable: isLighterMarketLive(d),
232
395
  };
233
396
  }
234
397
  export function lighterPublicData(venue) {
235
398
  return {
236
- async fetchMarkets(net) {
237
- const [details, funding] = await Promise.all([fetchPerpDetails(venue, net), fetchOwnFunding(venue, net)]);
399
+ async fetchMarkets(net, opts) {
400
+ // The settled rate is the WS snapshot: unreadable → the rows are listed with fundingRate null
401
+ // (unknown, never 0), and the reason is printed.
402
+ const [details, funding] = await Promise.all([
403
+ fetchPerpDetails(venue, net),
404
+ opts?.funding === false ? Promise.resolve(new Map()) : fetchLighterFundingStats(venue, net).catch((e) => {
405
+ console.warn(`[${venue}] settled funding rate unavailable (fundingRate null): ${e instanceof Error ? e.message : String(e)}`);
406
+ return new Map();
407
+ }),
408
+ ]);
238
409
  const out = [];
239
- const unclassified = [];
240
410
  for (const d of details) {
241
- const cls = classify(venue, d.symbol);
242
- if (cls === null) {
243
- unclassified.push(d.symbol);
411
+ // Live markets only (the rule of market list / the WS directory); inactive ones are not listed.
412
+ if (!isLighterMarketLive(d))
244
413
  continue;
245
- }
414
+ const cls = classify(venue, d.symbol);
246
415
  out.push(toMarket(venue, net, d, cls, funding.get(d.market_id)));
247
416
  }
248
- warnExcluded(venue, "unclassified/ambiguous market(s)", unclassified);
249
417
  return out;
250
418
  },
251
419
  async fetchFundingRates(net) {
252
- const funding = await fetchOwnFunding(venue, net);
420
+ // Settled hourly rates of the live markets (the market rows' fundingRate). A failed snapshot
421
+ // propagates: the venue is reported as failed, never a list without Lighter rates.
422
+ const [details, funding] = await Promise.all([fetchPerpDetails(venue, net), fetchLighterFundingStats(venue, net)]);
253
423
  const out = [];
254
- const unclassified = [];
255
- for (const r of funding.values()) {
256
- const cls = classify(venue, r.symbol);
257
- if (cls === null) {
258
- unclassified.push(r.symbol);
424
+ for (const d of details) {
425
+ if (!isLighterMarketLive(d))
259
426
  continue;
260
- }
427
+ const rate = funding.get(d.market_id)?.rate ?? null;
428
+ if (rate === null)
429
+ continue; // no settled print yet: unknown, not 0
261
430
  out.push({
262
431
  venue,
263
- venueSymbol: String(r.market_id),
264
- symbol: r.symbol,
265
- canonical: canonicalFor(venue, r.symbol, cls),
266
- rate: venueRateField(r.rate, "funding-rates rate", venue),
267
- basis: BASIS_8H,
268
- markPrice: null, // /funding-rates carries no mark price
269
- nextFundingTime: null, // not published
432
+ venueSymbol: String(d.market_id),
433
+ symbol: d.symbol,
434
+ canonical: canonicalFor(venue, d.symbol, classify(venue, d.symbol)),
435
+ rate,
436
+ basis: BASIS_1H,
437
+ markPrice: d.mark_price,
438
+ nextFundingTime: nextTopOfHourMs(), // not published; docs: "Funding payments occur at each hour mark"
270
439
  });
271
440
  }
272
- warnExcluded(venue, "unclassified/ambiguous market(s)", unclassified);
273
441
  return out;
274
442
  },
275
443
  };
@@ -22,7 +22,7 @@ export declare const LIGHTER_ALL_MARKETS = 255;
22
22
  /**
23
23
  * One Go runtime of the official signer. The Go `main` registers its functions on
24
24
  * globalThis and then blocks; they are captured synchronously right after `go.run()`
25
- * and the globals restored, so several runtimes (one per venue+network, design §10.5)
25
+ * and the globals restored, so several runtimes (one per venue+network)
26
26
  * never see each other's functions.
27
27
  */
28
28
  export declare class LighterWasmSigner {
@@ -55,7 +55,7 @@ function nonceArg(v) {
55
55
  /**
56
56
  * One Go runtime of the official signer. The Go `main` registers its functions on
57
57
  * globalThis and then blocks; they are captured synchronously right after `go.run()`
58
- * and the globals restored, so several runtimes (one per venue+network, design §10.5)
58
+ * and the globals restored, so several runtimes (one per venue+network)
59
59
  * never see each other's functions.
60
60
  */
61
61
  export class LighterWasmSigner {
@@ -14,6 +14,12 @@ import type { LighterAdapter } from "./lighter.js";
14
14
  * (`filled_base_amount`, the venue's own field — never size − remaining).
15
15
  */
16
16
  export declare const ACCOUNT_ORDERS_FILL_SOURCE = "account-orders";
17
+ /**
18
+ * Spot balances of one Lighter-family account object (GET /account `assets`) — the one mapper
19
+ * behind the keyed spot adapter and the keyless `account balance --address`. `quote` is the
20
+ * venue collateral ("USDC" on Lighter, "USDG" on Lighter RH).
21
+ */
22
+ export declare function lighterSpotBalanceRows(acct: Record<string, unknown>, venue: string, quote: string): SpotBalance[];
17
23
  export declare class LighterSpotAdapter implements SpotAdapter {
18
24
  /** Venue id of the wrapped LighterAdapter ("lighter" | "lighter-rh"). */
19
25
  readonly name: string;
@@ -34,7 +40,7 @@ export declare class LighterSpotAdapter implements SpotAdapter {
34
40
  private _getDecimals;
35
41
  private resolveSymbol;
36
42
  getSpotMarkets(): Promise<SpotMarketInfo[]>;
37
- getSpotOrderbook(symbol: string): Promise<{
43
+ getSpotOrderbook(symbol: string, depth?: number): Promise<{
38
44
  bids: [string, string][];
39
45
  asks: [string, string][];
40
46
  }>;
@@ -74,7 +80,7 @@ export declare class LighterSpotAdapter implements SpotAdapter {
74
80
  tif?: string;
75
81
  }): Promise<unknown>;
76
82
  /**
77
- * TIF mapping, as perps (§13.3): GTC/GTT → GTT, IOC → IOC, ALO / POST_ONLY → post-only (2).
83
+ * TIF mapping, as perps: GTC/GTT → GTT, IOC → IOC, ALO / POST_ONLY → post-only (2).
78
84
  * FOK and anything else → CAPABILITY_UNSUPPORTED (never silently GTT).
79
85
  */
80
86
  private _limitTif;
@@ -107,7 +113,7 @@ export declare class LighterSpotAdapter implements SpotAdapter {
107
113
  transferUsdcToSpot(amount: number): Promise<unknown>;
108
114
  /** Transfer USDC from spot account back to perp account */
109
115
  transferUsdcToPerp(amount: number): Promise<unknown>;
110
- /** SpotTransferCapable (§12.4 #4): only the venue collateral (USDC on Lighter, USDG on Lighter RH). */
116
+ /** SpotTransferCapable: only the venue collateral (USDC on Lighter, USDG on Lighter RH). */
111
117
  transferToSpot(amount: string, asset: string): Promise<unknown>;
112
118
  transferToPerp(amount: string, asset: string): Promise<unknown>;
113
119
  private _transferAmount;
@@ -139,8 +145,7 @@ export declare class LighterSpotAdapter implements SpotAdapter {
139
145
  private _nextClientOrderIndex;
140
146
  private _getNextNonce;
141
147
  /**
142
- * POST /sendTx. `kind` "place" (order placement): failures are typed (design
143
- * §12.3): before the request → ORDER_REJECTED; transport error, HTTP 5xx or an
148
+ * POST /sendTx. `kind` "place" (order placement): failures are typed: before the request → ORDER_REJECTED; transport error, HTTP 5xx or an
144
149
  * unreadable body after it → ORDER_PENDING (the tx may have been accepted — never
145
150
  * resubmit); an explicit non-200 code → ORDER_REJECTED. "order" (cancels) / "action"
146
151
  * (transfers): an explicit non-200 code → ORDER_REJECTED / ACTION_REJECTED