perp-cli 0.14.2 → 0.15.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 (313) hide show
  1. package/README.md +152 -13
  2. package/dist/agent-wallet/store.d.ts +3 -2
  3. package/dist/agent-wallet/store.js +2 -2
  4. package/dist/api/public/hyperliquid.js +4 -0
  5. package/dist/api/public/pacifica.js +83 -13
  6. package/dist/api/public/urls.d.ts +2 -0
  7. package/dist/api/public/urls.js +3 -0
  8. package/dist/arb/utils.d.ts +1 -2
  9. package/dist/arb/utils.js +1 -2
  10. package/dist/bot/apex/pulse.js +3 -0
  11. package/dist/bot/apex/radar.js +2 -1
  12. package/dist/bot/engine.d.ts +10 -1
  13. package/dist/bot/engine.js +14 -6
  14. package/dist/bot/indicators.d.ts +7 -0
  15. package/dist/bot/indicators.js +16 -0
  16. package/dist/bot/perp-order.d.ts +4 -4
  17. package/dist/bot/perp-order.js +5 -5
  18. package/dist/bot/quarantine.d.ts +1 -1
  19. package/dist/bot/quarantine.js +1 -1
  20. package/dist/bot/strategies/apex-strategy.js +3 -2
  21. package/dist/bot/strategies/engine-mm.js +6 -5
  22. package/dist/bot/strategies/funding-arb-strategy.js +9 -9
  23. package/dist/bot/strategies/funding-arb-utils.d.ts +15 -2
  24. package/dist/bot/strategies/funding-arb-utils.js +43 -24
  25. package/dist/bot/strategies/funding-auto.js +2 -2
  26. package/dist/bot/strategies/liquidation-mm.d.ts +1 -0
  27. package/dist/bot/strategies/liquidation-mm.js +8 -2
  28. package/dist/bot/strategies/momentum-breakout.d.ts +1 -0
  29. package/dist/bot/strategies/momentum-breakout.js +11 -3
  30. package/dist/bot/strategies/spot-perp-arb-strategy.js +23 -12
  31. package/dist/bot/strategies/spot-perp-executor.d.ts +1 -1
  32. package/dist/bot/strategies/spot-perp-executor.js +1 -1
  33. package/dist/bot/strategy-types.d.ts +2 -1
  34. package/dist/bot/tui/BotDashboard.d.ts +1 -1
  35. package/dist/bot/tui/BotDashboard.js +1 -1
  36. package/dist/cache.js +12 -6
  37. package/dist/cli-program.d.ts +15 -0
  38. package/dist/cli-program.js +125 -5
  39. package/dist/commands/agent-import.d.ts +7 -0
  40. package/dist/commands/agent-import.js +30 -1
  41. package/dist/commands/agent.d.ts +6 -3
  42. package/dist/commands/agent.js +160 -12
  43. package/dist/commands/arb/index.js +4 -4
  44. package/dist/commands/arb-auto.js +21 -17
  45. package/dist/commands/arb.d.ts +12 -0
  46. package/dist/commands/arb.js +61 -143
  47. package/dist/commands/bot.js +1 -1
  48. package/dist/commands/builder.js +1 -1
  49. package/dist/commands/funds.js +113 -3
  50. package/dist/commands/init.d.ts +1 -1
  51. package/dist/commands/init.js +27 -7
  52. package/dist/commands/manage.js +23 -21
  53. package/dist/commands/market.js +168 -36
  54. package/dist/commands/options.d.ts +9 -0
  55. package/dist/commands/options.js +134 -0
  56. package/dist/commands/pacifica-earn.d.ts +5 -0
  57. package/dist/commands/pacifica-earn.js +468 -0
  58. package/dist/commands/pacifica-orders.d.ts +14 -0
  59. package/dist/commands/pacifica-orders.js +142 -0
  60. package/dist/commands/portfolio.js +32 -47
  61. package/dist/commands/rebalance.d.ts +1 -0
  62. package/dist/commands/rebalance.js +15 -0
  63. package/dist/commands/risk.d.ts +11 -2
  64. package/dist/commands/risk.js +39 -44
  65. package/dist/commands/trade.d.ts +1 -0
  66. package/dist/commands/trade.js +63 -58
  67. package/dist/commands/wallet.js +1 -1
  68. package/dist/config.d.ts +2 -2
  69. package/dist/config.js +15 -4
  70. package/dist/constants.js +6 -0
  71. package/dist/dashboard/server.js +1 -1
  72. package/dist/dashboard/ui.js +1 -1
  73. package/dist/errors.d.ts +24 -1
  74. package/dist/errors.js +25 -3
  75. package/dist/exchanges/arcus/adapter.d.ts +7 -7
  76. package/dist/exchanges/arcus/adapter.js +12 -12
  77. package/dist/exchanges/arcus/agent.d.ts +1 -1
  78. package/dist/exchanges/arcus/agent.js +1 -1
  79. package/dist/exchanges/arcus/client.js +1 -1
  80. package/dist/exchanges/arcus/signing.d.ts +2 -3
  81. package/dist/exchanges/arcus/signing.js +1 -1
  82. package/dist/exchanges/arcus/spot-chain.d.ts +1 -1
  83. package/dist/exchanges/arcus/spot-chain.js +1 -1
  84. package/dist/exchanges/arcus/spot-router.d.ts +1 -1
  85. package/dist/exchanges/arcus/spot-router.js +2 -2
  86. package/dist/exchanges/arcus/spot.d.ts +2 -3
  87. package/dist/exchanges/arcus/spot.js +2 -3
  88. package/dist/exchanges/aster-spot.d.ts +3 -3
  89. package/dist/exchanges/aster-spot.js +6 -9
  90. package/dist/exchanges/aster-typed-data.d.ts +1 -1
  91. package/dist/exchanges/aster-typed-data.js +1 -1
  92. package/dist/exchanges/aster.d.ts +9 -4
  93. package/dist/exchanges/aster.js +125 -55
  94. package/dist/exchanges/builder-fee.d.ts +1 -1
  95. package/dist/exchanges/builder-fee.js +13 -2
  96. package/dist/exchanges/canonical-symbols.d.ts +1 -2
  97. package/dist/exchanges/canonical-symbols.js +26 -2
  98. package/dist/exchanges/derive/client.d.ts +37 -0
  99. package/dist/exchanges/derive/client.js +135 -0
  100. package/dist/exchanges/derive/options.d.ts +68 -0
  101. package/dist/exchanges/derive/options.js +360 -0
  102. package/dist/exchanges/extended/adapter.d.ts +82 -0
  103. package/dist/exchanges/extended/adapter.js +179 -0
  104. package/dist/exchanges/extended/client.d.ts +38 -0
  105. package/dist/exchanges/extended/client.js +88 -0
  106. package/dist/exchanges/extended/public.d.ts +130 -0
  107. package/dist/exchanges/extended/public.js +429 -0
  108. package/dist/exchanges/grvt/adapter.d.ts +86 -0
  109. package/dist/exchanges/grvt/adapter.js +206 -0
  110. package/dist/exchanges/grvt/client.d.ts +25 -0
  111. package/dist/exchanges/grvt/client.js +86 -0
  112. package/dist/exchanges/grvt/public.d.ts +151 -0
  113. package/dist/exchanges/grvt/public.js +438 -0
  114. package/dist/exchanges/hyperliquid-spot.d.ts +1 -1
  115. package/dist/exchanges/hyperliquid-spot.js +5 -5
  116. package/dist/exchanges/hyperliquid.d.ts +22 -16
  117. package/dist/exchanges/hyperliquid.js +80 -55
  118. package/dist/exchanges/index.d.ts +1 -1
  119. package/dist/exchanges/index.js +1 -1
  120. package/dist/exchanges/interface.d.ts +97 -8
  121. package/dist/exchanges/interface.js +19 -2
  122. package/dist/exchanges/ioc-outcome.d.ts +1 -1
  123. package/dist/exchanges/ioc-outcome.js +1 -1
  124. package/dist/exchanges/legacy-trading-v2.d.ts +2 -2
  125. package/dist/exchanges/legacy-trading-v2.js +7 -2
  126. package/dist/exchanges/lighter-public.d.ts +2 -2
  127. package/dist/exchanges/lighter-public.js +2 -2
  128. package/dist/exchanges/lighter-signer.d.ts +1 -1
  129. package/dist/exchanges/lighter-signer.js +1 -1
  130. package/dist/exchanges/lighter-spot.d.ts +3 -4
  131. package/dist/exchanges/lighter-spot.js +6 -7
  132. package/dist/exchanges/lighter.d.ts +11 -11
  133. package/dist/exchanges/lighter.js +28 -14
  134. package/dist/exchanges/ondo/adapter.d.ts +5 -6
  135. package/dist/exchanges/ondo/adapter.js +16 -14
  136. package/dist/exchanges/ondo/agent.d.ts +1 -1
  137. package/dist/exchanges/ondo/agent.js +1 -1
  138. package/dist/exchanges/ondo/client.d.ts +1 -1
  139. package/dist/exchanges/ondo/client.js +2 -2
  140. package/dist/exchanges/ondo/public.d.ts +8 -1
  141. package/dist/exchanges/ondo/public.js +13 -2
  142. package/dist/exchanges/ondo/spot.d.ts +2 -2
  143. package/dist/exchanges/ondo/spot.js +3 -3
  144. package/dist/exchanges/options-interface.d.ts +158 -0
  145. package/dist/exchanges/options-interface.js +17 -0
  146. package/dist/exchanges/options-venues.d.ts +12 -0
  147. package/dist/exchanges/options-venues.js +35 -0
  148. package/dist/exchanges/pacifica-atomic.d.ts +211 -0
  149. package/dist/exchanges/pacifica-atomic.js +440 -0
  150. package/dist/exchanges/pacifica-decimal.d.ts +10 -0
  151. package/dist/exchanges/pacifica-decimal.js +51 -0
  152. package/dist/exchanges/pacifica-presigned.d.ts +53 -0
  153. package/dist/exchanges/pacifica-presigned.js +141 -0
  154. package/dist/exchanges/pacifica-print.d.ts +200 -0
  155. package/dist/exchanges/pacifica-print.js +417 -0
  156. package/dist/exchanges/pacifica-spot.d.ts +2 -2
  157. package/dist/exchanges/pacifica-spot.js +3 -3
  158. package/dist/exchanges/pacifica-typed-data.d.ts +1 -1
  159. package/dist/exchanges/pacifica-typed-data.js +1 -1
  160. package/dist/exchanges/pacifica-vaults.d.ts +121 -0
  161. package/dist/exchanges/pacifica-vaults.js +264 -0
  162. package/dist/exchanges/pacifica.d.ts +32 -5
  163. package/dist/exchanges/pacifica.js +114 -48
  164. package/dist/exchanges/precision.d.ts +3 -1
  165. package/dist/exchanges/precision.js +9 -2
  166. package/dist/exchanges/qfex/adapter.d.ts +18 -5
  167. package/dist/exchanges/qfex/adapter.js +32 -12
  168. package/dist/exchanges/qfex/agent.d.ts +1 -1
  169. package/dist/exchanges/qfex/agent.js +1 -1
  170. package/dist/exchanges/qfex/client.d.ts +1 -1
  171. package/dist/exchanges/qfex/client.js +1 -1
  172. package/dist/exchanges/qfex/errors.d.ts +1 -1
  173. package/dist/exchanges/qfex/errors.js +2 -2
  174. package/dist/exchanges/qfex/public.d.ts +3 -3
  175. package/dist/exchanges/qfex/public.js +3 -3
  176. package/dist/exchanges/qfex/signing.d.ts +2 -2
  177. package/dist/exchanges/qfex/signing.js +4 -5
  178. package/dist/exchanges/qfex/ws-transport.d.ts +2 -2
  179. package/dist/exchanges/qfex/ws-transport.js +3 -3
  180. package/dist/exchanges/rate-limiter.d.ts +1 -1
  181. package/dist/exchanges/rate-limiter.js +5 -2
  182. package/dist/exchanges/registry.d.ts +1 -1
  183. package/dist/exchanges/registry.js +1 -1
  184. package/dist/exchanges/risex/adapter.d.ts +148 -0
  185. package/dist/exchanges/risex/adapter.js +796 -0
  186. package/dist/exchanges/risex/agent.d.ts +154 -0
  187. package/dist/exchanges/risex/agent.js +384 -0
  188. package/dist/exchanges/risex/client.d.ts +47 -0
  189. package/dist/exchanges/risex/client.js +174 -0
  190. package/dist/exchanges/risex/nonce.d.ts +43 -0
  191. package/dist/exchanges/risex/nonce.js +212 -0
  192. package/dist/exchanges/risex/public.d.ts +64 -0
  193. package/dist/exchanges/risex/public.js +150 -0
  194. package/dist/exchanges/risex/session.d.ts +71 -0
  195. package/dist/exchanges/risex/session.js +171 -0
  196. package/dist/exchanges/risex/typed-data.d.ts +173 -0
  197. package/dist/exchanges/risex/typed-data.js +240 -0
  198. package/dist/exchanges/risex/units.d.ts +29 -0
  199. package/dist/exchanges/risex/units.js +104 -0
  200. package/dist/exchanges/slippage.d.ts +1 -1
  201. package/dist/exchanges/slippage.js +1 -1
  202. package/dist/exchanges/spot-factory.d.ts +3 -3
  203. package/dist/exchanges/spot-factory.js +7 -7
  204. package/dist/exchanges/spot-interface.d.ts +5 -5
  205. package/dist/exchanges/spot-interface.js +2 -2
  206. package/dist/exchanges/spot-result.d.ts +3 -3
  207. package/dist/exchanges/spot-result.js +3 -3
  208. package/dist/exchanges/trading-v2.d.ts +3 -3
  209. package/dist/exchanges/trading-v2.js +9 -6
  210. package/dist/exchanges/txflow/adapter.d.ts +54 -0
  211. package/dist/exchanges/txflow/adapter.js +118 -0
  212. package/dist/exchanges/txflow/client.d.ts +47 -0
  213. package/dist/exchanges/txflow/client.js +153 -0
  214. package/dist/exchanges/txflow/public.d.ts +76 -0
  215. package/dist/exchanges/txflow/public.js +284 -0
  216. package/dist/exchanges/unknown-symbol.d.ts +29 -0
  217. package/dist/exchanges/unknown-symbol.js +51 -0
  218. package/dist/exchanges/variational/adapter.d.ts +71 -0
  219. package/dist/exchanges/variational/adapter.js +137 -0
  220. package/dist/exchanges/variational/client.d.ts +21 -0
  221. package/dist/exchanges/variational/client.js +66 -0
  222. package/dist/exchanges/variational/public.d.ts +126 -0
  223. package/dist/exchanges/variational/public.js +430 -0
  224. package/dist/exchanges/venue-types.d.ts +6 -7
  225. package/dist/exchanges/venue-types.js +2 -2
  226. package/dist/exchanges/venue.d.ts +51 -8
  227. package/dist/exchanges/venue.js +54 -4
  228. package/dist/exchanges/venues/arcus.d.ts +1 -2
  229. package/dist/exchanges/venues/arcus.js +5 -4
  230. package/dist/exchanges/venues/aster.d.ts +2 -2
  231. package/dist/exchanges/venues/aster.js +6 -4
  232. package/dist/exchanges/venues/create-helpers.d.ts +1 -1
  233. package/dist/exchanges/venues/create-helpers.js +3 -3
  234. package/dist/exchanges/venues/extended.d.ts +21 -0
  235. package/dist/exchanges/venues/extended.js +96 -0
  236. package/dist/exchanges/venues/grvt.d.ts +30 -0
  237. package/dist/exchanges/venues/grvt.js +98 -0
  238. package/dist/exchanges/venues/hyperliquid.d.ts +2 -2
  239. package/dist/exchanges/venues/hyperliquid.js +10 -8
  240. package/dist/exchanges/venues/index.d.ts +7 -2
  241. package/dist/exchanges/venues/index.js +8 -2
  242. package/dist/exchanges/venues/lighter-family.d.ts +7 -9
  243. package/dist/exchanges/venues/lighter-family.js +9 -11
  244. package/dist/exchanges/venues/lighter-rh.d.ts +2 -2
  245. package/dist/exchanges/venues/lighter-rh.js +7 -5
  246. package/dist/exchanges/venues/lighter.d.ts +1 -1
  247. package/dist/exchanges/venues/lighter.js +5 -3
  248. package/dist/exchanges/venues/ondo.d.ts +1 -1
  249. package/dist/exchanges/venues/ondo.js +5 -3
  250. package/dist/exchanges/venues/pacifica.d.ts +2 -2
  251. package/dist/exchanges/venues/pacifica.js +6 -4
  252. package/dist/exchanges/venues/qfex.d.ts +1 -1
  253. package/dist/exchanges/venues/qfex.js +4 -2
  254. package/dist/exchanges/venues/risex-release.d.ts +14 -0
  255. package/dist/exchanges/venues/risex-release.js +14 -0
  256. package/dist/exchanges/venues/risex.d.ts +31 -0
  257. package/dist/exchanges/venues/risex.js +116 -0
  258. package/dist/exchanges/venues/txflow.d.ts +18 -0
  259. package/dist/exchanges/venues/txflow.js +77 -0
  260. package/dist/exchanges/venues/variational.d.ts +21 -0
  261. package/dist/exchanges/venues/variational.js +85 -0
  262. package/dist/execution-log.d.ts +1 -1
  263. package/dist/funding/legacy-public.d.ts +1 -1
  264. package/dist/funding/legacy-public.js +9 -4
  265. package/dist/funding/normalize.d.ts +1 -1
  266. package/dist/funding/normalize.js +1 -1
  267. package/dist/funding/rates.d.ts +44 -4
  268. package/dist/funding/rates.js +56 -12
  269. package/dist/index.js +7 -6
  270. package/dist/jobs.d.ts +1 -0
  271. package/dist/jobs.js +25 -1
  272. package/dist/landing.d.ts +2 -0
  273. package/dist/landing.js +1 -1
  274. package/dist/mcp-pacifica-earn.d.ts +9 -0
  275. package/dist/mcp-pacifica-earn.js +58 -0
  276. package/dist/mcp-server.js +113 -59
  277. package/dist/pacifica/client.d.ts +67 -4
  278. package/dist/pacifica/client.js +170 -8
  279. package/dist/pacifica/rate-limit.d.ts +144 -0
  280. package/dist/pacifica/rate-limit.js +267 -0
  281. package/dist/pacifica/types/order.d.ts +2 -1
  282. package/dist/plan-executor.js +7 -2
  283. package/dist/rebalance.js +1 -1
  284. package/dist/risk.d.ts +2 -1
  285. package/dist/risk.js +2 -4
  286. package/dist/settings.d.ts +32 -3
  287. package/dist/signer/ows-evm.d.ts +1 -1
  288. package/dist/signer/ows-evm.js +1 -1
  289. package/dist/smart-order.d.ts +1 -1
  290. package/dist/smart-order.js +1 -1
  291. package/dist/strategies/funding-arb.d.ts +1 -1
  292. package/dist/strategies/funding-arb.js +1 -1
  293. package/dist/trade-validator.d.ts +1 -1
  294. package/dist/trade-validator.js +9 -4
  295. package/dist/utils.d.ts +12 -3
  296. package/dist/utils.js +11 -3
  297. package/dist/venue-health.d.ts +40 -0
  298. package/dist/venue-health.js +75 -0
  299. package/dist/withdraw-gate.d.ts +1 -1
  300. package/dist/withdraw-gate.js +1 -1
  301. package/dist/ws/index.d.ts +959 -0
  302. package/dist/ws/index.js +4295 -0
  303. package/dist/ws/node.d.ts +975 -0
  304. package/dist/ws/node.js +4366 -0
  305. package/dist/ws/pacifica-instrument.d.ts +8 -0
  306. package/dist/ws/pacifica-instrument.js +8 -0
  307. package/dist/ws-cli/credentials.d.ts +62 -0
  308. package/dist/ws-cli/credentials.js +126 -0
  309. package/package.json +58 -10
  310. package/skills/perp-cli/SKILL.md +62 -9
  311. package/skills/perp-cli/references/agent-operations.md +7 -0
  312. package/skills/perp-cli/references/commands.md +76 -5
  313. package/skills/perp-cli/references/ws-library.md +492 -0
@@ -9,9 +9,9 @@ import { rateLimitedError } from "./rate-limiter.js";
9
9
  import { fetchAndCache, withCache, TTL_ACCOUNT } from "../cache.js";
10
10
  import { approvalFromMax, builderGateOf, hlFeeTenthsBps, NO_BUILDER, requireFeeBps } from "./builder-fee.js";
11
11
  /**
12
- * Map a TIF input to HL's native value (design §13.3). Accepts the common names
12
+ * Map a TIF input to HL's native value. Accepts the common names
13
13
  * GTC/IOC/ALO and the native spellings case-insensitively. FOK is not offered by
14
- * HL (no FOK emulation, §13.3) → CAPABILITY_UNSUPPORTED; anything else likewise.
14
+ * HL (no FOK emulation) → CAPABILITY_UNSUPPORTED; anything else likewise.
15
15
  */
16
16
  export function hlTif(raw) {
17
17
  const t = raw.trim().toUpperCase();
@@ -31,7 +31,7 @@ export function hlSizeStep(szDecimals) {
31
31
  return szDecimals <= 0 ? "1" : `0.${"0".repeat(szDecimals - 1)}1`;
32
32
  }
33
33
  /**
34
- * Slippage-bounded IOC protection price (design §13.2, §13.10 #5).
34
+ * Slippage-bounded IOC protection price.
35
35
  *
36
36
  * `reference` × (1 ± bps/10000), then aligned TOWARD CROSSING (buy → up, sell →
37
37
  * down) on HL's price grid: at most 5 significant figures and at most
@@ -56,8 +56,8 @@ export function hlProtectionPrice(reference, side, bps, szDecimals, maxDecimals)
56
56
  return { protectionPrice, appliedBps };
57
57
  }
58
58
  /**
59
- * A USER-SUPPLIED limit / trigger / modify price checked against HL's price grid (design §10.10:
60
- * an off-grid limit price is refused, never rounded — rounding to nearest can move a buy price UP).
59
+ * A USER-SUPPLIED limit / trigger / modify price checked against HL's price grid:
60
+ * an off-grid limit price is refused, never rounded — rounding to nearest can move a buy price UP.
61
61
  * HL docs (trading/tick-and-lot-size): "Prices can have up to 5 significant figures, but no more
62
62
  * than MAX_DECIMALS - szDecimals decimal places where MAX_DECIMALS is 6 for perps and 8 for spot.
63
63
  * Integer prices are always allowed, regardless of the number of significant figures."
@@ -140,7 +140,7 @@ export async function assertHlAppliedBps(appliedBps, what) {
140
140
  }
141
141
  /**
142
142
  * Definite IOC outcome of a raw HL `order` response (shared contract with the
143
- * perp-order lane, design §13.10 #4). Reads `response.data.statuses[0]`:
143
+ * perp-order lane). Reads `response.data.statuses[0]`:
144
144
  * - `{ filled: { totalSz } }` with a plain decimal totalSz → that size, final;
145
145
  * - `{ error }` that is HL's IOC no-match cancel ("could not immediately match")
146
146
  * → the venue explicitly cancelled the IOC with nothing filled → "0", final;
@@ -653,7 +653,7 @@ export class HyperliquidAdapter {
653
653
  // A dex-prefixed symbol must name THIS adapter's dex — never rewritten onto another dex.
654
654
  const [prefix, base] = sym.split(":");
655
655
  if (prefix.toLowerCase() !== this._dex.toLowerCase()) {
656
- throw new PerpError("SYMBOL_NOT_FOUND", `Hyperliquid symbol ${symbol} is on dex "${prefix.toLowerCase()}", not ${this._dex ? `this adapter's dex "${this._dex}"` : "the native perp dex"}`, {
656
+ throw new PerpError("SYMBOL_NOT_FOUND", `Hyperliquid symbol ${prefix.toLowerCase()}:${base} is on dex "${prefix.toLowerCase()}", not ${this._dex ? `this adapter's dex "${this._dex}"` : "the native perp dex"}`, {
657
657
  exchange: "hyperliquid", remediation: `Select the dex: perp -e hyperliquid --dex ${prefix.toLowerCase()} ...`,
658
658
  });
659
659
  }
@@ -726,7 +726,14 @@ export class HyperliquidAdapter {
726
726
  }
727
727
  return idx;
728
728
  }
729
- throw new PerpError("SYMBOL_NOT_FOUND", `Unknown asset: ${symbol}`, { exchange: "hyperliquid" });
729
+ throw this._unknownSymbol(symbol, `Unknown asset: ${symbol}`);
730
+ }
731
+ /** SYMBOL_NOT_FOUND for a coin the venue does not list (on this adapter's dex), with the listing command. */
732
+ _unknownSymbol(symbol, message) {
733
+ return new PerpError("SYMBOL_NOT_FOUND", message ?? `Hyperliquid has no market ${symbol.toUpperCase()}${this._dex ? ` on dex "${this._dex}"` : ""}`, {
734
+ exchange: "hyperliquid",
735
+ remediation: `List markets: perp -e hyperliquid${this._dex ? ` --dex ${this._dex}` : ""} market list`,
736
+ });
730
737
  }
731
738
  async getMarkets() {
732
739
  if (this._marketsCache && Date.now() - this._marketsCacheTime < HyperliquidAdapter.CACHE_TTL)
@@ -785,32 +792,57 @@ export class HyperliquidAdapter {
785
792
  this._assetMapReverse.set(i, sym);
786
793
  });
787
794
  }
788
- const result = universe.map((asset, i) => {
795
+ // Delisted assets (meta `isDelisted: true`; live 2026-10-14: 56 of 234 native perps, all with
796
+ // funding / dayNtlVlm / openInterest "0.0") are not markets: excluded from the listing and
797
+ // everything built on it. They stay in the asset map (_loadAssetMap), so an explicit symbol
798
+ // still resolves for orders / position reads.
799
+ const delisted = new Set();
800
+ const result = universe.flatMap((asset, i) => {
801
+ if (asset.isDelisted === true) {
802
+ delisted.add(String(asset.name));
803
+ return [];
804
+ }
789
805
  const ctx = (ctxs[i] ?? {});
790
806
  const sym = String(asset.name);
791
807
  const szDec = this._szDecimalsMap.get(sym) ?? (asset.szDecimals !== undefined ? Number(asset.szDecimals) : null);
792
- return {
793
- symbol: sym,
794
- markPrice: String(ctx.markPx ?? mids[sym] ?? "0"),
795
- indexPrice: ctx.oraclePx != null ? String(ctx.oraclePx) : null,
796
- fundingRate: ctx.funding != null ? String(ctx.funding) : null,
797
- volume24h: ctx.dayNtlVlm != null ? String(ctx.dayNtlVlm) : null,
798
- openInterest: ctx.openInterest != null ? String(ctx.openInterest) : null,
799
- maxLeverage: Number(asset.maxLeverage ?? 50),
800
- sizeDecimals: szDec,
801
- // HL has no separate lot-size field; the step is implied by szDecimals.
802
- stepSize: null,
803
- // HL funding is uniform (venue definition), not per-market.
804
- fundingHours: null,
805
- marginTiers: tierMap.get(Number(asset.marginTableId)) ?? null,
806
- };
808
+ return [{
809
+ symbol: sym,
810
+ markPrice: String(ctx.markPx ?? mids[sym] ?? "0"),
811
+ indexPrice: ctx.oraclePx != null ? String(ctx.oraclePx) : null,
812
+ fundingRate: ctx.funding != null ? String(ctx.funding) : null,
813
+ volume24h: ctx.dayNtlVlm != null ? String(ctx.dayNtlVlm) : null,
814
+ openInterest: ctx.openInterest != null ? String(ctx.openInterest) : null,
815
+ maxLeverage: Number(asset.maxLeverage ?? 50),
816
+ sizeDecimals: szDec,
817
+ // HL has no separate lot-size field; the step is implied by szDecimals.
818
+ stepSize: null,
819
+ // HL funding is uniform (venue definition), not per-market.
820
+ fundingHours: null,
821
+ marginTiers: tierMap.get(Number(asset.marginTableId)) ?? null,
822
+ }];
807
823
  });
824
+ this._delisted = delisted;
808
825
  this._marketsCache = result;
809
826
  this._marketsCacheTime = Date.now();
810
827
  return result;
811
828
  }
829
+ /** Display names of the delisted assets seen by the last getMarkets() (meta isDelisted). */
830
+ _delisted = new Set();
831
+ /**
832
+ * Why `symbol` is not in getMarkets(): it is delisted (message), or null when it is not a
833
+ * delisted asset. Read after getMarkets(). `market info` uses it to say "delisted" rather than
834
+ * "not found" — the asset map still resolves it for orders / positions / history.
835
+ */
836
+ delistedMessage(symbol) {
837
+ const resolved = this.resolveSymbol(symbol.toUpperCase());
838
+ if (!this._delisted.has(resolved))
839
+ return null;
840
+ return `${resolved.replace(/-PERP$/, "")} is delisted on Hyperliquid (positions / history still readable)`;
841
+ }
812
842
  async getOrderbook(symbol) {
813
843
  let levels;
844
+ // l2Book answers `null` for a coin the venue does not list (live 2026-10-14, coin "NOPE"):
845
+ // SYMBOL_NOT_FOUND, never an empty book (which reads as "no liquidity").
814
846
  if (this._dex) {
815
847
  // HIP-3 dex: full dex-prefixed coin (e.g. "US500" → "km:US500") + dex param
816
848
  const book = await this._infoPost({
@@ -818,11 +850,15 @@ export class HyperliquidAdapter {
818
850
  coin: this._venueCoin(symbol),
819
851
  dex: this._dex,
820
852
  });
821
- levels = book?.levels ?? [[], []];
853
+ if (book === null)
854
+ throw this._unknownSymbol(symbol);
855
+ levels = book.levels ?? [[], []];
822
856
  }
823
857
  else {
824
858
  const book = await this._infoPost({ type: "l2Book", coin: this._venueCoin(symbol) });
825
- levels = book?.levels ?? [[], []];
859
+ if (book === null)
860
+ throw this._unknownSymbol(symbol);
861
+ levels = book.levels ?? [[], []];
826
862
  }
827
863
  return {
828
864
  bids: (levels[0] ?? []).map((l) => [
@@ -1234,11 +1270,11 @@ export class HyperliquidAdapter {
1234
1270
  }
1235
1271
  }
1236
1272
  /**
1237
- * Market order = slippage-bounded IOC limit (design §13.2, §13.10 #1/#5) for
1273
+ * Market order = slippage-bounded IOC limit for
1238
1274
  * native perps and HIP-3 dexes alike. Replaces the SDK's marketOpen/marketClose
1239
1275
  * (hidden built-in slippage) and the former HIP-3 5% constant.
1240
1276
  *
1241
- * Reference price (the single declared source, §13.10 #5): the l2Book mid
1277
+ * Reference price (the single declared source): the l2Book mid
1242
1278
  * (best bid + best ask) / 2 of this coin — see referencePrice(). No runtime
1243
1279
  * substitute (mark, allMids, last trade): a missing side → PRICE_STALE before
1244
1280
  * anything is sent. Protection = reference ± opts.slippage.bps, aligned toward
@@ -1531,7 +1567,7 @@ export class HyperliquidAdapter {
1531
1567
  return hlAlignPriceToGrid(price, this.getSzDecimals(symbol), 6, side === "buy" ? "down" : "up");
1532
1568
  }
1533
1569
  async limitOrder(symbol, side, price, size, opts) {
1534
- // TIF aliases (§13.3): GTC/IOC/ALO or native spellings; FOK → CAPABILITY_UNSUPPORTED.
1570
+ // TIF aliases: GTC/IOC/ALO or native spellings; FOK → CAPABILITY_UNSUPPORTED.
1535
1571
  let action;
1536
1572
  const cloid = opts?.clientOrderId === undefined ? null : HyperliquidAdapter.requireCloid(opts.clientOrderId);
1537
1573
  try { // pre-send (see marketOrder)
@@ -1680,7 +1716,7 @@ export class HyperliquidAdapter {
1680
1716
  }
1681
1717
  // ── Interface methods ──
1682
1718
  /**
1683
- * Amend (design §13.4, §13.10 #10) via HL native batchModify. `size` = the NEW
1719
+ * Amend via HL native batchModify. `size` = the NEW
1684
1720
  * open (unfilled) size — native-modify semantics, not the original total. The
1685
1721
  * order's own tif (Gtc/Alo) and reduceOnly are read from frontendOpenOrders
1686
1722
  * and preserved; nothing is hardcoded.
@@ -1770,8 +1806,13 @@ export class HyperliquidAdapter {
1770
1806
  });
1771
1807
  }
1772
1808
  async getRecentTrades(symbol, limit = 20) {
1809
+ // recentTrades answers HTTP 500 "null" for an unlisted coin (live 2026-10-14), which would read
1810
+ // as a retryable venue error: resolve the coin against the asset map first (SYMBOL_NOT_FOUND).
1811
+ await this.getAssetIndex(symbol);
1773
1812
  const trades = await this._infoPost({ type: "recentTrades", coin: this._venueCoin(symbol) });
1774
- return (trades ?? [])
1813
+ if (trades === null)
1814
+ throw this._unknownSymbol(symbol);
1815
+ return trades
1775
1816
  .slice(0, limit)
1776
1817
  .map((t) => ({
1777
1818
  time: Number(t.time ?? 0),
@@ -1779,10 +1820,11 @@ export class HyperliquidAdapter {
1779
1820
  side: String(t.side) === "B" ? "buy" : "sell",
1780
1821
  price: String(t.px ?? "0"),
1781
1822
  size: String(t.sz ?? ""),
1782
- fee: "0",
1823
+ fee: null, // the public tape carries no fee
1783
1824
  }));
1784
1825
  }
1785
1826
  async getKlines(symbol, interval, startTime, endTime) {
1827
+ await this.getAssetIndex(symbol); // unlisted coin: SYMBOL_NOT_FOUND (candleSnapshot answers HTTP 500 "null")
1786
1828
  const candles = await this._infoPost({
1787
1829
  type: "candleSnapshot",
1788
1830
  req: { coin: this._venueCoin(symbol), interval, startTime, endTime },
@@ -1793,7 +1835,10 @@ export class HyperliquidAdapter {
1793
1835
  high: String(c.h ?? "0"),
1794
1836
  low: String(c.l ?? "0"),
1795
1837
  close: String(c.c ?? "0"),
1796
- volume: String(c.v ?? ""),
1838
+ // absent / non-numeric → null (never "")
1839
+ volume: typeof c.v === "string" && c.v.trim() !== "" && Number.isFinite(Number(c.v)) ? c.v
1840
+ : typeof c.v === "number" && Number.isFinite(c.v) ? String(c.v) : null,
1841
+ quoteVolume: null, // candleSnapshot carries base volume only
1797
1842
  trades: Number(c.n ?? 0),
1798
1843
  }));
1799
1844
  }
@@ -1943,6 +1988,7 @@ export class HyperliquidAdapter {
1943
1988
  return !/[:@#/]/.test(coin);
1944
1989
  }
1945
1990
  async getFundingHistory(symbol, limit = 10) {
1991
+ await this.getAssetIndex(symbol); // unlisted coin: SYMBOL_NOT_FOUND (fundingHistory answers HTTP 500)
1946
1992
  const now = Date.now();
1947
1993
  const history = await this._infoPost({ type: "fundingHistory", coin: this._venueCoin(symbol), startTime: now - 24 * 60 * 60 * 1000 });
1948
1994
  return (history ?? []).slice(-limit).map((h) => ({
@@ -1958,7 +2004,7 @@ export class HyperliquidAdapter {
1958
2004
  * Place a trigger order (stop loss / take profit).
1959
2005
  * Python SDK: order() with trigger type {"trigger": {triggerPx, isMarket, tpsl: "tp"|"sl"}}
1960
2006
  *
1961
- * Pricing (design §13.10 #3):
2007
+ * Pricing:
1962
2008
  * - isMarket (default): HL native market trigger; `p` = trigger ± 10 % (the venue's documented
1963
2009
  * market TP/SL slippage tolerance, HL_MARKET_TPSL_SLIPPAGE_BPS), aligned toward crossing.
1964
2010
  * - limit trigger with an explicit `limitPrice`: that price, rounded to HL's grid.
@@ -2385,27 +2431,6 @@ export class HyperliquidAdapter {
2385
2431
  }
2386
2432
  return res;
2387
2433
  }
2388
- /**
2389
- * Get funding history for a symbol.
2390
- */
2391
- async getFundingHistoryRaw(symbol, startTime, endTime) {
2392
- const baseUrl = this._testnet
2393
- ? "https://api.hyperliquid-testnet.xyz"
2394
- : "https://api.hyperliquid.xyz";
2395
- const body = {
2396
- type: "fundingHistory",
2397
- coin: symbol.toUpperCase(),
2398
- startTime,
2399
- };
2400
- if (endTime)
2401
- body.endTime = endTime;
2402
- const res = await fetch(`${baseUrl}/info`, {
2403
- method: "POST",
2404
- headers: { "Content-Type": "application/json" },
2405
- body: JSON.stringify(body),
2406
- });
2407
- return res.json();
2408
- }
2409
2434
  /**
2410
2435
  * Get user trade fills.
2411
2436
  */
@@ -1,4 +1,4 @@
1
- export type { ExchangeMarketInfo, ExchangePosition, ExchangeOrder, ExchangeBalance, ExchangeTrade, ExchangeFundingPayment, ExchangeKline, ExchangeAdapter, } from "./interface.js";
1
+ export type { ExchangeMarketInfo, ExchangePosition, ExchangeOrder, ExchangeBalance, ExchangeTrade, ExchangePublicTrade, ExchangeFundingPayment, ExchangeKline, ExchangeAdapter, } from "./interface.js";
2
2
  export type { SpotMarketInfo, SpotBalance, SpotAdapter } from "./spot-interface.js";
3
3
  export { SPOT_PERP_TOKEN_MAP, PERP_TO_SPOT_MAP, MAX_PRICE_DEVIATION_PCT } from "./spot-interface.js";
4
4
  export * from "./capabilities.js";
@@ -9,7 +9,7 @@ export { LighterAdapter } from "./lighter.js";
9
9
  export { AsterAdapter } from "./aster.js";
10
10
  export { HyperliquidSpotAdapter } from "./hyperliquid-spot.js";
11
11
  export { LighterSpotAdapter } from "./lighter-spot.js";
12
- // Venue abstraction (docs/DESIGN-venue-abstraction.md §10)
12
+ // Venue abstraction
13
13
  export { getVenue, listVenues, listVenuesWithRole, resolveVenueId, tryResolveVenueId, parseVenueRef, networkConfig, requireCapabilities, fundingBasisOf, settlementIntervalOf, isLegacyVenue, isVenueId, READ_ONLY_CREDENTIALS, } from "./venue.js";
14
14
  export { ensureVenuesRegistered, ALL_VENUES } from "./venues/index.js";
15
15
  export { isTradingV2, validateOrderRequest, validateLegacyTif } from "./trading-v2.js";
@@ -9,11 +9,16 @@ export interface ExchangeMarketInfo {
9
9
  /** null = venue does not publish an index/oracle price for this market */
10
10
  indexPrice: string | null;
11
11
  fundingRate: string | null;
12
- /** null = venue does not publish 24h volume */
12
+ /** 24h volume in USD notional; null = venue does not publish 24h volume */
13
13
  volume24h: string | null;
14
- /** null = venue does not publish open interest (never "0" as a stand-in) */
14
+ /**
15
+ * Open interest in BASE-asset units (contracts of the underlying, e.g. BTC) — every venue
16
+ * publishes it that way, so it is never a USD figure. null = venue does not publish it
17
+ * (never "0" as a stand-in).
18
+ */
15
19
  openInterest: string | null;
16
- maxLeverage: number;
20
+ /** null = the venue does not publish it (Aster: the public exchangeInfo carries no leverage) */
21
+ maxLeverage: number | null;
17
22
  /** quantity precision (e.g. 0 = integers only, 2 = 0.01); null = unknown */
18
23
  sizeDecimals: number | null;
19
24
  /** lot step size (e.g. "1", "0.1", "0.001"); null = unknown */
@@ -38,7 +43,7 @@ export interface ExchangeMarketInfo {
38
43
  * A venue that publishes no tiers (`marginTiers === null`) has one flat cap,
39
44
  * `maxLeverage`, at every size — that is the venue's definition, not a fallback.
40
45
  */
41
- export declare function maxLeverageForNotional(market: ExchangeMarketInfo, notional: number): number;
46
+ export declare function maxLeverageForNotional(market: ExchangeMarketInfo, notional: number): number | null;
42
47
  export interface ExchangePosition {
43
48
  symbol: string;
44
49
  side: "long" | "short";
@@ -78,6 +83,27 @@ export interface ExchangeTrade {
78
83
  size: string;
79
84
  fee: string;
80
85
  }
86
+ /**
87
+ * A row of the PUBLIC trade tape (getRecentTrades). The tape carries no fee for the viewer —
88
+ * a fee exists only on the account's own fills (getTradeHistory) — so `fee` is always null
89
+ * here, never "0" as a stand-in.
90
+ */
91
+ export interface ExchangePublicTrade extends Omit<ExchangeTrade, "fee"> {
92
+ fee: null;
93
+ }
94
+ /**
95
+ * Rows of a public tape the adapter left out because they carry a value the venue documents but
96
+ * does not declare exhaustive (e.g. a new Pacifica event_type) — never guessed into a direction.
97
+ * Attached to the returned array under this symbol key (not serialized); `market trades` reports
98
+ * it as `meta.skippedRows`. Absent = nothing skipped.
99
+ */
100
+ export declare const TAPE_SKIPPED: unique symbol;
101
+ export interface TapeSkipped {
102
+ count: number;
103
+ reason: string;
104
+ }
105
+ export declare function withTapeSkipped<T>(rows: T[], skipped: TapeSkipped | null): T[];
106
+ export declare function tapeSkippedOf(rows: readonly unknown[]): TapeSkipped | null;
81
107
  export interface ExchangeFundingPayment {
82
108
  time: number;
83
109
  symbol: string;
@@ -89,10 +115,69 @@ export interface ExchangeKline {
89
115
  high: string;
90
116
  low: string;
91
117
  close: string;
92
- volume: string;
118
+ /** Base-asset volume of the candle; null = venue does not publish it (never "0" as a stand-in) */
119
+ volume: string | null;
120
+ /** Quote (USD) notional volume of the candle; null = venue does not publish it */
121
+ quoteVolume: string | null;
93
122
  /** null = venue does not publish a trade count for the candle */
94
123
  trades: number | null;
95
124
  }
125
+ /** One indicative quote of an RFQ venue's maker at a fixed size. */
126
+ export interface RfqQuoteTier {
127
+ /** Venue tier id ("base" = the market's minimum order size). */
128
+ tier: string;
129
+ /** USD notional of the tier; null when the venue does not publish it (minimum order size). */
130
+ notionalUsd: string | null;
131
+ bid: string;
132
+ ask: string;
133
+ }
134
+ /** An RFQ venue's indicative maker quotes — NOT order-book levels (`market book` on such a venue). */
135
+ export interface RfqQuotes {
136
+ kind: "rfqQuotes";
137
+ venue: string;
138
+ symbol: string;
139
+ ticker: string;
140
+ markPrice: string;
141
+ /** null = no quotes published right now (e.g. a closed market). */
142
+ updatedAt: string | null;
143
+ baseSpreadBps: string | null;
144
+ quotes: RfqQuoteTier[];
145
+ note: string;
146
+ }
147
+ /** Separate long / short rates of one daily swap funding payment (fractions). */
148
+ export interface SwapFundingRates {
149
+ annualizedLong: string;
150
+ annualizedShort: string;
151
+ intervalLong: string;
152
+ intervalShort: string;
153
+ }
154
+ /** Current funding terms of one market, for a venue that publishes no funding history (`market funding`). */
155
+ export interface CurrentFundingTerms {
156
+ kind: "currentFunding";
157
+ venue: string;
158
+ symbol: string;
159
+ ticker: string;
160
+ contractType: "perpetual" | "swap";
161
+ /** "predicted": the rate charged at nextFundingTime, recomputed during the window. */
162
+ rateKind: "predicted" | null;
163
+ /** Fraction per interval as published (perpetual); null for a swap or when unknown. */
164
+ intervalRate: string | null;
165
+ intervalHours: number | null;
166
+ /** intervalRate / intervalHours. */
167
+ hourlyRate: number | null;
168
+ /** hourlyRate × 24 × 365 × 100 (same normalization as arb scan). */
169
+ annualizedPct: number | null;
170
+ /** The venue's own annualized rate (fraction), for cross-checking. */
171
+ venueAnnualizedRate: string | null;
172
+ /** Unix ms; null when not published. */
173
+ nextFundingTime: number | null;
174
+ /** Swap only: long / short rates of the last applied and the upcoming payment. */
175
+ swap: {
176
+ last: SwapFundingRates | null;
177
+ next: SwapFundingRates | null;
178
+ } | null;
179
+ note: string;
180
+ }
96
181
  export interface ExchangeAdapter {
97
182
  readonly name: string;
98
183
  readonly chain?: string;
@@ -105,13 +190,17 @@ export interface ExchangeAdapter {
105
190
  bids: [string, string][];
106
191
  asks: [string, string][];
107
192
  }>;
108
- getRecentTrades(symbol: string, limit?: number): Promise<ExchangeTrade[]>;
193
+ getRecentTrades(symbol: string, limit?: number): Promise<ExchangePublicTrade[]>;
109
194
  getFundingHistory(symbol: string, limit?: number): Promise<{
110
195
  time: number;
111
196
  rate: string;
112
197
  price: string | null;
113
198
  }[]>;
114
199
  getKlines(symbol: string, interval: string, startTime: number, endTime: number): Promise<ExchangeKline[]>;
200
+ /** RFQ venue (no order book): the maker's indicative quotes. Absent = the venue has an order book. */
201
+ getRfqQuotes?(symbol: string): Promise<RfqQuotes>;
202
+ /** Venue without a funding-history API: the current funding terms. Absent = use getFundingHistory. */
203
+ getFundingTerms?(symbol: string): Promise<CurrentFundingTerms>;
115
204
  getBalance(): Promise<ExchangeBalance>;
116
205
  getPositions(): Promise<ExchangePosition[]>;
117
206
  getOpenOrders(): Promise<ExchangeOrder[]>;
@@ -119,7 +208,7 @@ export interface ExchangeAdapter {
119
208
  getTradeHistory(limit?: number): Promise<ExchangeTrade[]>;
120
209
  getFundingPayments(limit?: number): Promise<ExchangeFundingPayment[]>;
121
210
  /**
122
- * Market order = IOC within the resolved slippage bound (design §13.2). `opts` is
211
+ * Market order = IOC within the resolved slippage bound. `opts` is
123
212
  * required so every caller states reduceOnly and passes resolveSlippage() output.
124
213
  */
125
214
  marketOrder(symbol: string, side: "buy" | "sell", size: string, opts: {
@@ -141,7 +230,7 @@ export interface ExchangeAdapter {
141
230
  * `slippage` (resolveSlippage() output) bounds the execution price of a market
142
231
  * trigger on venues that send it as a protection-priced limit once triggered
143
232
  * (Lighter, Arcus: required there for a market trigger — adapters never read
144
- * settings, design §13.10 #1); venue-native market triggers ignore it.
233
+ * settings); venue-native market triggers ignore it.
145
234
  * `kind` ("tp" | "sl") states the protective intent explicitly: venues with distinct
146
235
  * take-profit / stop-loss trigger types (Aster, Lighter) send that type as given — no
147
236
  * price-based classification — and a trigger already crossed is left for the venue to
@@ -10,11 +10,28 @@ export function maxLeverageForNotional(market, notional) {
10
10
  }
11
11
  const tiers = market.marginTiers;
12
12
  if (tiers === null || tiers.length === 0)
13
- return market.maxLeverage;
14
- let effective = market.maxLeverage;
13
+ return market.maxLeverage; // null = not published
14
+ // No headline but published tiers: the first (lowest-notional) tier is the cap below every threshold.
15
+ let effective = market.maxLeverage ?? tiers[0].maxLeverage;
15
16
  for (const t of tiers) {
16
17
  if (notional >= t.lowerBound)
17
18
  effective = t.maxLeverage;
18
19
  }
19
20
  return effective;
20
21
  }
22
+ /**
23
+ * Rows of a public tape the adapter left out because they carry a value the venue documents but
24
+ * does not declare exhaustive (e.g. a new Pacifica event_type) — never guessed into a direction.
25
+ * Attached to the returned array under this symbol key (not serialized); `market trades` reports
26
+ * it as `meta.skippedRows`. Absent = nothing skipped.
27
+ */
28
+ export const TAPE_SKIPPED = Symbol.for("perp-cli.tapeSkipped");
29
+ export function withTapeSkipped(rows, skipped) {
30
+ if (skipped !== null && skipped.count > 0)
31
+ Object.defineProperty(rows, TAPE_SKIPPED, { value: skipped, enumerable: false });
32
+ return rows;
33
+ }
34
+ export function tapeSkippedOf(rows) {
35
+ const v = rows[TAPE_SKIPPED];
36
+ return v === undefined ? null : v;
37
+ }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Venue-final IOC / market order outcome (design `docs/DESIGN-venue-abstraction.md` §13.10 #4).
2
+ * Venue-final IOC / market order outcome.
3
3
  *
4
4
  * An adapter whose market / IOC responses report the order's FINAL filled size (nothing
5
5
  * of the order can still execute) implements `iocOutcomeOf(raw)` on the RAW result its
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Venue-final IOC / market order outcome (design `docs/DESIGN-venue-abstraction.md` §13.10 #4).
2
+ * Venue-final IOC / market order outcome.
3
3
  *
4
4
  * An adapter whose market / IOC responses report the order's FINAL filled size (nothing
5
5
  * of the order can still execute) implements `iocOutcomeOf(raw)` on the RAW result its
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * TradingV2 for the four pre-existing venues (pacifica, hyperliquid, lighter /
3
- * lighter-rh, aster) — design §13.7, §13.10 #8.
3
+ * lighter-rh, aster).
4
4
  *
5
5
  * Composition, not modification: the legacy ExchangeAdapter methods keep returning
6
6
  * their raw venue responses (in-process contract for smart-order, perp-order,
@@ -17,7 +17,7 @@ import { type TradingV2 } from "./trading-v2.js";
17
17
  import { type Network, type OrderResult } from "./venue-types.js";
18
18
  export declare function tradingV2Of(adapter: ExchangeAdapter, network: Network): TradingV2;
19
19
  export declare function toTradingV2(adapter: ExchangeAdapter, network: Network): TradingV2;
20
- /** One reduce-only protective trigger (TP or SL) of a separateOrders venue (design §13.5). */
20
+ /** One reduce-only protective trigger (TP or SL) of a separateOrders venue. */
21
21
  export interface TpSlLeg {
22
22
  symbol: string;
23
23
  /** Side that closes the protected position (sell closes a long). */
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * TradingV2 for the four pre-existing venues (pacifica, hyperliquid, lighter /
3
- * lighter-rh, aster) — design §13.7, §13.10 #8.
3
+ * lighter-rh, aster).
4
4
  *
5
5
  * Composition, not modification: the legacy ExchangeAdapter methods keep returning
6
6
  * their raw venue responses (in-process contract for smart-order, perp-order,
@@ -13,6 +13,7 @@
13
13
  */
14
14
  import { PerpError, orderOutcomeUnknown } from "../errors.js";
15
15
  import { isPacificaStopType, pacificaRefused } from "./pacifica.js";
16
+ import { isPacificaRateLimited } from "../pacifica/rate-limit.js";
16
17
  import { iocLotTolerance, isIocOutcomeCapable } from "./ioc-outcome.js";
17
18
  import { isQueryOrderCapable } from "./capabilities.js";
18
19
  import { floorSize, lotStepOf } from "./precision.js";
@@ -621,7 +622,11 @@ class LegacyTradingV2 {
621
622
  if (this.family !== "pacifica" || !pacificaRefused(e))
622
623
  throw e;
623
624
  raw = { error: e instanceof Error ? e.message : String(e) };
624
- refusal = await this.adapter.cancelRefusalOutcome(ref.value, e);
625
+ // RATE_LIMITED with sent:false (local throttle or HTTP 429): this cancel was not executed —
626
+ // failed (nothing cancelled), no history read needed. Unknown-after-send never lands here.
627
+ refusal = isPacificaRateLimited(e)
628
+ ? { kind: "failed", error: `cancel of ${ref.value} not executed (rate limited, nothing sent / refused): ${e instanceof Error ? e.message : String(e)}` }
629
+ : await this.adapter.cancelRefusalOutcome(ref.value, e);
625
630
  }
626
631
  const out = (v, reason = "") => {
627
632
  if (v === "cancelled")
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Lighter-family public market data (`lighter`, `lighter-rh`) — design §10.6.
2
+ * Lighter-family public market data (`lighter`, `lighter-rh`).
3
3
  *
4
4
  * Sources (REST base from venues/lighter-family.ts, per venue + network):
5
5
  * GET /api/v1/orderBookDetails → perps in `order_book_details` (decimals, min
@@ -11,7 +11,7 @@
11
11
  * venue's own; the RH host labels its own rows "lighter" too (live
12
12
  * 2026-09-30: 57 "lighter" rows = RH's 57 perps, matched by market_id).
13
13
  *
14
- * FUNDING: basis 8h per quoted rate, hourly settlement (design §10.1, Lighter
14
+ * FUNDING: basis 8h per quoted rate, hourly settlement (Lighter
15
15
  * and Lighter RH identical).
16
16
  *
17
17
  * ASSET CLASS: the API has no asset-class field (the undocumented
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Lighter-family public market data (`lighter`, `lighter-rh`) — design §10.6.
2
+ * Lighter-family public market data (`lighter`, `lighter-rh`).
3
3
  *
4
4
  * Sources (REST base from venues/lighter-family.ts, per venue + network):
5
5
  * GET /api/v1/orderBookDetails → perps in `order_book_details` (decimals, min
@@ -11,7 +11,7 @@
11
11
  * venue's own; the RH host labels its own rows "lighter" too (live
12
12
  * 2026-09-30: 57 "lighter" rows = RH's 57 perps, matched by market_id).
13
13
  *
14
- * FUNDING: basis 8h per quoted rate, hourly settlement (design §10.1, Lighter
14
+ * FUNDING: basis 8h per quoted rate, hourly settlement (Lighter
15
15
  * and Lighter RH identical).
16
16
  *
17
17
  * ASSET CLASS: the API has no asset-class field (the undocumented
@@ -22,7 +22,7 @@ export declare const LIGHTER_ALL_MARKETS = 255;
22
22
  /**
23
23
  * One Go runtime of the official signer. The Go `main` registers its functions on
24
24
  * globalThis and then blocks; they are captured synchronously right after `go.run()`
25
- * and the globals restored, so several runtimes (one per venue+network, design §10.5)
25
+ * and the globals restored, so several runtimes (one per venue+network)
26
26
  * never see each other's functions.
27
27
  */
28
28
  export declare class LighterWasmSigner {
@@ -55,7 +55,7 @@ function nonceArg(v) {
55
55
  /**
56
56
  * One Go runtime of the official signer. The Go `main` registers its functions on
57
57
  * globalThis and then blocks; they are captured synchronously right after `go.run()`
58
- * and the globals restored, so several runtimes (one per venue+network, design §10.5)
58
+ * and the globals restored, so several runtimes (one per venue+network)
59
59
  * never see each other's functions.
60
60
  */
61
61
  export class LighterWasmSigner {
@@ -74,7 +74,7 @@ export declare class LighterSpotAdapter implements SpotAdapter {
74
74
  tif?: string;
75
75
  }): Promise<unknown>;
76
76
  /**
77
- * TIF mapping, as perps (§13.3): GTC/GTT → GTT, IOC → IOC, ALO / POST_ONLY → post-only (2).
77
+ * TIF mapping, as perps: GTC/GTT → GTT, IOC → IOC, ALO / POST_ONLY → post-only (2).
78
78
  * FOK and anything else → CAPABILITY_UNSUPPORTED (never silently GTT).
79
79
  */
80
80
  private _limitTif;
@@ -107,7 +107,7 @@ export declare class LighterSpotAdapter implements SpotAdapter {
107
107
  transferUsdcToSpot(amount: number): Promise<unknown>;
108
108
  /** Transfer USDC from spot account back to perp account */
109
109
  transferUsdcToPerp(amount: number): Promise<unknown>;
110
- /** SpotTransferCapable (§12.4 #4): only the venue collateral (USDC on Lighter, USDG on Lighter RH). */
110
+ /** SpotTransferCapable: only the venue collateral (USDC on Lighter, USDG on Lighter RH). */
111
111
  transferToSpot(amount: string, asset: string): Promise<unknown>;
112
112
  transferToPerp(amount: string, asset: string): Promise<unknown>;
113
113
  private _transferAmount;
@@ -139,8 +139,7 @@ export declare class LighterSpotAdapter implements SpotAdapter {
139
139
  private _nextClientOrderIndex;
140
140
  private _getNextNonce;
141
141
  /**
142
- * POST /sendTx. `kind` "place" (order placement): failures are typed (design
143
- * §12.3): before the request → ORDER_REJECTED; transport error, HTTP 5xx or an
142
+ * POST /sendTx. `kind` "place" (order placement): failures are typed: before the request → ORDER_REJECTED; transport error, HTTP 5xx or an
144
143
  * unreadable body after it → ORDER_PENDING (the tx may have been accepted — never
145
144
  * resubmit); an explicit non-200 code → ORDER_REJECTED. "order" (cancels) / "action"
146
145
  * (transfers): an explicit non-200 code → ORDER_REJECTED / ACTION_REJECTED