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
package/dist/index.js CHANGED
@@ -17,6 +17,7 @@ import { createRequire } from "node:module";
17
17
  config({ path: resolve(process.env.HOME || "~", ".perp", ".env") });
18
18
  import chalk from "chalk";
19
19
  import { listVenues } from "./exchanges/venue.js";
20
+ import { optionsVenueWords } from "./exchanges/options-venues.js";
20
21
  import { PerpError } from "./errors.js";
21
22
  import { loadSettings } from "./settings.js";
22
23
  import { jsonError, jsonOk, printCliError, printJson } from "./utils.js";
@@ -49,7 +50,7 @@ const _defaultExchange = _settings.defaultExchange || "pacifica";
49
50
  const { program, getAdapterForExchange, isJson } = buildProgram({ defaultExchange: _defaultExchange, version: _pkg.version });
50
51
  // Smart landing page: `perp` with no subcommand
51
52
  const rawArgs = process.argv.slice(2);
52
- const _venueWords = listVenues().flatMap(v => [v.id, ...v.aliases]);
53
+ const _venueWords = [...listVenues().flatMap(v => [v.id, ...v.aliases]), ...optionsVenueWords()];
53
54
  const hasSubcommand = rawArgs.some((a) => !a.startsWith("-") && ![..._venueWords, "mainnet", "testnet"].includes(a));
54
55
  // `history list -n 5` (old record-count flag) → INVALID_PARAMS with the --limit migration, before
55
56
  // Commander turns it into a bare "invalid network" usage error.
@@ -118,18 +119,18 @@ if (rawArgs.length === 0 || (!hasSubcommand && !rawArgs.includes("-h") && !rawAr
118
119
  const landingVenues = [];
119
120
  for (const ex of LANDING_EXCHANGES) {
120
121
  const def = getVenue(ex);
121
- if (def.create === null || await hasCredentials(def.id, NO_CLI_CREDENTIAL_OPTS))
122
+ if (!def.roles.includes("account") || await hasCredentials(def.id, NO_CLI_CREDENTIAL_OPTS))
122
123
  landingVenues.push(ex);
123
124
  }
124
125
  const statusResults = await Promise.allSettled(landingVenues.map(async (ex) => {
125
- if (getVenue(ex).create === null) {
126
- return { exchange: ex, marketDataOnly: true, ok: false, equity: 0, positions: 0 };
126
+ if (!getVenue(ex).roles.includes("account")) {
127
+ return { exchange: ex, marketDataOnly: true, unofficialApi: getVenue(ex).apiStatus.kind === "unofficial", ok: false, equity: 0, positions: 0 };
127
128
  }
128
129
  try {
129
130
  const adapter = await withTimeout(getAdapterForExchange(ex), 5000);
130
131
  const [balance, positions] = await withTimeout(Promise.all([adapter.getBalance(), adapter.getPositions()]), 5000);
131
132
  const posCount = positions.filter(p => Number(p.size) > 0).length;
132
- // Spot value on top of perp equity for venues with def.spot (§12). Shared balances
133
+ // Spot value on top of perp equity for venues with def.spot. Shared balances
133
134
  // (already in perp equity) are skipped; unpriced tokens are excluded + warned.
134
135
  let spotValue = 0;
135
136
  const spotDef = getVenue(ex);
@@ -196,7 +197,7 @@ else {
196
197
  }).catch(async (err) => {
197
198
  // Central printer (utils.printCliError): typed PerpError code / remediation / details
198
199
  // are preserved (Rule #2: stay loud, keep semantic envelope); generic Errors go
199
- // through classifyError; CAPABILITY_UNSUPPORTED prints the uniform §13.6 line.
200
+ // through classifyError; CAPABILITY_UNSUPPORTED prints the uniform line.
200
201
  const { printCliError } = await import("./utils.js");
201
202
  printCliError(err, isJson());
202
203
  _origExit(1);
package/dist/jobs.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { Command } from "commander";
2
2
  import type { Network } from "./exchanges/venue-types.js";
3
+ import "./exchanges/venues/index.js";
3
4
  export interface JobEntry {
4
5
  id: string;
5
6
  strategy: string;
package/dist/jobs.js CHANGED
@@ -4,9 +4,11 @@ import { join } from "node:path";
4
4
  import { homedir } from "node:os";
5
5
  import { randomBytes } from "node:crypto";
6
6
  import { parse as parseDotenv } from "dotenv";
7
+ import { getVenue, roleUnsupported, tryResolveVenueId } from "./exchanges/venue.js";
8
+ import "./exchanges/venues/index.js";
7
9
  import { PerpError } from "./errors.js";
8
10
  import { QFEX_AUTOMATION_VERIFIED, QFEX_REDUCE_ONLY_WIRE, qfexAutomationGate, qfexReduceOnlyGate } from "./exchanges/qfex/signing.js";
9
- import { startRefusal } from "./exchanges/trading-v2.js";
11
+ import { startRefusal, unsupported } from "./exchanges/trading-v2.js";
10
12
  import { scrubSecretEnv, secretEnvNamesIn } from "./secret-env.js";
11
13
  const JOBS_DIR = join(homedir(), ".perp", "jobs");
12
14
  const LOGS_DIR = join(homedir(), ".perp", "logs");
@@ -165,6 +167,28 @@ export function startJob(opts) {
165
167
  if (automation !== null)
166
168
  throw startRefusal(what, "it would trade unattended", automation);
167
169
  }
170
+ for (const v of new Set([opts.venue, opts.exchange])) {
171
+ const id = v?.toLowerCase();
172
+ const what = `Background job "${opts.strategy}"`;
173
+ // RISEx: unattended trading stays off until its trading path is verified on mainnet (no TP/SL yet).
174
+ if (id === "risex" || id === "rise") {
175
+ // Read-only release (trading role gated): the uniform phase refusal.
176
+ const risex = getVenue("risex");
177
+ if (!risex.roles.includes("trading"))
178
+ throw startRefusal(what, "it would trade unattended", roleUnsupported(risex, "automation"));
179
+ throw startRefusal(what, "it would trade unattended", unsupported("RISEx", "automation", "unattended trading on RISEx is not enabled until its trading path is verified on mainnet (and it has no TP/SL yet)", "Trade RISEx manually with perp trade …"));
180
+ }
181
+ // TxFlow: market data only (unofficial read-only API).
182
+ if (id === "txflow" || id === "txf") {
183
+ throw startRefusal(what, "TxFlow has no trading in perp-cli", unsupported("txflow", "trading", "TxFlow is integrated through an unofficial read-only API (market data only)", "Trade on the TxFlow website"));
184
+ }
185
+ // Any other registered venue without the trading role (Variational, GRVT, Extended: read-only in this version).
186
+ const venueId = id === undefined ? null : tryResolveVenueId(id);
187
+ if (venueId !== null && !getVenue(venueId).roles.includes("trading")) {
188
+ const def = getVenue(venueId);
189
+ throw startRefusal(what, `${def.displayName} has no trading in perp-cli`, roleUnsupported(def, "trading"));
190
+ }
191
+ }
168
192
  }
169
193
  if (!hasTmux()) {
170
194
  throw new Error("tmux is required for background jobs. Install with: brew install tmux");
package/dist/landing.d.ts CHANGED
@@ -5,6 +5,8 @@ export type LandingExchangeStatus = {
5
5
  exchange: string;
6
6
  /** Venue has no account API — rendered as market data only. */
7
7
  marketDataOnly?: boolean;
8
+ /** Venue is read through an undocumented API (VenueDefinition.apiStatus) — labelled "unofficial API". */
9
+ unofficialApi?: boolean;
8
10
  ok: boolean;
9
11
  equity: number;
10
12
  positions: number;
package/dist/landing.js CHANGED
@@ -25,7 +25,7 @@ export function renderLandingExchangeLine(status, asterAgentMissing) {
25
25
  return ` ${chalk.yellow("⚙")} ${chalk.cyan(exchangeLabel(status.exchange).padEnd(14))} ${chalk.yellow("agent required")} ${chalk.gray("→ perp wallet agent approve aster")}`;
26
26
  }
27
27
  if (status.marketDataOnly) {
28
- return ` ${chalk.gray("◇")} ${chalk.cyan(exchangeLabel(status.exchange).padEnd(14))} ${chalk.gray("market data only")}`;
28
+ return ` ${chalk.gray("◇")} ${chalk.cyan(exchangeLabel(status.exchange).padEnd(14))} ${chalk.gray("market data only")}${status.unofficialApi ? chalk.yellow(" (unofficial API)") : ""}`;
29
29
  }
30
30
  const icon = status.ok ? chalk.green("●") : chalk.red("○");
31
31
  const equity = status.ok
@@ -26,7 +26,9 @@ export declare function computeExecutableSize(levels: [string, string][], reques
26
26
  * Check liquidity on both sides for an arb entry.
27
27
  * Returns adjusted size or 0 if not viable.
28
28
  */
29
- export declare function checkArbLiquidity(longAdapter: ExchangeAdapter, shortAdapter: ExchangeAdapter, symbol: string, sizeUsd: number, maxSlippagePct?: number, log?: (msg: string) => void): Promise<{
29
+ export declare function checkArbLiquidity(longAdapter: ExchangeAdapter, shortAdapter: ExchangeAdapter, symbol: string, sizeUsd: number, maxSlippagePct?: number, log?: (msg: string) => void,
30
+ /** The short venue's own symbol when it differs (kPEPE ↔ 1000PEPE); default `symbol`. */
31
+ shortSymbol?: string): Promise<{
30
32
  viable: boolean;
31
33
  adjustedSizeUsd: number;
32
34
  longSlippage: number;
package/dist/liquidity.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { classifyError } from "./errors.js";
1
2
  /**
2
3
  * Walk through orderbook levels and compute how much can be filled
3
4
  * within the given slippage tolerance.
@@ -63,11 +64,13 @@ export function computeExecutableSize(levels, requestedSizeUsd, maxSlippagePct =
63
64
  * Check liquidity on both sides for an arb entry.
64
65
  * Returns adjusted size or 0 if not viable.
65
66
  */
66
- export async function checkArbLiquidity(longAdapter, shortAdapter, symbol, sizeUsd, maxSlippagePct = 0.5, log) {
67
+ export async function checkArbLiquidity(longAdapter, shortAdapter, symbol, sizeUsd, maxSlippagePct = 0.5, log,
68
+ /** The short venue's own symbol when it differs (kPEPE ↔ 1000PEPE); default `symbol`. */
69
+ shortSymbol = symbol) {
67
70
  try {
68
71
  const [longOB, shortOB] = await Promise.all([
69
72
  longAdapter.getOrderbook(symbol),
70
- shortAdapter.getOrderbook(symbol),
73
+ shortAdapter.getOrderbook(shortSymbol),
71
74
  ]);
72
75
  // For long entry we consume asks, for short entry we consume bids
73
76
  const longCheck = computeExecutableSize(longOB.asks, sizeUsd, maxSlippagePct);
@@ -145,8 +148,9 @@ export async function checkSpotPerpLiquidity(spotAdapter, perpAdapter, spotSymbo
145
148
  perpSlippage: perpCheck.slippagePct,
146
149
  };
147
150
  }
148
- catch {
149
- log?.(`[LIQ] spot-perp ${spotSymbol}: orderbook fetch failed`);
151
+ catch (e) {
152
+ const c = classifyError(e);
153
+ log?.(`[LIQ] spot-perp ${spotSymbol}: orderbook fetch failed (${c.code}: ${c.message})`);
150
154
  return { viable: false, adjustedSizeUsd: 0, spotSlippage: 0, perpSlippage: 0 };
151
155
  }
152
156
  }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Read-only MCP tools for Pacifica Print and vaults (unauthenticated GETs; nothing is signed).
3
+ * Print deposits / ends and vault deposits / withdrawals are NOT exposed over MCP: the server has
4
+ * no money-moving deposit / withdraw tools (funds moves are CLI-only, `perp funds …`), and these
5
+ * follow the same rule — use `perp print deposit` / `perp vault deposit|withdraw` (with --dry-run).
6
+ */
7
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
8
+ import type { Network } from "./exchanges/venue-types.js";
9
+ export declare function registerPacificaEarnMcpTools(server: McpServer, network: Network, ok: (data: unknown, meta?: Record<string, unknown>) => string, errOf: (e: unknown, meta?: Record<string, unknown>) => string): void;
@@ -0,0 +1,64 @@
1
+ import { z } from "zod";
2
+ import { PacificaClient, requireSolanaAddress } from "./pacifica/client.js";
3
+ import { fetchPrintGames, fetchPrintHistory, fetchPrintMarket, fetchPrintPositions, findPrintGame, quotePrintOrder } from "./exchanges/pacifica-print.js";
4
+ import { DEPOSIT_WHITELIST_API_STATUS, readDepositWhitelist, fetchVaults, findVault, heldShares, withdrawWindowAt } from "./exchanges/pacifica-vaults.js";
5
+ export function registerPacificaEarnMcpTools(server, network, ok, errOf) {
6
+ const client = () => new PacificaClient({ network });
7
+ const run = async (meta, f) => {
8
+ try {
9
+ return { content: [{ type: "text", text: ok(await f(), meta) }] };
10
+ }
11
+ catch (e) {
12
+ return { content: [{ type: "text", text: errOf(e, meta) }], isError: true };
13
+ }
14
+ };
15
+ const address = z.string().refine((v) => { try {
16
+ requireSolanaAddress(v);
17
+ return true;
18
+ }
19
+ catch {
20
+ return false;
21
+ } }, "base58 Solana address (32-byte public key; not an EVM address)");
22
+ server.tool("pacifica_print_products", "Pacifica Print products (read-only): game id (e.g. BTC_24H, BTC_7D, BTC_1M), cycle length in days, max leverage, deposit caps, allowed target distance from mark. Print = a strike order that earns a premium each cycle; while resting it fills / is liquidated only at a cycle checkpoint, after a fill it is an ordinary perp position (continuous liquidation).", {}, async () => run({ exchange: "pacifica" }, async () => fetchPrintGames(client())));
23
+ server.tool("pacifica_print_quote", "Validate a Pacifica Print order and preview it (read-only, nothing signed): notional, size on fill, docs-formula liquidation price (an outer bound — a liquidation was observed earlier in one live case; venue trigger unpublished), max loss (deposit + premiums), lock period. The premium is not quoted (the venue's preview is a signed request). Placing the order is CLI-only: perp -e pacifica print deposit … (supports --dry-run).", {
24
+ game: z.string().describe("Print product, e.g. BTC_24H"),
25
+ direction: z.enum(["long", "short"]).describe("long = target below mark, short = target above mark"),
26
+ deposit: z.string().describe("USDC deposit, min 10"),
27
+ strike: z.string().describe("Target price (on the market tick)"),
28
+ leverage: z.string().describe("Whole-number leverage 1 … product max"),
29
+ cycles: z.number().int().optional().describe("Cycles 1 … 1000; omit = roll until cancelled"),
30
+ }, async ({ game, direction, deposit, strike, leverage, cycles }) => run({ exchange: "pacifica", game }, async () => {
31
+ const c = client();
32
+ const g = findPrintGame(await fetchPrintGames(c), game);
33
+ return quotePrintOrder(g, { game: g.game, direction, deposit, strikePrice: strike, leverage, cycles: cycles ?? null }, await fetchPrintMarket(c, g.asset));
34
+ }));
35
+ server.tool("pacifica_print_positions", "Pacifica Print orders of an account (read-only): current orders, or with history=true every order (paginated: limit / cursor). Status printing | cancelling | filled | liquidated | cancelled | completed | ended.", {
36
+ account: address.describe("Pacifica account (Solana address)"),
37
+ history: z.boolean().optional().describe("true = every order (history_summary), default false = current orders"),
38
+ limit: z.number().int().positive().optional(),
39
+ cursor: z.string().optional(),
40
+ }, async ({ account, history, limit, cursor }) => run({ exchange: "pacifica", account }, async () => {
41
+ if (history !== true)
42
+ return { account, positions: await fetchPrintPositions(client(), account) };
43
+ const page = await fetchPrintHistory(client(), account, { limit: limit ?? null, cursor: cursor ?? null });
44
+ return { account, positions: page.items, hasMore: page.hasMore, nextCursor: page.nextCursor };
45
+ }));
46
+ server.tool("pacifica_vaults", "Pacifica vaults (API: lakes), read-only. Without vault: every vault (TVL, NAV per share, fee, lock-up, withdrawal window, config); with account: plus that account's shares. With vault (address, or a nickname matching exactly one vault — an ambiguous nickname is INVALID_PARAMS listing the candidates): one vault plus live account equity, positions, deposit whitelist (unofficial endpoint, advisory) and whether withdrawals are open now. APY is not published (null). Deposits / withdrawals are CLI-only: perp -e pacifica vault deposit|withdraw (supports --dry-run).", {
47
+ vault: z.string().optional().describe("Vault address or exact nickname"),
48
+ account: address.optional().describe("Include this account's shares"),
49
+ }, async ({ vault, account }) => run({ exchange: "pacifica" }, async () => {
50
+ const c = client();
51
+ const vaults = await fetchVaults(c, account ?? null);
52
+ if (vault === undefined)
53
+ return vaults;
54
+ const v = findVault(vaults, vault);
55
+ const [acct, positions, whitelist] = await Promise.all([c.getAccount(v.address), c.getPositions(v.address), readDepositWhitelist(c, v.address)]);
56
+ return {
57
+ ...v,
58
+ ...(account !== undefined ? { holding: heldShares(v, account) } : {}),
59
+ live: { accountEquity: acct.account_equity ?? null, availableToWithdraw: acct.available_to_withdraw ?? null, positions: positions.map((p) => ({ symbol: p.symbol, side: p.side, amount: p.amount, entryPrice: p.entry_price })) },
60
+ depositWhitelist: { apiStatus: DEPOSIT_WHITELIST_API_STATUS, addresses: whitelist.addresses, error: whitelist.error },
61
+ withdrawWindow: withdrawWindowAt(v.config, Date.now()),
62
+ };
63
+ }));
64
+ }