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
@@ -23,7 +23,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
23
23
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
24
24
  import { z } from "zod";
25
25
  import { hasCredentials, listConfiguredAccountVenues, resolveCredentials, NO_CLI_CREDENTIAL_OPTS } from "./config.js";
26
- import { getVenue, listVenues, listVenuesWithRole, networkConfig, READ_ONLY_CREDENTIALS, requireCapabilities } from "./exchanges/venue.js";
26
+ import { getVenue, listVenues, listVenuesWithRole, networkConfig, READ_ONLY_CREDENTIALS, requireCapabilities, roleUnsupported } from "./exchanges/venue.js";
27
27
  import "./exchanges/venues/index.js";
28
28
  import { newVenueClientOrderId, placeAndConfirm, validateLegacyTif, validateOrderRequest } from "./exchanges/trading-v2.js";
29
29
  import { closePerpVerified, isOutcomeUnknown } from "./bot/perp-order.js";
@@ -32,7 +32,8 @@ import { fillSizeString, sizeDecimalsOf } from "./exchanges/spot-result.js";
32
32
  import { tradingV2Of } from "./exchanges/legacy-trading-v2.js";
33
33
  import { PerpError, classifyError, extractErrorMessage, isDefiniteOrderFailure, orderOutcomeUnknown, parsePositiveDecimal } from "./errors.js";
34
34
  import { invalidateCache } from "./cache.js";
35
- import { pingPacifica, pingHyperliquid, pingLighter, } from "./shared-api.js";
35
+ import { probeVenueHealth } from "./venue-health.js";
36
+ import { getOptionsVenue, listOptionsVenueIds } from "./exchanges/options-venues.js";
36
37
  import { fetchAllFundingRates } from "./funding-rates.js";
37
38
  import { loadArbState } from "./arb/state.js";
38
39
  import { validateTrade } from "./trade-validator.js";
@@ -41,6 +42,7 @@ import { logMcpExecution, mcpPreTradeGate, mcpReduceOnlyGate, resolveMcpNetwork
41
42
  import { setSharedApiNetwork } from "./api/public/urls.js";
42
43
  import { logClientId } from "./client-id-tracker.js";
43
44
  import { loadSettings } from "./settings.js";
45
+ import { registerPacificaEarnMcpTools } from "./mcp-pacifica-earn.js";
44
46
  /**
45
47
  * The one network this server serves: PERP_NETWORK, validated like `-n` (an invalid value
46
48
  * makes the server refuse to start). Unset = mainnet, the documented default. Reported in
@@ -52,8 +54,8 @@ setQuarantineNetwork(MCP_NETWORK);
52
54
  setSharedApiNetwork(MCP_NETWORK);
53
55
  // ── Adapter cache & factory ──
54
56
  //
55
- // Same creation path and signer tiers as the CLI (agent → OWS master → PK;
56
- // design §9.1 #1, §10.2). The MCP server has no CLI flags, so credentials come
57
+ // Same creation path and signer tiers as the CLI (agent → OWS master → PK).
58
+ // The MCP server has no CLI flags, so credentials come
57
59
  // from the registered agent, settings.owsActiveWallet, and (legacy venues) env.
58
60
  const adapters = new Map();
59
61
  /** The network each adapter was created on (TradingV2 wrappers must use the same one). */
@@ -71,6 +73,9 @@ async function getOrCreateAdapter(exchange) {
71
73
  const cached = adapters.get(def.id);
72
74
  if (cached)
73
75
  return cached;
76
+ // Market-data-only venue (TxFlow: unofficial read-only API): every account / trading tool refuses here.
77
+ if (!def.roles.includes("account"))
78
+ throw roleUnsupported(def, "account");
74
79
  const create = requireCreate(def);
75
80
  if (!(await hasCredentials(def.id, NO_CLI_CREDENTIAL_OPTS))) {
76
81
  throw new PerpError("NO_SIGNER_AVAILABLE", `No credentials configured for ${def.id}`, {
@@ -118,9 +123,35 @@ async function tryGetAdapter(exchange) {
118
123
  throw e;
119
124
  }
120
125
  }
121
- /** Fetch markets using the venue's public data path (no key needed). */
126
+ /**
127
+ * Fetch markets using the venue's public data path (no key needed). Unofficial-API rows carry
128
+ * venueApi; rows of a venue whose funding is unverified (QFEX, GRVT, TxFlow) carry fundingVerified false.
129
+ */
122
130
  async function fetchMarketsPublic(exchange) {
123
- return getVenue(exchange).publicData.fetchMarkets(MCP_NETWORK);
131
+ return labelMarketRows(exchange, await getVenue(exchange).publicData.fetchMarkets(MCP_NETWORK));
132
+ }
133
+ /**
134
+ * The one row label for market rows of any source (public data path or a credentialed adapter):
135
+ * unofficial-API rows carry venueApi + fundingVerified; unverified-funding rows carry fundingVerified false.
136
+ */
137
+ function labelMarketRows(exchange, rows) {
138
+ const def = getVenue(exchange);
139
+ if (def.apiStatus.kind === "unofficial")
140
+ return rows.map(r => ({ ...r, venueApi: "unofficial", fundingVerified: def.fundingVerified }));
141
+ return def.fundingVerified ? rows : rows.map(r => ({ ...r, fundingVerified: false }));
142
+ }
143
+ /**
144
+ * meta fields every market-data tool adds for its venue: apiStatus, the note for an unofficial API,
145
+ * and fundingVerified false (with a note) when the venue's funding rate is unverified.
146
+ */
147
+ function apiMeta(exchange) {
148
+ const def = getVenue(exchange);
149
+ if (def.apiStatus.kind === "unofficial") {
150
+ return { apiStatus: "unofficial", apiNote: `${def.displayName}: UNOFFICIAL API — ${def.apiStatus.note}`, fundingVerified: def.fundingVerified };
151
+ }
152
+ return def.fundingVerified
153
+ ? { apiStatus: "official" }
154
+ : { apiStatus: "official", fundingVerified: false, fundingNote: `${def.displayName}: funding rate UNVERIFIED (not confirmed against settled payments) — display only, never a basis for trading` };
124
155
  }
125
156
  /** One book level from a venue payload; a level without a string price / size is a payload error (never "0"). */
126
157
  function bookLevel(venue, symbol, price, size) {
@@ -219,6 +250,8 @@ export const MCP_WITHDRAW_VENUES = ["pacifica", "hyperliquid", "lighter", "aster
219
250
  const _require = createRequire(import.meta.url);
220
251
  const _pkg = _require("../package.json");
221
252
  const server = new McpServer({ name: "perp-cli", version: _pkg.version }, { capabilities: { tools: {}, resources: {}, prompts: {} } });
253
+ // Pacifica Print + vaults: read-only tools (src/mcp-pacifica-earn.ts).
254
+ registerPacificaEarnMcpTools(server, MCP_NETWORK, ok, errOf);
222
255
  // ============================================================
223
256
  // Market Data tools (read-only, no private key needed)
224
257
  // ============================================================
@@ -227,11 +260,11 @@ server.tool("get_markets", `Get all available perpetual futures markets on an ex
227
260
  // Try adapter first (richer data), fall back to public API (no key needed)
228
261
  const adapter = await tryGetAdapter(exchange);
229
262
  if (adapter) {
230
- const markets = await adapter.getMarkets();
231
- return { content: [{ type: "text", text: ok(markets, { exchange, count: markets.length }) }] };
263
+ const markets = labelMarketRows(exchange, await adapter.getMarkets());
264
+ return { content: [{ type: "text", text: ok(markets, { exchange, count: markets.length, ...apiMeta(exchange) }) }] };
232
265
  }
233
266
  const markets = await fetchMarketsPublic(exchange);
234
- return { content: [{ type: "text", text: ok(markets, { exchange, count: markets.length, source: "public" }) }] };
267
+ return { content: [{ type: "text", text: ok(markets, { exchange, count: markets.length, source: "public", ...apiMeta(exchange) }) }] };
235
268
  }
236
269
  catch (e) {
237
270
  return { content: [{ type: "text", text: errOf(e, { exchange }) }], isError: true };
@@ -246,24 +279,25 @@ server.tool("get_orderbook", `Get the order book (bids and asks) for a symbol on
246
279
  const adapter = await tryGetAdapter(exchange);
247
280
  if (adapter) {
248
281
  const book = await adapter.getOrderbook(symbol);
249
- return { content: [{ type: "text", text: ok(book, { exchange, symbol }) }] };
282
+ return { content: [{ type: "text", text: ok(book, { exchange, symbol, ...apiMeta(exchange) }) }] };
250
283
  }
251
284
  const book = await fetchOrderbookPublic(exchange, symbol);
252
- return { content: [{ type: "text", text: ok(book, { exchange, symbol, source: "public" }) }] };
285
+ return { content: [{ type: "text", text: ok(book, { exchange, symbol, source: "public", ...apiMeta(exchange) }) }] };
253
286
  }
254
287
  catch (e) {
255
288
  return { content: [{ type: "text", text: errOf(e, { exchange, symbol }) }], isError: true };
256
289
  }
257
290
  });
258
- server.tool("get_funding_rates", "Compare funding rates across every market-data venue. Returns rates per symbol with spread analysis", {
291
+ server.tool("get_funding_rates", "Compare funding rates across every market-data venue whose funding rate is verified. Returns rates per symbol with spread analysis. includeUnverified also returns venues whose rate is unverified (QFEX; TxFlow — unofficial API; Variational — a predicted rate not checked against settled payments; GRVT — indicative rate; Extended — not checked against settled payments), each row tagged fundingVerified / apiStatus — display only, never a basis for trading (mirrors the CLI `arb scan --include-unverified`).", {
259
292
  symbols: z
260
293
  .array(z.string())
261
294
  .optional()
262
295
  .describe("Filter to specific symbols (e.g. ['BTC','ETH']). Omit for all available"),
263
296
  minSpread: z.number().optional().describe("Minimum annualized spread % to include (default: 0)"),
264
- }, async ({ symbols, minSpread }) => {
297
+ includeUnverified: z.boolean().optional().describe("Also include venues whose funding rate is unverified (default false); rows carry fundingVerified:false / apiStatus"),
298
+ }, async ({ symbols, minSpread, includeUnverified }) => {
265
299
  try {
266
- const snapshot = await fetchAllFundingRates({ symbols, minSpread });
300
+ const snapshot = await fetchAllFundingRates({ symbols, minSpread, includeUnverified: includeUnverified === true });
267
301
  return {
268
302
  content: [{
269
303
  type: "text",
@@ -275,7 +309,7 @@ server.tool("get_funding_rates", "Compare funding rates across every market-data
275
309
  return { content: [{ type: "text", text: errOf(e) }], isError: true };
276
310
  }
277
311
  });
278
- server.tool("get_prices", "Get cross-exchange prices for symbols. Fetches mark prices from every market-data venue for comparison", {
312
+ server.tool("get_prices", "Get cross-exchange prices for symbols. Fetches mark prices from every market-data venue for comparison; a venue appears in a row only when it lists that symbol (e.g. QFEX lists no BTC). Each row's unofficialApiVenues names the venues in it read through an undocumented API (TxFlow) — like get_markets' venueApi tag.", {
279
313
  symbols: z
280
314
  .array(z.string())
281
315
  .optional()
@@ -303,8 +337,13 @@ server.tool("get_prices", "Get cross-exchange prices for symbols. Fetches mark p
303
337
  priceMap.get(sym)[ex] = Number(m.markPrice);
304
338
  }
305
339
  });
306
- const data = Array.from(priceMap.entries()).map(([symbol, prices]) => ({ symbol, prices }));
307
- return { content: [{ type: "text", text: ok(data, { count: data.length, errors }) }] };
340
+ const unofficial = listVenuesWithRole("marketData").filter(v => v.apiStatus.kind === "unofficial").map(v => v.id);
341
+ const data = Array.from(priceMap.entries()).map(([symbol, prices]) => ({
342
+ symbol,
343
+ prices,
344
+ unofficialApiVenues: Object.keys(prices).filter(ex => unofficial.includes(ex)),
345
+ }));
346
+ return { content: [{ type: "text", text: ok(data, { count: data.length, errors, unofficialApiVenues: unofficial }) }] };
308
347
  }
309
348
  catch (e) {
310
349
  return { content: [{ type: "text", text: errOf(e) }], isError: true };
@@ -362,6 +401,44 @@ server.tool("get_outcome_book", "Get the orderbook for one outcome side. Public
362
401
  }
363
402
  });
364
403
  // ============================================================
404
+ // Options market data (read-only, keyless; venues: src/exchanges/options-venues.ts)
405
+ // ============================================================
406
+ const OPTIONS_VENUE_ARG = z.string().describe(`Options venue: ${listOptionsVenueIds().join(", ")}`);
407
+ server.tool("get_option_expiries", "List the active option expiries of an underlying on an options venue (Derive): per expiry the UTC date (YYYY-MM-DD), expiry ms, strike and instrument counts, soonest first. Public read — no API key needed.", { venue: OPTIONS_VENUE_ARG, underlying: z.string().describe("Underlying, e.g. ETH, BTC") }, async ({ venue, underlying }) => {
408
+ try {
409
+ const data = await (await getOptionsVenue(venue, MCP_NETWORK)).listExpiries(underlying);
410
+ return { content: [{ type: "text", text: ok(data, { venue, count: data.expiries.length }) }] };
411
+ }
412
+ catch (e) {
413
+ return { content: [{ type: "text", text: errOf(e, { venue, underlying }) }], isError: true };
414
+ }
415
+ });
416
+ server.tool("get_option_chain", "Option chain for one expiry (Derive): rows per strike with call and put quotes — bid / ask (price + size; null = empty side), mark, index, forward, IV (mark / bid / ask; null = not computable), greeks (delta, gamma, theta, vega, rho), open interest, 24h volume — plus the ATM strike. Decimals are strings. One venue request per expiry. Public read.", {
417
+ venue: OPTIONS_VENUE_ARG,
418
+ underlying: z.string().describe("Underlying, e.g. ETH, BTC"),
419
+ expiry: z.string().optional().describe("Expiry date YYYY-MM-DD (UTC); omit for the nearest active expiry (result expirySelection: \"nearest\")"),
420
+ strikes: z.number().int().min(1).optional().describe("Only the N strikes closest to the ATM reference (forward, else index); omit for all strikes"),
421
+ }, async ({ venue, underlying, expiry, strikes }) => {
422
+ try {
423
+ const chain = await (await getOptionsVenue(venue, MCP_NETWORK)).getChain({
424
+ underlying, expiry: expiry === undefined ? null : expiry, strikesAroundAtm: strikes === undefined ? null : strikes,
425
+ });
426
+ return { content: [{ type: "text", text: ok(chain, { venue, expiry: chain.expiry, rows: chain.rows.length }) }] };
427
+ }
428
+ catch (e) {
429
+ return { content: [{ type: "text", text: errOf(e, { venue, underlying }) }], isError: true };
430
+ }
431
+ });
432
+ server.tool("get_option_quote", "Quote one option instrument (Derive name, e.g. ETH-20261225-3500-P): bid / ask (price + size), mark, index, forward, IV, greeks, open interest, 24h stats. Unknown instrument → SYMBOL_NOT_FOUND. Public read.", { venue: OPTIONS_VENUE_ARG, instrument: z.string().describe("Venue instrument name, e.g. ETH-20261225-3500-P") }, async ({ venue, instrument }) => {
433
+ try {
434
+ const q = await (await getOptionsVenue(venue, MCP_NETWORK)).getQuote(instrument);
435
+ return { content: [{ type: "text", text: ok(q, { venue, instrument: q.instrument }) }] };
436
+ }
437
+ catch (e) {
438
+ return { content: [{ type: "text", text: errOf(e, { venue, instrument }) }], isError: true };
439
+ }
440
+ });
441
+ // ============================================================
365
442
  // Account tools (need private key)
366
443
  // ============================================================
367
444
  server.tool("get_outcome_positions", "Get the active account's open outcome positions (size, entry notional, mark price, unrealized PnL). Requires a configured Hyperliquid wallet or agent.", {}, async () => {
@@ -1125,6 +1202,9 @@ server.tool("arb_scan", "Scan for funding rate arbitrage opportunities across ex
1125
1202
  symbol: s.symbol,
1126
1203
  maxSpreadAnnual: `${s.maxSpreadAnnual.toFixed(2)}%`,
1127
1204
  strategy: `Long ${s.longExchange} / Short ${s.shortExchange}`,
1205
+ // false = a leg is on a read-only venue (RISEx in this release): data only, not tradable here.
1206
+ executable: s.executable,
1207
+ readOnlyLegs: s.readOnlyLegs,
1128
1208
  estHourlyIncomePerK: `$${s.estHourlyIncomeUsd.toFixed(4)}`,
1129
1209
  rates: s.rates.map(r => ({
1130
1210
  exchange: r.exchange,
@@ -1149,44 +1229,14 @@ server.tool("arb_scan", "Scan for funding rate arbitrage opportunities across ex
1149
1229
  });
1150
1230
  server.tool("health_check", "Ping every registered venue on the server's network and return connectivity status and latency. Pacifica / Hyperliquid / Lighter / Aster / QFEX: REST ping (status = HTTP status, 0 = no response); every other venue: its public market-data read (status null). A failure carries its error message.", {}, async () => {
1151
1231
  try {
1152
- const timed = async (probe, fn) => {
1153
- const start = Date.now();
1154
- try {
1155
- const r = await fn();
1156
- return { ok: r.ok, latencyMs: Date.now() - start, status: r.status, error: r.ok ? null : `HTTP ${r.status}`, probe };
1157
- }
1158
- catch (e) {
1159
- return { ok: false, latencyMs: Date.now() - start, status: probe === "ping" ? 0 : null, error: extractErrorMessage(e), probe };
1160
- }
1161
- };
1162
- const restPing = (url) => timed("ping", async () => {
1163
- const res = await fetch(url);
1164
- return { ok: res.ok, status: res.status };
1165
- });
1166
- // Shared-api helpers report a transport failure as status 0 (no message).
1167
- const helperPing = (fn) => async () => {
1168
- const r = await fn();
1169
- return { ...r, error: r.ok ? null : r.status === 0 ? "no response" : `HTTP ${r.status}`, probe: "ping" };
1170
- };
1171
- const pings = {
1172
- pacifica: helperPing(pingPacifica),
1173
- hyperliquid: helperPing(pingHyperliquid),
1174
- lighter: helperPing(pingLighter),
1175
- aster: () => restPing(`${networkConfig(getVenue("aster"), MCP_NETWORK).restUrl}/fapi/v1/time`),
1176
- // QFEX: public GET /refdata for one instrument on the server's network.
1177
- qfex: () => restPing(`${networkConfig(getVenue("qfex"), MCP_NETWORK).restUrl}/refdata?ticker=AAPL-USD`),
1178
- };
1179
- const venues = listVenues();
1180
- const probes = await Promise.all(venues.map(v => {
1181
- const ping = pings[v.id];
1182
- return ping !== undefined
1183
- ? ping()
1184
- : timed("markets", async () => { await v.publicData.fetchMarkets(MCP_NETWORK); return { ok: true, status: null }; });
1185
- }));
1232
+ const health = await probeVenueHealth(MCP_NETWORK);
1186
1233
  const result = {};
1187
- venues.forEach((v, i) => { result[v.id] = { ...probes[i], statusText: probes[i].ok ? "healthy" : "unreachable" }; });
1188
- result.covered = venues.map(v => v.id);
1189
- result.allHealthy = probes.every(p => p.ok);
1234
+ for (const { venue, ...p } of health.probes)
1235
+ result[venue] = { ...p, statusText: p.ok ? "healthy" : "unreachable" };
1236
+ result.covered = health.probes.map(p => p.venue);
1237
+ // A venue without an environment on the server's network (TxFlow has no testnet) is not probed.
1238
+ result.skipped = health.skipped;
1239
+ result.allHealthy = health.allHealthy;
1190
1240
  return { content: [{ type: "text", text: ok(result) }] };
1191
1241
  }
1192
1242
  catch (e) {
@@ -1446,7 +1496,7 @@ function mcpOrderRequest(adapter, p) {
1446
1496
  };
1447
1497
  }
1448
1498
  server.tool("trade_preview", `Preview a trade WITHOUT executing. Runs trade_execute's pre-send checks read-only (size parse, order validation incl. TIF, quarantine, local risk limits — never forced) and reports any refusal as valid:false with its code + remediation; also returns the estimated fill price from the book, notional, margin impact, the builder fee the order would carry, and the existing position. Venue trading fees are NOT estimated. ALWAYS call this before trade_execute and show the result to the user for confirmation. ${HL_SCOPE_NOTE}`, {
1449
- exchange: z.string().describe(`Exchange: ${listVenues().filter(v => v.create !== null).map(v => v.id).join(", ")} (aliases accepted)`),
1499
+ exchange: z.string().describe(`Exchange: ${listVenues().filter(v => v.roles.includes("trading")).map(v => v.id).join(", ")} (aliases accepted)`),
1450
1500
  symbol: z.string().describe("Trading symbol (e.g., BTC, ETH, SOL)"),
1451
1501
  side: z.enum(["buy", "sell"]).describe("Order side"),
1452
1502
  size: z.string().describe("Order size (base currency units, e.g., '0.1' for 0.1 BTC)"),
@@ -1456,6 +1506,8 @@ server.tool("trade_preview", `Preview a trade WITHOUT executing. Runs trade_exec
1456
1506
  reduceOnly: z.boolean().default(false).describe("Reduce-only order (close position only) — checked like trade_execute (quarantine applies only to non-reduce-only orders)"),
1457
1507
  }, async ({ exchange, symbol, side, size, orderType, price, tif, reduceOnly }) => {
1458
1508
  try {
1509
+ // No trading role (TxFlow, release-gated RISEx) → CAPABILITY_UNSUPPORTED before any credential.
1510
+ requireCapabilities(getVenue(exchange));
1459
1511
  const adapter = await getOrCreateAdapter(exchange);
1460
1512
  const sym = symbol.toUpperCase();
1461
1513
  const isLimit = orderType === "limit";
@@ -1570,9 +1622,9 @@ server.tool("trade_preview", `Preview a trade WITHOUT executing. Runs trade_exec
1570
1622
  });
1571
1623
  /**
1572
1624
  * Place one order through TradingV2 (native on ondo/arcus, legacy wrapper on the four
1573
- * pre-existing venues) and return OrderResult + execution (design §13.7). Pre-send
1625
+ * pre-existing venues) and return OrderResult + execution. Pre-send
1574
1626
  * validation failures stay definite; anything thrown after the request may have reached
1575
- * the venue becomes ORDER_PENDING ("do NOT resubmit", design §12.3).
1627
+ * the venue becomes ORDER_PENDING ("do NOT resubmit").
1576
1628
  */
1577
1629
  async function placeViaV2(adapter, req, what, remediation) {
1578
1630
  const def = getVenue(adapter.name);
@@ -1589,7 +1641,7 @@ async function placeViaV2(adapter, req, what, remediation) {
1589
1641
  }
1590
1642
  }
1591
1643
  server.tool("trade_execute", `Execute a REAL trade on the server's network (meta.network; PERP_NETWORK, default mainnet). IMPORTANT: Always call trade_preview first and get explicit user confirmation before calling this tool. Refused with RISK_VIOLATION when the order breaches the local risk limits (perp risk set; there is no override over MCP) or when the symbol is quarantined (only reduce-only orders pass). Every order is written to the execution log. Supports market and limit orders. Returns the uniform OrderResult (status, finality, filledSize, execution: slippage / protection price / TIF sent) with the raw venue response under \`legacy\`, plus top-level filledSize / requestedSize / partial. Outcomes: an unknown outcome (transport failure after send, or a non-final venue ack) → ok:false, code ORDER_PENDING, executed:false, pending:true and a "do NOT resubmit" remediation — the symbol is quarantined for opening orders until a human clears it; a final rejection / cancel with nothing filled → ORDER_REJECTED, executed:false; a cancel after a partial fill → executed:true, partial:true with the real filledSize. ${HL_SCOPE_NOTE}`, {
1592
- exchange: z.string().describe(`Exchange: ${listVenues().filter(v => v.create !== null).map(v => v.id).join(", ")} (aliases accepted)`),
1644
+ exchange: z.string().describe(`Exchange: ${listVenues().filter(v => v.roles.includes("trading")).map(v => v.id).join(", ")} (aliases accepted)`),
1593
1645
  symbol: z.string().describe("Trading symbol (e.g., BTC, ETH, SOL)"),
1594
1646
  side: z.enum(["buy", "sell"]).describe("Order side"),
1595
1647
  size: z.string().describe("Order size (base currency units)"),
@@ -1602,6 +1654,7 @@ server.tool("trade_execute", `Execute a REAL trade on the server's network (meta
1602
1654
  try {
1603
1655
  // One parsed size for the risk gate and the order ("1,000" / "abc" refused before any read or send).
1604
1656
  const size = parsePositiveDecimal(rawSize, "size");
1657
+ requireCapabilities(getVenue(exchange)); // trading role first, before any credential
1605
1658
  const adapter = await getOrCreateAdapter(exchange);
1606
1659
  const def = getVenue(adapter.name);
1607
1660
  const caps = requireCapabilities(def);
@@ -1722,10 +1775,11 @@ server.tool("trade_execute", `Execute a REAL trade on the server's network (meta
1722
1775
  }
1723
1776
  });
1724
1777
  server.tool("trade_close", `Close an existing position. IMPORTANT: Call trade_preview first with the opposite side to show impact, then get user confirmation. Verified close: \`closedSize\` is the measured / venue-final fill (one residual market close is attempted); a residual still open → ORDER_PARTIAL error (symbol quarantined). Includes the uniform OrderResult of the reduce-only market order. ${HL_SCOPE_NOTE}`, {
1725
- exchange: z.string().describe(`Exchange: ${listVenues().filter(v => v.create !== null).map(v => v.id).join(", ")} (aliases accepted)`),
1778
+ exchange: z.string().describe(`Exchange: ${listVenues().filter(v => v.roles.includes("trading")).map(v => v.id).join(", ")} (aliases accepted)`),
1726
1779
  symbol: z.string().describe("Symbol to close (e.g., BTC, ETH)"),
1727
1780
  }, async ({ exchange, symbol }) => {
1728
1781
  try {
1782
+ requireCapabilities(getVenue(exchange)); // trading role first, before any credential
1729
1783
  const adapter = await getOrCreateAdapter(exchange);
1730
1784
  const def = getVenue(adapter.name);
1731
1785
  const caps = requireCapabilities(def);
@@ -1,8 +1,16 @@
1
1
  import { type Network } from "./constants.js";
2
- import type { MarketInfo, PriceInfo, Orderbook, Trade, Kline, KlineInterval, AggLevel, AccountInfo, AccountSettings, Position, OrderInfo, MarketOrderParams, LimitOrderParams, StopOrderParams, EditOrderParams, CancelOrderParams, CancelAllOrdersParams, TWAPParams, CancelTWAPParams, TPSLParams, UpdateLeverageParams, WithdrawParams, TransferFundsParams, BatchAction, CreateLakeParams, LakeDepositParams, LakeWithdrawParams } from "./types/index.js";
2
+ import type { MarketInfo, PriceInfo, Orderbook, Trade, Kline, KlineInterval, AggLevel, AccountInfo, AccountSettings, Position, OrderInfo, MarketOrderParams, LimitOrderParams, StopOrderParams, EditOrderParams, CancelOrderParams, CancelAllOrdersParams, TWAPParams, CancelTWAPParams, TPSLParams, UpdateLeverageParams, WithdrawParams, TransferFundsParams, BatchAction, BatchActionType, CreateLakeParams, LakeDepositParams, LakeWithdrawParams } from "./types/index.js";
3
3
  type SignMessageFn = (message: Uint8Array) => Promise<Uint8Array>;
4
4
  /** Per-request timeout of a POST (fetch + body read). */
5
5
  export declare const PACIFICA_POST_TIMEOUT_MS = 15000;
6
+ /**
7
+ * Credits ×10 reserved for one POST /orders/batch. The docs (api/rate-limits "Credit Costs") price
8
+ * a "Standard request/action" at 1 credit and an "Order cancellation" at 0.5 and say nothing
9
+ * batch-specific (batch-order page: no cost); every action is individually signed and processed,
10
+ * so the batch is reserved per ACTION — the conservative reading (over-reserving only throttles
11
+ * earlier; the venue's ratelimit headers on the response settle the real count).
12
+ */
13
+ export declare function pacificaBatchCost(types: readonly BatchActionType[]): number;
6
14
  export interface PacificaClientConfig {
7
15
  network?: Network;
8
16
  baseUrl?: string;
@@ -18,6 +26,10 @@ export declare class PacificaClient {
18
26
  * against the agent key. Undefined for master/PK signers.
19
27
  */
20
28
  private requestAgentWallet?;
29
+ /** Credit-quota state for this base URL + key tier (rate-limit.ts; process-local): unsigned GETs (IP quota) … */
30
+ private readonly rate;
31
+ /** … and signed POSTs (may report the account's quota) kept apart. */
32
+ private readonly signedRate;
21
33
  /** Attach (or clear) the agent wallet used for subsequent signed requests. */
22
34
  setRequestAgentWallet(agentWallet?: string): void;
23
35
  /** Build a signed POST body, attaching agent_wallet when an agent is the active signer. */
@@ -31,8 +43,12 @@ export declare class PacificaClient {
31
43
  * outcome unknown → ORDER_PENDING (sendFailure), never a retryable network error. No connection
32
44
  * at all → not sent. A 4xx is the venue's refusal and keeps the plain `POST <path> failed
33
45
  * (<status>): <body>` error the adapters map (422 business codes) — except on
34
- * DEFINITE_4XX_PATHS, where it is a definite ACTION_REJECTED (429 stays the plain error →
35
- * RATE_LIMITED). A fetch timeout (PACIFICA_POST_TIMEOUT_MS) on a write is ORDER_PENDING too;
46
+ * DEFINITE_4XX_PATHS, where it is a definite ACTION_REJECTED. HTTP 429 → RATE_LIMITED
47
+ * (details.sent === false, retryAfterMs) — never retried, a write is never resubmitted.
48
+ * "429 = not executed" is our reading of the docs ("When credits are exhausted, requests return
49
+ * HTTP 429"), not an explicit Pacifica statement. Before sending, the credit throttle may wait up
50
+ * to PACIFICA_SIGNED_MAX_WAIT_MS (the body is already signed) or fail fast with RATE_LIMITED
51
+ * (nothing sent). A write needs only its own cost, never the read reserve. A fetch timeout (PACIFICA_POST_TIMEOUT_MS) on a write is ORDER_PENDING too;
36
52
  * on a listing read a timeout is TIMEOUT and any other transport failure EXCHANGE_UNREACHABLE.
37
53
  */
38
54
  private post;
@@ -119,6 +135,27 @@ export declare class PacificaClient {
119
135
  createLake(params: CreateLakeParams, account: string, signMessage: SignMessageFn): Promise<unknown>;
120
136
  depositToLake(params: LakeDepositParams, account: string, signMessage: SignMessageFn): Promise<unknown>;
121
137
  withdrawFromLake(params: LakeWithdrawParams, account: string, signMessage: SignMessageFn): Promise<unknown>;
138
+ /**
139
+ * Unauthenticated GET that keeps the whole {success, data, has_more, next_cursor} envelope.
140
+ * Same credit limiter as get() (unsigned IP quota, PACIFICA_READ_NEED: may wait for the window,
141
+ * else RATE_LIMITED sent:false); the response headers are recorded; HTTP 429 → RATE_LIMITED
142
+ * (structural, never retried). Timeout → TIMEOUT, transport failure → EXCHANGE_UNREACHABLE,
143
+ * non-JSON / non-object body → EXCHANGE_ERROR (a read: nothing can have changed).
144
+ */
145
+ getEnvelope(path: string, params?: Record<string, string>): Promise<Record<string, unknown>>;
146
+ /**
147
+ * POST a body the caller already built and signed (Print / vault writes sign their own canonical
148
+ * message so `--dry-run` can show the exact body). Same unknown-outcome rules as every write.
149
+ */
150
+ postPresigned(path: "/game/deposit" | "/game/end" | "/lake/deposit" | "/lake/withdraw", body: Record<string, unknown>): Promise<unknown>;
151
+ /**
152
+ * Pre-sign credit wait for a pre-signed write (same rule as signedBody / amend): call BEFORE
153
+ * building + signing, so the post-sign wait in post() (≤ PACIFICA_SIGNED_MAX_WAIT_MS, inside the
154
+ * 5 s expiry_window) finds credits. Cost: the docs' rate-limits table lists no Print / vault
155
+ * entry — "Standard request/action: 1 credit" applies (end_game is not an order cancellation).
156
+ * Fail-fast RATE_LIMITED here sent and signed nothing (details.sent === false).
157
+ */
158
+ awaitPresignedCapacity(operationType: string): Promise<void>;
122
159
  approveBuilderCode(params: {
123
160
  builder_code: string;
124
161
  max_fee_rate: string;
@@ -137,6 +174,32 @@ export declare class PacificaClient {
137
174
  claimReferralCode(params: {
138
175
  code: string;
139
176
  }, account: string, signMessage: SignMessageFn): Promise<unknown>;
140
- batchOrders(actions: BatchAction[]): Promise<unknown>;
177
+ /**
178
+ * POST /orders/batch with the per-action cost (pacificaBatchCost) reserved. `maxWaitMs` caps the
179
+ * post-sign throttle wait (default PACIFICA_SIGNED_MAX_WAIT_MS, never more): a caller with a
180
+ * tighter signature deadline passes what is left of it, so a wait can never send an expired batch
181
+ * — a longer wait fails fast with RATE_LIMITED (sent: false, nothing sent).
182
+ */
183
+ batchOrders(actions: BatchAction[], opts?: {
184
+ maxWaitMs?: number;
185
+ }): Promise<unknown>;
186
+ /**
187
+ * Pre-sign throttle for a batch (like signedBody does for single writes): wait — up to
188
+ * PACIFICA_MAX_THROTTLE_WAIT_MS, else RATE_LIMITED with nothing signed or sent — until the
189
+ * batch's whole cost fits, so the post-sign acquire in batchOrders normally finds the credits.
190
+ */
191
+ awaitBatchCapacity(types: readonly BatchActionType[]): Promise<void>;
192
+ /**
193
+ * One signed batch action body (docs rest-api/orders/batch-order: "Batch orders are not signed
194
+ * as a whole, but rather by its individual actions components"; each action's `data` carries the
195
+ * fields of its standalone endpoint, signed with that endpoint's operation type). Nothing is sent.
196
+ * `header` fixes the signed timestamp / expiry window, so every action of one batch can share
197
+ * one timestamp. agent_wallet is attached when an agent is the active signer. A signing failure
198
+ * → ORDER_REJECTED (orderNotSent).
199
+ */
200
+ signBatchAction(operationType: string, payload: Record<string, unknown>, account: string, signMessage: SignMessageFn, header: {
201
+ timestamp: number;
202
+ expiry_window: number;
203
+ }): Promise<Record<string, unknown>>;
141
204
  }
142
205
  export {};