perp-cli 0.12.17 → 0.14.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 (361) hide show
  1. package/README.md +247 -27
  2. package/dist/_stderr-filter.js +0 -1
  3. package/dist/agent-wallet/lighter-keystore.d.ts +11 -0
  4. package/dist/agent-wallet/lighter-keystore.js +92 -10
  5. package/dist/agent-wallet/passphrase.d.ts +1 -1
  6. package/dist/agent-wallet/passphrase.js +16 -3
  7. package/dist/agent-wallet/store.d.ts +37 -4
  8. package/dist/agent-wallet/store.js +132 -0
  9. package/dist/agent-wallet/venue-keystore.d.ts +14 -0
  10. package/dist/agent-wallet/venue-keystore.js +121 -0
  11. package/dist/api/public/hyperliquid.js +4 -4
  12. package/dist/api/public/lighter.js +5 -5
  13. package/dist/api/public/pacifica.d.ts +0 -1
  14. package/dist/api/public/pacifica.js +4 -13
  15. package/dist/api/public/urls.d.ts +9 -1
  16. package/dist/api/public/urls.js +35 -13
  17. package/dist/arb/file-lock.d.ts +11 -0
  18. package/dist/arb/file-lock.js +74 -0
  19. package/dist/arb/index.d.ts +2 -2
  20. package/dist/arb/index.js +2 -2
  21. package/dist/arb/pending-entry.d.ts +32 -0
  22. package/dist/arb/pending-entry.js +77 -0
  23. package/dist/arb/sizing.d.ts +6 -13
  24. package/dist/arb/sizing.js +12 -51
  25. package/dist/arb/state.d.ts +45 -12
  26. package/dist/arb/state.js +214 -42
  27. package/dist/arb/utils.d.ts +20 -6
  28. package/dist/arb/utils.js +43 -39
  29. package/dist/bot/conditions.d.ts +4 -4
  30. package/dist/bot/conditions.js +11 -6
  31. package/dist/bot/config.d.ts +17 -1
  32. package/dist/bot/config.js +48 -12
  33. package/dist/bot/engine.d.ts +61 -2
  34. package/dist/bot/engine.js +610 -144
  35. package/dist/bot/fill-size.d.ts +7 -0
  36. package/dist/bot/fill-size.js +18 -0
  37. package/dist/bot/index.d.ts +1 -1
  38. package/dist/bot/index.js +1 -1
  39. package/dist/bot/perp-order.d.ts +99 -0
  40. package/dist/bot/perp-order.js +299 -0
  41. package/dist/bot/presets.d.ts +7 -0
  42. package/dist/bot/presets.js +17 -0
  43. package/dist/bot/quarantine.d.ts +75 -0
  44. package/dist/bot/quarantine.js +190 -0
  45. package/dist/bot/quote-rules.d.ts +23 -0
  46. package/dist/bot/quote-rules.js +69 -0
  47. package/dist/bot/strategies/avellaneda-mm.d.ts +32 -2
  48. package/dist/bot/strategies/avellaneda-mm.js +72 -70
  49. package/dist/bot/strategies/basis-arb.js +2 -0
  50. package/dist/bot/strategies/dca-strategy.d.ts +2 -0
  51. package/dist/bot/strategies/dca-strategy.js +5 -0
  52. package/dist/bot/strategies/funding-arb-strategy.d.ts +43 -3
  53. package/dist/bot/strategies/funding-arb-strategy.js +571 -380
  54. package/dist/bot/strategies/funding-arb-utils.d.ts +48 -23
  55. package/dist/bot/strategies/funding-arb-utils.js +159 -195
  56. package/dist/bot/strategies/funding-arb-v2.d.ts +32 -0
  57. package/dist/bot/strategies/funding-arb-v2.js +258 -47
  58. package/dist/bot/strategies/funding-auto.js +215 -194
  59. package/dist/bot/strategies/spot-perp-arb-strategy.d.ts +14 -0
  60. package/dist/bot/strategies/spot-perp-arb-strategy.js +217 -50
  61. package/dist/bot/strategies/spot-perp-executor.d.ts +73 -19
  62. package/dist/bot/strategies/spot-perp-executor.js +319 -120
  63. package/dist/bot/strategies/spot-perp-state.d.ts +43 -0
  64. package/dist/bot/strategies/spot-perp-state.js +70 -0
  65. package/dist/bot/strategy-types.d.ts +6 -0
  66. package/dist/bot/tui/BotDashboard.d.ts +7 -2
  67. package/dist/bot/tui/BotDashboard.js +6 -3
  68. package/dist/bridge-engine.d.ts +120 -19
  69. package/dist/bridge-engine.js +710 -422
  70. package/dist/bridge-signers.d.ts +54 -0
  71. package/dist/bridge-signers.js +161 -0
  72. package/dist/cache.d.ts +4 -1
  73. package/dist/cache.js +11 -0
  74. package/dist/cli-flags.d.ts +50 -0
  75. package/dist/cli-flags.js +104 -0
  76. package/dist/cli-program.d.ts +35 -0
  77. package/dist/cli-program.js +286 -0
  78. package/dist/cli-spec.js +1 -1
  79. package/dist/client-id-tracker.js +11 -2
  80. package/dist/commands/account.d.ts +7 -1
  81. package/dist/commands/account.js +70 -92
  82. package/dist/commands/agent-import.d.ts +114 -0
  83. package/dist/commands/agent-import.js +794 -0
  84. package/dist/commands/agent.d.ts +232 -2
  85. package/dist/commands/agent.js +1858 -955
  86. package/dist/commands/alerts.d.ts +1 -0
  87. package/dist/commands/alerts.js +31 -28
  88. package/dist/commands/arb/index.d.ts +60 -1
  89. package/dist/commands/arb/index.js +381 -384
  90. package/dist/commands/arb-auto.d.ts +132 -4
  91. package/dist/commands/arb-auto.js +1474 -967
  92. package/dist/commands/arb.d.ts +3 -1
  93. package/dist/commands/arb.js +62 -30
  94. package/dist/commands/bot.js +127 -47
  95. package/dist/commands/bridge.d.ts +2 -1
  96. package/dist/commands/bridge.js +339 -192
  97. package/dist/commands/builder.d.ts +55 -0
  98. package/dist/commands/builder.js +387 -0
  99. package/dist/commands/funds-onchain.d.ts +32 -0
  100. package/dist/commands/funds-onchain.js +286 -0
  101. package/dist/commands/funds.d.ts +25 -0
  102. package/dist/commands/funds.js +939 -245
  103. package/dist/commands/history.js +72 -45
  104. package/dist/commands/init.d.ts +107 -15
  105. package/dist/commands/init.js +1116 -249
  106. package/dist/commands/jobs.d.ts +2 -1
  107. package/dist/commands/jobs.js +77 -15
  108. package/dist/commands/manage.js +136 -91
  109. package/dist/commands/market.d.ts +4 -1
  110. package/dist/commands/market.js +35 -32
  111. package/dist/commands/outcome.d.ts +10 -0
  112. package/dist/commands/outcome.js +396 -0
  113. package/dist/commands/plan.js +52 -12
  114. package/dist/commands/portfolio.d.ts +1 -0
  115. package/dist/commands/portfolio.js +60 -72
  116. package/dist/commands/rebalance.d.ts +2 -1
  117. package/dist/commands/rebalance.js +33 -43
  118. package/dist/commands/risk.js +46 -19
  119. package/dist/commands/settings.d.ts +1 -0
  120. package/dist/commands/settings.js +246 -51
  121. package/dist/commands/trade.d.ts +50 -0
  122. package/dist/commands/trade.js +1943 -695
  123. package/dist/commands/wallet.d.ts +30 -1
  124. package/dist/commands/wallet.js +316 -337
  125. package/dist/config.d.ts +60 -9
  126. package/dist/config.js +252 -82
  127. package/dist/constants.d.ts +29 -4
  128. package/dist/constants.js +62 -20
  129. package/dist/dashboard/server.d.ts +2 -0
  130. package/dist/dashboard/server.js +9 -6
  131. package/dist/dashboard/ui.js +6 -4
  132. package/dist/dashboard/ws-feeds.js +20 -8
  133. package/dist/dex-asset-map.js +5 -3
  134. package/dist/errors.d.ts +122 -0
  135. package/dist/errors.js +194 -0
  136. package/dist/event-stream.js +75 -19
  137. package/dist/evm-master-tx.d.ts +59 -0
  138. package/dist/evm-master-tx.js +154 -0
  139. package/dist/exchanges/adapter-network.d.ts +10 -0
  140. package/dist/exchanges/adapter-network.js +10 -0
  141. package/dist/exchanges/arcus/adapter.d.ts +196 -0
  142. package/dist/exchanges/arcus/adapter.js +1092 -0
  143. package/dist/exchanges/arcus/agent.d.ts +55 -0
  144. package/dist/exchanges/arcus/agent.js +188 -0
  145. package/dist/exchanges/arcus/client.d.ts +63 -0
  146. package/dist/exchanges/arcus/client.js +285 -0
  147. package/dist/exchanges/arcus/public.d.ts +65 -0
  148. package/dist/exchanges/arcus/public.js +138 -0
  149. package/dist/exchanges/arcus/signing.d.ts +176 -0
  150. package/dist/exchanges/arcus/signing.js +288 -0
  151. package/dist/exchanges/arcus/spot-chain.d.ts +60 -0
  152. package/dist/exchanges/arcus/spot-chain.js +241 -0
  153. package/dist/exchanges/arcus/spot-router.d.ts +177 -0
  154. package/dist/exchanges/arcus/spot-router.js +183 -0
  155. package/dist/exchanges/arcus/spot.d.ts +109 -0
  156. package/dist/exchanges/arcus/spot.js +645 -0
  157. package/dist/exchanges/aster-funds.d.ts +127 -0
  158. package/dist/exchanges/aster-funds.js +252 -0
  159. package/dist/exchanges/aster-nonce.d.ts +2 -0
  160. package/dist/exchanges/aster-nonce.js +107 -0
  161. package/dist/exchanges/aster-spot.d.ts +117 -0
  162. package/dist/exchanges/aster-spot.js +686 -0
  163. package/dist/exchanges/aster-typed-data.d.ts +133 -7
  164. package/dist/exchanges/aster-typed-data.js +121 -7
  165. package/dist/exchanges/aster.d.ts +219 -6
  166. package/dist/exchanges/aster.js +1023 -153
  167. package/dist/exchanges/builder-fee.d.ts +254 -0
  168. package/dist/exchanges/builder-fee.js +421 -0
  169. package/dist/exchanges/canonical-symbols.d.ts +32 -0
  170. package/dist/exchanges/canonical-symbols.js +96 -0
  171. package/dist/exchanges/capabilities.d.ts +7 -1
  172. package/dist/exchanges/capabilities.js +7 -0
  173. package/dist/exchanges/hl-signing.d.ts +165 -0
  174. package/dist/exchanges/hl-signing.js +158 -0
  175. package/dist/exchanges/hyperliquid-outcome.d.ts +211 -0
  176. package/dist/exchanges/hyperliquid-outcome.js +646 -0
  177. package/dist/exchanges/hyperliquid-spot.d.ts +44 -5
  178. package/dist/exchanges/hyperliquid-spot.js +308 -117
  179. package/dist/exchanges/hyperliquid.d.ts +462 -57
  180. package/dist/exchanges/hyperliquid.js +1575 -449
  181. package/dist/exchanges/index.d.ts +6 -0
  182. package/dist/exchanges/index.js +4 -0
  183. package/dist/exchanges/interface.d.ts +63 -10
  184. package/dist/exchanges/interface.js +18 -3
  185. package/dist/exchanges/ioc-outcome.d.ts +44 -0
  186. package/dist/exchanges/ioc-outcome.js +57 -0
  187. package/dist/exchanges/legacy-trading-v2.d.ts +39 -0
  188. package/dist/exchanges/legacy-trading-v2.js +940 -0
  189. package/dist/exchanges/lighter-public.d.ts +43 -0
  190. package/dist/exchanges/lighter-public.js +276 -0
  191. package/dist/exchanges/lighter-rh-deposit.d.ts +62 -0
  192. package/dist/exchanges/lighter-rh-deposit.js +185 -0
  193. package/dist/exchanges/lighter-signer.d.ts +123 -0
  194. package/dist/exchanges/lighter-signer.js +215 -0
  195. package/dist/exchanges/lighter-spot.d.ts +91 -13
  196. package/dist/exchanges/lighter-spot.js +595 -233
  197. package/dist/exchanges/lighter.d.ts +611 -39
  198. package/dist/exchanges/lighter.js +1890 -649
  199. package/dist/exchanges/ondo/adapter.d.ts +166 -0
  200. package/dist/exchanges/ondo/adapter.js +835 -0
  201. package/dist/exchanges/ondo/agent.d.ts +31 -0
  202. package/dist/exchanges/ondo/agent.js +101 -0
  203. package/dist/exchanges/ondo/client.d.ts +60 -0
  204. package/dist/exchanges/ondo/client.js +297 -0
  205. package/dist/exchanges/ondo/funds.d.ts +122 -0
  206. package/dist/exchanges/ondo/funds.js +290 -0
  207. package/dist/exchanges/ondo/public.d.ts +95 -0
  208. package/dist/exchanges/ondo/public.js +214 -0
  209. package/dist/exchanges/ondo/spot.d.ts +127 -0
  210. package/dist/exchanges/ondo/spot.js +392 -0
  211. package/dist/exchanges/outcome-interface.d.ts +140 -0
  212. package/dist/exchanges/outcome-interface.js +16 -0
  213. package/dist/exchanges/pacifica-spot.d.ts +83 -0
  214. package/dist/exchanges/pacifica-spot.js +324 -0
  215. package/dist/exchanges/pacifica-typed-data.d.ts +30 -13
  216. package/dist/exchanges/pacifica-typed-data.js +57 -9
  217. package/dist/exchanges/pacifica.d.ts +288 -4
  218. package/dist/exchanges/pacifica.js +1013 -76
  219. package/dist/exchanges/precision.d.ts +47 -0
  220. package/dist/exchanges/precision.js +209 -0
  221. package/dist/exchanges/qfex/adapter.d.ts +341 -0
  222. package/dist/exchanges/qfex/adapter.js +1383 -0
  223. package/dist/exchanges/qfex/agent.d.ts +58 -0
  224. package/dist/exchanges/qfex/agent.js +188 -0
  225. package/dist/exchanges/qfex/client.d.ts +54 -0
  226. package/dist/exchanges/qfex/client.js +138 -0
  227. package/dist/exchanges/qfex/errors.d.ts +70 -0
  228. package/dist/exchanges/qfex/errors.js +236 -0
  229. package/dist/exchanges/qfex/public.d.ts +122 -0
  230. package/dist/exchanges/qfex/public.js +268 -0
  231. package/dist/exchanges/qfex/signing.d.ts +160 -0
  232. package/dist/exchanges/qfex/signing.js +283 -0
  233. package/dist/exchanges/qfex/ws-transport.d.ts +294 -0
  234. package/dist/exchanges/qfex/ws-transport.js +798 -0
  235. package/dist/exchanges/rate-limiter.d.ts +12 -0
  236. package/dist/exchanges/rate-limiter.js +64 -0
  237. package/dist/exchanges/registry.d.ts +14 -2
  238. package/dist/exchanges/registry.js +20 -32
  239. package/dist/exchanges/slippage.d.ts +37 -0
  240. package/dist/exchanges/slippage.js +70 -0
  241. package/dist/exchanges/spot-factory.d.ts +166 -0
  242. package/dist/exchanges/spot-factory.js +431 -0
  243. package/dist/exchanges/spot-interface.d.ts +98 -4
  244. package/dist/exchanges/spot-interface.js +27 -1
  245. package/dist/exchanges/spot-result.d.ts +79 -0
  246. package/dist/exchanges/spot-result.js +273 -0
  247. package/dist/exchanges/trading-v2.d.ts +117 -0
  248. package/dist/exchanges/trading-v2.js +301 -0
  249. package/dist/exchanges/venue-types.d.ts +231 -0
  250. package/dist/exchanges/venue-types.js +87 -0
  251. package/dist/exchanges/venue.d.ts +211 -0
  252. package/dist/exchanges/venue.js +132 -0
  253. package/dist/exchanges/venues/arcus.d.ts +8 -0
  254. package/dist/exchanges/venues/arcus.js +109 -0
  255. package/dist/exchanges/venues/aster.d.ts +49 -0
  256. package/dist/exchanges/venues/aster.js +176 -0
  257. package/dist/exchanges/venues/create-helpers.d.ts +18 -0
  258. package/dist/exchanges/venues/create-helpers.js +199 -0
  259. package/dist/exchanges/venues/hyperliquid.d.ts +23 -0
  260. package/dist/exchanges/venues/hyperliquid.js +126 -0
  261. package/dist/exchanges/venues/index.d.ts +16 -0
  262. package/dist/exchanges/venues/index.js +26 -0
  263. package/dist/exchanges/venues/lighter-family.d.ts +92 -0
  264. package/dist/exchanges/venues/lighter-family.js +166 -0
  265. package/dist/exchanges/venues/lighter-rh.d.ts +7 -0
  266. package/dist/exchanges/venues/lighter-rh.js +58 -0
  267. package/dist/exchanges/venues/lighter.d.ts +6 -0
  268. package/dist/exchanges/venues/lighter.js +55 -0
  269. package/dist/exchanges/venues/ondo.d.ts +34 -0
  270. package/dist/exchanges/venues/ondo.js +140 -0
  271. package/dist/exchanges/venues/pacifica.d.ts +8 -0
  272. package/dist/exchanges/venues/pacifica.js +95 -0
  273. package/dist/exchanges/venues/qfex.d.ts +28 -0
  274. package/dist/exchanges/venues/qfex.js +132 -0
  275. package/dist/execution-log.js +10 -2
  276. package/dist/funding/legacy-public.d.ts +31 -0
  277. package/dist/funding/legacy-public.js +369 -0
  278. package/dist/funding/normalize.d.ts +28 -16
  279. package/dist/funding/normalize.js +61 -29
  280. package/dist/funding/rates.d.ts +46 -11
  281. package/dist/funding/rates.js +228 -277
  282. package/dist/guardrail/perp-guardrail.js +0 -0
  283. package/dist/index.js +156 -684
  284. package/dist/jobs.d.ts +84 -6
  285. package/dist/jobs.js +239 -41
  286. package/dist/landing.d.ts +7 -2
  287. package/dist/landing.js +19 -3
  288. package/dist/mcp-server.d.ts +14 -4
  289. package/dist/mcp-server.js +820 -402
  290. package/dist/mcp-trade-guard.d.ts +16 -0
  291. package/dist/mcp-trade-guard.js +59 -0
  292. package/dist/pacifica/client.d.ts +41 -10
  293. package/dist/pacifica/client.js +167 -63
  294. package/dist/pacifica/constants.d.ts +0 -1
  295. package/dist/pacifica/constants.js +0 -5
  296. package/dist/pacifica/deposit.d.ts +30 -3
  297. package/dist/pacifica/deposit.js +119 -2
  298. package/dist/pacifica/faucet.d.ts +29 -0
  299. package/dist/pacifica/faucet.js +100 -0
  300. package/dist/pacifica/sign-tx.d.ts +15 -0
  301. package/dist/pacifica/sign-tx.js +41 -0
  302. package/dist/pacifica/types/account.d.ts +28 -4
  303. package/dist/pacifica/types/lake.d.ts +20 -5
  304. package/dist/pacifica/types/lake.js +4 -0
  305. package/dist/pacifica/types/market.d.ts +5 -0
  306. package/dist/pacifica/types/order.d.ts +4 -1
  307. package/dist/pacifica/types/position.d.ts +9 -1
  308. package/dist/plan-executor.d.ts +10 -5
  309. package/dist/plan-executor.js +165 -54
  310. package/dist/position-history.js +13 -0
  311. package/dist/rebalance.d.ts +26 -2
  312. package/dist/rebalance.js +86 -7
  313. package/dist/relay-swap.d.ts +232 -0
  314. package/dist/relay-swap.js +630 -0
  315. package/dist/risk.js +5 -1
  316. package/dist/secret-env.d.ts +15 -0
  317. package/dist/secret-env.js +36 -0
  318. package/dist/settings.d.ts +169 -6
  319. package/dist/settings.js +219 -38
  320. package/dist/signer/ows-evm.d.ts +13 -0
  321. package/dist/signer/ows-evm.js +22 -0
  322. package/dist/smart-order.d.ts +9 -0
  323. package/dist/smart-order.js +53 -8
  324. package/dist/strategies/dca.d.ts +6 -2
  325. package/dist/strategies/dca.js +66 -26
  326. package/dist/strategies/funding-arb.d.ts +11 -1
  327. package/dist/strategies/funding-arb.js +202 -89
  328. package/dist/strategies/grid.d.ts +31 -0
  329. package/dist/strategies/grid.js +89 -11
  330. package/dist/strategies/pending-stop.d.ts +8 -0
  331. package/dist/strategies/pending-stop.js +12 -0
  332. package/dist/strategies/split-order.d.ts +45 -17
  333. package/dist/strategies/split-order.js +157 -91
  334. package/dist/strategies/trailing-stop.d.ts +2 -1
  335. package/dist/strategies/trailing-stop.js +52 -6
  336. package/dist/strategies/twap.d.ts +6 -1
  337. package/dist/strategies/twap.js +39 -11
  338. package/dist/trade-validator.d.ts +22 -0
  339. package/dist/trade-validator.js +119 -15
  340. package/dist/utils/numeric.d.ts +46 -0
  341. package/dist/utils/numeric.js +79 -0
  342. package/dist/utils.d.ts +19 -0
  343. package/dist/utils.js +96 -19
  344. package/dist/withdraw-gate.d.ts +49 -0
  345. package/dist/withdraw-gate.js +131 -0
  346. package/package.json +15 -6
  347. package/skills/perp-cli/SKILL.md +142 -55
  348. package/skills/perp-cli/references/agent-operations.md +110 -56
  349. package/skills/perp-cli/references/commands.md +266 -71
  350. package/skills/perp-cli/references/strategies.md +34 -31
  351. package/skills/perp-cli/scripts/arb-monitor.sh +10 -5
  352. package/skills/perp-cli/scripts/funding-analysis.sh +14 -9
  353. package/skills/perp-cli/scripts/preflight.sh +21 -14
  354. package/skills/perp-cli/scripts/spot-perp-scan.sh +12 -7
  355. package/skills/perp-cli/scripts/validate-arb.sh +31 -15
  356. package/vendor/lighter-signer/SHA256SUMS +2 -0
  357. package/vendor/lighter-signer/VERSION +8 -0
  358. package/vendor/lighter-signer/lighter-signer.wasm +0 -0
  359. package/vendor/lighter-signer/wasm_exec.js +575 -0
  360. package/dist/bot/strategies/funding-arb-v2-strategy.d.ts +0 -42
  361. package/dist/bot/strategies/funding-arb-v2-strategy.js +0 -864
@@ -1,7 +1,12 @@
1
1
  import type { ExchangeAdapter, ExchangeMarketInfo, ExchangePosition, ExchangeOrder, ExchangeBalance, ExchangeTrade, ExchangeFundingPayment, ExchangeKline } from "./interface.js";
2
+ import type { ResolvedSlippage } from "./slippage.js";
2
3
  import type { EvmSigner } from "../signer/index.js";
3
4
  import type { AgentMeta } from "../settings.js";
4
- import type { WasmSignerClient as WasmSignerClientType } from "lighter-ts-sdk";
5
+ import { PerpError } from "../errors.js";
6
+ import type { Network, VenueNetworkConfig } from "./venue.js";
7
+ import { LIGHTER_REFERENCE_PRICE_SOURCE } from "./venues/lighter-family.js";
8
+ import type { LighterVenueId } from "./venues/lighter-family.js";
9
+ import { LighterWasmSigner } from "./lighter-signer.js";
5
10
  /** Lighter trigger orderType enum (matches WASM signer). */
6
11
  export declare const LIGHTER_ORDER_TYPE: {
7
12
  readonly STOP_LOSS: 2;
@@ -22,17 +27,279 @@ export type LighterTriggerOrderType = typeof LIGHTER_ORDER_TYPE.STOP_LOSS | type
22
27
  * Tied trigger==mark is classified as STOP_LOSS — the protective default.
23
28
  */
24
29
  export declare function classifyTriggerOrderType(side: "buy" | "sell", triggerPrice: number, markPrice: number, isMarket: boolean): LighterTriggerOrderType;
30
+ /** Lighter order time-in-force enum (lighter-go / SDK `TimeInForce`): 0 IOC, 1 GTT, 2 post-only. */
31
+ export declare const LIGHTER_TIF: {
32
+ readonly IOC: 0;
33
+ readonly GTT: 1;
34
+ readonly POST_ONLY: 2;
35
+ };
36
+ /**
37
+ * CLI format rule for a Lighter client order id (§13.10 #9): the venue's
38
+ * `clientOrderIndex` is numeric, so the id must be a plain decimal integer string
39
+ * (digits only, no sign / leading zero / exponent) in 1 ≤ n ≤ 2^48 − 1.
40
+ * Anything else → INVALID_PARAMS before anything is sent.
41
+ */
42
+ export declare function lighterClientOrderIndex(id: string): number;
43
+ /**
44
+ * Generated Lighter client order index (uint48, 1 ≤ n ≤ 2^48 − 1). Layout: the low 38 bits
45
+ * of the millisecond timestamp (wraps every ~8.7 years) shifted left 10 bits, plus 10 random
46
+ * bits. Two orders collide only when sent in the same millisecond AND drawing the same
47
+ * random value (1/1024) — the former second-granularity timestamp + per-process counter
48
+ * collided across processes within the same second. Caller-given ids are validated
49
+ * separately (lighterClientOrderIndex).
50
+ */
51
+ export declare function lighterGeneratedClientOrderIndex(): number;
52
+ /**
53
+ * /tx status codes (apidocs "Data Structures, Constants and Errors" → Transaction Status
54
+ * Mapping): 0 Failed · 1 Pending · 2 Executed · 3 Pending - Final State.
55
+ */
56
+ export declare const LIGHTER_TX_STATUS: {
57
+ readonly FAILED: 0;
58
+ readonly PENDING: 1;
59
+ readonly EXECUTED: 2;
60
+ readonly PENDING_FINAL: 3;
61
+ };
62
+ /**
63
+ * Parsed `event_info` of a /tx row (JSON string on the wire), or null when absent / unparseable.
64
+ * Integers of 16+ digits (order ids such as Lighter RH's 32088147345014782 > 2^53) are kept as
65
+ * exact decimal strings — JSON.parse would round them to another order's id.
66
+ */
67
+ export declare function lighterEventInfo(eventInfo: unknown): Record<string, unknown> | null;
68
+ /** Exact venue order id of an event_info order object's `i` (decimal string or safe integer), else null. */
69
+ export declare function lighterEventOrderId(i: unknown): string | null;
70
+ /** One /tx poll, classified. */
71
+ export type LighterTxState = {
72
+ kind: "executed";
73
+ status: number;
74
+ eventInfo: Record<string, unknown> | null;
75
+ } | {
76
+ kind: "rejected";
77
+ status: number;
78
+ reason: string;
79
+ } | {
80
+ kind: "pending";
81
+ status: number | null;
82
+ };
83
+ /**
84
+ * Classify a /tx response: 0 → rejected; 2 / 3 with executed_at > 0 → executed, unless the
85
+ * event_info carries a non-empty `ae` (app error) → rejected; 1, 2 / 3 not yet executed, a
86
+ * missing status or an unknown code → pending (keep polling; never guessed final).
87
+ */
88
+ export declare function lighterTxState(tx: unknown): LighterTxState;
89
+ /** Order status names by code (event_info `st`; accountOrders `status` strings). */
90
+ export declare const LIGHTER_ORDER_STATUS_NAMES: readonly ["in-progress", "pending", "open", "filled", "canceled", "canceled-post-only", "canceled-reduce-only", "canceled-position-not-allowed", "canceled-margin-not-allowed", "canceled-too-much-slippage", "canceled-not-enough-liquidity", "canceled-self-trade", "canceled-expired", "canceled-oco", "canceled-child", "canceled-liquidation", "canceled-invalid-balance"];
91
+ /** Final outcome of a placed (non-IOC) order, attached to the raw result as `orderOutcome`. */
92
+ export interface LighterOrderOutcome {
93
+ /** open = resting (or an untriggered trigger order); cancelled with a fill → partiallyFilled. */
94
+ status: "open" | "partiallyFilled" | "filled" | "cancelled";
95
+ final: true;
96
+ /** Venue status name, e.g. "open", "canceled-post-only". */
97
+ venueStatus: string;
98
+ /** Filled base size (decimal string). */
99
+ filledSize: string;
100
+ /** Venue order id (string; exact), when reported. */
101
+ orderId: string | null;
102
+ source: "event_info" | "accountOrders";
103
+ }
104
+ /**
105
+ * Normalized outcome from a venue order status (code or name) and its filled size, or null
106
+ * when not final (0 in-progress) / unknown. 1 pending = an untriggered trigger order (it
107
+ * exists on the venue) → open.
108
+ */
109
+ export declare function lighterOrderOutcomeOf(st: number | string, filledSize: string, orderId: string | null, source: LighterOrderOutcome["source"]): LighterOrderOutcome | null;
110
+ /**
111
+ * Filled base units of an event_info order object (`to` taker / `no` modified order), proven
112
+ * ONLY when the venue status is 3 "filled" — the whole order (`is`) filled. Any other status →
113
+ * null: event_info carries no filled field, and the venue zeroes `rs` when it cancels the
114
+ * remainder (live testnet 2026-10-02: a crossing post-only came back canceled-post-only with
115
+ * is 89 / rs 0 while accountOrders reported filled_base_amount "0.000"), so is − rs is never a
116
+ * fill. Callers read accountOrders `filled_base_amount` instead (lighterRowOutcomeOf).
117
+ */
118
+ export declare function lighterEventFilledBase(o: Record<string, unknown>): number | null;
119
+ /**
120
+ * Outcome of an accountOrders row from the venue's own fields: `status` and `filled_base_amount`
121
+ * (a plain decimal string). A missing / malformed filled amount → null (never "0", never
122
+ * size − remaining).
123
+ */
124
+ export declare function lighterRowOutcomeOf(row: Record<string, unknown>, orderId: string | null): LighterOrderOutcome | null;
125
+ /**
126
+ * Outcome of a modify (ModifyOrder, tx type 17) from its executed tx event_info: the new order
127
+ * `no` ({ i order id, u client index, is size, rs remaining, p price ticks, st status }). Final
128
+ * only when `no` is this order (i = orderId, or u = clientOrderIndex when i is not exact),
129
+ * carries the price ticks / base amount sent AND its status is "filled" (filled = is,
130
+ * lighterEventFilledBase). Any other status → null: the filled amount is read from accountOrders.
131
+ */
132
+ export declare function lighterModifyOutcomeOf(eventInfo: Record<string, unknown> | null, orderId: string, clientOrderIndex: number | null, sent: {
133
+ baseAmount: number;
134
+ priceTicks: number;
135
+ }, sizeDecimals: number): LighterOrderOutcome | null;
136
+ /**
137
+ * The integer to sign a cancel / modify with, from the order's active-orders row: its client
138
+ * order index when set (non-zero, ≤ 2^48 − 1); else (client index 0, e.g. a front-end order)
139
+ * its order id — only when that decimal string is exactly representable as a JS number (the
140
+ * signer takes a number). Otherwise throws INVALID_PARAMS: never a different order, never cancel-all.
141
+ */
142
+ export declare function lighterOrderSignIndex(row: Record<string, unknown>, venue: string): number;
143
+ /** Venue order id of an orders row as an exact string (order_id is a string on the wire; order_index a number). */
144
+ export declare function lighterOrderIdOf(row: Record<string, unknown>): string;
145
+ /**
146
+ * Filled base amount (integer base units) from an executed tx's `event_info` taker order `to`,
147
+ * proven only when the venue status is "filled" and its initial size equals what was sent
148
+ * (lighterEventFilledBase) → the whole sent amount. Otherwise null (a cancelled remainder
149
+ * zeroes `rs` — is − rs is never a fill): the caller reads the venue's filled amount
150
+ * (accountOrders `filled_base_amount`) or measures it. Shared by the perp and spot IOC paths.
151
+ */
152
+ export declare function lighterTakerFilledBase(eventInfo: unknown, sentBaseAmount: number): number | null;
153
+ /**
154
+ * A required open-order row field as a string (Rule #2): missing / empty / non-finite numeric →
155
+ * EXCHANGE_ERROR, never listed as price / size "0" or status "open".
156
+ */
157
+ export declare function lighterRowField(o: Record<string, unknown>, key: string, venue: string): string;
158
+ /** What identifies OUR accountOrders row besides the client order index: the market sent to and the send time. */
159
+ export interface LighterRowMatch {
160
+ marketIndex: number;
161
+ sentAtMs: number;
162
+ }
163
+ /** Definite IOC outcome attached to a Lighter raw order result (`raw.iocOutcome`). */
164
+ export interface LighterIocOutcome {
165
+ /** Filled base size (decimal string, venue size decimals). */
166
+ filledSize: string;
167
+ /** The IOC remainder is cancelled by the venue — this fill is final. */
168
+ final: true;
169
+ /** Filled / sent base amount in integer base units. */
170
+ filledBase: number;
171
+ sentBase: number;
172
+ txHash: string;
173
+ /**
174
+ * /tx status of the executed tx: 2 (Executed) or 3 (Pending - Final State), with executed_at > 0;
175
+ * null when /tx did not settle within the poll window and the accountOrders terminal row did.
176
+ */
177
+ txStatus: number | null;
178
+ /** Where the fill was read: event_info (status "filled" → the whole order) or the accountOrders row's filled_base_amount. */
179
+ source: "event_info" | "accountOrders";
180
+ }
181
+ /** Slippage protection actually sent with a Lighter order (`raw.protection`). */
182
+ export interface LighterProtection {
183
+ /** Declared reference source (LIGHTER_REFERENCE_PRICE_SOURCE) or "triggerPrice" for trigger orders. */
184
+ referenceSource: typeof LIGHTER_REFERENCE_PRICE_SOURCE | "triggerPrice";
185
+ referencePrice: string;
186
+ /** Tick-aligned toward crossing (buy → up, sell → down). */
187
+ protectionPrice: string;
188
+ slippageBps: number;
189
+ slippageSource: ResolvedSlippage["source"];
190
+ /** |protectionPrice / referencePrice − 1| in bps after tick alignment. */
191
+ appliedBps: number;
192
+ }
193
+ /** `iocOutcomeOf` parser shared by LighterAdapter and LighterSpotAdapter. */
194
+ export declare function lighterIocOutcomeOf(raw: unknown): {
195
+ filledSize: string;
196
+ final: true;
197
+ } | null;
198
+ /**
199
+ * An explicit non-200 `code` in a /sendTx response: the venue validated the tx and refused it
200
+ * before execution (e.g. "invalid ToAccount", "invalid nonce") — a definite rejection, nothing
201
+ * executed. Orders (place / cancel / modify / trigger) → ORDER_REJECTED; account actions
202
+ * (transfer / withdraw / leverage) → ACTION_REJECTED; a balance / margin refusal keeps its
203
+ * specific (also definite) code so shortfall handling still applies. Transport failures /
204
+ * unreadable bodies are NOT routed here (their outcome is unknown).
205
+ */
206
+ export declare function lighterSendTxRejection(venue: string, json: {
207
+ code?: unknown;
208
+ message?: string;
209
+ }, kind: "order" | "action"): PerpError;
210
+ /**
211
+ * A /sendTx `code` that says the venue VALIDATED the tx and refused it (nothing executed): the
212
+ * documented validation / rate-limit ranges 20000–28999 (apidocs "Data Structures, Constants and
213
+ * Errors": 21xxx account / collateral / tx / order-book / order / asset errors, 23xxx rate limits).
214
+ * NOT definite: a missing / non-numeric code, 29xxx (29500 internal server error, 29501 process
215
+ * timeout — the tx may still execute) and anything outside the documented ranges.
216
+ */
217
+ export declare function lighterSendTxCodeIsDefinite(code: unknown): boolean;
218
+ /**
219
+ * Verdict of a parsed /sendTx body: code 200 → returns; a documented validation code → definite
220
+ * rejection (lighterSendTxRejection); any other / missing code → ORDER_PENDING (outcome unknown).
221
+ */
222
+ export declare function lighterSendTxVerdict(venue: string, json: {
223
+ code?: unknown;
224
+ message?: string;
225
+ }, kind: "order" | "action", what: string): void;
226
+ /** Per-request timeout of POST /sendTx (fetch + body read). */
227
+ export declare const LIGHTER_SEND_TIMEOUT_MS = 15000;
228
+ /**
229
+ * POST /sendTx (shared by the perp and spot adapters). Once the signed tx is on the wire only
230
+ * the venue's own answer settles it: no connection → not sent; a connection reset / timeout /
231
+ * HTTP 5xx / unreadable body → ORDER_PENDING; then lighterSendTxVerdict on the body.
232
+ */
233
+ export declare function lighterPostSendTx(baseUrl: string, signed: {
234
+ txType: number;
235
+ txInfo: string;
236
+ }, venue: string, kind: "order" | "action", what: string): Promise<{
237
+ code: number;
238
+ message?: string;
239
+ tx_hash?: string;
240
+ }>;
241
+ /** created_at / timestamp of an orders row in ms (the venue reports seconds; ms / µs are normalized), or null. */
242
+ export declare function lighterRowCreatedMs(row: Record<string, unknown>): number | null;
243
+ /**
244
+ * Configured leverage and margin mode of an account `positions[]` entry (GET /api/v1/account).
245
+ * Docs (apidocs.lighter.xyz/reference/account-1, PositionDetails): `initial_margin_fraction`
246
+ * "type": "string", example "20.00"; `margin_mode` "type": "integer", example 1. The fraction
247
+ * is a PERCENT on this read (live 2026-10-05: "5.00" on a 20x market, "6.66" after a 15x
248
+ * update) — the same value updateLeverage signs in basis points (`int(10_000 / leverage)`), so
249
+ * leverage = floor(10000 / bps), which returns the integer leverage that was set. margin_mode:
250
+ * 0 cross, 1 isolated (the values updateLeverage signs). Anything else throws — never a guess.
251
+ */
252
+ export declare function lighterPositionSettings(p: Record<string, unknown>, venue: string): {
253
+ leverage: number;
254
+ marginMode: "cross" | "isolated";
255
+ };
256
+ /** Clock-skew allowance when requiring an order row to be created after the send (client vs venue clock). */
257
+ export declare const LIGHTER_ROW_SKEW_MS = 120000;
258
+ /**
259
+ * The account to use from a `/account?by=l1_address` listing. A known account index → that
260
+ * account or null (never another one). Unknown index: the only account; with several, the single
261
+ * main account (account_type 0); otherwise INVALID_PARAMS — never "the first one".
262
+ */
263
+ export declare function lighterSelectAccount(accounts: Array<Record<string, unknown>> | undefined, accountIndex: number, venue: string): Record<string, unknown> | null;
264
+ /**
265
+ * On-disk lifetime of the perp market list (symbol → market id, size / price decimals) read from
266
+ * `GET /api/v1/orderBooks`, shared by every CLI process of the same venue + network (cache.ts).
267
+ * Public static metadata only — account state, orders, positions, balances and nonces are never
268
+ * cached here. It keeps the list off the per-invocation request budget (apidocs.lighter.xyz
269
+ * rate-limits: "Standard Accounts: 60 requests per rolling minute"). A market listed inside this
270
+ * window is unknown (SYMBOL_NOT_FOUND) until the entry expires.
271
+ */
272
+ export declare const LIGHTER_MARKET_LIST_TTL_MS: number;
273
+ export interface LighterAdapterOpts {
274
+ apiKey?: string;
275
+ accountIndex?: number;
276
+ apiKeyIndex?: number;
277
+ }
25
278
  export declare class LighterAdapter implements ExchangeAdapter {
26
- readonly name = "lighter";
27
- readonly chain = "ethereum";
28
- readonly aliases: readonly ["lt"];
279
+ /** GTC→GTT resting-order lifetime (28 days) for the execution record (§13.10 #14). */
280
+ static readonly gttExpiryMs: number;
281
+ /** Venue id ("lighter" | "lighter-rh"). */
282
+ readonly name: LighterVenueId;
283
+ readonly venueId: LighterVenueId;
284
+ readonly family: "lighter";
285
+ /** Settlement chain of the venue network ("ethereum" for Lighter, "robinhood" for Lighter RH). */
286
+ readonly chain: string;
287
+ readonly aliases: readonly string[];
288
+ readonly networkName: Network;
289
+ private readonly _network;
29
290
  private _signer;
30
291
  private _accountIndex;
292
+ /**
293
+ * Account trading mode (`account_trading_mode`: Classic=0, Unified=1 — lighter-python
294
+ * models/account.py; docs.lighter.xyz "Unified Trading Accounts"). Unified: spot and perp
295
+ * share the USDC margin, so there is no spot↔perp transfer. Read by
296
+ * resolveAccountTradingMode() (LighterSpotAdapter.init); null = not read yet.
297
+ */
298
+ private _tradingMode;
31
299
  private _apiKeyIndex;
32
300
  private _address;
33
301
  private _marketMap;
34
302
  private _marketDecimals;
35
- private _clientOrderCounter;
36
303
  private _evmKey;
37
304
  private _apiKey;
38
305
  private _accountIndexInit;
@@ -54,26 +321,62 @@ export declare class LighterAdapter implements ExchangeAdapter {
54
321
  /** --no-agent bypass flag. */
55
322
  private _useNoAgent;
56
323
  /**
324
+ * Legacy constructor: this signature DEFINES the Lighter (main) venue — it is
325
+ * not a default for other venues. Lighter RH (and any explicit venue) is
326
+ * built with `LighterAdapter.forVenue()`, which passes `venue`.
327
+ *
57
328
  * @param evmKey EVM private key (0x-prefixed, 32 bytes) — for deposits & key registration
58
- * @param testnet Use testnet (chain ID 300) instead of mainnet (chain ID 304)
59
- * @param opts Optional: apiKey (40-byte Lighter signing key), accountIndex
60
- */
61
- constructor(evmKey: string, testnet?: boolean, opts?: {
62
- apiKey?: string;
63
- accountIndex?: number;
64
- apiKeyIndex?: number;
65
- });
66
- get signer(): {
329
+ * @param testnet Use the venue testnet instead of mainnet
330
+ * @param opts Optional: apiKey (40-byte Lighter signing key), accountIndex, apiKeyIndex
331
+ * @param venue @internal — set only by `forVenue()`; absent means the Lighter venue by definition
332
+ */
333
+ constructor(evmKey: string, testnet?: boolean, opts?: LighterAdapterOpts, venue?: LighterVenueId);
334
+ /** Construct an adapter for an explicit Lighter-family venue. */
335
+ static forVenue(venue: LighterVenueId, evmKey: string, testnet: boolean, opts?: LighterAdapterOpts): LighterAdapter;
336
+ /** Network config of this adapter's venue + network (SSOT: venues/lighter-family.ts). */
337
+ get network(): VenueNetworkConfig;
338
+ /** Collateral symbol of this venue on its network ("USDC" on Lighter, "USDG" on Lighter RH mainnet, "USDC" on RH testnet). */
339
+ get collateralSymbol(): string;
340
+ /** Lighter asset index of the collateral (3 on both venues). */
341
+ get collateralAssetIndex(): number;
342
+ /**
343
+ * Cache key prefix for account reads shared with LighterSpotAdapter.
344
+ * "lt" is the historical Lighter prefix (kept so existing cache keys are unchanged);
345
+ * other venues use their venue id so accounts never collide across venues.
346
+ */
347
+ get accountCachePrefix(): string;
348
+ /** Lighter RH reserves API key indexes {0,1,2,3,157} for its own interfaces. */
349
+ private static _assertKeyIndexAllowed;
350
+ get signer(): Omit<LighterWasmSigner, "createAuthToken"> & {
67
351
  createAuthToken(deadline: number): Promise<{
68
352
  authToken: string;
69
353
  }>;
70
- } & WasmSignerClientType;
354
+ };
71
355
  get accountIndex(): number;
72
356
  get address(): string;
73
357
  /** @internal — evmKey is intentionally not exposed publicly for security */
74
358
  get isReadOnly(): boolean;
359
+ /**
360
+ * Sign an unsigned L1 transaction with the master wallet (on-chain deposit txs); the
361
+ * digest is derived from the tx inside the signer. Only an OWS master signer can sign
362
+ * L1 txs; anything else → NO_SIGNER_AVAILABLE.
363
+ */
364
+ signL1Transaction(tx: import("ethers").Transaction): Promise<string>;
75
365
  /** Inject an external EVM signer. Call before init() to skip LocalEvmSigner creation. */
76
366
  setSigner(signer: EvmSigner): void;
367
+ /**
368
+ * Set the account owner's L1 address without attaching a signer — for an agent whose master
369
+ * wallet is not on this machine (API key imported from the website). Account reads are keyed
370
+ * by this address; nothing L1 can be signed (signL1Transaction / setupApiKey still refuse).
371
+ */
372
+ setAddress(address: string): void;
373
+ /**
374
+ * Prove the loaded agent API key is the one registered at its slot: sign an auth token with it
375
+ * and make one authenticated read (`GET /api/v1/accountActiveOrders`). Lighter validates the
376
+ * token against the public key registered at (account_index, api_key_index), so a key that does
377
+ * not match the slot is refused. Read-only — nothing is sent. Throws on any refusal.
378
+ */
379
+ assertAgentKeyAccepted(): Promise<void>;
77
380
  /**
78
381
  * Tier 1: inject a Lighter agent's slot+L2 key (Phase 2d).
79
382
  *
@@ -103,44 +406,256 @@ export declare class LighterAdapter implements ExchangeAdapter {
103
406
  * Tier 3 (pk): active when constructor was supplied an evmKey. Same role
104
407
  * as Tier 2 — signs L1 ChangePubKey for auto-setup.
105
408
  *
106
- * Lighter is unique among the 4 DEXs in that the actual order-signing is
409
+ * Lighter is unique among the venues in that the actual order-signing is
107
410
  * always done by the L2 secp256k1 key (`_apiKey`), regardless of tier. The
108
411
  * tiers differ in WHICH L2 key is loaded: Tier 1 uses the agent's slot/key
109
412
  * from AgentMeta; Tier 2/3 use whatever the env/auto-setup produced.
110
413
  */
111
414
  private _resolveSigner;
415
+ private agentExpired;
416
+ /**
417
+ * true = Unified Trading Account (spot shares perp margin), false = Classic. Throws when the
418
+ * mode was not read or the read failed — never assumes either mode (SSOT Rule #2).
419
+ */
420
+ get isUnifiedAccount(): boolean;
421
+ /**
422
+ * Read `account_trading_mode` from the account (shared `acct:` cache). A failed or invalid
423
+ * read is kept and re-thrown by isUnifiedAccount, so callers that depend on the mode fail
424
+ * while public spot reads (markets, books) keep working.
425
+ */
426
+ resolveAccountTradingMode(): Promise<void>;
112
427
  init(): Promise<void>;
113
- /** Populate marketMap + decimals from /orderBooks API (safe to call multiple times) */
428
+ /**
429
+ * Populate the perp market map + decimals: ONE `GET /api/v1/orderBooks` (it carries
430
+ * supported_size_decimals / supported_price_decimals for every market), served from the on-disk
431
+ * market-list cache while fresh (LIGHTER_MARKET_LIST_TTL_MS). A failed read (429, transport,
432
+ * no / empty list) throws the real error — never an empty map, which every later symbol lookup
433
+ * would report as SYMBOL_NOT_FOUND. No second endpoint and no retry: each costs a request of
434
+ * the 60 / minute budget.
435
+ */
114
436
  private _refreshMarketMap;
115
437
  getMarketIndex(symbol: string): number;
438
+ /**
439
+ * Lot step of a perp market from the loaded market list (size decimals of /orderBooks) —
440
+ * precision.lotStepOf uses it instead of a full getMarkets() read (/orderBookDetails +
441
+ * /funding-rates, two requests an order placement does not need).
442
+ */
443
+ lotStepOf(symbol: string): string;
116
444
  /** Ensure market map is populated; lazy-refresh if empty */
117
445
  private ensureMarketMap;
118
- private getMarkPrice;
446
+ /**
447
+ * Reference price for slippage-bounded orders — the ONE declared source
448
+ * (LIGHTER_REFERENCE_PRICE_SOURCE): mid of best bid / best ask from
449
+ * `/orderBookOrders`. A missing side or unreadable book → PRICE_STALE (no substitute).
450
+ */
451
+ private getReferencePrice;
452
+ /**
453
+ * Protection price = reference ± slippage bps, aligned to the price tick toward
454
+ * crossing (buy → up, sell → down; precision.alignProtectionPrice), as signer ticks.
455
+ */
456
+ private protectionFor;
457
+ /** Validated caller client order index, or a generated one. */
458
+ private clientOrderIndexFor;
459
+ /**
460
+ * /tx poll attempts (500 ms apart). Testnet sequencing is slower, so its window is 3× longer.
461
+ * Public: LighterSpotAdapter polls with the same window.
462
+ */
463
+ txPollAttempts(base: number): number;
464
+ /**
465
+ * Poll /tx by hash until the tx is executed or rejected (lighterTxState), or the poll
466
+ * window ends → `{ kind: "pending" }`. A tx not indexed yet (HTTP 400 "transaction not
467
+ * found") or a transient read failure polls again.
468
+ */
469
+ private pollTx;
470
+ /**
471
+ * Definite IOC outcome (§13.10 #4) from the executed tx: poll /tx by hash. A taker order the
472
+ * venue reports "filled" (event_info `to.st` 3, `is` = sent) filled the whole order. Any other
473
+ * status (the remainder was cancelled — the venue zeroes `rs`, so is − rs is NOT a fill) →
474
+ * the venue's own `filled_base_amount` from accountOrders by client order index. Zero fill →
475
+ * ORDER_REJECTED; positive fill → the raw result carrying `iocOutcome` (final). Executed =
476
+ * status 2 / 3 with executed_at > 0 (lighterTxState); 1 Pending keeps polling. Status 0 or a
477
+ * non-empty event_info `ae` → ORDER_REJECTED. /tx not settled within the poll window → the
478
+ * accountOrders terminal row still settles it. No terminal row either → raw result without
479
+ * `iocOutcome` (outcome unknown; iocOutcomeOf() returns null).
480
+ */
481
+ private awaitIocOutcome;
482
+ /**
483
+ * Poll /tx until the tx is executed (status 2 / 3 with executed_at > 0) — used for cancels
484
+ * and trigger orders (TP/SL legs), which carry no fill to read. Status 0 or an event_info
485
+ * `ae` → ORDER_REJECTED (definite); not executed within the poll window → ORDER_PENDING.
486
+ */
487
+ awaitTxExecuted(sendResult: unknown, what: string, kind?: "order" | "action"): Promise<void>;
488
+ /**
489
+ * Orders of this account by client order index (`GET /api/v1/accountOrders`, auth token in
490
+ * the Authorization header; up to 20 indexes; last 10K active / 1K inactive within 24 h).
491
+ * Throws on a failed read or a response without an `orders` array (never "no orders").
492
+ */
493
+ getOrdersByClientIndex(clientOrderIndexes: number[]): Promise<Array<Record<string, unknown>>>;
494
+ /**
495
+ * Our order's accountOrders row (by client order index; and order id when given) → outcome
496
+ * from the venue's own `status` / `filled_base_amount` (lighterRowOutcomeOf — never
497
+ * size − remaining). `settled` decides whether the row settles the question (e.g. a modify's
498
+ * open row must carry the new price / size). Up to 4 reads 500 ms apart (indexing lag); a
499
+ * failed read is warned. Unsettled → null. Public: LighterSpotAdapter resolves spot orders
500
+ * with the same read (accountOrders lists spot and perp orders alike).
501
+ */
502
+ orderRowOutcome(clientOrderIndex: number, orderId: string | null, what: string, settled?: (out: LighterOrderOutcome, row: Record<string, unknown>) => boolean, match?: LighterRowMatch | null): Promise<LighterOrderOutcome | null>;
503
+ /**
504
+ * Final outcome of a placed resting / post-only order (§13.10 #4 analogue for non-IOC): poll
505
+ * /tx (rejected → ORDER_REJECTED). Our order (`to`, matched by client order index) reported
506
+ * "filled" in event_info → filled = is (the whole order). Any other status — open, or a
507
+ * canceled-* whose remainder the venue zeroed (`rs` 0, so is − rs is NOT a fill) — or an
508
+ * unsettled event → `accountOrders?client_order_indexes=<coi>` with the venue's
509
+ * `filled_base_amount`. Still unknown → null.
510
+ */
511
+ private resolveOrderOutcome;
512
+ /**
513
+ * Final IOC fill reported by marketOrder (`raw.iocOutcome`), or null
514
+ * when the outcome is unknown (no usable /tx report). Zero fills never reach here —
515
+ * they throw ORDER_REJECTED.
516
+ */
517
+ iocOutcomeOf(raw: unknown): {
518
+ filledSize: string;
519
+ final: true;
520
+ } | null;
521
+ /**
522
+ * Integer base amount / price ticks. `size` (decimal string, "0" = none) is FLOORED to the
523
+ * size step with exact decimal arithmetic (floorSize) — never rounded up past the request;
524
+ * a size that floors to 0 → SIZE_TOO_SMALL.
525
+ */
119
526
  private toTicks;
120
527
  getMarkets(): Promise<ExchangeMarketInfo[]>;
528
+ private get accountCacheKey();
529
+ /** The in-flight cached account read: parallel callers (getBalance + getPositions) share one request. */
530
+ private _accountInFlight;
531
+ /** `fresh`: always read live (write-through) — open-order listings must not see a pre-cancel / pre-place snapshot. */
121
532
  private fetchAccount;
533
+ /**
534
+ * Book from GET /orderBookOrders?market_id=<id> on this venue's host (Lighter RH: its own host
535
+ * and market ids, e.g. RH testnet TSLA = 112). Rule #2: an unknown symbol (SYMBOL_NOT_FOUND) or
536
+ * 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).
538
+ */
122
539
  getOrderbook(symbol: string): Promise<{
123
540
  bids: [string, string][];
124
541
  asks: [string, string][];
125
542
  }>;
126
543
  getBalance(): Promise<ExchangeBalance>;
127
544
  getPositions(): Promise<ExchangePosition[]>;
545
+ /**
546
+ * Per-market leverage / margin mode the venue exposes: every `positions[]` entry of the
547
+ * account (the venue keeps an entry for a market once it was traded or configured, open
548
+ * position or not).
549
+ */
550
+ getMarketSettings(): Promise<Array<{
551
+ symbol: string;
552
+ leverage: number;
553
+ marginMode: "cross" | "isolated";
554
+ }>>;
128
555
  private getAuthToken;
129
556
  private restGetAuth;
130
557
  getOpenOrders(): Promise<ExchangeOrder[]>;
131
- marketOrder(symbol: string, side: "buy" | "sell", size: string, opts?: {
132
- reduceOnly?: boolean;
558
+ /** Order / trade side from Lighter's `is_ask`; a missing / non-boolean value throws (never defaults to "buy"). */
559
+ private sideOfIsAsk;
560
+ /**
561
+ * Slippage-bounded IOC (§13.2): protection price = orderbook mid ± opts.slippage.bps,
562
+ * tick-aligned toward crossing. The returned raw sendTx result carries `protection`
563
+ * and, when the venue reported the fill, `iocOutcome` (see iocOutcomeOf).
564
+ * `opts.clientOrderIndex` (optional) = caller's numeric client order id (lighterClientOrderIndex rule).
565
+ */
566
+ marketOrder(symbol: string, side: "buy" | "sell", size: string, opts: {
567
+ reduceOnly: boolean;
568
+ slippage: ResolvedSlippage;
569
+ clientOrderIndex?: number;
133
570
  }): Promise<unknown>;
571
+ /**
572
+ * TIF mapping (§13.3): GTC/GTT → GTT (28-day expiry, gttExpiryMs), IOC → IOC,
573
+ * 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).
575
+ * FOK and any other value → CAPABILITY_UNSUPPORTED (never silently GTT).
576
+ * `opts.clientOrderIndex` as in marketOrder.
577
+ * IOC: the same definite outcome as marketOrder (awaitIocOutcome — zero fill →
578
+ * ORDER_REJECTED, positive fill → `iocOutcome`, no report → unknown).
579
+ * GTT / post-only: the placement outcome is resolved (resolveOrderOutcome) and attached as
580
+ * `orderOutcome` (open / filled / cancelled, final); unresolved → no `orderOutcome` (pending).
581
+ */
134
582
  limitOrder(symbol: string, side: "buy" | "sell", price: string, size: string, opts?: {
135
583
  reduceOnly?: boolean;
136
584
  tif?: string;
585
+ clientOrderIndex?: number;
137
586
  }): Promise<unknown>;
587
+ /** Final placement outcome attached by limitOrder (`raw.orderOutcome`), or null when unresolved. */
588
+ orderOutcomeOf(raw: unknown): LighterOrderOutcome | null;
589
+ /**
590
+ * The open order `orderId` (exact venue id string) of `symbol`, from a live authenticated
591
+ * `/accountActiveOrders` read. Not listed open → ORDER_NOT_FOUND (nothing is sent).
592
+ */
593
+ private activeOrderRow;
594
+ /**
595
+ * A failure before a cancel / modify / leverage tx was sent: orderNotSent (definite — a 429 or
596
+ * transport failure on the nonce / active-orders read is never an unknown write outcome). The
597
+ * lookup's own verdict ORDER_NOT_FOUND keeps its code (nothing was sent either).
598
+ */
599
+ private notSent;
600
+ /**
601
+ * Cancel one open order. The order is looked up among the market's open orders and the
602
+ * cancel is signed with its client order index (or its order id when that is 0 and exactly
603
+ * representable — lighterOrderSignIndex); otherwise refused. Never falls back to cancel-all.
604
+ */
138
605
  cancelOrder(symbol: string, orderId: string): Promise<unknown>;
606
+ /**
607
+ * Cancel the PERP open orders (of `symbol`, or of every perp market) one by one, each cancel
608
+ * polled to executed (awaitTxExecuted: rejected → ORDER_REJECTED, not executed in the poll
609
+ * window → ORDER_PENDING). Never the account-wide CancelAllOrders tx (market 255): that also
610
+ * cancels the account's SPOT orders, which a perp cancel-all / bot / plan must not touch.
611
+ */
139
612
  cancelAllOrders(symbol?: string): Promise<unknown>;
140
613
  modifyOrder(symbol: string, orderId: string, price: string, size: string): Promise<unknown>;
614
+ /**
615
+ * Final outcome of a modify: poll /tx (rejected → ORDER_REJECTED, the order is unchanged);
616
+ * once executed, the new order `no` from event_info — final there only when it is "filled"
617
+ * with the sent price / size (lighterModifyOutcomeOf). Otherwise `accountOrders?client_order_indexes=<coi>`: a terminal
618
+ * row (filled / canceled-*) is final as is; an open row only with the new price and size.
619
+ * Still unknown → null (pending).
620
+ */
621
+ private resolveModifyOutcome;
622
+ /**
623
+ * After a cancel tx EXECUTED (awaitTxExecuted): confirm the order is gone. With a client
624
+ * order index (attached by cancelOrder as `cancelTarget`), its accountOrders row: canceled-*
625
+ * → "cancelled", filled → "filled", still open → "open". Without one, the market's open
626
+ * orders: absent → "cancelled" (gone), listed → "open". Unreadable / not indexed after a
627
+ * few reads → null (unknown).
628
+ */
629
+ cancelOutcome(sendResult: unknown, symbol: string, orderId: string): Promise<"cancelled" | "filled" | "open" | null>;
630
+ /**
631
+ * One order's venue row, for a per-order status query. Client order index →
632
+ * `accountOrders?client_order_indexes=<coi>` (active and inactive within 24 h). Order id →
633
+ * the market's `/accountActiveOrders`, then its `/accountInactiveOrders` (latest 100).
634
+ * A failed read throws; not listed → ORDER_NOT_FOUND (never "cancelled").
635
+ */
636
+ orderStatusRow(symbol: string, ref: {
637
+ kind: "orderId" | "clientOrderId";
638
+ value: string;
639
+ }): Promise<Record<string, unknown>>;
640
+ /**
641
+ * Trigger order. Market trigger (no limitPrice): execution price bound = trigger price ±
642
+ * `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
644
+ * result as `protection`. Accepted risk: a fast move through the bound leaves the
645
+ * triggered order unfilled.
646
+ * TP vs SL: `opts.kind` given (TP/SL legs) → that type as given (a trigger already crossed
647
+ * is left for the venue to reject); omitted (plain `trade stop`) → classified from the
648
+ * trigger vs the declared reference price (orderbook mid).
649
+ * `size` must be a positive size (never "0" = "whole position", which Lighter does not have).
650
+ * `opts.clientOrderIndex` as in marketOrder; the result carries the `clientOrderIndex` sent
651
+ * and, once resolved (resolveOrderOutcome), the final `orderOutcome` (untriggered → open).
652
+ */
141
653
  stopOrder(symbol: string, side: "buy" | "sell", size: string, triggerPrice: string, opts?: {
142
654
  limitPrice?: string;
143
655
  reduceOnly?: boolean;
656
+ slippage?: ResolvedSlippage;
657
+ clientOrderIndex?: number;
658
+ kind?: "tp" | "sl";
144
659
  }): Promise<unknown>;
145
660
  updateLeverage(symbol: string, leverage: number, marginMode?: "cross" | "isolated"): Promise<unknown>;
146
661
  withdraw(amount: string, destination: string, opts?: {
@@ -157,8 +672,45 @@ export declare class LighterAdapter implements ExchangeAdapter {
157
672
  price: string | null;
158
673
  }[]>;
159
674
  getKlines(symbol: string, interval: string, startTime: number, endTime: number): Promise<ExchangeKline[]>;
675
+ /**
676
+ * Account-wide history: ONE request per 100 rows, whatever the number of markets (the former
677
+ * per-market fan-out sent one request per perp market — 235 on Lighter mainnet — against
678
+ * rate-limits "Standard Accounts: 60 requests per rolling minute", and dropped every failed
679
+ * market). Docs (apidocs.lighter.xyz/reference): `limit` "minimum": 1, "maximum": 100 and a
680
+ * `cursor` request parameter / `next_cursor` response field on accountInactiveOrders, trades
681
+ * and positionFunding. Reads ⌈want / 100⌉ pages at most; a failed page throws — a partial
682
+ * history is never returned (SSOT Rule #2).
683
+ */
684
+ private historyRows;
685
+ /** Symbol of a history row's market id; a market no longer in the loaded perp list is named by its id. */
686
+ private historySymbol;
687
+ /**
688
+ * Order history: `GET /accountInactiveOrders` for the whole account. Docs (reference/
689
+ * accountinactiveorders): account_index and limit are the only required parameters; market_id
690
+ * is optional ("default": "255"), market_type is "all" | "spot" | "perp".
691
+ */
160
692
  getOrderHistory(limit?: number): Promise<ExchangeOrder[]>;
693
+ /**
694
+ * Trade history: `GET /trades` for the whole account, newest first. Docs (reference/trades):
695
+ * "Get trades for lighter accounts, including sub-accounts and public pools."; sort_by and
696
+ * limit are the only required parameters, account_index / market_id are optional filters and
697
+ * the endpoint lists no authorization parameter.
698
+ * Row (Trade schema + live rows 2026-10-05): no `is_ask` / `symbol` / fee amount — the account
699
+ * is `ask_account_id` (sold) or `bid_account_id` (bought); `timestamp` is unix milliseconds
700
+ * (live 1791168722794); `taker_fee` / `maker_fee` are integers "omitted if zero" (websocket
701
+ * reference, Trade JSON). The docs do not state their unit; live rows read as a RATE in 1e-6
702
+ * of `usd_amount` (a liquidation row carries 10000 = 1%, maker 28–32 on unrelated notionals),
703
+ * so the fee is usd_amount × fee / 1e6 for the side this account took.
704
+ */
161
705
  getTradeHistory(limit?: number): Promise<ExchangeTrade[]>;
706
+ /**
707
+ * Funding payments: `GET /positionFunding` for the whole account, newest first. Docs
708
+ * (reference/positionfunding): account_index and limit are the only required parameters;
709
+ * `market_ids` ("comma-separated int64s") is an optional filter. `authorization` "is required
710
+ * when fetching an account_index linked to a main account or a sub-account". Row (live public
711
+ * pool read 2026-10-05): `timestamp` unix SECONDS (1791169200), `market_id`, `change` (signed
712
+ * quote amount: a short at a positive rate has a positive change).
713
+ */
162
714
  getFundingPayments(limit?: number): Promise<ExchangeFundingPayment[]>;
163
715
  /**
164
716
  * Get funding rates for all markets.
@@ -166,24 +718,12 @@ export declare class LighterAdapter implements ExchangeAdapter {
166
718
  */
167
719
  getFundingRates(): Promise<Map<string, {
168
720
  rate: string;
169
- markPrice: string;
721
+ markPrice: string | null;
170
722
  }>>;
171
723
  /**
172
724
  * Get candle data for a market.
173
725
  */
174
726
  getCandles(symbol: string, resolution: string, startTime: number, endTime: number, countBack?: number): Promise<unknown>;
175
- /**
176
- * Get order history (inactive orders) — raw response.
177
- */
178
- private _getOrderHistoryRaw;
179
- /**
180
- * Get trade history — raw response.
181
- */
182
- private _getTradeHistoryRaw;
183
- /**
184
- * Get position funding history — raw response.
185
- */
186
- private _getPositionFundingRaw;
187
727
  /**
188
728
  * Get PnL chart data.
189
729
  */
@@ -217,7 +757,8 @@ export declare class LighterAdapter implements ExchangeAdapter {
217
757
  */
218
758
  createIntentAddress(chainId: number): Promise<unknown>;
219
759
  /**
220
- * Use a referral code.
760
+ * Use a referral code (signed auth + POST). Called only from the explicit
761
+ * `wallet manage referral set` command — never on adapter creation.
221
762
  */
222
763
  useReferralCode(code: string): Promise<unknown>;
223
764
  /**
@@ -225,21 +766,52 @@ export declare class LighterAdapter implements ExchangeAdapter {
225
766
  */
226
767
  private getNextNonce;
227
768
  private signOrder;
769
+ /**
770
+ * Lighter RH REST budget (standard account: 60 req/min, rate-limits.md):
771
+ * every RH trading/account REST call and sendTx takes a token from the
772
+ * `${venueId}:${network}` bucket first. Venue "lighter" is not metered here.
773
+ */
774
+ /** Take a token from the Lighter RH rate-limit bucket (no-op for venue "lighter"). Also used by LighterSpotAdapter. */
775
+ rhRate(endpoint: string): Promise<void>;
228
776
  private sendTx;
229
777
  private restGet;
230
778
  /** Generate a unique client order index (uint48). */
231
779
  private nextClientOrderIndex;
232
780
  private ensureSigner;
233
- private static _wasmClient;
234
- private static getWasmClient;
235
781
  /**
236
- * Generate a new Lighter API key pair using the WASM signer.
237
- * Returns { privateKey, publicKey } (both 0x-prefixed, 40 bytes).
782
+ * One WASM signer (one Go runtime) per `${venueId}:${network}` (design §10.5).
783
+ * lighter-go keys its clients by (accountIndex, apiKeyIndex) only and keeps a
784
+ * package-global chainId for L1 messages, so two venues must never share a
785
+ * runtime. Keyed by venue+network rather than chainId because Lighter testnet
786
+ * and Lighter RH testnet both use chainId 300.
238
787
  */
239
- static generateApiKey(): Promise<{
788
+ private static _wasmClients;
789
+ private get _wasmKey();
790
+ private _getWasmClient;
791
+ /**
792
+ * Load one official signer runtime (vendored lighter-go v1.0.9 WASM, sha256-verified;
793
+ * see lighter-signer.ts). The Go exports are captured synchronously right after go.run(),
794
+ * so concurrent creations cannot overwrite each other's functions.
795
+ */
796
+ private static _createWasmClient;
797
+ /**
798
+ * Generate a new Lighter API key pair using this venue's WASM signer
799
+ * (key generation is chain-independent). Returns { privateKey, publicKey }.
800
+ */
801
+ generateApiKey(): Promise<{
240
802
  privateKey: string;
241
803
  publicKey: string;
242
804
  }>;
805
+ /**
806
+ * Read every API-key slot registered on this account (`GET /api/v1/apikeys`).
807
+ * Used before a ChangePubKey (approve must not overwrite an in-use slot) and after
808
+ * one (revoke must confirm the slot's public key actually changed). Throws on a
809
+ * malformed response — callers must never treat an unreadable list as "all free".
810
+ */
811
+ listApiKeys(): Promise<Array<{
812
+ apiKeyIndex: number;
813
+ publicKey: string;
814
+ }>>;
243
815
  /**
244
816
  * Generate an API key and register it on-chain via ChangePubKey.
245
817
  * Uses WASM signer to sign + ETH key for L1 signature.