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
@@ -7,10 +7,11 @@
7
7
  * Composes with LighterAdapter for signing and API access.
8
8
  */
9
9
  import { TX_EVENT_FILL_SOURCE } from "./spot-interface.js";
10
- import { lighterWafChallenge } from "./lighter-public.js";
10
+ import { LIGHTER_BOOK_ORDERS_LIMIT, lighterBook, lighterWafChallenge } from "./lighter-public.js";
11
11
  import { LIGHTER_TIF, lighterEventFilledBase, lighterEventOrderId, lighterGeneratedClientOrderIndex, lighterOrderIdOf, lighterOrderSignIndex, lighterPostSendTx, lighterRowOutcomeOf, lighterSelectAccount, lighterTakerFilledBase, lighterTxState, } from "./lighter.js";
12
12
  import { alignProtectionPrice, floorSize, formatComputedPrice, requireOnTick, slippagePrice, subDecimal, toUnitsExact } from "./precision.js";
13
13
  import { unsupported } from "./trading-v2.js";
14
+ import { rateLimitedError } from "./rate-limiter.js";
14
15
  import { PerpError, orderNotSent, parsePositiveDecimal } from "../errors.js";
15
16
  /** The row match (market + send time) _placeOrder attached to its result; absent → null (no extra match). */
16
17
  function lighterRowMatchOf(result) {
@@ -28,6 +29,82 @@ function spotStatusOf(o) {
28
29
  return "partial";
29
30
  return o.status;
30
31
  }
32
+ /**
33
+ * Spot balances of one Lighter-family account object (GET /account `assets`) — the one mapper
34
+ * behind the keyed spot adapter and the keyless `account balance --address`. `quote` is the
35
+ * venue collateral ("USDC" on Lighter, "USDG" on Lighter RH).
36
+ */
37
+ export function lighterSpotBalanceRows(acct, venue, quote) {
38
+ const balances = [];
39
+ if (acct.assets !== undefined && !Array.isArray(acct.assets)) {
40
+ throw new PerpError("EXCHANGE_ERROR", `${venue} spot balances: account.assets is not an array`, { exchange: venue, raw: acct.assets });
41
+ }
42
+ const assets = (acct.assets ?? []);
43
+ // Docs (docs.lighter.xyz/trading/unified-trading-accounts): "Unified Trading Accounts (UTA)
44
+ // enables unified margin on Spot and Perpetuals USDC balances." vs Simple: "perpetual and spot
45
+ // balances are maintained separately." Mode = this same response's account_trading_mode
46
+ // ("Classic=0 and Unified=1", apidocs reference/account-1); an unknown mode fails the quote row.
47
+ const quoteShared = () => {
48
+ const mode = acct.account_trading_mode;
49
+ if (mode !== 0 && mode !== 1) {
50
+ throw new PerpError("EXCHANGE_ERROR", `${venue} spot balances: account_trading_mode is ${JSON.stringify(mode ?? null)} (expected 0 classic | 1 unified)`, {
51
+ exchange: venue,
52
+ remediation: `Retry; check the account with: perp -e ${venue} account info`,
53
+ });
54
+ }
55
+ return mode === 1;
56
+ };
57
+ const plainDecimal = (v, field) => {
58
+ if (typeof v !== "string" || !/^-?\d+(\.\d+)?$/.test(v)) {
59
+ throw new PerpError("EXCHANGE_ERROR", `${venue} spot balances: ${field} is ${JSON.stringify(v ?? null)} (expected a decimal string)`, {
60
+ exchange: venue,
61
+ remediation: `Retry; check the account with: perp -e ${venue} account info`,
62
+ });
63
+ }
64
+ return v;
65
+ };
66
+ for (const asset of assets) {
67
+ const bal = Number(asset.balance);
68
+ const locked = Number(asset.locked_balance);
69
+ if (!Number.isFinite(bal) || !Number.isFinite(locked)) {
70
+ throw new PerpError("EXCHANGE_ERROR", `${venue} spot balance for ${asset.symbol} is not a number (balance=${asset.balance}, locked=${asset.locked_balance})`, { exchange: venue, raw: asset });
71
+ }
72
+ if (asset.symbol === quote && quoteShared()) {
73
+ // Unified account: the quote is ONE balance for spot and perp, and the venue books it
74
+ // under the asset row's `margin_balance` with `balance` "0.000000" (GET /account,
75
+ // mainnet account 723334, 2026-10-05: assets[USDC] balance "0.000000", margin_balance
76
+ // "15.952247503314"; account available_balance "15.952247"). apidocs reference/account-1
77
+ // lists the asset fields `balance`, `locked_balance`, `margin_mode` ("enabled" |
78
+ // "disabled"), `margin_balance` and the account field `available_balance` without
79
+ // defining them further, so:
80
+ // total = balance + margin_balance (the quote the account holds, exact sum);
81
+ // available = account `available_balance` — the only "free" figure the venue reports
82
+ // for the unified margin, i.e. what is not committed as perp margin and
83
+ // therefore usable by a spot order. It is the venue's number, not
84
+ // total − held (it moves with perp margin use and unrealized PnL);
85
+ // held = locked_balance (quote locked by resting spot orders).
86
+ // Named by the bare quote symbol: it is not a separate spot balance (`_SPOT`).
87
+ const total = subDecimal(plainDecimal(asset.balance, `${quote} balance`), subDecimal("0", plainDecimal(asset.margin_balance, `${quote} margin_balance`)));
88
+ if (Number(total) > 0) {
89
+ balances.push({ token: quote, total, available: plainDecimal(acct.available_balance, "available_balance"), held: asset.locked_balance, shared: true });
90
+ }
91
+ continue;
92
+ }
93
+ if (bal > 0) {
94
+ balances.push({
95
+ // The quote row carries the bare quote symbol ("USDC" / "USDG") on classic accounts too:
96
+ // `shared: false` is what says it is a separate spot balance, not a `_SPOT` suffix.
97
+ token: asset.symbol,
98
+ total: asset.balance,
99
+ available: String(bal - locked),
100
+ held: asset.locked_balance,
101
+ // Classic quote: a separate spot balance. Base assets are never perp margin here.
102
+ shared: false,
103
+ });
104
+ }
105
+ }
106
+ return balances;
107
+ }
31
108
  export class LighterSpotAdapter {
32
109
  /** Venue id of the wrapped LighterAdapter ("lighter" | "lighter-rh"). */
33
110
  name;
@@ -159,26 +236,22 @@ export class LighterSpotAdapter {
159
236
  };
160
237
  });
161
238
  }
162
- async getSpotOrderbook(symbol) {
239
+ async getSpotOrderbook(symbol, depth) {
163
240
  await this.init();
164
241
  const resolved = this.resolveSymbol(symbol);
165
242
  const marketId = this._spotMarketMap.get(resolved);
166
243
  if (marketId === undefined) {
167
- throw new Error(`Unknown Lighter spot market: ${symbol}`);
168
- }
169
- try {
170
- const res = await this._restGet("/orderBookOrders", {
171
- market_id: String(marketId),
172
- limit: "50",
244
+ throw new PerpError("SYMBOL_NOT_FOUND", `Unknown Lighter spot market: ${symbol}`, {
245
+ exchange: this.name, remediation: `Check the symbol: perp -e ${this.name} market spot-list`,
173
246
  });
174
- return {
175
- bids: (res.bids ?? []).map((l) => [l.price, l.remaining_base_amount ?? l.size ?? "0"]),
176
- asks: (res.asks ?? []).map((l) => [l.price, l.remaining_base_amount ?? l.size ?? "0"]),
177
- };
178
- }
179
- catch {
180
- return { bids: [], asks: [] };
181
247
  }
248
+ // A failed read throws its typed error (429 / WAF / transport) — never an empty book, which
249
+ // callers (arb-auto, liquidity) would read as "no liquidity". Orders → price levels as on perps.
250
+ const res = await this._restGet("/orderBookOrders", {
251
+ market_id: String(marketId),
252
+ limit: String(LIGHTER_BOOK_ORDERS_LIMIT),
253
+ });
254
+ return lighterBook(this.name, res, resolved, depth);
182
255
  }
183
256
  /**
184
257
  * Spot token balances. Reads the account through the shared 15s `acct:` cache
@@ -218,80 +291,11 @@ export class LighterSpotAdapter {
218
291
  remediation: `Check the ${this.name} account index / address (perp -e ${this.name} account info)`,
219
292
  });
220
293
  }
221
- const balances = [];
222
- const quote = this._quote;
223
- if (acct.assets !== undefined && !Array.isArray(acct.assets)) {
224
- throw new PerpError("EXCHANGE_ERROR", `${this.name} spot balances: account.assets is not an array`, { exchange: this.name, raw: acct.assets });
225
- }
226
- const assets = (acct.assets ?? []);
227
- // Docs (docs.lighter.xyz/trading/unified-trading-accounts): "Unified Trading Accounts (UTA)
228
- // enables unified margin on Spot and Perpetuals USDC balances." vs Simple: "perpetual and spot
229
- // balances are maintained separately." Mode = this same response's account_trading_mode
230
- // ("Classic=0 and Unified=1", apidocs reference/account-1); an unknown mode fails the quote row.
231
- const quoteShared = () => {
232
- const mode = acct.account_trading_mode;
233
- if (mode !== 0 && mode !== 1) {
234
- throw new PerpError("EXCHANGE_ERROR", `${this.name} spot balances: account_trading_mode is ${JSON.stringify(mode ?? null)} (expected 0 classic | 1 unified)`, {
235
- exchange: this.name,
236
- remediation: `Retry; check the account with: perp -e ${this.name} account info`,
237
- });
238
- }
239
- return mode === 1;
240
- };
241
- const plainDecimal = (v, field) => {
242
- if (typeof v !== "string" || !/^-?\d+(\.\d+)?$/.test(v)) {
243
- throw new PerpError("EXCHANGE_ERROR", `${this.name} spot balances: ${field} is ${JSON.stringify(v ?? null)} (expected a decimal string)`, {
244
- exchange: this.name,
245
- remediation: `Retry; check the account with: perp -e ${this.name} account info`,
246
- });
247
- }
248
- return v;
249
- };
250
- for (const asset of assets) {
251
- const bal = Number(asset.balance);
252
- const locked = Number(asset.locked_balance);
253
- if (!Number.isFinite(bal) || !Number.isFinite(locked)) {
254
- throw new PerpError("EXCHANGE_ERROR", `${this.name} spot balance for ${asset.symbol} is not a number (balance=${asset.balance}, locked=${asset.locked_balance})`, { exchange: this.name, raw: asset });
255
- }
256
- if (asset.symbol === quote && quoteShared()) {
257
- // Unified account: the quote is ONE balance for spot and perp, and the venue books it
258
- // under the asset row's `margin_balance` with `balance` "0.000000" (GET /account,
259
- // mainnet account 723334, 2026-10-05: assets[USDC] balance "0.000000", margin_balance
260
- // "15.952247503314"; account available_balance "15.952247"). apidocs reference/account-1
261
- // lists the asset fields `balance`, `locked_balance`, `margin_mode` ("enabled" |
262
- // "disabled"), `margin_balance` and the account field `available_balance` without
263
- // defining them further, so:
264
- // total = balance + margin_balance (the quote the account holds, exact sum);
265
- // available = account `available_balance` — the only "free" figure the venue reports
266
- // for the unified margin, i.e. what is not committed as perp margin and
267
- // therefore usable by a spot order. It is the venue's number, not
268
- // total − held (it moves with perp margin use and unrealized PnL);
269
- // held = locked_balance (quote locked by resting spot orders).
270
- // Named by the bare quote symbol: it is not a separate spot balance (`_SPOT`).
271
- const total = subDecimal(plainDecimal(asset.balance, `${quote} balance`), subDecimal("0", plainDecimal(asset.margin_balance, `${quote} margin_balance`)));
272
- if (Number(total) > 0) {
273
- balances.push({ token: quote, total, available: plainDecimal(acct.available_balance, "available_balance"), held: asset.locked_balance, shared: true });
274
- }
275
- continue;
276
- }
277
- if (bal > 0) {
278
- balances.push({
279
- // The quote row carries the bare quote symbol ("USDC" / "USDG") on classic accounts too:
280
- // `shared: false` is what says it is a separate spot balance, not a `_SPOT` suffix.
281
- token: asset.symbol,
282
- total: asset.balance,
283
- available: String(bal - locked),
284
- held: asset.locked_balance,
285
- // Classic quote: a separate spot balance. Base assets are never perp margin here.
286
- shared: false,
287
- });
288
- }
289
- }
290
- return balances;
294
+ return lighterSpotBalanceRows(acct, this.name, this._quote);
291
295
  }
292
296
  async spotMarketOrder(symbol, side, size, opts) {
293
297
  // Everything up to sendTx is pre-send: a failure there is a definite "not placed"
294
- // (ORDER_REJECTED); sendTx transport failures are ORDER_PENDING (design §12.3).
298
+ // (ORDER_REJECTED); sendTx transport failures are ORDER_PENDING.
295
299
  let prep;
296
300
  try {
297
301
  prep = await this._prepareMarketOrder(symbol, side, size, opts.slippage.bps);
@@ -392,30 +396,32 @@ export class LighterSpotAdapter {
392
396
  const resolved = this.resolveSymbol(symbol);
393
397
  const marketId = this._spotMarketMap.get(resolved);
394
398
  if (marketId === undefined) {
395
- throw new Error(`Unknown Lighter spot market: ${symbol}`);
399
+ throw new PerpError("SYMBOL_NOT_FOUND", `Unknown Lighter spot market: ${symbol}`, {
400
+ exchange: this.name, remediation: `Check the symbol: perp -e ${this.name} market spot-list`,
401
+ });
396
402
  }
397
403
  // Validate min order size
398
404
  const minSize = this._spotMinSize.get(resolved);
399
405
  const sizeNum = parseFloat(size);
400
406
  if (minSize && sizeNum < minSize.base) {
401
- throw new Error(`Size ${size} below min_base_amount ${minSize.base} for ${resolved}`);
407
+ throw new PerpError("SIZE_TOO_SMALL", `Size ${size} below min_base_amount ${minSize.base} for ${resolved}`, { exchange: this.name });
402
408
  }
403
- // Protection price = best opposite quote ± the resolved slippage bound (design §13.2)
409
+ // Protection price = best opposite quote ± the resolved slippage bound
404
410
  const ob = await this.getSpotOrderbook(resolved);
405
411
  let refPrice;
406
412
  if (side === "buy") {
407
413
  if (ob.asks.length === 0)
408
- throw new Error(`No asks in ${resolved} spot orderbook`);
414
+ throw new PerpError("PRICE_STALE", `No asks in ${resolved} spot orderbook — no reference price`, { exchange: this.name });
409
415
  refPrice = Number(ob.asks[0][0]);
410
416
  }
411
417
  else {
412
418
  if (ob.bids.length === 0)
413
- throw new Error(`No bids in ${resolved} spot orderbook`);
419
+ throw new PerpError("PRICE_STALE", `No bids in ${resolved} spot orderbook — no reference price`, { exchange: this.name });
414
420
  refPrice = Number(ob.bids[0][0]);
415
421
  }
416
422
  // Validate min quote amount (size × price ≥ min_quote)
417
423
  if (minSize && sizeNum * refPrice < minSize.quote) {
418
- throw new Error(`Order value $${(sizeNum * refPrice).toFixed(2)} below min_quote_amount $${minSize.quote} for ${resolved}`);
424
+ throw new PerpError("SIZE_TOO_SMALL", `Order value $${(sizeNum * refPrice).toFixed(2)} below min_quote_amount $${minSize.quote} for ${resolved}`, { exchange: this.name });
419
425
  }
420
426
  const dec = this._getDecimals(resolved);
421
427
  // Tick conversion rounds toward crossing (buy → up, sell → down), never to nearest.
@@ -453,7 +459,7 @@ export class LighterSpotAdapter {
453
459
  const sizeStep = dec.size <= 0 ? "1" : `0.${"0".repeat(dec.size - 1)}1`;
454
460
  const tick = dec.price <= 0 ? "1" : `0.${"0".repeat(dec.price - 1)}1`;
455
461
  // Size floored to the size step (never rounded up); price must already be on tick
456
- // (INVALID_TICK, never rounded — design §10.10).
462
+ // (INVALID_TICK, never rounded).
457
463
  const sentSize = floorSize(size, sizeStep);
458
464
  const sentPrice = requireOnTick(price, tick);
459
465
  // Venue minimums: refused, never bumped up to the minimum (the order would exceed the request).
@@ -505,7 +511,7 @@ export class LighterSpotAdapter {
505
511
  };
506
512
  }
507
513
  /**
508
- * TIF mapping, as perps (§13.3): GTC/GTT → GTT, IOC → IOC, ALO / POST_ONLY → post-only (2).
514
+ * TIF mapping, as perps: GTC/GTT → GTT, IOC → IOC, ALO / POST_ONLY → post-only (2).
509
515
  * FOK and anything else → CAPABILITY_UNSUPPORTED (never silently GTT).
510
516
  */
511
517
  _limitTif(tif) {
@@ -656,7 +662,7 @@ export class LighterSpotAdapter {
656
662
  async transferUsdcToPerp(amount) {
657
663
  return this._selfTransfer(String(amount), 1, 0); // route: Spot(1) → Perp(0)
658
664
  }
659
- /** SpotTransferCapable (§12.4 #4): only the venue collateral (USDC on Lighter, USDG on Lighter RH). */
665
+ /** SpotTransferCapable: only the venue collateral (USDC on Lighter, USDG on Lighter RH). */
660
666
  async transferToSpot(amount, asset) {
661
667
  return this._selfTransfer(this._transferAmount(amount, asset), 0, 1);
662
668
  }
@@ -864,8 +870,7 @@ export class LighterSpotAdapter {
864
870
  return nonce;
865
871
  }
866
872
  /**
867
- * POST /sendTx. `kind` "place" (order placement): failures are typed (design
868
- * §12.3): before the request → ORDER_REJECTED; transport error, HTTP 5xx or an
873
+ * POST /sendTx. `kind` "place" (order placement): failures are typed: before the request → ORDER_REJECTED; transport error, HTTP 5xx or an
869
874
  * unreadable body after it → ORDER_PENDING (the tx may have been accepted — never
870
875
  * resubmit); an explicit non-200 code → ORDER_REJECTED. "order" (cancels) / "action"
871
876
  * (transfers): an explicit non-200 code → ORDER_REJECTED / ACTION_REJECTED
@@ -900,6 +905,9 @@ export class LighterSpotAdapter {
900
905
  const res = await fetch(url.toString());
901
906
  if (!res.ok) {
902
907
  const text = await res.text();
908
+ // apidocs.lighter.xyz/docs/rate-limits: a breached limit answers "HTTP 429" (as LighterAdapter.restGet).
909
+ if (res.status === 429)
910
+ throw rateLimitedError(this._lt.name, res.headers.get("retry-after"), text);
903
911
  const waf = lighterWafChallenge(this._lt.name, res.status, text);
904
912
  if (waf !== null)
905
913
  throw waf;
@@ -1,10 +1,11 @@
1
- import type { ExchangeAdapter, ExchangeMarketInfo, ExchangePosition, ExchangeOrder, ExchangeBalance, ExchangeTrade, ExchangeFundingPayment, ExchangeKline } from "./interface.js";
1
+ import type { ExchangeAdapter, ExchangeMarketInfo, ExchangePosition, ExchangeOrder, ExchangeBalance, ExchangeTrade, ExchangePublicTrade, ExchangeFundingPayment, ExchangeKline, FundingHistoryRow } from "./interface.js";
2
2
  import type { ResolvedSlippage } from "./slippage.js";
3
3
  import type { EvmSigner } from "../signer/index.js";
4
4
  import type { AgentMeta } from "../settings.js";
5
5
  import { PerpError } from "../errors.js";
6
6
  import type { Network, VenueNetworkConfig } from "./venue.js";
7
7
  import { LIGHTER_REFERENCE_PRICE_SOURCE } from "./venues/lighter-family.js";
8
+ import { type LighterFundingStat } from "./lighter-public.js";
8
9
  import type { LighterVenueId } from "./venues/lighter-family.js";
9
10
  import { LighterWasmSigner } from "./lighter-signer.js";
10
11
  /** Lighter trigger orderType enum (matches WASM signer). */
@@ -34,7 +35,12 @@ export declare const LIGHTER_TIF: {
34
35
  readonly POST_ONLY: 2;
35
36
  };
36
37
  /**
37
- * CLI format rule for a Lighter client order id (§13.10 #9): the venue's
38
+ * One GET /api/v1/fundings row → a funding history row (fraction per 1 h, signed).
39
+ * `rate` is percent per hour, unsigned; `direction` "long" = longs pay (positive), "short" = shorts pay.
40
+ */
41
+ export declare function lighterFundingRow(venue: string, f: unknown): FundingHistoryRow;
42
+ /**
43
+ * CLI format rule for a Lighter client order id: the venue's
38
44
  * `clientOrderIndex` is numeric, so the id must be a plain decimal integer string
39
45
  * (digits only, no sign / leading zero / exponent) in 1 ≤ n ≤ 2^48 − 1.
40
46
  * Anything else → INVALID_PARAMS before anything is sent.
@@ -249,6 +255,19 @@ export declare function lighterRowCreatedMs(row: Record<string, unknown>): numbe
249
255
  * leverage = floor(10000 / bps), which returns the integer leverage that was set. margin_mode:
250
256
  * 0 cross, 1 isolated (the values updateLeverage signs). Anything else throws — never a guess.
251
257
  */
258
+ /**
259
+ * Balance of one Lighter-family account object (GET /account) — the one implementation behind
260
+ * LighterAdapter.getBalance() and the keyless `account balance --address`. Equity includes the
261
+ * spot collateral asset (USDC on Lighter, USDG on Lighter RH; separate from perp collateral).
262
+ */
263
+ export declare function lighterBalanceOf(acct: Record<string, unknown>, venue: string, collateralSymbol: string): ExchangeBalance;
264
+ /**
265
+ * Open positions of one Lighter account (`GET /account` `accounts[].positions[]`): the venue lists
266
+ * every market the account ever traded or configured, so rows with `position` 0 are dropped. The
267
+ * ONE mapper of the keyed `getPositions` and the public-address read; `priceDecimalsOf` formats
268
+ * the computed mark (position_value / size) to the market's price decimals when known.
269
+ */
270
+ export declare function lighterPositionRows(positions: unknown, venue: string, priceDecimalsOf: (symbol: string) => number | undefined): ExchangePosition[];
252
271
  export declare function lighterPositionSettings(p: Record<string, unknown>, venue: string): {
253
272
  leverage: number;
254
273
  marginMode: "cross" | "isolated";
@@ -270,13 +289,21 @@ export declare function lighterSelectAccount(accounts: Array<Record<string, unkn
270
289
  * window is unknown (SYMBOL_NOT_FOUND) until the entry expires.
271
290
  */
272
291
  export declare const LIGHTER_MARKET_LIST_TTL_MS: number;
292
+ /** GET /api/v1/candles resolutions, live-verified 2026-10-19 on lighter + lighter-rh mainnet and lighter testnet (3m / 2h / 6h / 8h / 1w / 1M / 2m: code 20001 "invalid param"). */
293
+ export declare const LIGHTER_CANDLE_INTERVALS: Readonly<Record<string, number>>;
294
+ /** "Returns at most 500 candles per call" (apidocs.lighter.xyz/reference/candles). */
295
+ export declare const LIGHTER_CANDLES_PER_CALL = 500;
296
+ /** Max `limit` of GET /api/v1/recentTrades. */
297
+ export declare const LIGHTER_RECENT_TRADES_MAX = 100;
298
+ /** Requests one `market kline` may send (the venue allows 60 / minute on standard accounts). */
299
+ export declare const LIGHTER_KLINE_MAX_PAGES = 10;
273
300
  export interface LighterAdapterOpts {
274
301
  apiKey?: string;
275
302
  accountIndex?: number;
276
303
  apiKeyIndex?: number;
277
304
  }
278
305
  export declare class LighterAdapter implements ExchangeAdapter {
279
- /** GTC→GTT resting-order lifetime (28 days) for the execution record (§13.10 #14). */
306
+ /** GTC→GTT resting-order lifetime (28 days) for the execution record. */
280
307
  static readonly gttExpiryMs: number;
281
308
  /** Venue id ("lighter" | "lighter-rh"). */
282
309
  readonly name: LighterVenueId;
@@ -300,6 +327,8 @@ export declare class LighterAdapter implements ExchangeAdapter {
300
327
  private _address;
301
328
  private _marketMap;
302
329
  private _marketDecimals;
330
+ /** symbol → live (isLighterMarketLive). Inactive markets stay in _marketMap for reads and closes. */
331
+ private _marketLive;
303
332
  private _evmKey;
304
333
  private _apiKey;
305
334
  private _accountIndexInit;
@@ -434,6 +463,12 @@ export declare class LighterAdapter implements ExchangeAdapter {
434
463
  * the 60 / minute budget.
435
464
  */
436
465
  private _refreshMarketMap;
466
+ /**
467
+ * An order that can open or add exposure (not reduce-only) on a market that is not live
468
+ * (`status` inactive / `is_frozen`) is refused before signing. Reduce-only orders and closes are
469
+ * still sent, so a position on a market that went inactive can be closed.
470
+ */
471
+ private assertOpenable;
437
472
  getMarketIndex(symbol: string): number;
438
473
  /**
439
474
  * Lot step of a perp market from the loaded market list (size decimals of /orderBooks) —
@@ -468,7 +503,7 @@ export declare class LighterAdapter implements ExchangeAdapter {
468
503
  */
469
504
  private pollTx;
470
505
  /**
471
- * Definite IOC outcome (§13.10 #4) from the executed tx: poll /tx by hash. A taker order the
506
+ * Definite IOC outcome from the executed tx: poll /tx by hash. A taker order the
472
507
  * venue reports "filled" (event_info `to.st` 3, `is` = sent) filled the whole order. Any other
473
508
  * status (the remainder was cancelled — the venue zeroes `rs`, so is − rs is NOT a fill) →
474
509
  * the venue's own `filled_base_amount` from accountOrders by client order index. Zero fill →
@@ -501,7 +536,7 @@ export declare class LighterAdapter implements ExchangeAdapter {
501
536
  */
502
537
  orderRowOutcome(clientOrderIndex: number, orderId: string | null, what: string, settled?: (out: LighterOrderOutcome, row: Record<string, unknown>) => boolean, match?: LighterRowMatch | null): Promise<LighterOrderOutcome | null>;
503
538
  /**
504
- * Final outcome of a placed resting / post-only order (§13.10 #4 analogue for non-IOC): poll
539
+ * Final outcome of a placed resting / post-only order (analogue for non-IOC): poll
505
540
  * /tx (rejected → ORDER_REJECTED). Our order (`to`, matched by client order index) reported
506
541
  * "filled" in event_info → filled = is (the whole order). Any other status — open, or a
507
542
  * canceled-* whose remainder the venue zeroed (`rs` 0, so is − rs is NOT a fill) — or an
@@ -524,7 +559,13 @@ export declare class LighterAdapter implements ExchangeAdapter {
524
559
  * a size that floors to 0 → SIZE_TOO_SMALL.
525
560
  */
526
561
  private toTicks;
527
- getMarkets(): Promise<ExchangeMarketInfo[]>;
562
+ /** Settled / predicted hourly funding per market_id (WS market_stats snapshot, shared with the public directory). */
563
+ protected fundingStats(): Promise<Map<number, LighterFundingStat>>;
564
+ /** Why the last listing's fundingRate is null (the settled-rate snapshot failed), else null. */
565
+ fundingWarning(): string | null;
566
+ getMarkets(opts?: {
567
+ funding?: boolean;
568
+ }): Promise<ExchangeMarketInfo[]>;
528
569
  private get accountCacheKey();
529
570
  /** The in-flight cached account read: parallel callers (getBalance + getPositions) share one request. */
530
571
  private _accountInFlight;
@@ -534,9 +575,11 @@ export declare class LighterAdapter implements ExchangeAdapter {
534
575
  * Book from GET /orderBookOrders?market_id=<id> on this venue's host (Lighter RH: its own host
535
576
  * and market ids, e.g. RH testnet TSLA = 112). Rule #2: an unknown symbol (SYMBOL_NOT_FOUND) or
536
577
  * a failed read throws — it is never reported as an empty book. An empty `bids`/`asks` is the
537
- * venue's real answer (no liquidity).
578
+ * venue's real answer (no liquidity). The endpoint lists individual ORDERS (up to 250 per side,
579
+ * the documented max); they are aggregated into price levels (lighterBookLevels), as the WS
580
+ * `order_book` channel publishes them.
538
581
  */
539
- getOrderbook(symbol: string): Promise<{
582
+ getOrderbook(symbol: string, depth?: number): Promise<{
540
583
  bids: [string, string][];
541
584
  asks: [string, string][];
542
585
  }>;
@@ -558,7 +601,7 @@ export declare class LighterAdapter implements ExchangeAdapter {
558
601
  /** Order / trade side from Lighter's `is_ask`; a missing / non-boolean value throws (never defaults to "buy"). */
559
602
  private sideOfIsAsk;
560
603
  /**
561
- * Slippage-bounded IOC (§13.2): protection price = orderbook mid ± opts.slippage.bps,
604
+ * Slippage-bounded IOC: protection price = orderbook mid ± opts.slippage.bps,
562
605
  * tick-aligned toward crossing. The returned raw sendTx result carries `protection`
563
606
  * and, when the venue reported the fill, `iocOutcome` (see iocOutcomeOf).
564
607
  * `opts.clientOrderIndex` (optional) = caller's numeric client order id (lighterClientOrderIndex rule).
@@ -569,9 +612,9 @@ export declare class LighterAdapter implements ExchangeAdapter {
569
612
  clientOrderIndex?: number;
570
613
  }): Promise<unknown>;
571
614
  /**
572
- * TIF mapping (§13.3): GTC/GTT → GTT (28-day expiry, gttExpiryMs), IOC → IOC,
615
+ * TIF mapping: GTC/GTT → GTT (28-day expiry, gttExpiryMs), IOC → IOC,
573
616
  * ALO / POST_ONLY → time-in-force 2 (POST_ONLY per apidocs trading.md and the official
574
- * lighter-go signer; 28-day expiry like GTT — testnet confirmation pending, design §11).
617
+ * lighter-go signer; 28-day expiry like GTT — testnet confirmation pending).
575
618
  * FOK and any other value → CAPABILITY_UNSUPPORTED (never silently GTT).
576
619
  * `opts.clientOrderIndex` as in marketOrder.
577
620
  * IOC: the same definite outcome as marketOrder (awaitIocOutcome — zero fill →
@@ -640,7 +683,7 @@ export declare class LighterAdapter implements ExchangeAdapter {
640
683
  /**
641
684
  * Trigger order. Market trigger (no limitPrice): execution price bound = trigger price ±
642
685
  * `opts.slippage` bps (the caller's resolveSlippage() output — required; the adapter never
643
- * reads settings, §13.10 #1), tick-aligned toward crossing (§13.10 #3), recorded in the
686
+ * reads settings), tick-aligned toward crossing, recorded in the
644
687
  * result as `protection`. Accepted risk: a fast move through the bound leaves the
645
688
  * triggered order unfilled.
646
689
  * TP vs SL: `opts.kind` given (TP/SL legs) → that type as given (a trigger already crossed
@@ -665,12 +708,27 @@ export declare class LighterAdapter implements ExchangeAdapter {
665
708
  private _withdrawRaw;
666
709
  editOrder(symbol: string, orderId: string, price: string, size: string): Promise<unknown>;
667
710
  setLeverage(symbol: string, leverage: number, marginMode?: "cross" | "isolated"): Promise<unknown>;
668
- getRecentTrades(symbol: string, limit?: number): Promise<ExchangeTrade[]>;
669
- getFundingHistory(symbol: string, limit?: number): Promise<{
670
- time: number;
671
- rate: string;
672
- price: string | null;
673
- }[]>;
711
+ getRecentTrades(symbol: string, limit?: number): Promise<ExchangePublicTrade[]>;
712
+ /**
713
+ * Settled funding prints: GET /api/v1/fundings (apidocs.lighter.xyz/reference/fundings;
714
+ * `count_back` rows from `start_timestamp`, max 750). Each row is one hourly settlement:
715
+ * `rate` is PERCENT per 1 h, unsigned, with `direction` "long" (longs pay → positive) or
716
+ * "short" (shorts pay → negative). Live 2026-10-19 BTC: rate "0.0012", value "0.99315" =
717
+ * mark 82,763 × 0.000012, i.e. value / mark = rate / 100. NOT the /funding-rates unit (8 h).
718
+ */
719
+ getFundingHistory(symbol: string, limit?: number): Promise<FundingHistoryRow[]>;
720
+ /**
721
+ * Candles opening in [startTime, endTime] (ms). GET /api/v1/candles answers the
722
+ * max(count_back, bars in the window) newest bars ending at `end_timestamp`, at most 500
723
+ * (live 2026-10-19, BTC 1h: a 96-bar window with count_back 1 / 96 → those 96 bars; with
724
+ * count_back 500 → 500 bars, 404 of them before start_timestamp; a future window → past bars).
725
+ * So count_back is the window's bar count (≤ 500), rows outside the window are dropped, and a
726
+ * longer window is paged backwards in 500-bar chunks by moving end_timestamp. `end_timestamp` is
727
+ * exclusive at second resolution (live: end = a bar's open excludes it, open + 1 s includes it),
728
+ * so end + 1 s is sent for an inclusive --end. Each answer's `r`
729
+ * must be the requested resolution. Intervals outside LIGHTER_CANDLE_INTERVALS and windows over
730
+ * LIGHTER_KLINE_MAX_PAGES pages are refused with INVALID_PARAMS before any request.
731
+ */
674
732
  getKlines(symbol: string, interval: string, startTime: number, endTime: number): Promise<ExchangeKline[]>;
675
733
  /**
676
734
  * Account-wide history: ONE request per 100 rows, whatever the number of markets (the former
@@ -713,8 +771,9 @@ export declare class LighterAdapter implements ExchangeAdapter {
713
771
  */
714
772
  getFundingPayments(limit?: number): Promise<ExchangeFundingPayment[]>;
715
773
  /**
716
- * Get funding rates for all markets.
717
- * API: GET /api/v1/funding-rates
774
+ * GET /api/v1/funding-rates: the venue's PREDICTED rate × 8, a fraction per 8 h — not the venue
775
+ * basis (1 h; market rows carry the settled hourly rate, fundingStats). Not used for funding
776
+ * comparisons; normalize with 8 h if read.
718
777
  */
719
778
  getFundingRates(): Promise<Map<string, {
720
779
  rate: string;
@@ -779,7 +838,7 @@ export declare class LighterAdapter implements ExchangeAdapter {
779
838
  private nextClientOrderIndex;
780
839
  private ensureSigner;
781
840
  /**
782
- * One WASM signer (one Go runtime) per `${venueId}:${network}` (design §10.5).
841
+ * One WASM signer (one Go runtime) per `${venueId}:${network}`.
783
842
  * lighter-go keys its clients by (accountIndex, apiKeyIndex) only and keeps a
784
843
  * package-global chainId for L1 messages, so two venues must never share a
785
844
  * runtime. Keyed by venue+network rather than chainId because Lighter testnet