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
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Pacifica signed writes whose body the caller builds before signing (Print `/game/*`, vault
3
+ * `/lake/*`). Building the canonical message and the request body is pure, so `--dry-run`
4
+ * prints exactly what a live run would sign and send — only the signature is missing.
5
+ *
6
+ * Signing scheme (docs.pacifica.fi api-documentation/api/signing, reused from
7
+ * src/pacifica/signing.ts): message = compact JSON, keys sorted recursively, of
8
+ * `{ type, timestamp, expiry_window, data: <payload> }`; Ed25519 signature, base58. The body is
9
+ * `{ account, agent_wallet?, signature, timestamp, expiry_window, ...payload }` — the same shape
10
+ * as `buildSignedRequest` / `buildAgentSignedRequest`.
11
+ *
12
+ * Send outcome (money-safety rules):
13
+ * - HTTP 4xx (except 409 / 429): the venue refused — ACTION_REJECTED, nothing happened;
14
+ * - HTTP 409 "duplicate idempotency key": a request with this key already exists — ORDER_PENDING;
15
+ * - HTTP 429: RATE_LIMITED, nothing happened;
16
+ * - timeout / reset / 5xx / unreadable or ambiguous 2xx body: ORDER_PENDING — never resubmit.
17
+ */
18
+ import bs58 from "bs58";
19
+ import { prepareMessage } from "../pacifica/signing.js";
20
+ import { DEFAULT_EXPIRY_WINDOW } from "../pacifica/constants.js";
21
+ import { PerpError, extractErrorMessage, orderNotSent } from "../errors.js";
22
+ /** Build the canonical message and unsigned body. Undefined payload values are refused (they would be dropped by JSON but not by the signer). */
23
+ export function buildPresigned(p) {
24
+ for (const [k, v] of Object.entries(p.payload)) {
25
+ if (v === undefined)
26
+ throw new Error(`buildPresigned: payload field ${k} is undefined`);
27
+ }
28
+ const expiryWindow = p.expiryWindow ?? DEFAULT_EXPIRY_WINDOW;
29
+ const message = prepareMessage({ type: p.type, timestamp: p.timestamp, expiry_window: expiryWindow }, p.payload);
30
+ const body = {
31
+ account: p.identity.account,
32
+ ...(p.identity.agentWallet !== null ? { agent_wallet: p.identity.agentWallet } : {}),
33
+ timestamp: p.timestamp,
34
+ expiry_window: expiryWindow,
35
+ ...p.payload,
36
+ };
37
+ const key = p.payload.idempotency_key;
38
+ return { type: p.type, path: p.path, message, body, idempotencyKey: typeof key === "string" ? key : null };
39
+ }
40
+ /**
41
+ * The same request with a new timestamp (message + body re-derived; payload, identity, expiry
42
+ * window and idempotency key unchanged) — used after the pre-sign credit wait so the signature's
43
+ * expiry window starts when it is signed.
44
+ */
45
+ export function restampPresigned(req, timestamp) {
46
+ const { account, agent_wallet, timestamp: _t, expiry_window, ...payload } = req.body;
47
+ return buildPresigned({
48
+ type: req.type, path: req.path, payload, timestamp, expiryWindow: expiry_window,
49
+ identity: { account: account, agentWallet: typeof agent_wallet === "string" ? agent_wallet : null },
50
+ });
51
+ }
52
+ /** Sign the canonical message; returns the full body (`signature` added). A signing failure is "not sent". */
53
+ export async function signPresigned(req, signMessage) {
54
+ try {
55
+ const sig = await signMessage(new TextEncoder().encode(req.message));
56
+ const { account, agent_wallet, ...rest } = req.body;
57
+ return { account, ...(agent_wallet !== undefined ? { agent_wallet } : {}), signature: bs58.encode(sig), ...rest };
58
+ }
59
+ catch (e) {
60
+ throw orderNotSent("pacifica", req.type, e);
61
+ }
62
+ }
63
+ /**
64
+ * Send a signed body and return the response `data` object. `what` names the action in errors
65
+ * ("Print deposit"); `check` is the read command that settles an unknown outcome.
66
+ */
67
+ export async function sendPresigned(client, req, signedBody, ctx) {
68
+ const details = { exchange: "pacifica", path: req.path, idempotencyKey: req.idempotencyKey, ...(ctx.before !== undefined ? { before: ctx.before } : {}) };
69
+ const pending = (why) => new PerpError("ORDER_PENDING", `Pacifica ${ctx.what}: outcome unknown — ${why}`, {
70
+ ...details,
71
+ remediation: pendingRemediation(ctx.what, ctx.check, req.idempotencyKey),
72
+ });
73
+ let raw;
74
+ try {
75
+ raw = await client.postPresigned(req.path, signedBody);
76
+ }
77
+ catch (e) {
78
+ if (e instanceof PerpError) {
79
+ if (e.structured.code === "ORDER_PENDING")
80
+ throw pending(e.message);
81
+ throw e; // definite (not sent / refused) — client already classified it
82
+ }
83
+ const m = /^POST \S+ failed \((\d{3})\): ([\s\S]*)$/.exec(extractErrorMessage(e));
84
+ if (m === null)
85
+ throw pending(extractErrorMessage(e));
86
+ const status = Number(m[1]);
87
+ const venueError = venueErrorOf(m[2]);
88
+ if (status === 409)
89
+ throw pending(`HTTP 409 duplicate idempotency key ${req.idempotencyKey ?? "(none)"} — a request with this key already reached the venue: ${venueError}`);
90
+ if (status === 429) {
91
+ throw new PerpError("RATE_LIMITED", `Pacifica ${ctx.what} rate-limited (HTTP 429, nothing was executed): ${venueError}`, { ...details, remediation: "Wait and retry" });
92
+ }
93
+ if (status >= 400 && status < 500) {
94
+ throw new PerpError("ACTION_REJECTED", `Pacifica ${ctx.what} refused (HTTP ${status}, nothing was executed): ${venueError}`, {
95
+ ...details, httpStatus: status, remediation: "Fix the parameter named in the venue message and retry",
96
+ });
97
+ }
98
+ throw pending(`HTTP ${status}: ${venueError}`);
99
+ }
100
+ if (raw === null || typeof raw !== "object")
101
+ throw pending(`unreadable response ${JSON.stringify(raw)?.slice(0, 160)}`);
102
+ const env = raw;
103
+ if (env.success === false) {
104
+ throw new PerpError("ACTION_REJECTED", `Pacifica ${ctx.what} refused (nothing was executed): ${String(env.error ?? "success: false")}`, {
105
+ ...details, venueCode: env.code ?? null, remediation: "Fix the parameter named in the venue message and retry",
106
+ });
107
+ }
108
+ const data = env.data;
109
+ if (env.success !== true || data === null || typeof data !== "object" || Array.isArray(data)) {
110
+ throw pending(`response without a data object: ${JSON.stringify(raw).slice(0, 200)}`);
111
+ }
112
+ return data;
113
+ }
114
+ /**
115
+ * ORDER_PENDING remediation. With an idempotency key, the ONLY safe retry is the same request with
116
+ * the same key (`--idempotency-key`): the venue answers a duplicate with HTTP 409 instead of
117
+ * executing it twice. How long Pacifica remembers a key is not documented (unverified).
118
+ */
119
+ export function pendingRemediation(what, check, idempotencyKey) {
120
+ const base = `Do NOT resubmit with a new request — the ${what} may have been executed. Check first: ${check}.`;
121
+ return idempotencyKey === null
122
+ ? `${base} This action carries no idempotency key: run it again only once that check shows it did not take effect.`
123
+ : `${base} If you must retry, the only safe way is the same command with --idempotency-key ${idempotencyKey} (the venue refuses a duplicate key with HTTP 409; its dedupe window is unverified).`;
124
+ }
125
+ const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
126
+ /** `--idempotency-key`: a full UUID string (API docs), lowercased; refused otherwise. */
127
+ export function requireIdempotencyKey(raw) {
128
+ const k = raw.trim();
129
+ if (!UUID.test(k))
130
+ throw new PerpError("INVALID_PARAMS", `--idempotency-key must be a full UUID (got "${raw}")`, { remediation: "Pass the idempotencyKey reported by the earlier attempt" });
131
+ return k.toLowerCase();
132
+ }
133
+ function venueErrorOf(text) {
134
+ try {
135
+ const j = JSON.parse(text);
136
+ if (typeof j.error === "string" && j.error !== "")
137
+ return j.error;
138
+ }
139
+ catch { /* not JSON */ }
140
+ return text.slice(0, 300);
141
+ }
@@ -0,0 +1,200 @@
1
+ import type { PacificaClient } from "../pacifica/client.js";
2
+ import { type PresignedIdentity, type PresignedRequest } from "./pacifica-presigned.js";
3
+ /** docs print/placing-and-managing-orders: "Deposit — your locked margin, minimum $10". */
4
+ export declare const PRINT_MIN_DEPOSIT_USDC = "10";
5
+ /** docs: target "at least 0.5% away from the current mark price". */
6
+ export declare const PRINT_MIN_TARGET_DISTANCE_PCT = "0.5";
7
+ /** docs: "at most 10% on a 24-hour cycle, 20% on 7 days, or 40% on 30 days" (keyed by cycle days). */
8
+ export declare const PRINT_MAX_TARGET_DISTANCE_PCT: Readonly<Record<number, string>>;
9
+ /** API create-print-order: "total_segments … 1 to 1000". */
10
+ export declare const PRINT_MAX_CYCLES = 1000;
11
+ /**
12
+ * The docs formula (target ∓ (deposit + yield) × target / (leverage × deposit)) is where the margin
13
+ * is fully lost. A liquidation was observed earlier than that in one live case (mainnet 2026-10-16:
14
+ * a ZEC_24H short, strike 1150.95, 10×, deposit 922.93, premium 23.80, liquidated at the checkpoint
15
+ * with mark 1216.836 while the formula gives ≈ 1269.0). The venue's trigger is unpublished; its own
16
+ * figure comes only from the signed preview (preview_game_account), not called here.
17
+ */
18
+ export declare const PRINT_LIQUIDATION_NOTE = "docsLiquidationPrice is the docs formula (margin fully lost) \u2014 an outer bound, not the trigger: a liquidation was observed earlier in one live case (2026-10-16); the venue's trigger is unpublished. After a fill the position follows ordinary perp liquidation (continuous mark price, main account).";
19
+ export type PrintDirection = "long" | "short";
20
+ export interface PrintGame {
21
+ schema: 1;
22
+ /** Product id sent as `game` (e.g. BTC_24H, BTC_7D, BTC_1M). */
23
+ game: string;
24
+ asset: string;
25
+ /** Cycle length in days (segment_kind fixed_days), null when the venue reports another kind. */
26
+ cycleDays: number | null;
27
+ maxLeverage: string | null;
28
+ /** Cap on the TOTAL open deposits of this product across all users (USDC) — not a per-order limit. */
29
+ productDepositCap: string | null;
30
+ /** Cap on open deposits of the whole Print pool (USDC). */
31
+ poolDepositCap: string | null;
32
+ capScope: string | null;
33
+ /** Vault ("lake") that pays the premiums. */
34
+ poolAddress: string | null;
35
+ minDeposit: string;
36
+ targetDistancePct: {
37
+ min: string;
38
+ max: string | null;
39
+ };
40
+ }
41
+ export type PrintStatus = "printing" | "cancelling" | "filled" | "liquidated" | "cancelled" | "completed" | "ended";
42
+ export interface PrintPosition {
43
+ schema: 1;
44
+ /** Print order account address (`game_account`). */
45
+ address: string;
46
+ game: string;
47
+ asset: string | null;
48
+ direction: PrintDirection;
49
+ deposit: string;
50
+ strikePrice: string;
51
+ leverage: string;
52
+ entryMarkPrice: string | null;
53
+ /** Premiums credited so far (USDC). */
54
+ premiumPaid: string | null;
55
+ /** deposit × leverage. */
56
+ notional: string;
57
+ /** Size opened on a fill: notional ÷ strike. */
58
+ size: string | null;
59
+ /**
60
+ * docs formula (margin fully lost) with the premiums paid; null when ≤ 0 or unknown. NOT the
61
+ * venue's trigger: it liquidates earlier, at maintenance margin (PRINT_LIQUIDATION_NOTE).
62
+ */
63
+ docsLiquidationPrice: string | null;
64
+ /** deposit + premiums — the most that can be lost. */
65
+ maxLoss: string | null;
66
+ cycles: {
67
+ total: number | null;
68
+ started: number | null;
69
+ };
70
+ createdAt: number | null;
71
+ startedAt: number | null;
72
+ currentCycleEndAt: number | null;
73
+ scheduledEndAt: number | null;
74
+ endedAt: number | null;
75
+ endReason: string | null;
76
+ cancelRequested: boolean;
77
+ status: PrintStatus;
78
+ }
79
+ export interface PrintEvent {
80
+ schema: 1;
81
+ id: number;
82
+ printAddress: string;
83
+ depositor: string | null;
84
+ event: string;
85
+ amount: string | null;
86
+ strikePrice: string | null;
87
+ markPrice: string | null;
88
+ /** Position size of a position_opened event. */
89
+ size: string | null;
90
+ cycleStartedAt: number | null;
91
+ cycleEndedAt: number | null;
92
+ cycleNumber: number | null;
93
+ time: number;
94
+ }
95
+ export interface Page<T> {
96
+ items: T[];
97
+ hasMore: boolean | null;
98
+ nextCursor: string | null;
99
+ }
100
+ /** `data` of a `{success: true, data}` envelope; a refusal / other shape is EXCHANGE_ERROR. */
101
+ export declare function envelopeData(env: Record<string, unknown>, path: string): unknown;
102
+ /** GET /game/config `data` → products (`{configs: [...]}`; the app also accepts a bare array). */
103
+ export declare function parsePrintGames(data: unknown): PrintGame[];
104
+ /** docs margin-and-liquidation: target ∓ (deposit + yield) × target / (leverage × deposit). */
105
+ export declare function printLiquidationPrice(direction: PrintDirection, strike: string, deposit: string, leverage: string, premium: string, tickSize?: string | null): string | null;
106
+ /** One /game/accounts or /game/history_summary row. */
107
+ export declare function parsePrintPosition(x: unknown): PrintPosition;
108
+ /** GET /game/accounts `data` (`{game_accounts: [...]}`). */
109
+ export declare function parsePrintAccounts(data: unknown): PrintPosition[];
110
+ /** One /game/history event (created / premium / end_requested / filled / liquidated / …). */
111
+ export declare function parsePrintEvent(x: unknown): PrintEvent;
112
+ type Reader = Pick<PacificaClient, "getEnvelope">;
113
+ export declare function fetchPrintGames(client: Reader): Promise<PrintGame[]>;
114
+ export declare function fetchPrintPositions(client: Reader, account: string): Promise<PrintPosition[]>;
115
+ export declare function fetchPrintHistory(client: Reader, account: string, page: {
116
+ limit: number | null;
117
+ cursor: string | null;
118
+ }): Promise<Page<PrintPosition>>;
119
+ export declare function fetchPrintEvents(client: Reader, printAddress: string, page: {
120
+ limit: number | null;
121
+ cursor: string | null;
122
+ }): Promise<Page<PrintEvent>>;
123
+ /** Mark price + tick size of the product's perp market (GET /prices, GET /info). */
124
+ export declare function fetchPrintMarket(client: Pick<PacificaClient, "getPrices" | "getInfo">, asset: string): Promise<{
125
+ mark: string;
126
+ tickSize: string;
127
+ }>;
128
+ /** The product `game` (case-insensitive) from the live list; unknown → SYMBOL_NOT_FOUND naming what exists. */
129
+ export declare function findPrintGame(games: PrintGame[], game: string): PrintGame;
130
+ export interface PrintOrderInput {
131
+ game: string;
132
+ direction: PrintDirection;
133
+ /** USDC deposit (decimal string). */
134
+ deposit: string;
135
+ strikePrice: string;
136
+ leverage: string;
137
+ /** Number of cycles (total_segments) or null = roll until ended. */
138
+ cycles: number | null;
139
+ }
140
+ export interface PrintQuote {
141
+ schema: 1;
142
+ game: string;
143
+ asset: string;
144
+ cycleDays: number;
145
+ direction: PrintDirection;
146
+ deposit: string;
147
+ leverage: string;
148
+ strikePrice: string;
149
+ markPrice: string;
150
+ /** |mark − strike| ÷ mark × 100, 4 decimals. */
151
+ targetDistancePct: string;
152
+ allowedTargetDistancePct: {
153
+ min: string;
154
+ max: string;
155
+ };
156
+ notional: string;
157
+ /** Position size opened on a fill (asset units, 8 decimals). */
158
+ size: string;
159
+ /** docs formula before any premium (margin fully lost) — the venue liquidates EARLIER (PRINT_LIQUIDATION_NOTE). */
160
+ docsLiquidationPrice: string | null;
161
+ liquidationNote: string;
162
+ /** The deposit now; the deposit plus every premium credited later. Never more. */
163
+ maxLoss: string;
164
+ cycles: number | null;
165
+ /** cycles × cycleDays, null = until ended. */
166
+ maxDurationDays: number | null;
167
+ /** An end request takes effect at the end of the running cycle: up to this many days. */
168
+ cancelSettlesWithinDays: number;
169
+ /** The venue's premium quote is a signed request (preview_game_account) — not called on a read path. */
170
+ estimatedPremium: null;
171
+ notes: string[];
172
+ }
173
+ /** Plain non-negative decimal without leading zeros ("0.5", "10", "10.25"; not "010", "1e3", ".5"). */
174
+ export declare const PLAIN_POSITIVE: RegExp;
175
+ /** Strict USDC amount: plain positive decimal, no leading zeros, at most 6 fractional digits (USDC precision). */
176
+ export declare function requireUsdcAmount(raw: string, what: string): string;
177
+ /**
178
+ * Validate a Print order against the product and the live mark (docs limits) and compute the
179
+ * preview. Throws INVALID_PARAMS / INVALID_TICK / CAPABILITY_UNSUPPORTED; signs and sends nothing.
180
+ */
181
+ export declare function quotePrintOrder(game: PrintGame, input: PrintOrderInput, market: {
182
+ mark: string;
183
+ tickSize: string;
184
+ }): PrintQuote;
185
+ /** POST /game/deposit body + canonical message (deposit_to_game). Field set per the API docs. */
186
+ export declare function buildPrintDepositRequest(q: PrintQuote, identity: PresignedIdentity, opts: {
187
+ timestamp: number;
188
+ idempotencyKey: string;
189
+ expiryWindow?: number;
190
+ }): PresignedRequest;
191
+ /** POST /game/end body + canonical message (end_game, payload `{game_account}` as app.pacifica.fi sends it). */
192
+ export declare function buildPrintEndRequest(printAddress: string, identity: PresignedIdentity, opts: {
193
+ timestamp: number;
194
+ expiryWindow?: number;
195
+ }): PresignedRequest;
196
+ /** An end request is accepted only for a running order of the account (not ended, not already ending). */
197
+ export declare function requireEndable(positions: PrintPosition[], printAddress: string): PrintPosition;
198
+ /** When a cycle that ends at `cycleEndAt` frees the funds, in days from `now` (null = unknown). */
199
+ export declare function daysUntil(cycleEndAt: number | null, now: number): string | null;
200
+ export {};