perp-cli 0.14.3 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (363) hide show
  1. package/README.ja.md +243 -0
  2. package/README.ko.md +243 -0
  3. package/README.md +138 -405
  4. package/README.zh.md +243 -0
  5. package/dist/agent-wallet/store.d.ts +3 -2
  6. package/dist/agent-wallet/store.js +2 -2
  7. package/dist/api/public/hyperliquid.js +4 -0
  8. package/dist/api/public/lighter.d.ts +5 -0
  9. package/dist/api/public/lighter.js +5 -0
  10. package/dist/api/public/pacifica.js +85 -15
  11. package/dist/api/public/urls.d.ts +2 -0
  12. package/dist/api/public/urls.js +3 -0
  13. package/dist/arb/sizing.js +4 -2
  14. package/dist/arb/state.d.ts +6 -0
  15. package/dist/arb/utils.d.ts +1 -2
  16. package/dist/arb/utils.js +1 -2
  17. package/dist/balance-by-address.d.ts +39 -0
  18. package/dist/balance-by-address.js +44 -0
  19. package/dist/bot/apex/pulse.js +3 -0
  20. package/dist/bot/apex/radar.js +2 -1
  21. package/dist/bot/engine.d.ts +10 -1
  22. package/dist/bot/engine.js +14 -6
  23. package/dist/bot/indicators.d.ts +7 -0
  24. package/dist/bot/indicators.js +16 -0
  25. package/dist/bot/perp-order.d.ts +4 -4
  26. package/dist/bot/perp-order.js +5 -5
  27. package/dist/bot/quarantine.d.ts +1 -1
  28. package/dist/bot/quarantine.js +1 -1
  29. package/dist/bot/quote-rules.js +1 -1
  30. package/dist/bot/strategies/apex-strategy.js +3 -2
  31. package/dist/bot/strategies/engine-mm.js +6 -5
  32. package/dist/bot/strategies/funding-arb-strategy.js +12 -5
  33. package/dist/bot/strategies/funding-arb-utils.d.ts +15 -3
  34. package/dist/bot/strategies/funding-arb-utils.js +53 -20
  35. package/dist/bot/strategies/funding-auto.js +2 -2
  36. package/dist/bot/strategies/liquidation-mm.d.ts +1 -0
  37. package/dist/bot/strategies/liquidation-mm.js +8 -2
  38. package/dist/bot/strategies/momentum-breakout.d.ts +1 -0
  39. package/dist/bot/strategies/momentum-breakout.js +11 -3
  40. package/dist/bot/strategies/spot-perp-arb-strategy.d.ts +1 -1
  41. package/dist/bot/strategies/spot-perp-arb-strategy.js +6 -4
  42. package/dist/bot/strategies/spot-perp-executor.d.ts +1 -1
  43. package/dist/bot/strategies/spot-perp-executor.js +3 -3
  44. package/dist/bot/strategy-types.d.ts +2 -1
  45. package/dist/bot/tui/BotDashboard.d.ts +1 -1
  46. package/dist/bot/tui/BotDashboard.js +1 -1
  47. package/dist/cache.js +12 -6
  48. package/dist/cli-program.d.ts +15 -0
  49. package/dist/cli-program.js +126 -6
  50. package/dist/commands/account.js +168 -24
  51. package/dist/commands/agent-import.d.ts +7 -0
  52. package/dist/commands/agent-import.js +30 -1
  53. package/dist/commands/agent.d.ts +6 -3
  54. package/dist/commands/agent.js +160 -12
  55. package/dist/commands/arb/index.js +23 -81
  56. package/dist/commands/arb-auto.d.ts +24 -0
  57. package/dist/commands/arb-auto.js +175 -97
  58. package/dist/commands/arb.d.ts +20 -0
  59. package/dist/commands/arb.js +107 -163
  60. package/dist/commands/backtest.js +23 -21
  61. package/dist/commands/bot.js +1 -1
  62. package/dist/commands/builder.js +1 -1
  63. package/dist/commands/funds.js +113 -3
  64. package/dist/commands/init.d.ts +1 -1
  65. package/dist/commands/init.js +27 -7
  66. package/dist/commands/manage.js +23 -21
  67. package/dist/commands/market.d.ts +48 -0
  68. package/dist/commands/market.js +395 -100
  69. package/dist/commands/options.d.ts +14 -0
  70. package/dist/commands/options.js +151 -0
  71. package/dist/commands/pacifica-earn.d.ts +5 -0
  72. package/dist/commands/pacifica-earn.js +455 -0
  73. package/dist/commands/pacifica-orders.d.ts +14 -0
  74. package/dist/commands/pacifica-orders.js +142 -0
  75. package/dist/commands/portfolio.d.ts +16 -0
  76. package/dist/commands/portfolio.js +83 -55
  77. package/dist/commands/rebalance.d.ts +1 -0
  78. package/dist/commands/rebalance.js +15 -0
  79. package/dist/commands/risk.d.ts +11 -2
  80. package/dist/commands/risk.js +39 -44
  81. package/dist/commands/trade.d.ts +1 -0
  82. package/dist/commands/trade.js +67 -62
  83. package/dist/commands/wallet.js +1 -1
  84. package/dist/config.d.ts +2 -2
  85. package/dist/config.js +15 -4
  86. package/dist/constants.js +6 -0
  87. package/dist/cross-chain-margin.d.ts +3 -1
  88. package/dist/cross-chain-margin.js +4 -2
  89. package/dist/dashboard/server.js +3 -3
  90. package/dist/dashboard/ui.js +9 -6
  91. package/dist/errors.d.ts +29 -1
  92. package/dist/errors.js +35 -3
  93. package/dist/exchanges/address.d.ts +8 -0
  94. package/dist/exchanges/address.js +47 -0
  95. package/dist/exchanges/arcus/adapter.d.ts +16 -12
  96. package/dist/exchanges/arcus/adapter.js +45 -18
  97. package/dist/exchanges/arcus/agent.d.ts +1 -1
  98. package/dist/exchanges/arcus/agent.js +1 -1
  99. package/dist/exchanges/arcus/client.js +1 -1
  100. package/dist/exchanges/arcus/public.js +3 -2
  101. package/dist/exchanges/arcus/signing.d.ts +2 -3
  102. package/dist/exchanges/arcus/signing.js +1 -1
  103. package/dist/exchanges/arcus/spot-chain.d.ts +1 -1
  104. package/dist/exchanges/arcus/spot-chain.js +1 -1
  105. package/dist/exchanges/arcus/spot-router.d.ts +1 -1
  106. package/dist/exchanges/arcus/spot-router.js +2 -2
  107. package/dist/exchanges/arcus/spot.d.ts +2 -3
  108. package/dist/exchanges/arcus/spot.js +2 -3
  109. package/dist/exchanges/aster-spot.d.ts +3 -3
  110. package/dist/exchanges/aster-spot.js +6 -9
  111. package/dist/exchanges/aster-typed-data.d.ts +1 -1
  112. package/dist/exchanges/aster-typed-data.js +1 -1
  113. package/dist/exchanges/aster.d.ts +30 -10
  114. package/dist/exchanges/aster.js +153 -53
  115. package/dist/exchanges/builder-fee.d.ts +1 -1
  116. package/dist/exchanges/builder-fee.js +13 -2
  117. package/dist/exchanges/canonical-symbols.d.ts +8 -2
  118. package/dist/exchanges/canonical-symbols.js +46 -2
  119. package/dist/exchanges/capabilities.d.ts +2 -0
  120. package/dist/exchanges/capabilities.js +2 -1
  121. package/dist/exchanges/derive/client.d.ts +37 -0
  122. package/dist/exchanges/derive/client.js +135 -0
  123. package/dist/exchanges/derive/options.d.ts +73 -0
  124. package/dist/exchanges/derive/options.js +379 -0
  125. package/dist/exchanges/extended/adapter.d.ts +96 -0
  126. package/dist/exchanges/extended/adapter.js +241 -0
  127. package/dist/exchanges/extended/client.d.ts +38 -0
  128. package/dist/exchanges/extended/client.js +88 -0
  129. package/dist/exchanges/extended/public.d.ts +133 -0
  130. package/dist/exchanges/extended/public.js +436 -0
  131. package/dist/exchanges/grvt/adapter.d.ts +100 -0
  132. package/dist/exchanges/grvt/adapter.js +283 -0
  133. package/dist/exchanges/grvt/client.d.ts +25 -0
  134. package/dist/exchanges/grvt/client.js +86 -0
  135. package/dist/exchanges/grvt/public.d.ts +151 -0
  136. package/dist/exchanges/grvt/public.js +438 -0
  137. package/dist/exchanges/hyperliquid-outcome.d.ts +2 -0
  138. package/dist/exchanges/hyperliquid-outcome.js +29 -1
  139. package/dist/exchanges/hyperliquid-spot.d.ts +9 -1
  140. package/dist/exchanges/hyperliquid-spot.js +24 -16
  141. package/dist/exchanges/hyperliquid.d.ts +199 -22
  142. package/dist/exchanges/hyperliquid.js +550 -202
  143. package/dist/exchanges/index.d.ts +1 -1
  144. package/dist/exchanges/index.js +1 -1
  145. package/dist/exchanges/interface.d.ts +157 -13
  146. package/dist/exchanges/interface.js +47 -0
  147. package/dist/exchanges/ioc-outcome.d.ts +1 -1
  148. package/dist/exchanges/ioc-outcome.js +1 -1
  149. package/dist/exchanges/legacy-trading-v2.d.ts +2 -2
  150. package/dist/exchanges/legacy-trading-v2.js +7 -2
  151. package/dist/exchanges/lighter-public.d.ts +67 -12
  152. package/dist/exchanges/lighter-public.js +250 -82
  153. package/dist/exchanges/lighter-signer.d.ts +1 -1
  154. package/dist/exchanges/lighter-signer.js +1 -1
  155. package/dist/exchanges/lighter-spot.d.ts +10 -5
  156. package/dist/exchanges/lighter-spot.js +105 -97
  157. package/dist/exchanges/lighter.d.ts +80 -21
  158. package/dist/exchanges/lighter.js +312 -105
  159. package/dist/exchanges/ondo/adapter.d.ts +38 -13
  160. package/dist/exchanges/ondo/adapter.js +86 -27
  161. package/dist/exchanges/ondo/agent.d.ts +1 -1
  162. package/dist/exchanges/ondo/agent.js +1 -1
  163. package/dist/exchanges/ondo/client.d.ts +1 -1
  164. package/dist/exchanges/ondo/client.js +2 -2
  165. package/dist/exchanges/ondo/public.d.ts +35 -3
  166. package/dist/exchanges/ondo/public.js +75 -32
  167. package/dist/exchanges/ondo/spot.d.ts +2 -2
  168. package/dist/exchanges/ondo/spot.js +3 -3
  169. package/dist/exchanges/options-interface.d.ts +158 -0
  170. package/dist/exchanges/options-interface.js +17 -0
  171. package/dist/exchanges/options-venues.d.ts +12 -0
  172. package/dist/exchanges/options-venues.js +35 -0
  173. package/dist/exchanges/outcome-interface.d.ts +4 -0
  174. package/dist/exchanges/pacifica-atomic.d.ts +211 -0
  175. package/dist/exchanges/pacifica-atomic.js +440 -0
  176. package/dist/exchanges/pacifica-decimal.d.ts +10 -0
  177. package/dist/exchanges/pacifica-decimal.js +51 -0
  178. package/dist/exchanges/pacifica-presigned.d.ts +53 -0
  179. package/dist/exchanges/pacifica-presigned.js +141 -0
  180. package/dist/exchanges/pacifica-print.d.ts +200 -0
  181. package/dist/exchanges/pacifica-print.js +417 -0
  182. package/dist/exchanges/pacifica-spot.d.ts +8 -2
  183. package/dist/exchanges/pacifica-spot.js +26 -18
  184. package/dist/exchanges/pacifica-typed-data.d.ts +1 -1
  185. package/dist/exchanges/pacifica-typed-data.js +1 -1
  186. package/dist/exchanges/pacifica-vaults.d.ts +130 -0
  187. package/dist/exchanges/pacifica-vaults.js +277 -0
  188. package/dist/exchanges/pacifica.d.ts +108 -10
  189. package/dist/exchanges/pacifica.js +428 -171
  190. package/dist/exchanges/precision.d.ts +3 -1
  191. package/dist/exchanges/precision.js +9 -2
  192. package/dist/exchanges/public-balances.d.ts +25 -0
  193. package/dist/exchanges/public-balances.js +158 -0
  194. package/dist/exchanges/public-positions.d.ts +43 -0
  195. package/dist/exchanges/public-positions.js +154 -0
  196. package/dist/exchanges/qfex/adapter.d.ts +69 -13
  197. package/dist/exchanges/qfex/adapter.js +102 -17
  198. package/dist/exchanges/qfex/agent.d.ts +1 -1
  199. package/dist/exchanges/qfex/agent.js +1 -1
  200. package/dist/exchanges/qfex/client.d.ts +1 -1
  201. package/dist/exchanges/qfex/client.js +1 -1
  202. package/dist/exchanges/qfex/errors.d.ts +1 -1
  203. package/dist/exchanges/qfex/errors.js +2 -2
  204. package/dist/exchanges/qfex/public.d.ts +65 -12
  205. package/dist/exchanges/qfex/public.js +131 -25
  206. package/dist/exchanges/qfex/signing.d.ts +2 -2
  207. package/dist/exchanges/qfex/signing.js +4 -5
  208. package/dist/exchanges/qfex/ws-transport.d.ts +3 -3
  209. package/dist/exchanges/qfex/ws-transport.js +3 -3
  210. package/dist/exchanges/rate-limiter.d.ts +1 -1
  211. package/dist/exchanges/rate-limiter.js +5 -2
  212. package/dist/exchanges/registry.d.ts +1 -1
  213. package/dist/exchanges/registry.js +1 -1
  214. package/dist/exchanges/risex/adapter.d.ts +160 -0
  215. package/dist/exchanges/risex/adapter.js +842 -0
  216. package/dist/exchanges/risex/agent.d.ts +154 -0
  217. package/dist/exchanges/risex/agent.js +384 -0
  218. package/dist/exchanges/risex/client.d.ts +47 -0
  219. package/dist/exchanges/risex/client.js +174 -0
  220. package/dist/exchanges/risex/nonce.d.ts +43 -0
  221. package/dist/exchanges/risex/nonce.js +212 -0
  222. package/dist/exchanges/risex/public.d.ts +64 -0
  223. package/dist/exchanges/risex/public.js +150 -0
  224. package/dist/exchanges/risex/session.d.ts +71 -0
  225. package/dist/exchanges/risex/session.js +171 -0
  226. package/dist/exchanges/risex/typed-data.d.ts +173 -0
  227. package/dist/exchanges/risex/typed-data.js +240 -0
  228. package/dist/exchanges/risex/units.d.ts +29 -0
  229. package/dist/exchanges/risex/units.js +104 -0
  230. package/dist/exchanges/slippage.d.ts +1 -1
  231. package/dist/exchanges/slippage.js +1 -1
  232. package/dist/exchanges/spot-factory.d.ts +3 -3
  233. package/dist/exchanges/spot-factory.js +8 -8
  234. package/dist/exchanges/spot-interface.d.ts +5 -5
  235. package/dist/exchanges/spot-interface.js +2 -2
  236. package/dist/exchanges/spot-result.d.ts +3 -3
  237. package/dist/exchanges/spot-result.js +3 -3
  238. package/dist/exchanges/trading-v2.d.ts +3 -3
  239. package/dist/exchanges/trading-v2.js +9 -6
  240. package/dist/exchanges/txflow/adapter.d.ts +61 -0
  241. package/dist/exchanges/txflow/adapter.js +150 -0
  242. package/dist/exchanges/txflow/client.d.ts +47 -0
  243. package/dist/exchanges/txflow/client.js +155 -0
  244. package/dist/exchanges/txflow/public.d.ts +87 -0
  245. package/dist/exchanges/txflow/public.js +355 -0
  246. package/dist/exchanges/unknown-symbol.d.ts +34 -0
  247. package/dist/exchanges/unknown-symbol.js +56 -0
  248. package/dist/exchanges/variational/adapter.d.ts +67 -0
  249. package/dist/exchanges/variational/adapter.js +137 -0
  250. package/dist/exchanges/variational/client.d.ts +21 -0
  251. package/dist/exchanges/variational/client.js +66 -0
  252. package/dist/exchanges/variational/public.d.ts +126 -0
  253. package/dist/exchanges/variational/public.js +430 -0
  254. package/dist/exchanges/venue-types.d.ts +52 -10
  255. package/dist/exchanges/venue-types.js +82 -11
  256. package/dist/exchanges/venue.d.ts +150 -11
  257. package/dist/exchanges/venue.js +126 -4
  258. package/dist/exchanges/venues/arcus.d.ts +1 -2
  259. package/dist/exchanges/venues/arcus.js +5 -4
  260. package/dist/exchanges/venues/aster.d.ts +2 -2
  261. package/dist/exchanges/venues/aster.js +6 -4
  262. package/dist/exchanges/venues/create-helpers.d.ts +1 -1
  263. package/dist/exchanges/venues/create-helpers.js +3 -3
  264. package/dist/exchanges/venues/extended.d.ts +21 -0
  265. package/dist/exchanges/venues/extended.js +96 -0
  266. package/dist/exchanges/venues/grvt.d.ts +30 -0
  267. package/dist/exchanges/venues/grvt.js +98 -0
  268. package/dist/exchanges/venues/hyperliquid.d.ts +2 -2
  269. package/dist/exchanges/venues/hyperliquid.js +19 -8
  270. package/dist/exchanges/venues/index.d.ts +7 -2
  271. package/dist/exchanges/venues/index.js +8 -2
  272. package/dist/exchanges/venues/lighter-family.d.ts +7 -9
  273. package/dist/exchanges/venues/lighter-family.js +9 -11
  274. package/dist/exchanges/venues/lighter-rh.d.ts +2 -2
  275. package/dist/exchanges/venues/lighter-rh.js +20 -8
  276. package/dist/exchanges/venues/lighter.d.ts +1 -1
  277. package/dist/exchanges/venues/lighter.js +18 -6
  278. package/dist/exchanges/venues/ondo.d.ts +1 -1
  279. package/dist/exchanges/venues/ondo.js +5 -3
  280. package/dist/exchanges/venues/pacifica.d.ts +2 -2
  281. package/dist/exchanges/venues/pacifica.js +15 -4
  282. package/dist/exchanges/venues/qfex.d.ts +1 -1
  283. package/dist/exchanges/venues/qfex.js +4 -2
  284. package/dist/exchanges/venues/risex-release.d.ts +14 -0
  285. package/dist/exchanges/venues/risex-release.js +14 -0
  286. package/dist/exchanges/venues/risex.d.ts +31 -0
  287. package/dist/exchanges/venues/risex.js +131 -0
  288. package/dist/exchanges/venues/txflow.d.ts +18 -0
  289. package/dist/exchanges/venues/txflow.js +77 -0
  290. package/dist/exchanges/venues/variational.d.ts +21 -0
  291. package/dist/exchanges/venues/variational.js +85 -0
  292. package/dist/execution-log.d.ts +1 -1
  293. package/dist/funding/legacy-public.d.ts +6 -4
  294. package/dist/funding/legacy-public.js +42 -41
  295. package/dist/funding/normalize.d.ts +1 -1
  296. package/dist/funding/normalize.js +1 -1
  297. package/dist/funding/rates.d.ts +95 -6
  298. package/dist/funding/rates.js +99 -19
  299. package/dist/index.js +7 -6
  300. package/dist/jobs.d.ts +1 -0
  301. package/dist/jobs.js +25 -1
  302. package/dist/landing.d.ts +2 -0
  303. package/dist/landing.js +1 -1
  304. package/dist/liquidity.d.ts +3 -1
  305. package/dist/liquidity.js +8 -4
  306. package/dist/mcp-pacifica-earn.d.ts +9 -0
  307. package/dist/mcp-pacifica-earn.js +64 -0
  308. package/dist/mcp-server.js +211 -68
  309. package/dist/pacifica/client.d.ts +69 -5
  310. package/dist/pacifica/client.js +181 -8
  311. package/dist/pacifica/rate-limit.d.ts +144 -0
  312. package/dist/pacifica/rate-limit.js +267 -0
  313. package/dist/pacifica/types/order.d.ts +2 -1
  314. package/dist/plan-executor.js +7 -2
  315. package/dist/positions-by-address.d.ts +34 -0
  316. package/dist/positions-by-address.js +46 -0
  317. package/dist/rebalance.js +1 -1
  318. package/dist/risk.d.ts +2 -1
  319. package/dist/risk.js +2 -4
  320. package/dist/settings.d.ts +32 -3
  321. package/dist/signer/ows-evm.d.ts +1 -1
  322. package/dist/signer/ows-evm.js +1 -1
  323. package/dist/smart-order.d.ts +1 -1
  324. package/dist/smart-order.js +1 -1
  325. package/dist/strategies/funding-arb.d.ts +1 -1
  326. package/dist/strategies/funding-arb.js +36 -63
  327. package/dist/trade-validator.js +2 -2
  328. package/dist/utils.d.ts +22 -3
  329. package/dist/utils.js +11 -3
  330. package/dist/venue-health.d.ts +40 -0
  331. package/dist/venue-health.js +75 -0
  332. package/dist/withdraw-gate.d.ts +1 -1
  333. package/dist/withdraw-gate.js +1 -1
  334. package/dist/ws/arcus-market.d.ts +9 -0
  335. package/dist/ws/arcus-market.js +9 -0
  336. package/dist/ws/aster-market.d.ts +33 -0
  337. package/dist/ws/aster-market.js +30 -0
  338. package/dist/ws/index.d.ts +980 -0
  339. package/dist/ws/index.js +4460 -0
  340. package/dist/ws/lighter-market.d.ts +14 -0
  341. package/dist/ws/lighter-market.js +13 -0
  342. package/dist/ws/node.d.ts +996 -0
  343. package/dist/ws/node.js +4554 -0
  344. package/dist/ws/pacifica-instrument.d.ts +8 -0
  345. package/dist/ws/pacifica-instrument.js +8 -0
  346. package/dist/ws/unclassified.d.ts +16 -0
  347. package/dist/ws/unclassified.js +43 -0
  348. package/dist/ws-cli/credentials.d.ts +62 -0
  349. package/dist/ws-cli/credentials.js +126 -0
  350. package/package.json +71 -10
  351. package/skills/perp-cli/SKILL.md +153 -36
  352. package/skills/perp-cli/package.json +15 -2
  353. package/skills/perp-cli/references/agent-operations.md +22 -12
  354. package/skills/perp-cli/references/commands.md +143 -17
  355. package/skills/perp-cli/references/strategies.md +38 -3
  356. package/skills/perp-cli/references/ws-library.md +523 -0
  357. package/skills/perp-cli/scripts/arb-monitor.sh +13 -10
  358. package/skills/perp-cli/scripts/funding-analysis.sh +57 -29
  359. package/skills/perp-cli/scripts/preflight.sh +27 -19
  360. package/skills/perp-cli/scripts/spot-perp-scan.sh +58 -38
  361. package/skills/perp-cli/scripts/validate-arb.sh +56 -39
  362. package/dist/cli-spec.d.ts +0 -46
  363. package/dist/cli-spec.js +0 -81
@@ -0,0 +1,267 @@
1
+ /**
2
+ * Pacifica credit rate limit, read from the venue's own response headers.
3
+ *
4
+ * docs.pacifica.fi api-documentation/api/rate-limits (read 2026-10-19): credit-based, rolling
5
+ * 60 s window; 100 credits / 60 s per unidentified IP, 300 with a valid API Config Key (more for
6
+ * higher fee tiers); standard request 1, cancel 0.5, heavy GET 3-12 (1-4 with a key). Exhausted →
7
+ * HTTP 429. "All credit values are multiplied by 10 to support fractional costs":
8
+ *
9
+ * ratelimit: "credits";r=1200;t=32 r = remaining (×10), t = seconds until refresh
10
+ * ratelimit-policy: "credits";q=1250;w=60 q = quota per window (×10), w = window seconds
11
+ *
12
+ * Live mainnet GET /info/prices (2026-10-19, no key): `ratelimit: "credits";r=980;t=22`,
13
+ * `ratelimit-policy: "credits";q=1000;w=60`. Values below stay in those ×10 units.
14
+ *
15
+ * CloudFront caches some GETs (/info: `x-cache: Hit from cloudfront`, `age: 16`): a cache hit
16
+ * replays the headers of whoever filled the cache (live: q=3000, a keyed caller) — not this
17
+ * caller's quota, so a hit carries no information.
18
+ *
19
+ * Scope: one state per REST base URL (mainnet / testnet), credential tier (no key = IP quota;
20
+ * an API Config Key has its own) and request kind (signed POST vs unsigned GET). Process-local: other perp-cli processes (CLI + MCP + bots) on the
21
+ * same IP spend the same quota unseen, so a 429 can still happen — it is then surfaced as
22
+ * RATE_LIMITED, never retried here.
23
+ */
24
+ import { createHash } from "crypto";
25
+ import { PerpError } from "../errors.js";
26
+ /** `"credits";k=v;k=v` with non-negative integer values; null on any deviation. */
27
+ function parseCreditsItem(raw) {
28
+ if (raw === null)
29
+ return null;
30
+ const parts = raw.trim().split(";").map((p) => p.trim());
31
+ if (parts[0] !== '"credits"')
32
+ return null;
33
+ const out = new Map();
34
+ for (const p of parts.slice(1)) {
35
+ const m = /^([a-z][a-z0-9_-]*)=(\d{1,12})$/.exec(p);
36
+ if (m === null || out.has(m[1]))
37
+ return null;
38
+ out.set(m[1], Number(m[2]));
39
+ }
40
+ return out;
41
+ }
42
+ /**
43
+ * Strict parse of the `ratelimit` / `ratelimit-policy` header values. `ratelimit` absent or
44
+ * malformed (no `"credits"` item, missing / non-integer / duplicate r or t) → null: no info, never
45
+ * a guessed value. A malformed policy only nulls quota / windowSec.
46
+ */
47
+ export function parsePacificaRateLimit(ratelimit, policy) {
48
+ const rl = parseCreditsItem(ratelimit);
49
+ const r = rl?.get("r");
50
+ const t = rl?.get("t");
51
+ if (r === undefined || t === undefined)
52
+ return null;
53
+ const pol = parseCreditsItem(policy);
54
+ const q = pol?.get("q");
55
+ const w = pol?.get("w");
56
+ const policyOk = q !== undefined && w !== undefined && w > 0;
57
+ return { remaining: r, resetSec: t, quota: policyOk ? q : null, windowSec: policyOk ? w : null };
58
+ }
59
+ /** `Retry-After` in delta-seconds → ms; absent / HTTP-date / malformed → null. */
60
+ export function parseRetryAfterMs(raw) {
61
+ if (raw === null || !/^\d{1,9}$/.test(raw.trim()))
62
+ return null;
63
+ return Number(raw.trim()) * 1000;
64
+ }
65
+ function header(res, name) {
66
+ // Every real fetch Response has headers; a value without them carries no rate-limit info.
67
+ const h = res?.headers;
68
+ return h !== undefined && typeof h.get === "function" ? h.get(name) : null;
69
+ }
70
+ /** A CloudFront cache hit replays someone else's headers (see module doc). */
71
+ function isCacheHit(res) {
72
+ const xc = header(res, "x-cache");
73
+ return (xc !== null && /^(Hit|RefreshHit)\b/i.test(xc.trim())) || header(res, "age") !== null;
74
+ }
75
+ /** Parsed rate-limit info of a response this caller's request produced; null = no info. */
76
+ export function pacificaRateLimitOf(res) {
77
+ if (isCacheHit(res))
78
+ return null;
79
+ return parsePacificaRateLimit(header(res, "ratelimit"), header(res, "ratelimit-policy"));
80
+ }
81
+ /** Read reserve (credits ×10): the largest documented heavy-GET cost (12 credits) stays unspent after a read. */
82
+ export const PACIFICA_READ_RESERVE = 120;
83
+ /** Cost (credits ×10) of a standard request / action (docs: 1 credit). */
84
+ export const PACIFICA_COST_STANDARD = 10;
85
+ /** Cost (credits ×10) of an order cancellation (docs: 0.5 credits). */
86
+ export const PACIFICA_COST_CANCEL = 5;
87
+ /** Slack after the venue's `t` (whole seconds) before the window is treated as refreshed. */
88
+ const RESET_MARGIN_MS = 250;
89
+ /** Documented window (docs: "60-second rolling window") — only an upper clamp for `t` / Retry-After. */
90
+ const DOC_WINDOW_SEC = 60;
91
+ /** A reset / Retry-After longer than the window + this is clamped (a bogus value must not stall). */
92
+ const RESET_CLAMP_MARGIN_MS = 1_000;
93
+ /** Longest pre-send wait before failing fast with RATE_LIMITED. */
94
+ export const PACIFICA_MAX_THROTTLE_WAIT_MS = 15_000;
95
+ /** Longest wait between signing and sending (signed bodies expire after expiry_window = 5 s). */
96
+ export const PACIFICA_SIGNED_MAX_WAIT_MS = 2_000;
97
+ /** Monotonic: elapsed time never follows a wall-clock step (NTP, VM resume). */
98
+ const realClock = {
99
+ now: () => performance.now(),
100
+ sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
101
+ };
102
+ export const PACIFICA_READ_NEED = { cost: PACIFICA_COST_STANDARD, reserve: PACIFICA_READ_RESERVE, maxWaitMs: PACIFICA_MAX_THROTTLE_WAIT_MS };
103
+ function clampResetMs(ms, windowSec) {
104
+ const cap = (windowSec !== null ? windowSec : DOC_WINDOW_SEC) * 1000 + RESET_CLAMP_MARGIN_MS;
105
+ return Math.min(ms, cap);
106
+ }
107
+ export class PacificaRateLimiter {
108
+ label;
109
+ clock;
110
+ obs = null;
111
+ /** Credits ×10 reserved by requests sent and not yet settled — not reset by observe(). */
112
+ inFlight = 0;
113
+ lastRaw = Number.NEGATIVE_INFINITY;
114
+ skew = 0;
115
+ constructor(label, clock = realClock) {
116
+ this.label = label;
117
+ this.clock = clock;
118
+ }
119
+ /** clock.now() made monotonic: a backwards step is absorbed instead of restarting elapsed time. */
120
+ now() {
121
+ const raw = this.clock.now();
122
+ if (raw < this.lastRaw)
123
+ this.skew += this.lastRaw - raw;
124
+ this.lastRaw = raw;
125
+ return raw + this.skew;
126
+ }
127
+ /** ms until the observed window refreshes; null = no live observation. */
128
+ resetWaitMs() {
129
+ if (this.obs === null)
130
+ return null;
131
+ const left = this.obs.resetInMs + RESET_MARGIN_MS - (this.now() - this.obs.observedAt);
132
+ if (left <= 0) {
133
+ this.obs = null;
134
+ return null;
135
+ } // window refreshed: the observation is spent
136
+ return left;
137
+ }
138
+ /** Current state for diagnostics (credits ×10); null = no live observation. */
139
+ snapshot() {
140
+ const wait = this.resetWaitMs();
141
+ if (wait === null || this.obs === null)
142
+ return null;
143
+ return { remaining: this.obs.remaining, inFlight: this.inFlight, effectiveRemaining: this.obs.remaining - this.inFlight, resetInMs: wait };
144
+ }
145
+ /** ms to wait before a request with `need` may be sent: 0 = now (no info, or enough credits left). */
146
+ waitMs(need) {
147
+ const wait = this.resetWaitMs();
148
+ if (wait === null || this.obs === null)
149
+ return 0;
150
+ return this.obs.remaining - this.inFlight - need.cost >= need.reserve ? 0 : wait;
151
+ }
152
+ ticket(cost) {
153
+ this.inFlight += cost;
154
+ let open = true;
155
+ const release = () => { if (open) {
156
+ open = false;
157
+ this.inFlight -= cost;
158
+ } };
159
+ return {
160
+ release,
161
+ settle: (res) => { release(); return this.observe(res); },
162
+ };
163
+ }
164
+ /**
165
+ * Pre-send throttle + reservation. Enough credits (or no info) → the cost is reserved
166
+ * synchronously, before any await, so concurrent callers see each other. Otherwise waits for the
167
+ * window to refresh (total ≤ need.maxWaitMs) or fails fast with RATE_LIMITED (sent: false).
168
+ */
169
+ async acquire(what, need) {
170
+ let budget = need.maxWaitMs;
171
+ for (;;) {
172
+ const wait = this.waitMs(need);
173
+ if (wait === 0)
174
+ return this.ticket(need.cost);
175
+ if (wait > budget)
176
+ throw this.throttled(what, wait);
177
+ const waitedOn = this.obs;
178
+ const start = this.now();
179
+ await this.clock.sleep(wait);
180
+ budget -= this.now() - start;
181
+ // The window that observation described has refreshed; a newer one (a response that landed
182
+ // meanwhile) is kept and re-checked.
183
+ if (this.obs === waitedOn)
184
+ this.obs = null;
185
+ }
186
+ }
187
+ /** Like acquire but never waits or refuses (health probe): reserves and records only. */
188
+ track(cost) {
189
+ return this.ticket(cost);
190
+ }
191
+ /** Wait (no reservation) until `need` would pass — used before signing, so the post-sign acquire finds credits. */
192
+ async awaitCapacity(what, need) {
193
+ (await this.acquire(what, need)).release();
194
+ }
195
+ throttled(what, wait) {
196
+ return new PerpError("RATE_LIMITED", `Pacifica ${what} not sent: rate-limit credits nearly exhausted (${this.label}), window refreshes in ${Math.ceil(wait / 1000)} s`, {
197
+ exchange: "pacifica", sent: false, retryAfterMs: Math.ceil(wait),
198
+ remediation: `Nothing was sent. Retry after ${Math.ceil(wait / 1000)} s; other perp-cli processes on this IP share the same Pacifica quota — reduce request frequency or use an API Config Key (300 credits / 60 s)`,
199
+ });
200
+ }
201
+ /**
202
+ * Record a response's headers (any status). No / malformed / cached headers → unchanged. Within
203
+ * the live window an observation with a higher `r` (a late response from before others landed)
204
+ * or a different `q` (another quota: account vs IP) is dropped.
205
+ */
206
+ observe(res) {
207
+ const info = pacificaRateLimitOf(res);
208
+ if (info === null)
209
+ return null;
210
+ const live = this.resetWaitMs() !== null && this.obs !== null ? this.obs : null;
211
+ if (live !== null) {
212
+ if (info.remaining > live.remaining)
213
+ return null;
214
+ if (live.quota !== null && info.quota !== null && info.quota !== live.quota)
215
+ return null;
216
+ }
217
+ this.obs = { remaining: info.remaining, resetInMs: clampResetMs(info.resetSec * 1000, info.windowSec), observedAt: this.now(), quota: info.quota };
218
+ return info;
219
+ }
220
+ /**
221
+ * HTTP 429 → RATE_LIMITED (structural, by status). retryAfterMs = `Retry-After`, else the
222
+ * ratelimit reset `t`, else absent (clamped to the window). The quota is recorded as exhausted.
223
+ *
224
+ * `sent: false` ("not executed") is OUR reading of the docs — "When credits are exhausted,
225
+ * requests return HTTP 429" — i.e. the request is refused before processing. Pacifica does not
226
+ * state explicitly that a 429'd write was not executed.
227
+ */
228
+ rateLimitedError(what, res, body) {
229
+ const info = pacificaRateLimitOf(res);
230
+ const fromHeader = parseRetryAfterMs(header(res, "retry-after"));
231
+ const raw = fromHeader !== null ? fromHeader : info !== null ? info.resetSec * 1000 : null;
232
+ const retryAfterMs = raw !== null ? clampResetMs(raw, info !== null ? info.windowSec : null) : null;
233
+ if (retryAfterMs !== null)
234
+ this.obs = { remaining: 0, resetInMs: retryAfterMs, observedAt: this.now(), quota: info !== null ? info.quota : null };
235
+ return new PerpError("RATE_LIMITED", `Pacifica ${what} rate limited (HTTP 429); nothing was executed: ${body.slice(0, 200)}`, {
236
+ exchange: "pacifica", httpStatus: 429, sent: false,
237
+ ...(retryAfterMs !== null ? { retryAfterMs } : {}),
238
+ remediation: `${retryAfterMs !== null ? `Retry after ${Math.ceil(retryAfterMs / 1000)} s` : "Wait for the 60 s window to refresh, then retry"}; other perp-cli processes on this IP share the same Pacifica quota — reduce request frequency or use an API Config Key (300 credits / 60 s)`,
239
+ });
240
+ }
241
+ }
242
+ /** A Pacifica RATE_LIMITED that sent nothing (pre-send throttle or HTTP 429): a definite refusal. */
243
+ export function isPacificaRateLimited(e) {
244
+ return e instanceof PerpError && e.structured.code === "RATE_LIMITED"
245
+ && e.structured.details?.exchange === "pacifica" && e.structured.details?.sent === false;
246
+ }
247
+ const limiters = new Map();
248
+ /**
249
+ * The process-local limiter for a REST base URL + credential tier (no key = IP quota) + request
250
+ * kind. Signed POSTs are kept apart from unsigned GETs: credits are shared per main account and
251
+ * scale with its fee tier, so signed responses can report an account quota (e.g. q=3000) while
252
+ * keyless GETs report the IP quota (q=1000).
253
+ */
254
+ export function pacificaRateLimiter(baseUrl, apiKey, kind) {
255
+ const tier = apiKey ? `key:${createHash("sha256").update(apiKey).digest("hex").slice(0, 12)}` : "ip";
256
+ const key = `${baseUrl}|${tier}|${kind}`;
257
+ let l = limiters.get(key);
258
+ if (l === undefined) {
259
+ l = new PacificaRateLimiter(`${baseUrl} ${apiKey ? "API Config Key" : "IP"} ${kind} quota`);
260
+ limiters.set(key, l);
261
+ }
262
+ return l;
263
+ }
264
+ /** Test hook: forget every limiter's state. */
265
+ export function resetPacificaRateLimiters() {
266
+ limiters.clear();
267
+ }
@@ -71,7 +71,8 @@ export interface TPSLParams {
71
71
  stop_price: string;
72
72
  };
73
73
  }
74
- export type BatchActionType = "Create" | "Cancel";
74
+ /** docs rest-api/orders/batch-order `type` (case sensitive; not the signing operation type). */
75
+ export type BatchActionType = "Create" | "CreateMarket" | "Cancel" | "Edit" | "SetPositionTpsl" | "CancelStopOrder";
75
76
  export interface BatchAction {
76
77
  type: BatchActionType;
77
78
  data: Record<string, unknown>;
@@ -1,4 +1,5 @@
1
1
  import { assertCanClosePositions } from "./exchanges/trading-v2.js";
2
+ import { getVenue, requireRole, tryResolveVenueId } from "./exchanges/venue.js";
2
3
  import { symbolMatch } from "./utils.js";
3
4
  import { logExecution } from "./execution-log.js";
4
5
  import { randomUUID } from "crypto";
@@ -83,6 +84,10 @@ export async function executePlan(adapter, plan, opts) {
83
84
  const completedSteps = new Map();
84
85
  const dryRun = opts?.dryRun ?? false;
85
86
  const log = opts?.log ?? (() => { });
87
+ // A venue without the trading role (TxFlow, release-gated RISEx) runs no plan — dry-run included.
88
+ const venueId = tryResolveVenueId(adapter.name);
89
+ if (venueId !== null)
90
+ requireRole(getVenue(venueId), "trading", "plan");
86
91
  // A plan that places orders must be able to close them (rollback / close_position are
87
92
  // reduce-only): refuse before the first step on a venue that cannot.
88
93
  if (!dryRun && plan.steps.some(s => PLAN_ORDER_ACTIONS.has(s.action))) {
@@ -155,7 +160,7 @@ export async function executePlan(adapter, plan, opts) {
155
160
  const onFailure = step.onFailure ?? "abort";
156
161
  if (ORDER_ACTIONS.has(step.action) && isOutcomeUnknown(err)) {
157
162
  // The order may have been placed: never treat it as failed, never resubmit or roll it
158
- // back. Stop the plan and quarantine the symbol (design §12.3).
163
+ // back. Stop the plan and quarantine the symbol.
159
164
  const sym = String(step.params.symbol ?? "").toUpperCase();
160
165
  log(`[plan:${planId}] Step ${step.id} (${step.action}): OUTCOME UNKNOWN — ${message}`);
161
166
  quarantine(sym, `step ${step.id} (${step.action}) outcome unknown: ${message}`);
@@ -300,7 +305,7 @@ async function executeStep(adapter, step, log, placed) {
300
305
  const closeSide = pos.side === "long" ? "sell" : "buy";
301
306
  // Size from the live position (abs), reduce-only: a stale / repeated close can never open
302
307
  // or flip a position — the venue rejects it instead. Fill measured (ORDER_PENDING when unconfirmed).
303
- // A partial close (venue-final IOC partial fills are accepted, §13.10 #4) gets ONE residual
308
+ // A partial close (venue-final IOC partial fills are accepted) gets ONE residual
304
309
  // close (closePerpVerified); a residual still open fails the step with ORDER_PARTIAL.
305
310
  const liveSize = pos.size.replace(/^-/, "");
306
311
  const c = await closePerpVerified(adapter, adapter.name, pos.symbol, closeSide, liveSize);
@@ -0,0 +1,34 @@
1
+ import { type Network, type PublicPosition } from "./exchanges/venue.js";
2
+ export interface AddressPositions {
3
+ venue: string;
4
+ positions: PublicPosition[];
5
+ /** Sub-reads that failed (Hyperliquid HIP-3 dex), keyed "hip3:<dex>". */
6
+ errors: Record<string, {
7
+ code: string;
8
+ message: string;
9
+ }>;
10
+ notes: string[];
11
+ /** One human line per failed sub-read: its rows are unknown, not absent. */
12
+ warnings: string[];
13
+ }
14
+ export interface AddressPositionsOptions {
15
+ accountIndex?: number;
16
+ symbol?: string;
17
+ }
18
+ /** Rows of `symbol` (plain asset; HIP-3 "xyz:GOLD" also matches "GOLD"; "BTC-PERP" matches "BTC"). */
19
+ export declare function filterPositionsBySymbol<T extends {
20
+ symbol: string;
21
+ }>(rows: T[], symbol: string | undefined): T[];
22
+ export declare function readPositionsByAddress(venue: string, net: Network, address: string, opts?: AddressPositionsOptions): Promise<AddressPositions>;
23
+ export interface AddressPositionsFanOut {
24
+ venues: Record<string, PublicPosition[]>;
25
+ /** A venue that failed (`<venue>`) or a failed sub-read of a venue (`<venue>:hip3:<dex>`). */
26
+ errors: Record<string, {
27
+ code: string;
28
+ message: string;
29
+ }>;
30
+ notes: Record<string, string[]>;
31
+ warnings: string[];
32
+ }
33
+ /** Every venue that reads positions by address; a venue that fails (address format included) is an `errors` entry. */
34
+ export declare function readPositionsByAddressAll(net: Network, address: string, opts?: AddressPositionsOptions): Promise<AddressPositionsFanOut>;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * `perp account positions --address` and MCP get_positions_by_address: one read path over the
3
+ * registry (VenuePublicData.fetchPositionsByAddress). Keyless; nothing is signed.
4
+ */
5
+ import { PerpError } from "./errors.js";
6
+ import { fetchPositionsByAddress, getVenue, listPublicPositionVenues } from "./exchanges/venue.js";
7
+ import { bareSymbolOf } from "./commands/market.js";
8
+ /** Rows of `symbol` (plain asset; HIP-3 "xyz:GOLD" also matches "GOLD"; "BTC-PERP" matches "BTC"). */
9
+ export function filterPositionsBySymbol(rows, symbol) {
10
+ if (symbol === undefined)
11
+ return rows;
12
+ const want = bareSymbolOf(symbol).toUpperCase();
13
+ return rows.filter(r => {
14
+ const s = r.symbol.toUpperCase();
15
+ return s === want || bareSymbolOf(r.symbol).toUpperCase() === want || s.split(":").pop() === want;
16
+ });
17
+ }
18
+ function warningsOf(venue, errors) {
19
+ return Object.entries(errors).map(([src, e]) => `${venue} ${src} unavailable (${e.code}: ${e.message}) — its positions are missing from this answer`);
20
+ }
21
+ export async function readPositionsByAddress(venue, net, address, opts = {}) {
22
+ const id = getVenue(venue).id;
23
+ const r = await fetchPositionsByAddress(id, net, address, { accountIndex: opts.accountIndex });
24
+ return { venue: id, positions: filterPositionsBySymbol(r.positions, opts.symbol), errors: r.errors, notes: r.notes, warnings: warningsOf(id, r.errors) };
25
+ }
26
+ /** Every venue that reads positions by address; a venue that fails (address format included) is an `errors` entry. */
27
+ export async function readPositionsByAddressAll(net, address, opts = {}) {
28
+ const venues = listPublicPositionVenues().map(v => v.id);
29
+ const out = { venues: {}, errors: {}, notes: {}, warnings: [] };
30
+ const settled = await Promise.allSettled(venues.map(v => readPositionsByAddress(v, net, address, opts.accountIndex !== undefined && v !== "lighter" && v !== "lighter-rh" ? { symbol: opts.symbol } : opts)));
31
+ settled.forEach((res, i) => {
32
+ const v = venues[i];
33
+ if (res.status === "rejected") {
34
+ const e = res.reason;
35
+ out.errors[v] = e instanceof PerpError ? { code: e.structured.code, message: e.structured.message } : { code: "EXCHANGE_ERROR", message: e instanceof Error ? e.message : String(e) };
36
+ return;
37
+ }
38
+ out.venues[v] = res.value.positions;
39
+ for (const [src, e] of Object.entries(res.value.errors))
40
+ out.errors[`${v}:${src}`] = e;
41
+ if (res.value.notes.length > 0)
42
+ out.notes[v] = res.value.notes;
43
+ out.warnings.push(...res.value.warnings);
44
+ });
45
+ return out;
46
+ }
package/dist/rebalance.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { PerpError } from "./errors.js";
2
2
  import { getVenue, tryResolveVenueId } from "./exchanges/venue.js";
3
3
  import "./exchanges/venues/index.js";
4
- /** Settlement chains with no withdraw → bridge → deposit route in this CLI (design §10.10). */
4
+ /** Settlement chains with no withdraw → bridge → deposit route in this CLI. */
5
5
  const NO_ROUTE_CHAINS = new Set(["robinhood", "offchain"]);
6
6
  /** Throws NO_BRIDGE_ROUTE when the venue's funds live where no bridge route exists. */
7
7
  export function assertBridgeRoute(exchange) {
package/dist/risk.d.ts CHANGED
@@ -52,7 +52,8 @@ export interface RiskAssessment {
52
52
  marginUtilization: number;
53
53
  largestPositionUsd: number;
54
54
  maxLeverageUsed: number;
55
- minLiquidationDistancePct: number;
55
+ /** null = no position with a known liquidation price (no positions, or none reported) — never a -1 sentinel */
56
+ minLiquidationDistancePct: number | null;
56
57
  };
57
58
  liquidationDistances: LiquidationDistanceInfo[];
58
59
  limits: RiskLimits;
package/dist/risk.js CHANGED
@@ -159,9 +159,9 @@ export function assessRisk(balances, positions, limits) {
159
159
  }
160
160
  // Check liquidation distances
161
161
  const liquidationDistances = getLiquidationDistances(positions, lim);
162
- let minLiquidationDistancePct = Infinity;
162
+ let minLiquidationDistancePct = null;
163
163
  for (const ld of liquidationDistances) {
164
- if (ld.distancePct < minLiquidationDistancePct) {
164
+ if (minLiquidationDistancePct === null || ld.distancePct < minLiquidationDistancePct) {
165
165
  minLiquidationDistancePct = ld.distancePct;
166
166
  }
167
167
  if (ld.distancePct < lim.minLiquidationDistance) {
@@ -174,8 +174,6 @@ export function assessRisk(balances, positions, limits) {
174
174
  });
175
175
  }
176
176
  }
177
- if (minLiquidationDistancePct === Infinity)
178
- minLiquidationDistancePct = -1; // no positions
179
177
  // Determine overall risk level
180
178
  let level = "low";
181
179
  if (violations.some(v => v.severity === "critical"))
@@ -168,7 +168,36 @@ export interface QfexAgentMeta {
168
168
  approvedAt: string;
169
169
  source: "imported";
170
170
  }
171
- export type AnyAgentMeta = AgentMeta | OndoAgentMeta | ArcusAgentMeta | QfexAgentMeta;
171
+ /**
172
+ * RISEx session signer (EVM key). Registered by the master with RegisterSigner (+ the signer's
173
+ * VerifySigner) and then restricted ON-CHAIN to the trading permission (DisablePermission for every
174
+ * other permission, signed by the signer and sent by the master). The private key lives only in OWS wallet `agentWalletName`
175
+ * (SSOT Rule #3).
176
+ */
177
+ export interface RisexAgentMeta {
178
+ kind: "risex";
179
+ agentName: string;
180
+ agentWalletName: string;
181
+ /** Signer (session key) address. */
182
+ signerAddress: `0x${string}`;
183
+ /** The RISEx account (master wallet address) the signer trades for. */
184
+ accountAddress: `0x${string}`;
185
+ /** ISO timestamp of the on-chain expiration signed in RegisterSigner. */
186
+ expiresAt: string;
187
+ /**
188
+ * On-chain permission state proven after registration (Authorization.hasPermission):
189
+ * trading-only = only the router permission enabled. Never written from a guess.
190
+ */
191
+ permissions: {
192
+ tradingOnly: boolean;
193
+ disabled: number[];
194
+ verifiedAt: string | null;
195
+ };
196
+ network: "mainnet" | "testnet";
197
+ approvedAt: string;
198
+ source: "approved";
199
+ }
200
+ export type AnyAgentMeta = AgentMeta | OndoAgentMeta | ArcusAgentMeta | QfexAgentMeta | RisexAgentMeta;
172
201
  export interface AgentsByExchange {
173
202
  aster?: Record<string, AgentMeta>;
174
203
  hyperliquid?: Record<string, AgentMeta>;
@@ -178,6 +207,7 @@ export interface AgentsByExchange {
178
207
  ondo?: Record<string, OndoAgentMeta>;
179
208
  arcus?: Record<string, ArcusAgentMeta>;
180
209
  qfex?: Record<string, QfexAgentMeta>;
210
+ risex?: Record<string, RisexAgentMeta>;
181
211
  }
182
212
  export interface Settings {
183
213
  /** Default exchange when -e flag is omitted */
@@ -203,8 +233,7 @@ export interface Settings {
203
233
  /** OWS-native agent wallets registered per exchange (Phase 2a: Aster only) */
204
234
  agents?: AgentsByExchange;
205
235
  /**
206
- * Per-venue slippage bound override (basis points) for market-type orders
207
- * (design §13.2). Absent key = use `defaultSlippageBps`.
236
+ * Per-venue slippage bound override (basis points) for market-type orders. Absent key = use `defaultSlippageBps`.
208
237
  * Resolved only by resolveSlippage() (src/exchanges/slippage.ts).
209
238
  */
210
239
  slippageBps: {
@@ -17,7 +17,7 @@ export declare class OwsEvmSigner implements EvmSigner {
17
17
  }>>, value: Record<string, unknown>): Promise<string>;
18
18
  /**
19
19
  * Sign an unsigned EVM transaction (on-chain txs sent by the master wallet — Lighter RH
20
- * deposit, design §13). The digest is computed HERE from the transaction (`unsignedHash`),
20
+ * deposit). The digest is computed HERE from the transaction (`unsignedHash`),
21
21
  * so callers can never feed an arbitrary 32-byte hash to the master key. Returns the
22
22
  * 65-byte 0x signature; the caller attaches it and checks the recovered sender.
23
23
  */
@@ -44,7 +44,7 @@ export class OwsEvmSigner {
44
44
  }
45
45
  /**
46
46
  * Sign an unsigned EVM transaction (on-chain txs sent by the master wallet — Lighter RH
47
- * deposit, design §13). The digest is computed HERE from the transaction (`unsignedHash`),
47
+ * deposit). The digest is computed HERE from the transaction (`unsignedHash`),
48
48
  * so callers can never feed an arbitrary 32-byte hash to the master key. Returns the
49
49
  * 65-byte 0x signature; the caller attaches it and checks the recovered sender.
50
50
  */
@@ -16,7 +16,7 @@
16
16
  * - Saves 5-50+ bps vs raw market orders on thin books
17
17
  * - Predictable execution price
18
18
  *
19
- * Order-outcome typing (design §12.3): every failure BEFORE the IOC is sent (orderbook read,
19
+ * Order-outcome typing: every failure BEFORE the IOC is sent (orderbook read,
20
20
  * empty book, unusable price), an explicit venue rejection embedded in the response, and an
21
21
  * explicit IOC no-match (nothing filled, nothing rests) throw a definite ORDER_REJECTED
22
22
  * (orderNotSent), so placePerpVerified does not quarantine a leg that never traded. Anything
@@ -16,7 +16,7 @@
16
16
  * - Saves 5-50+ bps vs raw market orders on thin books
17
17
  * - Predictable execution price
18
18
  *
19
- * Order-outcome typing (design §12.3): every failure BEFORE the IOC is sent (orderbook read,
19
+ * Order-outcome typing: every failure BEFORE the IOC is sent (orderbook read,
20
20
  * empty book, unusable price), an explicit venue rejection embedded in the response, and an
21
21
  * explicit IOC no-match (nothing filled, nothing rests) throw a definite ORDER_REJECTED
22
22
  * (orderNotSent), so placePerpVerified does not quarantine a leg that never traded. Anything
@@ -13,7 +13,7 @@ export interface FundingArbParams {
13
13
  maxDrawdown?: number;
14
14
  }
15
15
  /**
16
- * `perp strategy funding-arb` loop. With autoExecute (design §12.3):
16
+ * `perp strategy funding-arb` loop. With autoExecute:
17
17
  * - entry = openPerpPairVerified (long, then the short sized to the long's VERIFIED fill;
18
18
  * definite short failure → reduce-only rollback; unknown outcome → quarantine). A lot-size
19
19
  * rejection is never resubmitted blindly: the long is re-sized only when it was definitely